This module gives additional infos about various game events. Its three main components are the detection of animations (used mostly for flying and flailing), damage and object activation.
In FFX 3.0-3.1, the module could be enabled or disabled, as it was still very experimental. This is no longer the case as the MLOG Reader is now much improved and is required by various functions in FFX and M25 AI.
The mlogreader.py module :
The Reader could be extended to support other MLOG modules. (see list at the end of this document). However, one must be cautious before doing so, as it could severely impact game performances, since some modules are very verbose and/or require much processing to interpret the data; compound that with the need to read ff.log ten times per second…
Here is some documentation for some of the higher-level functions in the mlogreader module. These may be handy for mission or attribute scripting as well as AI.
Note that, from an animation standpoint, there is no difference in a character taking off and landing from a flight power, levitation, or jumping up/down. So these functions treat them as one and when the description mentions flying, jumping and levitation are implied as well. (The codefor difeenciating jumping from flight/levitation is available in MLOG Reader, but it is not activated by default, as it requires the Movement MLOG module,which outputs a lot of info to ff.log, thus impairing performances. See mlogreader.py itself for the related functions.)
Check if character char is flying, levitating, or in the air from jumping up or down and returns 1 if true and 0 if false.IMPORTANT: Jumping up or down characters (including using Superleaper, but not using Jump Travel, Low Jumper or Clumsy Jumper) will also register as flying, since all these movements use the hover animation.
Check if character char is flailing (as happens at the start of a knockback sequence or when a flying character is stunned) and returns 1 if true and 0 if false.
Check if character char is landing from either flying or flailing and returns 1 if true and 0 if false.
Check if character char is getting up (as happens at the end of a knockback sequence) and returns 1 if true and 0 if false.
Checks if a character's ai_idle attribute has been set and returns the value.
Checks if a character's ai_knockback attribute has been set and returns the value.
Top-level functions: These just call the lower-level regAnimation(), but they are specific and probably a bit easier to use. The event structure sent to the callback functions from each of these will have the character registered for the event sink passed as event.object and the event.user, event.float, and event.string fields given as the optional parameters in the registration call. An additional parameter event.animation is passed containing the name of the animation that triggered the callback by starting or ending the registered animation state.
Setting the persistent parameter to 1 will retain the sink through multiple triggers until the mission ends or it is cancelled by either cancelAnimationCallbackSink() or cancelAnimationCallbackSinks(). By default, these sinks are not persistent. (The event structure event.data will be passed to the callback function with the value given to the persistent parameter.)
Detect when a character first takes flight. (This detects jumping as flight.)
Detect when a character's flight ends, either by landing or because he enters a flail state.
Detect when a character first starts flailing.
Detect when a character stops flailing, defined by no longer being in a flail animation. (Note that flailing characters normally cannot initiate new actions until after they have finished their get up animations.)
Detect when a character starts to land, either by crashing into the ground from a flail state, by ending flight or ending a jump. (Note that this will detect characters who use the land animations in attributes such as ACROBATIC.)
Detect when a character finishes landing, defined by no longer being in a land animation after having been in one. (Note that this will detect characters who use the land animations in attributes such as ACROBATIC.)
Detect when a character starts to get up, which they do after crashing into the ground after a flail state.
Detect when a character finishes getting up, defined by no longer being in a get_up_* animation. Note that this is useful when creating a more natural-looking point for characters to resume activity after they have been flailing (e.g. knocked back). That is, when waiting for a flail to end before triggering a move or power use, use this function to start the action when the flail is done and the character has stood up, not when the flail itself ends (which happens when the character is still laying on the ground).
Detect when a character is idle (hovering or standing on the ground).
Detect when a character is no longer idle - attacking, running, etc.
Detect when a character has been knocked back.
Detect when a character has finished getting up after being knocked back.
The Acrobatic FFX attribute interrupts knockback, so it should call ResetKnockBack to trigger the callbacks properly.
Cancel an object's regAnimation() sinks for a particular callback function.
Cancel all regAnimation() sinks for a particular object.
These examples assume that the mlogreader module has been loaded by a call to
from mlogreader import *
(Note that it is actually safer and less memory-intensive to use "import mlogreader" and using the "mlogreader." prefix rather than use the "from mlogreader import *".)
We try a simple check to see if a character is flying.
if MLOG_IsFlying('hero_1'): Mission_StatusText('up, up, and away!!!')
We detect when a character takes off to fly and call a generic callback function. In most cicumstances, we would likely have a more interesting callback function, but suppose we have defined the following function for testing event sinks and callbacks (hint, hint ;) ). It just prints out the contents of the event structure when it is triggered.
def GenericCallback(event): fields = dir(event) for field in fields: print 'GenericCallback: event.%s = %s' % (field,repr(eval('event.%s'%field)))
Then, at the console, we can do a little test to detect when hero_0 takes flight, when he finishes flying and when he finishes his landing animation.
>>> regFlightStart('hero_0','GenericCallback',string='look mom: no hands or feet') >>> regFlightStop('hero_0','GenericCallback',float=33.2,string='touchdown!') >>> regLandStop('hero_0','GenericCallback',float=5,user=6,string='welcome home') # this is what we see when hero_0 leaves the ground GenericCallback: event.animation = 'fly' GenericCallback: event.data = 0 GenericCallback: event.event = 66 GenericCallback: event.float = 0 GenericCallback: event.object = 'hero_0' GenericCallback: event.string = 'look mom: no hands or feet' GenericCallback: event.user = 0 # this is what we see when hero_0 touches down GenericCallback: event.animation = 'land_from_jump' GenericCallback: event.data = 0 GenericCallback: event.event = 67 GenericCallback: event.float = 33.2 GenericCallback: event.object = 'hero_0' GenericCallback: event.string = 'touchdown!' GenericCallback: event.user = 0 # this is what we see when hero_0 finishes landing GenericCallback: event.animation = 'idle' GenericCallback: event.data = 0 GenericCallback: event.event = 73 GenericCallback: event.float = 5 GenericCallback: event.object = 'hero_0' GenericCallback: event.string = 'welcome home' GenericCallback: event.user = 6
Note: This module is a recent addition. As such, it's still not widely used by FFX and M25 AI yet.
Other possible uses, requiring additional coding in the MLOG Reader module:
Detect the spawning of any non-projectile object
Detect the spawning of any projectile object (anything with a 'projectile_standin' template).
Detect the spawning of any object with the given template.
Detect the spawning of any object with the given class value. Matches based on logical AND match of object class to given class.
Detect the spawning of any object with the given class value.
Detect when the given object is removed from the game.
Cancel all non-projectile object spawn sinks that call the given function.
Cancel all projectile spawn sinks that call the given function.
Cancel all template spawn sinks that call the given function.
Cancel all class object spawn sinks that call the given function.
Cancel all character object spawn sinks that call the given function.
Cancel an object destroy sink for the given object and function.
Cancel all regActivationDestroySink() sinks for a given object.
Cancel regActivationDestroySink() sinks for a given function.
Note: Contrary to the much more used character animation detection functions, the performances of the damage detection code hasn't been optimized. As such, functions are subject to change.
Other possible uses, requiring additional coding in the MLOG Reader module:
Calls a user-defined function if a certain type of damage happens in certain circumstances (rather vague, I know). Not done as a pseudo event sink, since there are too many arguments.
A sample function might be:
def OnResistGeneticDamage(event): Object_SetPrimaryState(target, PCSTATE_TOAD, 15)
which, when registered as
regMLOGDamage('OnResistGeneticDamage', object=''hero_3, target='', event_type='OBJSTATE_ALTERED_STRUCTURE', success=0, persistent=1, float=0.0, user=0.0, string='')with Microwave as 'hero_3', would transform into toads targets who successfully resist his Genetic Damage direct attack.
Cancel all regAnimation() sinks, including generic ones (i.e., object='')
Cancel an object's regMLOGDamage() sinks for a particular callback function
Cancel all regMLOGDamage() sinks for a particular object
Cancel a target's regMLOGDamage() sinks for a particular callback function
Cancel all regMLOGDamage() sinks for a particular target
Note: These functions require the 'Movement' module t be enabled manually. It is not active by default, since 'Movement' is very verbose (creates lots of lines in ff.log) and has soo far proved far less useful than expected. It is not recommended that you enable it by default.
As such, the following is only listed for the sake of being complete.
Activate or desactivate the 'Movement' MLOG module used to check jumping, etc.
enable should be 1 to enable or 0 to disable.
Note that using the Movement module adds a lot of overhead to the game. Use it only if really necessary and disable it after use.
Checks if a character's ai_jumping attribute has been set and returns the value.
Detect when a character starts jumping.
Detect when a character's jump ends, either by landing or because he enters a flail state.
Cancel an object's regMLOGMovement() sinks for a particular callback function.
Cancel all regMLOGMovement() sinks for a particular object.
The following FFvsTTR modules may be registered with the built-in MLOG() function.
By default, the activation , animator and Damage modules are registered. Other potentially interesting modules include CEffectHandler, Movement, controller and ranged. Please note that enabling a new module might severely impact performances, especially for longer game sessions with numerous characters, as the ff.log file is erased only when the game (not the mission) starts.
As a not-so-trivial aside, a more general coding hint may be helpful to some scripters. Since not everyone has this module installed for their game, one might want to be able to detect whether it is there at run time. There are lots of ways to do this in Python, but probably the most straightforward is to check the sys.modules dictionary. This is a dictionary structure with all of the currently loaded modules. To determine if a module is loaded, just check if the module name (as a string) is in the dictionary's keys. For example
if 'mlogreader' in sys.modules.keys(): # mlogreader loaded regFlightStart(char,'onFlight') else: # mlogreader not loaded # do something else...