BLSE0.6

Python mods

The world: entities, console variables, camera and sound

On this page 38 sections

This page is about the game world around the player: putting things into it (an NPC, an item on the floor), moving them, giving and taking items, finding what is nearby, reading and changing the game's settings, moving the camera and playing sounds.

Come here when your mod needs to:

  • spawn an NPC or an item, or teleport someone (a quest, a summon, a debug tool);
  • give the player items or take them away (a shop, a reward, a crafting recipe);
  • find the NPCs around the player (an area effect, a radar);
  • read or change a game setting (fps_max, r_drawviewmodel) or read one of the game's files;
  • place the camera for a cut scene, change the field of view, or play a sound.

NPCs' behaviour (who they fight, where they walk) is on its own page, NPC AI; how characters look, in Models and appearance.

A first example: type gift in the console and the player gets a blood pack, and a pedestrian appears next to them.

Python
import blse

def gift(name, args):
    blse.give_item(1, 'item_g_bloodpack')          # 1 is the player
    x, y, z = blse.entity_position(1)
    blse.spawn_entity('npc_VPedestrian', x + 64, y, z, 180)
    blse.play_sound('interface/mm_click_on.wav')

blse.add_command('gift', gift, 'gift: a blood pack and a visitor')

Read this first

  • Most functions here work only while a level runs: after the blse.level_init event and before blse.level_shutdown. At the main menu, during loading, and inside a blse.level_shutdown handler they do nothing and return 0 or None. A mod usually calls them from a console command, a key handler or an event handler during play.
  • Call them from your mod's normal code. BLSE runs your scripts and event handlers on the game's main thread (the thread the game itself runs on). A function called from another thread raises RuntimeError. You only meet this if your script starts threads of its own.
  • Saves: entities you spawn, items you give and keyvalues you set are part of the level, so the game saves them like the map's own. Camera changes are not saved.
  • These functions refuse bad input (a position far outside the world, an invalid class name) and return 0 or None rather than crash the game. Check the return value.

Words used on this page#

  • Entity: any object in a level the game keeps track of: the player, an NPC, a door, a prop, an item lying on the floor or carried in an inventory, a trigger, a sound source.
  • Classname: the kind of an entity, as maps and the game name it: npc_VPedestrian, item_g_bloodpack, prop_physics. One class can have many entities.
  • Targetname (or just name): the name a map or script gives one entity, such as guard_1, so scripts can find it. Many entities have none ('').
  • Index: a small number for an entity's slot in the game's entity list. 0 is the world itself and 1 is always the player. When an entity is removed, its slot can be reused by a new one.
  • Handle: a larger number that names one entity for as long as it exists. Unlike an index, a handle of a removed entity never points at a new entity: functions given it simply fail. Events and find_entities give handles; keep handles, not indexes, when you remember an entity for later. In event payloads the handle is text: int(handle).
  • entity / owner parameters accept either: a number below 8192 is read as an index, a larger one as a handle. So 1 always means the player.
  • Keyvalue: one setting of an entity, written as a key and a value in the map (targetname = guard_1, model = models/...mdl). Maps set them when the level is built; spawn_entity and set_keyvalue set them the same way.
  • Position x, y, z: a point in the level, in the game's units (a unit is roughly an inch). z is up.
  • Angles in degrees: yaw turns left and right around the vertical axis (0 faces along the map's x axis, 90 along its y axis), pitch looks up and down (negative is up), roll tilts the view sideways.
  • Console variable (cvar): a named game setting you can type in the console, such as fps_max 60. Its value is always text.
  • Event: a message BLSE sends when something happens. Your function receives it after blse.subscribe(topic, function); the details come as one string with the parts separated by NUL characters ('\0'), so data.split('\0') gives the parts. See Events.

Spawning, teleporting and inventories#

Function
blse.spawn_entity(classname, x, y, z[, yaw[, keyvalues]]) Creates an entity as the map does: an NPC ('npc_VPedestrian'), an item lying in the world ('item_g_bloodpack'), a prop. keyvalues: the map's keys as a dict ({'model': 'models/character/npc/common/citizen/male/male_citizen_1.mdl', 'targetname': 'guard_1'}; unknown keys are ignored, as in maps). The new entity's handle, or None (the reason is logged)
blse.teleport_entity(entity, x, y, z[, yaw]) Puts an entity (an NPC, the player, a prop) somewhere at once, optionally turned
blse.set_keyvalue(entity, key, value) (b0.5.48) Sets one of the entity's keyvalues as the map does: 'targetname' renames it (scripts find it by its new name), 'dialogname' gives an NPC another conversation (a .dlg file or a mod's conversation). Keys an entity reads only when it spawns (its model, most settings) change nothing afterwards. 1 or 0
blse.give_item(owner, classname) Gives an item to the player, an NPC or a container (the player's goes through the game's GiveItem). One the owner has already: a stack (blood packs, ammunition) grows by one; a second unstackable one is refused (0), as the game allows one of each
blse.remove_item(owner, classname[, count]) Removes items (one of a stack at a time, as the game does); how many were removed
blse.item_count(owner, classname) How many the owner has (stacks counted), None if it has no inventory
blse.equip_item(owner, classname) The character takes the item in its hands
blse.drop_item(owner, classname) Drops one into the world, as the inventory screen does; 0 for items that may not be dropped
blse.move_item(from, to, classname) Moves the item (a whole stack) between inventories: the player, NPCs, containers. The same item goes, with its ammunition. Not the item in the character's hands (switch away first)

owner and entity are indexes or handles (1 is the player). Spawned entities are saved with the game like the map's own. A shop of a mod's own: the price from blse.item_info, the player's money from the game's pc.money / pc.MoneyAdd, then give_item or remove_item. While a level runs.

All nine need a running level and return 0 / None otherwise. Item class names are 1 to 63 characters from A-Z a-z 0-9 _; anything else is refused (0, or None for item_count).

blse.spawn_entity#

Python
blse.spawn_entity(classname, x, y, z[, yaw[, keyvalues]])   # -> handle, or None

Creates a new entity in the level, exactly as the game does for the entities a map lists: it creates the entity, applies the keyvalues, then lets it start up ("spawn").

When to use it: a quest mod makes a contact appear in an alley; a "summon" Discipline creates a ghoul next to the player; a loot mod drops an item on the floor.

  • classname (text): the kind of entity, e.g. 'npc_VPedestrian' (an NPC), 'item_g_bloodpack' (an item lying in the world), 'prop_physics'. 1 to 63 characters from A-Z a-z 0-9 _. 'player' and 'worldspawn' cannot be spawned.
  • x, y, z (numbers): where it appears. Each must be between -65536 and 65536.
  • yaw (number, optional, default 0): the direction it faces, in degrees.
  • keyvalues (dict, optional): the map's keys for it, such as {'model': 'models/character/npc/common/citizen/male/male_citizen_1.mdl', 'targetname': 'guard_1'}. Keys are 1 to 63 characters from A-Z a-z 0-9 _; values are text or numbers (numbers are turned into text), up to 255 characters. Do not put classname or origin here: they are the separate arguments. Keys the class does not know are ignored, as in maps. None is the same as no dict.

Returns the new entity's handle, or None if it was not created. The reason is written to blse.log, for example the game does not know that class, position out of the world, the entity did not spawn, the entity removed itself while spawning, or not now (no level, ...).

Raises TypeError if keyvalues is not a dict, or a key or value cannot be turned into text.

Python
h = blse.spawn_entity('npc_VPedestrian', 100, 200, 0, 90,
                      {'targetname': 'mymod_contact',
                       'model': 'models/character/npc/common/citizen/male/male_citizen_1.mdl'})
if h is None:
    blse.log('the contact did not appear; see the line above')

Notes: the entity is saved with the game like the map's own. A spawned NPC does what its class does on its own; to give it orders, see NPC AI. Spawning inside a wall or the floor is not checked: pick a free spot (for example next to the player).

blse.teleport_entity#

Python
blse.teleport_entity(entity, x, y, z[, yaw])   # -> 1 or 0

Moves an entity to a new position at once, without walking there, and optionally turns it.

When to use it: a quest mod brings an NPC to a meeting place; a "blink" Discipline moves the player a few steps forward; a debug command puts the player at a spot.

  • entity: an index or handle (1 is the player). Not 0 (the world).
  • x, y, z: the new position, each between -65536 and 65536.
  • yaw (optional): the direction to face afterwards, in degrees. Left out or None: the entity keeps its current direction.

Returns 1 if it was moved, 0 if not (no level, unknown entity, the world, a position out of range).

Python
x, y, z = blse.entity_position(1)
blse.teleport_entity(1, x, y, z + 200)    # lift the player 200 units

blse.set_keyvalue#

Python
blse.set_keyvalue(entity, key, value)   # -> 1 or 0

(b0.5.48) Sets one keyvalue of an existing entity, the way a map does.

When to use it: rename an NPC so your other scripts (or the game's FindEntityByName) can find it; give an NPC another conversation with 'dialogname' (a .dlg file or a mod's conversation).

  • entity: an index or handle. Not 0 (the world).
  • key (text): 1 to 63 characters from A-Z a-z 0-9 _. 'targetname' renames the entity; 'dialogname' changes an NPC's conversation.
  • value (text): up to 255 characters.

Returns 1 if the entity accepted the key, 0 if not (no level, unknown entity, a key it does not know, bad text).

Many keys are read only once, when the entity spawns (its model, most settings): setting them later returns 1 or 0 but changes nothing you can see. For those, set them through spawn_entity's keyvalues instead.

Python
blse.set_keyvalue(h, 'targetname', 'mymod_guard')
blse.set_keyvalue(h, 'dialogname', 'mymod_guard.dlg')

blse.give_item#

Python
blse.give_item(owner, classname)   # -> 1 or 0

Puts an item into an inventory: the player's, an NPC's or a container's.

When to use it: a quest reward, a shop sale, a crafting result, arming a spawned NPC.

  • owner: an index or handle of a character (the player, an NPC) or a container. 1 is the player.
  • classname: the item's class, e.g. 'item_g_bloodpack', 'item_w_colt_anaconda'.

What happens: for the player, the game's own GiveNamedItem is used. If the owner already has one of these items, a stackable item (blood packs, ammunition) grows by one; a second unstackable item (most weapons) is refused, because the game allows one of each.

Returns 1 if the item was given, 0 if not (no level, the owner has no inventory, an unknown class, a second unstackable item).

Python
for i in range(3):
    blse.give_item(1, 'item_g_bloodpack')    # three blood packs

blse.remove_item#

Python
blse.remove_item(owner, classname[, count])   # -> how many were removed

Takes items out of an inventory, as the game does: from a stack, one at a time; an item that is not stacked is removed whole.

When to use it: a shop buys an item from the player; a quest takes away a key; a recipe uses up ingredients.

  • owner: an index or handle (the player, an NPC, a container).
  • classname: the item's class.
  • count (optional, default 1): how many to remove, 1 to 100000. Outside that range raises ValueError.

Returns the number actually removed: 0 if the owner had none (or no level), fewer than count if the owner had fewer.

Python
if blse.remove_item(1, 'item_g_bloodpack', 2) == 2:
    blse.give_item(1, 'item_g_bluebloodpack')    # trade two packs for a better one

blse.item_count#

Python
blse.item_count(owner, classname)   # -> number, or None

Counts how many of an item an owner has. Stacks are counted with their size: five blood packs in one stack count as 5.

  • owner: an index or handle.
  • classname: the item's class.

Returns the count (0 if none), or None if the owner has no inventory (not a character or container), there is no level, or the class name is invalid.

Python
if blse.item_count(1, 'item_g_bloodpack') == 0:
    blse.show_text('You are out of blood packs.')

blse.equip_item#

Python
blse.equip_item(owner, classname)   # -> 1 or 0

Makes a character take an item from its inventory into its hands (the same as selecting a weapon).

When to use it: arm a spawned NPC with the gun you gave it; switch the player to a weapon at the start of a fight scene.

  • owner: the character, as an index or handle.
  • classname: an item the character already carries.

Returns 1 if the switch was asked for, 0 if the character does not carry the item (or no level).

Python
blse.give_item(h, 'item_w_colt_anaconda')
blse.equip_item(h, 'item_w_colt_anaconda')

blse.drop_item#

Python
blse.drop_item(owner, classname)   # -> 1 or 0

Drops one of the item into the world in front of the owner, as the inventory screen does.

  • owner: an index or handle.
  • classname: an item the owner carries.

Returns 1 if one was dropped, 0 if not: the owner does not carry it, or the item may not be dropped (quest items, for example). The function checks the count afterwards, so 1 means the item really left the inventory.

blse.move_item#

Python
blse.move_item(from_owner, to_owner, classname)   # -> 1 or 0

Moves an item from one inventory to another: between the player, NPCs and containers. The very same item moves, with its ammunition and state; a stack moves whole.

When to use it: a companion hands the player a weapon; a stash mod puts the player's items into a chest.

  • from_owner, to_owner: indexes or handles; they must be different.
  • classname: the item's class.

Returns 1 if the item is now in the new inventory, 0 if not: the item is in the giver's hands (switch to something else first, as the game does), the receiving inventory is full (the item is put back), an owner has no inventory, or no level.

Python
blse.move_item(1, chest, 'item_w_colt_anaconda')

A shop of a mod's own#

Combine these with the game's own Python functions: the item's price from blse.item_info, the player's money from the game's pc.money and pc.MoneyAdd, then give_item (sell) or remove_item (buy).

Python
import blse, __main__

def buy_pack(name, args):
    pc = __main__.FindPlayer()
    if pc.money < 50:
        blse.show_text('Not enough money.')
    elif blse.give_item(1, 'item_g_bloodpack'):
        pc.MoneyAdd(-50)

blse.add_command('mymod_buy_pack', buy_pack, 'Buys a blood pack for 50')

Console variables#

Function
blse.get_cvar(name) The value as text, or None if there is no such variable (get_cvar('r_drawviewmodel') -> '1')
blse.set_cvar(name, value) Sets it as the console would (value is text: str(5)); 1, or 0 if there is no such variable
Function
blse.cvars([commands]) (b0.5.35) The names of all console variables (with commands=1, the commands' too), in the engine's order
blse.cvar_changed (event) (b0.5.35) name, old, new = data.split('\0'): a variable changed, from the console, the options screen, a config file, the game itself or a mod. Values are compared twice a second while anyone listens. Loading a level changes many (host_map, sv_skyname, the sk_* ammunition values, dsp_* sound settings): filter by name
blse.read_file(path) (b0.5.35) A file's contents as a string (at most 4 MB), or None; found the way the game finds its files: the mod's folder, the game's, then the .vpk packs. The game's settings are in 'cfg/config.cfg' (key bindings and variables, as the game wrote them)
blse.find_files(wildcard) (b0.5.35) The names (not paths) matching a wildcard, each once: find_files('vdata/items/*.txt'); None if unavailable

A console variable is a game setting with a name, such as fps_max or r_drawviewmodel: what you change by typing fps_max 60 in the console. A console command (map, togglecamera) does something instead of holding a value. These functions work at any time, also at the main menu.

blse.get_cvar and blse.set_cvar#

Python
blse.get_cvar(name)          # -> text, or None
blse.set_cvar(name, value)   # -> 1 or 0

Read or change one console variable.

When to use them: a mod reads fps_max to adapt its own timing; a photo mode turns off the weapon model with r_drawviewmodel 0 and back on afterwards.

  • name (text): the variable's name, e.g. 'r_drawviewmodel'.
  • value (text): the new value. Values are always text, so write str(5), not 5.

get_cvar returns the current value as text (get_cvar('r_drawviewmodel') gives '1'), or None if there is no such variable. A name that is a console command, not a variable, also gives None. Values longer than 511 characters are cut.

set_cvar sets the value exactly as typing it in the console would (the game's own checks and reactions run), and returns 1, or 0 if there is no such variable.

Python
old = blse.get_cvar('r_drawviewmodel')
blse.set_cvar('r_drawviewmodel', '0')     # hide the weapon for a screenshot
# ... later
blse.set_cvar('r_drawviewmodel', old)

blse.cvars#

Python
blse.cvars([commands])   # -> list of names

(b0.5.35) Lists the names of all console variables, in the engine's order.

  • commands (optional, default 0): 1 lists console commands too.

Returns a list of text. Raises RuntimeError if the list cannot be read in this game build.

Python
names = [n for n in blse.cvars() if n[:3] == 'sk_']    # all skill settings

The blse.cvar_changed event#

(b0.5.35) Sent when a console variable's value changes, whoever changed it: the console, the options screen, a config file, the game itself or a mod.

Payload, three parts: the variable's name, its old value, its new value.

Python
import blse

def on_cvar(topic, data):
    name, old, new = data.split('\0')
    if name == 'fps_max':
        blse.log('frame limit changed from %s to %s' % (old, new))

blse.subscribe('blse.cvar_changed', on_cvar)

How it works: while at least one handler is subscribed, BLSE compares all values twice a second, so a change is reported up to half a second late, and a value changed and changed back in between is not reported. The first comparison after you subscribe only records the values (no events). Variables that appear later (when a game library loads) are recorded without an event. Loading a level changes many (host_map, sv_skyname, the sk_* ammunition values, dsp_* sound settings): filter by name.

blse.read_file#

Python
blse.read_file(path)   # -> text, or None

(b0.5.35) Reads a whole file the way the game finds its own files: loose files in the game's folders (and mod folders) first, then the .vpk packs.

When to use it: read a data file your mod ships (a .txt, a .dlg to pass to the dialogue functions); read the game's settings from 'cfg/config.cfg' (key bindings and variables, as the game wrote them).

  • path (text): relative to the game's folder, with /, e.g. 'cfg/config.cfg', 'scripts/mymod/data.txt'. Shorter than 260 characters.

Returns the contents as a string (bytes; binary files work too), or None if the file is not found, is larger than 4 MB, or the path is invalid.

Python
text = blse.read_file('cfg/config.cfg')
if text is not None:
    for line in text.split('\n'):
        if line[:4] == 'bind':
            blse.log(line)

blse.find_files#

Python
blse.find_files(wildcard)   # -> list of names, or None

(b0.5.35) Lists files matching a wildcard, through the same file system as read_file (folders and packs).

  • wildcard (text): a path with * in the last part, e.g. 'vdata/items/*.txt'. Shorter than 260 characters.

Returns the names only ('item_g_bloodpack.txt', not the folder), each name once even when it exists in several places, at most 8192. None if file searching is unavailable or the wildcard is invalid.

Python
for name in blse.find_files('vdata/items/*.txt'):
    text = blse.read_file('vdata/items/' + name)

Finding entities#

blse.find_entities(x, y, z, radius[, classname[, flags[, limit]]]) -> a list of (handle, classname, name, distance), nearest first (64 at most by default, limit up to 512). classname: '' any, 'npc_*' a prefix, or one class (case is ignored). flags: words from 'characters' (the player and NPCs), 'alive' (characters that are not dead) and 'noplayer'. blse.entity_position(entity) -> (x, y, z).

Python
x, y, z = blse.entity_position(1)
for handle, cls, name, distance in blse.find_entities(x, y, z, 400, 'npc_*', 'alive noplayer'):
    ...

blse.entity_box(entity) -> (min_x, min_y, min_z, max_x, max_y, max_z): the entity's collision box around its origin.

All three work only while a level runs.

blse.find_entities#

Python
blse.find_entities(x, y, z, radius[, classname[, flags[, limit]]])   # -> list, or None

Finds the entities within a distance of a point, nearest first.

When to use it: an area Discipline affects every living NPC within 400 units of the player; a radar lists the cops nearby; a script looks for the item it dropped.

  • x, y, z: the centre point.
  • radius: how far to look, in units, 0 or more. Distance is measured in a straight line in 3D, from the point to each entity's origin (its position).
  • classname (optional, default ''): '' matches any entity; a name ending in * matches a prefix ('npc_*' all NPCs, 'item_w_*' all weapons); anything else matches one class. Case is ignored.
  • flags (optional, default ''): words separated by spaces (or , | +):
    • 'characters': only the player and NPCs;
    • 'alive': only characters that are not dead (implies 'characters');
    • 'noplayer': leave out the player. An unknown word raises ValueError.
  • limit (optional, default 64): the most results to return, 1 to 512. Outside that range (or a negative radius) raises ValueError.

Returns a list of tuples (handle, classname, name, distance): the entity's handle, its class, its targetname ('' if none) and its distance. Empty if nothing matches. None outside a level.

Python
x, y, z = blse.entity_position(1)
for handle, cls, name, distance in blse.find_entities(x, y, z, 400, 'npc_*', 'alive noplayer'):
    blse.log('%s %s at %d units' % (cls, name, distance))

blse.entity_position#

Python
blse.entity_position(entity)   # -> (x, y, z), or None

Where an entity is: its origin, usually the point at its feet for characters.

  • entity: an index or handle (1 is the player).

Returns a tuple of three numbers, or None if the entity does not exist or no level runs.

blse.entity_box#

Python
blse.entity_box(entity)   # -> (min_x, min_y, min_z, max_x, max_y, max_z), or None

The entity's collision box: the box the game uses for bumping into it, given as offsets from its origin (not world positions).

When to use it: place something on top of an entity's head, or check whether a spot is inside it.

Returns the six numbers, or None if the entity does not exist or no level runs.

Python
x, y, z = blse.entity_position(h)
box = blse.entity_box(h)
head_z = z + box[5]       # the top of its box

Frame rate#

blse.frame_stats() -> (fps, last_ms, average_ms, worst_ms, frames) over the last second, or None before two frames were drawn. Measured at the end of every frame the game draws, so menus, the console and paused frames count too. The game's limit is the fps_max setting (get_cvar('fps_max')).

blse.frame_stats#

Python
blse.frame_stats()   # -> (fps, last_ms, average_ms, worst_ms, frames), or None

How smoothly the game runs right now, measured over the last second.

When to use it: a mod lowers its own work (fewer HUD updates) when the frame rate drops; a performance overlay shows the numbers.

Returns a tuple:

  • fps: frames per second over the last second;
  • last_ms: how long the most recent frame took, in milliseconds;
  • average_ms: the average frame time over the last second;
  • worst_ms: the longest frame in the last second (a stutter shows here);
  • frames: how many frames the numbers are based on.

None before the game has drawn two frames. Works at any time, also at the main menu: every drawn frame counts, including menus, the console and paused frames.

Python
s = blse.frame_stats()
if s and s[0] < 30:
    blse.log('slow: %.0f fps, worst frame %.0f ms' % (s[0], s[3]))

Camera#

Function
blse.camera_mode() 'first' or 'third' (person), None if unknown
blse.set_camera_mode(mode) Switches the view through the game's own camera toggle (what the togglecamera command does, with the game's rules for sniper rifles and holstering); 1, or 0 outside a level
blse.get_fov() The player's field of view in degrees; 0 is the game's default (as it normally is); None outside a level
blse.set_fov(degrees) Sets it (1..179; 0 restores the default); 1 or 0. The game sets it itself when zooming
blse.camera_view() (x, y, z, pitch, yaw, roll): where the last frame was rendered from, in first and third person (b0.5.31); None outside a level
blse.set_camera_view(x, y, z[, pitch, yaw, roll]) Renders the game from this point (and with these angles; left out: the player's own; all three or none, else ValueError) until clear_camera_view(), the level ends or Python restarts (b0.5.32). Only the picture moves: the player still walks and aims as before, so it suits cut scenes and fixed cameras, not playing. While the camera has its own position the game is in third person (switched with its own toggle, and back afterwards), so the player's character is seen
blse.set_camera_angles(pitch, yaw, roll) Renders with these angles from the player's own view point (b0.5.32). Walking with the picture turned away from where the player faces feels wrong: for moments, not for play
blse.clear_camera_view() The game's own view again (b0.5.32)

blse.camera_mode and blse.set_camera_mode#

Python
blse.camera_mode()           # -> 'first', 'third' or None
blse.set_camera_mode(mode)   # -> 1 or 0

Read or switch between first person (looking through the character's eyes) and third person (the camera behind the character).

  • mode: 'first' or 'third' (any case). Anything else raises ValueError.

camera_mode returns 'first' or 'third', or None if it cannot be read yet.

set_camera_mode switches through the game's own camera toggle (what the togglecamera command does), so the game's rules apply: some weapons (sniper rifles) and holstering affect it. It returns 1 if the view is now in that mode (also if it already was), 0 if not (no level, or the game refused). A mode you set yourself is not switched back by BLSE later.

Python
if blse.camera_mode() == 'first':
    blse.set_camera_mode('third')

blse.get_fov and blse.set_fov#

Python
blse.get_fov()          # -> degrees, or None
blse.set_fov(degrees)   # -> 1 or 0

The player's field of view (FOV): how wide the view is, in degrees. Larger shows more of the world (wider, "fish eye"); smaller zooms in.

  • degrees (whole number): 1 to 179, or 0 for the game's default.

get_fov returns the current value; 0 means the game's default (this is the normal value). None outside a level.

set_fov returns 1, or 0 outside a level or for a value out of range. The game sets the FOV itself when the player zooms (a sniper rifle, for example), which replaces your value.

Python
blse.set_fov(60)    # a slight zoom for a dramatic moment
blse.set_fov(0)     # back to normal

blse.camera_view#

Python
blse.camera_view()   # -> (x, y, z, pitch, yaw, roll), or None

(b0.5.31) Where the last frame was drawn from and in which direction it looked: the camera's real position and angles, in first and third person.

When to use it: start a cut-scene camera from where the player's view is now; play a sound or spawn something in front of the camera.

Returns six numbers, or None outside a level.

blse.set_camera_view#

Python
blse.set_camera_view(x, y, z[, pitch, yaw, roll])   # -> 1 or 0

(b0.5.32) Draws the game from a camera you place, until you call clear_camera_view(), the level ends, or Python restarts.

When to use it: a cut scene, a security-camera view, a fixed camera looking at a scene while dialogue plays.

  • x, y, z: the camera's position.
  • pitch, yaw, roll (optional): the direction it looks. Give all three or none (giving one or two raises ValueError). Left out: the camera keeps the player's own view direction.
  • Values must be ordinary numbers (not infinite, smaller than 10 million).

Returns 1 if the camera is placed, 0 if not.

Only the picture moves: the player still walks and aims as before, so this suits cut scenes and fixed cameras, not playing. While the camera has its own position, BLSE switches the game to third person (with the game's own toggle) so the player's character can be seen, and back to first person afterwards if it switched.

Python
blse.set_camera_view(512, -300, 120, 10, 90, 0)    # look at the scene
# ... a few seconds later, e.g. from a timer in a game_frame handler:
blse.clear_camera_view()

blse.set_camera_angles#

Python
blse.set_camera_angles(pitch, yaw, roll)   # -> 1 or 0

(b0.5.32) Draws the game from the player's own view point, but looking in the direction you give.

When to use it: make the player look at something for a moment (an explosion, a character who calls out), or tilt the view (roll) for a dizzy effect.

  • pitch, yaw, roll: the angles in degrees.

Returns 1, or 0 if it could not be set. Walking while the picture is turned away from where the player faces feels wrong: use it for moments, not for play. End it with clear_camera_view().

blse.clear_camera_view#

Python
blse.clear_camera_view()   # -> None

(b0.5.32) Ends set_camera_view or set_camera_angles: the game's own view again. If BLSE switched to third person for the placed camera, it switches back to first person. Calling it when nothing is set does nothing.

Sounds#

Function
blse.play_sound(file[, volume[, pitch]]) Plays a sound file below sound/ ('interface/mm_click_on.wav'), heard by the player without position, also while the console or a menu is open. volume 0..1 (default 1), pitch 100 is normal. 1, or 0 if sounds are unavailable
blse.play_sound_at(file, x, y, z[, volume[, pitch[, attenuation]]]) Plays a sound from a point in the world: it fades with distance and comes from that direction (b0.5.31). attenuation 0.8 is normal (default), larger fades faster, 0 is heard everywhere
blse.play_sound_on(file, entity[, volume[, pitch[, attenuation]]]) Plays a sound from an entity (its handle, e.g. from look_target(), or its index), following it as it moves (b0.5.31)
blse.play_ui_sound(file[, volume[, pitch]]) An interface sound, played the way the game's main menu plays its own (b0.5.49): also at the main menu with no level loaded. Buttons' sounds: see Button sounds
blse.stop_sound(file[, entity]) Stops a sound started with play_sound or play_sound_at, or with play_sound_on on that entity (for loops)
blse.sound_length(file) The file's length in seconds, read from its WAV or MP3 header through the game's file system (archives and loose files); None if not found (b0.5.31)

A file that does not exist is silently skipped. (The Unofficial Patch silences player/stealth_discovered.wav with a 10 ms file: sound_length gives 0.00998.) Files are found the way the game finds its own (loose files below a sound/ folder, like the game's music, or in the archives).

Common to all sound functions:

  • file is a path below the sound/ folder, with /: 'interface/mm_click_on.wav' plays sound/interface/mm_click_on.wav. Up to 259 characters. Your mod's own sounds go in a sound/ folder of your mod folder (or the game's).
  • volume: 0 (silent) to 1 (full, the default). Values outside are clamped (brought to the nearest allowed value).
  • pitch: speed and tone, 100 is normal (the default); 50 is half speed and lower, 200 double speed and higher. Clamped to 1..255.
  • attenuation (sounds in the world): how fast the sound fades with distance. 0.8 is normal (the default), larger fades faster, 0 is heard everywhere at full volume. Clamped to 0..4.
  • They return 1 when the sound was handed to the game's sound system, 0 if sounds are unavailable or an argument is invalid. A file that does not exist still returns 1 and plays nothing.

blse.play_sound#

Python
blse.play_sound(file[, volume[, pitch]])   # -> 1 or 0

Plays a sound the player hears "in their head": without a position, the same from every direction. It also plays while the console or a menu is open.

When to use it: a notification, a click in your mod's HUD, a quest jingle.

Python
blse.play_sound('interface/mm_click_on.wav', 0.5)

blse.play_sound_at#

Python
blse.play_sound_at(file, x, y, z[, volume[, pitch[, attenuation]]])   # -> 1 or 0

(b0.5.31) Plays a sound from a point in the world: it gets quieter with distance and comes from that direction. Only while a level runs.

When to use it: an explosion where a trap went off, a voice from behind a door.

  • x, y, z: the point (each between -1000000 and 1000000).
Python
blse.play_sound_at('mymod/boom.wav', 100, 200, 0, 1.0, 100, 0.5)

blse.play_sound_on#

Python
blse.play_sound_on(file, entity[, volume[, pitch[, attenuation]]])   # -> 1 or 0

(b0.5.31) Plays a sound from an entity: it follows the entity as it moves. Only while a level runs.

When to use it: an NPC's voice line, a ringing phone the player carries, a hum on a moving car.

  • entity: a handle (for example from look_target() or find_entities) or an index. A handle of an entity that no longer exists returns 0.
Python
target = blse.look_target()
if target:
    blse.play_sound_on('mymod/whisper.wav', target[2])

blse.play_ui_sound#

Python
blse.play_ui_sound(file[, volume[, pitch]])   # -> 1 or 0

(b0.5.49) Plays an interface sound the way the game's main menu plays its own: it works also at the main menu with no level loaded, and over the paused Esc menu.

When to use it: sounds of your own menu screens. For the sounds of buttons, see Button sounds.

Python
blse.play_ui_sound('interface/mm_click_on.wav')

blse.stop_sound#

Python
blse.stop_sound(file[, entity])   # -> 1 or 0

Stops a sound you started, by its file name. Needed for looping sounds (sounds made to repeat until stopped).

  • file: the same name you played.
  • entity (optional): give the entity you passed to play_sound_on. Without it, the sound started with play_sound or play_sound_at is stopped.

Returns 1 if the stop was sent, 0 if not (sounds unavailable; a handle of an entity that no longer exists).

Python
blse.play_sound_on('mymod/alarm_loop.wav', h)
# ... later
blse.stop_sound('mymod/alarm_loop.wav', h)

blse.sound_length#

Python
blse.sound_length(file)   # -> seconds, or None

(b0.5.31) How long a sound file is, in seconds, read from its WAV or MP3 header through the game's file system (archives and loose files).

When to use it: wait until a voice line has finished before the next one; time subtitles.

Returns the length as a number (1.5), or None if the file is not found or is not a WAV or MP3 file. The Unofficial Patch silences player/stealth_discovered.wav with a 10 ms file: sound_length gives 0.00998.

Python
seconds = blse.sound_length('mymod/line_01.wav')