XML:TRAM: Difference between revisions

From OniGalore
Jump to navigation Jump to search
m (link fix)
m (copy edit of material added after my last copy edit)
Line 1: Line 1:
{{XML_File_Header | type=TRAM | prev=TRAC | next=TRAS | name=Totoro Animation }}
{{XML_File_Header | type=TRAM | prev=TRAC | next=TRAS | name=Totoro Animation }}
 
{{update}}
{{TOCfloat|side=right}}
{{TOCfloat|side=right}}


 
TRAM files animation data for characters are basically made of three chunks:
TRAM files - animation data for characters - are basically made of three chunks.
* Metadata or "header": animation type, state, flags, particle, sounds, etc.
 
* Meta data or "header": animation type, state, flags, particle, sounds, etc.
* Animation data: pelvis heights, pelvis velocities, bone rotations
* Animation data: pelvis heights, pelvis velocities, bone rotations
* Attack data: damage, self-damage, extends (danger zones for AI awareness) and throws
* Attack data: damage, self-damage, extents (danger zones for AI awareness) and throws
 
The term '''animation''' is often shortened to '''anim''' by modders following the naming of commands in BSL: chr_wait_animstate, chr_wait_animtype, env_anim, etc.
 


The term '''animation''' is often shortened to '''anim''' by modders, following the naming of commands in BSL: chr_wait_animstate, chr_wait_animtype, env_anim, etc.


===Decision path of animation lookup===
===Decision path of animation lookup===
* At first the game builds a pool of anims a character can use. They are loaded from the TRAC file registered in ONCC, including parent TRACs.
* First the game builds a pool of anims a character can use. They are loaded from the TRAC file registered in [[ONCC]], including parent TRACs.
* Anims from child TRAC override those of the parent if their combination of state, type and variant is excatly the same.
* Anims from a child TRAC override those of the parent if their combination of state, type and variant is exactly the same.
* On the other hand child TRAC often miss some anims. For example elite striker don't have their own run anims, they must and will use the parent anims of normal strikers. The game was here designed to save resources. See [[XML:TRAC|TRAC]] page for details.
* Child TRACs usually omit some anims. For example, Elite Strikers don't have their own run anims, so they use the parent anims of normal Strikers. See [[XML:TRAC|TRAC]] page for details.
* A character possesses always one animation state. This term derives from state machines but you only need to know that states are the first point in the decision path determining what anims are actually allowed to played at a given moment.
* A character always possesses a single animation state. This term derives from state machines, but you only need to know that states are the first point in the decision path determining what anims are actually allowed to play at a given moment.
* It follows the full decision path:
* Here is the full decision path:
** anim '''state''' check
** anim '''state''' check
** event (user input / engine input for AI) -> [[XML_talk:StNA|context check]] -> anim '''type''' check
** event (user input, or engine input for the AI) -> [[XML_talk:StNA|context check]] -> anim '''type''' check
** anim '''variant''' check
** anim '''variant''' check
** TRAC '''weight''' check
** TRAC '''weight''' check


One detailed example:
Detailed example: Let's say that we shapeshifted to a Ninja ONCC, we are in the state Standing, and we hit the action key to perform a taunt. The engine recognizes the context (a hostile character to interact with) and looks up anims of type Taunt. Since we are in combat mode, the next anim must be of variant Combat if possible. These lookups boil down to two valid possible anims: NINCOMtaunt1 and NINCOMtaunt2. If there are multiple anims available at this point, the engine picks one of them randomly.
 
Let's say we shapeshifted to an ninja ONCC, are in state Standing and hit the action key for taunt.
 
The engine recognizes the context (an hostile character to interact with) and looks up anims of type Taunt.
 
Since we are in combat mode the following anim must be of variant Combat if possible.
 
Those lookups all boile down to two valid anims, NINCOMtaunt1 and NINCOMtaunt2.
 
If there are multiple anims avaible at this point the engine has to pick one of them randomly.
 
However, NINCOMtaunt1 has a TRAC Weight (probability) of 100 while NINCOMtaunt2 has a TRAC Weight value is just 5.
 
Chances are quite high we will not see the Moon Walk taunt.
 
Keep in mind that if the engine cannot find an anim of a specific variant it will fall back to use the non-variant anim instead.
 
Confused how Weights work? Apparently, that Weight value is only one part of the equation - otherwise NINCOMtaunt2 would never execute.
 
If there is only one anim to chose from, it will always play no matter what Weight, even if it is zero.


As for multiple anim being a valid choice the calculation seems to be this for an individual anim: weight / sum of all weight.
However, NINCOMtaunt1 has a TRAC Weight (probability) of 100 while NINCOMtaunt2 has a TRAC Weight value of just 5. So the chances are quite high that we will not see the Moon Walk taunt.


For NINCOMtaunt2 it means 5 / 105 = 0,047 (4,7%).
Keep in mind that if the engine cannot find an anim of a specific variant, it will fall back to a non-variant anim instead.


Confused by how Weights work? Apparently, the Weight value is only one part of the equation — otherwise NINCOMtaunt2 would never execute. If there is only one anim to choose from, it will always play no matter what its Weight, even if it is zero. When it comes to multiple anims being a valid choice, the calculation seems to be: weight / sum of all weights. For NINCOMtaunt2, this means 5 / 105 = 0.047 (4.7%).


===List of tags, types, and flags===
===List of tags, types, and flags===
Use the search function of your web browser to quickly find a tag.
Use the search function in your browser to quickly find a tag.


{| class="wikitable" width=100%
{| class="wikitable" width=100%
Line 66: Line 43:
| <Type>
| <Type>
| flag
| flag
| Look them up over [[XML:StNA#animation_types|HERE]]. Pool of valid TRAM (animations a character can chose from) is build from TRAC files registered in ONCC. Most of the anim types are associated with player inputs.
| Look them up over [[XML:StNA#animation_types|HERE]]. The pool of valid TRAMs (animations a character can choose from) is built from the TRAC files registered in the ONCC. Most of the anim types are connected to player inputs.
|-
|-
| <AimingType>
| <AimingType>
| flag
| flag
| Look them up over [[XML:StNA#animation_types|HERE]]. Pool of valid TRAM, and therefor TRAS, (animations a character can chose from) is build from TRSC files registered in ONCC.
| Look them up over [[XML:StNA#animation_types|HERE]]. The pool of valid TRAMs, and therefore TRASs (aiming screens a character can choose from) is built from the TRSC files registered in the ONCC.
:
:
|-
|-
Line 78: Line 55:


Look them up over [[XML:StNA#animation_states|HERE]].
Look them up over [[XML:StNA#animation_states|HERE]].
: When FromState is set to None some default behaviors are ignored and are replaced by Shortcuts.
: When FromState is set to None, some default behaviors are ignored and are replaced by Shortcuts.
: Shortcuts extend the number of states from which an animation can be played and under what conditions (replacing this atomic yes/no).
: Shortcuts extend the number of states from which an animation can be played and under what conditions (replacing this atomic yes/no).
|-
|-
Line 87: Line 64:
|valign="top"| <Varient>
|valign="top"| <Varient>
|valign="top"| flag
|valign="top"| flag
|(misspelled because Oni misspells it) If unused, tag will be simply "<Varient />", such as for non-combat animations. Otherwise contains one of these values:
|(misspelled because Oni misspells it) If unused, the tag will simply be "<Varient />", such as for non-combat animations. Otherwise it contains one of these values:
: Combat
: Combat
: LeftPistol
: LeftPistol
Line 105: Line 82:
Works as an '''alternative FromState''' collection.
Works as an '''alternative FromState''' collection.


Shortcuts are accepted if their <Shortcut><FromState> value differs from the "primary" <Lookup><FromState> value.
Shortcuts are accepted if their <Shortcut><FromState> value differs from the "primary" <Lookup><FromState> value. In other words, if you want to make a '''Shortcut''' that uses the '''same FromState''' value then you have to set '''primary FromState''' value to '''None'''. By doing that, the hardcoded interpolation frame length of about 8 frames can be overridden.
 
In other words: If you want to make a '''Shortcut''' that uses the '''same FromState''' value then you have to set '''primary FromState''' value to '''None'''. By that the hardcoded interpolation frame length of about 8 frames can be overridden.


In the following example the new interpolation length is 0. This will require the animation to match perfectly with the previous one. For a smooth transition to next animation set a suitable value at <Interpolation><End>.
In the following example, the new interpolation length is 0. This will require the animation to match perfectly with the previous one. For a smooth transition to the next animation, set a suitable value at <Interpolation><End>.


         <Lookup>
         <Lookup>
Line 123: Line 98:
             </Shortcuts>
             </Shortcuts>


[[Image:TRAM interpolation - standard case.jpg|thumb|400px|left|Scenario A: hardcoded interpolation 8 frames long; scenario B: changeable interpolation frame number]]
[[Image:TRAM interpolation - standard case.jpg|thumb|400px|left|Scenario A: hardcoded interpolation of 8 frames. Scenario B: changeable interpolation frame number.]]
|-
|-
| <Shortcut>
| <Shortcut>
Line 135: Line 110:
|valign="top"| <Length>
|valign="top"| <Length>
|valign="top"| int16
|valign="top"| int16
|Amount of interpolating frames. While interpolations with rotations are less noticeable, interpolations of different positions can cause an additional drift (i.e. sliding).
|Amount of interpolating frames. While interpolations of rotation are less noticeable, interpolations of different positions can cause drift (i.e. sliding).


This was especially observed for transitions of idle to movements and vice versa, basically any combination of animations with different accelerations at start and end. By default, animations without specified Shortcut interpolation give about 8 frames of interpolation. For moves starting or ending in idle better don't use interpolation. Just let the start and end frames have same positions and rotation values as the idle. Interpolations should always be considered as ''last resort''.
This is especially observed for transitions from idle to movements and vice versa basically any combination of animations with different accelerations at start and end. By default, animations without specified Shortcut interpolation give about 8 frames of interpolation. For moves starting or ending in idle, it's better not to use interpolation. Just give the start and end frames the same positions and rotation values as the idle. Interpolations should always be considered a ''last resort''.


This drift can be observed even in vanilla animations - most prominently in Konoko's comb_k. Konoko's left foot should be in a single position, as the animation starts from from Konoko's idle pose. However, the interpolation is causing her left foot to drift noticeably to the right and bit forward.
This drift can be observed even in vanilla animations most prominently in Konoko's comb_k. Konoko's left foot should be in a fixed position as the animation starts from from Konoko's idle pose. However, the interpolation is causing her left foot to drift noticeably to the right and a bit forward.


The reason this happens is because the interpolation "mixes" two animations. When one animation transitions into another via interpolation, part of the animation system continues playing the initial animation, and part of it is playing the follow-up animation, with all the rotations and positions getting linearly interpolated.
The reason this happens is because the interpolation "mixes" two animations. When one animation transitions into another via interpolation, part of the animation system continues playing the initial animation, and part of it is playing the follow-up animation, with all the rotations and positions getting linearly interpolated.
Line 161: Line 136:
::Same as above, only it can block low or undefined attacks.
::Same as above, only it can block low or undefined attacks.
:Attack
:Attack
::Animations with an attack part have this turned on. Uncertain what it does, but it may enable the melee soft-lock (where the character turns a bit during the animation to face a nearby enemy).
::Animations with an attack part have this turned on. It's unclear what it does, but it may enable the melee soft-lock (where the character turns a bit during the animation to face a nearby enemy).
:DropWeapon
:DropWeapon
::If the player is armed, he drops his weapon when this animation plays.
::If the player is armed, he drops his weapon when this animation plays.
Line 171: Line 146:
:::Player cannot turn by mouse while performing this animation.
:::Player cannot turn by mouse while performing this animation.
:AttackForward
:AttackForward
::Unknown, but it looks like this is rough info for the AI about where an attack is aiming, from the player's point of view.
::Unknown, but it looks like this is a hint for the AI about where an attack is aiming, from the player's point of view.
:AttackLeft
:AttackLeft
::Same as above.
::Same as above.
Line 186: Line 161:
:ThrowTarget
:ThrowTarget
::Animation can hurt anybody with its attack part, including teammates. The player can even hurt himself with the TRAM's damage part (whereas a player cannot hurt himself with his own animation's attack part). It also allows two attack parts to be executed instead of only one (maybe a bug? more than two will result in a crash).
::Animation can hurt anybody with its attack part, including teammates. The player can even hurt himself with the TRAM's damage part (whereas a player cannot hurt himself with his own animation's attack part). It also allows two attack parts to be executed instead of only one (maybe a bug? more than two will result in a crash).
:::If you set the first attack part to be able to deal damage from the 1st to the 100th frame of the TRAM, and the second attack part to deal damage within that range (e.g. from the 25th to the 41st frame), then the first attack part will deal damage from the 1st to the 100th frame (as usual), but even if it hits, that second attack part can the hurt enemy as well during frames 25–41. Note that the second attack part must be executed within the first attack part's active "window", otherwise it won't work.
:::If you set the first attack part to be able to deal damage from the 1st to the 100th frame of the TRAM, and the second attack part to deal damage within that range (e.g. from the 25th to the 41st frame), then the first attack part will deal damage from the 1st to the 100th frame (as usual), but even if it hits, that second attack part can hurt the enemy as well during frames 25–41. Note that the second attack part must be executed within the first attack part's active "window", otherwise it won't work.
:RealWorld
:RealWorld
::It appears this flag was used to create a TRAM and an OBAN from one animation source. The OBAN is supposed to store pelvis rotations and positions, allowing a character to move over obstacles/gaps. The vast majority of them are used in cutscenes.
::It appears this flag was used to create a TRAM and an OBAN from one animation source. The OBAN is supposed to store pelvis rotations and positions, allowing a character to move over obstacles/gaps. The vast majority of them are used in cutscenes.
Line 204: Line 179:
| <Atomic>
| <Atomic>
| parent tag
| parent tag
| <!--Makes animation partical atomic?-->
| Makes animation particle atomic?
|-
|-
| <Start>
| <Start>
Line 216: Line 191:
| <Invulnerable>
| <Invulnerable>
| parent tag
| parent tag
| Character will not take melee damge during a timeframe defined by Start and End frames.
| Character will not take melee damage during a time frame defined by the Start and End frames.
|-
|-
| <Start>
| <Start>
Line 296: Line 271:
|valign="top"| <Soft>
|valign="top"| <Soft>
|valign="top"| int16
|valign="top"| int16
| Player cannot make new inputs during this pause unless this animation is followed by a followup combo animation defined by <DirectAnimations><Link>.
| Player cannot enter new inputs during this pause unless this animation is followed by a combo animation defined by <DirectAnimations><Link>.
: Examples:
: Examples:
: COMcomb_p, (no pause) COMcomb_p_p
: COMcomb_p, (no pause) COMcomb_p_p
Line 310: Line 285:
|
|
* interpolates first X frames of next animation
* interpolates first X frames of next animation
* if the first follow-up animation is too short, it can continue to play even further (not observed with vanilla)
* if the first follow-up animation is too short, it can continue to play even further (not observed with vanilla anims)


While interpolations with rotations are less noticeable, interpolations of different positions can cause an additional drift.
While interpolations with rotations are less noticeable, interpolations of different positions can cause an additional drift.


This was especially observed for transitions of idle to movements and vice versa, basically any combination of animations with different accelerationsat start and end. By default, animations without specified Shortcut interpolation give about 8 frames of interpolation. For moves starting or ending in idle better don't use interpolation. Just let the start and end frames have same positions and rotation values as the idle. Interpolations should always be considered as ''last resort''.
This was especially observed for transitions of idle to movements and vice versa basically any combination of animations with different accelerations at the start and end. By default, animations without a specified Shortcut interpolation get about 8 frames of interpolation. For moves starting or ending in idle, it's better not to use interpolation. Just give the start and end frames the same positions and rotation values as the idle. Interpolations should always be considered a ''last resort''.


[[Image:TRAM interpolations - end interpolation bigger than next anim.jpg|thumb|400px|left|"end" interpolation covering multiple follow-up animations]]
[[Image:TRAM interpolations - end interpolation bigger than next anim.jpg|thumb|400px|left|"End" interpolation covering multiple follow-up animations.]]
|-
|-
| <Max>
| <Max>
Line 324: Line 299:
|valign="top"| <FinalRotation>
|valign="top"| <FinalRotation>
|valign="top"| float
|valign="top"| float
|valign="top"| Ending rotation in degrees. (During animation the camera is detached rotation-wise. If this value matches the body's final rotation it will prevent a 'glitchy' re-attaching.)
|valign="top"| Ending rotation in degrees. (During an animation, the camera is detached rotation-wise. If this value matches the body's final rotation, it will prevent a "glitchy" re-attaching.)
|-
|-
|valign="top"| <Direction>
|valign="top"| <Direction>
Line 337: Line 312:
| <Vocalization>
| <Vocalization>
| int
| int
| Id of one of the [[XML:SNDD#step_1:_preparing_the_TRAM|SoundConstances in ONCC]]
| ID of one of the [[XML:SNDD#step_1:_preparing_the_TRAM|SoundConstants in ONCC]]
|-
|-
| <ActionFrame>
| <ActionFrame>
| int
| int
| Frame number for spacial events associated with this animation: weapon theft in disarms, weapon holster, Mukade actually teleporting, items getting handed over to player. "Give me that hypo!" Yada yada.
| Frame number for any special events associated with this animation: weapon theft via disarm, weapon holstering, Mukade teleporting, items getting handed over to player, etc.
|-
|-
| <Impact>
| <Impact>
Line 361: Line 336:
|valign="top"| <End>
|valign="top"| <End>
|valign="top"| int
|valign="top"| int
| frame number for particle to end (if number exceeds frame count of animation the particle will simply die with end of animation)
| frame number for particle to end (if the number exceeds frame count of animation, the particle will simply die at the end of the animation)
|-
|-
|valign="top"| <Bone>
|valign="top"| <Bone>
Line 487: Line 462:
| <Velocity>
| <Velocity>
| 2 x float
| 2 x float
|Relative positions. (Delta values: the numbers represent only the change of position from one frame to another.)
|Relative positions (delta values); the numbers represent the change in position from one frame to another.
|-
|-
| <Rotations>
| <Rotations>
Line 509: Line 484:
| <PositionOffset>
| <PositionOffset>
| parent tag
| parent tag
| <PositionOffset> and <Positions> belong together. In the [[OBD:TRAM/raw0x30|binaries]], they are written in place. '''Seems unused, changing those has no effect in game.'''
| <PositionOffset> and <Positions> belong together. In the [[OBD:TRAM/raw0x30|binaries]], they are written in place. '''Seems unused; changing them has no effect in-game.'''
|-
|-
| <X>
| <X>
Line 525: Line 500:
| <Position>
| <Position>
| float
| float
| seems to be unused (also with chr_debug_sphere = 1 the spheres remain unchanged)
| seems to be unused (and when checking this with "chr_debug_sphere = 1", the spheres remain unchanged)
|-
|-
| <Height>
| <Height>
Line 533: Line 508:
| <YOffset>
| <YOffset>
| float
| float
| y offset of the vertical extent from character location  
| Y offset of the vertical extent from character location  
|-
|-
| <ThrowSource>
| <ThrowSource>
Line 546: Line 521:
|valign="top"| 3 * float
|valign="top"| 3 * float
| Contains XYZ values, which position the target character:
| Contains XYZ values, which position the target character:
*X - Side axis. Negative values move the target to the right, positive values move the target to the left.
*X - Side axis. Negative values move the target to the right and positive values move the target to the left.
*Y - Height axis. Negative values move the target downwards, but in case of collision due to too low negative value, it will not make the target go below the surface. Positive values make the target go upwards - if the value is too big, the target will teleport above, and then immediately start falling, interrupting the target animation.
*Y - Height axis. Negative values move the target downwards, but cannot make the target go below the floor. Positive values make the target go upwards if the value is too big, the target will teleport upward and then immediately start falling, interrupting the target animation.
*Z - Forward axis. Negative values move the target backwards, positive values move the target forward.
*Z - Forward axis. Negative values move the target backwards and positive values move the target forward.
|-
|-
| <Angle>
| <Angle>
Line 556: Line 531:
| <Distance>
| <Distance>
| float
| float
| Activation distance. The throw can be triggered if it is within this range. However the value must be greater than the equivalent TRAM in parent TRAC.
| Activation distance. The throw can be triggered if it is within this range. However the value must be greater than the equivalent TRAM in the parent TRAC.
|-
|-
|valign="top"| <TargetType>
|valign="top"| <TargetType>
Line 589: Line 564:
: "bk" = thrower is facing victim's back
: "bk" = thrower is facing victim's back
: "throw" inside TRAM names is sometimes shortened to "thr"
: "throw" inside TRAM names is sometimes shortened to "thr"
: "p"/"k" = triggered by punch or kick button ("p" can also be omitted)
: "p"/"k" = triggered by punch or kick button ("p" is sometimes omitted)
|-
|-
| <SelfDamage>
| <SelfDamage>
Line 632: Line 607:
: Unblockable
: Unblockable
: Low - Target of attack needs to crouch in order to block this attack.
: Low - Target of attack needs to crouch in order to block this attack.
: High - Blocker needs to stand; if Low and High are set then blocker can block from both standing and crouching positions.
: High - Blocker needs to stand; if both Low and High are set, blocker can block from both standing and crouching positions.
: HalfDamage - Blocker receives half of the normal damage.
: HalfDamage - Blocker receives half of the normal damage.
|-
|-
| <Knockback>
| <Knockback>
| float
| float
| Target gets "knockback"ed by this amount.
| Target gets knocked back by this amount.
|-
|-
| <HitPoints>
| <HitPoints>
Line 649: Line 624:
| <HitLength>
| <HitLength>
| int16
| int16
| Number of frames for how long the target should remain in his "hit" animation state when he gets hit.
| Number of frames that the target should remain in his hit animation state when he gets hit.
|-
|-
| <StunLength>
| <StunLength>
| int16
| int16
| Number in frames for how long the target should remain in his blocking animation when he blocks the attack.
| Number of frames that the target should remain in his blocking animation state when he blocks the attack.
|-
|-
| <StaggerLength>
| <StaggerLength>
| int16
| int16
| Number of frames for how long the target should perform his "stagger" animation after a successful block.
| Number of frames that the target should perform his stagger animation after a successful block.
|-
|-
| <Extents>
| <Extents>
| parent tag
| parent tag
| Explained below. Automatically calculated by OniSplit if there's a DAE file referenced in XML.
| Explained below. Automatically calculated by OniSplit if there's a DAE file referenced in the XML.
|-
|-
| <Extent>
| <Extent>
Line 689: Line 664:
|valign="top"| <Length>
|valign="top"| <Length>
|valign="top"| float
|valign="top"| float
| Horizontal extents, explained below. They create a "danger zone" around the attacker so that the AI has a chance to dodge an attack.
| Horizontal extents, explained below. They create a "danger zone" around the attacker which the AI uses to try to dodge an attack.
|}
|}


===Export===
===Export===
Line 703: Line 677:
  Cannot find instance 'TRAMKONPIScorner_hide'
  Cannot find instance 'TRAMKONPIScorner_hide'


Ignore them, as those files doesn't exist. (Someday we should remove them from the TRACs.)
Ignore them, as those files doesn't exist. (Someday we should remove them from the TRACs.)


====Via command line====
====Via command line====
Line 713: Line 687:


====Via Vago====
====Via Vago====
[[Image:Vago_xml_plus_dae_extraction.png|thumb|200px|right|combined extraction of dae and xml]]
[[Image:Vago_xml_plus_dae_extraction.png|thumb|200px|right|Combined extraction of DAE and XML.]]


When you start '''[[Vago_(tool)|Vago]]''', the "General" tab should be open by default. If not, click on it. Then follow these five easy steps.
When you start '''[[Vago_(tool)|Vago]]''', the "General" tab should be open by default. If not, click on it. Then follow these five easy steps.
<!-- General tab should be step 1 but i've already another img. If Vago gets updated I will upload a better img. -->


'''Step 1:''' Select "ONI" as input format ("From").
'''Step 1:''' Select "ONI" as input format ("From").
Line 722: Line 695:
'''Step 2:''' Select "XML" as output format ("To").
'''Step 2:''' Select "XML" as output format ("To").


'''Step 3:''' Check "Another TRAM" to chose a character animation file.
'''Step 3:''' Check "Another TRAM" to choose a character animation file.


'''Step 4:''' Click "Add" button to choose an ONCC file.
'''Step 4:''' Click "Add" button to choose an ONCC file.


'''Step 5:''' Click "Convert".
'''Step 5:''' Click "Convert".


====Via Simple OniSplit GUI====
====Via Simple OniSplit GUI====
Line 734: Line 706:
'''[http://www.paradox.oni2.net/programs/Simple_OniSplit_GUI.zip Simple OniSplit GUI]''' post-edits the DAE to fix missing textures. The character-related .oni files must be all in one folder. Usually the level0_Final folder does the trick.
'''[http://www.paradox.oni2.net/programs/Simple_OniSplit_GUI.zip Simple OniSplit GUI]''' post-edits the DAE to fix missing textures. The character-related .oni files must be all in one folder. Usually the level0_Final folder does the trick.


'''Step 1:''' Drag and drop TRAM and ONCC into the [http://www.paradox.oni2.net/images/simpleOniSplitGui.png big field.] (One by one or simultaneously; the order doesn't matter.)
'''Step 1:''' Drag and drop the TRAM and ONCC into the [http://www.paradox.oni2.net/images/simpleOniSplitGui.png big field.] (One by one or simultaneously; the order doesn't matter.)


'''Step 2:''' Hit "Convert".
'''Step 2:''' Hit "Convert".


===Editing 3D data===
===Editing 3D data===
Line 745: Line 716:


Here are some hints for creating animations when there is no rigging available:
Here are some hints for creating animations when there is no rigging available:
* Use the ONCC model in your 3D editor that is also intended for the animations. This makes sure the pelvis height will match and feet will not float in the air or go through the ground.  
* Use the ONCC model in your 3D editor that will actually make use of the animations. This makes sure that the pelvis height will match and that the character's feet will not float in the air or go through the ground.  
* First frame and last frame should match the probable previous and follow-up animations. This will reduce the necessity for long interpolations.
* The first frame and last frames should match the probable previous and follow-up animations. This will reduce the necessity for long interpolations.
* When setting keyframes each body part should have been moved. This rule of thumb will give a more natural looking animation.
* When setting keyframes, each body part should have moved. This rule of thumb will give a more natural-looking animation.
* The first body part to be animated is always the pelvis.
* The first body part to be animated is always the pelvis.
* Watch out for pelvis rotations so that the xyz rotations don't overlap too much otherwise you will get into a [[wikipedia:Gimbal_lock|gimbal lock]].
* Watch out for pelvis rotations so that the XYZ rotations don't overlap too much, otherwise you will get into a [[wikipedia:Gimbal_lock|gimbal lock]].
 
See also our [http://oni.bungie.org/forum/viewtopic.php?id=1433 OCF thread].


Also see our [http://oni.bungie.org/forum/viewtopic.php?id=1433 OCF thread].


====Blender====
====Blender====
Theoretical possible. Very difficult in practice and we don't have a tutorial on this one.
Theoretically possible. Very difficult in practice and we don't have a tutorial on this one.
 


===Import===
===Import===
  onisplit -create output_path path_to\TRAMname.xml
  onisplit -create output_path path_to\TRAMname.xml


==Additional details==
==Additional details==
===Existing TRAMS===
===Existing TRAMS===
TRAMS used in Oni follow a naming pattern. A list of all Combat TRAMS in game, and their naming can be found [[Combat moves|here.]]
TRAMS used in Oni follow a naming pattern. A list of all combat TRAMS in-game and their naming can be found [[Combat moves|here.]]


===Speeding up existing animations===
===Speeding up existing animations===
s10k has created a XmlTools patch that allow the speedup of any existing TRAM (by removing frames). More information and download [http://mods.oni2.net/node/354 here.]
s10k has created an XmlTools script that allows the speed-up of any existing TRAM by removing frames. More information and download link [http://mods.oni2.net/node/354 here.]
 


===Attacks===
===Attacks===
Line 779: Line 745:
::<Angle> at which this extent radiates from the character.
::<Angle> at which this extent radiates from the character.
::<Length> of this extent.
::<Length> of this extent.
::<MinY> minimal height of this extent.
::<MinY> minimum height of this extent.
::<MaxY> maximum height of this extent.
::<MaxY> maximum height of this extent.
:Length, MinY and MaxY serve to create an invisible area in space which is "dangerous to be in". If an AI intersects with this area and notices it (refer to the Notice field in [[MELE]]), it will attempt to block or dodge according to its modifiers in its MELE profile (again, see the MELE page).
:Length, MinY and MaxY serve to create an invisible area in space which is "dangerous to be in". If an AI intersects with this area and notices it (refer to the Notice field in [[MELE]]), it will attempt to block or dodge according to its modifiers in its MELE profile.
::The number of <Extent>s is equal to the number of attack frames: <End> minus <Start> plus one (because start frame counts too). For example, for TRAMKONCOMkick_low1: <End>30</End> minus <Start>22</Start> plus one = 9 <Extent>s.
::The number of <Extent>s is equal to the number of attack frames: <End> minus <Start> plus one (because the start frame counts too). For example, for TRAMKONCOMkick_low1: <End>30</End> minus <Start>22</Start> plus 1 = 9 <Extent>s.


:These extents are pretty impossible to guess, so leave them alone until Neo comes up with extent computation (probably from attack bones and bone rotations). However, always add at least one set of component tags, because those Length, MinY and MaxY components will be taken as the longest extent, the highest Y value, and the lowest Y value. Without those, a character won't react to this attack.
:These extents are pretty impossible to guess, so leave them alone until Neo comes up with extent computation (probably from attack bones and bone rotations). However, always add at least one set of component tags, because those Length, MinY and MaxY components will be taken as the longest extent, the lowest Y value, and the highest Y value. Without those, a character won't react to this attack.


*'''<HorizontalExtents>''' stores this info:
*'''<HorizontalExtents>''' stores this info:
::36 fields (exactly 36, otherwise it won't compile back into a .oni file), which correspond to areas in 10° intervals around the character as described above.
::36 fields (exactly 36, otherwise it won't compile back into a .oni file), which correspond to areas in 10° intervals around the character as described above.


====Adding extents to an existing animation====
====Adding extents to an existing animation====
Let's say that you want to convert a non-attack animation to a damage-dealing animation. Non-attack TRAMs do not have extents information used to notify the AIs about incoming attacks, so how do you generate this information from the animation?
Let's say that you want to convert a non-attack animation to a damage-dealing animation. Non-attack TRAMs do not have extents information used to notify the AIs about incoming attacks, so how do you generate this information from the animation?
:1. Export the animation to XML with a body attached. If you extract using just "-extract:xml dest_folder TRAMsomething.oni", you'll get the 3D animation data inside the XML (namely, the tags Heights, Velocities, Rotations, PositionOffset, and Positions; for an attack animation, you'll also get Attacks and AttackRing, and inside Attacks' elements, each Attack element will have Extents at the end of it).
:1. Export the animation to XML with a body attached. If you extract using just "-extract:xml dest_folder TRAMsomething.oni", you'll get the 3D animation data inside the XML (namely, the tags Heights, Velocities, Rotations, PositionOffset, and Positions; for an attack animation, you'll also get Attacks and AttackRing, and inside Attacks' elements, each Attack element will have Extents at the end of it).
:However, if you extract this same animation using "-extract:xml dest_folder TRAMsomething.oni '''-anim-body ONCCtramuser.oni'''", the animation data will be placed in a DAE file along with the character model geometry. Be sure to pick a body with a representative size for the character classes that will actually use this TRAM, because the extents will be calculated from it. The XML file will be very short without the 3D data in it. This is how we want the non-attack TRAM to look. We do not know the extents information that should go in Extents or AttackRing, so we just want to add the part that distinguishes a DAE-extracted attack TRAM XML from a DAE-extracted non-attack TRAM XML. That part is the Attacks section, without the Extents under each Attack.
:However, if you extract this same animation using "-extract:xml dest_folder TRAMsomething.oni '''-anim-body ONCCtramuser.oni'''", the animation data will be placed in a DAE file along with the character model geometry. Be sure to pick a body with a size that's representative of the character classes that will actually use this TRAM, because the extents will be calculated from it. The XML file will be very short without the 3D data in it — this is how we want the non-attack TRAM to look. We do not know the extents information that should go in Extents or AttackRing, so we just want to add the part that distinguishes a DAE-extracted attack TRAM XML from a DAE-extracted non-attack TRAM XML. That part is the Attacks section, without the Extents under each Attack.
:2. First, consider whether the TRAM should have something added to its Flags section, like Attack or ThrowTarget.
:2. First, consider whether the TRAM should have something added to its Flags section, like Attack or ThrowTarget.
:3. Now add to the XML of the non-attack TRAM data in the following format (after the <SelfDamage /> section, typically):
:3. Now add to the XML of the non-attack TRAM data in the following format (after the <SelfDamage /> section, typically):
Line 812: Line 777:
:Do not add an AttackRing section after Attacks.
:Do not add an AttackRing section after Attacks.
:4. Import this with "-create dest_folder TRAMsomething.xml". The Extents sections and the AttackRing will be calculated by OniSplit from the attached DAE.
:4. Import this with "-create dest_folder TRAMsomething.xml". The Extents sections and the AttackRing will be calculated by OniSplit from the attached DAE.
:5. If you need this information for a patch mod, run "-extract:xml" on the TRAMsomething.oni you've created, <u>without</u> using "-anim-body". Now you can copy the Extents and AttackRing data to your XML patch. For an example of how the patch should look, see the [http://mods.oni2.net/node/311 Domino Knockdowns] mod.
:5. If you need this information for a patch mod, run "-extract:xml" on the TRAMsomething.oni you've created <u>without</u> using "-anim-body". Now you can copy the Extents and AttackRing data to your XML patch. For an example of how the patch should look, see the [http://mods.oni2.net/node/311 Domino Knockdowns] mod.
 


===Combos===
===Combos===
The type and order of keystroke or mouse clicks for combos is hardcoded.
The type and order of player input for triggering a given animation type (such as PPK) is hardcoded, and new animation types cannot be created. To assign an animation type to a specific combo attack, you set a corresponding value in <Lookup><Type>.
 
To assign an animation for a specific combo attack you set corresponding value in <Lookup><Type>.


Setting a value in <Link> of '''<DirectAnimations>''' will do two things:
Setting a value in <Link> of '''<DirectAnimations>''' will do two things:
# It will increase the time for player input, meaning the next animation can be executed more easily. (In vanilla the Crescent Moon Kick has no link in KONCOMcomb_k_k_kfw and therefore is difficult to use.)
# It will increase the time for player input, meaning the next animation can be executed more easily. (In vanilla Oni, the Crescent Moon Kick has no link in KONCOMcomb_k_k_kfw and therefore is difficult to use.)
# It disables <Interpolation><End> for the next combo anim.
# It disables <Interpolation><End> for the next combo anim.
# It enables <Pause><Soft> and <Pause><Hard>.
# It enables <Pause><Soft> and <Pause><Hard>.


===Just Frame combos===
===Just Frame combos===
For short '''JF combos''' or '''JF anims'''. Created by Delano, inspired by the game series Tekken.
For short '''JF combos''' or '''JF anims'''. Created by Delano762, inspired by the game series Tekken. "JF" means that you have to press certain keys (W+K or W+P) at the exact same time, which is more difficult than it might sound. Delano's mod 54000 New Combat Moves for Konoko has a collection of animations which utilize existing animation types to create new combos.
 
JF means you have to press certain keys (w + k or w + p) at the exact time, which is more difficult than it might sound.
 
Package 54000 has basically a collection of new state cycles.
 


Example 1:
Example 1:
Line 839: Line 795:
* old forward kick = TRAMKONCOMkick_fw <FromState>RunStart
* old forward kick = TRAMKONCOMkick_fw <FromState>RunStart
** key strokes: w, k
** key strokes: w, k


Example 2:
Example 2:
Line 846: Line 801:
* old forward punch = TRAMKONCOMpunch_fw <FromState>RunStart
* old forward punch = TRAMKONCOMpunch_fw <FromState>RunStart
** key strokes: w, p
** key strokes: w, p


===Throws===
===Throws===
Throw target animations are registered in the TRAC of the throw initiator (AKA the throw source). Target animations are forced onto the other character, removing the need to have that animation in the target's TRAC. Throw target (TRAM*tgt) animations can cover only up to 256 (0-255) frames.
Throw target animations are registered in the TRAC of the throw initiator (AKA the throw source). Target animations are forced onto the other character, removing the need to have that animation in the target's TRAC. Throw target (TRAM*tgt) animations can only cover up to 256 frames (0-255).
 


====Forward throws====
====Forward throws====
Scenario: you load two characters into Mod Tool and rotate (+/-180°) the throw target character because you need them to stand face to face as you work on an animation. When you are done animating, the target animation would need to be reversed again. This means multiplying the velocities by -1; the rotation also needs correcting. So it looks like you need *(-1) for the x rotation and -/+180° (depending on your initial change) for the y rotation.
Scenario: You load two characters into Mod Tool and rotate (+/-180°) the throw target character because you need them to stand face to face as you work on an animation. When you are done animating, the target animation would need to be reversed again. This means multiplying the velocities by -1; the rotation also needs correcting. So it looks like you need *(-1) for the x rotation and -/+180° (depending on your initial change) for the Y rotation.
 


====Blender Forward throw adjustment script====
====Blender Forward throw adjustment script====
This is a Blender script for rotating -/+180° and adding PositionOffset to a forward throw Target animation. This was made by one hero from Blender Discord named Danta. The add_object_offset_about_cursor_Z was written by Delano762.
This is a Blender script for rotating -/+180° and adding PositionOffset to a forward throw Target animation. This was made by a hero from the Blender Discord named Danta. The add_object_offset_about_cursor_Z() function was written by Delano762.


What this script does is, for each frame of the range you specify, rotate the selected object by 180 degrees (or however many you want), and translate it by a given Position offset, that's available in the <TargetAdjustment> <Position> tag of the attacker's throw animation XML. It also has a frame checking functionality that's bugged; however, ultimately there is no real reason at the moment to use it - however, it may come in handy in the future, so it should be left in this snippet commented.
For each frame in the range you specify, this script rotates the selected object by 180 degrees (or however many you want), and translates it by the offset found in the <TargetAdjustment> <Position> tag of the attacker's throw animation XML. It also has a frame-checking functionality that's buggy; ultimately there is no real reason at the moment to use it, but it may come in handy in the future, so it should be left in this snippet.


Step-by-step guide on using this script:
Step-by-step guide on using this script:
 
:1. Import a throw animation and its target animation into Blender.
'''Step 1:''' Import a throw animation and its target animation into Blender.
:2. Open Scripting tab.
 
:3. Create a new text, and name it however you want with .py extension, e.g. TRAMAdjuster.py
'''Step 2:''' Open Scripting tab.
:4. Paste the script.
 
:5. On the following lines…
'''Step 3:''' Create a new text, and name it however you want with .py extension, e.g. TRAMAdjuster.py
 
'''Step 4:''' Paste the script.
 
'''Step 5:''' In the following lines:


<pre>scene.frame_set(start)
<pre>scene.frame_set(start)
for i in range(start, end):</pre>
for i in range(start, end):</pre>


Set ''start'' and ''end'' to the start frame of the animation (always 0 for vanilla anims, but if you're animating and starting from 1, you'll want it set to 1) and the ''end'' to the end+1 frame of your animation, meaning, if you have a 99 frame animation, set ''end'' to 100.
…set ''start'' and ''end'' to the start frame of the animation (always 0 for vanilla anims, but if you're animating and starting from 1, you'll want it set to 1) and the ''end'' to the (end + 1) frame of your animation; e.g. if you have a 99 frame animation, set ''end'' to 100.


'''Step 6:''' In the following line:
:6. On the following line…


<pre>add_object_offset_about_cursor_Z(obj,x,-z,-y) #translate object</pre>
<pre>add_object_offset_about_cursor_Z(obj,x,-z,-y) #translate object</pre>


Paste the values from the <Position> tag accordingly to the order in the arguments of the function. The minus means the value should be inverted in the function. As an example, assuming you have the following <Position> tag:
…paste the values from the <Position> tag according to the order of the function arguments. The minus sign means the value should be inverted in the function. As an example, assuming you have the following <Position> tag…


<pre><Position>1 2 -3</Position></pre>
<pre><Position>1 2 -3</Position></pre>


The function should be following:
…the function call should be as follows…


<pre>add_object_offset_about_cursor_Z(obj,1,3,-2) #translate object</pre>
<pre>add_object_offset_about_cursor_Z(obj,1,3,-2) #translate object</pre>


'''Step 7:''' Select the pelvis of the target animation.
:7. Select the pelvis of the target animation.
 
:8. Press Shift+C to ensure your 3D cursor is in the center of the animation.
'''Step 8:''' Press Shift + C to ensure your 3D cursor is in the center of the animation.
:9. Set the Transform Pivot Point to "3D Cursor".
 
:10. On the Scripting tab, run the script.
'''Step 9:''' Set the Transform Pivot Point to 3D Cursor.
:11. The target should be now adjusted as expected.
 
:12. If you want to revert the target back to an exportable position and rotation, simply invert the Z argument in the add_object_offset_about_cursor_Z function and run the script again.
'''Step 10:''' In the Scripting tab, run the script.
 
'''Step 11:''' The target should be now adjusted as expected.
 
'''Step 12:''' If you want to revert the target back to an exportable position and rotation, simply invert the z argument in the add_object_offset_about_cursor_Z function and run the script again.


<pre>import bpy
<pre>import bpy
Line 951: Line 893:
obj.keyframe_insert(data_path="location", frame=i) #keyframe location
obj.keyframe_insert(data_path="location", frame=i) #keyframe location
</pre>
</pre>


====Excel macro====
====Excel macro====
Line 959: Line 900:
* For all TRAMs except overlays. [https://www.youtube.com/watch?v=vDTPYfvMf4M Demo vid here]. Usage:
* For all TRAMs except overlays. [https://www.youtube.com/watch?v=vDTPYfvMf4M Demo vid here]. Usage:
* Put your files into the "input_and_output" folder.
* Put your files into the "input_and_output" folder.
* Disable macro security if you don't want to have to click on the macro options button every time.
* Disable macro security if you don't want to have to click on the "Enable Content" button every time.
* Close other worksheets before you run the macro.
* Close other worksheets before you run the macro.
* If you are not afraid of VBA code, you can enter the dev environment by hitting Alt+F11. If you want to extend the attack library with more screenshots and settings, search for: "LibraryThrows", " LibraryAttack", "Picture", and "CBAttackHelp.AddItem".
* If you are not afraid of VBA code, you can enter the dev environment by hitting Alt+F11. If you want to extend the attack library with more screenshots and settings, search for "LibraryThrows", " LibraryAttack", "Picture", and "CBAttackHelp.AddItem".
 


===Run animations===
===Run animations===
Line 990: Line 930:
Image:XML_TRAM_STRIKErun1stepa.png|STRIKErun1stepa
Image:XML_TRAM_STRIKErun1stepa.png|STRIKErun1stepa
</gallery>
</gallery>


===List of unused animations===
===List of unused animations===
Here are all the known unused animations. These could be reintegrated/recycled/whatever....
Here are all the known unused animations. These could be recycled in a new mod.
 


'''From the original game'''
'''From the original game'''
* KONOKOconsole_punch: what the name says (the engine can use that animation depending on the console's configuration, see [[OBD:BINA/OBJC/CONS|CONS]])  
* KONOKOconsole_punch: What the name says (the engine can use that animation depending on the console's configuration, see [[OBD:BINA/OBJC/CONS|CONS]]) .
* KONOKOlev3_intro: looks like she was placing something (bomb?) and then running away
* KONOKOlev3_intro: Looks like she's placing something (bomb?) and then running away.
* KONOKOlev4_undress: from an aborted clothes-changing cutscene
* KONOKOlev4_undress: From an aborted clothes-changing cutscene.
* KONOKOlev16_bomb: planting a bomb
* KONOKOlev16_bomb: Planting a bomb.
* KONCOMsuper_kick: now used in OTA scripts (mod) as spawn event, and by custom made character [[Shinatama Bot]]
* KONCOMsuper_kick: Now used in [[OTA]] as a spawn event, and by the fan-made character [[Shinatama Bot]].
* KONCOMsuper_punch: KONCOMpunch_heavy but without the shouted attack name, has HalfDamage flag, and does 10 less damage in its first attack part
* KONCOMsuper_punch: KONCOMpunch_heavy but without the shouted attack name, has HalfDamage flag, and does 10 less damage in its first attack part.
* COMPISidle_special1: Comguy checking environment and his gun (meant for a feature that would visually depict an elevation in the AI's level of alertness after, say, hearing a noise)
* COMPISidle_special1: Comguy checking environment and his gun; meant for a feature that would visually depict an elevation in the AI's level of alertness after, say, hearing a noise.
* STRPISidle_special1: Striker checking his his gun and communicating with an ally (another unused alertness animation)
* STRPISidle_special1: Striker checking his his gun and communicating with an ally (another unused alertness-elevation animation).
* THUGlev1_direct: Thug probably directing a truck driver
* THUGlev1_direct: Thug probably directing a truck driver.
 


'''From modders'''
'''From modders'''


[[Image:female_stun.jpg|right|thumb|charA and charB performing stun animations]]
[[Image:female_stun.jpg|right|thumb|Char A and Char B performing stun animations.]]


* http://mods.oni2.net/node/376
* http://mods.oni2.net/node/376
Line 1,019: Line 956:
** female_stun--dae.zip
** female_stun--dae.zip


 
===Special effects===
===FX - special effects===
If the scene is overloaded by too many particles (including motion blur), these effects will cease being rendered. So don't overuse effects.
If the scene is overloaded by particle - including motion blur - these effects will stop to be rendered.
 
So, don't overuse effects.
 


====Color trails====
====Color trails====
Line 1,075: Line 1,008:
                 <BodyPart>-1</BodyPart>
                 <BodyPart>-1</BodyPart>
             </ONCPParticle>
             </ONCPParticle>


====Motion blur====
====Motion blur====
[[Image:XML_TRAM_willow_kick_with_motion_blur.jpg|thumb|200px]]
[[Image:XML_TRAM_willow_kick_with_motion_blur.jpg|thumb|200px]]


====Impact effect====
====Impact effect====
[[Image:XML_TRAM_KONCOMkick_fw_with_ninflash1.jpg|thumb|200px]]
[[Image:XML_TRAM_KONCOMkick_fw_with_ninflash1.jpg|thumb|200px]]


See also: [[XML:ONCC]].
See also [[XML:ONCC]].
 


{{XML}}
{{XML}}

Revision as of 23:10, 16 March 2021

TRAM : Totoro Animation
XML modding tips
  • See HERE to start learning about XML modding.
  • See HERE if you are searching for information on how to handle object coordinates.
  • See HERE for some typical modding errors and their causes.
XML.png
XML

TRAC << Other file types >> TRAS

switch to OBD page


Aged parchment-60px.jpg

This page contains information that is out of date.
Please update this information to reflect where the community is at today.

TRAM files — animation data for characters — are basically made of three chunks:

  • Metadata or "header": animation type, state, flags, particle, sounds, etc.
  • Animation data: pelvis heights, pelvis velocities, bone rotations
  • Attack data: damage, self-damage, extents (danger zones for AI awareness) and throws

The term animation is often shortened to anim by modders, following the naming of commands in BSL: chr_wait_animstate, chr_wait_animtype, env_anim, etc.

Decision path of animation lookup

  • First the game builds a pool of anims a character can use. They are loaded from the TRAC file registered in ONCC, including parent TRACs.
  • Anims from a child TRAC override those of the parent if their combination of state, type and variant is exactly the same.
  • Child TRACs usually omit some anims. For example, Elite Strikers don't have their own run anims, so they use the parent anims of normal Strikers. See TRAC page for details.
  • A character always possesses a single animation state. This term derives from state machines, but you only need to know that states are the first point in the decision path determining what anims are actually allowed to play at a given moment.
  • Here is the full decision path:
    • anim state check
    • event (user input, or engine input for the AI) -> context check -> anim type check
    • anim variant check
    • TRAC weight check

Detailed example: Let's say that we shapeshifted to a Ninja ONCC, we are in the state Standing, and we hit the action key to perform a taunt. The engine recognizes the context (a hostile character to interact with) and looks up anims of type Taunt. Since we are in combat mode, the next anim must be of variant Combat if possible. These lookups boil down to two valid possible anims: NINCOMtaunt1 and NINCOMtaunt2. If there are multiple anims available at this point, the engine picks one of them randomly.

However, NINCOMtaunt1 has a TRAC Weight (probability) of 100 while NINCOMtaunt2 has a TRAC Weight value of just 5. So the chances are quite high that we will not see the Moon Walk taunt.

Keep in mind that if the engine cannot find an anim of a specific variant, it will fall back to a non-variant anim instead.

Confused by how Weights work? Apparently, the Weight value is only one part of the equation — otherwise NINCOMtaunt2 would never execute. If there is only one anim to choose from, it will always play no matter what its Weight, even if it is zero. When it comes to multiple anims being a valid choice, the calculation seems to be: weight / sum of all weights. For NINCOMtaunt2, this means 5 / 105 = 0.047 (4.7%).

List of tags, types, and flags

Use the search function in your browser to quickly find a tag.

tag type description
<Lookup> parent tag
<Type> flag Look them up over HERE. The pool of valid TRAMs (animations a character can choose from) is built from the TRAC files registered in the ONCC. Most of the anim types are connected to player inputs.
<AimingType> flag Look them up over HERE. The pool of valid TRAMs, and therefore TRASs (aiming screens a character can choose from) is built from the TRSC files registered in the ONCC.
<FromState> flag
Primary <FromState> in <Lookup> uses about 8 interpolating frames by default. Use Shortcut's <FromState> to override this frame number.

Look them up over HERE.

When FromState is set to None, some default behaviors are ignored and are replaced by Shortcuts.
Shortcuts extend the number of states from which an animation can be played and under what conditions (replacing this atomic yes/no).
<ToState> flag Look them up over HERE.
<Varient> flag (misspelled because Oni misspells it) If unused, the tag will simply be "<Varient />", such as for non-combat animations. Otherwise it contains one of these values:
Combat
LeftPistol
LeftRifle
Panic
RightPistol
RightRifle
Sprint
<FirstLevel> int16 Number of first level in which move becomes available to the player ("0" to make it available from the start).
<Shortcuts> parent tag

Works as an alternative FromState collection.

Shortcuts are accepted if their <Shortcut><FromState> value differs from the "primary" <Lookup><FromState> value. In other words, if you want to make a Shortcut that uses the same FromState value then you have to set primary FromState value to None. By doing that, the hardcoded interpolation frame length of about 8 frames can be overridden.

In the following example, the new interpolation length is 0. This will require the animation to match perfectly with the previous one. For a smooth transition to the next animation, set a suitable value at <Interpolation><End>.

       <Lookup>
           ...
           <FromState>None</FromState>
           ...
           <Shortcuts>
               <Shortcut>
                   <FromState>Standing</FromState>
                   <Length>0</Length>
                   <ReplaceAtomic>no</ReplaceAtomic>
               </Shortcut>
           </Shortcuts>
Scenario A: hardcoded interpolation of 8 frames. Scenario B: changeable interpolation frame number.
<Shortcut> parent tag
<FromState> flag Look them up over HERE.
<Length> int16 Amount of interpolating frames. While interpolations of rotation are less noticeable, interpolations of different positions can cause drift (i.e. sliding).

This is especially observed for transitions from idle to movements and vice versa — basically any combination of animations with different accelerations at start and end. By default, animations without specified Shortcut interpolation give about 8 frames of interpolation. For moves starting or ending in idle, it's better not to use interpolation. Just give the start and end frames the same positions and rotation values as the idle. Interpolations should always be considered a last resort.

This drift can be observed even in vanilla animations — most prominently in Konoko's comb_k. Konoko's left foot should be in a fixed position as the animation starts from from Konoko's idle pose. However, the interpolation is causing her left foot to drift noticeably to the right and a bit forward.

The reason this happens is because the interpolation "mixes" two animations. When one animation transitions into another via interpolation, part of the animation system continues playing the initial animation, and part of it is playing the follow-up animation, with all the rotations and positions getting linearly interpolated.

<ReplaceAtomic> flag
yes
no
<Flags> flag
RuntimeLoaded
(This bit is not stored on disk; it is used at runtime to mark that the animation was loaded.)
Invulnerable
While playing this animation, the player is invulnerable to melee damage and also cannot be thrown. Damage from particles and fall damage still hurt.
BlockHigh
While playing this animation, the player is invulnerable to high or undefined attacks within some arc in front of him. If you set this flag on an animation where the player character is spinning, then the character can still be kicked in the back or thrown.
BlockLow
Same as above, only it can block low or undefined attacks.
Attack
Animations with an attack part have this turned on. It's unclear what it does, but it may enable the melee soft-lock (where the character turns a bit during the animation to face a nearby enemy).
DropWeapon
If the player is armed, he drops his weapon when this animation plays.
InAir
Something to do with jumps; not investigated.
Atomic
The whole animation must be played; player cannot interrupt it once it starts.
NoTurn
Player cannot turn by mouse while performing this animation.
AttackForward
Unknown, but it looks like this is a hint for the AI about where an attack is aiming, from the player's point of view.
AttackLeft
Same as above.
AttackRight
Same as above.
AttackBackward
Same as above.
Overlay
Not a standalone animation; it just overwrites part of an already-playing one, e.g. the weapon-holstering animation.
DontInterpolateVelocity
Unknown, but maybe it has something to do with {x,y,z} velocities and the fact that directional jumps, for example, take information about their direction vector from the {x,z} velocity part of the TRAM (the vertical Y component is in the ONCC).
ThrowSource
Unknown, but throws use it.
ThrowTarget
Animation can hurt anybody with its attack part, including teammates. The player can even hurt himself with the TRAM's damage part (whereas a player cannot hurt himself with his own animation's attack part). It also allows two attack parts to be executed instead of only one (maybe a bug? more than two will result in a crash).
If you set the first attack part to be able to deal damage from the 1st to the 100th frame of the TRAM, and the second attack part to deal damage within that range (e.g. from the 25th to the 41st frame), then the first attack part will deal damage from the 1st to the 100th frame (as usual), but even if it hits, that second attack part can hurt the enemy as well during frames 25–41. Note that the second attack part must be executed within the first attack part's active "window", otherwise it won't work.
RealWorld
It appears this flag was used to create a TRAM and an OBAN from one animation source. The OBAN is supposed to store pelvis rotations and positions, allowing a character to move over obstacles/gaps. The vast majority of them are used in cutscenes.
DoAim
Applies the aiming animation overlay (PIS/RIF) if the player has a weapon.
DontAim
An aiming overlay will not be applied.
CanPickup
Player can pick up an item during this animation if he intersects with one during his movement.
Aim360
Unknown.
DisableShield
If the player has an active supershield (chr_super "name" 1), this forces him to disable it (chr_super "name" 0)
NoAIPickup
AIs are not permitted to pick up items with this animation.
<Atomic> parent tag Makes animation particle atomic?
<Start> int16
<End> int16
<Invulnerable> parent tag Character will not take melee damage during a time frame defined by the Start and End frames.
<Start> int16 First frame of character being invulnerable.
<End> int16 Last frame of character being invulnerable.
<Overlay> parent tag
<UsedBones> flag Simply contains "<UsedBones />" if no bones are involved, otherwise:
Pelvis
LeftThigh
LeftCalf
LeftFoot
RightThigh
RightCalf
RightFoot
Mid
Chest
Neck
Head
LeftShoulder
LeftArm
LeftWrist
LeftFist
RightShoulder
RightArm
RightFist
<ReplacedBones> flag "<ReplacedBones />" if unused, otherwise:
Pelvis
LeftThigh
LeftCalf
LeftFoot
RightThigh
RightCalf
RightFoot
Mid
Chest
Neck
Head
LeftShoulder
LeftArm
LeftWrist
LeftFist
RightShoulder
RightArm
RightFist
<DirectAnimations> parent tag
<Link> link First slot. "<Link />" if unused.
<Link> link Second slot. "<Link />" if unused.
<Pause> parent tag
<Hard> int16
<Soft> int16 Player cannot enter new inputs during this pause unless this animation is followed by a combo animation defined by <DirectAnimations><Link>.
Examples:
COMcomb_p, (no pause) COMcomb_p_p
COMcomb_p, (pause) COMcomb_k

Combos ignore <Interpolation><End>.

<Interpolation> parent tag
<End> int16
  • interpolates first X frames of next animation
  • if the first follow-up animation is too short, it can continue to play even further (not observed with vanilla anims)

While interpolations with rotations are less noticeable, interpolations of different positions can cause an additional drift.

This was especially observed for transitions of idle to movements and vice versa — basically any combination of animations with different accelerations at the start and end. By default, animations without a specified Shortcut interpolation get about 8 frames of interpolation. For moves starting or ending in idle, it's better not to use interpolation. Just give the start and end frames the same positions and rotation values as the idle. Interpolations should always be considered a last resort.

"End" interpolation covering multiple follow-up animations.
<Max> int16 unused
<FinalRotation> float Ending rotation in degrees. (During an animation, the camera is detached rotation-wise. If this value matches the body's final rotation, it will prevent a "glitchy" re-attaching.)
<Direction>
None
Forward
Backward
Left
Right
<Vocalization> int ID of one of the SoundConstants in ONCC
<ActionFrame> int Frame number for any special events associated with this animation: weapon theft via disarm, weapon holstering, Mukade teleporting, items getting handed over to player, etc.
<Impact> link "<Impact />" if unused.
<Particles> parent tag serves as group element
<Particle> parent tag holds individual particle data
<Start> int frame number for particle to start
<End> int frame number for particle to end (if the number exceeds frame count of animation, the particle will simply die at the end of the animation)
<Bone> flag
Pelvis
LeftThigh
LeftCalf
LeftFoot
RightThigh
RightCalf
RightFoot
Mid
Chest
Neck
Head
LeftShoulder
LeftArm
LeftWrist
LeftFist
RightShoulder
RightArm
RightFist
<Name> link particle name in ONCC-ONCP
<MotionBlur> parent tag
<MotionBlur> parent tag sequence element
<Bones> flag
Pelvis
LeftThigh
LeftCalf
LeftFoot
RightThigh
RightCalf
RightFoot
Mid
Chest
Neck
Head
LeftShoulder
LeftArm
LeftWrist
LeftFist
RightShoulder
RightArm
RightFist
<Start> int16
<End> int16
<Lifetime> int8
<Alpha> int8
<Interval> int8
<Footsteps> parent tag
<Footstep> parent tag
<Frame> int16
<Type> flag
Left
Right
<Sounds> parent tag "<Sounds />" if unused.
<Sound> parent tag
<Name> char[32] OSBDfile.imp.oni (don't use resource type's prefix or suffix)
<Start> int16 The frame when the sound starts to play.
<Heights> parent tag
<Height> float Absolute position.
<Velocities> parent tag
<Velocity> 2 x float Relative positions (delta values); the numbers represent the change in position from one frame to another.
<Rotations> parent tag
<Bone> parent tag There are 19 bone tags, one for each body part.
<EKey> int8 + 3 * float For normal animations. The first value is the number of frames for which the rotation is maintained; the sum of all of these first EKey components always equals the total number of frames for the animation.
<QKey> int8 + 4 * float For overlay animations used by TRAS aiming screens.

OniSplit v0.9.54.0 produces <QKey>s (quaternions) instead of <EKey>s (Euler rotations) for normal animations.

<PositionOffset> parent tag <PositionOffset> and <Positions> belong together. In the binaries, they are written in place. Seems unused; changing them has no effect in-game.
<X> int16
<Z> int16
<Positions> parent tag
<Position> float seems to be unused (and when checking this with "chr_debug_sphere = 1", the spheres remain unchanged)
<Height> float vertical extent
<YOffset> float Y offset of the vertical extent from character location
<ThrowSource> parent tag "<ThrowSource />" if unused.
<TargetAdjustment> parent tag Used to position targets during throws, relative to the position of the character executing the throw.
<Position> 3 * float Contains XYZ values, which position the target character:
  • X - Side axis. Negative values move the target to the right and positive values move the target to the left.
  • Y - Height axis. Negative values move the target downwards, but cannot make the target go below the floor. Positive values make the target go upwards — if the value is too big, the target will teleport upward and then immediately start falling, interrupting the target animation.
  • Z - Forward axis. Negative values move the target backwards and positive values move the target forward.
<Angle> float
<Distance> float Activation distance. The throw can be triggered if it is within this range. However the value must be greater than the equivalent TRAM in the parent TRAC.
<TargetType> flag The flags are part of the animation type list.

(static throws)

Thrown1 = ###COMthrow_fw_p_tgt
Thrown2 = ###COMthrow_fw_k_tgt
Thrown3 = ###COMthrow_bk_p_tgt
Thrown4 = ###COMthrow_bk_k_tgt

(running throws)

Thrown5 = ###COMrun_throw_fw_p_tgt
Thrown6 = ###COMrun_throw_fw_p_tgt
Thrown7 = ###COMrun_throw_bk_k_tgt
Thrown8 = ###COMrun_throw_bk_k_tgt (not tested)

(tackle throw = catching)

Thrown9 = ###COMrun_tkl_fw_p_tgt (not tested)
Thrown10 = ###COMrun_tkl_bk_p_tgt

(pistol disarms)

Thrown11 = ###PISthrow_fw_p_tgt
Thrown12 = ###PISthrow_fw_k_tgt
Thrown13 = ###PISthrow_bk_p_tgt

(rifle disarm)

Thrown14 = ###PISthrow_bk_k_tgt (not tested)
Thrown15 = ###RIFthrow_fw_p_tgt
Thrown16 = ###RIFthrow_bk_p_tgt
Thrown17 = ###RIF? = (not tested)

About the naming:

"fw" = face-to-face throw
"bk" = thrower is facing victim's back
"throw" inside TRAM names is sometimes shortened to "thr"
"p"/"k" = triggered by punch or kick button ("p" is sometimes omitted)
<SelfDamage> parent tag "<SelfDamage />" if unused.
<Damage> parent tag sequence element
<Points> int16 Damage taken by character.
<Frame> int16 Frame of the animation when damage is dealt.
<Attacks> parent tag
<Attack> parent tag Only 2 attack parts per file are allowed. Normally the target gets only one hit. But if the attack frame ranges of both attack parts are overlapping, then the target can be hit by both of them.
<Start> int16 First frame where damage can be inflicted on an opponent.
<End> int16 Last frame where damage can be inflicted on an opponent.
<Bones> flag The bones which can inflict damage.
<Flags> flag
Unblockable
Low - Target of attack needs to crouch in order to block this attack.
High - Blocker needs to stand; if both Low and High are set, blocker can block from both standing and crouching positions.
HalfDamage - Blocker receives half of the normal damage.
<Knockback> float Target gets knocked back by this amount.
<HitPoints> int16 Damage points inflicted by attack.
<HitType> flag Animation type for opponent's animation when the attack isn't blocked. The flags are part of the animation type list.
<HitLength> int16 Number of frames that the target should remain in his hit animation state when he gets hit.
<StunLength> int16 Number of frames that the target should remain in his blocking animation state when he blocks the attack.
<StaggerLength> int16 Number of frames that the target should perform his stagger animation after a successful block.
<Extents> parent tag Explained below. Automatically calculated by OniSplit if there's a DAE file referenced in the XML.
<Extent> parent tag One tag per frame.
<Angle> float In degrees.
<Length> float
<MinY> float
<MaxY> float
<AttackRing> parent tag Always contains 36 <Length> tags, explained below. Automatically calculated by OniSplit if there's a DAE file referenced in the XML. (AttackRing was formerly known as "horizontal extents" in older versions of OniSplit.)
<Length> float Horizontal extents, explained below. They create a "danger zone" around the attacker which the AI uses to try to dodge an attack.

Export

TRAM files can be extracted A) as pure XML files or B) as a pair of XML and DAE files. For editing the actual animation, you will want to use method B. While exporting an ONCC, you might see errors such as:

Cannot find instance 'TRAMKONCOMthrow_rev'
Cannot find instance 'TRAMKONCOMthrow_rev'
Cannot find instance 'TRAMKONRIFturn_right'
Cannot find instance 'TRAMKONOKOlev18_ZomStand'
Cannot find instance 'TRAMKONOKOcorner_hide'
Cannot find instance 'TRAMKONPIScorner_hide'

Ignore them, as those files doesn't exist. (Someday we should remove them from the TRACs.)

Via command line

To export a single TRAM:

onisplit -extract:xml output_path -anim-body:path_to\TRBS_or_ONCCname.oni path_to\TRAMname.oni

To export merged TRAMs:

onisplit -extract:xml output_path -anim-merge -anim-body:path_to\TRBS_or_ONCCname.oni path_to\TRAMname1.oni  path_to\TRAMnameN.oni

Via Vago

Combined extraction of DAE and XML.

When you start Vago, the "General" tab should be open by default. If not, click on it. Then follow these five easy steps.

Step 1: Select "ONI" as input format ("From").

Step 2: Select "XML" as output format ("To").

Step 3: Check "Another TRAM" to choose a character animation file.

Step 4: Click "Add" button to choose an ONCC file.

Step 5: Click "Convert".

Via Simple OniSplit GUI

There was a long-standing problem with combined ONCC/TRAM files where the textures would be missing.

Simple OniSplit GUI post-edits the DAE to fix missing textures. The character-related .oni files must be all in one folder. Usually the level0_Final folder does the trick.

Step 1: Drag and drop the TRAM and ONCC into the big field. (One by one or simultaneously; the order doesn't matter.)

Step 2: Hit "Convert".

Editing 3D data

XSI

You can load the DAE file into a compatible editor. So far, the community's favorite is (formerly "XSI") Mod Tool.

  • For the correct Mod Tool settings, see HERE.

Here are some hints for creating animations when there is no rigging available:

  • Use the ONCC model in your 3D editor that will actually make use of the animations. This makes sure that the pelvis height will match and that the character's feet will not float in the air or go through the ground.
  • The first frame and last frames should match the probable previous and follow-up animations. This will reduce the necessity for long interpolations.
  • When setting keyframes, each body part should have moved. This rule of thumb will give a more natural-looking animation.
  • The first body part to be animated is always the pelvis.
  • Watch out for pelvis rotations so that the XYZ rotations don't overlap too much, otherwise you will get into a gimbal lock.

Also see our OCF thread.

Blender

Theoretically possible. Very difficult in practice and we don't have a tutorial on this one.

Import

onisplit -create output_path path_to\TRAMname.xml

Additional details

Existing TRAMS

TRAMS used in Oni follow a naming pattern. A list of all combat TRAMS in-game and their naming can be found here.

Speeding up existing animations

s10k has created an XmlTools script that allows the speed-up of any existing TRAM by removing frames. More information and download link here.

Attacks

Extents and XML

Ever wondered how the AI can recognize incoming attacks and block or dodge them? Extents (found by geyser and fully uncovered by Neo) are the key. Imagine the character looked at from above, and visualize a circle with this character being at the center of the circle. Now divide this circle into 10° segments, and those are the 36 units of horizontal extents (that is, the lateral reach of the attack). The 0° point is directly in front of the character and 180° is behind the character. The segments run clockwise around the character. So the first Extent tag is the horizontal reach on the 0° line, the second tag is for the line 10° clockwise, and so on. Note that a frontal attack like a simple kick could hit a target not only if he's standing at 0° (directly in front), but also at 10° or 20° to the right, and also at 340° and 350° (a bit to the left). When setting these manually, you should guess the inner and outer ranges of the reach of the attacker's bones that have damage attached to them. Test these values with an AI that blocks often. If you did it right, your attack will often be blocked, but if the extent length is too high, the AIs will react when too far from you, which does not look good.

There are two types of extents:

  • <Extents> stores this info:
<Angle> at which this extent radiates from the character.
<Length> of this extent.
<MinY> minimum height of this extent.
<MaxY> maximum height of this extent.
Length, MinY and MaxY serve to create an invisible area in space which is "dangerous to be in". If an AI intersects with this area and notices it (refer to the Notice field in MELE), it will attempt to block or dodge according to its modifiers in its MELE profile.
The number of <Extent>s is equal to the number of attack frames: <End> minus <Start> plus one (because the start frame counts too). For example, for TRAMKONCOMkick_low1: <End>30</End> minus <Start>22</Start> plus 1 = 9 <Extent>s.
These extents are pretty impossible to guess, so leave them alone until Neo comes up with extent computation (probably from attack bones and bone rotations). However, always add at least one set of component tags, because those Length, MinY and MaxY components will be taken as the longest extent, the lowest Y value, and the highest Y value. Without those, a character won't react to this attack.
  • <HorizontalExtents> stores this info:
36 fields (exactly 36, otherwise it won't compile back into a .oni file), which correspond to areas in 10° intervals around the character as described above.

Adding extents to an existing animation

Let's say that you want to convert a non-attack animation to a damage-dealing animation. Non-attack TRAMs do not have extents information used to notify the AIs about incoming attacks, so how do you generate this information from the animation?

1. Export the animation to XML with a body attached. If you extract using just "-extract:xml dest_folder TRAMsomething.oni", you'll get the 3D animation data inside the XML (namely, the tags Heights, Velocities, Rotations, PositionOffset, and Positions; for an attack animation, you'll also get Attacks and AttackRing, and inside Attacks' elements, each Attack element will have Extents at the end of it).
However, if you extract this same animation using "-extract:xml dest_folder TRAMsomething.oni -anim-body ONCCtramuser.oni", the animation data will be placed in a DAE file along with the character model geometry. Be sure to pick a body with a size that's representative of the character classes that will actually use this TRAM, because the extents will be calculated from it. The XML file will be very short without the 3D data in it — this is how we want the non-attack TRAM to look. We do not know the extents information that should go in Extents or AttackRing, so we just want to add the part that distinguishes a DAE-extracted attack TRAM XML from a DAE-extracted non-attack TRAM XML. That part is the Attacks section, without the Extents under each Attack.
2. First, consider whether the TRAM should have something added to its Flags section, like Attack or ThrowTarget.
3. Now add to the XML of the non-attack TRAM data in the following format (after the <SelfDamage /> section, typically):
       <Attacks>
           <Attack>
               <Start>1</Start>
               <End>10</End>
               <Bones>RightWrist RightFist</Bones>
               <Flags />
               <Knockback>4</Knockback>
               <HitPoints>10</HitPoints>
               <HitType>KnockdownHead</HitType>
               <HitLength>5</HitLength>
               <StunLength>8</StunLength>
               <StaggerLength>0</StaggerLength>
           </Attack>
       </Attacks>
Do not add an AttackRing section after Attacks.
4. Import this with "-create dest_folder TRAMsomething.xml". The Extents sections and the AttackRing will be calculated by OniSplit from the attached DAE.
5. If you need this information for a patch mod, run "-extract:xml" on the TRAMsomething.oni you've created without using "-anim-body". Now you can copy the Extents and AttackRing data to your XML patch. For an example of how the patch should look, see the Domino Knockdowns mod.

Combos

The type and order of player input for triggering a given animation type (such as PPK) is hardcoded, and new animation types cannot be created. To assign an animation type to a specific combo attack, you set a corresponding value in <Lookup><Type>.

Setting a value in <Link> of <DirectAnimations> will do two things:

  1. It will increase the time for player input, meaning the next animation can be executed more easily. (In vanilla Oni, the Crescent Moon Kick has no link in KONCOMcomb_k_k_kfw and therefore is difficult to use.)
  2. It disables <Interpolation><End> for the next combo anim.
  3. It enables <Pause><Soft> and <Pause><Hard>.

Just Frame combos

For short JF combos or JF anims. Created by Delano762, inspired by the game series Tekken. "JF" means that you have to press certain keys (W+K or W+P) at the exact same time, which is more difficult than it might sound. Delano's mod 54000 New Combat Moves for Konoko has a collection of animations which utilize existing animation types to create new combos.

Example 1:

  • new forward kick = TRAMKONCOMkick_fw_JF <FromState>Standing
    • key strokes: w + k
  • old forward kick = TRAMKONCOMkick_fw <FromState>RunStart
    • key strokes: w, k

Example 2:

  • new forward punch = TRAMKONCOMpunch_fw_JF <FromState>Standing
    • key strokes: w + p
  • old forward punch = TRAMKONCOMpunch_fw <FromState>RunStart
    • key strokes: w, p

Throws

Throw target animations are registered in the TRAC of the throw initiator (AKA the throw source). Target animations are forced onto the other character, removing the need to have that animation in the target's TRAC. Throw target (TRAM*tgt) animations can only cover up to 256 frames (0-255).

Forward throws

Scenario: You load two characters into Mod Tool and rotate (+/-180°) the throw target character because you need them to stand face to face as you work on an animation. When you are done animating, the target animation would need to be reversed again. This means multiplying the velocities by -1; the rotation also needs correcting. So it looks like you need *(-1) for the x rotation and -/+180° (depending on your initial change) for the Y rotation.

Blender Forward throw adjustment script

This is a Blender script for rotating -/+180° and adding PositionOffset to a forward throw Target animation. This was made by a hero from the Blender Discord named Danta. The add_object_offset_about_cursor_Z() function was written by Delano762.

For each frame in the range you specify, this script rotates the selected object by 180 degrees (or however many you want), and translates it by the offset found in the <TargetAdjustment> <Position> tag of the attacker's throw animation XML. It also has a frame-checking functionality that's buggy; ultimately there is no real reason at the moment to use it, but it may come in handy in the future, so it should be left in this snippet.

Step-by-step guide on using this script:

1. Import a throw animation and its target animation into Blender.
2. Open Scripting tab.
3. Create a new text, and name it however you want with .py extension, e.g. TRAMAdjuster.py
4. Paste the script.
5. On the following lines…
scene.frame_set(start)
		for i in range(start, end):

…set start and end to the start frame of the animation (always 0 for vanilla anims, but if you're animating and starting from 1, you'll want it set to 1) and the end to the (end + 1) frame of your animation; e.g. if you have a 99 frame animation, set end to 100.

6. On the following line…
add_object_offset_about_cursor_Z(obj,x,-z,-y) #translate object

…paste the values from the <Position> tag according to the order of the function arguments. The minus sign means the value should be inverted in the function. As an example, assuming you have the following <Position> tag…

<Position>1 2 -3</Position>

…the function call should be as follows…

add_object_offset_about_cursor_Z(obj,1,3,-2) #translate object
7. Select the pelvis of the target animation.
8. Press Shift+C to ensure your 3D cursor is in the center of the animation.
9. Set the Transform Pivot Point to "3D Cursor".
10. On the Scripting tab, run the script.
11. The target should be now adjusted as expected.
12. If you want to revert the target back to an exportable position and rotation, simply invert the Z argument in the add_object_offset_about_cursor_Z function and run the script again.
import bpy
from math import pi, radians
from mathutils import Matrix, Quaternion, Vector

obj = bpy.context.active_object
scene = bpy.context.scene


def add_object_offset_about_cursor_Z(object,x,y,z): #Translation function
	cursor_loc = bpy.context.scene.cursor.location #3D Cursor location
	
	mat = (Matrix.Translation(cursor_loc) @
		Matrix.Translation((x,y,z))) #PositionOffset translation applied
	object.matrix_world = mat @ object.matrix_world #Change applied to object

def rotate_object_about_cursor_Z(object, degrees): #Rotation function
	cursor_loc = bpy.context.scene.cursor.location #3D Cursor location
	
	mat = (Matrix.Translation(cursor_loc) @
	   Matrix.Rotation(radians(degrees), 4, 'Z') @
	   Matrix.Translation(-cursor_loc)) #Rotation applied
	   
	object.matrix_world = mat @ object.matrix_world #Change applied to object

#BUGGED KEYFRAME-CHECKING FUNCTION, NOT USED BUT MIGHT BE USEFUL IN THE FEATURE
"""def is_keyframe(ob, frame, data_path, array_index=-1):
	if ob is not None and ob.animation_data is not None and ob.animation_data.action is not None:
		for fcu in ob.animation_data.action.fcurves:
			if fcu.data_path == data_path:
				if array_index == -1 or fcu.array_index == array_index:
					return frame in (p.co.x for p in fcu.keyframe_points)
	return False

bpy.types.Object.is_keyframe = is_keyframe   """

#not really sure why those three lines are here, I think they can be left out
#obj.keyframe_insert(data_path="location", frame = 0)
#obj.matrix_world.translation += Vector((-100, 0, 0)) 
#obj.keyframe_insert(data_path="location", frame = 100)

scene.frame_set(start) #set start frame
for i in range(start, end): #loop for every frame
	#if obj.is_keyframe(i, obj.path_from_id("location")): Bugged keyframe-check
		scene.frame_set(i)
		rotate_object_about_cursor_Z(obj, 180) #rotate object
		add_object_offset_about_cursor_Z(obj,x,-z,y) #translate object
		obj.keyframe_insert(data_path="rotation_euler", frame=i) #keyframe rotation
		obj.keyframe_insert(data_path="location", frame=i) #keyframe location

Excel macro

Needs update.

Animation macro v4.png
  • For all TRAMs except overlays. Demo vid here. Usage:
  • Put your files into the "input_and_output" folder.
  • Disable macro security if you don't want to have to click on the "Enable Content" button every time.
  • Close other worksheets before you run the macro.
  • If you are not afraid of VBA code, you can enter the dev environment by hitting Alt+F11. If you want to extend the attack library with more screenshots and settings, search for "LibraryThrows", " LibraryAttack", "Picture", and "CBAttackHelp.AddItem".

Run animations

Here's a breakdown of the Striker's run animations, meant as an illustration for what would be needed to make new run TRAMs.

Run cancel:

  • STRIKEidle1 / another idle animation
  • STRIKErun1stepa
  • STRIKErun1stepb
  • STRIKEidle1 / another idle animation

Run – a minimal cycle:

  • STRIKEidle1 / another idle animation
  • STRIKErun1stepa
  • STRIKErunstart
  • STRIKErun_rt
  • STRIKErun_lt (optional)
  • STRIKErunstop
  • STRIKEidle1 / another idle animation

Follow the images below from right to left.

List of unused animations

Here are all the known unused animations. These could be recycled in a new mod.

From the original game

  • KONOKOconsole_punch: What the name says (the engine can use that animation depending on the console's configuration, see CONS) .
  • KONOKOlev3_intro: Looks like she's placing something (bomb?) and then running away.
  • KONOKOlev4_undress: From an aborted clothes-changing cutscene.
  • KONOKOlev16_bomb: Planting a bomb.
  • KONCOMsuper_kick: Now used in OTA as a spawn event, and by the fan-made character Shinatama Bot.
  • KONCOMsuper_punch: KONCOMpunch_heavy but without the shouted attack name, has HalfDamage flag, and does 10 less damage in its first attack part.
  • COMPISidle_special1: Comguy checking environment and his gun; meant for a feature that would visually depict an elevation in the AI's level of alertness after, say, hearing a noise.
  • STRPISidle_special1: Striker checking his his gun and communicating with an ally (another unused alertness-elevation animation).
  • THUGlev1_direct: Thug probably directing a truck driver.

From modders

Char A and Char B performing stun animations.
  • http://mods.oni2.net/node/376
    • StrikerKneeStepKickThrow.zip
    • REDCOMjump_fw_crouch--double_flip--dae.zip
    • KONprone_getup--dae.zip
    • KONRIF_k_bk_throw.zip
    • female_stun--dae.zip

Special effects

If the scene is overloaded by too many particles (including motion blur), these effects will cease being rendered. So don't overuse effects.

Color trails

Open the XML-accompanied TRAM, search for the "Particles" tag, and insert your markup.

First example: TRAMSTRCOMcomb_p_p.xml

Colorful contrail added.png
       <Particles>
           <Particle>
               <StartFrame>0</StartFrame>
               <EndFrame>12</EndFrame>
               <Bone>LeftFist</Bone>
               <Name>contrail</Name>
           </Particle>
       </Particles>

"contrail" is looked up by the character class (ONCC) that emits the actual particle; here it is "h2h_strtrail_e01".

This second example is about creating two different contrails in a TRAM at the same time. The animation is "TRAMSTRCOMpunch_heavy.xml".

Different contrails in attack.png
       <Particles>
           <Particle>
               <Start>0</Start>
               <End>54</End>
               <Bone>RightWrist</Bone>
               <Name>contrail</Name>
           </Particle>
           <Particle>
               <Start>0</Start>
               <End>54</End>
               <Bone>LeftWrist</Bone>
               <Name>contrail_2</Name>
           </Particle>
       </Particles>

Note that you need to register the second contrail in the ONCC as well. Using your own contrail particle is also possible; just insert its name between the <Type> tags.

           <ONCPParticle>
               <Name>contrail</Name>
               <Type>h2h_strtrail_e01</Type>
               <BodyPart>-1</BodyPart>
           </ONCPParticle>
           <ONCPParticle>
               <Name>contrail_2</Name>
               <Type>h2h_murtrail_e01</Type>
               <BodyPart>-1</BodyPart>
           </ONCPParticle>

Motion blur

XML TRAM willow kick with motion blur.jpg

Impact effect

XML TRAM KONCOMkick fw with ninflash1.jpg

See also XML:ONCC.