AI animation scripts (``animscripts/*.gsc``) ============================================== .. meta:: :description: Reference for the stock Call of Duty: United Offensive AI animation scripts: corpus layout, animation state variables, tree selection, observed animation methods, notetracks, pose and movement helpers, and turret tree switching. :keywords: call of duty, united offensive, cod uo, animscripts, ai animation, setanimknob, setflaggedanimknob, notetrack, useanimtree, mg42, 30cal Status and authority -------------------- This page documents the ``animscripts`` layer as it appears in the stock Call of Duty: United Offensive script corpus. It is not a recovered engine API reference. The corpus establishes: * the file layout and the behavior entry points; * the animation state variables the scripts maintain; * the animation method names and call forms they use; * the notetrack bridge in ``shared.gsc``; * the pose and movement helper layer; * the turret tree-switching pattern. The recovered ``coduomp`` source does not contain implementations of the AI animation methods. A search for the method names in that tree returns no implementation: .. code-block:: text grep -ril "setflaggedanimknob\|setanimknob\|useanimtree\|clearanim" src The stock ``codbook`` API page likewise lists only ``getanimlength`` and ``animhasnotetrack`` among the animation builtins. This page therefore records observed call forms and names their argument positions as they appear at the call sites. It does not invent parameter contracts, return values, or error behavior for methods the recovered source does not implement. The corpus is a superset of the scripts shipped in the stock UO packages. Across those packages, only ``pakuo00.pk3`` lists ``animscripts/`` entries. It carries 21 scripts, all present in the supplied attachment. The attachment adds behavior scripts and map-specific variants, for 67 files in total. What the AI animation layer is ------------------------------ These files are ordinary GSC scripts. They are not a separate language, and they are not the engine ``mp/playeranim.script`` table described in :doc:`player_animation_script`. Behavior scripts are started through ``main()``. 50 of the 67 files define one; the rest are helper or callback files. A behavior script selects an animation tree with ``#using_animtree`` and drives an AI actor with animation method calls. The scripts also keep a small animation state model in GSC variables. The engine does not derive that model from the tree or the player animation table. The recovered engine source does not contain the AI behavior selector that starts these scripts. The scripts are started by the stock AI or by level scripts, not by the player animation table. Corpus layout ------------- The supplied corpus contains 67 ``.gsc`` files. Directory distribution: .. list-table:: :header-rows: 1 :widths: 22 12 66 * - Directory - Files - Contents * - ``animscripts/`` - 41 - Base behaviors and shared helpers: ``init``, ``shared``, ``utility``, ``combat``, ``cover_*``, ``walk``, ``run``, ``stop``, ``pain``, ``death``, ``look``, ``aim``, ``prone``, ``wounded``, and others. * - ``animscripts/traverse/`` - 17 - Ledge, fence, and platform traversal behaviors. * - ``animscripts/scripted/`` - 3 - Scripted sequence playback, including vehicle and truck-ride cases. * - ``animscripts/mg42/`` - 3 - MG42 turret behavior. * - ``animscripts/b30cal/`` - 3 - M1919 Browning turret behavior. 50 files define a ``main`` function. The rest are helper or callback files. 63 files contain an active ``#using_animtree`` directive. Every file's first active directive selects ``generic_human``. Five files contain a second active directive: ``scripted.gsc`` repeats ``generic_human`` before ``init``, and the four turret files switch to ``mg42`` or ``30cal``. In-game paths use backslashes in GSC calls: .. code-block:: text animscripts\utility::initialize("combat"); animscripts\shared::DoNoteTracks("animdone"); Script names and function names are canonicalized like other GSC names, so a case mismatch between a call and a filename does not necessarily fail. The supplied corpus carries both ``weaponList.gsc`` and ``weaponlist.gsc``, and ``init.gsc`` calls ``animscripts\WeaponList::initWeaponList()``. Entry point pattern ------------------- A behavior ``main()`` follows a consistent shape: .. code-block:: text #using_animtree ("generic_human"); main() { self trackScriptState( "Walk Main", "code" ); self endon("killanimscript"); animscripts\utility::initialize("walk"); for (;;) { // choose pose, movement, cover, enemy response, and so on } } The important parts are: * ``#using_animtree`` selects the tree for every ``%`` reference that follows it in the file. * ``self endon("killanimscript")`` lets the AI cancel the behavior. * ``trackScriptState`` tags the current script state for the AI debug view. * ``utility::initialize`` clears the body pose and applies the common setup. * The loop selects a behavior and waits on notifications or timers. Some scripts use ``trackScriptState`` with a reason string rather than ``"code"``, for example when a sub-state returns. The method is observed in the corpus and is not implemented in the recovered source. Animation state variables ------------------------- ``init.gsc`` documents the model at the top of the file. The variables are conventional GSC fields on the AI actor. .. list-table:: :header-rows: 1 :widths: 24 30 46 * - Variable - Values - Meaning * - ``self.anim_pose`` - ``"stand"``, ``"crouch"``, ``"prone"``, ``"back"``, ``"wounded"`` - Current body pose. ``"back"`` is a pain or death pose. ``"wounded"`` is handled by the wounded behavior, not by the general pose table. * - ``self.anim_movement`` - ``"stop"``, ``"walk"``, ``"run"`` - Current movement family. * - ``self.anim_idleSet`` - ``"none"`` and behavior-specific sets - Selected idle set. * - ``self.anim_special`` - ``"none"``, ``"mg42"``, and behavior-specific values - Special animation mode. * - ``self.anim_gunHand`` - ``"left"``, ``"right"``, ``"none"`` - Which hand holds the weapon model. * - ``self.anim_script`` - Current behavior name - Set by ``utility::initialize`` and by behavior transitions. * - ``self.anim_alertness`` - ``"casual"``, ``"alert"``, ``"aiming"`` - Alertness pose family. * - ``self.anim_meleeState`` - ``"aim"``, ``"left"``, ``"right"`` - Melee state. * - ``self.anim_needsToRechamber`` - ``0`` or ``1`` - Weapon rechamber flag. * - ``self.anim_combatEndTime`` - Millisecond timestamp - Combat memory expiry. These are script conventions. They are not fields in the player animation table, and the engine does not enforce their values. Initialization -------------- ``init.gsc`` runs once for the level and once per AI actor. The level pass is guarded by ``anim.NotFirstTime``. It sets: * the debug entity cvar ``animscriptent``; * the global function pointers ``anim.println``, ``anim.locSpam``, ``anim.assert``, and ``anim.PutGunInHand``; * combat range and accuracy constants; * the pose and movement lookup table through ``SetPoseMovement::InitPoseMovementFunctions``; * the weapon list and level face tables. The per-actor pass sets these animation fields, among other per-actor bookkeeping: .. code-block:: text self.anim_pose = "stand"; self.anim_movement = "stop"; self.anim_idleSet = "none"; self.anim_special = "none"; self.anim_gunHand = "none"; self.anim_PrevPutGunInHandTime = -1; self.anim_needsToRechamber = 0; self.anim_combatEndTime = gettime(); self.anim_script = "init"; self.anim_alertness = "casual"; self.anim_woundedBias = 0; self.anim_woundedAmount = 0; self.anim_woundedTime = GetTime(); self.anim_lastWound = "upper"; self.anim_lastDebugPrint = ""; self.anim_StopCowering = ::DoNothing; It also calls ``shared::PutGunInHand("right")``, initializes unique animations, starts the look thread, starts the debug info thread, and refills the weapon clip. ``anim.PutGunInHand`` and the other ``anim`` entries are GSC function references, not engine natives. ``init.gsc`` assigns them so later code can call a function through an array or a function-pointer slot. Shared helpers -------------- ``shared.gsc`` contains functions shared by animation scripts and level scripts. Its header states that it cannot rely on ``init`` having run and cannot call functions that are not allowed in level scripts. That constraint explains why it reimplements or delegates low-level work instead of assuming per-actor initialization. Observed shared helpers include: * ``PutGunInHand(hand)``: attaches or detaches the weapon model on ``tag_weapon_left`` and ``tag_weapon_right``. ``hand`` is ``"left"``, ``"right"``, or ``"none"``. * ``DropAIWeapon()``. * ``LookAtEntity``, ``LookAtPosition``, ``LookAtStop``, ``LookAtAnimations``. * ``SetInCombat``. * ``UpdateWounds``. * ``DoNoteTracks`` and ``DoNoteTracksForever``. Level scripts call these directly. The recovered campaign script ``bastogne1.gsc`` calls ``animscripts\shared::putGunInHand`` and ``animscripts\shared::lookatentity``, which confirms that the shared file is part of the level-facing surface, not only the AI-internal surface. Animation tree selection ------------------------ AI files select a tree at compile time: .. code-block:: c #using_animtree ("generic_human"); Every ``%name`` after that directive is resolved against ``generic_human`` until another directive changes the selection. A name missing from the selected tree is a compile error, not a runtime fallback. Turret scripts use a second tree for the turret entity. In ``mg42/prone.gsc`` and ``mg42/stand.gsc`` the file starts with ``generic_human`` for the AI body functions, then repeats a directive before the turret section: .. code-block:: text #using_animtree("mg42"); init(owner) { self UseAnimTree(#animtree); // ... } The ``init(owner)`` function runs on the turret entity because the body script starts it with ``turret thread init(self)``. The body functions before the switch play ``generic_human`` references such as ``%proneMG42gunner_fire``. The functions after it play ``mg42`` references such as ``%proneMG42gun_fire_forward_medium``. ``mg42/common.gsc`` contains no tree directive and no ``%`` reference. It is the shared fire and aim loop that calls the body script's callbacks. The turret ``init`` functions keep a reference count: .. code-block:: text init(owner) { self UseAnimTree(#animtree); if (isdefined(self.animTreeUsage)) self.animTreeUsage++; else self.animTreeUsage = 0; owner waittill("killanimscript"); if (self.animTreeUsage) { self.animTreeUsage--; return; } self.animTreeUsage = undefined; self stopuseanimtree(); } The count prevents one user from stopping the tree while another user still holds it. ``b30cal/prone.gsc`` and ``b30cal/stand.gsc`` use the same pattern with ``#using_animtree("30cal")``. Their ``b30cal/common.gsc`` also has no tree directive. ``UseAnimTree`` and ``stopuseanimtree`` are observed methods. The recovered source does not define them. ``#animtree`` is the compiler-side registry index described in :doc:`animtrees`. Observed animation methods -------------------------- The following names and call forms appear in the supplied corpus. Argument names describe the observed positions, not a recovered signature. .. list-table:: :header-rows: 1 :widths: 44 56 * - Observed call form - Purpose in the scripts * - ``setAnimKnob(anim, weight, blendTime[, rate])`` - Set one animation knob with a blend. * - ``setAnimKnobAll(anim, rootNode, weight, blendTime[, rate])`` - Set a knob over a node and its descendants. * - ``setAnimKnobRestart(anim[, weight, blendTime, rate])`` - Set a knob and restart the animation. Observed with one argument and with four. Turret calls use both forms; AI body calls use four. * - ``setAnimKnobAllRestart(anim, rootNode, weight, blendTime, rate)`` - Set a whole-subtree knob and restart. * - ``setFlaggedAnimKnob(notifyName, anim, weight, blendTime, rate)`` - Set a knob and associate a completion notification. * - ``setFlaggedAnimKnobAll(notifyName, anim, rootNode, weight, blendTime, rate)`` - Whole-subtree flagged knob. * - ``setFlaggedAnimKnobRestart(notifyName, anim, weight, blendTime, rate)`` - Flagged knob with restart. * - ``setFlaggedAnimKnobAllRestart(notifyName, anim, rootNode, weight, blendTime, rate)`` - Flagged whole-subtree knob with restart. * - ``setAnim(anim[, weight, blendTime[, rate]])`` - General animation set. Observed with two, three, and four arguments. * - ``setFlaggedAnimRestart(notifyName, anim, weight, blendTime, rate)`` - Flagged animation with restart. Appears only in a commented-out call in the supplied corpus. * - ``clearanim(node, blendTime)`` - Clear a node. * - ``getAnimTime(node)`` - Read animation progress. Scripts compare it with values such as ``0.5``. * - ``UseAnimTree(#animtree)`` - Switch an entity to a compiled tree index. * - ``stopuseanimtree()`` - Release the switch. * - ``setTurretAnim(anim)`` - Set the AI actor's turret-body animation. * - ``startscriptedanim(notifyName, origin, angles, anim, animMode, root)`` - Start a scripted animation sequence. * - ``setLookAt(position[, speed])`` - Aim the look controller at a position. * - ``setLookAtAnimNodes(straight, left, right)`` - Set the look animation nodes. * - ``setLookAtYawLimits(max, limit, blendTime)`` - Set yaw limits for the look controller. * - ``stopLookAt(speed)`` - Stop the look controller. * - ``SetProneAnimNodes(minAngle, maxAngle, downAnim, straightAnim, upAnim)`` - Set the prone ground-orientation animations. * - ``EnterProne(blendTime)`` - Enter prone orientation blending. * - ``ExitProne(blendTime)`` - Leave prone orientation blending. * - ``UpdateProne(anim1, anim2, weight, blendTime, rate)`` - Blend the prone orientation pair. * - ``trackScriptState(label, reason)`` - Record the current behavior state for debugging. * - ``animMode(mode)``, ``traverseMode(mode)``, ``OrientMode(mode[, value])`` - Behavior mode changes used throughout the corpus. ``setAnim`` needs a warning. The two-argument call ``self setanim(%body, 0.2)`` and the four-argument call ``self setanim(%shoot,0.0,0.2,1)`` do not share a documented positional meaning in the recovered source. Read the call site and the animation comment before reusing either form. ``Set3FlaggedAnimKnobs`` is not an engine method. It is a wrapper in ``corner.gsc``: .. code-block:: c Set3FlaggedAnimKnobs(animFlag, animArray, weight, blendTime, rate) { self SetAnimKnob(animArray["left"], weight, blendTime, rate); self SetFlaggedAnimKnob(animFlag, animArray["middle"], weight, blendTime, rate); self SetAnimKnob(animArray["right"], weight, blendTime, rate); } ``finishLookAt`` is also a GSC helper, not an engine method. It resets the eye animations and calls ``stopLookAt``. It lives in ``look.gsc``. Pose and movement helpers ------------------------- ``SetPoseMovement.gsc`` builds a two-dimensional function table: .. code-block:: c anim.SetPoseMovementFnArray["stand"]["stop"] = StandStop; anim.SetPoseMovementFnArray["stand"]["walk"] = StandWalk; anim.SetPoseMovementFnArray["stand"]["run"] = StandRun; anim.SetPoseMovementFnArray["crouch"]["stop"] = CrouchStop; // ... crouch walk, crouch run, prone stop, prone walk, prone run The public function is: .. code-block:: c SetPoseMovement(desiredPose, desiredMovement) { // fill empty arguments from the current state [[anim.SetPoseMovementFnArray[desiredPose][desiredMovement]]](); } It accepts empty strings for "leave this part of the state alone". A move from prone to walk or run with an empty desired pose becomes crouch first. A current pose of ``"wounded"`` is an error for this helper, because the wounded behavior owns that state. ``utility.gsc`` supplies the common start-of-behavior setup: .. code-block:: c initialize(animscript) { initAnimTree(animscript); UpdateAnimPose(); } ``initAnimTree`` puts the gun in the right hand, clears ``%body``, sets ``%body`` and ``%shoot``, updates the combat memory, and records the behavior name in ``self.anim_script``. ``UpdateAnimPose`` handles prone setup and teardown: .. code-block:: c if (self.desired_anim_pose == "prone") { self SetProneAnimNodes(-45, 45, %prone_legsdown, %prone_legsstraight, %prone_legsup); self EnterProne(0.5); } else { self ExitProne(0.5); } The helper also reconciles ``self.anim_pose`` and ``self.desired_anim_pose``. A script can set ``self.desired_anim_pose`` before calling ``UpdateAnimPose`` to request a pose change. Notetrack bridge ---------------- Animation notetracks are the bridge from an ``xanim`` asset back into GSC. The shared handler is: .. code-block:: c self waittill(animName, note); ``animName`` is the animation or flag name the script is waiting on. ``note`` is the notetrack string. ``DoNoteTracks(animName, customFunction, debugIdentifier)`` loops until it receives ``"end"``, ``"finish"``, or ``"undefined"``. The handler recognizes these note families: .. list-table:: :header-rows: 1 :widths: 30 70 * - Note family - Effect * - ``end``, ``finish``, ``undefined`` - Return from ``DoNoteTracks``. * - ``anim_pose = "stand"``, ``"crouch"``, ``"prone"``, ``"back"`` - Update ``self.anim_pose``. Prone transitions also update orientation and prone nodes. * - ``anim_movement = "stop"``, ``"walk"``, ``"run"`` - Update ``self.anim_movement``. * - ``anim_aiming = 1``, ``anim_aiming = 0`` - Set alertness to ``"aiming"`` or ``"alert"``. * - ``anim_alertness = casual``, ``alert``, ``aiming`` - Set alertness directly. * - ``anim_gunhand = "left"``, ``"right"``, ``"none"`` - Move the weapon model. * - ``gravity on``, ``gravity off`` - Call ``animMode("gravity")`` or ``animMode("nogravity")``. * - ``bodyfall large``, ``bodyfall small`` - Play a ground-type bodyfall sound. * - ``attach clip right``, ``detach clip right`` - Placeholders in the stock script. They have empty bodies. * - ``rechamber``, ``reload done`` - Clear the rechamber flag and, for ``reload done``, refill the clip. * - ``anim_melee = "left"``, ``"right"`` - Update ``self.anim_meleeState``. * - ``footstep``, ``step``, ``footscrape`` - Play a ground-type step or scrape sound. * - ``swish small``, ``swish large`` - Play a melee swing sound. The stock mapping is inverted: ``swish small`` plays ``melee_swing_large`` and ``swish large`` plays ``melee_swing_small``. * - ``dropgun`` - Drop the AI weapon. * - ``swap taghelmet to tagleft`` - Detach the helmet and attach it to the left weapon tag. * - Anything else - Call the optional ``customFunction(note)``. ``DoNoteTracksForever`` repeats the handler and guards against a note that returns too quickly. It is used with a kill string and also ends on ``"killanimscript"``. The notetrack names themselves live in the ``xanim`` assets. The recovered source does not contain those assets, so this page can document the handler, not the complete note vocabulary of every animation. Scripted animations ------------------- ``scripted.gsc`` is the adapter between the level command ``animscripted`` and the engine call ``startscriptedanim``. .. code-block:: c init(notifyName, origin, angles, theAnim, animMode, root) { self.codeScripted["notifyName"] = notifyName; self.codeScripted["origin"] = origin; self.codeScripted["angles"] = angles; self.codeScripted["anim"] = theAnim; self.codeScripted["animMode"] = animMode; self.codeScripted["root"] = root; } main() { self endon("end_sequence"); self startscriptedanim(self.codeScripted["notifyName"], self.codeScripted["origin"], self.codeScripted["angles"], self.codeScripted["anim"], self.codeScripted["animMode"], self.codeScripted["root"]); } The header states that the stock level command calls this script only for AI. For a script model, the level script calls ``startscriptedanim`` directly. Two stock details matter: * ``init`` defaults ``animMode`` to ``"normal"`` and ``root`` to ``%body`` when the caller omits them. * ``main`` overwrites the stored root with ``%body`` before the call, marked ``// TEMP!`` in the source. A caller-supplied root is therefore not honored by this stock adapter. The recovered campaign script ``bastogne1_anim.gsc`` uses ``animscripted`` extensively, which confirms the level-script path. Turret scripts -------------- The turret scripts are split into two layers. The AI body layer selects ``generic_human``: .. code-block:: text #using_animtree("generic_human"); main() { self desired_anim_pose = "crouch"; animscripts\utility::UpdateAnimPose(); self desired_anim_pose = "prone"; self.anim_movement = "stop"; turret = self GetTurret(); turret thread init(self); thread animscripts\mg42\common::main( ::DoShoot, ::DoRecover, ::DoAim, turret); } The body layer calls ``setTurretAnim`` with ``generic_human`` references: .. code-block:: c self setTurretAnim(%proneMG42gunner_fire); self setAnimKnobRestart(%proneMG42gunner_fire, 1, 0.2, 1); The turret layer selects ``mg42`` or ``30cal``, switches the turret entity with ``UseAnimTree(#animtree)``, and plays the turret's own references: .. code-block:: c turret setAnimKnobRestart(%proneMG42gun_fire_forward_medium); The two trees contain different names by design. ``generic_human`` contains the gunner body poses, and ``mg42`` contains the turret gun poses. Do not move a name from one tree to the other without checking both script layers. Debugging --------- The corpus uses several debug-only facilities: * ``/# ... #/`` blocks are developer-only. The compiler strips them outside developer mode. * ``[[anim.println]]`` prints a message. * ``[[anim.locSpam]]`` prints a location or state marker. * ``[[anim.assert]]`` stops the server when its condition is false. The comment in ``init.gsc`` notes that the stock scripts have no stack traces, so the message must identify the call site. * ``trackScriptState`` labels the current behavior state. * ``UpdateDebugInfo`` maintains a debug display. * ``animscriptent`` selects a debug entity. * ``anim.doSpam`` enables location spam. ``anim.assert`` and ``anim.locSpam`` are GSC function references, not engine natives. ``[[...]]`` is the GSC function-pointer call syntax used by the corpus. Authoring guidance ------------------ #. Start the file with ``#using_animtree`` for the tree that contains every animation you plan to use. #. Add the animation nodes to that tree before loading the script. A missing node is a compile error. #. Use the stock ``main()`` shape: ``trackScriptState``, ``endon``, ``utility::initialize``, then a behavior loop. #. Use ``thread`` for non-blocking sub-behaviors and ``waittill`` for their completion. #. Use ``endon("killanimscript")`` so a behavior can be cancelled. #. Use ``utility::SetPoseMovement`` or the pose table for pose changes, rather than setting ``self.anim_pose`` alone. The helper plays the transition. #. Use ``DoNoteTracks`` for animation notes. Return from it on ``"end"`` or ``"finish"``. #. For a turret, select the narrow tree in the turret's ``init`` and keep the AI body layer on ``generic_human``. #. Balance ``UseAnimTree`` with ``stopuseanimtree`` through the ``animTreeUsage`` reference count. #. Do not assume an animation method exists because it appears in the corpus. The recovered source does not define the AI method set. Known gaps ---------- .. list-table:: :header-rows: 1 :widths: 32 68 * - Gap - Consequence * - AI animation method implementations - Argument meaning, defaults, return values, and error behavior are not established by the recovered source. The call forms above come from stock call sites. * - AI behavior selector - The recovered source does not show which script starts ``combat``, ``walk``, ``cover_*``, or the other behaviors. * - Notetrack vocabulary - The notes handled by ``shared.gsc`` are known. The complete set of notes inside every ``xanim`` asset is not. * - Turret tree contents - ``mg42.atr`` and ``30cal.atr`` are in the corpus, but the engine-side turret animation selection is outside the recovered AI method set. * - Map-specific scripts - The attachment includes scripts that are not in ``pakuo00.pk3``. A stock installation may not contain every behavior named here. Related pages ------------- Animation tree syntax and sync groups are specified in :doc:`animtrees`. The player animation table is specified in :doc:`player_animation_script`. Implementation basis -------------------- .. list-table:: :header-rows: 1 :widths: 56 44 * - Source - Role * - ``animscripts/init.gsc`` - Global and per-actor animation state initialization. * - ``animscripts/shared.gsc`` - Shared level-facing helpers and the notetrack bridge. * - ``animscripts/utility.gsc`` - ``initialize``, ``initAnimTree``, ``UpdateAnimPose``, pose selection. * - ``animscripts/SetPoseMovement.gsc`` - Pose and movement function table and transition helpers. * - ``animscripts/corner.gsc`` - ``Set3FlaggedAnimKnobs`` wrapper and cover-corner behavior. * - ``animscripts/look.gsc`` - Look controller, look animation nodes, ``finishLookAt``. * - ``animscripts/combat.gsc`` - Example combat entry point and behavior loop. * - ``animscripts/walk.gsc`` - Example movement entry point and pose selection. * - ``animscripts/cover_stand.gsc`` - Example cover behavior using ``SetPoseMovement``. * - ``animscripts/scripted.gsc`` - Level ``animscripted`` adapter and ``startscriptedanim`` call. * - ``animscripts/mg42/common.gsc`` - Shared turret fire and aim loop and callback dispatch. * - ``animscripts/mg42/prone.gsc`` - MG42 prone body calls, mid-file ``mg42`` tree switch, and ``UseAnimTree`` reference count. * - ``animscripts/mg42/stand.gsc`` - MG42 standing body calls, mid-file ``mg42`` tree switch, and ``UseAnimTree`` reference count. * - ``animscripts/b30cal/common.gsc`` - Shared 30cal turret fire and aim loop and callback dispatch. * - ``animscripts/b30cal/prone.gsc`` - 30cal prone body calls, mid-file ``30cal`` tree switch, and ``UseAnimTree`` reference count. * - ``animscripts/b30cal/stand.gsc`` - 30cal standing body calls, mid-file ``30cal`` tree switch, and ``UseAnimTree`` reference count. * - ``pakuo00.pk3`` - Base ``animscripts/`` package contents. * - ``pakuo01.pk3`` - Source of ``mp/playeranim.script``; no ``animscripts`` entries. * - ``bastogne1.gsc`` and ``bastogne1_anim.gsc`` - Campaign level calls to shared helpers and ``animscripted``. * - ``src/scripting/script_anim_runtime.c`` - Compiler-side ``#using_animtree``, ``%``, and ``#animtree`` behavior.