IETS - v0.5.1
    Preparing search index...

    Examples

    Real TBAF patterns using @bgforge/iets/bg2. These are TypeScript snippets as they appear in .tbaf files - the TBAF transpiler wraps top-level if blocks into IF condition THEN action END and inlines all variables, functions, and loops at compile time. The resulting .baf contains no TypeScript abstractions.

    For full transpiler semantics see the TBAF forum thread. For dialog scripting in .td files see the TD forum thread.

    From the tbaf-example project - on-sight talk-then-fight behavior for an NPC mage:

    import { LOCALS } from "@bgforge/iets";
    import {
    FaceObject, Global, LastSeenBy, LevelLT, Myself, NearestEnemyOf, Player1,
    ReallyForceSpell, ReallyForceSpellRES, See, SetGlobal, SmallWait, StartDialog,
    WIZARD_ARMOR, WIZARD_SHIELD,
    } from "@bgforge/iets/bg2";

    const LVAR_doomed = "doomed";
    const LVAR_castSpellTrigger = "castSpellTrigger";

    // First talk, then fight
    if (See(Player1) && Global(LVAR_doomed, LOCALS, 0)) {
    SetGlobal(LVAR_doomed, LOCALS, 1);
    FaceObject(Player1);
    SmallWait(8);
    StartDialog("WM_RHIA", Player1);
    }

    // Spell trigger setup, branching on observed enemy level
    if (See(NearestEnemyOf(Myself)) && Global(LVAR_castSpellTrigger, LOCALS, 0)) {
    if (LevelLT(LastSeenBy(Myself), 3)) {
    ReallyForceSpell(Myself, WIZARD_ARMOR);
    ReallyForceSpell(Myself, WIZARD_SHIELD);
    }
    if (LevelLT(LastSeenBy(Myself), 8)) {
    ReallyForceSpellRES("WM_LIGHT", Myself);
    ReallyForceSpell(Myself, WIZARD_SHIELD);
    }
    }

    Each top-level if becomes one or more IF/THEN/END blocks. Nested ifs accumulate conditions: the inner block's condition list becomes parent-conditions plus child-condition.

    Most action and trigger arguments take an ObjectPtr. Common forms:

    • Pre-defined identifiers: Player1, Myself, LastSeenBy, LastAttackerOf(Myself), NearestEnemyOf(Myself).
    • Constructed specifiers via obj(): [ENEMY.0.0.MAGE]-style strings.
    import { obj } from "@bgforge/iets";
    import { Attack, Kill, Myself } from "@bgforge/iets/bg2";

    if (See(obj("[ENEMY.0.0.MAGE]"))) {
    Attack(obj("[ENEMY.0.0.MAGE]"));
    }

    The TBAF transpiler maps TypeScript boolean operators to BAF condition algebra:

    • && -> implicit AND between conditions in the same IF block
    • || -> OR(n) group
    • ! -> !
    if (See(Player1) && Global("hostile", LOCALS, 1)) { Attack(Player1); }
    // -> IF See(Player1) Global("hostile","LOCALS",1) THEN Attack(Player1) END

    if (See(Player1) || See(Player2)) { Attack(NearestEnemyOf(Myself)); }
    // -> IF OR(2) See(Player1) See(Player2) THEN Attack(NearestEnemyOf(Myself)) END

    if (!See(Player1)) { NoAction(); }
    // -> IF !See(Player1) THEN NoAction() END

    IDS constants are typed IE<number, "..."> and exported from the same bg2 barrel as actions and triggers. Use the symbolic name; the transpiler emits it verbatim into the .baf:

    import { ReallyForceSpell, Myself, WIZARD_FIREBALL, CLERIC_BLESS } from "@bgforge/iets/bg2";

    ReallyForceSpell(Myself, WIZARD_FIREBALL);
    ReallyForceSpell(Myself, CLERIC_BLESS);

    Many actions come in two flavors: one taking an IDS-typed ID, one taking a resref string. The resref form is suffixed RES:

    ReallyForceSpell(Myself, WIZARD_SHIELD);        // ID form  -> typed SpellID
    ReallyForceSpellRES("WM_LIGHT", Myself); // RES form -> raw resref string

    Resrefs (ResRef, SplRef, ItmRef, AreRef, CreRef) are intentionally unbranded string & {} - pass string literals directly, no cast needed. See Type system for the rationale.

    Variable names are plain string literals. Scope accepts GLOBAL, LOCALS, MYAREA, or any area resref:

    import { GLOBAL, LOCALS } from "@bgforge/iets";
    import { Global, SetGlobal } from "@bgforge/iets/bg2";

    if (Global("chapter", GLOBAL, 3)) {
    SetGlobal("seen_chapter3_intro", LOCALS, 1);
    }

    if (Global("ar0602_explored", "AR0602", 1)) {
    // ...
    }

    Point is a [number, number] tuple - no helper needed:

    import { MoveToPoint } from "@bgforge/iets/bg2";

    MoveToPoint([1024, 768]);

    Both expand at compile time. Loops over arrays become repeated blocks; user-defined functions inline their bodies at each call site. This is how TBAF gives you abstractions over a flat BAF target:

    function attackIfVisible(target: ObjectPtr) {
    if (See(target)) { Attack(target); }
    }

    for (const enemy of [obj("[ENEMY.0.0.MAGE]"), obj("[ENEMY.0.0.FIGHTER]")]) {
    attackIfVisible(enemy);
    }

    The generated .baf contains four IF/THEN/END blocks (two enemies x one condition each), with no surviving function or loop construct.