23 KiB
MossTank research: Virindi Tank parity and UtilityBelt expressions
Date: 2026-08-26
This report is the requirements baseline for turning MossTank from the small self-buffing sample into acdream's full automation plugin. The product target is deliberately broad: all Virindi Tank functionality, with UtilityBelt's more capable expression dialect as the scripting baseline. File compatibility is a separate decision; behavioral capability is not.
1. Evidence and limits
The following primary VTank pages were read and cross-checked (the live wiki and its indexed historical revisions were both used where a mirror was temporarily unavailable):
http://virindi.net/wiki/index.php/Virindi_Tankhttp://virindi.net/wiki/index.php/Virindi_Tank_Standard_Optionshttp://virindi.net/wiki/index.php/Virindi_Tank_Advanced_Optionshttp://virindi.net/wiki/index.php/Virindi_Tank_Commandshttp://virindi.net/wiki/index.php/Virindi_Tank_Meta_Systemhttp://virindi.net/wiki/index.php/Meta_Expressionshttps://utilitybelt.gitlab.io/docs/expressions/
The 2026-08-27 MT2 follow-up also verified the exact documented distinctions that drive the combat scheduler:
- A+R requires
MinimumRingTargetsinside Ring Range; R without A rings with any configured target inside range and falls back to standard war outside; UseArcsprefers an arc over a bolt only at/aboveArcRange;Void Basic,Drain Auto, andHarmare distinct Monsters damage choices;GhostMonsterSpellAttemptCountcounts spell attempts which never start, whileBlacklistMonsterAttemptCountcounts successful attacks which miss;- the health-tracker ghost detector is independent and applies to melee, missile, and magic.
Sources: the official Virindi_Tank_Standard_Options,
Virindi_Tank_Advanced_Options, Virindi_Tank_FAQ, Options_List, and
Virindi_Tank_Changelog pages listed above.
For UtilityBelt, documentation was checked against the primary source rather
than relying on the generated web page alone. The inspected repository was
https://gitlab.com/utilitybelt/utilitybelt, commit
5fe9825a82f38047737768fd92c61dd47d88e467 (2026-03-05). The grammar is
UtilityBelt/Lib/Expressions/MetaExpressions.g4; every method carrying an
ExpressionMethod attribute was enumerated. The source is MIT licensed.
This report extends, rather than replaces,
2026-07-29-vtank-plugin-automation-requirements.md. That earlier report
already decoded VTank's .met, .nav, and .utl structures from primary
sources and remains the format reference.
2. Complete VTank capability map
2.1 Combat
VTank is a priority-driven combat controller, not merely an auto-attack loop. Its supported combat family includes:
- melee, missile, mage, hybrid, two-handed, Void and Summoning characters;
- Life harm/martyr attacks, grenades, lenses, cast-on-strike weapons, streaks;
- automatic damage/weapon choice and monster-specific weapon, offhand and pet element overrides;
- monster rules with
DEFAULTplus ordered first-match expressions; - per-rule priority from ignore (
-1) through4, attack/debuff flags, damage type, attack height, ring/streak choices, and void curses; - target selection by distance, angular deviation, or the hybrid method using angle inside a configurable cutoff and distance outside it;
- target lock, blacklist/retry behavior, and ghost-target retirement after failed casts or missing health updates;
- debuff scheduling by one target, priority group, or all targets before attack; spell-level versus skill-based debuff choice and reapply windows;
- automatic ring use by nearby-target density and arc/bolt choice by range;
- melee high/middle/low attacks, automatic or explicit power, Recklessness;
- pet density, element, refill and test behavior.
VTank's macro scheduler checks multiple action lists in priority order. Combat therefore cannot be implemented as an isolated timer: healing, buffing, navigation, looting, fellowship assistance and combat all need one arbiter.
2.2 Buffing and vitals
- automatic trained attribute/skill buffs, protections, banes, auras, regeneration and configured extra buffs;
- protection/bane profile sets, exclusions, level/tier selection, signed skill-over-difficulty thresholds, force buff and idle top-off;
- time-remaining rebuff and persisted item-buff duration knowledge;
- combat, idle and fellowship-helper vital thresholds;
- kits, vital transfers, post-switch recharge behavior and special healing items;
- self-dispel in response to high-level vulnerabilities.
MossTank's current buff engine already owns the first useful subset: known self buffs, tier/difficulty choice, in-force enchantment timing, force buff, and stamina/mana upkeep. It remains plugin policy over host primitives.
2.3 Inventory and crafting
- AutoStack and AutoCram;
- pea splitting and priority rules;
- crafting of kits, foods, arrowheads and special ammunition;
- mana-stone acquisition, filling and application to equipped items;
- lockpick selection and use;
- component, consumable, tool and ammunition upkeep.
2.4 Looting
- corpse approach/open/retry/timeout/blacklist;
- all/fellow/rare loot modes and priority boosts;
- appraisal/ID wait, unknown-scroll reading and salvage combining;
- a loot-plugin seam, with VTClassic as the canonical ordered, first-match rule engine over raw and computed item properties;
- actions including no-loot, keep, keep-up-to, salvage, sell, read and custom user actions.
The host must expose object property bags, appraisal completion and transaction primitives. Rule ordering and loot-profile policy belong in MossTank.
2.5 Navigation
- circular, linear, once/runback and follow routes;
- points, portals, recalls, pauses, chat, vendor, repeated NPC talk/use, server-confirmed checkpoints and charged/shift/strafe jumps;
- closest-entry, reversal, arrival/off-course ranges, door use and follow-around-corners;
- combat/nav priority interaction.
Route storage belongs to the plugin. The host owes move-to, follow, turn, jump, use and authoritative-arrival primitives.
Direct inspection of the official assembly on 2026-08-27 pinned the route contract more tightly:
eNavTypeis Circular, Linear, Target and Once; Once destructively removes its first completed row and Linear deliberately visits each endpoint once while flipping direction;eWaypointTypeassigns Point/Portal/Recall/Pause/ChatCommand/OpenVendor/ Portal2/UseNPC/Checkpoint/Jump to numeric ids 0..9;fd.csturns outside 4°, moves while turning only within 45° beyond 3 m or 15° inside 3 m, and stops atNavCloseStopRange(default 2 m);gr.cscompares the checkpoint against the last server position rather than client prediction and nudges forward after 15 seconds without an acknowledgement;gl.csrecords the followed player's path by approximately 9.6 cm and drops old breadcrumbs when the follower comes within 2.4 m of a later path segment, preserving follow-around-corners;e9.csandfa.csreacquire exact-name/class objects within 2.5 m of the stored position. Portal2 retries when portal exit remains within 15 m of its origin; UseNPC repeats until the named NPC tells or gives to the player;b7.csis a rule independent of the route node list.OpenDoorsdefaults false; it IDs doors at 20 m, opens at 4 m, and accepts a lock when Lockpick is at leastdifficulty - 50using an owned lockpick.
These are plugin policies over additive canonical projections, not a second movement model. The host applies semantic movement intent through Runtime's existing command interpreter and supplies the accepted server position needed only by Checkpoint.
2.6 Fellowship and social automation
- tell-driven recruitment and waiting lists;
- fellowship leader/member/state queries and leader replacement voting;
- fellowship healing, corpse permissions and coordinated target/debuff policy;
- multi-client composition through chat rather than a privileged macro API.
External loot-classifier seam
VTank loads one LootPluginBase, asks DoesPotentialItemNeedID, and then
calls GetLootDecision(GameItemInfo). Its public result vocabulary is
NoLoot, Keep, Salvage, Sell, Read, User1–User5 and KeepUpTo with Data1 as the
limit. MossTank modernizes discovery into a host-owned classifier registry:
plugins register a namespaced classifier for their own lifetime, while
MossTank remains the corpse/appraisal/pickup/action executor. The selected
engine is durable policy; if it unloads, MossTank returns no classifier match
instead of silently applying the built-in profile.
Direct inspection of the official hv.cs also shows that a custom loot
plugin's per-item action is retained only after the item enters owned
inventory and is removed when the item leaves. The modern registry therefore
has matching OnLooted and OnItemRemoved callbacks. MossTank invokes them
only from authoritative inventory publication/removal, never when pickup is
merely dispatched.
Options-page scheduler findings
The official Options controls are not merely presentation aliases:
fz.csruns the ordinaryRebuffTimeRemainingSecondsrule before combat;cLogic.csruns a secondIdleBuffTopoffTimeSecondspass only behindIdleBuffTopoff, after attack/loot work has gone idle;- the PRETARGETAPPROACH
g8rule navigates only betweenAttackDistanceandApproachDistance, and requires both combat and navigation to be enabled; cm.cschanges to Peace only as the final no-target/no-work fallback.
The UI displays AC-distance settings multiplied by 240. MossTank stores metres in its typed controllers and converts only at the VTank option boundary.
2.7 Meta state machine
- named states beginning at
Default; - state-local rules, each firing once per state entry;
- nested conditions (
All,Any,Not) and conditions for chat regex, inventory, timers, nav state, death, vendors, monsters, buffs, coordinates, portals, burden, route distance, expressions and captured chat groups; - actions for state transition, chat, grouped actions, embedded navigation, call/return stack, expression execution, expression-derived chat, watchdogs, option read/write and runtime-created views;
- a roughly 293 ms decision cadence plus evaluation when the macro asks for its next action.
2.8 Profiles, commands and companion behavior
- independent settings, navigation, loot and meta profiles; global and per-character variants; hot loading and automatic persistence;
- command parity for macro state, options, buffing, meta, item testing, property dumps, monster/spell diagnostics, route editing, attack power and debug output;
- extensibility equivalent to VTClassic, VI2, item tools, follower/status HUD, alerts and cross-character inventory. Some belong as separate acdream plugins, but MossTank's API must permit them without privileged host code.
3. Expression language target
3.1 Why UtilityBelt is the baseline
VTank expressions are enough to power classic metas, but UtilityBelt preserves the familiar syntax while adding typed lists and dictionaries, slicing, higher-order collection functions, broader object queries and more action primitives. MossTank should implement the UtilityBelt-compatible semantic superset and offer a VTank compatibility mode for old expressions.
3.2 Grammar and evaluation semantics
The audited UtilityBelt grammar supports:
- multiple
;-separated statements, returning the final result; - session (
$), persistent (@) and global (&) variables; - decimal and hexadecimal numbers, booleans and two string forms;
- function calls using
name[...]; - typed values: number, string, boolean, list, dictionary, coordinate, world object, stopwatch and UI control;
- list/string/dictionary indexing, slices and negative indices;
- complement, shifts, bitwise operators, exponentiation, arithmetic, regex
match (
#), comparison, short-circuit&&and||; - registered function metadata, arity/type validation and documented return types;
- collection creation/mutation/copying plus map/filter/reduce/sort/range.
Implementation requirements follow directly: parse into an immutable AST; compile or interpret without ambient reflection; use explicit value kinds; short-circuit logical nodes; attach cancellation and an instruction budget; make all world/action functions capabilities supplied by the MossTank engine; and serialize only persistent/global variable stores.
3.3 Audited UtilityBelt function catalog (260 declarations)
The declaration count includes aliases/overloads. Grouped by capability, the public names are:
- language/conversion/math:
abs,acos,asin,atan,atan2,ceiling,chr,cnumber,cos,cosh,cstr,cstrf,floor,hexstr,iif,ifthen,isfalse,istrue,lumavg,lumtotal,ord,randint,round,sin,sinh,sqrt,strlen,tan,tanh,tostring,vitae; - variables:
getvar,setvar,testvar,touchvar,clearvar,clearallvarsand the correspondingpvarandgvarfamilies; - execution/chat:
exec,delayexec,clearexec,echo,chatbox,chatboxpaste; - lists:
listcreate,listadd,listinsert,listremove,listremoveat,listgetitem,listcontains,listindexof,listlastindexof,listcopy,listreverse,listpop,listcount,listclear,listfilter,listmap,listreduce,listsort,listfromrange; - dictionaries:
dictcreate,dictgetitem,dictadditem,dicthaskey,dictremovekey,dictkeys,dictvalues,dictsize,dictclear,dictcopy; - time/location:
getdatetimelocal,getdatetimeutc,getunixtime,getworldname,getplayercoordinates,getplayerlandblock,getplayerlandcell, coordinate parse/get/distance/string functions, stopwatch functions, and the elevengetgame*/day/night functions; - character: raw typed property reads, base/buffed skills, training level, base/current/buffed-max vitals, base/buffed attributes, burden, free slots, cooldown expiration, account hash and character index;
- spells/components:
getknownspells,getisspellknown,getcancastspell_buff,getcancastspell_hunt,getspellexpiration,getspellexpirationbyname,spelldata,spellname,componentdata,componentname; - world objects: validity/data/ID-time, raw typed properties, identity,
health/vitals, spells, coordinates, selection/player/open-container, door
state, nearest monster/door/by class/name/template, and
wobjectfindall*variants over world, landscape, inventory and containers; - actions: select, use, apply, give, equip wand, cast, cast-on-target, move, split and drop;
- combat/movement: combat state get/set, busy state, equipped weapon type, heading/get-heading-to, motion get/set/clear and portal-state query;
- inventory/loot/salvage: counts by name/regex/type, give-profile,
unopened corpse queries,
ustadd,ustopen,ustsalvage; - fellowship/quest/XP: thirteen fellowship queries, quest state/progress, seven XP-meter operations;
- UI/options/network/login: status HUD, view/control get/set/visibility, VT option/meta get/set, macro status, UtilityBelt options, regex capture, network clients and next-login control.
This catalog is a compatibility test ledger. Each name must eventually be implemented, deliberately aliased, or marked unsupported with a documented reason; silent omission is not acceptable.
4. acdream mapping after the 2026-08 campaigns
The 2026-07 report's architecture remains correct, but its gap table is stale.
The Runtime now owns inventory transactions, selection, combat mode and power
state, casting, fellowship, allegiance, vendor and secure-trade state. MossTank
already consumes a small BCL-only IAutomationSurface for vitals, skills,
spells, enchantments, casting and local chat.
The gaps relevant to the first autocombat milestone are narrower:
| Need | Canonical owner today | Plugin gap |
|---|---|---|
| hostile query and live position | RuntimeEntityDirectory + ClientObjectTable |
no target snapshot/query |
| health and selected target | RuntimeActionState |
no combat view |
| melee/missile charge/release | RuntimeCombatAttackState |
no command surface |
| combat-mode transition | RuntimeCombatModeState |
no command surface |
| known offensive spells | Spellbook |
only self buffs are enumerated |
| target-specific cast | selection + RuntimeSpellCastState |
possible only by composing two old services |
| polished plugin controls | retained IUiRegistry markup |
markup lacks bound visibility/enabled/style affordances |
The first implementation therefore does not need a second runtime bridge or a second object model. It needs a narrow additive projection of those exact owners.
5. Decisions for MossTank
- MossTank remains an ordinary plugin. It never references App, Runtime, rendering, networking or DAT assemblies.
- The host API exposes snapshots and attempt-style commands; MossTank owns target scoring, rule ordering, spell/attack choice and timing.
- The first combat milestone supports melee, missile and direct offensive magic, target lock, range/angle/hybrid scoring, priority rules, attack height and power. Navigation, weapon swapping, debuffs, vulnerabilities, pets and monster expressions are later combat slices, not hidden stubs.
- Expressions will use UtilityBelt's richer typed semantics. Compatibility is defined by parser/evaluator tests and the audited function ledger, not by copying UtilityBelt implementation code.
- Native MossTank profiles will be versioned JSON. Importers for VTank files can be added later without constraining the internal model.
- The UI uses acdream's retained plugin UI contract. Missing generic controls should improve that contract/markup rather than making MossTank depend on a presentation implementation.
5.1 Follow-up implementation findings (2026-08-27)
VTank's official e0.d(name) first looks in MonsterDamageOverrides, then
maps the monster to SpeciesDamages; ga.g(...) walks that ordered preference
list and finally tries the unlisted elements 0..6. acdream already projects
retail CreatureType as PluginCombatTarget.SpeciesId, so MossTank can bypass
VTank's name-to-species compatibility table while preserving the same ordered
damage result. Exact name overrides still win. The imported official feed has
59 overrides and 103 species rows.
5.2 Official inventory and loot findings (2026-08-27)
The official VTank assembly and its GameInfoDB were inspected rather than inferring behavior from the UI labels:
el.cs/cf.cssupply 757 exact craft rows; prerequisites are recursive and share the canonical item-use transaction;fo.csidentifies every corpse before selection, parsesKilled by ..., admits the player's own corpse immediately, admits a Share Loot fellow immediately, waits 100 seconds for a non-sharing fellow or unrelated public corpse, and never crosses ownership on another player's rare-generating corpse;- the default corpse-open retry contract is 30 attempts, then a 200-second blacklist; completed corpse records expire after 60 minutes;
hv.csapplies the ordered loot rule first, then falls back to readable unknown scrolls and automatic mana-stone/tank acquisition;dy.csproves that ManaTank is a mana-bearing donor target, not a worn-item recharge consumable. A ManaStone is used on that donor when its mana is at leastManaTankMinimumMana(default 1000);c7.cscombines only same-material salvage bags in exact workmanship bands<7,7–<9,9–<10, and exactly10; one bugged source is abandoned after 40 failed combine attempts;gmSalvageUI::SalvagecallsCM_Inventory::Event_CreateTinkeringTool: game action0x027D, tool id, thenPackableList<unsigned long>(count plus ordered item ids). This same operation handles ordinary source salvage and salvage-bag combination.
The native implementation keeps settings, loot, route, and meta documents
independent, matching VTank's profile model while using versioned JSON as the
working format. It also emits and imports exact compatibility files: uTank2 NAV 1.2, CondAct .met, and VTClassic UTL 1 (plus legacy UTL v0 reads).
The UTL port preserves unknown length-delimited requirement and extra-block
payloads, executes the complete 31-type requirement vocabulary, and carries
the SalvageCombine material ranges/value modes into the live combine planner.
VTClassic's color rules use the original ordered ObjDesc subpalettes and the
original sample index length*16 + offset*32 + 8, resolved from portal DAT
palette colors rather than approximated from icon pixels.
Profiles are implemented over manifest-scoped JSON with exact VTank files as
an interchange/export layer: By char hashes the canonical character name into a distinct
document, named profiles are explicit shared snapshots, and the index records
owner plus per-character active selection. Create/copy/clear/select all hot-
load the same mutable policy owners already borrowed by the controllers. The
generic retained markup contract gained editable fields and retail dropdown
menus for this editor; later Monsters, Loot, Route, and Meta editors reuse the
same controls.
6. Acceptance boundary for “autocombat ported”
The milestone is complete when an in-world MossTank panel can enable/disable combat, periodically capture canonical hostile targets, preserve a valid locked target, choose a target by configured range/angle/hybrid policy and priority, enter the equipped default combat mode, drive retail's physical press/charge/release state machine at configured height/power, or cast the best usable learned direct offensive spell in magic mode. It must stop cleanly on session loss, invalid/dead/out-of-range targets, and user disable; it must not duplicate Runtime state or issue overlapping requests.
Full VTank parity is the campaign target. This acceptance boundary is only the first executable slice requested for this work session.
7. Official binary combat-item findings (2026-08-27)
The official vt.tar.gz update was decompiled for behavior research and the
live GameInfoDB v9 feed was read directly. The decisive implementations are
dz.cs (debuff source selection), ga.cs (item classification), gs.cs
(caster-item confirmation), bo.cs (physical/proc confirmation), and hi.cs
(attack-power policy).
dz.b.CompareToranks spell quality then source skill/spellcraft forSpellLevel, reverses those two forSkill, and gives a learned spell the final tie. Spell quality is normally spell difficulty.- Caster items activate on the target. Melee/missile proc weapons are equipped
and repeatedly attack at power 0/1 respectively. Neither path counts as
applied until color-7 combat chat matches
^You cast (.*) on .*$. - Grenades are missile-class items with CombatUse 0 and
Phialin the name; the official database contains exactly 72 names across eight material tiers, with Alchemy requirements 75..400 and spellcraft 100..520. - Normal physical attack power is not a smooth heuristic.
hi.csemits the exact 0, .2, .49, .5 or 1 values for slash/pierce hybrid arrangements, then clamps to .11..90 when trained Recklessness is enabled.
These findings require three host facts VTank formerly obtained through Decal: retained per-item appraisal SpellBooks, ordered transcript capture, and an explicit combat-mode command. They are additive BCL plugin contracts; MossTank retains all source-choice and retry policy.