You are viewing our Forum Archives. To view or take place in current topics click here.
#31. Posted:
temtam
  • Powerhouse
Status: Offline
Joined: Oct 18, 20109 Year Member
Posts: 429
Reputation Power: 16
Here is the entire "animscripts/zombie_utility" coding:


#include animscripts\zombie_SetPoseMovement;
#include animscripts\combat_utility;
#include animscripts\debug;
#include common_scripts\utility;
#include maps\_utility;

#using_animtree ("generic_human");

// Every script calls initAnimTree to ensure a clean, fresh, known animtree state.
// ClearAnim should never be called directly, and this should never occur other than
// at the start of an animscript
// This function now also does any initialization for the scripts that needs to happen
// at the beginning of every main script.
initAnimTree(animscript)
{
if ( isValidEnemy( self.a.personImMeleeing ) )
{
ImNotMeleeing( self.a.personImMeleeing );
}

self ClearAnim( %body, 0.2 );
//self SetAnim( %body, 1, 0 ); // The %body node should always have weight 1.

if ( animscript != "pain" && animscript != "death" )
{
self.a.special = "none";
}

self.missedSightChecks = 0;

IsInCombat();

assertEX( IsDefined( animscript ), "Animscript not specified in initAnimTree" );
self.a.script = animscript;

// Call the handler to get out of Cowering pose.
[[self.a.StopCowering]]();
}

// UpdateAnimPose does housekeeping at the start of every script's main function.
UpdateAnimPose()
{
assertEX( self.a.movement=="stop" || self.a.movement=="walk" || self.a.movement=="run", "UpdateAnimPose "+self.a.pose+" "+self.a.movement );

self.desired_anim_pose = undefined;
}

initialize( animscript )
{
if ( IsDefined( self.longDeathStarting ) )
{
if ( animscript != "pain" && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}
if ( animscript != "pain" )
{
self.longDeathStarting = undefined;
self notify( "kill_long_death" );
}
}
if ( IsDefined( self.a.mayOnlyDie ) && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}

// scripts can define this to allow cleanup before moving on
if ( IsDefined( self.a.postScriptFunc ) )
{
scriptFunc = self.a.postScriptFunc;
self.a.postScriptFunc = undefined;

[[scriptFunc]]( animscript );
}

if ( animscript != "death" )
{
self.a.nodeath = false;
}

if ( IsDefined( self.isHoldingGrenade ) && (animscript == "pain" || animscript == "death" || animscript == "flashed") )
{
self dropGrenade();
}

self.isHoldingGrenade = undefined;

/#
//thread checkGrenadeInHand( animscript );
#/

/#
if( IsDefined(self.a.script) && !self animscripts\debug::debugShouldClearState() )
{
self animscripts\debug::debugPopState( self.a.script );
}
else
{
self animscripts\debug::debugClearState();
}

self animscripts\debug::debugPushState( animscript );
#/

self.coverNode = undefined;
self.changingCoverPos = false;
self.a.scriptStartTime = GetTime();

self.a.atConcealmentNode = false;
if ( IsDefined( self.node ) && (self.node.type == "Conceal Crouch" || self.node.type == "Conceal Stand") )
{
self.a.atConcealmentNode = true;
}

initAnimTree( animscript );

UpdateAnimPose();
}

/#
checkGrenadeInHand( animscript )
{
// ensure no grenade left in hand
self endon("killanimscript");

// pain and death animscripts don't execute script between notifying killanimscript and starting the next animscript,
// so the grenade cleanup thread might still be waiting to run.
if ( animscript == "pain" || animscript == "death" )
{
wait .05;
waittillframeend;
}

attachSize = self getattachsize();
for ( i = 0; i < attachSize; i++ )
{
model = toLower( self getAttachModelName( i ) );
assertex( model != "weapon_m67_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_m84_flashbang_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_us_smoke_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
}
}
#/

should_find_a_new_node()
{
self.a.next_move_to_new_cover--;
if ( self.a.next_move_to_new_cover > 0 )
{
return false;
}

anim_set_next_move_to_new_cover();
return true;
}


badplacer(time, org, radius)
{
for (i=0;i<time*20;i++)
{
for (p=0;p<10;p++)
{
angles = (0,RandomInt(360),0);
forward = AnglesToForward(angles);
scale = vector_scale(forward, radius);
line (org, org + scale, (1,0.3,0.3));
}
wait(0.05);
}
}


printDisplaceInfo()
{
self endon ("death");
self notify ("displaceprint");
self endon ("displaceprint");

for (;;)
{
Print3d (self.origin + (0,0,60), "displacer", (0,0.4,0.7), 0.85, 0.5);
wait (0.05);
}
}


getOldRadius()
{
self notify ("newOldradius");
self endon ("newOldradius");
self endon ("death");
wait (6);
self.goalradius = self.a.oldgoalradius;
}

// Returns whether or not the character should be acting like he's under fire or expecting an enemy to appear
// any second.
IsInCombat()
{
if ( isValidEnemy( self.enemy ) )
{
self.a.combatEndTime = GetTime() + anim.combatMemoryTimeConst + RandomInt(anim.combatMemoryTimeRand);
return true;
}

return ( self.a.combatEndTime > GetTime() );
}

GetNodeYawToOrigin(pos)
{
if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
if (IsDefined (self.node))
{
forward = AnglesToForward(self.node.angles);
}
else
{
forward = AnglesToForward(self.angles);
}

forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.coverNode.angles + self.animarray["angle_step_out"][self.a.cornerMode]);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.CoverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToSpot(spot)
{
pos = spot;
yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}
// warning! returns (my yaw - yaw to enemy) instead of (yaw to enemy - my yaw)
GetYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.angles);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYaw(org)
{
angles = VectorToAngles(org-self.origin);
return angles[1];
}

GetYaw2d(org)
{
angles = VectorToAngles((org[0], org[1], 0)-(self.origin[0], self.origin[1], 0));
return angles[1];
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy2d()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw2d(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

AbsYawToAngles(angles)
{
yaw = self.angles[1] - angles;
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

GetYawFromOrigin(org, start)
{
angles = VectorToAngles(org-start);
return angles[1];
}

GetYawToTag(tag, org)
{
yaw = self GetTagAngles( tag )[1] - GetYawFromOrigin(org, self GetTagOrigin(tag));
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetEyeYawToOrigin(org)
{
yaw = self GetTagAngles("TAG_EYE")[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToOrigin(org)
{
yaw = self.coverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}


isStanceAllowedWrapper( stance )
{
if ( IsDefined( self.coverNode ) )
{
return self.coverNode doesNodeAllowStance( stance );
}

return self IsStanceAllowed( stance );
}


choosePose(preferredPose)
{
if ( !IsDefined( preferredPose ) )
{
preferredPose = self.a.pose;
}
if ( EnemiesWithinStandingRange() )
{
preferredPose = "stand";
}

// Find out if we should be standing or crouched
switch (preferredPose)
{
case "stand":
if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else
{
println ("No stance allowed! Remaining standing.");
resultPose = "stand";
}
break;

case "crouch":
if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else
{
println ("No stance allowed! Remaining crouched.");
resultPose = "crouch";
}
break;

default:
println ("utility::choosePose, called in "+self.a.script+" script: Unhandled anim_pose "+self.a.pose+" - using stand.");
resultPose = "stand";
break;
}
return resultPose;
}

// Melee stuff. Note that IsAlive is better than IsDefined when you're checking variables that are either
// undefined or set to an AI.
okToMelee(person)
{
assert( IsDefined( person ) );
if (IsDefined(self.a.personImMeleeing)) // Tried to melee someone else when I am already meleeing, possibly because code changed my enemy.
{
ImNotMeleeing(self.a.personImMeleeing);
assert(!IsDefined(self.a.personImMeleeing));
}

if (IsDefined(person.a.personMeleeingMe))
{
// This means that oldAttacker was the last person to melee person. He may or may not still be meleeing him.
oldAttacker = person.a.personMeleeingMe;
if ( IsDefined(oldAttacker.a.personImMeleeing) && oldAttacker.a.personImMeleeing == person )
{
// This means that oldAttacker is currently meleeing person.
return false;
}
println("okToMelee - Shouldn't get to here");
// This means that oldAttacker is no longer meleeing person and somehow person was never informed. We can still handle it though.
person.a.personMeleeingMe = undefined;
assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

IAmMeleeing(person)
{
assert(IsDefined(person));
assert(!IsDefined(person.a.personMeleeingMe));
assert(!IsDefined(self.a.personImMeleeing));
person.a.personMeleeingMe = self;
self.a.personImMeleeing = person;
}

ImNotMeleeing(person)
{
// First check that everything is in synch, just for my own peace of mind. This can go away once there are no bugs.
if ( (IsDefined(person)) && (IsDefined(self.a.personImMeleeing)) && (self.a.personImMeleeing==person) )
{
assert(IsDefined(person.a.personMeleeingMe));
assert(person.a.personMeleeingMe == self);
}
// This function does not require that I was meleeing Person to start with.
if (!IsDefined(person))
{
self.a.personImMeleeing = undefined;
}
else if ( (IsDefined(person.a.personMeleeingMe)) && (person.a.personMeleeingMe==self) )
{
person.a.personMeleeingMe = undefined;
assert(self.a.personImMeleeing==person);
self.a.personImMeleeing = undefined;
}
// A final check that I got this right...
assert( !IsDefined(person) || !IsDefined(self.a.personImMeleeing) || (self.a.personImMeleeing!=person) );
assert( !IsDefined(person) || !IsDefined(person.a.personMeleeingMe) || (person.a.personMeleeingMe!=self) );
}

GetClaimedNode()
{
myNode = self.node;
if ( IsDefined(myNode) && (self nearNode(myNode) || (IsDefined( self.coverNode ) && myNode == self.coverNode)) )
{
return myNode;
}

return undefined;
}

GetNodeType()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.type;
}

return "none";
}

GetNodeDirection()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
//thread [[anim.println]]("GetNodeDirection found node, returned: "+myNode.angles[1]);#/
return myNode.angles[1];
}
//thread [[anim.println]]("GetNodeDirection didn't find node, returned: "+self.desiredAngle);#/
return self.desiredAngle;
}

GetNodeForward()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return AnglesToForward ( myNode.angles );
}

return AnglesToForward( self.angles );
}

GetNodeOrigin()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.origin;
}

return self.origin;
}

safemod(a,b)
{
/*
Here are some modulus results from in-game:
10 % 3 = 1
10 % -3 = 1
-10 % 3 = -1
-10 % -3 = -1
however, we never want a negative result.
*/
result = int(a) % b;
result += b;
return result % b;
}

// Gives the result as an angle between 0 and 360
AngleClamp( angle )
{
angleFrac = angle / 360.0;
angle = (angleFrac - floor( angleFrac )) * 360.0;
return angle;
}

// Returns an array of 4 weights (2 of which are guaranteed to be 0), which should be applied to forward,
// right, back and left animations to get the angle specified.
// front
// /----|----\
// / 180 \
// /\ | /\
// / -135 | 135 \
// | \ | / |
// left|-90----+----90-|right
// | / | \ |
// \ -45 | 45 /
// \/ | \/
// \ 0 /
// \----|----/
// back

QuadrantAnimWeights( yaw )
{
// ALEXP 6/26/09: I don't understand why they'd want trig interpolation between angles instead of linear
//forwardWeight = cos( yaw );
//leftWeight = sin( yaw );

forwardWeight = (90 - abs(yaw)) / 90;
leftWeight = (90 - AbsAngleClamp180(abs(yaw-90))) / 90;

result["front"] = 0;
result["right"] = 0;
result["back"] = 0;
result["left"] = 0;

if ( IsDefined( self.alwaysRunForward ) )
{
assert( self.alwaysRunForward ); // always set alwaysRunForward to either true or undefined.

result["front"] = 1;
return result;
}

useLeans = GetDvarInt( #"ai_useLeanRunAnimations");

if (forwardWeight > 0)
{
result["front"] = forwardWeight;

if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else if( useLeans )
{
result["back"] = -1 * forwardWeight;
if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else //cod4 back strafe
{
// if moving backwards, don't blend.
// it looks horrible because the feet cycle in the opposite direction.
// either way, feet slide, but this looks better.
backWeight = -1 * forwardWeight;
if ( leftWeight > backWeight )
{
result["left"] = 1;
}
else if ( leftWeight < forwardWeight )
{
result["right"] = 1;
}
else
{
result["back"] = 1;
}
}


return result;
}

getQuadrant(angle)
{
angle = AngleClamp(angle);

if (angle<45 || angle>315)
{
quadrant = "front";
}
else if (angle<135)
{
quadrant = "left";
}
else if (angle<225)
{
quadrant = "back";
}
else
{
quadrant = "right";
}
return quadrant;
}


// Checks to see if the input is equal to any of up to ten other inputs.
IsInSet(input, set)
{
for (i = set.size - 1; i >= 0; i--)
{
if (input == set[i])
{
return true;
}
}

return false;
}

playAnim(animation)
{
if (IsDefined(animation))
{
//self thread drawString(animation); // Doesn't work for animations, only strings.
println ("NOW PLAYING: ",animation);
self SetFlaggedAnimKnobAllRestart("playAnim", animation, %root, 1, .2, 1);
timeToWait = getanimlength(animation);
timeToWait = ( 3 * timeToWait ) + 1; // So looping animations play through 3 times.
self thread NotifyAfterTime("time is up", "time is up", timeToWait);
self waittill ("time is up");
self notify("enddrawstring");
}
}

NotifyAfterTime(notifyString, killmestring, time)
{
self endon("death");
self endon(killmestring);
wait time;
self notify (notifyString);
}

// Utility function, made for MilestoneAnims(), which displays a string until killed.
drawString(stringtodraw)
{
self endon("killanimscript");
self endon("enddrawstring");
for (;;)
{
wait .05;
Print3d ((self GetDebugEye()) + (0,0,8), stringtodraw, (1, 1, 1), 1, 0.2);
}
}

drawStringTime(msg, org, color, timer)
{
maxtime = timer*20;
for (i=0;i<maxtime;i++)
{
Print3d (org, msg, color, 1, 1);
wait .05;
}
}

showLastEnemySightPos(string)
{
self notify ("got known enemy2");
self endon ("got known enemy2");
self endon ("death");

if ( !isValidEnemy( self.enemy ) )
{
return;
}

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);

if (!IsDefined (self.lastEnemySightPos))
{
continue;
}

Print3d (self.lastEnemySightPos, string, color, 1, 2.15); // origin, text, RGB, alpha, scale
}
}

/#
printDebugTextProc (string, org, printTime, color)
{
level notify ("stop debug print " + org);
level endon ("stop debug print " + org);

if (!IsDefined (color))
{
color = (0.3,0.9,0.6);
}

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
Print3d (org, string, color, 1, 1); // origin, text, RGB, alpha, scale
}
}

printDebugText (string, org, printTime, color)
{
if (GetDebugDvar ("anim_debug") != "")
{
level thread printDebugTextProc(string, org, printTime, color);
}
}
#/

tryTurret (targetname)
{
turret = getent (targetname, "targetname");
if (!IsDefined (turret))
{
return false;
}

if ((turret.classname != "misc_mg42") && (turret.classname != "misc_turret"))
{
return false;
}

if ( !self IsInGoal(self.covernode.origin))
{
return false;
}

canuse = self useturret(turret); // dude should be near the mg42
if ( canuse )
{
turret setmode("auto_ai"); // auto, auto_ai, manual
self thread maps\_mgturret::mg42_firing(turret);
turret notify ("startfiring");
return true;
}
else
{
return false;
}
}

debugTimeout()
{
wait(5);
self notify ("timeout");
}

debugPosInternal( org, string, size )
{
self endon ("death");
self notify ("stop debug " + org);
self endon ("stop debug " + org);

ent = SpawnStruct();
ent thread debugTimeout();
ent endon ("timeout");

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);
Print3d (org, string, color, 1, size); // origin, text, RGB, alpha, scale
}
}

debugPos( org, string )
{
thread debugPosInternal( org, string, 2.15 );
}

debugPosSize( org, string, size )
{
thread debugPosInternal( org, string, size );
}

showDebugProc(fromPoint, toPoint, color, printTime)
{
self endon ("death");
// self notify ("stop debugline " + self.export);
// self endon ("stop debugline " + self.export);

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
line (fromPoint, toPoint, color);
}
}

showDebugLine( fromPoint, toPoint, color, printTime )
{
self thread showDebugProc( fromPoint, toPoint +( 0, 0, -5 ), color, printTime );
}

setEnv(env)
{
anim.idleAnimTransition [ "stand" ][ "in" ] = %casual_stand_idle_trans_in;
// anim.idleAnimTransition [ "stand" ][ "out" ] = %casual_stand_idle_trans_out;

anim.idleAnimArray [ "stand" ][ 0 ][ 0 ] = %casual_stand_idle;
anim.idleAnimArray [ "stand" ][ 0 ][ 1 ] = %casual_stand_idle_twitch;
anim.idleAnimArray [ "stand" ][ 0 ][ 2 ] = %casual_stand_idle_twitchB;
anim.idleAnimWeights [ "stand" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand" ][ 0 ][ 1 ] = 1;
anim.idleAnimWeights [ "stand" ][ 0 ][ 2 ] = 1;

anim.idleAnimArray [ "stand" ][ 1 ][ 0 ] = %casual_stand_v2_idle;
anim.idleAnimArray [ "stand" ][ 1 ][ 1 ] = %casual_stand_v2_twitch_radio;
anim.idleAnimArray [ "stand" ][ 1 ][ 2 ] = %casual_stand_v2_twitch_shift;
anim.idleAnimArray [ "stand" ][ 1 ][ 3 ] = %casual_stand_v2_twitch_talk;
anim.idleAnimWeights [ "stand" ][ 1 ][ 0 ] = 10;
anim.idleAnimWeights [ "stand" ][ 1 ][ 1 ] = 4;
anim.idleAnimWeights [ "stand" ][ 1 ][ 2 ] = 7;
anim.idleAnimWeights [ "stand" ][ 1 ][ 3 ] = 4;

anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 1 ] = 1;

anim.idleAnimTransition [ "crouch" ][ "in" ] = %casual_crouch_idle_in;
// anim.idleAnimTransition [ "crouch" ][ "out" ] = %casual_crouch_idle_out;

anim.idleAnimArray [ "crouch" ][ 0 ][ 0 ] = %casual_crouch_idle;
anim.idleAnimArray [ "crouch" ][ 0 ][ 1 ] = %casual_crouch_twitch;
anim.idleAnimArray [ "crouch" ][ 0 ][ 2 ] = %casual_crouch_point;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 0 ] = 6;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 2 ] = 1;

// MikeD (1/24/2008): Banzai Feature Added
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 1 ] = 1;

// SCRIPTER_MOD: JesseS (4/16/2008): HMG anims added
anim.idleAnimTransition [ "stand_hmg" ][ "in" ] = %ai_mg_shoulder_run2stand;
anim.idleAnimArray [ "stand_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_stand_idle;
anim.idleAnimWeights [ "stand_hmg" ][ 0 ][ 0 ] = 1;

anim.idleAnimTransition [ "crouch_hmg" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "crouch_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_crouch_idle;
anim.idleAnimWeights [ "crouch_hmg" ][ 0 ][ 0 ] = 1;

//anim.idleAnimTransition [ "stand_flame" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 0 ] = %ai_flamethrower_stand_idle_casual_v1;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 1 ] = %ai_flamethrower_stand_twitch;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 1 ] = 1;

anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 0 ] = %ai_flamethrower_crouch_idle_a;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 1 ] = %ai_flamethrower_crouch_idle_b;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 2 ] = %ai_flamethrower_crouch_twitch;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 2 ] = 1;

if (env == "cold")
{
array_thread(GetAIArray(),::PersonalColdBreath);
array_thread(getspawnerarray(),::PersonalColdBreathSpawner);
}
}

PersonalColdBreath()
{
tag = "TAG_EYE";

self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
if (self.a.movement != "run")
{
playfxOnTag ( level._effect["cold_breath"], self, tag );
wait (2.5 + RandomFloat(3));
}
else
{
wait (0.5);
}
}
}

PersonalColdBreathSpawner()
{
self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
self waittill ("spawned", Spawn);
if (maps\_utility::spawn_failed(Spawn))
{
continue;
}

Spawn thread PersonalColdBreath();
}
}

getNodeOffset(node)
{
if ( IsDefined( node.offset ) )
{
return node.offset;
}

//(right offset, forward offset, vertical offset)
// you can get an actor's current eye offset by setting scr_eyeoffset to his entnum.
// this should be redone whenever animations change significantly.
cover_left_crouch_offset = (-26, .4, 36);
cover_left_stand_offset = (-32, 7, 63);
cover_right_crouch_offset = (43.5, 11, 36);
cover_right_stand_offset = (36, 8.3, 63);
cover_crouch_offset = (3.5, -12.5, 45); // maybe we could account for the fact that in cover crouch he can stand if he needs to?
cover_stand_offset = (-3.7, -22, 63);

cornernode = false;
nodeOffset = (0,0,0);

right = AnglesToRight(node.angles);
forward = AnglesToForward(node.angles);

switch(node.type)
{
case "Cover Left":
case "Cover Left Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_stand_offset );
}
break;

case "Cover Right":
case "Cover Right Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_stand_offset );
}
break;

case "Cover Stand":
case "Conceal Stand":
case "Turret":
nodeOffset = calculateNodeOffset( right, forward, cover_stand_offset );
break;

case "Cover Crouch":
case "Cover Crouch Window":
case "Conceal Crouch":
nodeOffset = calculateNodeOffset( right, forward, cover_crouch_offset );
break;
}

node.offset = nodeOffset;
return node.offset;
}

calculateNodeOffset( right, forward, baseoffset )
{
return vector_scale( right, baseoffset[0] ) + vector_scale( forward, baseoffset[1] ) + (0, 0, baseoffset[2]);
}

checkPitchVisibility( fromPoint, toPoint, atNode )
{
// check vertical angle is within our aiming abilities

pitch = AngleClamp180( VectorToAngles( toPoint - fromPoint )[0] );
if ( abs( pitch ) > 45 )
{
if ( IsDefined( atNode ) && atNode.type != "Cover Crouch" && atNode.type != "Conceal Crouch" )
{
return false;
}

if ( pitch > 45 || pitch < anim.coverCrouchLeanPitch - 45 )
{
return false;
}
}
return true;
}

showLines(start, end, end2)
{
for (;;)
{
line(start, end, (1,0,0), 1);
wait (0.05);
line(start, end2, (0,0,1), 1);
wait (0.05);
}
}

// Returns an animation from an array of animations with a corresponding array of weights.
anim_array(animArray, animWeights)
{
total_anims = animArray.size;
idleanim = RandomInt(total_anims);

assert (total_anims);
assert (animArray.size == animWeights.size);

if (total_anims == 1)
{
return animArray[0];
}

weights = 0;
total_weight = 0;

for (i = 0; i < total_anims; i++)
{
total_weight += animWeights[i];
}

anim_play = RandomFloat(total_weight);
current_weight = 0;

for (i = 0; i < total_anims; i++)
{
current_weight += animWeights[i];
if (anim_play >= current_weight)
{
continue;
}

idleanim = i;
break;
}

return animArray[idleanim];
}

notForcedCover()
{
return ((self.a.forced_cover == "none") || (self.a.forced_cover == "Show"));
}

forcedCover(msg)
{
return IsDefined(self.a.forced_cover) && (self.a.forced_cover == msg);
}

print3dtime(timer, org, msg, color, alpha, scale)
{
newtime = timer / 0.05;
for (i=0;i<newtime;i++)
{
Print3d (org, msg, color, alpha, scale);
wait (0.05);
}
}

print3drise (org, msg, color, alpha, scale)
{
newtime = 5 / 0.05;
up = 0;
org = org + randomvector(30);

for (i=0;i<newtime;i++)
{
up+=0.5;
Print3d (org + (0,0,up), msg, color, alpha, scale);
wait (0.05);
}
}

crossproduct (vec1, vec2)
{
return (vec1[0]*vec2[1] - vec1[1]*vec2[0] > 0);
}

scriptChange()
{
self.a.current_script = "none";
self notify (anim.scriptChange);
}

delayedScriptChange()
{
wait (0.05);
scriptChange();
}

getGrenadeModel()
{
return getWeaponModel(self.grenadeweapon);
}

sawEnemyMove(timer)
{
if (!IsDefined(timer))
{
timer = 500;
}

return (GetTime() - self.personalSightTime < timer);
}

canThrowGrenade()
{
if (!self.grenadeAmmo)
{
return false;
}

if (self.script_forceGrenade)
{
return true;
}

return (IsPlayer(self.enemy));
}

random_weight (array)
{
idleanim = RandomInt (array.size);
if (array.size > 1)
{
anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
}

anim_play = RandomFloat (anim_weight);

anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
if (anim_play < anim_weight)
{
idleanim = i;
break;
}
}
}

return idleanim;
}

removeableHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

if (IsDefined(anim.noHatClassname[self.classname]))
{
return false;
}

return (!IsDefined(anim.noHat[self.model]));
}

metalHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

return (IsDefined(anim.metalHat[self.model]));
}

fatGuy()
{
return (IsDefined(anim.fatGuy[self.model]));
}

setFootstepEffect(name, fx)
{
assertEx(IsDefined(name), "Need to define the footstep surface type.");
assertEx(IsDefined(fx), "Need to define the mud footstep effect.");

if (!IsDefined(anim.optionalStepEffects))
{
anim.optionalStepEffects = [];
}

anim.optionalStepEffects[anim.optionalStepEffects.size] = name;
level._effect["step_" + name] = fx;
anim.optionalStepEffectFunction = animscripts\zombie_shared::playFootStepEffect;
}

persistentDebugLine(start, end)
{
self endon ("death");
level notify ("newdebugline");
level endon ("newdebugline");

for (;;)
{
line (start,end, (0.3,1,0), 1);
wait (0.05);
}
}

isNodeDontStand()
{
return (self.spawnflags & 4) == 4;
}
isNodeDontCrouch()
{
return (self.spawnflags & 8) == 8;
}

doesNodeAllowStance( stance )
{
if ( stance == "stand" )
{
return !self isNodeDontStand();
}
else
{
Assert( stance == "crouch" );
return !self isNodeDontCrouch();
}
}

animArray( animname ) /* string */
{
//println( "playing anim: ", animname );

assert( IsDefined(self.a.array) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname];
}

animArrayAnyExist( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname].size > 0;
}

animArrayPickRandom( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

assert( self.a.array[animname].size > 0 );

if ( self.a.array[animname].size > 1 )
{
index = RandomInt( self.a.array[animname].size );
}
else
{
index = 0;
}

return self.a.array[animname][index];
}

/#
dumpAnimArray()
{
println("self.a.array:");
keys = getArrayKeys( self.a.array );

for ( i=0; i < keys.size; i++ )
{
if ( isarray( self.a.array[ keys[i] ] ) )
{
println( " array[ \"" + keys[i] + "\" ] = {array of size " + self.a.array[ keys[i] ].size + "}" );
}
else
{
println( " array[ \"" + keys[i] + "\" ] = ", self.a.array[ keys[i] ] );
}
}
}
#/

getAnimEndPos( theanim )
{
moveDelta = getMoveDelta( theanim, 0, 1 );
return self localToWorldCoords( moveDelta );
}

isValidEnemy( enemy )
{
if ( !IsDefined( enemy ) )
{
return false;
}

return true;
}


damageLocationIsAny( a, b, c, d, e, f, g, h, i, j, k, ovr )
{
/* possibile self.damageLocation's:
"torso_upper"
"torso_lower"
"helmet"
"head"
"neck"
"left_arm_upper"
"left_arm_lower"
"left_hand"
"right_arm_upper"
"right_arm_lower"
"right_hand"
"gun"
"none"
"left_leg_upper"
"left_leg_lower"
"left_foot"
"right_leg_upper"
"right_leg_lower"
"right_foot"
*/

if ( !IsDefined( a ) ) return false; if ( self.damageLocation == a ) return true;
if ( !IsDefined( b ) ) return false; if ( self.damageLocation == b ) return true;
if ( !IsDefined( c ) ) return false; if ( self.damageLocation == c ) return true;
if ( !IsDefined( d ) ) return false; if ( self.damageLocation == d ) return true;
if ( !IsDefined( e ) ) return false; if ( self.damageLocation == e ) return true;
if ( !IsDefined( f ) ) return false; if ( self.damageLocation == f ) return true;
if ( !IsDefined( g ) ) return false; if ( self.damageLocation == g ) return true;
if( !IsDefined( h ) ) return false; if( self.damageLocation == h ) return true;
if( !IsDefined( i ) ) return false; if( self.damageLocation == i ) return true;
if( !IsDefined( j ) ) return false; if( self.damageLocation == j ) return true;
if( !IsDefined( k ) ) return false; if( self.damageLocation == k ) return true;
assert(!IsDefined(ovr));
return false;
}

ragdollDeath( moveAnim )
{
self endon ( "killanimscript" );

lastOrg = self.origin;
moveVec = (0,0,0);

for ( ;; )
{
wait ( 0.05 );
force = distance( self.origin, lastOrg );
lastOrg = self.origin;

if ( self.health == 1 )
{
self.a.nodeath = true;
self startRagdoll();
self ClearAnim( moveAnim, 0.1 );
wait ( 0.05 );
physicsExplosionSphere( lastOrg, 600, 0, force * 0.1 );
self notify ( "killanimscript" );
return;
}

}
}

isCQBWalking()
{
return IsDefined( self.cqbwalking ) && self.cqbwalking;
}

squared( value )
{
return value * value;
}

randomizeIdleSet()
{
self.a.idleSet = RandomInt( 2 );
}

// meant to be used with any integer seed, for a small integer maximum (ideally one that divides anim.randomIntTableSize)
getRandomIntFromSeed( intSeed, intMax )
{
assert( intMax > 0 );

index = intSeed % anim.randomIntTableSize;
return anim.randomIntTable[ index ] % intMax;
}

// MikeD (1/24/2008): Added Banzai Feature.
is_banzai()
{
return IsDefined( self.banzai ) && self.banzai;
}

// SCRIPTER_MOD: JesseS (4/16/2008): HMG guys have their own anims
is_heavy_machine_gun()
{
return IsDefined( self.heavy_machine_gunner ) && self.heavy_machine_gunner;
}

is_zombie()
{
if (IsDefined(self.is_zombie) && self.is_zombie)
{
return true;
}

return false;
}


is_civilian()
{
if (IsDefined(self.is_civilian) && self.is_civilian)
{
return true;
}

return false;
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
is_zombie_gibbed()
{
return ( self is_zombie() && self.gibbed );
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
set_zombie_gibbed()
{
if ( self is_zombie() )
{
self.gibbed = true;
}
}

is_skeleton(skeleton)
{
if ((skeleton == "base") && IsSubStr(get_skeleton(), "scaled"))
{
// Scaled skeletons should identify as "base" as well
return true;
}

return (get_skeleton() == skeleton);
}

get_skeleton()
{
if (IsDefined(self.skeleton))
{
return self.skeleton;
}
else
{
return "base";
}
}

debug_anim_print( text )
{
/#
if ( level.dog_debug_anims )
println( text+ " " + getTime() );

if ( level.dog_debug_anims_ent == self getentnum() )
println( text+ " " + getTime() );
#/
}

debug_turn_print( text, line )
{
/#
if ( level.dog_debug_turns == self getentnum() )
{
duration = 200;
currentYawColor = (1,1,1);
lookaheadYawColor = (1,0,0);
desiredYawColor = (1,1,0);

currentYaw = AngleClamp180(self.angles[1]);
desiredYaw = AngleClamp180(self.desiredangle);
lookaheadDir = self.lookaheaddir;
lookaheadAngles = vectortoangles(lookaheadDir);
lookaheadYaw = AngleClamp180(lookaheadAngles[1]);
println( text+ " " + getTime() + " cur: " + currentYaw + " look: " + lookaheadYaw + " desired: " + desiredYaw );
}
#/
}

#32. Posted:
i13thstar
  • Ladder Climber
Status: Offline
Joined: Dec 07, 20109 Year Member
Posts: 349
Reputation Power: 13
temtam wroteHere is the entire "animscripts/zombie_utility" coding:


#include animscripts\zombie_SetPoseMovement;
#include animscripts\combat_utility;
#include animscripts\debug;
#include common_scripts\utility;
#include maps\_utility;

#using_animtree ("generic_human");

// Every script calls initAnimTree to ensure a clean, fresh, known animtree state.
// ClearAnim should never be called directly, and this should never occur other than
// at the start of an animscript
// This function now also does any initialization for the scripts that needs to happen
// at the beginning of every main script.
initAnimTree(animscript)
{
if ( isValidEnemy( self.a.personImMeleeing ) )
{
ImNotMeleeing( self.a.personImMeleeing );
}

self ClearAnim( %body, 0.2 );
//self SetAnim( %body, 1, 0 ); // The %body node should always have weight 1.

if ( animscript != "pain" && animscript != "death" )
{
self.a.special = "none";
}

self.missedSightChecks = 0;

IsInCombat();

assertEX( IsDefined( animscript ), "Animscript not specified in initAnimTree" );
self.a.script = animscript;

// Call the handler to get out of Cowering pose.
[[self.a.StopCowering]]();
}

// UpdateAnimPose does housekeeping at the start of every script's main function.
UpdateAnimPose()
{
assertEX( self.a.movement=="stop" || self.a.movement=="walk" || self.a.movement=="run", "UpdateAnimPose "+self.a.pose+" "+self.a.movement );

self.desired_anim_pose = undefined;
}

initialize( animscript )
{
if ( IsDefined( self.longDeathStarting ) )
{
if ( animscript != "pain" && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}
if ( animscript != "pain" )
{
self.longDeathStarting = undefined;
self notify( "kill_long_death" );
}
}
if ( IsDefined( self.a.mayOnlyDie ) && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}

// scripts can define this to allow cleanup before moving on
if ( IsDefined( self.a.postScriptFunc ) )
{
scriptFunc = self.a.postScriptFunc;
self.a.postScriptFunc = undefined;

[[scriptFunc]]( animscript );
}

if ( animscript != "death" )
{
self.a.nodeath = false;
}

if ( IsDefined( self.isHoldingGrenade ) && (animscript == "pain" || animscript == "death" || animscript == "flashed") )
{
self dropGrenade();
}

self.isHoldingGrenade = undefined;

/#
//thread checkGrenadeInHand( animscript );
#/

/#
if( IsDefined(self.a.script) && !self animscripts\debug::debugShouldClearState() )
{
self animscripts\debug::debugPopState( self.a.script );
}
else
{
self animscripts\debug::debugClearState();
}

self animscripts\debug::debugPushState( animscript );
#/

self.coverNode = undefined;
self.changingCoverPos = false;
self.a.scriptStartTime = GetTime();

self.a.atConcealmentNode = false;
if ( IsDefined( self.node ) && (self.node.type == "Conceal Crouch" || self.node.type == "Conceal Stand") )
{
self.a.atConcealmentNode = true;
}

initAnimTree( animscript );

UpdateAnimPose();
}

/#
checkGrenadeInHand( animscript )
{
// ensure no grenade left in hand
self endon("killanimscript");

// pain and death animscripts don't execute script between notifying killanimscript and starting the next animscript,
// so the grenade cleanup thread might still be waiting to run.
if ( animscript == "pain" || animscript == "death" )
{
wait .05;
waittillframeend;
}

attachSize = self getattachsize();
for ( i = 0; i < attachSize; i++ )
{
model = toLower( self getAttachModelName( i ) );
assertex( model != "weapon_m67_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_m84_flashbang_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_us_smoke_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
}
}
#/

should_find_a_new_node()
{
self.a.next_move_to_new_cover--;
if ( self.a.next_move_to_new_cover > 0 )
{
return false;
}

anim_set_next_move_to_new_cover();
return true;
}


badplacer(time, org, radius)
{
for (i=0;i<time*20;i++)
{
for (p=0;p<10;p++)
{
angles = (0,RandomInt(360),0);
forward = AnglesToForward(angles);
scale = vector_scale(forward, radius);
line (org, org + scale, (1,0.3,0.3));
}
wait(0.05);
}
}


printDisplaceInfo()
{
self endon ("death");
self notify ("displaceprint");
self endon ("displaceprint");

for (;;)
{
Print3d (self.origin + (0,0,60), "displacer", (0,0.4,0.7), 0.85, 0.5);
wait (0.05);
}
}


getOldRadius()
{
self notify ("newOldradius");
self endon ("newOldradius");
self endon ("death");
wait (6);
self.goalradius = self.a.oldgoalradius;
}

// Returns whether or not the character should be acting like he's under fire or expecting an enemy to appear
// any second.
IsInCombat()
{
if ( isValidEnemy( self.enemy ) )
{
self.a.combatEndTime = GetTime() + anim.combatMemoryTimeConst + RandomInt(anim.combatMemoryTimeRand);
return true;
}

return ( self.a.combatEndTime > GetTime() );
}

GetNodeYawToOrigin(pos)
{
if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
if (IsDefined (self.node))
{
forward = AnglesToForward(self.node.angles);
}
else
{
forward = AnglesToForward(self.angles);
}

forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.coverNode.angles + self.animarray["angle_step_out"][self.a.cornerMode]);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.CoverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToSpot(spot)
{
pos = spot;
yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}
// warning! returns (my yaw - yaw to enemy) instead of (yaw to enemy - my yaw)
GetYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.angles);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYaw(org)
{
angles = VectorToAngles(org-self.origin);
return angles[1];
}

GetYaw2d(org)
{
angles = VectorToAngles((org[0], org[1], 0)-(self.origin[0], self.origin[1], 0));
return angles[1];
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy2d()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw2d(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

AbsYawToAngles(angles)
{
yaw = self.angles[1] - angles;
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

GetYawFromOrigin(org, start)
{
angles = VectorToAngles(org-start);
return angles[1];
}

GetYawToTag(tag, org)
{
yaw = self GetTagAngles( tag )[1] - GetYawFromOrigin(org, self GetTagOrigin(tag));
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetEyeYawToOrigin(org)
{
yaw = self GetTagAngles("TAG_EYE")[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToOrigin(org)
{
yaw = self.coverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}


isStanceAllowedWrapper( stance )
{
if ( IsDefined( self.coverNode ) )
{
return self.coverNode doesNodeAllowStance( stance );
}

return self IsStanceAllowed( stance );
}


choosePose(preferredPose)
{
if ( !IsDefined( preferredPose ) )
{
preferredPose = self.a.pose;
}
if ( EnemiesWithinStandingRange() )
{
preferredPose = "stand";
}

// Find out if we should be standing or crouched
switch (preferredPose)
{
case "stand":
if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else
{
println ("No stance allowed! Remaining standing.");
resultPose = "stand";
}
break;

case "crouch":
if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else
{
println ("No stance allowed! Remaining crouched.");
resultPose = "crouch";
}
break;

default:
println ("utility::choosePose, called in "+self.a.script+" script: Unhandled anim_pose "+self.a.pose+" - using stand.");
resultPose = "stand";
break;
}
return resultPose;
}

// Melee stuff. Note that IsAlive is better than IsDefined when you're checking variables that are either
// undefined or set to an AI.
okToMelee(person)
{
assert( IsDefined( person ) );
if (IsDefined(self.a.personImMeleeing)) // Tried to melee someone else when I am already meleeing, possibly because code changed my enemy.
{
ImNotMeleeing(self.a.personImMeleeing);
assert(!IsDefined(self.a.personImMeleeing));
}

if (IsDefined(person.a.personMeleeingMe))
{
// This means that oldAttacker was the last person to melee person. He may or may not still be meleeing him.
oldAttacker = person.a.personMeleeingMe;
if ( IsDefined(oldAttacker.a.personImMeleeing) && oldAttacker.a.personImMeleeing == person )
{
// This means that oldAttacker is currently meleeing person.
return false;
}
println("okToMelee - Shouldn't get to here");
// This means that oldAttacker is no longer meleeing person and somehow person was never informed. We can still handle it though.
person.a.personMeleeingMe = undefined;
assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

IAmMeleeing(person)
{
assert(IsDefined(person));
assert(!IsDefined(person.a.personMeleeingMe));
assert(!IsDefined(self.a.personImMeleeing));
person.a.personMeleeingMe = self;
self.a.personImMeleeing = person;
}

ImNotMeleeing(person)
{
// First check that everything is in synch, just for my own peace of mind. This can go away once there are no bugs.
if ( (IsDefined(person)) && (IsDefined(self.a.personImMeleeing)) && (self.a.personImMeleeing==person) )
{
assert(IsDefined(person.a.personMeleeingMe));
assert(person.a.personMeleeingMe == self);
}
// This function does not require that I was meleeing Person to start with.
if (!IsDefined(person))
{
self.a.personImMeleeing = undefined;
}
else if ( (IsDefined(person.a.personMeleeingMe)) && (person.a.personMeleeingMe==self) )
{
person.a.personMeleeingMe = undefined;
assert(self.a.personImMeleeing==person);
self.a.personImMeleeing = undefined;
}
// A final check that I got this right...
assert( !IsDefined(person) || !IsDefined(self.a.personImMeleeing) || (self.a.personImMeleeing!=person) );
assert( !IsDefined(person) || !IsDefined(person.a.personMeleeingMe) || (person.a.personMeleeingMe!=self) );
}

GetClaimedNode()
{
myNode = self.node;
if ( IsDefined(myNode) && (self nearNode(myNode) || (IsDefined( self.coverNode ) && myNode == self.coverNode)) )
{
return myNode;
}

return undefined;
}

GetNodeType()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.type;
}

return "none";
}

GetNodeDirection()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
//thread [[anim.println]]("GetNodeDirection found node, returned: "+myNode.angles[1]);#/
return myNode.angles[1];
}
//thread [[anim.println]]("GetNodeDirection didn't find node, returned: "+self.desiredAngle);#/
return self.desiredAngle;
}

GetNodeForward()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return AnglesToForward ( myNode.angles );
}

return AnglesToForward( self.angles );
}

GetNodeOrigin()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.origin;
}

return self.origin;
}

safemod(a,b)
{
/*
Here are some modulus results from in-game:
10 % 3 = 1
10 % -3 = 1
-10 % 3 = -1
-10 % -3 = -1
however, we never want a negative result.
*/
result = int(a) % b;
result += b;
return result % b;
}

// Gives the result as an angle between 0 and 360
AngleClamp( angle )
{
angleFrac = angle / 360.0;
angle = (angleFrac - floor( angleFrac )) * 360.0;
return angle;
}

// Returns an array of 4 weights (2 of which are guaranteed to be 0), which should be applied to forward,
// right, back and left animations to get the angle specified.
// front
// /----|----\
// / 180 \
// /\ | /\
// / -135 | 135 \
// | \ | / |
// left|-90----+----90-|right
// | / | \ |
// \ -45 | 45 /
// \/ | \/
// \ 0 /
// \----|----/
// back

QuadrantAnimWeights( yaw )
{
// ALEXP 6/26/09: I don't understand why they'd want trig interpolation between angles instead of linear
//forwardWeight = cos( yaw );
//leftWeight = sin( yaw );

forwardWeight = (90 - abs(yaw)) / 90;
leftWeight = (90 - AbsAngleClamp180(abs(yaw-90))) / 90;

result["front"] = 0;
result["right"] = 0;
result["back"] = 0;
result["left"] = 0;

if ( IsDefined( self.alwaysRunForward ) )
{
assert( self.alwaysRunForward ); // always set alwaysRunForward to either true or undefined.

result["front"] = 1;
return result;
}

useLeans = GetDvarInt( #"ai_useLeanRunAnimations");

if (forwardWeight > 0)
{
result["front"] = forwardWeight;

if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else if( useLeans )
{
result["back"] = -1 * forwardWeight;
if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else //cod4 back strafe
{
// if moving backwards, don't blend.
// it looks horrible because the feet cycle in the opposite direction.
// either way, feet slide, but this looks better.
backWeight = -1 * forwardWeight;
if ( leftWeight > backWeight )
{
result["left"] = 1;
}
else if ( leftWeight < forwardWeight )
{
result["right"] = 1;
}
else
{
result["back"] = 1;
}
}


return result;
}

getQuadrant(angle)
{
angle = AngleClamp(angle);

if (angle<45 || angle>315)
{
quadrant = "front";
}
else if (angle<135)
{
quadrant = "left";
}
else if (angle<225)
{
quadrant = "back";
}
else
{
quadrant = "right";
}
return quadrant;
}


// Checks to see if the input is equal to any of up to ten other inputs.
IsInSet(input, set)
{
for (i = set.size - 1; i >= 0; i--)
{
if (input == set[i])
{
return true;
}
}

return false;
}

playAnim(animation)
{
if (IsDefined(animation))
{
//self thread drawString(animation); // Doesn't work for animations, only strings.
println ("NOW PLAYING: ",animation);
self SetFlaggedAnimKnobAllRestart("playAnim", animation, %root, 1, .2, 1);
timeToWait = getanimlength(animation);
timeToWait = ( 3 * timeToWait ) + 1; // So looping animations play through 3 times.
self thread NotifyAfterTime("time is up", "time is up", timeToWait);
self waittill ("time is up");
self notify("enddrawstring");
}
}

NotifyAfterTime(notifyString, killmestring, time)
{
self endon("death");
self endon(killmestring);
wait time;
self notify (notifyString);
}

// Utility function, made for MilestoneAnims(), which displays a string until killed.
drawString(stringtodraw)
{
self endon("killanimscript");
self endon("enddrawstring");
for (;;)
{
wait .05;
Print3d ((self GetDebugEye()) + (0,0,8), stringtodraw, (1, 1, 1), 1, 0.2);
}
}

drawStringTime(msg, org, color, timer)
{
maxtime = timer*20;
for (i=0;i<maxtime;i++)
{
Print3d (org, msg, color, 1, 1);
wait .05;
}
}

showLastEnemySightPos(string)
{
self notify ("got known enemy2");
self endon ("got known enemy2");
self endon ("death");

if ( !isValidEnemy( self.enemy ) )
{
return;
}

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);

if (!IsDefined (self.lastEnemySightPos))
{
continue;
}

Print3d (self.lastEnemySightPos, string, color, 1, 2.15); // origin, text, RGB, alpha, scale
}
}

/#
printDebugTextProc (string, org, printTime, color)
{
level notify ("stop debug print " + org);
level endon ("stop debug print " + org);

if (!IsDefined (color))
{
color = (0.3,0.9,0.6);
}

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
Print3d (org, string, color, 1, 1); // origin, text, RGB, alpha, scale
}
}

printDebugText (string, org, printTime, color)
{
if (GetDebugDvar ("anim_debug") != "")
{
level thread printDebugTextProc(string, org, printTime, color);
}
}
#/

tryTurret (targetname)
{
turret = getent (targetname, "targetname");
if (!IsDefined (turret))
{
return false;
}

if ((turret.classname != "misc_mg42") && (turret.classname != "misc_turret"))
{
return false;
}

if ( !self IsInGoal(self.covernode.origin))
{
return false;
}

canuse = self useturret(turret); // dude should be near the mg42
if ( canuse )
{
turret setmode("auto_ai"); // auto, auto_ai, manual
self thread maps\_mgturret::mg42_firing(turret);
turret notify ("startfiring");
return true;
}
else
{
return false;
}
}

debugTimeout()
{
wait(5);
self notify ("timeout");
}

debugPosInternal( org, string, size )
{
self endon ("death");
self notify ("stop debug " + org);
self endon ("stop debug " + org);

ent = SpawnStruct();
ent thread debugTimeout();
ent endon ("timeout");

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);
Print3d (org, string, color, 1, size); // origin, text, RGB, alpha, scale
}
}

debugPos( org, string )
{
thread debugPosInternal( org, string, 2.15 );
}

debugPosSize( org, string, size )
{
thread debugPosInternal( org, string, size );
}

showDebugProc(fromPoint, toPoint, color, printTime)
{
self endon ("death");
// self notify ("stop debugline " + self.export);
// self endon ("stop debugline " + self.export);

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
line (fromPoint, toPoint, color);
}
}

showDebugLine( fromPoint, toPoint, color, printTime )
{
self thread showDebugProc( fromPoint, toPoint +( 0, 0, -5 ), color, printTime );
}

setEnv(env)
{
anim.idleAnimTransition [ "stand" ][ "in" ] = %casual_stand_idle_trans_in;
// anim.idleAnimTransition [ "stand" ][ "out" ] = %casual_stand_idle_trans_out;

anim.idleAnimArray [ "stand" ][ 0 ][ 0 ] = %casual_stand_idle;
anim.idleAnimArray [ "stand" ][ 0 ][ 1 ] = %casual_stand_idle_twitch;
anim.idleAnimArray [ "stand" ][ 0 ][ 2 ] = %casual_stand_idle_twitchB;
anim.idleAnimWeights [ "stand" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand" ][ 0 ][ 1 ] = 1;
anim.idleAnimWeights [ "stand" ][ 0 ][ 2 ] = 1;

anim.idleAnimArray [ "stand" ][ 1 ][ 0 ] = %casual_stand_v2_idle;
anim.idleAnimArray [ "stand" ][ 1 ][ 1 ] = %casual_stand_v2_twitch_radio;
anim.idleAnimArray [ "stand" ][ 1 ][ 2 ] = %casual_stand_v2_twitch_shift;
anim.idleAnimArray [ "stand" ][ 1 ][ 3 ] = %casual_stand_v2_twitch_talk;
anim.idleAnimWeights [ "stand" ][ 1 ][ 0 ] = 10;
anim.idleAnimWeights [ "stand" ][ 1 ][ 1 ] = 4;
anim.idleAnimWeights [ "stand" ][ 1 ][ 2 ] = 7;
anim.idleAnimWeights [ "stand" ][ 1 ][ 3 ] = 4;

anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 1 ] = 1;

anim.idleAnimTransition [ "crouch" ][ "in" ] = %casual_crouch_idle_in;
// anim.idleAnimTransition [ "crouch" ][ "out" ] = %casual_crouch_idle_out;

anim.idleAnimArray [ "crouch" ][ 0 ][ 0 ] = %casual_crouch_idle;
anim.idleAnimArray [ "crouch" ][ 0 ][ 1 ] = %casual_crouch_twitch;
anim.idleAnimArray [ "crouch" ][ 0 ][ 2 ] = %casual_crouch_point;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 0 ] = 6;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 2 ] = 1;

// MikeD (1/24/2008): Banzai Feature Added
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 1 ] = 1;

// SCRIPTER_MOD: JesseS (4/16/2008): HMG anims added
anim.idleAnimTransition [ "stand_hmg" ][ "in" ] = %ai_mg_shoulder_run2stand;
anim.idleAnimArray [ "stand_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_stand_idle;
anim.idleAnimWeights [ "stand_hmg" ][ 0 ][ 0 ] = 1;

anim.idleAnimTransition [ "crouch_hmg" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "crouch_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_crouch_idle;
anim.idleAnimWeights [ "crouch_hmg" ][ 0 ][ 0 ] = 1;

//anim.idleAnimTransition [ "stand_flame" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 0 ] = %ai_flamethrower_stand_idle_casual_v1;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 1 ] = %ai_flamethrower_stand_twitch;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 1 ] = 1;

anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 0 ] = %ai_flamethrower_crouch_idle_a;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 1 ] = %ai_flamethrower_crouch_idle_b;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 2 ] = %ai_flamethrower_crouch_twitch;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 2 ] = 1;

if (env == "cold")
{
array_thread(GetAIArray(),::PersonalColdBreath);
array_thread(getspawnerarray(),::PersonalColdBreathSpawner);
}
}

PersonalColdBreath()
{
tag = "TAG_EYE";

self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
if (self.a.movement != "run")
{
playfxOnTag ( level._effect["cold_breath"], self, tag );
wait (2.5 + RandomFloat(3));
}
else
{
wait (0.5);
}
}
}

PersonalColdBreathSpawner()
{
self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
self waittill ("spawned", Spawn);
if (maps\_utility::spawn_failed(Spawn))
{
continue;
}

Spawn thread PersonalColdBreath();
}
}

getNodeOffset(node)
{
if ( IsDefined( node.offset ) )
{
return node.offset;
}

//(right offset, forward offset, vertical offset)
// you can get an actor's current eye offset by setting scr_eyeoffset to his entnum.
// this should be redone whenever animations change significantly.
cover_left_crouch_offset = (-26, .4, 36);
cover_left_stand_offset = (-32, 7, 63);
cover_right_crouch_offset = (43.5, 11, 36);
cover_right_stand_offset = (36, 8.3, 63);
cover_crouch_offset = (3.5, -12.5, 45); // maybe we could account for the fact that in cover crouch he can stand if he needs to?
cover_stand_offset = (-3.7, -22, 63);

cornernode = false;
nodeOffset = (0,0,0);

right = AnglesToRight(node.angles);
forward = AnglesToForward(node.angles);

switch(node.type)
{
case "Cover Left":
case "Cover Left Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_stand_offset );
}
break;

case "Cover Right":
case "Cover Right Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_stand_offset );
}
break;

case "Cover Stand":
case "Conceal Stand":
case "Turret":
nodeOffset = calculateNodeOffset( right, forward, cover_stand_offset );
break;

case "Cover Crouch":
case "Cover Crouch Window":
case "Conceal Crouch":
nodeOffset = calculateNodeOffset( right, forward, cover_crouch_offset );
break;
}

node.offset = nodeOffset;
return node.offset;
}

calculateNodeOffset( right, forward, baseoffset )
{
return vector_scale( right, baseoffset[0] ) + vector_scale( forward, baseoffset[1] ) + (0, 0, baseoffset[2]);
}

checkPitchVisibility( fromPoint, toPoint, atNode )
{
// check vertical angle is within our aiming abilities

pitch = AngleClamp180( VectorToAngles( toPoint - fromPoint )[0] );
if ( abs( pitch ) > 45 )
{
if ( IsDefined( atNode ) && atNode.type != "Cover Crouch" && atNode.type != "Conceal Crouch" )
{
return false;
}

if ( pitch > 45 || pitch < anim.coverCrouchLeanPitch - 45 )
{
return false;
}
}
return true;
}

showLines(start, end, end2)
{
for (;;)
{
line(start, end, (1,0,0), 1);
wait (0.05);
line(start, end2, (0,0,1), 1);
wait (0.05);
}
}

// Returns an animation from an array of animations with a corresponding array of weights.
anim_array(animArray, animWeights)
{
total_anims = animArray.size;
idleanim = RandomInt(total_anims);

assert (total_anims);
assert (animArray.size == animWeights.size);

if (total_anims == 1)
{
return animArray[0];
}

weights = 0;
total_weight = 0;

for (i = 0; i < total_anims; i++)
{
total_weight += animWeights[i];
}

anim_play = RandomFloat(total_weight);
current_weight = 0;

for (i = 0; i < total_anims; i++)
{
current_weight += animWeights[i];
if (anim_play >= current_weight)
{
continue;
}

idleanim = i;
break;
}

return animArray[idleanim];
}

notForcedCover()
{
return ((self.a.forced_cover == "none") || (self.a.forced_cover == "Show"));
}

forcedCover(msg)
{
return IsDefined(self.a.forced_cover) && (self.a.forced_cover == msg);
}

print3dtime(timer, org, msg, color, alpha, scale)
{
newtime = timer / 0.05;
for (i=0;i<newtime;i++)
{
Print3d (org, msg, color, alpha, scale);
wait (0.05);
}
}

print3drise (org, msg, color, alpha, scale)
{
newtime = 5 / 0.05;
up = 0;
org = org + randomvector(30);

for (i=0;i<newtime;i++)
{
up+=0.5;
Print3d (org + (0,0,up), msg, color, alpha, scale);
wait (0.05);
}
}

crossproduct (vec1, vec2)
{
return (vec1[0]*vec2[1] - vec1[1]*vec2[0] > 0);
}

scriptChange()
{
self.a.current_script = "none";
self notify (anim.scriptChange);
}

delayedScriptChange()
{
wait (0.05);
scriptChange();
}

getGrenadeModel()
{
return getWeaponModel(self.grenadeweapon);
}

sawEnemyMove(timer)
{
if (!IsDefined(timer))
{
timer = 500;
}

return (GetTime() - self.personalSightTime < timer);
}

canThrowGrenade()
{
if (!self.grenadeAmmo)
{
return false;
}

if (self.script_forceGrenade)
{
return true;
}

return (IsPlayer(self.enemy));
}

random_weight (array)
{
idleanim = RandomInt (array.size);
if (array.size > 1)
{
anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
}

anim_play = RandomFloat (anim_weight);

anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
if (anim_play < anim_weight)
{
idleanim = i;
break;
}
}
}

return idleanim;
}

removeableHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

if (IsDefined(anim.noHatClassname[self.classname]))
{
return false;
}

return (!IsDefined(anim.noHat[self.model]));
}

metalHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

return (IsDefined(anim.metalHat[self.model]));
}

fatGuy()
{
return (IsDefined(anim.fatGuy[self.model]));
}

setFootstepEffect(name, fx)
{
assertEx(IsDefined(name), "Need to define the footstep surface type.");
assertEx(IsDefined(fx), "Need to define the mud footstep effect.");

if (!IsDefined(anim.optionalStepEffects))
{
anim.optionalStepEffects = [];
}

anim.optionalStepEffects[anim.optionalStepEffects.size] = name;
level._effect["step_" + name] = fx;
anim.optionalStepEffectFunction = animscripts\zombie_shared::playFootStepEffect;
}

persistentDebugLine(start, end)
{
self endon ("death");
level notify ("newdebugline");
level endon ("newdebugline");

for (;;)
{
line (start,end, (0.3,1,0), 1);
wait (0.05);
}
}

isNodeDontStand()
{
return (self.spawnflags & 4) == 4;
}
isNodeDontCrouch()
{
return (self.spawnflags & 8) == 8;
}

doesNodeAllowStance( stance )
{
if ( stance == "stand" )
{
return !self isNodeDontStand();
}
else
{
Assert( stance == "crouch" );
return !self isNodeDontCrouch();
}
}

animArray( animname ) /* string */
{
//println( "playing anim: ", animname );

assert( IsDefined(self.a.array) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname];
}

animArrayAnyExist( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname].size > 0;
}

animArrayPickRandom( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

assert( self.a.array[animname].size > 0 );

if ( self.a.array[animname].size > 1 )
{
index = RandomInt( self.a.array[animname].size );
}
else
{
index = 0;
}

return self.a.array[animname][index];
}

/#
dumpAnimArray()
{
println("self.a.array:");
keys = getArrayKeys( self.a.array );

for ( i=0; i < keys.size; i++ )
{
if ( isarray( self.a.array[ keys[i] ] ) )
{
println( " array[ \"" + keys[i] + "\" ] = {array of size " + self.a.array[ keys[i] ].size + "}" );
}
else
{
println( " array[ \"" + keys[i] + "\" ] = ", self.a.array[ keys[i] ] );
}
}
}
#/

getAnimEndPos( theanim )
{
moveDelta = getMoveDelta( theanim, 0, 1 );
return self localToWorldCoords( moveDelta );
}

isValidEnemy( enemy )
{
if ( !IsDefined( enemy ) )
{
return false;
}

return true;
}


damageLocationIsAny( a, b, c, d, e, f, g, h, i, j, k, ovr )
{
/* possibile self.damageLocation's:
"torso_upper"
"torso_lower"
"helmet"
"head"
"neck"
"left_arm_upper"
"left_arm_lower"
"left_hand"
"right_arm_upper"
"right_arm_lower"
"right_hand"
"gun"
"none"
"left_leg_upper"
"left_leg_lower"
"left_foot"
"right_leg_upper"
"right_leg_lower"
"right_foot"
*/

if ( !IsDefined( a ) ) return false; if ( self.damageLocation == a ) return true;
if ( !IsDefined( b ) ) return false; if ( self.damageLocation == b ) return true;
if ( !IsDefined( c ) ) return false; if ( self.damageLocation == c ) return true;
if ( !IsDefined( d ) ) return false; if ( self.damageLocation == d ) return true;
if ( !IsDefined( e ) ) return false; if ( self.damageLocation == e ) return true;
if ( !IsDefined( f ) ) return false; if ( self.damageLocation == f ) return true;
if ( !IsDefined( g ) ) return false; if ( self.damageLocation == g ) return true;
if( !IsDefined( h ) ) return false; if( self.damageLocation == h ) return true;
if( !IsDefined( i ) ) return false; if( self.damageLocation == i ) return true;
if( !IsDefined( j ) ) return false; if( self.damageLocation == j ) return true;
if( !IsDefined( k ) ) return false; if( self.damageLocation == k ) return true;
assert(!IsDefined(ovr));
return false;
}

ragdollDeath( moveAnim )
{
self endon ( "killanimscript" );

lastOrg = self.origin;
moveVec = (0,0,0);

for ( ;; )
{
wait ( 0.05 );
force = distance( self.origin, lastOrg );
lastOrg = self.origin;

if ( self.health == 1 )
{
self.a.nodeath = true;
self startRagdoll();
self ClearAnim( moveAnim, 0.1 );
wait ( 0.05 );
physicsExplosionSphere( lastOrg, 600, 0, force * 0.1 );
self notify ( "killanimscript" );
return;
}

}
}

isCQBWalking()
{
return IsDefined( self.cqbwalking ) && self.cqbwalking;
}

squared( value )
{
return value * value;
}

randomizeIdleSet()
{
self.a.idleSet = RandomInt( 2 );
}

// meant to be used with any integer seed, for a small integer maximum (ideally one that divides anim.randomIntTableSize)
getRandomIntFromSeed( intSeed, intMax )
{
assert( intMax > 0 );

index = intSeed % anim.randomIntTableSize;
return anim.randomIntTable[ index ] % intMax;
}

// MikeD (1/24/2008): Added Banzai Feature.
is_banzai()
{
return IsDefined( self.banzai ) && self.banzai;
}

// SCRIPTER_MOD: JesseS (4/16/2008): HMG guys have their own anims
is_heavy_machine_gun()
{
return IsDefined( self.heavy_machine_gunner ) && self.heavy_machine_gunner;
}

is_zombie()
{
if (IsDefined(self.is_zombie) && self.is_zombie)
{
return true;
}

return false;
}


is_civilian()
{
if (IsDefined(self.is_civilian) && self.is_civilian)
{
return true;
}

return false;
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
is_zombie_gibbed()
{
return ( self is_zombie() && self.gibbed );
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
set_zombie_gibbed()
{
if ( self is_zombie() )
{
self.gibbed = true;
}
}

is_skeleton(skeleton)
{
if ((skeleton == "base") && IsSubStr(get_skeleton(), "scaled"))
{
// Scaled skeletons should identify as "base" as well
return true;
}

return (get_skeleton() == skeleton);
}

get_skeleton()
{
if (IsDefined(self.skeleton))
{
return self.skeleton;
}
else
{
return "base";
}
}

debug_anim_print( text )
{
/#
if ( level.dog_debug_anims )
println( text+ " " + getTime() );

if ( level.dog_debug_anims_ent == self getentnum() )
println( text+ " " + getTime() );
#/
}

debug_turn_print( text, line )
{
/#
if ( level.dog_debug_turns == self getentnum() )
{
duration = 200;
currentYawColor = (1,1,1);
lookaheadYawColor = (1,0,0);
desiredYawColor = (1,1,0);

currentYaw = AngleClamp180(self.angles[1]);
desiredYaw = AngleClamp180(self.desiredangle);
lookaheadDir = self.lookaheaddir;
lookaheadAngles = vectortoangles(lookaheadDir);
lookaheadYaw = AngleClamp180(lookaheadAngles[1]);
println( text+ " " + getTime() + " cur: " + currentYaw + " look: " + lookaheadYaw + " desired: " + desiredYaw );
}
#/
}




nice one dude sadly its not this script. having a quick look this it's just the coding that controls the damange done to a player. do you have access to the other files maybe? also where did you manage to get this?

thanks for helping us out i13thSTAR
#33. Posted:
TTG_Glockyy
  • TTG Senior
Status: Offline
Joined: Jan 15, 20109 Year Member
Posts: 1,036
Reputation Power: 42
im so tired of this node theory its never gonna work ever ight just give up
#34. Posted:
i13thstar
  • Ladder Climber
Status: Offline
Joined: Dec 07, 20109 Year Member
Posts: 349
Reputation Power: 13
read the title you dick! its not a **** theory!!!
this topic is based on FACT found in the code!!!
#35. Posted:
RandomBox
  • TTG Senior
Status: Offline
Joined: Feb 12, 20118 Year Member
Posts: 1,034
Reputation Power: 45
The only relevant fact thus far is that sections of coding for HITSAM and HYENA are not yet present.
#36. Posted:
i13thstar
  • Ladder Climber
Status: Offline
Joined: Dec 07, 20109 Year Member
Posts: 349
Reputation Power: 13
.....? bumppppp bumpppppp bumppppppppppppp!*
#37. Posted:
temtam
  • Powerhouse
Status: Offline
Joined: Oct 18, 20109 Year Member
Posts: 429
Reputation Power: 16
i13thstar wrote
temtam wroteHere is the entire "animscripts/zombie_utility" coding:


#include animscripts\zombie_SetPoseMovement;
#include animscripts\combat_utility;
#include animscripts\debug;
#include common_scripts\utility;
#include maps\_utility;

#using_animtree ("generic_human");

// Every script calls initAnimTree to ensure a clean, fresh, known animtree state.
// ClearAnim should never be called directly, and this should never occur other than
// at the start of an animscript
// This function now also does any initialization for the scripts that needs to happen
// at the beginning of every main script.
initAnimTree(animscript)
{
if ( isValidEnemy( self.a.personImMeleeing ) )
{
ImNotMeleeing( self.a.personImMeleeing );
}

self ClearAnim( %body, 0.2 );
//self SetAnim( %body, 1, 0 ); // The %body node should always have weight 1.

if ( animscript != "pain" && animscript != "death" )
{
self.a.special = "none";
}

self.missedSightChecks = 0;

IsInCombat();

assertEX( IsDefined( animscript ), "Animscript not specified in initAnimTree" );
self.a.script = animscript;

// Call the handler to get out of Cowering pose.
[[self.a.StopCowering]]();
}

// UpdateAnimPose does housekeeping at the start of every script's main function.
UpdateAnimPose()
{
assertEX( self.a.movement=="stop" || self.a.movement=="walk" || self.a.movement=="run", "UpdateAnimPose "+self.a.pose+" "+self.a.movement );

self.desired_anim_pose = undefined;
}

initialize( animscript )
{
if ( IsDefined( self.longDeathStarting ) )
{
if ( animscript != "pain" && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}
if ( animscript != "pain" )
{
self.longDeathStarting = undefined;
self notify( "kill_long_death" );
}
}
if ( IsDefined( self.a.mayOnlyDie ) && animscript != "death" )
{
// we probably just came out of an animcustom.
// just die, it's not safe to do anything else
self DoDamage( self.health + 100, self.origin );
}

// scripts can define this to allow cleanup before moving on
if ( IsDefined( self.a.postScriptFunc ) )
{
scriptFunc = self.a.postScriptFunc;
self.a.postScriptFunc = undefined;

[[scriptFunc]]( animscript );
}

if ( animscript != "death" )
{
self.a.nodeath = false;
}

if ( IsDefined( self.isHoldingGrenade ) && (animscript == "pain" || animscript == "death" || animscript == "flashed") )
{
self dropGrenade();
}

self.isHoldingGrenade = undefined;

/#
//thread checkGrenadeInHand( animscript );
#/

/#
if( IsDefined(self.a.script) && !self animscripts\debug::debugShouldClearState() )
{
self animscripts\debug::debugPopState( self.a.script );
}
else
{
self animscripts\debug::debugClearState();
}

self animscripts\debug::debugPushState( animscript );
#/

self.coverNode = undefined;
self.changingCoverPos = false;
self.a.scriptStartTime = GetTime();

self.a.atConcealmentNode = false;
if ( IsDefined( self.node ) && (self.node.type == "Conceal Crouch" || self.node.type == "Conceal Stand") )
{
self.a.atConcealmentNode = true;
}

initAnimTree( animscript );

UpdateAnimPose();
}

/#
checkGrenadeInHand( animscript )
{
// ensure no grenade left in hand
self endon("killanimscript");

// pain and death animscripts don't execute script between notifying killanimscript and starting the next animscript,
// so the grenade cleanup thread might still be waiting to run.
if ( animscript == "pain" || animscript == "death" )
{
wait .05;
waittillframeend;
}

attachSize = self getattachsize();
for ( i = 0; i < attachSize; i++ )
{
model = toLower( self getAttachModelName( i ) );
assertex( model != "weapon_m67_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_m84_flashbang_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
assertex( model != "weapon_us_smoke_grenade", "AI has a grenade in hand after animscript finished. Please call over an animscripter! " + self.origin );
}
}
#/

should_find_a_new_node()
{
self.a.next_move_to_new_cover--;
if ( self.a.next_move_to_new_cover > 0 )
{
return false;
}

anim_set_next_move_to_new_cover();
return true;
}


badplacer(time, org, radius)
{
for (i=0;i<time*20;i++)
{
for (p=0;p<10;p++)
{
angles = (0,RandomInt(360),0);
forward = AnglesToForward(angles);
scale = vector_scale(forward, radius);
line (org, org + scale, (1,0.3,0.3));
}
wait(0.05);
}
}


printDisplaceInfo()
{
self endon ("death");
self notify ("displaceprint");
self endon ("displaceprint");

for (;;)
{
Print3d (self.origin + (0,0,60), "displacer", (0,0.4,0.7), 0.85, 0.5);
wait (0.05);
}
}


getOldRadius()
{
self notify ("newOldradius");
self endon ("newOldradius");
self endon ("death");
wait (6);
self.goalradius = self.a.oldgoalradius;
}

// Returns whether or not the character should be acting like he's under fire or expecting an enemy to appear
// any second.
IsInCombat()
{
if ( isValidEnemy( self.enemy ) )
{
self.a.combatEndTime = GetTime() + anim.combatMemoryTimeConst + RandomInt(anim.combatMemoryTimeRand);
return true;
}

return ( self.a.combatEndTime > GetTime() );
}

GetNodeYawToOrigin(pos)
{
if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
if (IsDefined (self.node))
{
forward = AnglesToForward(self.node.angles);
}
else
{
forward = AnglesToForward(self.angles);
}

forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

if (IsDefined (self.node))
{
yaw = self.node.angles[1] - GetYaw(pos);
}
else
{
yaw = self.angles[1] - GetYaw(pos);
}

yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.coverNode.angles + self.animarray["angle_step_out"][self.a.cornerMode]);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.CoverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToSpot(spot)
{
pos = spot;
yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}
// warning! returns (my yaw - yaw to enemy) instead of (yaw to enemy - my yaw)
GetYawToEnemy()
{
pos = undefined;
if ( isValidEnemy( self.enemy ) )
{
pos = self.enemy.origin;
}
else
{
forward = AnglesToForward(self.angles);
forward = vector_scale (forward, 150);
pos = self.origin + forward;
}

yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}

GetYaw(org)
{
angles = VectorToAngles(org-self.origin);
return angles[1];
}

GetYaw2d(org)
{
angles = VectorToAngles((org[0], org[1], 0)-(self.origin[0], self.origin[1], 0));
return angles[1];
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToEnemy2d()
{
assert( isValidEnemy( self.enemy ) );

yaw = self.angles[1] - GetYaw2d(self.enemy.origin);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

// 0 if I'm facing my enemy, 90 if I'm side on, 180 if I'm facing away.
AbsYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

AbsYawToAngles(angles)
{
yaw = self.angles[1] - angles;
yaw = AngleClamp180( yaw );

if (yaw < 0)
{
yaw = -1 * yaw;
}

return yaw;
}

GetYawFromOrigin(org, start)
{
angles = VectorToAngles(org-start);
return angles[1];
}

GetYawToTag(tag, org)
{
yaw = self GetTagAngles( tag )[1] - GetYawFromOrigin(org, self GetTagOrigin(tag));
yaw = AngleClamp180( yaw );
return yaw;
}

GetYawToOrigin(org)
{
yaw = self.angles[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetEyeYawToOrigin(org)
{
yaw = self GetTagAngles("TAG_EYE")[1] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}

GetCoverNodeYawToOrigin(org)
{
yaw = self.coverNode.angles[1] + self.animarray["angle_step_out"][self.a.cornerMode] - GetYaw(org);
yaw = AngleClamp180( yaw );
return yaw;
}


isStanceAllowedWrapper( stance )
{
if ( IsDefined( self.coverNode ) )
{
return self.coverNode doesNodeAllowStance( stance );
}

return self IsStanceAllowed( stance );
}


choosePose(preferredPose)
{
if ( !IsDefined( preferredPose ) )
{
preferredPose = self.a.pose;
}
if ( EnemiesWithinStandingRange() )
{
preferredPose = "stand";
}

// Find out if we should be standing or crouched
switch (preferredPose)
{
case "stand":
if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else
{
println ("No stance allowed! Remaining standing.");
resultPose = "stand";
}
break;

case "crouch":
if (self isStanceAllowedWrapper("crouch"))
{
resultPose = "crouch";
}
else if (self isStanceAllowedWrapper("stand"))
{
resultPose = "stand";
}
else
{
println ("No stance allowed! Remaining crouched.");
resultPose = "crouch";
}
break;

default:
println ("utility::choosePose, called in "+self.a.script+" script: Unhandled anim_pose "+self.a.pose+" - using stand.");
resultPose = "stand";
break;
}
return resultPose;
}

// Melee stuff. Note that IsAlive is better than IsDefined when you're checking variables that are either
// undefined or set to an AI.
okToMelee(person)
{
assert( IsDefined( person ) );
if (IsDefined(self.a.personImMeleeing)) // Tried to melee someone else when I am already meleeing, possibly because code changed my enemy.
{
ImNotMeleeing(self.a.personImMeleeing);
assert(!IsDefined(self.a.personImMeleeing));
}

if (IsDefined(person.a.personMeleeingMe))
{
// This means that oldAttacker was the last person to melee person. He may or may not still be meleeing him.
oldAttacker = person.a.personMeleeingMe;
if ( IsDefined(oldAttacker.a.personImMeleeing) && oldAttacker.a.personImMeleeing == person )
{
// This means that oldAttacker is currently meleeing person.
return false;
}
println("okToMelee - Shouldn't get to here");
// This means that oldAttacker is no longer meleeing person and somehow person was never informed. We can still handle it though.
person.a.personMeleeingMe = undefined;
assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

assert(!IsDefined(self.a.personImMeleeing));
assert(!IsDefined(person.a.personMeleeingMe));
return true;
}

IAmMeleeing(person)
{
assert(IsDefined(person));
assert(!IsDefined(person.a.personMeleeingMe));
assert(!IsDefined(self.a.personImMeleeing));
person.a.personMeleeingMe = self;
self.a.personImMeleeing = person;
}

ImNotMeleeing(person)
{
// First check that everything is in synch, just for my own peace of mind. This can go away once there are no bugs.
if ( (IsDefined(person)) && (IsDefined(self.a.personImMeleeing)) && (self.a.personImMeleeing==person) )
{
assert(IsDefined(person.a.personMeleeingMe));
assert(person.a.personMeleeingMe == self);
}
// This function does not require that I was meleeing Person to start with.
if (!IsDefined(person))
{
self.a.personImMeleeing = undefined;
}
else if ( (IsDefined(person.a.personMeleeingMe)) && (person.a.personMeleeingMe==self) )
{
person.a.personMeleeingMe = undefined;
assert(self.a.personImMeleeing==person);
self.a.personImMeleeing = undefined;
}
// A final check that I got this right...
assert( !IsDefined(person) || !IsDefined(self.a.personImMeleeing) || (self.a.personImMeleeing!=person) );
assert( !IsDefined(person) || !IsDefined(person.a.personMeleeingMe) || (person.a.personMeleeingMe!=self) );
}

GetClaimedNode()
{
myNode = self.node;
if ( IsDefined(myNode) && (self nearNode(myNode) || (IsDefined( self.coverNode ) && myNode == self.coverNode)) )
{
return myNode;
}

return undefined;
}

GetNodeType()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.type;
}

return "none";
}

GetNodeDirection()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
//thread [[anim.println]]("GetNodeDirection found node, returned: "+myNode.angles[1]);#/
return myNode.angles[1];
}
//thread [[anim.println]]("GetNodeDirection didn't find node, returned: "+self.desiredAngle);#/
return self.desiredAngle;
}

GetNodeForward()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return AnglesToForward ( myNode.angles );
}

return AnglesToForward( self.angles );
}

GetNodeOrigin()
{
myNode = GetClaimedNode();
if (IsDefined(myNode))
{
return myNode.origin;
}

return self.origin;
}

safemod(a,b)
{
/*
Here are some modulus results from in-game:
10 % 3 = 1
10 % -3 = 1
-10 % 3 = -1
-10 % -3 = -1
however, we never want a negative result.
*/
result = int(a) % b;
result += b;
return result % b;
}

// Gives the result as an angle between 0 and 360
AngleClamp( angle )
{
angleFrac = angle / 360.0;
angle = (angleFrac - floor( angleFrac )) * 360.0;
return angle;
}

// Returns an array of 4 weights (2 of which are guaranteed to be 0), which should be applied to forward,
// right, back and left animations to get the angle specified.
// front
// /----|----\
// / 180 \
// /\ | /\
// / -135 | 135 \
// | \ | / |
// left|-90----+----90-|right
// | / | \ |
// \ -45 | 45 /
// \/ | \/
// \ 0 /
// \----|----/
// back

QuadrantAnimWeights( yaw )
{
// ALEXP 6/26/09: I don't understand why they'd want trig interpolation between angles instead of linear
//forwardWeight = cos( yaw );
//leftWeight = sin( yaw );

forwardWeight = (90 - abs(yaw)) / 90;
leftWeight = (90 - AbsAngleClamp180(abs(yaw-90))) / 90;

result["front"] = 0;
result["right"] = 0;
result["back"] = 0;
result["left"] = 0;

if ( IsDefined( self.alwaysRunForward ) )
{
assert( self.alwaysRunForward ); // always set alwaysRunForward to either true or undefined.

result["front"] = 1;
return result;
}

useLeans = GetDvarInt( #"ai_useLeanRunAnimations");

if (forwardWeight > 0)
{
result["front"] = forwardWeight;

if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else if( useLeans )
{
result["back"] = -1 * forwardWeight;
if (leftWeight > 0)
{
result["left"] = leftWeight;
}
else
{
result["right"] = -1 * leftWeight;
}
}
else //cod4 back strafe
{
// if moving backwards, don't blend.
// it looks horrible because the feet cycle in the opposite direction.
// either way, feet slide, but this looks better.
backWeight = -1 * forwardWeight;
if ( leftWeight > backWeight )
{
result["left"] = 1;
}
else if ( leftWeight < forwardWeight )
{
result["right"] = 1;
}
else
{
result["back"] = 1;
}
}


return result;
}

getQuadrant(angle)
{
angle = AngleClamp(angle);

if (angle<45 || angle>315)
{
quadrant = "front";
}
else if (angle<135)
{
quadrant = "left";
}
else if (angle<225)
{
quadrant = "back";
}
else
{
quadrant = "right";
}
return quadrant;
}


// Checks to see if the input is equal to any of up to ten other inputs.
IsInSet(input, set)
{
for (i = set.size - 1; i >= 0; i--)
{
if (input == set[i])
{
return true;
}
}

return false;
}

playAnim(animation)
{
if (IsDefined(animation))
{
//self thread drawString(animation); // Doesn't work for animations, only strings.
println ("NOW PLAYING: ",animation);
self SetFlaggedAnimKnobAllRestart("playAnim", animation, %root, 1, .2, 1);
timeToWait = getanimlength(animation);
timeToWait = ( 3 * timeToWait ) + 1; // So looping animations play through 3 times.
self thread NotifyAfterTime("time is up", "time is up", timeToWait);
self waittill ("time is up");
self notify("enddrawstring");
}
}

NotifyAfterTime(notifyString, killmestring, time)
{
self endon("death");
self endon(killmestring);
wait time;
self notify (notifyString);
}

// Utility function, made for MilestoneAnims(), which displays a string until killed.
drawString(stringtodraw)
{
self endon("killanimscript");
self endon("enddrawstring");
for (;;)
{
wait .05;
Print3d ((self GetDebugEye()) + (0,0,8), stringtodraw, (1, 1, 1), 1, 0.2);
}
}

drawStringTime(msg, org, color, timer)
{
maxtime = timer*20;
for (i=0;i<maxtime;i++)
{
Print3d (org, msg, color, 1, 1);
wait .05;
}
}

showLastEnemySightPos(string)
{
self notify ("got known enemy2");
self endon ("got known enemy2");
self endon ("death");

if ( !isValidEnemy( self.enemy ) )
{
return;
}

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);

if (!IsDefined (self.lastEnemySightPos))
{
continue;
}

Print3d (self.lastEnemySightPos, string, color, 1, 2.15); // origin, text, RGB, alpha, scale
}
}

/#
printDebugTextProc (string, org, printTime, color)
{
level notify ("stop debug print " + org);
level endon ("stop debug print " + org);

if (!IsDefined (color))
{
color = (0.3,0.9,0.6);
}

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
Print3d (org, string, color, 1, 1); // origin, text, RGB, alpha, scale
}
}

printDebugText (string, org, printTime, color)
{
if (GetDebugDvar ("anim_debug") != "")
{
level thread printDebugTextProc(string, org, printTime, color);
}
}
#/

tryTurret (targetname)
{
turret = getent (targetname, "targetname");
if (!IsDefined (turret))
{
return false;
}

if ((turret.classname != "misc_mg42") && (turret.classname != "misc_turret"))
{
return false;
}

if ( !self IsInGoal(self.covernode.origin))
{
return false;
}

canuse = self useturret(turret); // dude should be near the mg42
if ( canuse )
{
turret setmode("auto_ai"); // auto, auto_ai, manual
self thread maps\_mgturret::mg42_firing(turret);
turret notify ("startfiring");
return true;
}
else
{
return false;
}
}

debugTimeout()
{
wait(5);
self notify ("timeout");
}

debugPosInternal( org, string, size )
{
self endon ("death");
self notify ("stop debug " + org);
self endon ("stop debug " + org);

ent = SpawnStruct();
ent thread debugTimeout();
ent endon ("timeout");

if (self.enemy.team == "allies")
{
color = (0.4, 0.7, 1);
}
else
{
color = (1, 0.7, 0.4);
}

while (1)
{
wait (0.05);
Print3d (org, string, color, 1, size); // origin, text, RGB, alpha, scale
}
}

debugPos( org, string )
{
thread debugPosInternal( org, string, 2.15 );
}

debugPosSize( org, string, size )
{
thread debugPosInternal( org, string, size );
}

showDebugProc(fromPoint, toPoint, color, printTime)
{
self endon ("death");
// self notify ("stop debugline " + self.export);
// self endon ("stop debugline " + self.export);

timer = printTime*20;
for (i=0;i<timer;i+=1)
{
wait (0.05);
line (fromPoint, toPoint, color);
}
}

showDebugLine( fromPoint, toPoint, color, printTime )
{
self thread showDebugProc( fromPoint, toPoint +( 0, 0, -5 ), color, printTime );
}

setEnv(env)
{
anim.idleAnimTransition [ "stand" ][ "in" ] = %casual_stand_idle_trans_in;
// anim.idleAnimTransition [ "stand" ][ "out" ] = %casual_stand_idle_trans_out;

anim.idleAnimArray [ "stand" ][ 0 ][ 0 ] = %casual_stand_idle;
anim.idleAnimArray [ "stand" ][ 0 ][ 1 ] = %casual_stand_idle_twitch;
anim.idleAnimArray [ "stand" ][ 0 ][ 2 ] = %casual_stand_idle_twitchB;
anim.idleAnimWeights [ "stand" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand" ][ 0 ][ 1 ] = 1;
anim.idleAnimWeights [ "stand" ][ 0 ][ 2 ] = 1;

anim.idleAnimArray [ "stand" ][ 1 ][ 0 ] = %casual_stand_v2_idle;
anim.idleAnimArray [ "stand" ][ 1 ][ 1 ] = %casual_stand_v2_twitch_radio;
anim.idleAnimArray [ "stand" ][ 1 ][ 2 ] = %casual_stand_v2_twitch_shift;
anim.idleAnimArray [ "stand" ][ 1 ][ 3 ] = %casual_stand_v2_twitch_talk;
anim.idleAnimWeights [ "stand" ][ 1 ][ 0 ] = 10;
anim.idleAnimWeights [ "stand" ][ 1 ][ 1 ] = 4;
anim.idleAnimWeights [ "stand" ][ 1 ][ 2 ] = 7;
anim.idleAnimWeights [ "stand" ][ 1 ][ 3 ] = 4;

anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_cqb" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_cqb" ][ 0 ][ 1 ] = 1;

anim.idleAnimTransition [ "crouch" ][ "in" ] = %casual_crouch_idle_in;
// anim.idleAnimTransition [ "crouch" ][ "out" ] = %casual_crouch_idle_out;

anim.idleAnimArray [ "crouch" ][ 0 ][ 0 ] = %casual_crouch_idle;
anim.idleAnimArray [ "crouch" ][ 0 ][ 1 ] = %casual_crouch_twitch;
anim.idleAnimArray [ "crouch" ][ 0 ][ 2 ] = %casual_crouch_point;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 0 ] = 6;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch" ][ 0 ][ 2 ] = 1;

// MikeD (1/24/2008): Banzai Feature Added
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 0 ] = %cqb_stand_idle;
anim.idleAnimArray [ "stand_banzai" ][ 0 ][ 1 ] = %cqb_stand_twitch;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 0 ] = 2;
anim.idleAnimWeights [ "stand_banzai" ][ 0 ][ 1 ] = 1;

// SCRIPTER_MOD: JesseS (4/16/2008): HMG anims added
anim.idleAnimTransition [ "stand_hmg" ][ "in" ] = %ai_mg_shoulder_run2stand;
anim.idleAnimArray [ "stand_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_stand_idle;
anim.idleAnimWeights [ "stand_hmg" ][ 0 ][ 0 ] = 1;

anim.idleAnimTransition [ "crouch_hmg" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "crouch_hmg" ][ 0 ][ 0 ] = %ai_mg_shoulder_crouch_idle;
anim.idleAnimWeights [ "crouch_hmg" ][ 0 ][ 0 ] = 1;

//anim.idleAnimTransition [ "stand_flame" ][ "in" ] = %ai_mg_shoulder_run2crouch;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 0 ] = %ai_flamethrower_stand_idle_casual_v1;
anim.idleAnimArray [ "stand_flame" ][ 0 ][ 1 ] = %ai_flamethrower_stand_twitch;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "stand_flame" ][ 0 ][ 1 ] = 1;

anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 0 ] = %ai_flamethrower_crouch_idle_a;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 1 ] = %ai_flamethrower_crouch_idle_b;
anim.idleAnimArray [ "crouch_flame" ][ 0 ][ 2 ] = %ai_flamethrower_crouch_twitch;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 0 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 1 ] = 3;
anim.idleAnimWeights [ "crouch_flame" ][ 0 ][ 2 ] = 1;

if (env == "cold")
{
array_thread(GetAIArray(),::PersonalColdBreath);
array_thread(getspawnerarray(),::PersonalColdBreathSpawner);
}
}

PersonalColdBreath()
{
tag = "TAG_EYE";

self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
if (self.a.movement != "run")
{
playfxOnTag ( level._effect["cold_breath"], self, tag );
wait (2.5 + RandomFloat(3));
}
else
{
wait (0.5);
}
}
}

PersonalColdBreathSpawner()
{
self endon ("death");
self notify ("stop personal effect");
self endon ("stop personal effect");

for (;;)
{
self waittill ("spawned", Spawn);
if (maps\_utility::spawn_failed(Spawn))
{
continue;
}

Spawn thread PersonalColdBreath();
}
}

getNodeOffset(node)
{
if ( IsDefined( node.offset ) )
{
return node.offset;
}

//(right offset, forward offset, vertical offset)
// you can get an actor's current eye offset by setting scr_eyeoffset to his entnum.
// this should be redone whenever animations change significantly.
cover_left_crouch_offset = (-26, .4, 36);
cover_left_stand_offset = (-32, 7, 63);
cover_right_crouch_offset = (43.5, 11, 36);
cover_right_stand_offset = (36, 8.3, 63);
cover_crouch_offset = (3.5, -12.5, 45); // maybe we could account for the fact that in cover crouch he can stand if he needs to?
cover_stand_offset = (-3.7, -22, 63);

cornernode = false;
nodeOffset = (0,0,0);

right = AnglesToRight(node.angles);
forward = AnglesToForward(node.angles);

switch(node.type)
{
case "Cover Left":
case "Cover Left Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_left_stand_offset );
}
break;

case "Cover Right":
case "Cover Right Wide":
if ( node isNodeDontStand() && !node isNodeDontCrouch() )
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_crouch_offset );
}
else
{
nodeOffset = calculateNodeOffset( right, forward, cover_right_stand_offset );
}
break;

case "Cover Stand":
case "Conceal Stand":
case "Turret":
nodeOffset = calculateNodeOffset( right, forward, cover_stand_offset );
break;

case "Cover Crouch":
case "Cover Crouch Window":
case "Conceal Crouch":
nodeOffset = calculateNodeOffset( right, forward, cover_crouch_offset );
break;
}

node.offset = nodeOffset;
return node.offset;
}

calculateNodeOffset( right, forward, baseoffset )
{
return vector_scale( right, baseoffset[0] ) + vector_scale( forward, baseoffset[1] ) + (0, 0, baseoffset[2]);
}

checkPitchVisibility( fromPoint, toPoint, atNode )
{
// check vertical angle is within our aiming abilities

pitch = AngleClamp180( VectorToAngles( toPoint - fromPoint )[0] );
if ( abs( pitch ) > 45 )
{
if ( IsDefined( atNode ) && atNode.type != "Cover Crouch" && atNode.type != "Conceal Crouch" )
{
return false;
}

if ( pitch > 45 || pitch < anim.coverCrouchLeanPitch - 45 )
{
return false;
}
}
return true;
}

showLines(start, end, end2)
{
for (;;)
{
line(start, end, (1,0,0), 1);
wait (0.05);
line(start, end2, (0,0,1), 1);
wait (0.05);
}
}

// Returns an animation from an array of animations with a corresponding array of weights.
anim_array(animArray, animWeights)
{
total_anims = animArray.size;
idleanim = RandomInt(total_anims);

assert (total_anims);
assert (animArray.size == animWeights.size);

if (total_anims == 1)
{
return animArray[0];
}

weights = 0;
total_weight = 0;

for (i = 0; i < total_anims; i++)
{
total_weight += animWeights[i];
}

anim_play = RandomFloat(total_weight);
current_weight = 0;

for (i = 0; i < total_anims; i++)
{
current_weight += animWeights[i];
if (anim_play >= current_weight)
{
continue;
}

idleanim = i;
break;
}

return animArray[idleanim];
}

notForcedCover()
{
return ((self.a.forced_cover == "none") || (self.a.forced_cover == "Show"));
}

forcedCover(msg)
{
return IsDefined(self.a.forced_cover) && (self.a.forced_cover == msg);
}

print3dtime(timer, org, msg, color, alpha, scale)
{
newtime = timer / 0.05;
for (i=0;i<newtime;i++)
{
Print3d (org, msg, color, alpha, scale);
wait (0.05);
}
}

print3drise (org, msg, color, alpha, scale)
{
newtime = 5 / 0.05;
up = 0;
org = org + randomvector(30);

for (i=0;i<newtime;i++)
{
up+=0.5;
Print3d (org + (0,0,up), msg, color, alpha, scale);
wait (0.05);
}
}

crossproduct (vec1, vec2)
{
return (vec1[0]*vec2[1] - vec1[1]*vec2[0] > 0);
}

scriptChange()
{
self.a.current_script = "none";
self notify (anim.scriptChange);
}

delayedScriptChange()
{
wait (0.05);
scriptChange();
}

getGrenadeModel()
{
return getWeaponModel(self.grenadeweapon);
}

sawEnemyMove(timer)
{
if (!IsDefined(timer))
{
timer = 500;
}

return (GetTime() - self.personalSightTime < timer);
}

canThrowGrenade()
{
if (!self.grenadeAmmo)
{
return false;
}

if (self.script_forceGrenade)
{
return true;
}

return (IsPlayer(self.enemy));
}

random_weight (array)
{
idleanim = RandomInt (array.size);
if (array.size > 1)
{
anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
}

anim_play = RandomFloat (anim_weight);

anim_weight = 0;
for (i=0;i<array.size;i++)
{
anim_weight += array[i];
if (anim_play < anim_weight)
{
idleanim = i;
break;
}
}
}

return idleanim;
}

removeableHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

if (IsDefined(anim.noHatClassname[self.classname]))
{
return false;
}

return (!IsDefined(anim.noHat[self.model]));
}

metalHat()
{
if (!IsDefined (self.hatmodel))
{
return false;
}

return (IsDefined(anim.metalHat[self.model]));
}

fatGuy()
{
return (IsDefined(anim.fatGuy[self.model]));
}

setFootstepEffect(name, fx)
{
assertEx(IsDefined(name), "Need to define the footstep surface type.");
assertEx(IsDefined(fx), "Need to define the mud footstep effect.");

if (!IsDefined(anim.optionalStepEffects))
{
anim.optionalStepEffects = [];
}

anim.optionalStepEffects[anim.optionalStepEffects.size] = name;
level._effect["step_" + name] = fx;
anim.optionalStepEffectFunction = animscripts\zombie_shared::playFootStepEffect;
}

persistentDebugLine(start, end)
{
self endon ("death");
level notify ("newdebugline");
level endon ("newdebugline");

for (;;)
{
line (start,end, (0.3,1,0), 1);
wait (0.05);
}
}

isNodeDontStand()
{
return (self.spawnflags & 4) == 4;
}
isNodeDontCrouch()
{
return (self.spawnflags & 8) == 8;
}

doesNodeAllowStance( stance )
{
if ( stance == "stand" )
{
return !self isNodeDontStand();
}
else
{
Assert( stance == "crouch" );
return !self isNodeDontCrouch();
}
}

animArray( animname ) /* string */
{
//println( "playing anim: ", animname );

assert( IsDefined(self.a.array) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname];
}

animArrayAnyExist( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

return self.a.array[animname].size > 0;
}

animArrayPickRandom( animname )
{
assert( IsDefined( self.a.array ) );

/#
if ( !IsDefined(self.a.array[animname]) )
{
dumpAnimArray();
assertex( IsDefined(self.a.array[animname]), "self.a.array[ \"" + animname + "\" ] is undefined" );
}
#/

assert( self.a.array[animname].size > 0 );

if ( self.a.array[animname].size > 1 )
{
index = RandomInt( self.a.array[animname].size );
}
else
{
index = 0;
}

return self.a.array[animname][index];
}

/#
dumpAnimArray()
{
println("self.a.array:");
keys = getArrayKeys( self.a.array );

for ( i=0; i < keys.size; i++ )
{
if ( isarray( self.a.array[ keys[i] ] ) )
{
println( " array[ \"" + keys[i] + "\" ] = {array of size " + self.a.array[ keys[i] ].size + "}" );
}
else
{
println( " array[ \"" + keys[i] + "\" ] = ", self.a.array[ keys[i] ] );
}
}
}
#/

getAnimEndPos( theanim )
{
moveDelta = getMoveDelta( theanim, 0, 1 );
return self localToWorldCoords( moveDelta );
}

isValidEnemy( enemy )
{
if ( !IsDefined( enemy ) )
{
return false;
}

return true;
}


damageLocationIsAny( a, b, c, d, e, f, g, h, i, j, k, ovr )
{
/* possibile self.damageLocation's:
"torso_upper"
"torso_lower"
"helmet"
"head"
"neck"
"left_arm_upper"
"left_arm_lower"
"left_hand"
"right_arm_upper"
"right_arm_lower"
"right_hand"
"gun"
"none"
"left_leg_upper"
"left_leg_lower"
"left_foot"
"right_leg_upper"
"right_leg_lower"
"right_foot"
*/

if ( !IsDefined( a ) ) return false; if ( self.damageLocation == a ) return true;
if ( !IsDefined( b ) ) return false; if ( self.damageLocation == b ) return true;
if ( !IsDefined( c ) ) return false; if ( self.damageLocation == c ) return true;
if ( !IsDefined( d ) ) return false; if ( self.damageLocation == d ) return true;
if ( !IsDefined( e ) ) return false; if ( self.damageLocation == e ) return true;
if ( !IsDefined( f ) ) return false; if ( self.damageLocation == f ) return true;
if ( !IsDefined( g ) ) return false; if ( self.damageLocation == g ) return true;
if( !IsDefined( h ) ) return false; if( self.damageLocation == h ) return true;
if( !IsDefined( i ) ) return false; if( self.damageLocation == i ) return true;
if( !IsDefined( j ) ) return false; if( self.damageLocation == j ) return true;
if( !IsDefined( k ) ) return false; if( self.damageLocation == k ) return true;
assert(!IsDefined(ovr));
return false;
}

ragdollDeath( moveAnim )
{
self endon ( "killanimscript" );

lastOrg = self.origin;
moveVec = (0,0,0);

for ( ;; )
{
wait ( 0.05 );
force = distance( self.origin, lastOrg );
lastOrg = self.origin;

if ( self.health == 1 )
{
self.a.nodeath = true;
self startRagdoll();
self ClearAnim( moveAnim, 0.1 );
wait ( 0.05 );
physicsExplosionSphere( lastOrg, 600, 0, force * 0.1 );
self notify ( "killanimscript" );
return;
}

}
}

isCQBWalking()
{
return IsDefined( self.cqbwalking ) && self.cqbwalking;
}

squared( value )
{
return value * value;
}

randomizeIdleSet()
{
self.a.idleSet = RandomInt( 2 );
}

// meant to be used with any integer seed, for a small integer maximum (ideally one that divides anim.randomIntTableSize)
getRandomIntFromSeed( intSeed, intMax )
{
assert( intMax > 0 );

index = intSeed % anim.randomIntTableSize;
return anim.randomIntTable[ index ] % intMax;
}

// MikeD (1/24/2008): Added Banzai Feature.
is_banzai()
{
return IsDefined( self.banzai ) && self.banzai;
}

// SCRIPTER_MOD: JesseS (4/16/2008): HMG guys have their own anims
is_heavy_machine_gun()
{
return IsDefined( self.heavy_machine_gunner ) && self.heavy_machine_gunner;
}

is_zombie()
{
if (IsDefined(self.is_zombie) && self.is_zombie)
{
return true;
}

return false;
}


is_civilian()
{
if (IsDefined(self.is_civilian) && self.is_civilian)
{
return true;
}

return false;
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
is_zombie_gibbed()
{
return ( self is_zombie() && self.gibbed );
}

// CODER_MOD: Austin (7/21/08): added to prevent zombies from gibbing more than once
set_zombie_gibbed()
{
if ( self is_zombie() )
{
self.gibbed = true;
}
}

is_skeleton(skeleton)
{
if ((skeleton == "base") && IsSubStr(get_skeleton(), "scaled"))
{
// Scaled skeletons should identify as "base" as well
return true;
}

return (get_skeleton() == skeleton);
}

get_skeleton()
{
if (IsDefined(self.skeleton))
{
return self.skeleton;
}
else
{
return "base";
}
}

debug_anim_print( text )
{
/#
if ( level.dog_debug_anims )
println( text+ " " + getTime() );

if ( level.dog_debug_anims_ent == self getentnum() )
println( text+ " " + getTime() );
#/
}

debug_turn_print( text, line )
{
/#
if ( level.dog_debug_turns == self getentnum() )
{
duration = 200;
currentYawColor = (1,1,1);
lookaheadYawColor = (1,0,0);
desiredYawColor = (1,1,0);

currentYaw = AngleClamp180(self.angles[1]);
desiredYaw = AngleClamp180(self.desiredangle);
lookaheadDir = self.lookaheaddir;
lookaheadAngles = vectortoangles(lookaheadDir);
lookaheadYaw = AngleClamp180(lookaheadAngles[1]);
println( text+ " " + getTime() + " cur: " + currentYaw + " look: " + lookaheadYaw + " desired: " + desiredYaw );
}
#/
}




nice one dude sadly its not this script. having a quick look this it's just the coding that controls the damange done to a player. do you have access to the other files maybe? also where did you manage to get this?

thanks for helping us out i13thSTAR


Yep I have all the codes which one do you want. 8)
Jump to:
You are viewing our Forum Archives. To view or take place in current topics click here.