On this page 22 sections
- Words used on this page
- Functions
blse.sequencesblse.lookup_sequenceblse.play_animationblse.stop_animationblse.animationblse.set_animation_ruleandblse.animation_rulesblse.activity_idandblse.activity_name- Playing on an NPC
- Rules: another animation for an activity
- New animations for models
blse.add_model_animationsblse.model_animations- How adding and replacing work
- Without code: blse/animations.txt
- Console command
anim_models - Events
blse.anim_startedblse.anim_endedblse.anim_chosen- Bones the game moves by itself
(b0.5.49) Playing an animation on any NPC, reading what a character plays now, events when an animation starts and ends, rules that change which animation the game picks for an activity, and new animations added to models without editing them.
Come here when your mod makes characters move in a new way: a dancer who dances on the spot, a guard who stands with crossed arms, every prostitute flirting instead of standing idle, a scene that waits until an NPC finished a gesture, or a pack of new dance animations added to every male NPC model.
A first example: look at an NPC, type dance in the console, and the NPC stops walking and dances until you type dance again.
import blse
def dance(name, args):
target = blse.look_target() # (classname, name, handle) or None
if not target:
return
npc = target[2]
if blse.animation(npc) and blse.animation(npc)['held']:
blse.stop_animation(npc) # stop: the NPC's own animation comes back
elif blse.play_animation(npc, 'pole_strole_01', 'loop still'):
blse.console_print('Dancing.\n')
blse.add_command('dance', dance, 'dance: the NPC you look at dances (again: stops)')Read this first
- Only while a level runs (after
blse.level_init, beforeblse.level_shutdown), and only from Python's normal code (the main thread, see Words used on this page). At the main menu and while loading, the functions return0orNone. Rules (set_animation_rule) and the activity functions also work outside a level. - Animations are not saved. A mod's
play_animationends with the level, also when a save is loaded or the player changes level. Play it again from ablse.level_inithandler if it should continue. - Sequence names depend on the model. A sequence that one model has may be missing on another; then
play_animationreturns0. Look withblse.sequences(entity)first. - A dead NPC, or one in a conversation or a scripted scene, refuses (
play_animationreturns0): the game's own scene goes first. - Nothing is hooked until a mod first uses a function or listens to an event. Some events are very frequent: listen only while you need them.
- On a game version BLSE does not recognize, these functions are unavailable and return
0/None.
Words used on this page#
- Entity, index, handle: see the world page.
entityis a server entity's index (1 = the player) or its handle (look_target()[2], or fromfind_entities). - Model: the 3D object the game draws for an entity, a
.mdlfile. A model holds the skeleton, the surfaces and the animations. - Sequence: one animation stored in a model (
'lap_dance_01','Stance_Anger_Idle_1'), with a name and a number. Numbers are counted per entity across the model and the models it includes, starting at 0. - Activity: what the AI asks for (
ACT_IDLE,ACT_WALK,ACT_RUN, VTMB's own such asACT_DISPOSITIONorACT_LAP_DANCE), not a particular animation. Each activity has a name and a number ('ACT_WALK'is 9). Sequences in the model are marked with an activity; when the AI asks for one, the game picks one of the sequences marked with it. - Cycle: how far a sequence has played, from
0.0(start) to1.0(end). - Rate: playback speed.
1.0is normal,0.5half speed,2.0double,0frozen. - Loop: a looping sequence (walk, idle) starts again at the end by itself; one that does not loop stops at its end ("finished").
- Think: the moment, many times a second, when the game updates an NPC's AI. At each think the AI also puts its own animation back.
- Schedule: a plan the AI follows (a list of tasks such as "stop moving, then wait").
SCHED_WAIT_FOR_SCRIPTis the game's "stand and wait" schedule. See NPC AI. - Include (a model): a model can take more animations from other
.mdlfiles it names (its include list). Bloodlines' character models take almost all their animations this way from the shared files inmodels/character/shared/. - Main thread, safe point: Python code runs on the game's main thread. Events that happen deep inside the game are delivered to Python a moment later, at the next safe point (between two frames), not at the exact moment.
- Payload: the text an event hands to your handler: several fields separated by NUL characters (character 0), read with
data.split('\0').
Bloodlines' animations are sequences in the models. A character model has almost none of its own: it includes the shared animation models (models/character/shared/female/..., male/...), so a pedestrian has several hundred, numbered across all of them. An activity (ACT_IDLE, ACT_WALK, ACT_RUN, VTMB's own such as ACT_DISPOSITION or ACT_LAP_DANCE) is what the AI asks for; the game then picks one of the sequences marked with it.
entity is an index or a handle (look_target()[2]); 1 is the player. While a level runs. Nothing is hooked until a mod first uses a function or listens to an event.
Functions#
| Function | |
|---|---|
blse.sequences(entity) |
[(index, name, activity, seconds, loops), ...] of its model, e.g. (312, 'lap_dance_01', 'ACT_LAP_DANCE', 9.6, 1); activity is '' if none, seconds the length at normal speed, loops 1 or 0. None without a model |
blse.lookup_sequence(entity, name) |
The sequence's number (case is ignored), or None |
blse.play_animation(entity, sequence[, options[, rate]]) |
Plays a sequence (its name, or its number) from the start. options: words, 'loop' (until stop_animation; otherwise once), 'still' (an NPC first stops walking, see below). rate 0 to 16, 1 normal (default). 1 or 0 |
blse.stop_animation(entity) |
Ends a mod's animation; the NPC's own comes back at its next think. 1, or 0 if none plays |
blse.animation(entity) |
e.g. {'sequence': 312, 'name': 'lap_dance_01', 'activity': 'ACT_LAP_DANCE', 'npc_activity': 'ACT_IDLE', 'ideal_activity': 'ACT_IDLE', 'cycle': 0.42, 'rate': 1.0, 'loops': 1, 'finished': 0, 'held': 1}, or None |
blse.set_animation_rule(who, activity, sequences) |
When the game picks a sequence for activity on an NPC matching who, one of sequences is used instead. 1 or 0 |
blse.animation_rules() |
[(who, activity, sequences), ...] |
blse.activity_id(name) / blse.activity_name(number) |
Activity numbers and names ('ACT_WALK' <-> 9), or None |
animation(entity): sequence, name and activity are what the model plays now; npc_activity and ideal_activity (characters only, else None) are the activity the AI plays and the one it wants; cycle runs from 0 to 1 through the sequence; finished is 1 once a sequence that does not loop reached its end; held is 1 while a mod's play_animation holds the NPC.
blse.sequences#
blse.sequences(entity) # -> [(index, name, activity, seconds, loops), ...] or NoneLists every animation the entity's model can play. Use it to find out which names a character has before you play one, for example in a console command that prints them while you write your mod.
entity: index or handle of an entity with a model (a character, a prop, an item in the world).- Returns a list with one tuple per sequence, in number order:
index(int): the sequence's number, from 0;name(str): its name, asplay_animationtakes it;activity(str): the activity it is marked with ('ACT_IDLE'), or''if none;seconds(float): its length at normal speed (rate 1);loops(int): 1 if it loops by itself, else 0.
- Returns
Noneoutside a level, for an entity that does not exist or has no model. RaisesRuntimeErrorif memory runs out.
# Print every dance a character has.
for index, name, activity, seconds, loops in blse.sequences(npc) or []:
if name.lower().find('dance') >= 0:
blse.log('%d %s %s %.1f s' % (index, name, activity, seconds))Notes: a character has several hundred sequences (at most 4096 are listed). The list includes the sequences of the models it includes and of any animation file a mod added.
blse.lookup_sequence#
blse.lookup_sequence(entity, name) # -> int or NoneFinds one sequence's number by its name. Use it to check that a model has an animation before playing it, or to compare with the sequence number from blse.animation.
entity: index or handle of an entity with a model.name(str): the sequence's name; case is ignored. A text of digits ('312') is taken as a number and returned if the model has that many sequences.- Returns the number (int), or
Noneif the model has no such sequence, the name is empty or longer than 127 characters, the entity has no model, or no level runs.
if blse.lookup_sequence(npc, 'lap_dance_01') is None:
blse.log('this model cannot lap dance')blse.play_animation#
blse.play_animation(entity, sequence[, options[, rate]]) # -> 1 or 0Plays one animation on an entity, from its start. On an NPC, BLSE keeps it playing against the AI (see Playing on an NPC) until it ends, stop_animation ends it, or the game changes the NPC's animation itself.
entity: index or handle of an entity with a model.sequence: the sequence's name (str, case ignored) or its number (int). Anything else raisesTypeError.options(str, optional): words separated by spaces, commas or tabs, case ignored.Noneor''means none.'loop': play again and again untilstop_animation(or until the game changes the animation). Without it the sequence plays once.'once': play once (the default; cancels a'loop'written before it).'still': an NPC first stops what it does (walking, for example) and stands while it plays. Ignored for other entities.- Any other word raises
ValueError.
rate(float, optional): speed,0to16;1.0(default) is normal speed,0freezes the first frame. Outside the range raisesValueError.- Returns
1if it plays (with'still', it may start up to 1.5 seconds later, once the NPC stands),0otherwise: no level runs, the entity does not exist or has no model, the model has no such sequence, the NPC is dead, in a conversation or in a scripted scene, or the game refused.
# A bystander dances on the spot until told to stop.
blse.play_animation(npc, 'pole_strole_01', 'loop still')
# Half-speed, once.
blse.play_animation(npc, 'Stance_Anger_Idle_1', '', 0.5)
# By number, from the list of sequences.
blse.play_animation(npc, 312)Notes: playing again on the same NPC replaces the earlier play (its 'still' wait too). With 'still', if the NPC cannot be made to stand (the game refuses its waiting schedule), the animation plays at once anyway and BLSE writes the reason to the log. The player and other non-NPC entities just get the sequence, without the holding (see below).
blse.stop_animation#
blse.stop_animation(entity) # -> 1 or 0Ends an animation a mod started with play_animation. The NPC's own animation comes back at its next think; an NPC that was made to stand ('still') ends its waiting schedule and goes back to its own plans.
entity: index or handle.- Returns
1if a mod's animation was playing (or a'still'play was still waiting to start),0if none was, or no level runs.
blse.stop_animation(npc)Note: this does not stop the game's own animations; on props and the player there is nothing held to stop, so it returns 0.
blse.animation#
blse.animation(entity) # -> dict or NoneReads what an entity plays right now. Use it to wait until a gesture is over, to check if your mod's animation still holds, or to find out which sequence the game picked.
entity: index or handle of an entity with a model.- Returns a dictionary, or
Noneoutside a level, for a missing entity or one without a model. RaisesRuntimeErrorif memory runs out. The keys:'sequence'(int): the number of the sequence the model plays;'name'(str): its name;'activity'(str orNone): the activity that sequence is marked with,Noneif none;'npc_activity'(str orNone): the activity the AI plays now (characters only;Nonefor other entities);'ideal_activity'(str orNone): the activity the AI wants to play next (characters only);'cycle'(float): how far it has played, 0 to 1;'rate'(float): the speed, 1.0 normal;'loops'(int): 1 if it loops;'finished'(int): 1 once a sequence that does not loop reached its end;'held'(int): 1 while a mod'splay_animationholds the NPC (also while a'still'play waits for the NPC to stand).
a = blse.animation(npc)
if a and a['name'] == 'pole_strole_01' and a['finished']:
blse.log('done')blse.set_animation_rule and blse.animation_rules#
blse.set_animation_rule(who, activity, sequences) # -> 1 or 0
blse.animation_rules() # -> [(who, activity, sequences), ...]A rule says: "when the game picks an animation for this activity on these NPCs, use one of mine instead". Unlike play_animation, the NPC keeps its AI: it walks, idles and fights as before, only with other animations. A mod uses it to give every prostitute a flirting idle, or one guard an aggressive walk. See Rules: another animation for an activity for the details.
who: which NPCs, one of:- an entity (int, index or handle): that NPC only, until the level ends. An entity that does not exist returns
0; '*': every NPC;'model:<text>': NPCs whose model path contains the text, case ignored ('model:prostitute');- any other text: a classname (
'npc_VPedestrian') or a targetname (the name a map gives an entity), case ignored. At most 200 characters.
- an entity (int, index or handle): that NPC only, until the level ends. An entity that does not exist returns
activity: a name ('ACT_WALK', case ignored) or a number (9, or'9'). An unknown activity returns0.sequences: one sequence name, or several separated by commas, spaces, tabs or;(one is chosen at random each time).Noneor''removes the rule for thiswhoand activity.- Returns
1if the rule was set or removed (also when there was none to remove),0otherwise (unknown activity, missing entity, emptywho, game version not recognized). Wrong argument types raiseTypeError.
animation_rules() lists the rules in the order they apply: who as given (an entity shows as '#<handle>'), the activity's name (or its number as text if it has no name), and the sequences joined with commas. Rules of plugins are listed too.
blse.set_animation_rule('model:prostitute', 'ACT_IDLE', 'Stance_Flirt_Idle_1, Stance_Flirt_Idle_2')
blse.set_animation_rule(npc, 'ACT_WALK', 'knife_aggressive_walk') # this NPC stalks
blse.set_animation_rule(npc, 'ACT_WALK', None) # and walks again
for who, activity, sequences in blse.animation_rules():
blse.log('%s %s -> %s' % (who, activity, sequences))Notes: a rule can be set outside a level (at the top of a script, for example). Python's rules are removed when Python starts again with the engine; the scripts then set them again.
blse.activity_id and blse.activity_name#
blse.activity_id(name) # -> int or None
blse.activity_name(number) # -> str or NoneTurn an activity's name into its number and back. Useful to read numbers in the game's data or to check a name is right before making a rule.
name(str): the activity's name, case ignored ('act_walk'works). A text of digits is taken as a number and returned if it is 0 to 8191.number(int): 0 to 8191.- Return the number or the name, or
Noneif the game does not know it (or the game version is not recognized).
blse.activity_id('ACT_WALK') # 9
blse.activity_name(9) # 'ACT_WALK'Playing on an NPC#
An NPC's AI puts its own animation back at every think. BLSE keeps a mod's animation against that until:
- it ends (played once), or
stop_animation; - the game changes the NPC's animation itself: it dies, flinches from a hit, is knocked back, starts a conversation or a scripted scene, or its schedule sets an activity;
- the level ends (loads and level changes included; animations are not saved).
Then the NPC's own animation comes back. Without 'still' the NPC keeps doing what it did: one walking somewhere keeps walking while it plays (its feet slide). With 'still' it stops at once and plays (the game's SCHED_WAIT_FOR_SCRIPT: it stands and waits; damage ends it); afterwards it goes back to its own schedules. A dead NPC, or one in a conversation or a scripted scene, refuses (0).
While the animation is held, BLSE also keeps the rate and the looping the mod asked for (the game resets both with every new sequence).
Other entities (props, items in the world) just get the sequence. The player does too, but the player's movement animation takes over at once (the console's player_sequence has the same limit).
# A bystander dances on the spot until told to stop.
def dance(npc):
return blse.play_animation(npc, 'pole_strole_01', 'loop still')
# Half-speed, once.
blse.play_animation(npc, 'Stance_Anger_Idle_1', '', 0.5)Rules: another animation for an activity#
who is one of:
who |
Matches |
|---|---|
| an entity (number) | that NPC only, until the level ends |
'*' |
every NPC |
'model:<text>' |
NPCs whose model path contains the text ('model:prostitute') |
| any other text | a classname ('npc_VPedestrian') or a targetname, case ignored |
activity is a name ('ACT_WALK') or a number. A rule matches the activity the AI asks for and the one the game turns it into (by the weapon held, e.g. a walk with a pistol). sequences is one name or several separated by commas or spaces (one is chosen at random each time); a model that has none of them keeps the game's choice. None or '' removes the rule. A later rule for the same who and activity replaces it. The first matching rule in the order they were made applies. Rules last until removed (Python's until Python restarts with the engine; one entity's until the level ends).
In detail: when one sequence is picked at random and this model does not have it, the game's own choice stays for that time. Plugins can also change the choice (after the rules); the blse.anim_chosen event tells you the final pick.
blse.set_animation_rule('model:prostitute', 'ACT_IDLE', 'Stance_Flirt_Idle_1, Stance_Flirt_Idle_2')
blse.set_animation_rule(npc, 'ACT_WALK', 'knife_aggressive_walk') # this NPC stalks
blse.set_animation_rule(npc, 'ACT_WALK', None) # and walks againNot covered by rules: animations the game picks another way (gestures in conversations, melee attack lists, the knockback's flying, the player's animations). A rule replacing a movement activity (ACT_WALK, ACT_RUN) with a sequence that does not move makes the NPC slide.
New animations for models#
(b0.5.49) A mod ships an animation-only .mdl (the skeleton and its sequences, no meshes) and BLSE adds it to a model when the engine loads it, without editing the model's .mdl. Several mods can add to the same model side by side.
This is the game's own mechanism: character models already take their animations from included models (models/character/shared/male/npc_allsequences.mdl and the files it includes). BLSE appends the mod's file to the model's include list; the engine then loads it through the search paths (mod folders included), matches the bones by name (a different number of bones or other proportions are fine: the engine retargets) and numbers its sequences after all of the model's own, so the game's sequence numbers (and saves) do not change.
| Function | |
|---|---|
blse.add_model_animations(target, anim_mdl, replace=0) |
Adds anim_mdl to target at its next load. 1, or 0 if not available on this game build. ValueError for paths that are not .mdl files (or the same file twice) |
blse.model_animations([text]) |
[(target, file, 'add' or 'replace', who, [models it was added to]), ...], only those whose paths contain text |
# Every male NPC that uses the game's shared NPC animations gets a mod's dances.
blse.add_model_animations('models/character/shared/male/npc_allsequences.mdl', 'models/mymod/male_dances.mdl')
# One character only.
blse.add_model_animations('models/character/npc/unique/Downtown/Lacroix/Lacroix.mdl', 'models/mymod/lacroix_extra.mdl')blse.add_model_animations#
blse.add_model_animations(target, anim_mdl, replace=0) # -> 1 or 0Registers an animation file to be added to a model (or to every model that includes it) the next time the engine loads that model. Use it at the top of your script so it is in place before the first level loads.
target(str): the model to change, a.mdlpath as the game names it (models/...; case and/or\do not matter;models/is added if missing). A shared model that other models include means every model that includes it directly (see the list below).anim_mdl(str): your animation file, also a.mdlpath.replace(int, optional):0(default) adds the sequences next to the model's own;1replaces the model's sequences of the same names (see "Replacing" below).- Returns
1when registered,0if the feature is not available on this game build. RaisesValueErrorif either path is not a.mdlpath, or iftargetandanim_mdlare the same file. Registering the same pair again only changesreplace.
blse.add_model_animations('models/character/shared/female/npc_allsequences.mdl',
'models/mymod/female_idles.mdl', 1)Note: if the model is already loaded, it gets the file only at its next load, usually the next game start (BLSE logs this).
blse.model_animations#
blse.model_animations([text]) # -> [(target, file, mode, who, models), ...]Lists the registered animation files: from Python, from plugins and from blse/animations.txt files. Use it to check that your registration took effect.
text(str, optional): only registrations whose target or file path contains this text (case ignored). Left out: all.- Returns a list of tuples:
target(str): the model path as BLSE stores it (lower case,/);file(str): the animation file;mode(str):'add'or'replace';who(str): who registered it:'python', the plugin's name, or'mod <folder>'for a mod folder'sanimations.txt;models(list of str): the loaded models it was actually added to so far.
for target, file, mode, who, models in blse.model_animations('mymod'):
blse.log('%s %s %s: %d models' % (mode, file, target, len(models)))How adding and replacing work#
- Targets: paths as the game names them (
models/...mdl; case and/or\do not matter; a path withoutmodels/gets it). A model other models include (any file undermodels/character/shared/, or one BLSE has seen in another model's include list) means every model that includes it directly: 58 male and 35 female NPC models include theirnpc_allsequences.mdl. The shared file itself never gets the include (the numbers inside every tree using it would shift). Any other target gets it itself. - Adding: the new sequences are found by name (
play_animation,lookup_sequence,set_animation_rule, scripted sequences, choreography) and, if they carry an activity, join the game's choice for that activity. Two mods adding the same name to one model: the first in load order is found (logged). - Replacing (
replace=1): every sequence of the animation file replaces the original of the same name, which BLSE renames<name>@orig(still playable by that name) and takes out of the activity choice. For a shared target the originals are hidden in the whole tree it includes (e.g. a male replacement in the male files only), and every model whose tree uses a file with a hidden original gets the replacement too (the player's model, characters that include such a file directly; logged). For an exact model only its own sequences are replaced: to replace an animation that comes from a shared file, target the shared model. Two mods replacing the same name: the later registration wins (logged). - When: register before the model loads: at the top of a script (scripts run at startup), from a plugin's load, or with a data file (below). A model already loaded gets it at its next load, which is usually the next game start (the engine keeps models across maps and saves; BLSE logs it). Python's registrations are made again by the scripts at each Python start.
- The file must be a version 2531 (VTMB)
.mdlwith the bone names of the skeleton it animates (Bip01 ...): bones the target lacks are ignored (the engine printschained model ... has a bone ... that isn't in chaining model ...), target bones the file lacks are not animated by it. At most 24 pose parameters. A missing file is skipped by the engine ("Model ... not found!"). - Saves: sequence numbers are saved. A save made with an animation mod and loaded without it may hold numbers past a model's end: after every load from a save BLSE gives such characters sequence 0 (logged; their AI picks its own animation at once). The game alone does not do this: load a save made while a character played an added animation with BLSE installed.
- Console:
anim_models [text]lists the registrations and every loaded model BLSE changed, with its added files and hidden sequences.
Without code: blse/animations.txt#
A mod folder may hold blse/animations.txt, read at startup in load order (before plugins and scripts): one registration per line, <target> <animation file> [replace]; # or // start a comment; paths with spaces in "quotes". The file may be at most 1 MB; lines that are not two .mdl paths are skipped and written to the log.
# my_mod/blse/animations.txt
models/character/shared/male/npc_allsequences.mdl models/my_mod/male_dances.mdl
models/character/shared/female/npc_allsequences.mdl models/my_mod/female_idles.mdl replaceMaking the animation file needs the model tools modders already use for whole-model animation mods (decompile with Crowbar, compile back to version 2531): keep the skeleton and the new sequences, drop the meshes.
Console command anim_models#
anim_models [text]Typed in the game's console: lists every registration (from Python, plugins and animations.txt files) and every loaded model BLSE changed so far, with the files added to it and the sequences hidden by a replacement. With text, only lines containing it. Use it to see why your animation does not show up (wrong path, model not loaded yet).
Events#
Listen only while needed: the hooks behind them are installed with the first listener, and some are frequent. Python gets them at the next safe point.
| Event | Payload |
|---|---|
blse.anim_started |
handle, cls, name, seq, seqname, activity, previous = data.split('\0'): an entity's sequence (re)started (also the game's own); activity and previous (the sequence before) may be '' |
blse.anim_ended |
handle, cls, name, seq, seqname, activity, how = data.split('\0'): how is 'finished' (it reached its end) or 'interrupted' (another sequence replaced it first). A looping sequence (walk, idle) never finishes: it ends when another one replaces it |
blse.anim_chosen |
handle, cls, name, activity, translated, seqname, changed = data.split('\0'): an NPC's AI picked a sequence for an activity; translated is the activity after the game's weapon translation, changed '1' if a rule or filter changed the game's choice. Very frequent |
Every entity with a model sends anim_started and anim_ended (props too): compare the handle.
All fields are text. handle is the entity's handle as a number in text (use int(handle) to pass it to other functions); cls its classname; name its targetname ('' if it has none); seq the sequence number as text; seqname its name; activity the activity it is marked with ('' if none).
def on_ended(topic, data):
handle, cls, name, seq, seqname, activity, how = data.split('\0')
if seqname == 'pole_strole_01' and how == 'finished':
blse.log('%s finished dancing' % name)
blse.subscribe('blse.anim_ended', on_ended)blse.anim_started#
Fires when any entity with a model starts a sequence (or starts the same one again), whether the game or a mod started it. Use it to react when a character begins a gesture.
Payload, in order: handle, cls, name, seq, seqname, activity, previous (the name of the sequence it played before, '' if none or if the entity had not played a frame yet).
def on_started(topic, data):
handle, cls, name, seq, seqname, activity, previous = data.split('\0')
if int(handle) == watched and activity == 'ACT_LAP_DANCE':
blse.log('the dance begins')
blse.subscribe('blse.anim_started', on_started)blse.anim_ended#
Fires when a sequence ends: either it reached its end (how is 'finished', only for sequences that do not loop) or another sequence replaced it first ('interrupted'). Use it to start the next step of a scene when a gesture is over.
Payload, in order: handle, cls, name, seq, seqname, activity, how. See the example under the Events table.
Note: an animation that finished and is then replaced does not send a second 'interrupted' event.
blse.anim_chosen#
Fires each time an NPC's AI picks a sequence for an activity, after BLSE's rules and plugins' filters. Use it while you write rules, to see which activities an NPC asks for and what it gets. It fires very often (many times a second per NPC): unsubscribe when you are done.
Payload, in order: handle, cls, name, activity (what the AI asked for), translated (the activity after the game turned it into a weapon-specific one, e.g. a walk with a pistol), seqname (the sequence finally used), changed ('1' if a rule or filter changed the game's choice, else '0').
def on_chosen(topic, data):
handle, cls, name, activity, translated, seqname, changed = data.split('\0')
if int(handle) == npc:
blse.log('%s -> %s (%s)' % (activity, seqname, changed))
blse.subscribe('blse.anim_chosen', on_chosen)Bones the game moves by itself#
Hair, coat tails and breasts of many character models swing by themselves: the game's physics chains, a table in the model (not the .phy). Their console variables (bc_override, bc_maxangle, bc_spring, bc_damp, bc_gravity, bc_ground, bc_fade) can be set with blse.set_cvar; with bc_override 1 the others replace every chain's own values.
blse.set_cvar('bc_override', '1') # the bc_ values below now apply to every chain