feat(vt): A1 .usd engine + A3 metaf .af engine, real VTank/metas fixtures

Campaign VT slice 1 Part A. Two new file-format ports, both against real
committed fixtures (owner's own VTank profiles + the metas repo's af/met/nav
corpus), not synthetic data.

A1 — VtankUsdDocument.cs is a from-scratch port of VTank's gy/bd/cw/y
self-describing text-database grammar (docs/research/vtank-kb/01-settings-
and-profiles.md section 1), preserving every table/row/cell it doesn't
understand byte-for-byte. VtankSettingsProfileSerializer.cs maps all 137
Settings rows (VtankOptionCatalog.Names) onto CombatSettings/BuffSettings/
VitalSettings/InventorySettings/NavigationSettings using the exact unit
transforms already verified in MossTankPanel.SetMetaOption/GetMetaOption
(the *240/100 scaling, the TargetSelectMethod +1/-1 offset, etc.) — cited as
the oracle rather than re-derived, since a file-format serializer must not
depend on a live session. RechargeHandlerSet's real 5-column nested table
(26 rows, not the 24 the KB doc estimated) now drives
VitalRechargePlanner.Handlers via a new RechargeHandlerRow, replacing the
hand-typed default replica; the parsed defaults corrected one real
discrepancy (magic-mode Health<=15% never included Kit) while confirming
the rest matched. BuffProfileDocument gained the 10 fields it was silently
dropping (KB doc 01 section 5 gap 2). Save() only rewrites a Settings row
when the live value differs from what was parsed (a tolerant numeric
compare, not exact-text), so an untouched profile round-trips byte-for-byte
even where VTank's own older double formatting differs from .NET 10's.

A3 — MetafSerializer.cs ports metaf's STATE:/IF:/DO:/NAV: text grammar
(github.com/JJEII/metaf, metaf_monolithic.py, GPLv3 — grammar read and
cited by line, never copied) onto the existing Meta.cs/Navigation.cs
models. All 28 conditions, 16 actions, and 10 nav-node types; strict
All/Any child-depth nesting; Not's real same-line (not depth+1) operand
placement, discovered by testing against real fixtures after an initial
wrong read of the collapsed IF:/DO: layout; EmbedNav's separate NAV: block
with tag cross-referencing, including re-synthesizing the "uTank2 NAV 1.2"
blob MetaEngine already expects. The jump-charge 2000ms clamp (KB doc 06
row 5) is applied at .af load. All four contract proofs pass: every real
.af parses; parse-write-parse is model-identical; our binary-.met and
.nav import matches the same content loaded from metaf's own .af
conversion; the writer's output is byte-identical (after comment-stripping)
to metaf's own canonical emission for 5 real fixtures, once two real metaf
quirks were matched (ADestroyView's literal double space; the
GenerateUniqueNavTag "nav{n}__name" tag scheme) and the two files with a
pre-existing single-Position-field limitation in RouteWaypoint (ptl/tlk
inside an embedded nav) were excluded with a documented reason.

Also: the .utl BuffedInt/BuffedDouble base-key-exists gate (KB doc 05
section 2.2 / gap 4) — a spell bonus no longer applies to a value the item
never had a base key for.

Fixtures: the owner's own defaultsettings.usd/owner-{a,b,c}.usd+.ast,
4 .utl loot profiles, and a hand-picked set of real metas-repo .af/.met/.nav
files chosen by grepping metas/af for keyword coverage (every condition,
action, and nav-node type actually present in that corpus; GetOpt/flw/jmp
appear in none of it, so those three are covered by one small hand-authored
fixture instead, called out in its own test). Two met/nav pairs were
swapped for a fresh selection after their timestamps proved the shipped
.af had drifted from a since-re-recorded .nav (a real data-consistency
issue in the source repo, not a port bug).

Shown to fail by: VtankSettingsProfileSerializerTests (temporarily reverting
the ValuesEqual numeric-tolerance compare made the untouched-round-trip
test fail with a real text diff); MetafSerializerTests (every proof
genuinely failed against the real fixtures until the Not/nav-blank-skip/
pau-scaling/EmbedNav-tag bugs below were fixed, confirmed failing at each
step during authoring); VtankLootRequirementEvaluatorTests (confirmed via
`git stash` on VtankLootRequirementEvaluator.cs that
BuffedIntRequirementDoesNotApplyBonusWhenBaseKeyIsAbsent fails without the
gate).

Deviation: added -text entries to the root .gitattributes, scoped to only
the new tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/** paths, so
these CRLF-exact fixtures survive a checkout on any OS/core.autocrlf
setting instead of being silently normalized — flagged per the contract's
"stay inside the plugin/tests trees" rule since this one line is outside
both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-06 20:52:51 +02:00
parent 1b81836747
commit 9a7e7c4ae8
56 changed files with 54687 additions and 3 deletions

15
.gitattributes vendored
View file

@ -1 +1,14 @@
.github/workflows/*.lock.yml linguist-generated=true merge=ours
.github/workflows/*.lock.yml linguist-generated=true merge=ours
# VTank file-compatibility fixtures (Campaign VT slice 1, Part A): these are
# real VTank .usd/.ast/.utl profiles and real metaf .af/.met/.nav samples
# whose exact CRLF-vs-LF byte layout is asserted by round-trip tests
# (VtankSettingsProfileSerializerTests, MetafSerializerTests). `-text`
# disables git's line-ending normalization entirely so a checkout on any OS
# or core.autocrlf setting reproduces the committed bytes exactly.
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.usd -text
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.ast -text
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.utl -text
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.af -text
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.met -text
tests/AcDream.Plugins.MossTank.Tests/Fixtures/vtank/**/*.nav -text

File diff suppressed because it is too large Load diff

View file

@ -819,6 +819,21 @@ internal sealed class MossTankProfileStore
public bool BuffOther { get; set; }
public bool BuffTrainedSkillsOnly { get; set; } = true;
// VTank-catalog fields SetMetaOption already writes at runtime
// (MossTankPanel.cs:2942-2973,3297-3317) but this document never
// captured, so they silently reset to class defaults on the next
// save/load round-trip (KB doc 01 section 5, gap #2).
public double BuffCastRecastSeconds { get; set; } = 30d;
public double BuffCastRecastResetSeconds { get; set; } = 30d;
public bool FastCastBuffs { get; set; }
public bool RandomHelperBuffs { get; set; }
public double RandomHelperIntervalSeconds { get; set; } = 5d;
public string BlacklistedSpellComponents { get; set; } = string.Empty;
public string ProtectionElements { get; set; } = "ALFCBPS";
public int ProtectionProfileMode { get; set; } = 2;
public string BaneElements { get; set; } = "ALFCBPS";
public int BaneProfileMode { get; set; } = 2;
public static BuffProfileDocument Capture(BuffSettings value) => new()
{
Enabled = value.Enabled,
@ -833,6 +848,16 @@ internal sealed class MossTankProfileStore
BuffRegeneration = value.BuffRegeneration,
BuffOther = value.BuffOther,
BuffTrainedSkillsOnly = value.BuffTrainedSkillsOnly,
BuffCastRecastSeconds = value.BuffCastRecastSeconds,
BuffCastRecastResetSeconds = value.BuffCastRecastResetSeconds,
FastCastBuffs = value.FastCastBuffs,
RandomHelperBuffs = value.RandomHelperBuffs,
RandomHelperIntervalSeconds = value.RandomHelperIntervalSeconds,
BlacklistedSpellComponents = value.BlacklistedSpellComponents,
ProtectionElements = value.ProtectionElements,
ProtectionProfileMode = value.ProtectionProfileMode,
BaneElements = value.BaneElements,
BaneProfileMode = value.BaneProfileMode,
};
public void Apply(BuffSettings value)
@ -852,6 +877,19 @@ internal sealed class MossTankProfileStore
value.BuffRegeneration = BuffRegeneration;
value.BuffOther = BuffOther;
value.BuffTrainedSkillsOnly = BuffTrainedSkillsOnly;
value.BuffCastRecastSeconds = Math.Clamp(
BuffCastRecastSeconds, 0d, 3600d);
value.BuffCastRecastResetSeconds = Math.Clamp(
BuffCastRecastResetSeconds, 0d, 3600d);
value.FastCastBuffs = FastCastBuffs;
value.RandomHelperBuffs = RandomHelperBuffs;
value.RandomHelperIntervalSeconds = Math.Clamp(
RandomHelperIntervalSeconds, 0.25d, 3600d);
value.BlacklistedSpellComponents = BlacklistedSpellComponents ?? string.Empty;
value.ProtectionElements = ProtectionElements ?? "ALFCBPS";
value.ProtectionProfileMode = Math.Clamp(ProtectionProfileMode, 1, 8);
value.BaneElements = BaneElements ?? "ALFCBPS";
value.BaneProfileMode = Math.Clamp(BaneProfileMode, 1, 8);
}
}

View file

@ -46,6 +46,14 @@ public sealed class VitalSettings
public bool ClearLevelBoostFlagOnCast { get; set; } = true;
public int DropToPeaceModeRetryCount { get; set; } = 34;
public string RechargeHandlerSet { get; set; } = "RechargeHandlerSet";
/// <summary>
/// The real VTank <c>RechargeHandlerSet</c> nested table (5 columns:
/// Vital/HandlerString/MinPercent/MaxPercent/Stance), parsed from a
/// loaded <c>.usd</c> profile by <see cref="VtankSettingsProfileSerializer"/>.
/// Empty until a profile with this table is loaded; <see cref="VitalRechargePlanner"/>
/// falls back to its hand-ported default ordering when this is empty.
/// </summary>
public IReadOnlyList<RechargeHandlerRow> RechargeHandlerRows { get; set; } = [];
public bool UseKitsInMagicMode { get; set; } = true;
public bool GoToPeaceModeToUseKits { get; set; }
public int MinimumHealKitSuccessChance { get; set; } = 95;

View file

@ -33,6 +33,43 @@ internal enum VitalRechargeMethod
Food,
}
/// <summary>
/// One row of VTank's real <c>RechargeHandlerSet</c> nested table
/// (<c>refs/vtank/uTank2.Resources.defaultsettings.usd</c>, Settings row
/// 137's Value cell — a 5-column TABLE: Vital/HandlerString/MinPercent/
/// MaxPercent/Stance, 26 seed rows verified against the live fixture).
/// <c>Vital</c> uses VTank's own raw encoding (1=Health, 2=Stamina,
/// 3=Mana — distinct from this port's <see cref="VitalKind"/> which reuses
/// AC property-id values); <c>Stance</c> is 1=Magic, 2=Melee/Missile
/// (matches this planner's <c>magicMode</c> bool exactly, confirmed by
/// reproducing every existing hand-ported default list from the parsed
/// table). <c>MinPercent</c>/<c>MaxPercent</c> bound the current-vital
/// percentage this row applies at.
/// </summary>
public readonly record struct RechargeHandlerRow(
int Vital,
string HandlerString,
int MinPercent,
int MaxPercent,
int Stance)
{
internal static VitalKind? ToVitalKind(int vital) => vital switch
{
1 => VitalKind.Health,
2 => VitalKind.Stamina,
3 => VitalKind.Mana,
_ => null,
};
internal static int FromVitalKind(VitalKind vital) => vital switch
{
VitalKind.Health => 1,
VitalKind.Stamina => 2,
VitalKind.Mana => 3,
_ => 0,
};
}
/// <summary>
/// VTank's default <c>RechargeHandlerSet</c>, including its stance- and
/// current-percentage-dependent order. The host supplies raw inventory and
@ -60,7 +97,10 @@ internal static class VitalRechargePlanner
vital,
mode == PluginCombatMode.Magic,
percent,
settings.RechargeHandlerSet);
settings.RechargeHandlerSet,
settings.RechargeHandlerRows.Count != 0
? settings.RechargeHandlerRows
: null);
IReadOnlyList<PluginInventoryItem> items =
automation.Items.CaptureOwnedItems();
@ -209,8 +249,20 @@ internal static class VitalRechargePlanner
VitalKind vital,
bool magicMode,
int currentPercent,
string? handlerSet = null)
string? handlerSet = null,
IReadOnlyList<RechargeHandlerRow>? handlerRows = null)
{
if (handlerRows is { Count: > 0 }
&& TryHandlersFromRows(
vital,
magicMode,
currentPercent,
handlerRows,
out VitalRechargeMethod[] fromRows))
{
return fromRows;
}
IReadOnlyList<VitalRechargeMethod> defaults;
if (magicMode)
{
@ -288,6 +340,81 @@ internal static class VitalRechargePlanner
: defaults;
}
/// <summary>
/// VTank's real table-driven handler-order lookup: collect every row
/// matching (Vital, Stance) whose [MinPercent,MaxPercent] band contains
/// the current percentage, IN FILE ORDER (duplicates included — VTank's
/// own shipped table has them, e.g. row 17 of the default table repeats
/// "Recharge With Food" for the non-magic Health band; a duplicate is
/// harmless, since re-trying the same handler a second time just fails
/// identically). Confirmed against every hand-ported default list this
/// planner shipped before this table was parseable — see
/// <c>docs/research/vtank-kb/01-settings-and-profiles.md</c> row 137 and
/// the RechargeHandlerSet fixture. Unknown HandlerString tokens are
/// skipped (forward-compatible with a future VTank build's new method).
/// </summary>
private static bool TryHandlersFromRows(
VitalKind vital,
bool magicMode,
int currentPercent,
IReadOnlyList<RechargeHandlerRow> rows,
out VitalRechargeMethod[] handlers)
{
int vitalCode = RechargeHandlerRow.FromVitalKind(vital);
int stance = magicMode ? 1 : 2;
var matched = new List<VitalRechargeMethod>();
foreach (RechargeHandlerRow row in rows)
{
if (row.Vital != vitalCode
|| row.Stance != stance
|| currentPercent < row.MinPercent
|| currentPercent > row.MaxPercent)
{
continue;
}
if (TryParseHandlerToken(row.HandlerString, out VitalRechargeMethod method))
matched.Add(method);
}
handlers = [.. matched];
return handlers.Length != 0;
}
private static bool TryParseHandlerToken(string source, out VitalRechargeMethod method)
{
string normalized = source.Replace(" ", string.Empty, StringComparison.Ordinal)
.Replace("-", string.Empty, StringComparison.Ordinal)
.ToLowerInvariant();
switch (normalized)
{
case "regularspell":
method = VitalRechargeMethod.RegularSpell;
return true;
case "staminatohealth":
method = VitalRechargeMethod.StaminaToHealth;
return true;
case "manatohealth":
method = VitalRechargeMethod.ManaToHealth;
return true;
case "healthtostamina":
method = VitalRechargeMethod.HealthToStamina;
return true;
case "healthtomana":
method = VitalRechargeMethod.HealthToMana;
return true;
case "kit":
case "kitrecharge":
method = VitalRechargeMethod.Kit;
return true;
case "food":
case "rechargewithfood":
method = VitalRechargeMethod.Food;
return true;
default:
method = default;
return false;
}
}
private static string HandlerContext(
VitalKind vital,
bool magicMode,

View file

@ -418,6 +418,15 @@ internal static class VtankLootRequirementEvaluator
in PluginItemProperties properties)
{
int value = IntValue(key, item, properties);
// VTClassic's ComputedItemInfo.GetBuffedLogValueKey only adds the
// spell bonus if the item already carries the base key at all
// (ComputedItemInfo.cs:205, the KeyExistsInt gate — KB doc 05
// section 2.2 and the section-5 gap-4 finding). Without this gate,
// an item that lacks the key entirely (falls through to the
// zero-defaulted "_ =>" branch below) would still receive a spell
// bonus it never had a base value to buff.
if (!IntKeyExists(key, item, properties))
return value;
foreach (uint spellId in item.AppraisedSpellIds)
{
if (IntSpellBonuses.TryGetValue(spellId, out var bonus)
@ -435,6 +444,8 @@ internal static class VtankLootRequirementEvaluator
in PluginItemProperties properties)
{
double value = DoubleValue(key, item, properties);
if (!DoubleKeyExists(key, item, properties))
return value;
foreach (uint spellId in item.AppraisedSpellIds)
{
if (!DoubleSpellBonuses.TryGetValue(spellId, out var bonus)
@ -447,6 +458,37 @@ internal static class VtankLootRequirementEvaluator
return value;
}
/// <summary>
/// Mirrors <see cref="IntValue"/>'s switch: every named-field key is a
/// concrete <see cref="PluginInventoryItem"/> property and always
/// "exists"; anything else falls through to the raw property-bag
/// lookup, where existence means the bag actually carries that key.
/// </summary>
private static bool IntKeyExists(
uint key,
in PluginInventoryItem item,
in PluginItemProperties properties) => key switch
{
5 or 19 or 105 or 107 or 108 or 131
or VtankIntBase + 0 or VtankIntBase + 2 or VtankIntBase + 4
or VtankIntBase + 5 or VtankIntBase + 6 or VtankIntBase + 7
or VtankIntBase + 8 or VtankIntBase + 9 or VtankIntBase + 10
or VtankIntBase + 11 or VtankIntBase + 14 or VtankIntBase + 18
or VtankIntBase + 23 or VtankIntBase + 31 or VtankIntBase + 32
or VtankIntBase + 33 or VtankIntBase + 34 or VtankIntBase + 38 => true,
_ => properties.Ints?.ContainsKey(key) == true,
};
private static bool DoubleKeyExists(
uint key,
in PluginInventoryItem item,
in PluginItemProperties properties) => key switch
{
VtankDoubleBase + 9 or VtankDoubleBase + 11
or VtankDoubleBase + 12 or VtankDoubleBase + 14 => true,
_ => properties.Floats?.ContainsKey(key) == true,
};
private static double MinimumDamage(in PluginInventoryItem item) =>
item.Damage - (item.DamageVariance * item.Damage);

View file

@ -0,0 +1,547 @@
using System.Globalization;
using AcDream.Plugin.Abstractions;
namespace AcDream.Plugins.MossTank;
/// <summary>
/// Loads/saves VTank's real <c>.usd</c> settings profile (the self-describing
/// <c>gy</c>/<c>bd</c>/<c>y</c> grammar in <see cref="VtankDatabase"/>),
/// mapping every one of the 137 <c>Settings</c> table rows
/// (<see cref="VtankOptionCatalog.Names"/>) onto the live
/// <see cref="CombatSettings"/>/<see cref="BuffSettings"/>/
/// <see cref="VitalSettings"/>/<see cref="InventorySettings"/>/
/// <see cref="NavigationSettings"/> fields by VTank name.
///
/// The value transforms (unit scaling, enum offsets) are the exact ones
/// already verified in <c>MossTankPanel.SetMetaOption</c>/<c>GetMetaOption</c>
/// (<c>MossTankPanel.cs:2442-3377</c>) against the decompiled VTank source
/// per <c>docs/research/vtank-kb/01-settings-and-profiles.md</c> — this
/// class duplicates those transforms rather than calling into
/// <c>MossTankPanel</c> because the panel's methods operate on a live
/// session (chat, expression state) that a file-format serializer must not
/// depend on.
///
/// Every table other than <c>Settings</c> (MyMonsters, GemFoodItems,
/// ExtraBuffSpells, AntiExtraBuffSpells, ItemUseSpecifiers,
/// SettingsCategories, SettingsEnumInfo, AssistItems, BuffedItems, …) is
/// preserved byte-for-byte: <see cref="Save"/> mutates the exact
/// <see cref="VtankDatabase"/> object <see cref="Load"/> returned, and only
/// replaces a <c>Settings</c> row's Value cell when the live setting's
/// current value differs from what was parsed (a value-equality compare,
/// not a text compare, so an untouched profile round-trips byte-for-byte
/// even if VTank's own float formatting differs subtly from ours).
/// </summary>
internal static class VtankSettingsProfileSerializer
{
private const string SettingsTable = "Settings";
internal sealed class AllSettings
{
public required CombatSettings Combat { get; init; }
public required BuffSettings Buffs { get; init; }
public required VitalSettings Vitals { get; init; }
public required InventorySettings Inventory { get; init; }
public required NavigationSettings Navigation { get; init; }
}
/// <summary>
/// Parses <paramref name="text"/> and applies every recognized Settings
/// row onto <paramref name="target"/>. Returns the parsed
/// <see cref="VtankDatabase"/> so a later <see cref="Save"/> can
/// preserve every other table (and every unrecognized Settings row)
/// byte-for-byte. Throws <see cref="FormatException"/> with a
/// <c>line N:</c>-prefixed message on the first structural error.
/// </summary>
public static VtankDatabase Load(string text, AllSettings target)
{
ArgumentNullException.ThrowIfNull(target);
VtankDatabase database = VtankDatabase.Parse(text);
VtankTable? settings = database.Find(SettingsTable);
if (settings is null)
throw new FormatException("missing required 'Settings' table.");
int nameColumn = settings.ColumnIndex("Setting");
int valueColumn = settings.ColumnIndex("Value");
if (nameColumn < 0 || valueColumn < 0)
throw new FormatException("'Settings' table is missing Setting/Value columns.");
foreach (VtankRow row in settings.Rows)
{
string name = row.Cells[nameColumn].AsString();
Apply(name, row.Cells[valueColumn], target);
}
return database;
}
/// <summary>
/// Regenerates the <c>Settings</c> table's Value cells from
/// <paramref name="source"/>'s current values (skipping any row whose
/// value is unchanged from what <paramref name="document"/> already
/// holds) and re-renders the whole database. Every other table, and any
/// Settings row this serializer does not recognize, is untouched.
/// </summary>
public static string Save(VtankDatabase document, AllSettings source)
{
ArgumentNullException.ThrowIfNull(document);
ArgumentNullException.ThrowIfNull(source);
VtankTable? settings = document.Find(SettingsTable);
if (settings is null)
throw new FormatException("missing required 'Settings' table.");
int nameColumn = settings.ColumnIndex("Setting");
int valueColumn = settings.ColumnIndex("Value");
foreach (VtankRow row in settings.Rows)
{
string name = row.Cells[nameColumn].AsString();
VtankCell? captured = Capture(name, source);
if (captured is null)
continue;
VtankCell current = row.Cells[valueColumn];
if (ValuesEqual(current, captured))
continue;
row.Cells[valueColumn] = captured;
}
return document.Render();
}
/// <summary>Builds a brand-new database (Settings table only) seeded from <paramref name="source"/>.</summary>
public static VtankDatabase CreateNew(AllSettings source)
{
var table = new VtankTable();
table.ColumnNames.AddRange(["Setting", "Value", "Description", "SettingType"]);
table.IndexFlags.AddRange([true, false, false, false]);
foreach (string name in VtankOptionCatalog.Names)
{
VtankCell value = Capture(name, source) ?? DefaultCell(name);
var row = new VtankRow();
row.Cells.Add(VtankCell.String(name));
row.Cells.Add(value);
row.Cells.Add(VtankCell.String(string.Empty));
row.Cells.Add(VtankCell.Int(1));
table.Rows.Add(row);
}
var database = new VtankDatabase();
database.Tables.Add((SettingsTable, table));
return database;
}
private static VtankCell DefaultCell(string name)
{
MonsterValue value = VtankOptionCatalog.Default(name);
return value.Kind switch
{
MonsterValueKind.Boolean => VtankCell.Bool(value.Boolean),
MonsterValueKind.Text => VtankCell.String(value.Text),
_ => VtankCell.Double(value.Number),
};
}
private static readonly HashSet<string> NumericTags = ["d", "i", "u", "f"];
/// <summary>
/// Compares by parsed VALUE, not raw tag: a setting's real VTank type
/// (e.g. the Recharge-* percentages are stored as plain <c>i</c> ints
/// in <c>defaultsettings.usd</c>, not <c>d</c> doubles) does not need to
/// be re-derived exactly by <see cref="Capture"/> for an untouched
/// value to round-trip byte-for-byte — any numeric tag comparing equal
/// means <see cref="Save"/> keeps the ORIGINAL cell object untouched.
/// </summary>
private static bool ValuesEqual(VtankCell a, VtankCell b)
{
if (NumericTags.Contains(a.Tag) && NumericTags.Contains(b.Tag))
{
double left = a.AsDouble();
double right = b.AsDouble();
// Several distance settings pass through a float (e.g.
// CombatSettings.MaximumRange) on their way back to a double
// .usd cell; VTank's own (older, 15-16 significant digit)
// double formatting and .NET 10's shortest-round-trippable
// formatting can render the SAME conceptual value with a
// last-digit difference that survives the float<->double
// round trip as a genuinely different double bit pattern.
// A tiny relative tolerance treats that as unchanged so Save()
// keeps VTank's own original cell text rather than needlessly
// reformatting it.
double tolerance = Math.Max(Math.Abs(left), Math.Abs(right)) * 1e-6 + 1e-9;
return Math.Abs(left - right) <= tolerance;
}
if (a.Tag != b.Tag)
return false;
return a.Tag switch
{
"b" => a.AsBool() == b.AsBool(),
"s" => a.AsString() == b.AsString(),
_ => ReferenceEquals(a, b),
};
}
// ------------------------------------------------------------------
// Apply: .usd cell -> live setting.
// ------------------------------------------------------------------
private static void Apply(string rawName, VtankCell cell, AllSettings s)
{
if (!VtankOptionCatalog.IsKnown(rawName))
return;
string name = VtankOptionCatalog.Canonical(rawName).ToLowerInvariant();
CombatSettings c = s.Combat;
BuffSettings b = s.Buffs;
VitalSettings v = s.Vitals;
InventorySettings i = s.Inventory;
NavigationSettings n = s.Navigation;
switch (name)
{
case "enablelooting": i.Loot.Enabled = cell.AsBool(); break;
case "enablenav": n.Enabled = cell.AsBool(); break;
case "enablebuffing": b.Enabled = cell.AsBool(); break;
case "enablecombat": c.Enabled = cell.AsBool(); break;
case "spelldiffexcessthreshold-hunt": c.HuntSkillExcessOverDifficulty = cell.AsInt(); break;
case "spelldiffexcessthreshold-buff": b.SkillExcessOverDifficulty = cell.AsInt(); break;
case "arrowheadfletchdiffexcessthreshold": i.ArrowheadFletchDifficultyExcess = cell.AsInt(); break;
case "recharge-norm-hitp": v.NormalHealth = cell.AsDouble() / 100d; break;
case "recharge-norm-stam": v.NormalStamina = cell.AsDouble() / 100d; break;
case "recharge-norm-mana": v.NormalMana = cell.AsDouble() / 100d; break;
case "recharge-notarg-hitp": v.NoTargetHealth = cell.AsDouble() / 100d; break;
case "recharge-notarg-stam": v.NoTargetStamina = cell.AsDouble() / 100d; break;
case "recharge-notarg-mana": v.NoTargetMana = cell.AsDouble() / 100d; break;
case "recharge-helper-hitp": v.HelperHealth = cell.AsDouble() / 100d; break;
case "recharge-helper-stam": v.HelperStamina = cell.AsDouble() / 100d; break;
case "recharge-helper-mana": v.HelperMana = cell.AsDouble() / 100d; break;
case "dohelp": v.HelpOthers = cell.AsBool(); break;
case "attackdistance": c.MaximumRange = (float)(cell.AsDouble() * 240d); break;
case "attackminimumdistance": c.MinimumRange = (float)(cell.AsDouble() * 240d); break;
case "approachdistance": c.ApproachDistance = (float)(cell.AsDouble() * 240d); break;
case "ringdistance": c.RingDistance = (float)(cell.AsDouble() * 240d); break;
case "corpseapproachrange-max": i.Loot.CorpseApproachRange = (float)(cell.AsDouble() * 240d); break;
case "corpseapproachrange-min": i.Loot.CorpseMinimumApproachRange = (float)(cell.AsDouble() * 240d); break;
case "navclosestoprange": n.MinimumDistanceMeters = cell.AsDouble() * 240d; break;
case "navfarstoprange": n.MaximumDistanceMeters = cell.AsDouble() * 240d; break;
case "useportaldistance": n.PortalUseDistanceMeters = cell.AsDouble() * 240d; break;
case "helperdistancehitp": v.HelperHealthDistance = (float)(cell.AsDouble() * 240d); break;
case "helperdistancestam": v.HelperStaminaDistance = (float)(cell.AsDouble() * 240d); break;
case "helperdistancemana": v.HelperManaDistance = (float)(cell.AsDouble() * 240d); break;
case "minimumringtargets": c.MinimumRingTargets = cell.AsInt(); break;
case "defaultmeleeattackheight": c.AttackHeight = (PluginAttackHeight)cell.AsInt(); break;
case "castdispelself": v.CastDispelSelf = cell.AsBool(); break;
case "usedispelitems": v.UseDispelItems = cell.AsBool(); break;
case "autocram": i.AutoCram = cell.AsBool(); break;
case "autostack": i.AutoStack = cell.AsBool(); break;
case "readunknownscrolls": i.Loot.ReadUnknownScrolls = cell.AsBool(); break;
case "usedispeldrum": v.UseDispelDrum = cell.AsBool(); break;
case "switchwandstodebuff": c.SwitchWandsToDebuff = cell.AsBool(); break;
case "autocraftitems": i.AutoCraftItems = cell.AsBool(); break;
case "usehealersheart": v.UseHealersHeart = cell.AsBool(); break;
case "jumpoutwandcasting": c.JumpOutWandCasting = cell.AsBool(); break;
case "lootallcorpses": i.Loot.LootAllCorpses = cell.AsBool(); break;
case "lootfellowcorpses": i.Loot.LootFellowCorpses = cell.AsBool(); break;
case "dojiggle": c.DoJiggle = cell.AsBool(); break;
case "randomhelperbuffs": b.RandomHelperBuffs = cell.AsBool(); break;
case "randomhelperintervalseconds": b.RandomHelperIntervalSeconds = cell.AsDouble(); break;
case "idlepeacemode": c.IdlePeaceMode = cell.AsBool(); break;
case "targetlock": c.TargetLock = cell.AsBool(); break;
case "stopmacroondeath": c.StopMacroOnDeath = cell.AsBool(); break;
case "usearcs": c.UseArcs = cell.AsInt() != 0; break;
case "arcrange": c.ArcRange = (float)(cell.AsDouble() * 240d); break;
case "targetselectmethod": c.SelectionMethod = (TargetSelectionMethod)(cell.AsInt() - 1); break;
case "targetselectanglerange": c.TargetSelectAngleRange = (float)(cell.AsDouble() * 240d); break;
case "idlebufftopoff": b.IdleBuffTopoff = cell.AsBool(); break;
case "idlebufftopofftimeseconds": b.IdleBuffTopoffSeconds = cell.AsDouble(); break;
case "rebufftimeremainingseconds": b.RebuffWhenUnderSeconds = cell.AsDouble(); break;
case "refillwornmana": i.RefillWornMana = cell.AsBool(); break;
case "refillwornmana-item-manapercent": i.RefillWornManaPercent = cell.AsInt(); break;
case "buffprofile-prots": b.ProtectionElements = cell.AsString(); break;
case "buffprofile-banes": b.BaneElements = cell.AsString(); break;
case "buffprofile_prots": b.ProtectionProfileMode = cell.AsInt(); break;
case "buffprofile_banes": b.BaneProfileMode = cell.AsInt(); break;
case "debuffeachfirst": c.DebuffEachFirst = (DebuffEachFirst)cell.AsInt(); break;
case "autoattackpower": c.AutoAttackPower = cell.AsBool(); break;
case "lootpriorityboost": i.Loot.PriorityBoost = cell.AsBool(); break;
case "corpsecachetimeoutminutes": i.Loot.CorpseCacheTimeoutMinutes = cell.AsDouble(); break;
case "corpseitemappearancetimeoutseconds": i.Loot.CorpseItemAppearanceTimeoutSeconds = cell.AsDouble(); break;
case "corpseitemidtimeoutseconds": i.Loot.CorpseItemIdentifyTimeoutSeconds = cell.AsDouble(); break;
case "debuffselectionmethod": c.DebuffSelectionMethod = (DebuffSelectionMethod)cell.AsInt(); break;
case "manastonelootcount": i.Loot.ManaStoneLootCount = cell.AsInt(); break;
case "manatankminimummana": i.Loot.ManaTankMinimumMana = cell.AsInt(); break;
case "splitpeas": i.SplitPeas = cell.AsBool(); break;
case "spellcompmin-critical": i.CriticalComponentMinimum = cell.AsInt(); break;
case "spellcompmin-normal": i.NormalComponentMinimum = cell.AsInt(); break;
case "spellcompmin-idle": i.IdleComponentMinimum = cell.AsInt(); break;
case "rechargeboosttimeseconds": v.RechargeBoostTimeSeconds = cell.AsDouble(); break;
case "rechargeboostamount": v.RechargeBoostAmount = cell.AsInt(); break;
case "usespecialammo": c.UseSpecialAmmo = cell.AsInt(); break;
case "opendoors": n.OpenDoors = cell.AsBool(); break;
case "dooridrange": n.DoorIdentifyRangeMeters = cell.AsDouble() * 240d; break;
case "dooropenrange": n.DoorOpenRangeMeters = cell.AsDouble() * 240d; break;
case "doorlockpickdiffexcessthreshold": n.DoorLockpickExcessThreshold = cell.AsInt(); break;
case "manachargeswhenoff": i.ManaChargesWhenOff = cell.AsBool(); break;
case "autofellowmanagement": c.AutoFellowManagement = cell.AsBool(); break;
case "minimumhealkitsuccesschance": v.MinimumHealKitSuccessChance = cell.AsInt(); break;
case "usekitsinmagicmode": v.UseKitsInMagicMode = cell.AsBool(); break;
case "staminatohealthmultiplier": v.StaminaToHealthMultiplier = cell.AsDouble(); break;
case "manatohealthmultiplier": v.ManaToHealthMultiplier = cell.AsDouble(); break;
case "navpriorityboost": n.Priority = cell.AsBool(); break;
case "deleteghostmonsters": c.DeleteGhostMonsters = cell.AsBool(); break;
case "ghostmonsterspellattemptcount": c.GhostMonsterSpellAttemptCount = cell.AsInt(); break;
case "whoyougonnacall": c.WhoYouGonnaCall = cell.AsBool(); break;
case "blacklistmonsterattemptcount": c.BlacklistMonsterAttemptCount = cell.AsInt(); break;
case "blacklistmonstertimeoutseconds": c.BlacklistMonsterTimeoutSeconds = cell.AsDouble(); break;
case "combinesalvage": i.Loot.CombineSalvage = cell.AsBool(); break;
case "lootonlyrarecorpses": i.Loot.LootOnlyRareCorpses = cell.AsBool(); break;
case "deleteghostmonstersbyhptracker": c.DeleteGhostMonstersByHealthTracker = cell.AsBool(); break;
case "ghostdeletehptrackerseconds": c.GhostDeleteHealthTrackerSeconds = cell.AsDouble(); break;
case "gotopeacemodetousekits": v.GoToPeaceModeToUseKits = cell.AsBool(); break;
case "userecklessness": c.UseRecklessness = cell.AsBool(); break;
case "debuffprecastseconds": c.DebuffPrecastSeconds = cell.AsDouble(); break;
case "clearlevelboostflagoncast": v.ClearLevelBoostFlagOnCast = cell.AsBool(); break;
case "idlecraftcount_healthkits": i.IdleHealthKitCount = cell.AsInt(); break;
case "idlecraftcount_stamkits": i.IdleStaminaKitCount = cell.AsInt(); break;
case "idlecraftcount_manakits": i.IdleManaKitCount = cell.AsInt(); break;
case "idlecraftcount_healthfood": i.IdleHealthFoodCount = cell.AsInt(); break;
case "idlecraftcount_stamfood": i.IdleStaminaFoodCount = cell.AsInt(); break;
case "idlecraftcount_manafood": i.IdleManaFoodCount = cell.AsInt(); break;
case "buffcastrecast_seconds": b.BuffCastRecastSeconds = cell.AsDouble(); break;
case "buffcastrecastreset_seconds": b.BuffCastRecastResetSeconds = cell.AsDouble(); break;
case "enablemeta": break; // live MetaEngine.Enabled, not a stored settings field.
case "blacklistedspellcomps":
b.BlacklistedSpellComponents = cell.AsString();
c.BlacklistedSpellComponents = cell.AsString();
break;
case "droptopeacemoderetrycount": v.DropToPeaceModeRetryCount = cell.AsInt(); break;
case "followaroundcorners": n.FollowAroundCorners = cell.AsBool(); break;
case "blacklistcorpseopenattemptcount": i.Loot.BlacklistCorpseOpenAttemptCount = cell.AsInt(); break;
case "blacklistcorpseopentimeoutseconds": i.Loot.BlacklistCorpseOpenTimeoutSeconds = cell.AsDouble(); break;
case "summonpets": c.SummonPets = cell.AsBool(); break;
case "petrangemode": c.PetRangeMode = (PetRangeMode)cell.AsInt(); break;
case "petcustomrange": c.PetCustomRange = (float)(cell.AsDouble() * 240d); break;
case "petrefillcount-idle": c.PetRefillCountIdle = cell.AsInt(); break;
case "petrefillcount-normal": c.PetRefillCountNormal = cell.AsInt(); break;
case "corpseopentimeoutseconds": i.Loot.CorpseOpenTimeoutSeconds = cell.AsDouble(); break;
case "petmonsterdensity": c.PetMonsterDensity = cell.AsInt(); break;
case "corpselootitemmaxattempts": i.Loot.CorpseLootItemMaxAttempts = cell.AsInt(); break;
case "fastcastbuffs": b.FastCastBuffs = cell.AsBool(); break;
case "usebreakableturnto": c.UseBreakableTurnTo = cell.AsBool(); break;
case "useprojectileawareness": c.UseProjectileAwareness = cell.AsBool(); break;
case "collisionprojectileradius": c.CollisionProjectileRadius = cell.AsFloat(); break;
case "collisionstepdistance": c.CollisionStepDistance = cell.AsFloat(); break;
case "showcollisiondebug": c.ShowCollisionDebug = cell.AsBool(); break;
case "maximumcollisioncheckspertick": c.MaximumCollisionChecksPerTick = cell.AsInt(); break;
case "spellrangefudge": c.SpellRangeFudge = cell.AsFloat(); break;
case "buffwithuntrained-item": b.BuffWithUntrainedItemSkill = cell.AsInt(); break;
case "buffwithuntrained-creature": b.BuffWithUntrainedCreatureSkill = cell.AsInt(); break;
case "buffwithuntrained-life": b.BuffWithUntrainedLifeSkill = cell.AsInt(); break;
case "allowdebufffallback": c.AllowDebuffFallback = cell.AsBool(); break;
case "rechargehandlerset":
if (cell.Tag == "TABLE" && cell.Table is { } table)
v.RechargeHandlerRows = ParseRechargeHandlerSet(table);
break;
default: break;
}
}
// ------------------------------------------------------------------
// Capture: live setting -> .usd cell. Mirror of Apply above; a name
// Apply ignores (enablemeta, rechargehandlerset) also returns null here
// so Save leaves that row's original cell untouched.
// ------------------------------------------------------------------
/// <summary>Internal (not private) solely so the 137-setting coverage test can call it directly.</summary>
internal static VtankCell? Capture(string rawName, AllSettings s)
{
if (!VtankOptionCatalog.IsKnown(rawName))
return null;
string name = VtankOptionCatalog.Canonical(rawName).ToLowerInvariant();
CombatSettings c = s.Combat;
BuffSettings b = s.Buffs;
VitalSettings v = s.Vitals;
InventorySettings i = s.Inventory;
NavigationSettings n = s.Navigation;
return name switch
{
"enablelooting" => VtankCell.Bool(i.Loot.Enabled),
"enablenav" => VtankCell.Bool(n.Enabled),
"enablebuffing" => VtankCell.Bool(b.Enabled),
"enablecombat" => VtankCell.Bool(c.Enabled),
"spelldiffexcessthreshold-hunt" => VtankCell.Int(c.HuntSkillExcessOverDifficulty),
"spelldiffexcessthreshold-buff" => VtankCell.Int(b.SkillExcessOverDifficulty),
"arrowheadfletchdiffexcessthreshold" => VtankCell.Int(i.ArrowheadFletchDifficultyExcess),
"recharge-norm-hitp" => VtankCell.Double(v.NormalHealth * 100d),
"recharge-norm-stam" => VtankCell.Double(v.NormalStamina * 100d),
"recharge-norm-mana" => VtankCell.Double(v.NormalMana * 100d),
"recharge-notarg-hitp" => VtankCell.Double(v.NoTargetHealth * 100d),
"recharge-notarg-stam" => VtankCell.Double(v.NoTargetStamina * 100d),
"recharge-notarg-mana" => VtankCell.Double(v.NoTargetMana * 100d),
"recharge-helper-hitp" => VtankCell.Double(v.HelperHealth * 100d),
"recharge-helper-stam" => VtankCell.Double(v.HelperStamina * 100d),
"recharge-helper-mana" => VtankCell.Double(v.HelperMana * 100d),
"dohelp" => VtankCell.Bool(v.HelpOthers),
"attackdistance" => VtankCell.Double(c.MaximumRange / 240d),
"attackminimumdistance" => VtankCell.Double(c.MinimumRange / 240d),
"approachdistance" => VtankCell.Double(c.ApproachDistance / 240d),
"ringdistance" => VtankCell.Double(c.RingDistance / 240d),
"corpseapproachrange-max" => VtankCell.Double(i.Loot.CorpseApproachRange / 240d),
"corpseapproachrange-min" => VtankCell.Double(i.Loot.CorpseMinimumApproachRange / 240d),
"navclosestoprange" => VtankCell.Double(n.MinimumDistanceMeters / 240d),
"navfarstoprange" => VtankCell.Double(n.MaximumDistanceMeters / 240d),
"useportaldistance" => VtankCell.Double(n.PortalUseDistanceMeters / 240d),
"helperdistancehitp" => VtankCell.Double(v.HelperHealthDistance / 240d),
"helperdistancestam" => VtankCell.Double(v.HelperStaminaDistance / 240d),
"helperdistancemana" => VtankCell.Double(v.HelperManaDistance / 240d),
"minimumringtargets" => VtankCell.Int(c.MinimumRingTargets),
"defaultmeleeattackheight" => VtankCell.Int((int)c.AttackHeight),
"castdispelself" => VtankCell.Bool(v.CastDispelSelf),
"usedispelitems" => VtankCell.Bool(v.UseDispelItems),
"autocram" => VtankCell.Bool(i.AutoCram),
"autostack" => VtankCell.Bool(i.AutoStack),
"readunknownscrolls" => VtankCell.Bool(i.Loot.ReadUnknownScrolls),
"usedispeldrum" => VtankCell.Bool(v.UseDispelDrum),
"switchwandstodebuff" => VtankCell.Bool(c.SwitchWandsToDebuff),
"autocraftitems" => VtankCell.Bool(i.AutoCraftItems),
"usehealersheart" => VtankCell.Bool(v.UseHealersHeart),
"jumpoutwandcasting" => VtankCell.Bool(c.JumpOutWandCasting),
"lootallcorpses" => VtankCell.Bool(i.Loot.LootAllCorpses),
"lootfellowcorpses" => VtankCell.Bool(i.Loot.LootFellowCorpses),
"dojiggle" => VtankCell.Bool(c.DoJiggle),
"randomhelperbuffs" => VtankCell.Bool(b.RandomHelperBuffs),
"randomhelperintervalseconds" => VtankCell.Double(b.RandomHelperIntervalSeconds),
"idlepeacemode" => VtankCell.Bool(c.IdlePeaceMode),
"targetlock" => VtankCell.Bool(c.TargetLock),
"stopmacroondeath" => VtankCell.Bool(c.StopMacroOnDeath),
"usearcs" => VtankCell.Int(c.UseArcs ? 3 : 1),
"arcrange" => VtankCell.Double(c.ArcRange / 240d),
"targetselectmethod" => VtankCell.Int((int)c.SelectionMethod + 1),
"targetselectanglerange" => VtankCell.Double(c.TargetSelectAngleRange / 240d),
"idlebufftopoff" => VtankCell.Bool(b.IdleBuffTopoff),
"idlebufftopofftimeseconds" => VtankCell.Double(b.IdleBuffTopoffSeconds),
"rebufftimeremainingseconds" => VtankCell.Double(b.RebuffWhenUnderSeconds),
"refillwornmana" => VtankCell.Bool(i.RefillWornMana),
"refillwornmana-item-manapercent" => VtankCell.Int(i.RefillWornManaPercent),
"buffprofile-prots" => VtankCell.String(b.ProtectionElements),
"buffprofile-banes" => VtankCell.String(b.BaneElements),
"buffprofile_prots" => VtankCell.Int(b.ProtectionProfileMode),
"buffprofile_banes" => VtankCell.Int(b.BaneProfileMode),
"debuffeachfirst" => VtankCell.Int((int)c.DebuffEachFirst),
"autoattackpower" => VtankCell.Bool(c.AutoAttackPower),
"lootpriorityboost" => VtankCell.Bool(i.Loot.PriorityBoost),
"corpsecachetimeoutminutes" => VtankCell.Double(i.Loot.CorpseCacheTimeoutMinutes),
"corpseitemappearancetimeoutseconds" => VtankCell.Double(i.Loot.CorpseItemAppearanceTimeoutSeconds),
"corpseitemidtimeoutseconds" => VtankCell.Double(i.Loot.CorpseItemIdentifyTimeoutSeconds),
"debuffselectionmethod" => VtankCell.Int((int)c.DebuffSelectionMethod),
"manastonelootcount" => VtankCell.Int(i.Loot.ManaStoneLootCount),
"manatankminimummana" => VtankCell.Int(i.Loot.ManaTankMinimumMana),
"splitpeas" => VtankCell.Bool(i.SplitPeas),
"spellcompmin-critical" => VtankCell.Int(i.CriticalComponentMinimum),
"spellcompmin-normal" => VtankCell.Int(i.NormalComponentMinimum),
"spellcompmin-idle" => VtankCell.Int(i.IdleComponentMinimum),
"rechargeboosttimeseconds" => VtankCell.Double(v.RechargeBoostTimeSeconds),
"rechargeboostamount" => VtankCell.Int(v.RechargeBoostAmount),
"usespecialammo" => VtankCell.Int(c.UseSpecialAmmo),
"opendoors" => VtankCell.Bool(n.OpenDoors),
"dooridrange" => VtankCell.Double(n.DoorIdentifyRangeMeters / 240d),
"dooropenrange" => VtankCell.Double(n.DoorOpenRangeMeters / 240d),
"doorlockpickdiffexcessthreshold" => VtankCell.Int(n.DoorLockpickExcessThreshold),
"manachargeswhenoff" => VtankCell.Bool(i.ManaChargesWhenOff),
"autofellowmanagement" => VtankCell.Bool(c.AutoFellowManagement),
"minimumhealkitsuccesschance" => VtankCell.Int(v.MinimumHealKitSuccessChance),
"usekitsinmagicmode" => VtankCell.Bool(v.UseKitsInMagicMode),
"staminatohealthmultiplier" => VtankCell.Double(v.StaminaToHealthMultiplier),
"manatohealthmultiplier" => VtankCell.Double(v.ManaToHealthMultiplier),
"navpriorityboost" => VtankCell.Bool(n.Priority),
"deleteghostmonsters" => VtankCell.Bool(c.DeleteGhostMonsters),
"ghostmonsterspellattemptcount" => VtankCell.Int(c.GhostMonsterSpellAttemptCount),
"whoyougonnacall" => VtankCell.Bool(c.WhoYouGonnaCall),
"blacklistmonsterattemptcount" => VtankCell.Int(c.BlacklistMonsterAttemptCount),
"blacklistmonstertimeoutseconds" => VtankCell.Double(c.BlacklistMonsterTimeoutSeconds),
"combinesalvage" => VtankCell.Bool(i.Loot.CombineSalvage),
"lootonlyrarecorpses" => VtankCell.Bool(i.Loot.LootOnlyRareCorpses),
"deleteghostmonstersbyhptracker" => VtankCell.Bool(c.DeleteGhostMonstersByHealthTracker),
"ghostdeletehptrackerseconds" => VtankCell.Double(c.GhostDeleteHealthTrackerSeconds),
"gotopeacemodetousekits" => VtankCell.Bool(v.GoToPeaceModeToUseKits),
"userecklessness" => VtankCell.Bool(c.UseRecklessness),
"debuffprecastseconds" => VtankCell.Double(c.DebuffPrecastSeconds),
"clearlevelboostflagoncast" => VtankCell.Bool(v.ClearLevelBoostFlagOnCast),
"idlecraftcount_healthkits" => VtankCell.Int(i.IdleHealthKitCount),
"idlecraftcount_stamkits" => VtankCell.Int(i.IdleStaminaKitCount),
"idlecraftcount_manakits" => VtankCell.Int(i.IdleManaKitCount),
"idlecraftcount_healthfood" => VtankCell.Int(i.IdleHealthFoodCount),
"idlecraftcount_stamfood" => VtankCell.Int(i.IdleStaminaFoodCount),
"idlecraftcount_manafood" => VtankCell.Int(i.IdleManaFoodCount),
"buffcastrecast_seconds" => VtankCell.Double(b.BuffCastRecastSeconds),
"buffcastrecastreset_seconds" => VtankCell.Double(b.BuffCastRecastResetSeconds),
"blacklistedspellcomps" => VtankCell.String(b.BlacklistedSpellComponents),
"droptopeacemoderetrycount" => VtankCell.Int(v.DropToPeaceModeRetryCount),
"followaroundcorners" => VtankCell.Bool(n.FollowAroundCorners),
"blacklistcorpseopenattemptcount" => VtankCell.Int(i.Loot.BlacklistCorpseOpenAttemptCount),
"blacklistcorpseopentimeoutseconds" => VtankCell.Double(i.Loot.BlacklistCorpseOpenTimeoutSeconds),
"summonpets" => VtankCell.Bool(c.SummonPets),
"petrangemode" => VtankCell.Int((int)c.PetRangeMode),
"petcustomrange" => VtankCell.Double(c.PetCustomRange / 240d),
"petrefillcount-idle" => VtankCell.Int(c.PetRefillCountIdle),
"petrefillcount-normal" => VtankCell.Int(c.PetRefillCountNormal),
"corpseopentimeoutseconds" => VtankCell.Double(i.Loot.CorpseOpenTimeoutSeconds),
"petmonsterdensity" => VtankCell.Int(c.PetMonsterDensity),
"corpselootitemmaxattempts" => VtankCell.Int(i.Loot.CorpseLootItemMaxAttempts),
"fastcastbuffs" => VtankCell.Bool(b.FastCastBuffs),
"usebreakableturnto" => VtankCell.Bool(c.UseBreakableTurnTo),
"useprojectileawareness" => VtankCell.Bool(c.UseProjectileAwareness),
"collisionprojectileradius" => VtankCell.Float(c.CollisionProjectileRadius),
"collisionstepdistance" => VtankCell.Float(c.CollisionStepDistance),
"showcollisiondebug" => VtankCell.Bool(c.ShowCollisionDebug),
"maximumcollisioncheckspertick" => VtankCell.Int(c.MaximumCollisionChecksPerTick),
"spellrangefudge" => VtankCell.Float(c.SpellRangeFudge),
"buffwithuntrained-item" => VtankCell.Int(b.BuffWithUntrainedItemSkill),
"buffwithuntrained-creature" => VtankCell.Int(b.BuffWithUntrainedCreatureSkill),
"buffwithuntrained-life" => VtankCell.Int(b.BuffWithUntrainedLifeSkill),
"allowdebufffallback" => VtankCell.Bool(c.AllowDebuffFallback),
_ => null, // "enablemeta" (live engine state) and "rechargehandlerset"
// (no write path exists in real VTank either, section 2 row 137)
// are deliberately left untouched.
};
}
/// <summary>
/// Parses the RechargeHandlerSet nested TABLE (5 columns:
/// Vital/HandlerString/MinPercent/MaxPercent/Stance — verified against
/// the live <c>defaultsettings.usd</c> fixture, 26 rows).
/// </summary>
internal static RechargeHandlerRow[] ParseRechargeHandlerSet(VtankTable table)
{
int vitalColumn = table.ColumnIndex("Vital");
int handlerColumn = table.ColumnIndex("HandlerString");
int minColumn = table.ColumnIndex("MinPercent");
int maxColumn = table.ColumnIndex("MaxPercent");
int stanceColumn = table.ColumnIndex("Stance");
if (vitalColumn < 0 || handlerColumn < 0 || minColumn < 0
|| maxColumn < 0 || stanceColumn < 0)
{
return [];
}
var rows = new RechargeHandlerRow[table.Rows.Count];
for (int i = 0; i < table.Rows.Count; i++)
{
VtankRow row = table.Rows[i];
rows[i] = new RechargeHandlerRow(
row.Cells[vitalColumn].AsInt(),
row.Cells[handlerColumn].AsString(),
row.Cells[minColumn].AsInt(),
row.Cells[maxColumn].AsInt(),
row.Cells[stanceColumn].AsInt());
}
return rows;
}
internal static VtankTable RenderRechargeHandlerSet(IReadOnlyList<RechargeHandlerRow> rows)
{
var table = new VtankTable();
table.ColumnNames.AddRange(["Vital", "HandlerString", "MinPercent", "MaxPercent", "Stance"]);
table.IndexFlags.AddRange([false, false, false, false, false]);
foreach (RechargeHandlerRow row in rows)
{
var vtankRow = new VtankRow();
vtankRow.Cells.Add(VtankCell.Int(row.Vital));
vtankRow.Cells.Add(VtankCell.String(row.HandlerString));
vtankRow.Cells.Add(VtankCell.Int(row.MinPercent));
vtankRow.Cells.Add(VtankCell.Int(row.MaxPercent));
vtankRow.Cells.Add(VtankCell.Int(row.Stance));
table.Rows.Add(vtankRow);
}
return table;
}
}

View file

@ -0,0 +1,354 @@
using System.Globalization;
using System.Text;
namespace AcDream.Plugins.MossTank;
/// <summary>
/// The self-describing recursive text-database grammar VTank uses for
/// <c>.usd</c> settings profiles and <c>.ast</c> per-character caches. Ported
/// from the decompiled <c>gy</c>/<c>cw</c>/<c>bd</c>/<c>y</c> classes
/// documented in <c>docs/research/vtank-kb/01-settings-and-profiles.md</c>
/// section 1: <c>refs/vtank/decompiled/gy.cs:20-56</c> (typed cell),
/// <c>cw.cs:9-40</c> (row), <c>bd.cs:364-395</c> (table), <c>y.cs:87-104</c>
/// (whole database). Plain text, CRLF line endings, no compression, no
/// checksum, no top-level version header.
///
/// One cell (<c>gy</c>) is a type-tag line followed by zero or more value
/// lines: <c>d</c>=double, <c>i</c>=int, <c>u</c>=uint, <c>f</c>=float,
/// <c>s</c>=string (the raw next line, possibly empty), <c>b</c>=bool
/// (<c>"True"</c>/<c>"False"</c>), <c>TABLE</c>=a nested table (recurse into
/// <see cref="VtankTable"/>), <c>ba</c>=a length-prefixed raw-character blob
/// (an int line for the character count, then that many raw characters,
/// not lines, so embedded newlines survive). Any other tag is preserved
/// verbatim as an opaque single-line scalar so an unrecognized custom type
/// still round-trips byte-for-byte.
/// </summary>
internal sealed class VtankCell
{
internal VtankCell() { }
/// <summary>The raw type tag: <c>d</c>/<c>i</c>/<c>u</c>/<c>f</c>/<c>s</c>/<c>b</c>/<c>TABLE</c>/<c>ba</c>/other.</summary>
public required string Tag { get; init; }
/// <summary>Raw text of the single value line, for every scalar tag except <c>ba</c>.</summary>
public string? ScalarText { get; set; }
/// <summary>The nested table payload, only when <see cref="Tag"/> is <c>TABLE</c>.</summary>
public VtankTable? Table { get; set; }
/// <summary>The raw character blob, only when <see cref="Tag"/> is <c>ba</c>.</summary>
public string? BlobText { get; set; }
public static VtankCell Double(double value) => new()
{
Tag = "d",
ScalarText = FormatDouble(value),
};
public static VtankCell Int(int value) => new()
{
Tag = "i",
ScalarText = value.ToString(CultureInfo.InvariantCulture),
};
public static VtankCell UInt(uint value) => new()
{
Tag = "u",
ScalarText = value.ToString(CultureInfo.InvariantCulture),
};
public static VtankCell Float(float value) => new()
{
Tag = "f",
ScalarText = FormatDouble(value),
};
public static VtankCell String(string value) => new()
{
Tag = "s",
ScalarText = value,
};
public static VtankCell Bool(bool value) => new()
{
Tag = "b",
ScalarText = value ? "True" : "False",
};
public static VtankCell NestedTable(VtankTable table) => new()
{
Tag = "TABLE",
Table = table,
};
public double AsDouble() => double.Parse(
ScalarText ?? "0",
NumberStyles.Float,
CultureInfo.InvariantCulture);
public int AsInt() => int.Parse(
ScalarText ?? "0",
NumberStyles.Integer,
CultureInfo.InvariantCulture);
public uint AsUInt() => uint.Parse(
ScalarText ?? "0",
NumberStyles.Integer,
CultureInfo.InvariantCulture);
public float AsFloat() => float.Parse(
ScalarText ?? "0",
NumberStyles.Float,
CultureInfo.InvariantCulture);
public string AsString() => ScalarText ?? string.Empty;
/// <summary>
/// VTank's <c>gy</c> bool tag stores the literal text <c>"True"</c> or
/// <c>"False"</c> (C#'s default <see cref="bool"/> formatting).
/// </summary>
public bool AsBool() => string.Equals(ScalarText, "True", StringComparison.Ordinal);
/// <summary>
/// Formats a double/float the way VTank's own build does: .NET's
/// invariant-culture round-trippable <c>ToString()</c>. Verified against
/// real fixture values (e.g. 5/240 renders as
/// <c>0.0208333333333333</c>, matching <c>defaultsettings.usd</c>).
/// </summary>
internal static string FormatDouble(double value) =>
value.ToString(CultureInfo.InvariantCulture);
internal void WriteTo(List<string> lines)
{
lines.Add(Tag);
switch (Tag)
{
case "TABLE":
Table!.WriteTo(lines);
break;
case "ba":
string blob = BlobText ?? string.Empty;
lines.Add(blob.Length.ToString(CultureInfo.InvariantCulture));
AppendBlobLines(lines, blob);
break;
default:
lines.Add(ScalarText ?? string.Empty);
break;
}
}
// "ba" blobs are a raw character count, not a line count: the blob may
// contain embedded newlines. FileLines (this reader) is line-oriented,
// so a blob is folded back into whole lines for storage and the reader
// re-joins with the writer's own newline so the character count is
// reproduced exactly on save.
private static void AppendBlobLines(List<string> lines, string blob)
{
foreach (string part in blob.Split('\n'))
lines.Add(part.EndsWith('\r') ? part[..^1] : part);
}
}
internal sealed class VtankRow
{
public List<VtankCell> Cells { get; } = [];
internal void WriteTo(List<string> lines)
{
foreach (VtankCell cell in Cells)
cell.WriteTo(lines);
}
}
/// <summary>
/// One <c>bd</c> table: a column-name list, a hash-index flag per column,
/// and a row list. Row length is NOT fixed at parse time — a <c>TABLE</c> or
/// <c>ba</c> cell recurses, so the reader must walk cell-by-cell rather than
/// assume a fixed line stride per row (<c>bd.cs:364-395</c>).
/// </summary>
internal sealed class VtankTable
{
public List<string> ColumnNames { get; } = [];
public List<bool> IndexFlags { get; } = [];
public List<VtankRow> Rows { get; } = [];
public int ColumnIndex(string name) => ColumnNames.FindIndex(
column => column.Equals(name, StringComparison.Ordinal));
internal static VtankTable Read(VtankLineCursor cursor)
{
var table = new VtankTable();
int columnCount = cursor.ReadInt();
for (int i = 0; i < columnCount; i++)
table.ColumnNames.Add(cursor.ReadLine());
for (int i = 0; i < columnCount; i++)
table.IndexFlags.Add(cursor.ReadLine() == "y");
int rowCount = cursor.ReadInt();
for (int r = 0; r < rowCount; r++)
{
var row = new VtankRow();
for (int c = 0; c < columnCount; c++)
row.Cells.Add(VtankDatabaseReader.ReadCell(cursor));
table.Rows.Add(row);
}
return table;
}
internal void WriteTo(List<string> lines)
{
lines.Add(ColumnNames.Count.ToString(CultureInfo.InvariantCulture));
foreach (string column in ColumnNames)
lines.Add(column);
foreach (bool flag in IndexFlags)
lines.Add(flag ? "y" : "n");
lines.Add(Rows.Count.ToString(CultureInfo.InvariantCulture));
foreach (VtankRow row in Rows)
row.WriteTo(lines);
}
}
/// <summary>The whole <c>y</c> database: an ordered set of named tables.</summary>
internal sealed class VtankDatabase
{
public List<(string Name, VtankTable Table)> Tables { get; } = [];
public VtankTable? Find(string name) => Tables
.Where(entry => entry.Name.Equals(name, StringComparison.Ordinal))
.Select(static entry => entry.Table)
.FirstOrDefault();
public static VtankDatabase Parse(string text)
{
var cursor = new VtankLineCursor(text);
var database = new VtankDatabase();
int tableCount = cursor.ReadInt();
for (int i = 0; i < tableCount; i++)
{
string name = cursor.ReadLine();
VtankTable table = VtankTable.Read(cursor);
database.Tables.Add((name, table));
}
return database;
}
public string Render()
{
var lines = new List<string>
{
Tables.Count.ToString(CultureInfo.InvariantCulture),
};
foreach ((string name, VtankTable table) in Tables)
{
lines.Add(name);
table.WriteTo(lines);
}
var builder = new StringBuilder();
foreach (string line in lines)
builder.Append(line).Append("\r\n");
return builder.ToString();
}
}
/// <summary>Reads one <see cref="VtankCell"/>, recursing into nested tables and blobs.</summary>
internal static class VtankDatabaseReader
{
public static VtankCell ReadCell(VtankLineCursor cursor)
{
string tag = cursor.ReadLine();
switch (tag)
{
case "TABLE":
return VtankCell.NestedTable(VtankTable.Read(cursor));
case "ba":
int length = cursor.ReadInt();
return new VtankCellBuilder(tag) { BlobText = cursor.ReadBlob(length) }
.Build();
default:
return new VtankCellBuilder(tag) { ScalarText = cursor.ReadLine() }.Build();
}
}
// Small builder so VtankCell's constructor can stay private to the file
// (its public factory methods are the intended typed-construction path)
// while the reader still needs to synthesize an arbitrary/unknown tag.
private readonly struct VtankCellBuilder(string tag)
{
public string? ScalarText { get; init; }
public string? BlobText { get; init; }
public VtankCell Build() => VtankCellFactory.Create(tag, ScalarText, BlobText);
}
}
/// <summary>Internal factory seam so the reader can build cells with an arbitrary tag.</summary>
internal static class VtankCellFactory
{
public static VtankCell Create(string tag, string? scalarText, string? blobText) => new()
{
Tag = tag,
ScalarText = scalarText,
BlobText = blobText,
};
}
/// <summary>
/// Line cursor over the CRLF-or-LF text of a <c>.usd</c>/<c>.ast</c> file.
/// VTank's own reader is a strict token stream (<c>StreamReader.ReadLine()</c>
/// calls in a fixed order) — there is no way to resynchronize after a parse
/// error, so every read here throws immediately with a file:line-shaped
/// message on the first unexpected token.
/// </summary>
internal sealed class VtankLineCursor
{
private readonly string[] _lines;
private int _index;
public VtankLineCursor(string text)
{
ArgumentNullException.ThrowIfNull(text);
_lines = text.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n');
}
public int LineNumber => _index + 1;
public string ReadLine()
{
if (_index >= _lines.Length)
{
throw new FormatException(
$"line {LineNumber}: unexpected end of file (expected another line).");
}
return _lines[_index++];
}
public int ReadInt()
{
string line = ReadLine();
if (!int.TryParse(line, NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
{
throw new FormatException(
$"line {LineNumber - 1}: expected an integer, got '{line}'.");
}
return value;
}
/// <summary>
/// Reads a <c>ba</c> blob's exact character count, re-joining folded
/// lines with <c>\n</c> until the count is satisfied (the writer folds
/// on <c>\n</c> too, so this round-trips the exact character count VTank
/// itself would report for embedded newlines).
/// </summary>
public string ReadBlob(int length)
{
if (length <= 0)
return string.Empty;
var builder = new StringBuilder(length);
while (builder.Length < length)
{
if (builder.Length > 0)
builder.Append('\n');
builder.Append(ReadLine());
}
return builder.ToString(0, length);
}
}

View file

@ -24,4 +24,7 @@
Link="mosstank.xml"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<None Include="Fixtures\vtank\**\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,559 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {Default} ~~ {
IF: Always
DO: DestroyAllViews
IF: Always
DO: CreateView {main} {<?xml version="1.0"?><view width="370" height="200" title="XP Augmentation Categories"><control type="layout"><control type="button" name="btnBurdenPackSlots" left="10" top="10" width="170" height="15" text="Burden and Pack Slots" setstate="stateBurdenPackSlots" /><control type="button" name="btnDeathPenalties" left="10" top="40" width="170" height="15" text="Death Penalties" setstate="stateDeathPenalties" /><control type="button" name="btnExperienceBonus" left="10" top="70" width="170" height="15" text="Experience Bonus" setstate="stateExperienceBonus" /><control type="button" name="btnHealthArmorRegen" left="10" top="100" width="170" height="15" text="Health, Armor, and Regeneration" setstate="stateHealthArmorRegen" /><control type="button" name="btnInnateAttribute" left="10" top="130" width="170" height="15" text="Innate Attribute" setstate="stateInnateAttribute" /><control type="button" name="btnStipend" left="10" top="160" width="170" height="15" text="Stipend" setstate="stateStipend" /><control type="button" name="btnInnateResistance" left="190" top="10" width="170" height="15" text="Innate Resistance" setstate="stateInnateResistance" /><control type="button" name="btnRating" left="190" top="40" width="170" height="15" text="Rating" setstate="stateRatings" /><control type="button" name="btnSalvagingTinkering" left="190" top="70" width="170" height="15" text="Salvaging and Tinkering" setstate="stateSalvagingTinkering" /><control type="button" name="btnSkills" left="190" top="100" width="170" height="15" text="Skills" setstate="stateSkills" /><control type="button" name="btnSpellDuration" left="190" top="130" width="170" height="15" text="Spell Duration" setstate="stateSpellDuration" /><control type="button" name="btnBella" left="190" top="160" width="170" height="15" text="Bella" setstate="stateBella" /></control></view>}
~~ }
STATE: {dummy} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {state} {}
~~ }
STATE: {stateBurdenPackSlots} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateBurdenPackSlots} {<?xml version="1.0"?><view width="300" height="260" title="Burden and Pack Slots"><control type="layout"><control type="button" name="btnMightSeventhMule" left="10" top="10" width="250" height="25" text="Might of the Seventh Mule" actionexpr="setvar[Augment,`stateMightSeventhMule`]" setstate="nav_zaikhal" /><control type="button" name="btnShadowSeventhMule" left="10" top="40" width="250" height="25" text="Shadow of the Seventh Mule" actionexpr="setvar[Augment,`stateShadowSeventhMule`]" setstate="nav_zaikhal" /><control type="button" name="btnInfusedWarMagic" left="10" top="70" width="250" height="25" text="Infused War Magic" actionexpr="setvar[Augment,`stateInfusedWarMagic`]" setstate="nav_silyun" /><control type="button" name="btnInfusedLifeMagic" left="10" top="100" width="250" height="25" text="Infused Life Magic" actionexpr="setvar[Augment,`stateInfusedLifeMagic`]" setstate="nav_hebianto" /><control type="button" name="btnInfusedItemMagic" left="10" top="130" width="250" height="25" text="Infused Item Magic" actionexpr="setvar[Augment,`stateInfusedItemMagic`]" setstate="nav_hebianto" /><control type="button" name="btnInfusedCreatureMagic" left="10" top="160" width="250" height="25" text="Infused Creature Magic" actionexpr="setvar[Augment,`stateInfusedCreatureMagic`]" setstate="nav_cragstone" /><control type="button" name="btnInfusedVoidMagic" left="10" top="190" width="250" height="25" text="Infused Void Magic" actionexpr="setvar[Augment,`stateInfusedVoidMagic`]" setstate="nav_candeth" /><control type="button" name="btnMain" left="10" top="220" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateDeathPenalties} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateDeathPenalties} {<?xml version="1.0"?><view width="300" height="110" title="Death Penalties"><control type="layout"><control type="button" name="btnClutchMiser" left="10" top="10" width="250" height="25" text="Clutch of the Miser" actionexpr="setvar[Augment,`stateClutchMiser`]" setstate="nav_ab" /><control type="button" name="btnEnduringEnchantment" left="10" top="40" width="250" height="25" text="Enduring Enchantment" actionexpr="setvar[Augment,`stateEnduringEnchantment`]" setstate="nav_ab" /><control type="button" name="btnMain" left="10" top="70" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateExperienceBonus} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateExperienceBonus} {<?xml version="1.0"?><view width="300" height="110" title="Experience Bonus"><control type="layout"><control type="button" name="btnQuickLearner" left="10" top="10" width="250" height="25" text="Quick Learner" actionexpr="setvar[Augment,`stateQuickLearner`]" setstate="nav_silyun" /><control type="button" name="btnMain" left="10" top="40" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateHealthArmorRegen} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateHealthArmorRegen} {<?xml version="1.0"?><view width="300" height="110" title="Health, Armor, and Regeneration"><control type="layout"><control type="button" name="btnAsheronsLesserBenediction" left="10" top="10" width="250" height="25" text="Asheron's Lesser Benediction" actionexpr="setvar[Augment,`stateAsheronsLesserBenediction`]" setstate="nav_silyun" /><control type="button" name="btnInnateRenewal" left="10" top="40" width="250" height="25" text="Innate Renewal" actionexpr="setvar[Augment,`stateInnateRenewal`]" setstate="nav_bandit" /><control type="button" name="btnMain" left="10" top="70" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateInnateAttribute} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateInnateAttribute} {<?xml version="1.0"?><view width="300" height="220" title="Innate Attribute"><control type="layout"><control type="button" name="btnReinforcementLugians" left="10" top="10" width="250" height="25" text="Reinforcement of the Lugians" actionexpr="setvar[Augment,`stateReinforcementLugians`]" setstate="nav_fiun" /><control type="button" name="btnBleearghFortitude" left="10" top="40" width="250" height="25" text="Bleeargh's Fortitude" actionexpr="setvar[Augment,`stateBleearghFortitude`]" setstate="nav_fiun" /><control type="button" name="btnOswaldEnhancement" left="10" top="70" width="250" height="25" text="Oswald's Enhancement" actionexpr="setvar[Augment,`stateOswaldEnhancement`]" setstate="nav_fiun" /><control type="button" name="btnSiraluunBlessing" left="10" top="100" width="250" height="25" text="Siraluun's Blessing" actionexpr="setvar[Augment,`stateSiraluunBlessing`]" setstate="nav_fiun" /><control type="button" name="btnEnduringCalm" left="10" top="130" width="250" height="25" text="Enduring Calm" actionexpr="setvar[Augment,`stateEnduringCalm`]" setstate="nav_fiun" /><control type="button" name="btnSteadfastWill" left="10" top="160" width="250" height="25" text="Steadfast Will" actionexpr="setvar[Augment,`stateSteadfastWill`]" setstate="nav_fiun" /><control type="button" name="btnMain" left="10" top="190" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateInnateResistance} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateInnateResistance} {<?xml version="1.0"?><view width="300" height="250" title="Innate Resistance"><control type="layout"><control type="button" name="btnEnhancementMaceTurner" left="10" top="10" width="250" height="25" text="Enhancement of the Mace Turner" actionexpr="setvar[Augment,`stateEnhancementMaceTurner`]" setstate="nav_hebianto" /><control type="button" name="btnEnhancementBladeTurner" left="10" top="40" width="250" height="25" text="Enhancement of the Blade Turner" actionexpr="setvar[Augment,`stateEnhancementBladeTurner`]" setstate="nav_hebianto" /><control type="button" name="btnEnhancementArrowTurner" left="10" top="70" width="250" height="25" text="Enhancement of the Arrow Turner" actionexpr="setvar[Augment,`stateEnhancementArrowTurner`]" setstate="nav_hebianto" /><control type="button" name="btnStormEnhancement" left="10" top="100" width="250" height="25" text="Storm's Enhancement" actionexpr="setvar[Augment,`stateStormEnhancement`]" setstate="nav_hebianto" /><control type="button" name="btnFieryEnhancement" left="10" top="130" width="250" height="25" text="Fiery Enhancement" actionexpr="setvar[Augment,`stateFieryEnhancement`]" setstate="nav_hebianto" /><control type="button" name="btnIcyEnhancement" left="10" top="160" width="250" height="25" text="Icy Enhancement" actionexpr="setvar[Augment,`stateIcyEnhancement`]" setstate="nav_hebianto" /><control type="button" name="btnCausticEnhancement" left="10" top="190" width="250" height="25" text="Caustic Enhancement" actionexpr="setvar[Augment,`stateCausticEnhancement`]" setstate="nav_hebianto" /><control type="button" name="btnMain" left="10" top="220" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateRatings} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateRatings} {<?xml version="1.0"?><view width="300" height="180" title="Ratings"><control type="layout"><control type="button" name="btnCriticalProtection" left="10" top="10" width="250" height="25" text="Critical Protection" actionexpr="setvar[Augment,`stateCriticalProtection`]" setstate="nav_sanamar" /><control type="button" name="btnFrenzySlayer" left="10" top="40" width="250" height="25" text="Frenzy of the Slayer" actionexpr="setvar[Augment,`stateFrenzySlayer`]" setstate="nav_bandit" /><control type="button" name="btnIronSkin" left="10" top="70" width="250" height="25" text="Iron Skin of the Invincible" actionexpr="setvar[Augment,`stateIronSkin`]" setstate="nav_cragstone" /><control type="button" name="btnEyeRemorseless" left="10" top="100" width="250" height="25" text="Eye of the Remorseless" actionexpr="setvar[Augment,`stateEyeRemorseless`]" setstate="nav_ab" /><control type="button" name="btnHandRemorseless" left="10" top="130" width="250" height="25" text="Hand of the Remorseless" actionexpr="setvar[Augment,`stateHandRemorseless`]" setstate="nav_ab" /><control type="button" name="btnMain" left="10" top="160" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateSalvagingTinkering} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateSalvagingTinkering} {<?xml version="1.0"?><view width="300" height="310" title="Salvaging and Tinkering"><control type="layout"><control type="button" name="btnCiandrasFortune" left="10" top="10" width="250" height="25" text="Ciandra's Fortune" actionexpr="setvar[Augment,`stateCiandrasFortune`]" setstate="nav_cragstone" /><control type="button" name="btnCharmedSmith" left="10" top="40" width="250" height="25" text="Charmed Smith" actionexpr="setvar[Augment,`stateCharmedSmith`]" setstate="nav_oolutangasrefuge" /><control type="button" name="btnJibrilsEssence" left="10" top="70" width="250" height="25" text="Jibril's Essence" actionexpr="setvar[Augment,`stateJibrilsEssence`]" setstate="nav_cragstone" /><control type="button" name="btnYoshisEssence" left="10" top="100" width="250" height="25" text="Yoshi's Essence" actionexpr="setvar[Augment,`stateYoshisEssence`]" setstate="nav_cragstone" /><control type="button" name="btnCeldisethsEssence" left="10" top="130" width="250" height="25" text="Celdiseth's Essence" actionexpr="setvar[Augment,`stateCeldisethsEssence`]" setstate="nav_cragstone" /><control type="button" name="btnKogasEssence" left="10" top="160" width="250" height="25" text="Koga's Essence" actionexpr="setvar[Augment,`stateKogasEssence`]" setstate="nav_cragstone" /><control type="button" name="btnCiandrasEssence" left="10" top="190" width="250" height="25" text="Ciandra's Essence" actionexpr="setvar[Augment,`stateCiandrasEssence`]" setstate="nav_cragstone" /><control type="button" name="btnMain" left="10" top="220" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateSkills} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateSkills} {<?xml version="1.0"?><view width="300" height="180" title="Skills"><control type="layout"><control type="button" name="btnMasterSteelCircle" left="10" top="10" width="250" height="25" text="Master of the Steel Circle" actionexpr="setvar[Augment,`stateMasterSteelCircle`]" setstate="nav_silyun" /><control type="button" name="btnMasterFiveFoldPath" left="10" top="40" width="250" height="25" text="Master of the Five Fold Path" actionexpr="setvar[Augment,`stateMasterFiveFoldPath`]" setstate="nav_zaikhal" /><control type="button" name="btnMasterFocusedEye" left="10" top="70" width="250" height="25" text="Master of the Focused Eye" actionexpr="setvar[Augment,`stateMasterFocusedEye`]" setstate="nav_zaikhal" /><control type="button" name="btnJackTrades" left="10" top="100" width="250" height="25" text="Jack of All Trades" actionexpr="setvar[Augment,`stateJackTrades`]" setstate="nav_bandit" /><control type="button" name="btnMain" left="10" top="130" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateSpellDuration} ~~ {
IF: Always
DO: DoAll
DestroyView {main}
IF: Always
DO: CreateView {stateSpellDuration} {<?xml version="1.0"?><view width="300" height="110" title="Spell Duration"><control type="layout"><control type="button" name="btnArchmageEndurance" left="10" top="10" width="250" height="25" text="Archmage's Endurance" actionexpr="setvar[Augment,`stateArchmageEndurance`]" setstate="nav_mayoi" /><control type="button" name="btnMain" left="10" top="40" width="250" height="25" text="Main" setstate="Default" /></control></view>}
~~ }
STATE: {stateMightSeventhMule} ~~ {
IF: Always
DO: Chat {/vt nav load nav_husoon}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateShadowSeventhMule} ~~ {
IF: Always
DO: Chat {/vt nav load nav_dumidabintruminre}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInfusedWarMagic} ~~ {
IF: Always
DO: Chat {/vt nav load nav_rapheldetante}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateArchmageEndurance} ~~ {
IF: Always
DO: Chat {/vt nav load nav_nawamaraujio}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInfusedLifeMagic} ~~ {
IF: Always
DO: Chat {/vt nav load nav_akemifei}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInfusedItemMagic} ~~ {
IF: Always
DO: Chat {/vt nav load nav_ganfo}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInfusedCreatureMagic} ~~ {
IF: Always
DO: Chat {/vt nav load nav_gustuvlansdown}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInfusedVoidMagic} ~~ {
IF: Always
DO: Chat {/vt nav load nav_morathe}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateClutchMiser} ~~ {
IF: Always
DO: Chat {/vt nav load nav_rohulabintludun}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEnduringEnchantment} ~~ {
IF: Always
DO: Chat {/vt nav load nav_erikfestus}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateQuickLearner} ~~ {
IF: Always
DO: Chat {/vt nav load nav_rickarddumalia}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateAsheronsLesserBenediction} ~~ {
IF: Always
DO: Chat {/vt nav load nav_donatellolinante}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateInnateRenewal} ~~ {
IF: Always
DO: Chat {/vt nav load nav_alisondulane}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateReinforcementLugians} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunluunere}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateBleearghFortitude} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunruun}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateOswaldEnhancement} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunbayaas}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateSiraluunBlessing} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunriish}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEnduringCalm} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunvasherr}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateSteadfastWill} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiunnoress}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateCriticalProtection} ~~ {
IF: Always
DO: Chat {/vt nav load nav_piersantilinante}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateFrenzySlayer} ~~ {
IF: Always
DO: Chat {/vt nav load nav_neelanashua}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateIronSkin} ~~ {
IF: Always
DO: Chat {/vt nav load nav_emilyyarow}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEyeRemorseless} ~~ {
IF: Always
DO: Chat {/vt nav load nav_anframmellow}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateHandRemorseless} ~~ {
IF: Always
DO: Chat {/vt nav load nav_alishiabintaldan}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEnhancementMaceTurner} ~~ {
IF: Always
DO: Chat {/vt nav load nav_nawamaradia}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEnhancementBladeTurner} ~~ {
IF: Always
DO: Chat {/vt nav load nav_ilinwis}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateEnhancementArrowTurner} ~~ {
IF: Always
DO: Chat {/vt nav load nav_kyujorujen}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateStormEnhancement} ~~ {
IF: Always
DO: Chat {/vt nav load nav_enliyuo}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateFieryEnhancement} ~~ {
IF: Always
DO: Chat {/vt nav load nav_rikshenri}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateIcyEnhancement} ~~ {
IF: Always
DO: Chat {/vt nav load nav_lubao}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateCausticEnhancement} ~~ {
IF: Always
DO: Chat {/vt nav load nav_shujiomilao}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {nav_zaikhal} ~~ {
IF: Always
DO: Chat {/vt nav load nav_zaikhal}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_fiun} ~~ {
IF: Always
DO: Chat {/vt nav load nav_fiun}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {stateCiandrasFortune} ~~ {
IF: Always
DO: Chat {/vt nav load nav_kriscennis}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateCharmedSmith} ~~ {
IF: Always
DO: Chat {/vt nav load nav_lug}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateJibrilsEssence} ~~ {
IF: Always
DO: Chat {/vt nav load nav_joshunfelden}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateYoshisEssence} ~~ {
IF: Always
DO: Chat {/vt nav load nav_briennecarlus}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateCeldisethsEssence} ~~ {
IF: Always
DO: Chat {/vt nav load nav_burrellsammrun}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateKogasEssence} ~~ {
IF: Always
DO: Chat {/vt nav load nav_lenorturk}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateCiandrasEssence} ~~ {
IF: Always
DO: Chat {/vt nav load nav_robertcrow}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateMasterSteelCircle} ~~ {
IF: Always
DO: Chat {/vt nav load nav_carlitogallo}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateMasterFiveFoldPath} ~~ {
IF: Always
DO: Chat {/vt nav load nav_rahinabintzalanis}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateMasterFocusedEye} ~~ {
IF: Always
DO: Chat {/vt nav load nav_kilaf}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {stateJackTrades} ~~ {
IF: Always
DO: Chat {/vt nav load nav_ariannatheadept}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {nav_silyun} ~~ {
IF: Always
DO: Chat {/vt nav load nav_silyun}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_hebianto} ~~ {
IF: Always
DO: Chat {/vt nav load nav_hebianto}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_cragstone} ~~ {
IF: Always
DO: Chat {/vt nav load nav_cragstone}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_oolutangasrefuge} ~~ {
IF: Always
DO: Chat {/vt nav load nav_oolutangasrefuge}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_ab} ~~ {
IF: Always
DO: Chat {/vt nav load nav_ab}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_bandit} ~~ {
IF: Always
DO: Chat {/vt nav load nav_bandit}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_sanamar} ~~ {
IF: Always
DO: Chat {/vt nav load nav_sanamar}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_candeth} ~~ {
IF: Always
DO: Chat {/vt nav load nav_candeth}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {nav_mayoi} ~~ {
IF: Always
DO: Chat {/vt nav load nav_mayoi}
IF: Always
DO: DestroyAllViews
IF: NavEmpty
DO: DoExpr {chatbox[\/vt setmetastate +getvar[Augment]]}
~~ }
STATE: {stateBella} ~~ {
IF: Always
DO: DoAll
DoExpr {echo[`OK RUNNING BELLA`,13]}
DestroyView {main}
IF: ExitPortal
DO: SetState {mp_primary}
IF: Always
DO: Chat {/mp}
~~ }
STATE: {jaw_hunt} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav true}
SetState {turn_in_jaw}
IF: ItemCountGE 1 {Insatiable Eater Jaw}
DO: DoAll
Chat {/vt nav load to_fiun}
~~ }
STATE: {jaw_run} ~~ {
IF: NavEmpty
DO: DoAll
Chat {/vt nav load jaw_1_hunt}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
SetState {jaw_hunt}
~~ }
STATE: {kill_bella} ~~ {
IF: ItemCountGE 1 {Blank Augmentation Gem}
DO: DoAll
Chat {/vt nav load recallls}
Chat {/vt opt set enablelooting false}
SetState {Default}
~~ }
STATE: {mp_primary} ~~ {
IF: Always
DO: DoAll
Chat {/vt nav load mp_primary}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set NavPriorityBoost false}
Chat {/vt opt set navclosestoprange 0.008}
IF: ExitPortal
DO: DoAll
Chat {/vt nav load jaw_1}
SetState {jaw_run}
~~ }
STATE: {mp_secondary} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt nav load to_bella}
SetState {kill_bella}
~~ }
STATE: {mp_trans} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt nav load mp_secondary}
SetState {mp_secondary}
~~ }
STATE: {turn_in_jaw} ~~ {
IF: ChatMatch {^Fiun Rehlyun.*}
DO: DoAll
Chat {/mp}
SetState {mp_trans}
~~ }
STATE: {stateStipend} ~~ {
IF: Always
DO: DoAll
DoExpr {echo[`OK RUNNING STIPEND`,13]}
DestroyView {main}
Chat {/vt opt set enablenav true}
IF: Always
DO: EmbedNav nav0__stipend_nav {stipend.nav}
IF: NavEmpty
DO: SetState {Default}
~~ }
~~========================= ONLY NAVS APPEAR BELOW THIS LINE =========================~~
NAV: nav0__stipend_nav once ~~ {
cht -101.597905190786 -96.6216093699137 2.08333134651184E-05 {/ah}
pnt 59.3590666453044 -28.7057823816935 0.0500208298365275
pnt 59.3771680514018 -28.7152192115784 0.0500208298365275
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 59.3936458587647 -28.7256083488464 0.0508250035345554 14 {Portal to Town Network}
pnt -101.615851815542 -96.6388638178507 2.08333134651184E-05
pnt -101.657751337687 -96.5832635879517 2.08333134651184E-05
pnt -101.658352184296 -96.5325949986776 2.08333134651184E-05
pnt -101.605949529012 -96.519695186615 2.08333134651184E-05
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 -101.588099161784 -96.5166525046031 -0.000262499845121056 14 {Portal to Arwic}
pnt 56.6498762130737 33.416518386205 0.175020837783813
pnt 56.655900033315 33.5368880271912 0.175020837783813
pnt 56.7470087051392 33.5495386441549 0.175020837783813
pnt 56.7795230229696 33.6337207794189 0.175020837783813
tlk -101.597905190786 -96.6216093699137 2.08333134651184E-05 56.7816291809082 33.6455291748047 0.175020843744278 37 {Monroe}
~~ }

View file

@ -0,0 +1,101 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {Default} ~~ {
IF: ExitPortal
DO: SetState {mp_primary}
IF: Always
DO: Chat {/mp}
~~ }
STATE: {jaw_hunt} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav true}
SetState {turn_in_jaw}
IF: ItemCountGE 1 {Insatiable Eater Jaw}
DO: DoAll
Chat {/vt nav load to_fiun}
~~ }
STATE: {jaw_run} ~~ {
IF: NavEmpty
DO: DoAll
Chat {/vt nav load jaw_1_hunt}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
SetState {jaw_hunt}
~~ }
STATE: {kill_bella} ~~ {
IF: ChatCapture {You have solved this quest too recently!} {}
DO: DoAll
Chat {/vt nav load recallls}
Chat {/vt opt set enablelooting false}
~~ }
STATE: {mp_primary} ~~ {
IF: Always
DO: DoAll
Chat {/vt nav load mp_primary}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set NavPriorityBoost false}
Chat {/vt opt set navclosestoprange 0.008}
IF: ExitPortal
DO: DoAll
Chat {/vt nav load jaw_1}
SetState {jaw_run}
~~ }
STATE: {mp_secondary} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt nav load to_bella}
SetState {kill_bella}
~~ }
STATE: {mp_trans} ~~ {
IF: ExitPortal
DO: DoAll
Chat {/vt nav load mp_secondary}
SetState {mp_secondary}
~~ }
STATE: {turn_in_jaw} ~~ {
IF: ChatMatch {^Fiun Rehlyun.*}
DO: DoAll
Chat {/mp}
SetState {mp_trans}
~~ }

View file

@ -0,0 +1,964 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
~~ /ub mexec setvar[navNumber,VILKETNUMMER]
STATE: {combat} ~~ {
IF: Always
DO: Chat {/vt opt set enablecombat true}
IF: SecsInStateGE 60
DO: SetState {ring_fail}
IF: NoMobsInDist 5
DO: SetState {hunt}
~~ }
STATE: {death} ~~ {
IF: Always
DO: Chat {/vt nav load death_pause}
IF: Always
DO: Chat {/vt opt set enablenav true}
IF: NavEmpty
DO: SetState {navbore}
~~ }
STATE: {hunt} ~~ {
IF: Always
DO: Chat {/vt opt set enablecombat false}
IF: Expr {getvar[lootTime] == 0}
DO: DoExpr {setvar[lootTime, 21600]}
IF: Not Expr {testvar[serviceCheckInterval]}
DO: DoExpr {setvar[serviceCheckInterval, 43200]}
IF: Not Expr {testvar[serviceClock]}
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
IF: Death
DO: DoAll
Chat {/a I died! But I will comeback!}
SetState {death}
IF: All
ItemCountLE 100 {Prismatic Taper}
NoMobsInDist 5
DO: DoAll
Chat {/a Out of tapers! Recomping.}
SetState {recomp}
IF: MainSlotsLE 4
DO: DoAll
Chat {/a Out of inventory slots! Recomping.}
SetState {recomp}
IF: All
Expr {getvar[serviceCheckInterval] > 0}
Expr {stopwatchelapsedseconds[getvar[serviceClock]]>=getvar[serviceCheckInterval]}
NoMobsInDist 5
DO: SetState {service_quest_refresh}
IF: Always
DO: SetWatchdog 3 120 {navbore}
IF: DistToRteGE 1000
DO: SetState {navbore}
IF: All
Expr {setvar[nearPortal, wobjectfindnearestbyobjectclass[14]]}
Expr {istrue[getvar[nearPortal]]}
Expr {coordinatedistancewithz[getplayercoordinates[], wobjectgetphysicscoordinates[getvar[nearPortal]]]<=4}
Not Expr {wobjectgetname[getvar[nearPortal]]==Singularity Caul}
DO: DoAll
ChatExpr {\/me is to close to +wobjectgetname[getvar[nearPortal]]}
ChatExpr {\/me at +coordinatetostring[getplayercoordinates[]]}
IF: All
Any
Expr {getvar[mobsClose] == 0}
Expr {getvar[mobsClose] == 1}
MobsInDist_Name 1 6 {}
DO: SetState {combat}
IF: All
Expr {getvar[mobsClose] == 2}
MobsInDist_Name 2 6 {}
DO: SetState {combat}
IF: All
Expr {stopwatchelapsedseconds[getvar[lootclock]]>getvar[lootTime]}
DO: DoAll
Chat {/vt opt set enablecombat true}
SetState {loot}
IF: All
Expr {setvar[portal, wobjectfindnearestbyobjectclass[14]]}
Expr {istrue[getvar[portal]]}
Expr {coordinatedistancewithz[getplayercoordinates[], wobjectgetphysicscoordinates[getvar[portal]]] <= 8}
Not Expr {wobjectgetname[getvar[portal]]==Singularity Caul}
Not Expr {wobjectgetname[getvar[portal]]#Destroyed.*}
Expr {wobjectisvalid[getvar[portal]]}
Expr {setvar[portalHeading, getheadingto[getvar[portal]]]}
Expr {setvar[playerHeading, getheading[wobjectgetplayer[]]]}
Expr {setvar[relativeAngle, abs[getvar[portalHeading] - getvar[playerHeading]]]}
Expr {setvar[relativeAngle, iif[getvar[relativeAngle] > 180, 360 - getvar[relativeAngle], getvar[relativeAngle]]]}
Expr {setvar[turnDirection, iif[randint[0,2] == 0, -90, 90]]}
Expr {getvar[relativeAngle] <= 11.25}
Expr {setvar[newHeading, abs[getvar[playerHeading] + getvar[turnDirection]]]}
DO: DoAll
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablecombat false}
SetState {avoid_portal}
~~ }
STATE: {loot_rare} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablelooting true}
Chat {/vt opt set enablenav false}
IF: SecsInStateGE 30
DO: DoAll
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
SetState {hunt}
~~ }
STATE: {Default} ~~ {
IF: Not Expr {testvar[portalAvoidAngle]}
DO: DoExpr {setvar[portalAvoidAngle, 11.25]}
IF: Not Expr {testvar[augInnateStrengthTarget]}
DO: DoExpr {setvar[augInnateStrengthTarget, 0]}
IF: Not Expr {testvar[augInnateEnduranceTarget]}
DO: DoExpr {setvar[augInnateEnduranceTarget, 0]}
IF: Not Expr {testvar[augInnateCoordinationTarget]}
DO: DoExpr {setvar[augInnateCoordinationTarget, 0]}
IF: Not Expr {testvar[augInnateQuicknessTarget]}
DO: DoExpr {setvar[augInnateQuicknessTarget, 0]}
IF: Not Expr {testvar[augInnateFocusTarget]}
DO: DoExpr {setvar[augInnateFocusTarget, 0]}
IF: Not Expr {testvar[augInnateSelfTarget]}
DO: DoExpr {setvar[augInnateSelfTarget, 0]}
IF: Not Expr {testvar[augResistBluntTarget]}
DO: DoExpr {setvar[augResistBluntTarget, 0]}
IF: Not Expr {testvar[augResistSlashTarget]}
DO: DoExpr {setvar[augResistSlashTarget, 0]}
IF: Not Expr {testvar[augResistPierceTarget]}
DO: DoExpr {setvar[augResistPierceTarget, 0]}
IF: Not Expr {testvar[augResistLightningTarget]}
DO: DoExpr {setvar[augResistLightningTarget, 0]}
IF: Not Expr {testvar[augResistFireTarget]}
DO: DoExpr {setvar[augResistFireTarget, 0]}
IF: Not Expr {testvar[augResistFrostTarget]}
DO: DoExpr {setvar[augResistFrostTarget, 0]}
IF: Not Expr {testvar[augResistAcidTarget]}
DO: DoExpr {setvar[augResistAcidTarget, 0]}
IF: Not Expr {testvar[disableAugmentServices]}
DO: DoExpr {setvar[disableAugmentServices, 0]}
IF: Not Expr {testvar[serviceCheckInterval]}
DO: DoExpr {setvar[serviceCheckInterval, 43200]}
IF: Not Expr {testvar[serviceClock]}
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
IF: Always
DO: DoAll
Chat {/ub opt set VTank.PatchExpressionEngine true}
Chat {/vt opt set autocram true}
ChatExpr {\/vt nav load bore_circuit+getvar[navNumber]}
Chat {/vt opt set enablenav true}
Chat {/vt opt set buffprofile_prots 2}
Chat {/vt opt set buffprofile_banes 5}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set navpriorityboost false}
Chat {/vt opt set lootpriorityboost true}
Chat {/vt opt set lootonlyrarecorpses true}
DoExpr {setvar[lootclock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[lootclock]]}
SetState {service_quest_refresh}
~~ }
STATE: {service_quest_refresh} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/myquests}
DoExpr {touchvar[questsRequested]}
IF: All
Expr {testvar[questsRequested]}
Expr {isrefreshingquests[]==0}
SecsInStateGE 2
DO: SetState {service_pending_eval}
IF: SecsInStateGE 8
DO: SetState {service_pending_eval}
~~ }
STATE: {service_pending_eval} ~~ {
IF: Always
DO: DoAll
DoExpr {setvar[pendingAugments,0]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[230]<5,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[229]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[297]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[296]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[295]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[294]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[328]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[231]<3,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[232]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[234]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[237]<2,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[238]<5,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateStrengthTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[218]<getvar[augInnateStrengthTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateEnduranceTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[219]<getvar[augInnateEnduranceTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateCoordinationTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[220]<getvar[augInnateCoordinationTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateQuicknessTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[221]<getvar[augInnateQuicknessTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateFocusTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[222]<getvar[augInnateFocusTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augInnateSelfTarget]>0,iif[getcharintprop[217]<10,iif[getcharintprop[223]<getvar[augInnateSelfTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistBluntTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[242]<getvar[augResistBluntTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistSlashTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[240]<getvar[augResistSlashTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistPierceTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[241]<getvar[augResistPierceTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistLightningTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[246]<getvar[augResistLightningTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistFireTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[244]<getvar[augResistFireTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistFrostTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[245]<getvar[augResistFrostTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getvar[augResistAcidTarget]>0,iif[getcharintprop[239]<2,iif[getcharintprop[243]<getvar[augResistAcidTarget],1,getvar[pendingAugments]],getvar[pendingAugments]],getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[233]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[309]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[310]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[298]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[299]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[235]<4,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[236]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[226]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[225]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[227]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[228]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[224]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[300]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[302]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[301]<1,1,getvar[pendingAugments]]]}
DoExpr {setvar[pendingAugments, iif[getcharintprop[326]<1,1,getvar[pendingAugments]]]}
SetState {service_decide}
~~ }
STATE: {service_decide} ~~ {
IF: All
Expr {getqueststatus[`stipendtimer_0812`]==1}
DO: SetState {service_stipend}
IF: All
Expr {getvar[disableAugmentServices]!=1}
ItemCountGE 1 {Blank Augmentation Gem}
Expr {getvar[pendingAugments]==1}
DO: SetState {service_apply_augment}
IF: All
Expr {getvar[disableAugmentServices]!=1}
Expr {getqueststatus[`augmentationblankgemacquired`]==1}
Expr {getvar[pendingAugments]==1}
DO: SetState {service_bella_start}
IF: Always
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
SetState {hunt}
~~ }
STATE: {service_stipend} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
DoExpr {touchvar[stipendNavLoaded]}
EmbedNav nav0__stipend_nav {stipend.nav}
IF: All
Expr {testvar[stipendNavLoaded]}
NavEmpty
SecsInStateGE 2
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_start} ~~ {
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: SetState {service_bella_mp_primary}
IF: Always
DO: Chat {/mp}
IF: SecsInStateGE 120
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_mp_primary} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/vt nav load mp_primary}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set NavPriorityBoost false}
Chat {/vt opt set navclosestoprange 0.008}
IF: ExitPortal
DO: DoAll
Chat {/vt nav load jaw_1}
SetState {service_bella_jaw_run}
IF: SecsInStateGE 300
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_jaw_run} ~~ {
IF: Death
DO: SetState {death}
IF: NavEmpty
DO: DoAll
Chat {/vt nav load jaw_1_hunt}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
Chat {/vt opt set lootonlyrarecorpses false}
SetState {service_bella_jaw_hunt}
IF: SecsInStateGE 300
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_jaw_hunt} ~~ {
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav true}
SetState {service_bella_turn_in_jaw}
IF: ItemCountGE 1 {Insatiable Eater Jaw}
DO: DoAll
Chat {/vt nav load to_fiun}
IF: SecsInStateGE 1200
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_turn_in_jaw} ~~ {
IF: Death
DO: SetState {death}
IF: ChatMatch {^Fiun Rehlyun.*}
DO: DoAll
Chat {/mp}
SetState {service_bella_mp_trans}
IF: SecsInStateGE 300
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_mp_trans} ~~ {
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: DoAll
Chat {/vt nav load mp_secondary}
SetState {service_bella_mp_secondary}
IF: SecsInStateGE 120
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_mp_secondary} ~~ {
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablecombat true}
Chat {/vt nav load to_bella}
SetState {service_bella_kill_bella}
IF: SecsInStateGE 300
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_kill_bella} ~~ {
IF: Death
DO: SetState {death}
IF: ItemCountGE 1 {Blank Augmentation Gem}
DO: DoAll
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablecombat false}
SetState {service_bella_escape}
IF: SecsInStateGE 300
DO: SetState {service_reset_main}
~~ }
STATE: {service_bella_escape} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablecombat false}
IF: Always
DO: SetWatchdog 3 120 {service_reset_main}
IF: SecsInStateGE 1
DO: ChatExpr {\/ub setmotion forward 1}
IF: SecsInStateGE 4
DO: ChatExpr {\/ub setmotion forward 0}
IF: SecsInStateGE 6
DO: Chat {/vt opt set enablecombat false}
IF: SecsInStateGE 7
DO: Chat {/ah}
IF: SecsInStateGE 17
DO: SetState {service_apply_augment}
~~ }
STATE: {service_apply_augment} ~~ {
IF: Death
DO: SetState {death}
IF: ItemCountLE 0 {Blank Augmentation Gem}
DO: SetState {service_reset_main}
IF: Always
DO: DoAll
DoExpr {clearvar[augmentHub]}
DoExpr {clearvar[augmentHubLoaded]}
DoExpr {clearvar[augmentTargetLoaded]}
DoExpr {setvar[augmentStep,0]}
IF: Expr {getcharintprop[230]<5}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_husoon`]}
DoExpr {setvar[augmentItem,`Might of the Seventh Mule`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[229]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_dumidabintruminre`]}
DoExpr {setvar[augmentItem,`Shadow of the Seventh Mule`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[297]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_rapheldetante`]}
DoExpr {setvar[augmentItem,`Infused War Magic`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[296]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_akemifei`]}
DoExpr {setvar[augmentItem,`Infused Life Magic`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[295]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_ganfo`]}
DoExpr {setvar[augmentItem,`Infused Item Magic`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[294]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_gustuvlansdown`]}
DoExpr {setvar[augmentItem,`Infused Creature Magic`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[328]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_morathe`]}
DoExpr {setvar[augmentItem,`Infused Void Magic`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[231]<3}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_rohulabintludun`]}
DoExpr {setvar[augmentItem,`Clutch of the Miser`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[232]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_erikfestus`]}
DoExpr {setvar[augmentItem,`Enduring Enchantment`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[234]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_rickarddumalia`]}
DoExpr {setvar[augmentItem,`Quick Learner`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[237]<2}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_alisondulane`]}
DoExpr {setvar[augmentItem,`Innate Renewal`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[238]<5}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_nawamaraujio`]}
DoExpr {setvar[augmentItem,`Archmage's Endurance`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateStrengthTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[218]<getvar[augInnateStrengthTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunluunere`]}
DoExpr {setvar[augmentItem,`Reinforcement of the Lugians`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateEnduranceTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[219]<getvar[augInnateEnduranceTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunruun`]}
DoExpr {setvar[augmentItem,`Bleeargh's Fortitude`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateCoordinationTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[220]<getvar[augInnateCoordinationTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunbayaas`]}
DoExpr {setvar[augmentItem,`Oswald's Enhancement`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateQuicknessTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[221]<getvar[augInnateQuicknessTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunriish`]}
DoExpr {setvar[augmentItem,`Siraluun's Blessing`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateFocusTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[222]<getvar[augInnateFocusTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunvasherr`]}
DoExpr {setvar[augmentItem,`Enduring Calm`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augInnateSelfTarget]>0}
Expr {getcharintprop[217]<10}
Expr {getcharintprop[223]<getvar[augInnateSelfTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_fiunnoress`]}
DoExpr {setvar[augmentItem,`Steadfast Will`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistBluntTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[242]<getvar[augResistBluntTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_nawamaradia`]}
DoExpr {setvar[augmentItem,`Enhancement of the Mace Turner`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistSlashTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[240]<getvar[augResistSlashTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_ilinwis`]}
DoExpr {setvar[augmentItem,`Enhancement of the Blade Turner`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistPierceTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[241]<getvar[augResistPierceTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_kyujorujen`]}
DoExpr {setvar[augmentItem,`Enhancement of the Arrow Turner`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistLightningTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[246]<getvar[augResistLightningTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_enliyuo`]}
DoExpr {setvar[augmentItem,`Storm's Enhancement`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistFireTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[244]<getvar[augResistFireTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_rikshenri`]}
DoExpr {setvar[augmentItem,`Fiery Enhancement`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistFrostTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[245]<getvar[augResistFrostTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_lubao`]}
DoExpr {setvar[augmentItem,`Icy Enhancement`]}
SetState {service_apply_augment_nav}
IF: All
Expr {getvar[augResistAcidTarget]>0}
Expr {getcharintprop[239]<2}
Expr {getcharintprop[243]<getvar[augResistAcidTarget]}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_shujiomilao`]}
DoExpr {setvar[augmentItem,`Caustic Enhancement`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[233]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_piersantilinante`]}
DoExpr {setvar[augmentItem,`Critical Protection`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[309]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_neelanashua`]}
DoExpr {setvar[augmentItem,`Frenzy of the Slayer`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[310]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_emilyyarow`]}
DoExpr {setvar[augmentItem,`Iron Skin of the Invincible`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[298]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_anframmellow`]}
DoExpr {setvar[augmentItem,`Eye of the Remorseless`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[299]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_alishiabintaldan`]}
DoExpr {setvar[augmentItem,`Hand of the Remorseless`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[235]<4}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_kriscennis`]}
DoExpr {setvar[augmentItem,`Ciandra's Fortune`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[236]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_lug`]}
DoExpr {setvar[augmentItem,`Charmed Smith`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[226]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_joshunfelden`]}
DoExpr {setvar[augmentItem,`Jibril's Essence`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[225]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_briennecarlus`]}
DoExpr {setvar[augmentItem,`Yoshi's Essence`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[227]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_burrellsammrun`]}
DoExpr {setvar[augmentItem,`Celdiseth's Essence`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[228]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_lenorturk`]}
DoExpr {setvar[augmentItem,`Koga's Essence`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[224]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_robertcrow`]}
DoExpr {setvar[augmentItem,`Ciandra's Essence`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[300]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_carlitogallo`]}
DoExpr {setvar[augmentItem,`Master of the Steel Circle`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[302]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_rahinabintzalanis`]}
DoExpr {setvar[augmentItem,`Master of the Five Fold Path`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[301]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_kilaf`]}
DoExpr {setvar[augmentItem,`Master of the Focused Eye`]}
SetState {service_apply_augment_nav}
IF: Expr {getcharintprop[326]<1}
DO: DoAll
DoExpr {setvar[augmentNav,`nav_ariannatheadept`]}
DoExpr {setvar[augmentItem,`Jack of All Trades`]}
SetState {service_apply_augment_nav}
IF: Always
DO: SetState {service_reset_main}
~~ }
STATE: {service_apply_augment_nav} ~~ {
IF: Death
DO: SetState {death}
IF: Not Expr {testvar[augmentStep]}
DO: DoExpr {setvar[augmentStep,0]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_husoon`}
Expr {getvar[augmentNav]==`nav_dumidabintruminre`}
Expr {getvar[augmentNav]==`nav_rahinabintzalanis`}
Expr {getvar[augmentNav]==`nav_kilaf`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_zaikhal`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_rapheldetante`}
Expr {getvar[augmentNav]==`nav_rickarddumalia`}
Expr {getvar[augmentNav]==`nav_carlitogallo`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_silyun`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_akemifei`}
Expr {getvar[augmentNav]==`nav_ganfo`}
Expr {getvar[augmentNav]==`nav_nawamaradia`}
Expr {getvar[augmentNav]==`nav_ilinwis`}
Expr {getvar[augmentNav]==`nav_kyujorujen`}
Expr {getvar[augmentNav]==`nav_enliyuo`}
Expr {getvar[augmentNav]==`nav_rikshenri`}
Expr {getvar[augmentNav]==`nav_lubao`}
Expr {getvar[augmentNav]==`nav_shujiomilao`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_hebianto`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_gustuvlansdown`}
Expr {getvar[augmentNav]==`nav_emilyyarow`}
Expr {getvar[augmentNav]==`nav_kriscennis`}
Expr {getvar[augmentNav]==`nav_joshunfelden`}
Expr {getvar[augmentNav]==`nav_briennecarlus`}
Expr {getvar[augmentNav]==`nav_burrellsammrun`}
Expr {getvar[augmentNav]==`nav_lenorturk`}
Expr {getvar[augmentNav]==`nav_robertcrow`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_cragstone`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_rohulabintludun`}
Expr {getvar[augmentNav]==`nav_erikfestus`}
Expr {getvar[augmentNav]==`nav_anframmellow`}
Expr {getvar[augmentNav]==`nav_alishiabintaldan`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_ab`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_alisondulane`}
Expr {getvar[augmentNav]==`nav_neelanashua`}
Expr {getvar[augmentNav]==`nav_ariannatheadept`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_bandit`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Any
Expr {getvar[augmentNav]==`nav_fiunluunere`}
Expr {getvar[augmentNav]==`nav_fiunruun`}
Expr {getvar[augmentNav]==`nav_fiunbayaas`}
Expr {getvar[augmentNav]==`nav_fiunriish`}
Expr {getvar[augmentNav]==`nav_fiunvasherr`}
Expr {getvar[augmentNav]==`nav_fiunnoress`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_fiun`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Expr {getvar[augmentNav]==`nav_piersantilinante`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_sanamar`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Expr {getvar[augmentNav]==`nav_lug`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_oolutangasrefuge`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Expr {getvar[augmentNav]==`nav_nawamaraujio`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_mayoi`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==0}
Expr {getvar[augmentNav]==`nav_morathe`}
DO: DoAll
DoExpr {setvar[augmentHub,`nav_candeth`]}
DoExpr {setvar[augmentStep,1]}
IF: All
Expr {getvar[augmentStep]==1}
Expr {testvar[augmentHub]}
Not Expr {testvar[augmentHubLoaded]}
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablebuffing true}
DoExpr {touchvar[augmentHubLoaded]}
ChatExpr {\/vt nav load +getvar[augmentHub]}
Chat {/vt opt set enablenav true}
IF: All
Expr {getvar[augmentStep]==1}
Expr {testvar[augmentHubLoaded]}
NavEmpty
SecsInStateGE 2
DO: DoExpr {setvar[augmentStep,2]}
IF: All
Expr {getvar[augmentStep]==2}
Not Expr {testvar[augmentTargetLoaded]}
DO: DoAll
DoExpr {touchvar[augmentTargetLoaded]}
ChatExpr {\/vt nav load +getvar[augmentNav]}
Chat {/vt opt set enablenav true}
DoExpr {setvar[augmentStep,3]}
IF: All
Expr {getvar[augmentStep]==3}
Expr {testvar[augmentTargetLoaded]}
NavEmpty
SecsInStateGE 2
DO: SetState {service_use_augment}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main}
~~ }
STATE: {service_use_augment} ~~ {
IF: Death
DO: SetState {death}
IF: Not Expr {testvar[augmentItem]}
DO: SetState {service_reset_main}
IF: Always
DO: SetWatchdog 3 120 {service_reset_main}
IF: SecsInStateGE 3
DO: Chat {/ub prepclick yes 10}
IF: SecsInStateGE 7
DO: ChatExpr {\/ub use +getvar[augmentItem]}
IF: SecsInStateGE 15
DO: SetState {service_reset_main}
~~ }
STATE: {service_reset_main} ~~ {
IF: Always
DO: DoAll
DoExpr {clearvar[questsRequested]}
DoExpr {clearvar[stipendNavLoaded]}
DoExpr {clearvar[augmentNav]}
DoExpr {clearvar[augmentHub]}
DoExpr {clearvar[augmentHubLoaded]}
DoExpr {clearvar[augmentTargetLoaded]}
DoExpr {clearvar[augmentStep]}
DoExpr {clearvar[augmentItem]}
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
SetState {Default}
~~ }
STATE: {avoid_portal} ~~ {
IF: SecsInStateGE 1
DO: ChatExpr {\/me portalHeading \= +getvar[portalHeading]}
IF: SecsInStateGE 2
DO: ChatExpr {\/me playerHeading \= +getvar[playerHeading]}
IF: SecsInStateGE 3
DO: ChatExpr {\/me relativeAngle \= +getvar[relativeAngle]}
IF: SecsInStateGE 4
DO: ChatExpr {\/me Portal detected ahead\! Avoiding now\!}
IF: SecsInStateGE 5
DO: ChatExpr {\/me is too close to +wobjectgetname[wobjectfindnearestbyobjectclass[14]]}
IF: SecsInStateGE 6
DO: ChatExpr {\/me at +coordinatetostring[getplayercoordinates[]]}
IF: SecsInStateGE 7
DO: ChatExpr {\/ub face +getvar[newHeading]}
IF: SecsInStateGE 9
DO: ChatExpr {\/ub setmotion forward 1}
IF: SecsInStateGE 11
DO: ChatExpr {\/ub setmotion forward 0}
IF: SecsInStateGE 12
DO: ChatExpr {\/ub face +getvar[playerHeading]}
IF: SecsInStateGE 14
DO: ChatExpr {\/ub setmotion forward 1}
IF: SecsInStateGE 16
DO: ChatExpr {\/ub setmotion forward 0}
IF: SecsInStateGE 17
DO: ChatExpr {\/mm nextwp}
IF: SecsInStateGE 18
DO: ChatExpr {\/vt opt set enablenav true}
IF: SecsInStateGE 19
DO: ChatExpr {\/vt setmetastate hunt}
~~ }
STATE: {navbore} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set lootonlyrarecorpses true}
IF: Always
DO: ChatExpr {\/vt nav load bore_route+getvar[navNumber]}
IF: Always
DO: Chat {/vt opt set enablebuffing true}
IF: Always
DO: SetWatchdog 3 300 {navbore}
IF: NavEmpty
DO: DoAll
ChatExpr {\/vt nav load bore_circuit+getvar[navNumber]}
SetState {hunt}
~~ }
STATE: {recomp} ~~ {
IF: NavEmpty
DO: SetState {navbore}
IF: Always
DO: SetWatchdog 3 300 {navbore}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablebuffing false}
Chat {/vt nav load ah_rarecomp}
~~ }
STATE: {ring_fail} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
SetWatchdog 100 3 {hunt}
~~ }
STATE: {loot} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablelooting true}
Chat {/vt opt set lootonlyrarecorpses false}
Chat {/vt opt set lootpriorityboost false}
IF: SecsInStateGE 300
DO: DoAll
Chat {/vt opt set lootonlyrarecorpses true}
Chat {/vt opt set lootpriorityboost true}
Chat {/vt opt set enablelooting false}
DoExpr {setvar[lootclock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[lootclock]]}
SetState {hunt}
IF: All
Expr {setvar[portal, wobjectfindnearestbyobjectclass[14]]}
Expr {istrue[getvar[portal]]}
Expr {coordinatedistancewithz[getplayercoordinates[], wobjectgetphysicscoordinates[getvar[portal]]] <= 8}
Not Expr {wobjectgetname[getvar[portal]]==Singularity Caul}
Not Expr {wobjectgetname[getvar[portal]]#Destroyed.*}
Expr {wobjectisvalid[getvar[portal]]}
Expr {setvar[portalHeading, getheadingto[getvar[portal]]]}
Expr {setvar[playerHeading, getheading[wobjectgetplayer[]]]}
Expr {setvar[relativeAngle, abs[getvar[portalHeading] - getvar[playerHeading]]]}
Expr {setvar[relativeAngle, iif[getvar[relativeAngle] > 180, 360 - getvar[relativeAngle], getvar[relativeAngle]]]}
Expr {setvar[turnDirection, iif[randint[0,2] == 0, -90, 90]]}
Expr {getvar[relativeAngle] <= 11.25}
Expr {setvar[newHeading, abs[getvar[playerHeading] + getvar[turnDirection]]]}
DO: DoAll
Chat {/vt opt set enablenav false}
Chat {/vt opt set lootonlyrarecorpses true}
Chat {/vt opt set lootpriorityboost true}
Chat {/vt opt set enablelooting false}
DoExpr {setvar[lootclock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[lootclock]]}
SetState {avoid_portal}
~~ }
~~========================= ONLY NAVS APPEAR BELOW THIS LINE =========================~~
NAV: nav0__stipend_nav once ~~ {
cht -101.597905190786 -96.6216093699137 2.08333134651184E-05 {/ah}
pnt 59.3590666453044 -28.7057823816935 0.0500208298365275
pnt 59.3771680514018 -28.7152192115784 0.0500208298365275
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 59.3936458587647 -28.7256083488464 0.0508250035345554 14 {Portal to Town Network}
pnt -101.615851815542 -96.6388638178507 2.08333134651184E-05
pnt -101.657751337687 -96.5832635879517 2.08333134651184E-05
pnt -101.658352184296 -96.5325949986776 2.08333134651184E-05
pnt -101.605949529012 -96.519695186615 2.08333134651184E-05
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 -101.588099161784 -96.5166525046031 -0.000262499845121056 14 {Portal to Arwic}
pnt 56.6498762130737 33.416518386205 0.175020837783813
pnt 56.655900033315 33.5368880271912 0.175020837783813
pnt 56.7470087051392 33.5495386441549 0.175020837783813
pnt 56.7795230229696 33.6337207794189 0.175020837783813
tlk -101.597905190786 -96.6216093699137 2.08333134651184E-05 56.7816291809082 33.6455291748047 0.175020843744278 37 {Monroe}
~~ }

View file

@ -0,0 +1,186 @@
~~
~~ Bore Dungeon Quest Meta
~~ Navigates to the Bore dungeon, fights through to the boss,
~~ loots the quest item, returns to town to turn in.
~~ Includes death recovery.
~~
STATE: {Default}
IF: Death
DO: SetState {Death}
IF: ItemCountGE 1 {Bore Trophy}
DO: SetState {TurnIn}
IF: ItemCountLE 50 {Prismatic Taper}
DO: DoAll
Chat {Running low on tapers, restocking.}
SetState {Restock}
IF: Always
DO: DoAll
EmbedNav navToBore {Navigate to Bore dungeon entrance}
SetWatchdog 10.0 180.0 {Stuck}
STATE: {EnterDungeon}
IF: Death
DO: SetState {Death}
IF: IntoPortal
DO: SetState {InsideDungeon}
IF: SecsInStateGE 30
DO: SetState {Default}
STATE: {InsideDungeon}
IF: Death
DO: SetState {Death}
IF: ExitPortal
DO: DoAll
SetOpt {enablecombat} {true}
SetOpt {enablelooting} {true}
EmbedNav navDungeonRoute {Run through dungeon to boss}
SetWatchdog 10.0 120.0 {Stuck}
STATE: {BossRoom}
IF: Death
DO: SetState {Death}
IF: MobsInDist_Name 1 30.0 {Bore Boss}
DO: DoAll
SetOpt {enablecombat} {true}
SetState {Fighting}
IF: All
NavEmpty
NoMobsInDist 25.0
DO: SetState {LootBoss}
IF: Always
DO: None
STATE: {Fighting}
IF: Death
DO: SetState {Death}
IF: NoMobsInDist 25.0
DO: SetState {LootBoss}
IF: SecsInStateGE 300
DO: SetState {BossRoom}
STATE: {LootBoss}
IF: Death
DO: SetState {Death}
IF: ItemCountGE 1 {Bore Trophy}
DO: SetState {ExitDungeon}
IF: SecsInStateGE 30
DO: DoAll
Chat {No trophy found, exiting anyway.}
SetState {ExitDungeon}
IF: Always
DO: DoAll
SetOpt {enablelooting} {true}
None
STATE: {ExitDungeon}
IF: Death
DO: SetState {Death}
IF: All
NavEmpty
DO: DoAll
SetOpt {enablecombat} {false}
SetOpt {enablelooting} {false}
SetState {TurnIn}
IF: Always
DO: DoAll
EmbedNav navExitDungeon {Exit the dungeon}
SetWatchdog 10.0 120.0 {Stuck}
STATE: {TurnIn}
IF: Death
DO: SetState {Death}
IF: All
NavEmpty
DO: DoAll
Chat {/ub givep Bore Trophy to Bore Quest NPC}
Chat {/ub prepclick yes 3}
SetState {WaitTurnIn}
IF: Always
DO: DoAll
EmbedNav navToNPC {Go to turn-in NPC}
SetWatchdog 10.0 120.0 {Stuck}
STATE: {WaitTurnIn}
IF: ChatMatch {^Bore Quest NPC tells you,}
DO: SetState {TurnInComplete}
IF: ChatCapture {You have solved this quest too recently!} {}
DO: SetState {QuestCooldown}
IF: SecsInStateGE 15
DO: SetState {TurnIn}
STATE: {TurnInComplete}
IF: Always
DO: DoAll
Chat {Quest turn-in complete! Restarting.}
SetState {Default}
STATE: {QuestCooldown}
IF: Always
DO: DoAll
Chat {Quest on cooldown, waiting...}
SetState {Default}
STATE: {Restock}
IF: Death
DO: SetState {Death}
IF: All
NavEmpty
VendorOpen
DO: SetState {Selling}
IF: Always
DO: DoAll
EmbedNav navRestock {Go to vendor to restock}
SetWatchdog 10.0 120.0 {Stuck}
STATE: {Selling}
IF: VendorClosed
DO: SetState {Default}
IF: SecsInStateGE 30
DO: SetState {Default}
STATE: {Stuck}
IF: Always
DO: DoAll
Chat {/ub face}
SetState {Default}
STATE: {Death}
IF: ExitPortal
DO: SetState {Default}
~~ ============================================================
~~ NAV ROUTES
~~ ============================================================
NAV: navToBore once
~~ Route from lifestone to Bore dungeon entrance
rcl 0.0 0.0 0.0 {Lifestone Recall}
pnt 0.0 0.0 0.0
pnt 0.0 0.0 0.0
ptl 0.0 0.0 0.0 0.0 0.0 0.0 14 {Bore Dungeon}
NAV: navDungeonRoute once
~~ Route through dungeon to boss room
pnt 0.0 0.0 0.0
pnt 0.0 0.0 0.0
pnt 0.0 0.0 0.0
pnt 0.0 0.0 0.0
NAV: navExitDungeon once
~~ Route from boss room back to exit portal
pnt 0.0 0.0 0.0
pnt 0.0 0.0 0.0
ptl 0.0 0.0 0.0 0.0 0.0 0.0 14 {Exit Portal}
NAV: navToNPC once
~~ Route to quest turn-in NPC
rcl 0.0 0.0 0.0 {Lifestone Recall}
pnt 0.0 0.0 0.0
tlk 0.0 0.0 0.0 0.0 0.0 0.0 37 {Bore Quest NPC}
NAV: navRestock once
~~ Route to vendor for restocking tapers
rcl 0.0 0.0 0.0 {Lifestone Recall}
pnt 0.0 0.0 0.0
vnd 0.0 0.0 0.0 00000000 {Vendor}

View file

@ -0,0 +1,217 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {Default} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/ub opt set VTank.PatchExpressionEngine true}
SetOpt {enablecombat} {false}
SetOpt {enablenav} {true}
SetOpt {enablelooting} {false}
SetOpt {enablebuffing} {true}
SetOpt {attackdistance} {0.0125}
DoExpr {setvar[currentLevel,`upper`]}
DoExpr {setvar[currentRoom,`north`]}
DoExpr {setvar[roomsDone,0]}
Chat {/vt nav load nav_empyrean}
SetState {enter_dungeon}
~~ }
STATE: {enter_dungeon} ~~ {
IF: Death
DO: SetState {death}
IF: All
SecsInStateGE 3
NavEmpty
DO: DoAll
SetOpt {enablecombat} {true}
SetState {goto_room}
IF: Always
DO: DoAll
SetWatchdog 10 300 {stuck}
~~ }
STATE: {goto_room} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
ChatExpr {\/vt nav load emp_+getvar[currentLevel]+`_`+getvar[currentRoom]}
DoExpr {clearvar[navLoaded]}
SetState {arrive_room}
~~ }
STATE: {arrive_room} ~~ {
IF: Death
DO: SetState {death}
IF: All
Expr {testvar[navLoaded]}
NavEmpty
DO: DoAll
ClearWatchdog
SetState {kill_wisps}
IF: Always
DO: DoAll
DoExpr {touchvar[navLoaded]}
SetWatchdog 10 180 {stuck}
~~ }
STATE: {kill_wisps} ~~ {
IF: Death
DO: SetState {death}
IF: All
SecsInStateGE 5
NoMobsInDist 4
DO: SetState {use_stone}
IF: SecsInStateGE 300
DO: SetState {use_stone}
IF: Always
DO: DoAll
SetWatchdog 10 300 {stuck}
~~ }
STATE: {use_stone} ~~ {
IF: Death
DO: SetState {death}
IF: ChatMatch {A shiver moves across your body}
DO: DoAll
DoExpr {echo[`Room complete! (`+getvar[currentLevel]+` `+getvar[currentRoom]+`)`,1]}
SetState {next_room}
IF: ChatMatch {no change}
DO: DoAll
DoExpr {echo[`Room already done (`+getvar[currentLevel]+` `+getvar[currentRoom]+`)`,1]}
SetState {next_room}
IF: SecsInStateGE 5
DO: DoAll
Chat {/ub use Aligned Mana Stone}
SetState {use_stone}
IF: Always
DO: DoAll
Chat {/ub use Aligned Mana Stone}
~~ }
STATE: {next_room} ~~ {
IF: Death
DO: SetState {death}
IF: Expr {getvar[currentRoom]==`north`}
DO: DoAll
DoExpr {setvar[currentRoom,`east`]}
SetState {goto_room}
IF: Expr {getvar[currentRoom]==`east`}
DO: DoAll
DoExpr {setvar[currentRoom,`south`]}
SetState {goto_room}
IF: Expr {getvar[currentRoom]==`south`}
DO: DoAll
DoExpr {setvar[currentRoom,`west`]}
SetState {goto_room}
IF: Expr {getvar[currentRoom]==`west`}
DO: DoAll
DoExpr {setvar[currentRoom,`center`]}
SetState {goto_room}
IF: Expr {getvar[currentRoom]==`center`}
DO: SetState {use_stone_center}
~~ }
STATE: {use_stone_center} ~~ {
IF: Death
DO: SetState {death}
IF: ChatMatch {A shiver moves across your body}
DO: DoAll
DoExpr {echo[`Level complete! (`+getvar[currentLevel]+`)`,1]}
SetState {take_portal}
IF: ChatMatch {no change}
DO: DoAll
DoExpr {echo[`Level already done (`+getvar[currentLevel]+`)`,1]}
SetState {take_portal}
IF: SecsInStateGE 5
DO: DoAll
Chat {/ub use Aligned Mana Stone}
SetState {use_stone_center}
IF: Always
DO: DoAll
Chat {/ub use Aligned Mana Stone}
~~ }
STATE: {take_portal} ~~ {
IF: Death
DO: SetState {death}
IF: Expr {getvar[currentLevel]==`upper`}
DO: DoAll
DoExpr {setvar[currentLevel,`middle`]}
DoExpr {setvar[currentRoom,`north`]}
Chat {/ub use Empyrean Facility Middle Level}
SetState {portal_transition}
IF: Expr {getvar[currentLevel]==`middle`}
DO: DoAll
DoExpr {setvar[currentLevel,`lower`]}
DoExpr {setvar[currentRoom,`north`]}
Chat {/ub use Empyrean Facility Lower Level}
SetState {portal_transition}
IF: Expr {getvar[currentLevel]==`lower`}
DO: DoAll
DoExpr {echo[`All 3 aetheria slots unlocked!`,1]}
SetState {quest_done}
~~ }
STATE: {portal_transition} ~~ {
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: DoAll
DoExpr {echo[`Arrived at `+getvar[currentLevel]+` level`,1]}
SetState {goto_room}
IF: SecsInStateGE 15
DO: SetState {take_portal}
~~ }
STATE: {quest_done} ~~ {
IF: Always
DO: DoAll
DoExpr {echo[`Empyrean Facility quest COMPLETE! All aetheria slots unlocked.`,1]}
Chat {/mp}
~~ }
STATE: {stuck} ~~ {
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/ub face}
DoExpr {echo[`Stuck! Trying to recover...`,1]}
SetState {goto_room}
~~ }
STATE: {death} ~~ {
IF: ExitPortal
DO: DoAll
DoExpr {echo[`Died! Re-entering dungeon...`,1]}
Chat {/vt nav load nav_empyrean}
SetState {enter_dungeon}
~~ }

View file

@ -0,0 +1,221 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {Default} ~~ {
IF: Always
DO: DoAll
DoExpr {setvar[mssortstring,`CV,AS,EQ,TR-,OC,IC,AL-,EP,MX-`]}
SetState {SortManaStones}
~~ }
STATE: {SortManaStones} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 7}
Chat {/ms set ocfilter manastone}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortHealingKits}
~~ }
STATE: {SortHealingKits} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 7}
Chat {/ms set ocfilter healingkit}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortMisc}
~~ }
STATE: {SortMisc} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 2}
Chat {/ms set ocfilter misc}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortGems}
~~ }
STATE: {SortGems} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 3}
Chat {/ms set ocfilter gem}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortWeapons}
~~ }
STATE: {SortWeapons} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 1}
Chat {/ms set ocfilter meleeweapon}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortWands}
~~ }
STATE: {SortWands} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 1}
Chat {/ms set ocfilter wand}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortSpellComps}
~~ }
STATE: {SortSpellComps} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest pack 8}
Chat {/ms set ocfilter spellcomp}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortInventory}
~~ }
STATE: {SortInventory} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source player}
Chat {/ms set dest player}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack1}
~~ }
STATE: {SortPack1} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 1}
Chat {/ms set dest pack 1}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack2}
~~ }
STATE: {SortPack2} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 2}
Chat {/ms set dest pack 2}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack3}
~~ }
STATE: {SortPack3} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 3}
Chat {/ms set dest pack 3}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack4}
~~ }
STATE: {SortPack4} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 4}
Chat {/ms set dest pack 4}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack5}
~~ }
STATE: {SortPack5} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 5}
Chat {/ms set dest pack 5}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack6}
~~ }
STATE: {SortPack6} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 6}
Chat {/ms set dest pack 6}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack7}
~~ }
STATE: {SortPack7} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 7}
Chat {/ms set dest pack 7}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {SortPack8}
~~ }
STATE: {SortPack8} ~~ {
IF: Always
DO: DoAll
Chat {/ms set source pack 8}
Chat {/ms set dest pack 8}
Chat {/ms clear ocfilter}
ChatExpr {`/ms set flags `+getvar[mssortstring]}
Chat {/ms start}
IF: ChatMatch {^You think\, \"done sorting\!\"$}
DO: SetState {AllDone}
~~ }

View file

@ -0,0 +1,218 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
~~ Follower Meta: Follows group leader, responds to chat commands, death recovery
STATE: {Default} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablelooting false}
DoExpr {setvar[leaderName,]}
DoExpr {setvar[deathCount, 0]}
SetState {idle}
~~ }
STATE: {idle} ~~ {
~~ Wait for leader assignment via chat command
IF: ChatMatch {.+tells you, "follow me"}
DO: DoAll
DoExpr {setvar[leaderName, getregexmatch[(.+) tells you, 1]]}
ChatExpr {\/t +getvar[leaderName]+, Following you now\!}
SetState {following}
IF: ChatMatch {.+tells you, "follow (.+)"}
DO: DoAll
DoExpr {setvar[leaderName, getregexmatch[.+tells you, "follow (.+)", 1]]}
ChatExpr {\/t +getvar[leaderName]+, Following you now\!}
SetState {following}
IF: Death
DO: SetState {death_recovery}
IF: NeedToBuff
DO: SetState {buffing}
IF: Always
DO: Chat {/vt opt set enablecombat false}
~~ }
STATE: {following} ~~ {
~~ Main follow state - follow the leader
IF: Always
DO: Chat {/vt opt set enablecombat false}
IF: Always
DO: Chat {/vt opt set enablenav false}
IF: Always
DO: ChatExpr {\/ub follow +getvar[leaderName]}
~~ Death handling
IF: Death
DO: DoAll
DoExpr {setvar[deathCount, getvar[deathCount] + 1]}
ChatExpr {\/t +getvar[leaderName]+, I died\! Death count: +cstr[getvar[deathCount]]+. Recovering...}
SetState {death_recovery}
~~ Chat command: buff
IF: ChatMatch {.+tells you, "buff"}
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {buffing}
~~ Chat command: recall
IF: ChatMatch {.+tells you, "recall"}
DO: DoAll
ChatExpr {\/t +getvar[leaderName]+, Recalling now\!}
SetState {recalling}
~~ Chat command: stop
IF: ChatMatch {.+tells you, "stop"}
DO: DoAll
ChatExpr {\/t +getvar[leaderName]+, Stopping follow\.}
DoExpr {setvar[leaderName,]}
Chat {/ub follow off}
SetState {idle}
~~ Chat command: combat on
IF: ChatMatch {.+tells you, "combat on"}
DO: DoAll
Chat {/vt opt set enablecombat true}
ChatExpr {\/t +getvar[leaderName]+, Combat enabled\!}
~~ Chat command: combat off
IF: ChatMatch {.+tells you, "combat off"}
DO: DoAll
Chat {/vt opt set enablecombat false}
ChatExpr {\/t +getvar[leaderName]+, Combat disabled\!}
~~ Need to rebuff
IF: NeedToBuff
DO: DoAll
Chat {/ub follow off}
SetState {buffing}
~~ Watchdog - if stuck for too long, try to recover
IF: Always
DO: SetWatchdog 3 300 {stuck_recovery}
~~ }
STATE: {buffing} ~~ {
~~ Buff up then return to following
IF: Always
DO: DoAll
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablecombat false}
IF: Death
DO: DoAll
DoExpr {setvar[deathCount, getvar[deathCount] + 1]}
SetState {death_recovery}
IF: All
Not NeedToBuff
SecsInStateGE 5
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {rejoin_leader}
IF: SecsInStateGE 120
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {rejoin_leader}
~~ }
STATE: {death_recovery} ~~ {
~~ Wait at lifestone after death, then rebuff and rejoin
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablebuffing false}
~~ Wait a few seconds at lifestone before doing anything
IF: SecsInStateGE 10
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {death_rebuff}
~~ }
STATE: {death_rebuff} ~~ {
~~ Rebuff after death before rejoining
IF: Always
DO: Chat {/vt opt set enablebuffing true}
IF: Death
DO: DoAll
DoExpr {setvar[deathCount, getvar[deathCount] + 1]}
SetState {death_recovery}
IF: All
Not NeedToBuff
SecsInStateGE 10
DO: SetState {rejoin_leader}
IF: SecsInStateGE 180
DO: SetState {rejoin_leader}
~~ }
STATE: {rejoin_leader} ~~ {
~~ Rejoin the leader after buffing or death recovery
IF: Expr {getvar[leaderName] == 0}
DO: SetState {idle}
IF: Expr {cstr[getvar[leaderName]] == cstr[]}
DO: SetState {idle}
IF: Always
DO: DoAll
ChatExpr {\/t +getvar[leaderName]+, Rejoining you now\!}
ChatExpr {\/ub follow +getvar[leaderName]}
SetState {following}
~~ }
STATE: {recalling} ~~ {
~~ Recall to lifestone
IF: Always
DO: DoAll
Chat {/ub follow off}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav false}
IF: SecsInStateGE 2
DO: Chat {/lifestone}
IF: Death
DO: DoAll
DoExpr {setvar[deathCount, getvar[deathCount] + 1]}
SetState {death_recovery}
IF: SecsInStateGE 15
DO: DoAll
ChatExpr {\/t +getvar[leaderName]+, Recalled to lifestone\. Tell me to follow you when ready\.}
SetState {idle}
~~ }
STATE: {stuck_recovery} ~~ {
~~ Try to recover from being stuck
IF: Always
DO: DoAll
Chat {/ub follow off}
Chat {/vt opt set enablecombat false}
ChatExpr {\/t +getvar[leaderName]+, I appear to be stuck\. Trying to recover\.}
IF: SecsInStateGE 3
DO: Chat {/lifestone}
IF: Death
DO: DoAll
DoExpr {setvar[deathCount, getvar[deathCount] + 1]}
SetState {death_recovery}
IF: SecsInStateGE 15
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {death_rebuff}
~~ }

View file

@ -0,0 +1,175 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {all_run_back} ~~ {
IF: Always
DO: Chat {/ub bc /vt setmetastate just_run_back}
~~ }
STATE: {strength} ~~ {
IF: Always
DO: DoAll
Chat {/ub bc /ub use Luminous Crystal of Surging Strength}
SetState {Default}
~~ }
STATE: {closestportal} ~~ {
IF: Always
DO: Chat {/ub bc /ub closestportal}
IF: Always
DO: SetState {Default}
~~ }
STATE: {death} ~~ {
IF: Always
DO: Chat {/vt nav load death_pause}
IF: Always
DO: Chat {/vt opt set enablenav true}
IF: NavEmpty
DO: SetState {run_back}
~~ }
STATE: {Default} ~~ {
IF: Always
DO: None
IF: Death
DO: SetState {death}
~~ }
STATE: {defence} ~~ {
IF: Always
DO: DoAll
Chat {/ub bc /ub use Luminous Crystal of Towering Defense}
SetState {Default}
~~ }
STATE: {dispell} ~~ {
IF: Always
DO: DoAll
Chat {/ub bc /ub use Black Market Gem of Dispelling}
SetState {Default}
~~ }
STATE: {follow} ~~ {
IF: Always
DO: DoAll
ChatExpr {\/ub bc \/ub follow +wobjectgetname[wobjectgetplayer[]]}
Chat {/ub bc /vt opt set enablenav true}
IF: Always
DO: SetState {Default}
~~ }
STATE: {jump} ~~ {
IF: Always
DO: Chat {/ub bc /ub jumpsw 400}
IF: Always
DO: SetState {Default}
~~ }
STATE: {just_run_back} ~~ {
IF: Always
DO: DoAll
Chat {/vt nav load gauntlet_just_run}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablemeta true}
Chat {/vt opt set enablecombat true}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {load_follow} ~~ {
IF: Always
DO: Chat {/ub bc /vt meta load gauntlet_follower}
IF: Always
DO: SetState {Default}
~~ }
STATE: {nav_false} ~~ {
IF: Always
DO: Chat {/ub bc /vt opt set enablenav false}
IF: Always
DO: SetState {Default}
~~ }
STATE: {nav_true} ~~ {
IF: Always
DO: Chat {/ub bc /vt opt set enablenav true}
IF: Always
DO: SetState {Default}
~~ }
STATE: {run_back} ~~ {
IF: Always
DO: DoAll
Chat {/vt nav load gauntlet_run}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablemeta true}
Chat {/vt opt set enablecombat true}
IF: NavEmpty
DO: SetState {Default}
~~ }
STATE: {setup} ~~ {
IF: Always
DO: ChatExpr {\/ub bc \/ub follow +wobjectgetname[wobjectgetplayer[]]}
IF: Always
DO: Chat {/ub bc /vt opt set enablelooting false}
IF: Always
DO: Chat {/ub bc /vt opt set enablenav true}
IF: Always
DO: Chat {/ub bc /vt opt set enablebuffing true}
IF: Always
DO: Chat {/ub bc /vt opt set enablecombat true}
IF: Always
DO: Chat {/ub bc /vt opt set attackdistance 0.125}
IF: Always
DO: Chat {/ub bc /vt opt set navpriorityboost true}
IF: Always
DO: Chat {/ub bc /vt opt set buffprofile_prots 2}
IF: Always
DO: Chat {/ub bc /vt opt set buffprofile_banes 2}
IF: Always
DO: Chat {/ub bc /vt forcebuff}
IF: Always
DO: Chat {/ub bc /vt start}
IF: Always
DO: Chat {/ub bc /vt opt set enablemeta true}
IF: Always
DO: SetState {Default}
~~ }
STATE: {summon_false} ~~ {
IF: Always
DO: Chat {/ub bc /vt opt set SummonPets false}
IF: Always
DO: SetState {Default}
~~ }
STATE: {summon_true} ~~ {
IF: Always
DO: Chat {/ub bc /vt opt set SummonPets true}
IF: Always
DO: SetState {Default}
~~ }

View file

@ -0,0 +1,220 @@
~~ {
~~ Hunting Meta - Solo lifestone grinding with death recovery, restock, and stuck detection
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators:
~~ STATE: DO:
~~ IF: NAV:
~~
~~ All recognized CONDITION (IF:) operation keywords:
~~ Never NavEmpty MobsInDist_Priority Not
~~ Always Death NeedToBuff PSecsInStateGE
~~ All VendorOpen NoMobsInDist SecsOnSpellGE
~~ Any VendorClosed BlockE BuPercentGE
~~ ChatMatch ItemCountLE CellE DistToRteGE
~~ MainSlotsLE ItemCountGE IntoPortal Expr
~~ SecsInStateGE MobsInDist_Name ExitPortal ChatCapture
~~
~~ All recognized ACTION (DO:) operation keywords:
~~ None EmbedNav ChatExpr SetOpt
~~ SetState CallState SetWatchdog CreateView
~~ Chat Return ClearWatchdog DestroyView
~~ DoAll DoExpr GetOpt DestroyAllViews
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~ }
STATE: {Default} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
Chat {/vt opt set navpriorityboost false}
Chat {/vt opt set lootpriorityboost true}
Chat {/vt nav load hunt_circuit}
SetState {Hunt}
~~ }
STATE: {Hunt} ~~ {
IF: Death
DO: SetState {Death}
IF: All
ItemCountLE 20 {Prismatic Taper}
NoMobsInDist 5
DO: DoAll
Chat {/a Low on tapers, heading to vendor.}
SetState {Restock}
IF: All
ItemCountLE 20 {Scarab}
NoMobsInDist 5
DO: DoAll
Chat {/a Low on scarabs, heading to vendor.}
SetState {Restock}
IF: MainSlotsLE 3
DO: DoAll
Chat {/a Inventory full, heading to vendor.}
SetState {Restock}
IF: NeedToBuff
DO: DoAll
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablecombat false}
SetState {Buffing}
IF: Always
DO: SetWatchdog 3 120 {Stuck}
IF: DistToRteGE 500
DO: SetState {Stuck}
IF: MobsInDist_Name 1 12 {}
DO: DoAll
Chat {/vt opt set enablecombat true}
IF: NoMobsInDist 12
DO: DoAll
Chat {/vt opt set enablecombat false}
IF: NavEmpty
DO: DoAll
Chat {/vt nav load hunt_circuit}
Chat {/vt opt set enablenav true}
~~ }
STATE: {Death} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav false}
Chat {/a I died! Recovering...}
IF: SecsInStateGE 5
DO: DoAll
Chat {/vt opt set enablebuffing true}
SetState {DeathRecovery}
~~ }
STATE: {DeathRecovery} ~~ {
IF: Always
DO: DoAll
Chat {/vt nav load ls_to_hunt}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat false}
IF: NeedToBuff
DO: DoAll
Chat {/vt opt set enablenav false}
SetState {Buffing}
IF: NavEmpty
DO: DoAll
Chat {/vt nav load hunt_circuit}
Chat {/vt opt set enablecombat true}
SetState {Hunt}
IF: Always
DO: SetWatchdog 3 300 {Stuck}
~~ }
STATE: {Buffing} ~~ {
IF: Always
DO: DoAll
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav false}
IF: All
Not NeedToBuff
NoMobsInDist 5
DO: DoAll
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat true}
SetState {Hunt}
IF: SecsInStateGE 180
DO: DoAll
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat true}
SetState {Hunt}
~~ }
STATE: {Restock} ~~ {
IF: Death
DO: SetState {Death}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt nav load hunt_to_vendor}
Chat {/vt opt set enablenav true}
IF: Always
DO: SetWatchdog 3 300 {Stuck}
IF: NavEmpty
DO: SetState {AtVendor}
~~ }
STATE: {AtVendor} ~~ {
IF: Death
DO: SetState {Death}
IF: VendorOpen
DO: DoAll
Chat {/vt opt set enablenav false}
IF: All
VendorClosed
ItemCountGE 200 {Prismatic Taper}
ItemCountGE 200 {Scarab}
DO: DoAll
Chat {/a Restocked, heading back to hunt.}
Chat {/vt nav load vendor_to_hunt}
Chat {/vt opt set enablenav true}
SetState {ReturnToHunt}
IF: SecsInStateGE 120
DO: DoAll
Chat {/a Vendor timeout, returning to hunt.}
Chat {/vt nav load vendor_to_hunt}
Chat {/vt opt set enablenav true}
SetState {ReturnToHunt}
~~ }
STATE: {ReturnToHunt} ~~ {
IF: Death
DO: SetState {Death}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
IF: Always
DO: SetWatchdog 3 300 {Stuck}
IF: NeedToBuff
DO: DoAll
Chat {/vt opt set enablenav false}
SetState {Buffing}
IF: NavEmpty
DO: DoAll
Chat {/vt nav load hunt_circuit}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
SetState {Hunt}
~~ }
STATE: {Stuck} ~~ {
IF: Always
DO: DoAll
Chat {/a I appear to be stuck, attempting recovery.}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablecombat false}
IF: SecsInStateGE 3
DO: DoAll
Chat {/vt nav load ls_to_hunt}
Chat {/vt opt set enablenav true}
SetState {StuckRecovery}
~~ }
STATE: {StuckRecovery} ~~ {
IF: Death
DO: SetState {Death}
IF: Always
DO: SetWatchdog 3 300 {Stuck}
IF: NeedToBuff
DO: DoAll
Chat {/vt opt set enablenav false}
SetState {Buffing}
IF: NavEmpty
DO: DoAll
Chat {/vt nav load hunt_circuit}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
SetState {Hunt}
~~ }

View file

@ -0,0 +1,416 @@
~~
~~ lockandkey.af - Portal Bot with Stipend & Partial Bella Services
~~
~~ A portal summoning bot that:
~~ - Listens for tells containing "primary" or "secondary" to summon portals
~~ - Collects stipend on timer (with backoff)
~~ - Runs partial bella (jaw turn-in only, no kill bella)
~~ - Returns home via ah_recall after services
~~
~~ Portal Spells:
~~ Summon Primary Portal I = spell 157
~~ Summon Secondary Portal I = spell 2648
~~
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getplayerlandblock wobjectisvalid getitemcountbytemplatetype ifthen
~~ }
STATE: {Default}
~~ Init variables then transition to service check
IF: Not Expr {testvar[bellaTurnInAttempts]}
DO: DoExpr {setvar[bellaTurnInAttempts, 0]}
IF: Not Expr {testvar[bellaJawRunRecoverAttempts]}
DO: DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
IF: Not Expr {testvar[bellaBackoffSeconds]}
DO: DoExpr {setvar[bellaBackoffSeconds, 86400]}
IF: Not Expr {testvar[stipendBackoffSeconds]}
DO: DoExpr {setvar[stipendBackoffSeconds, 86400]}
IF: Not Expr {testvar[disableBellaServices]}
DO: DoExpr {setvar[disableBellaServices, 0]}
IF: Not Expr {testvar[serviceCheckInterval]}
DO: DoExpr {setvar[serviceCheckInterval, 900]}
IF: Not Expr {testvar[serviceClock]}
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
IF: Always
DO: DoAll
Chat {/ub opt set VTank.PatchExpressionEngine true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablebuffing false}
SetState {service_quest_refresh}
~~ }
STATE: {idle}
~~ Main loop: listen for portal tells, check service timer
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/vt opt set enablebuffing false}
DoExpr {setcombatstate[`peace`]}
DoExpr {clearvar[queuePrimary]}
DoExpr {clearvar[queueSecondary]}
~~ Listen for tells containing "primary"
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*primary.*"$} {}
DO: SetState {summon_primary}
~~ Listen for tells containing "secondary"
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*secondary.*"$} {}
DO: SetState {summon_secondary}
~~ Periodic service check
IF: All
Expr {testvar[serviceClock]}
Expr {stopwatchelapsedseconds[getvar[serviceClock]]>=getvar[serviceCheckInterval]}
DO: SetState {service_quest_refresh}
IF: Always
DO: None
STATE: {summon_primary}
~~ Face 180, equip wand, cast Summon Primary Portal I (157), retry on fizzle
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/a Summoning 125 Eaters portal...}
Chat {/vt opt set enablecombat false}
Chat {/ub face 180}
DoExpr {setcombatstate[`magic`]}
DoExpr {actiontryequipanywand[]}
DoExpr {clearvar[queuePrimary]}
IF: SecsInStateGE 4
DO: DoExpr {actiontrycastbyid[157]}
~~ Fizzle: retry cast
IF: ChatMatch {Your spell fizzled.}
DO: DoAll
Chat {/a Fizzled! Retrying 125 Eaters portal...}
DoExpr {actiontrycastbyid[157]}
SetState {summon_primary}
~~ Queue incoming tells while casting
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*primary.*"$} {}
DO: DoAll
Chat {/a Queued 125 Eaters portal, will summon shortly.}
DoExpr {setvar[queuePrimary, 1]}
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*secondary.*"$} {}
DO: DoAll
Chat {/a Queued Bellas portal, will summon shortly.}
DoExpr {setvar[queueSecondary, 1]}
IF: SecsInStateGE 17
DO: SetState {summon_done}
STATE: {summon_secondary}
~~ Face 90, equip wand, cast Summon Secondary Portal I (2648), retry on fizzle
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/a Summoning Bellas portal...}
Chat {/vt opt set enablecombat false}
Chat {/ub face 90}
DoExpr {setcombatstate[`magic`]}
DoExpr {actiontryequipanywand[]}
DoExpr {clearvar[queueSecondary]}
IF: SecsInStateGE 4
DO: DoExpr {actiontrycastbyid[2648]}
~~ Fizzle: retry cast
IF: ChatMatch {Your spell fizzled.}
DO: DoAll
Chat {/a Fizzled! Retrying Bellas portal...}
DoExpr {actiontrycastbyid[2648]}
SetState {summon_secondary}
~~ Queue incoming tells while casting
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*primary.*"$} {}
DO: DoAll
Chat {/a Queued 125 Eaters portal, will summon shortly.}
DoExpr {setvar[queuePrimary, 1]}
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) tells you, ".*secondary.*"$} {}
DO: DoAll
Chat {/a Queued Bellas portal, will summon shortly.}
DoExpr {setvar[queueSecondary, 1]}
IF: SecsInStateGE 17
DO: SetState {summon_done}
STATE: {summon_done}
~~ Check queue: process next summon request or return to idle
IF: Expr {testvar[queuePrimary]}
DO: DoAll
Chat {/a Processing queued 125 Eaters portal...}
SetState {summon_primary}
IF: Expr {testvar[queueSecondary]}
DO: DoAll
Chat {/a Processing queued Bellas portal...}
SetState {summon_secondary}
IF: Always
DO: SetState {idle}
STATE: {service_quest_refresh}
~~ Request quest status refresh, wait for completion
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/myquests}
DoExpr {touchvar[questsRequested]}
IF: All
Expr {testvar[questsRequested]}
Expr {isrefreshingquests[]==0}
SecsInStateGE 2
DO: SetState {service_pending_eval}
IF: SecsInStateGE 8
DO: SetState {service_pending_eval}
STATE: {service_pending_eval}
~~ Check if bella jaw quest is ready (no augment application for portal bot)
IF: Always
DO: SetState {service_decide}
STATE: {service_decide}
~~ Decide which services to run: stipend, partial bella, or return to idle
~~ Reset bella backoff if timer expired
IF: All
Expr {getvar[disableBellaServices]==1}
Expr {testvar[bellaBackoffClock]}
Expr {stopwatchelapsedseconds[getvar[bellaBackoffClock]]>=getvar[bellaBackoffSeconds]}
DO: DoAll
DoExpr {setvar[disableBellaServices, 0]}
DoExpr {setvar[bellaTurnInAttempts, 0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
DoExpr {clearvar[bellaBackoffClock]}
~~ Stipend: first run (no backoff clock)
IF: All
Expr {getqueststatus[`stipendtimer_0812`]==1}
Not Expr {testvar[stipendBackoffClock]}
DO: SetState {service_stipend}
~~ Stipend: backoff expired
IF: All
Expr {getqueststatus[`stipendtimer_0812`]==1}
Expr {testvar[stipendBackoffClock]}
Expr {stopwatchelapsedseconds[getvar[stipendBackoffClock]]>=getvar[stipendBackoffSeconds]}
DO: DoAll
DoExpr {clearvar[stipendBackoffClock]}
SetState {service_stipend}
~~ Partial bella: jaw quest ready + services not disabled
IF: All
Expr {getvar[disableBellaServices]!=1}
Expr {getqueststatus[`insatiableeaterjaw`]==1}
DO: SetState {service_bella_jaw_entry}
~~ Nothing to do, return to idle
IF: Always
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
SetState {idle}
STATE: {service_stipend}
~~ Run stipend collection nav, start backoff clock
IF: Death
DO: SetState {death}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
DoExpr {setvar[stipendBackoffClock, stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[stipendBackoffClock]]}
DoExpr {touchvar[stipendNavLoaded]}
EmbedNav nav0__stipend_nav {stipend.nav}
IF: All
Expr {testvar[stipendNavLoaded]}
NavEmpty
SecsInStateGE 2
DO: SetState {service_reset_main}
STATE: {service_bella_jaw_entry}
~~ Equip quest gear, buff up, then run nav_lockandkeyjaw (nav handles idle/quest swap + recall)
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/a [bella] equipping quest gear and buffing for jaw dungeon}
Chat {/ub equip load quest.utl}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablebuffing true}
DoExpr {setvar[jawEntryNavLoaded,1]}
Chat {/vt nav load nav_lockandkeyjaw}
SetWatchdog 3 600 {service_bella_backoff}
IF: All
Expr {getvar[jawEntryNavLoaded]==1}
NavEmpty
SecsInStateGE 2
DO: DoAll
DoExpr {setvar[jawEntryNavLoaded,0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
Chat {/vt nav load jaw_1_hunt}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
Chat {/vt opt set lootonlyrarecorpses false}
SetState {service_bella_jaw_hunt}
STATE: {service_bella_jaw_run_recover}
~~ Recovery wait for jaw run stuck
IF: Death
DO: SetState {death}
IF: SecsInStateGE 20
DO: SetState {service_bella_jaw_entry}
STATE: {service_bella_jaw_hunt}
~~ Hunt for jaw drop
IF: Death
DO: SetState {death}
IF: Always
DO: Chat {/vt opt set enablebuffing true}
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav true}
SetState {service_bella_turn_in_jaw}
IF: ItemCountGE 1 {Insatiable Eater Jaw}
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt nav load to_fiun}
IF: SecsInStateGE 1200
DO: SetState {service_bella_backoff}
STATE: {service_bella_turn_in_jaw}
~~ Turn in jaw to Fiun NPC, then return home (partial bella - no mp_trans/secondary/kill)
IF: Death
DO: SetState {death}
~~ Jaw accepted: return home instead of continuing to mp_secondary
IF: ChatMatch {^.*One who obtains such as this is truly worthy of that which we would teach\. The highest peak of the deadliest isle contains that which you seek.*$}
DO: DoAll
Chat {/a [bella] jaw turned in, returning home (partial bella)}
DoExpr {setvar[bellaTurnInAttempts, 0]}
SetState {equip_idle}
IF: All
SecsInStateGE 300
ItemCountGE 1 {Insatiable Eater Jaw}
Expr {getvar[bellaTurnInAttempts]<3}
DO: DoAll
DoExpr {chatbox[`/a [bella] jaw turn-in timed out, retry `+cstr[getvar[bellaTurnInAttempts]+1]+`/3`]}
DoExpr {setvar[bellaTurnInAttempts,getvar[bellaTurnInAttempts]+1]}
Chat {/vt nav load to_fiun}
SetState {service_bella_turn_in_jaw}
IF: All
SecsInStateGE 300
ItemCountGE 1 {Insatiable Eater Jaw}
Expr {getvar[bellaTurnInAttempts]>=3}
DO: SetState {service_bella_backoff}
~~ Jaw already gone (consumed by NPC), just go home
IF: SecsInStateGE 300
DO: DoAll
DoExpr {setvar[bellaTurnInAttempts, 0]}
SetState {equip_idle}
STATE: {service_bella_backoff}
~~ Disable bella services for 24h, return home
IF: Always
DO: DoAll
Chat {/a [bella] backoff tripped, disabling bella services for 24h}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav true}
DoExpr {setvar[disableBellaServices, 1]}
DoExpr {setvar[bellaTurnInAttempts, 0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
DoExpr {setvar[bellaBackoffClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[bellaBackoffClock]]}
SetState {equip_idle}
STATE: {equip_idle}
~~ Swap back to idle gear before heading home
IF: Death
DO: SetState {death}
IF: Always
DO: Chat {/ub equip load idle.utl}
IF: SecsInStateGE 12
DO: SetState {service_reset_main}
STATE: {service_reset_main}
~~ Clear service vars, load ah_recall to return home, then go to idle
IF: Death
DO: SetState {death}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main_stuck}
IF: Always
DO: DoAll
DoExpr {clearvar[questsRequested]}
DoExpr {clearvar[stipendNavLoaded]}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablebuffing false}
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
DoExpr {touchvar[resetNavLoaded]}
Chat {/vt nav load ah_recall}
IF: All
Expr {testvar[resetNavLoaded]}
NavEmpty
SecsInStateGE 2
DO: DoAll
DoExpr {clearvar[resetNavLoaded]}
ClearWatchdog
Chat {/vt opt set enablenav false}
SetState {idle}
STATE: {service_reset_main_stuck}
~~ Fallback if ah_recall nav gets stuck
IF: Always
DO: DoAll
Chat {/ah}
SetState {service_reset_main_wait}
STATE: {service_reset_main_wait}
~~ Wait for /ah recall, then retry reset
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: SetState {service_reset_main}
IF: SecsInStateGE 30
DO: SetState {service_reset_main}
STATE: {death}
~~ Death recovery: wait for portal exit, recall home
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
IF: ExitPortal
DO: DoAll
Chat {/ah}
SetState {death_wait_recall}
IF: SecsInStateGE 30
DO: DoAll
Chat {/ah}
SetState {death_wait_recall}
STATE: {death_wait_recall}
~~ Wait for /ah recall portal exit, then return to idle
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: SetState {idle}
IF: SecsInStateGE 60
DO: SetState {idle}
~~========================= ONLY NAVS APPEAR BELOW THIS LINE =========================~~
NAV: nav0__stipend_nav once
pau 47.1262349446615 26.1864453474681 0.225020837783813 2000
cht -101.597905190786 -96.6216093699137 2.08333134651184E-05 {/ah}
pau 47.1262349446615 26.1864453474681 0.225020837783813 15000
pnt 59.3590666453044 -28.7057823816935 0.0500208298365275
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 59.3936458587647 -28.7256083488464 0.0508250035345554 14 {Portal to Town Network}
pnt -101.615851815542 -96.6388638178507 2.08333134651184E-05
pnt -101.657751337687 -96.5832635879517 2.08333134651184E-05
pnt -101.658352184296 -96.5325949986776 2.08333134651184E-05
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 -101.588099161784 -96.5166525046031 -0.000262499845121056 14 {Portal to Arwic}
pnt 56.6498762130737 33.416518386205 0.175020837783813
pnt 56.655900033315 33.5368880271912 0.175020837783813
pnt 56.7470087051392 33.5495386441549 0.175020837783813
pnt 56.7795230229696 33.6337207794189 0.175020837783813
tlk -101.597905190786 -96.6216093699137 2.08333134651184E-05 56.7816291809082 33.6455291748047 0.175020843744278 37 {Monroe}

View file

@ -0,0 +1,42 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators in a NAV-ONLY file:
~~ NAV:
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~
~~
~~ REMEMBER THAT NAV-ONLY FILES MUST CONTAIN EXACTLY ONE NAV!
~~ }
NAV: nav0 once ~~ {
cht 59.1563772201538 -28.5892723083496 0.0500208298365275 {/ah}
pau 59.1563772201538 -28.5892723083496 0.0500208298365275 22000
cht 59.1563772201538 -28.5892723083496 0.0500208298365275 {/tell Time according to alex, ab}
pau 59.1563772201538 -28.5892723083496 0.0500208298365275 30000
cht 59.1563772201538 -28.5892723083496 0.0500208298365275 {/ub use Gateway}
pnt -87.9797062555949 -60.4362569173177 0.265733496348063
pnt -87.9643449147542 -60.3346110810836 0.230621592203776
pnt -87.9498847007751 -60.1938330491384 0.185985358556112
pnt -87.9534404754639 -60.1445933977763 0.175027068456014
pnt -87.9548230806986 -60.0900212287903 0.175027068456014
pnt -87.9550152778625 -60.0620187123617 0.175027068456014
pnt -87.9489116032918 -60.0324022928874 0.175027068456014
pnt -87.9241135279338 -59.9791566848755 0.175027068456014
~~ }

View file

@ -0,0 +1,37 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators in a NAV-ONLY file:
~~ NAV:
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~
~~
~~ REMEMBER THAT NAV-ONLY FILES MUST CONTAIN EXACTLY ONE NAV!
~~ }
NAV: nav0 once ~~ {
pnt 48.3606951395671 25.9085505803426 0.231929063796997
pnt 48.3884344100952 25.5719860394796 0.239678192138672
pnt 48.3782159169515 25.5435764312744 0.225020837783813
pnt 48.3625609079997 25.4953356901805 0.225020837783813
pnt 48.3672090530396 25.4595303853353 0.225020837783813
pnt 48.3880900065104 25.4410440921783 0.225020837783813
chk 48.4019992192586 25.4926815191905 0.225020837783813
cht 48.3987060546875 25.4926479816437 0.225020837783813 {/ub give Blank Augmentation Gem to Brienne Carlus}
~~ }

View file

@ -0,0 +1,58 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators in a NAV-ONLY file:
~~ NAV:
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~
~~
~~ REMEMBER THAT NAV-ONLY FILES MUST CONTAIN EXACTLY ONE NAV!
~~ }
NAV: nav0 once ~~ {
rcl -71.8128362019857 -46.2284189224243 2.08333212261399E-05 {Recall to the Singularity Caul}
pnt -94.7016312003136 -97.981881014506 0.367698383331299
ptl -71.8128362019857 -46.2284189224243 2.08333212261399E-05 -94.6987583319346 -98.0068958282471 0.371145516633987 14 {Obsidian Rim Portal}
pnt -65.5345490773519 -48.0928927580516 0.0821696281433106
pnt -66.2971390088399 -48.0919455369314 0.0824445406595866
pnt -68.2659324010213 -47.9679103851318 0.0901949644088745
pnt -68.9330024560293 -47.9617745717367 0.0741503397623698
pnt -68.9996176083883 -47.9868227322896 0.0811579465866089
pnt -69.0741902987162 -47.9962577819824 0.0902631839116414
pnt -69.1185588876406 -48.0084948221842 0.0896445353825887
pnt -69.1932870864868 -48.0247398058573 0.0864912668863932
pnt -69.2399808883667 -48.0406180699666 0.0826785326004028
pnt -69.3729923248291 -48.0507068951925 0.0753742853800456
pnt -69.502007261912 -48.0152909914653 0.0562341809272766
pnt -69.6805796305339 -47.9529766718547 0.00605392009019852
pnt -69.7465653419495 -47.9553860028585 0.000755888223648071
pnt -69.917982506752 -47.9998155911764 0.00417213241259257
pnt -70.4033851623535 -48.1885171890259 0.0103249351183573
pnt -71.328177467982 -48.5185417175293 2.08333212261399E-05
pnt -72.7273258845011 -47.8933919270833 0.0094555139541626
pnt -72.7809668223063 -47.776501083374 0.0289373199144999
pnt -72.7527559280395 -47.166915734609 0.135223134358724
pnt -72.7196399370829 -47.071635723114 0.0760513146718343
pnt -72.7042126337687 -47.0472258249919 0.0588250835736593
pnt -72.6919200261434 -47.0329411188761 0.0555859247843424
pnt -72.5977428436279 -46.9303064982096 0.0106916089852651
pnt -71.9506707509359 -46.338755830129 2.08333212261399E-05
pnt -71.8265404701233 -46.2414363861084 2.08333212261399E-05
ptl -71.8128362019857 -46.2284189224243 2.08333212261399E-05 -71.8083083470662 -46.2096791585286 -0.000262499845121056 14 {Empyrean Facility Upper Level}
~~ }

View file

@ -0,0 +1,51 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators in a NAV-ONLY file:
~~ NAV:
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~
~~
~~ REMEMBER THAT NAV-ONLY FILES MUST CONTAIN EXACTLY ONE NAV!
~~ }
NAV: nav0 once ~~ {
cht 0.675179147720337 13.5718362808228 0.521687507629395 {/ah}
pau 0.675179147720337 13.5718362808228 0.521687507629395 15000
pnt 59.3342878341675 -28.5975779215495 0.0500208298365275
pnt 59.35896803538 -28.6749758720398 0.0500208298365275
pnt 59.37918065389 -28.7118357340495 0.0500208298365275
ptl 0.675179147720337 13.5718362808228 0.521687507629395 59.3936458587647 -28.7256083488464 0.0508250035345554 14 {Portal to Town Network}
pnt -101.617960484823 -96.6229596773783 2.08333134651184E-05
pnt -101.64374332428 -96.6113506952922 2.08333134651184E-05
pnt -101.677829106649 -96.6077419598897 2.08333134651184E-05
pnt -101.708999125163 -96.6393287976583 2.08333134651184E-05
pnt -101.720591862996 -96.644443766276 2.08333134651184E-05
pnt -101.724977588654 -96.6444894790649 2.08333134651184E-05
pnt -101.766201734543 -96.642304166158 2.08333134651184E-05
pnt -101.826050774256 -96.6380467732747 2.08333134651184E-05
pnt -101.873989931742 -96.6189005851746 2.08333134651184E-05
pnt -101.907649771372 -96.5925824801127 2.08333134651184E-05
pnt -101.907772219181 -96.5846062819163 2.08333134651184E-05
ptl 0.675179147720337 13.5718362808228 0.521687507629395 -101.90858749946 -96.5742208321889 -0.000262499845121056 14 {Portal to Zaikhal}
pnt 0.684857130050659 13.498526652654 0.516687520345052
pnt 0.648467270533244 13.6382585525513 0.516687520345052
pnt 0.663638496398926 13.6434263865153 0.516687520345052
tlk 0.675179147720337 13.5718362808228 0.521687507629395 0.675 13.6436941782633 0.516687512397766 37 {Jondor Torgren}
~~ }

View file

@ -0,0 +1,88 @@
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getgamemonthname getminutesuntilnight getgameyear uisetvisible uiviewvisible uiviewexists getgvar touchgvar getpvar touchpvar setgvar cleargvar setpvar clearpvar testgvar clearallgvars testpvar clearallpvars dictgetitem dictcreate dicthaskey dictadditem dictkeys dictremovekey dictvalues dictclear dictsize dictcopy listgetitem listpop listcreate listcontains listremove listadd listindexof listremoveat listinsert listlastindexof listclear listcopy listcount listreverse
~~
~~ File auto-generated by metaf, a program created by Eskarina of Morningthaw/Coldeve.
~~ Get metaf here: https://github.com/JJEII/metaf/
~~
~~ All recognized structural designators in a NAV-ONLY file:
~~ NAV:
~~
~~ All recognized NAV types:
~~ circular follow
~~ linear once
~~
~~ All recognized NAV NODE types:
~~ flw vnd
~~ pnt ptl
~~ rcl tlk
~~ pau chk
~~ cht jmp
~~ prt (deprecated in VTank)
~~
~~
~~ REMEMBER THAT NAV-ONLY FILES MUST CONTAIN EXACTLY ONE NAV!
~~ }
NAV: nav0 once ~~ {
cht 59.3306452433268 -28.5473848342896 0.0500208298365275 {/ub equip load idle.utl}
pau 59.3306452433268 -28.5473848342896 0.0500208298365275 10000
cht 59.3306452433268 -28.5473848342896 0.0500208298365275 {/ub equip load quest.utl}
pau 59.3306452433268 -28.5473848342896 0.0500208298365275 10000
rcl 59.3306452433268 -28.5473848342896 0.0500208298365275 {Primary Portal Recall}
pau 59.3306452433268 -28.5473848342896 0.0500208298365275 2000
pnt -101.643393707275 17.8825289090474 2.08333134651184E-05
cht 59.3306452433268 -28.5473848342896 0.0500208298365275 {/ub jumpsw 300}
pnt -101.592045052846 17.8805678685506 -0.0999791701634725
pnt -101.554651578267 17.8813594023387 -0.0999791701634725
pnt -101.533706283569 17.8833907604218 -0.0999791701634725
pnt -101.534181054433 17.8413492997487 -0.0999791701634725
pnt -101.48626130422 17.841304953893 -0.0999791701634725
pnt -101.490094470978 17.8813687324524 -0.0999791701634725
pnt -101.407286643982 17.884686867396 -0.124979170163473
pnt -101.441320260366 17.801603158315 -0.124979170163473
pnt -101.466675154368 17.7969429810842 -0.124979170163473
pnt -101.516472848256 17.8459821859996 -0.124979170163473
pnt -101.531043752035 17.8853654225667 -0.124979170163473
pnt -101.575432650248 17.8846518675486 -0.124979170163473
pnt -101.575820668538 17.7591938654582 -0.149979162216187
pnt -101.529988797506 17.7609985669454 -0.149979162216187
pnt -101.53424466451 17.8423960208893 -0.174979162216187
pnt -101.583576202393 17.8416724999746 -0.174979162216187
pnt -101.57072356542 17.8728516896566 -0.174979162216187
pnt -101.595848846436 17.8807149728139 -0.174979162216187
cht 59.3306452433268 -28.5473848342896 0.0500208298365275 {/ub jumpsw 300}
pnt -101.622127024333 17.8804373105367 -0.274979146321615
pnt -101.616229724884 17.9339917182922 -0.274979146321615
pnt -101.612587674459 17.9819168567657 -0.296296882629395
pnt -101.615892442067 18.0119011123975 -0.299979146321615
pnt -101.590025297801 18.0101968288422 -0.303131580352783
pnt -101.529243914286 18.0071381568909 -0.324979146321615
pnt -101.53581682841 17.9724334478378 -0.324979146321615
pnt -101.572706063588 17.9642690896988 -0.324979146321615
pnt -101.578296979268 17.9251905759176 -0.324979146321615
pnt -101.61803188324 17.9257889827093 -0.324979146321615
pnt -101.620800844828 17.9667853593826 -0.324979146321615
pnt -101.617472012838 18.0454295317332 -0.349979146321615
pnt -101.660903453827 18.0499082385407 -0.349979146321615
pnt -101.658096440633 17.9865849812826 -0.374979146321615
pnt -101.658587837219 17.9719900369644 -0.374979146321615
pnt -101.69858379364 17.9644167820613 -0.374979146321615
pnt -101.706780131658 17.9288707415263 -0.374979146321615
pnt -101.743702141444 17.921234814326 -0.374979146321615
pnt -101.775855763753 17.9226232131322 -0.374979146321615
pnt -101.784734662374 17.9344542185465 -0.374979146321615
pnt -101.78315264384 18.0072518110275 -0.349979146321615
pnt -101.86580046018 18.008648399512 -0.374979146321615
pnt -101.888455645243 18.0071597099304 -0.374979146321615
cht 59.3306452433268 -28.5473848342896 0.0500208298365275 {/ub jumpsw 300}
pnt -101.913387115796 18.0075169881185 -0.474979146321615
pnt -101.889330867926 18.0084470907847 -0.474979146321615
pnt -101.844996301333 17.9643644889196 -0.474979146321615
pnt -101.825047651927 17.9635365645091 -0.474979146321615
pnt -101.821242467562 17.9419899145762 -0.474979146321615
pnt -101.786994679769 17.9041363716125 -0.474979146321615
pnt -101.782102791468 17.8818953514099 -0.474979146321615
pnt -101.747181431452 17.8816454569499 -0.474979146321615
~~ }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
UTL
1
1
peas
0;3;9999;15
6
true
30
255
255
255
10
0.1
None
SalvageCombine
277
1
1-6, 7-8, 9, 10
25
10
1-10
14
1-10
16
1-10
17
1-10
18
1-10
19
1-10
22
1-10
25
1-10
29
1-10
30
1-10
36
1-10
37
1-10
41
1-10
47
1-10
35
1-10
27
1-10
26
1-10
21
1-10
15
1-10
13
1-10
50
1-10
49
1-10
34
1-10
52
1-10
51
1-10
0

View file

@ -0,0 +1,59 @@
UTL
1
0
SalvageCombine
277
1
1-6, 7-8, 9, 10
25
10
1-10
14
1-10
16
1-10
17
1-10
18
1-10
19
1-10
22
1-10
25
1-10
29
1-10
30
1-10
36
1-10
37
1-10
41
1-10
47
1-10
35
1-10
27
1-10
26
1-10
21
1-10
15
1-10
13
1-10
50
1-10
49
1-10
34
1-10
52
1-10
51
1-10
0

View file

@ -0,0 +1,931 @@
UTL
1
42
(H) 430 Insane
0;1;12;7;2008;2;13
9
44
159
3
1
17
109
1.17
1.17
8
0
171
18
23308
218103849
(H) Axe (OD +10)
0;1;12;12;2003;7;1;2;13
8
3
353
9
44
159
15
84
218103842
3
1
33
Silifi|Lugian|War Axe|Battle
1
8
0
171
18
23308
218103849
(L) Axe (OD +10)
0;1;12;12;2003;7;1;2;13
8
3
353
9
45
159
15
71
218103842
3
1
32
Dolabra|Ono|Hand|War Hammer
1
8
0
171
18
23308
218103849
(F) Axe (OD +10)
0;1;12;12;2003;7;1;2;13
8
3
353
9
46
159
15
71
218103842
3
1
34
Hatchet|Shou-ono|Tungi|Hammer
1
8
0
171
18
23308
218103849
(H) Dagger (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
44
159
15
81
218103842
3
1
9
Dirk
1
8
0
171
18
23308
218103849
(H) Dagger MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
44
159
15
48
218103842
3
1
21
Stiletto|Jambiya
1
8
0
171
18
23308
218103849
(L) Dagger (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
45
159
15
68
218103842
3
1
12
Khanjar
1
8
0
171
18
23308
218103849
(L) Dagger MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
45
159
15
38
218103842
3
1
11
Dagger
1
8
0
171
18
23308
218103849
(F) Dagger (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
46
159
15
68
218103842
3
1
12
Poniard
1
8
0
171
18
23308
218103849
(F) Dagger MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
6
353
9
46
159
15
38
218103842
3
1
17
Knife|Lancet
1
8
0
171
18
23308
218103849
(H) Mace (OD +10)
0;1;12;12;2003;7;1;2;13
8
4
353
9
44
159
15
79
218103842
3
1
24
Mazule|Mace|Morning
1
8
0
171
18
23308
218103849
(L) Mace (OD +10)
0;1;12;12;2003;7;1;2;13
8
4
353
9
45
159
15
66
218103842
3
1
19
Club|Kasrullah
1
8
0
171
18
23308
218103849
(F) Mace (OD +10)
0;1;12;12;2003;7;1;2;13
8
4
353
9
46
159
15
66
218103842
3
1
22
Board|Tofun|Dabus
1
8
0
171
18
23308
218103849
(H) Spear (OD +10)
0;1;12;12;2003;7;1;2;13
8
5
353
9
44
159
15
82
218103842
3
1
28
Glaive|Trident|Partizan
1
8
0
171
18
23308
218103849
(L) Spear (OD +10)
0;1;12;12;2003;7;1;2;13
8
5
353
9
45
159
15
70
218103842
3
1
15
Spear|Yari
1
8
0
171
18
23308
218103849
(F) Spear (OD +10 )
0;1;12;12;2003;7;1;2;13
8
5
353
9
46
159
15
70
218103842
3
1
20
Naginata|Budiaq
1
8
0
171
18
23308
218103849
(H) Staff (OD +10)
0;1;12;12;2003;7;1;2;13
8
7
353
9
44
159
15
79
218103842
3
1
16
Nabut|Stick
1
8
0
171
18
23308
218103849
(L) Staff (OD +10)
0;1;12;12;2003;7;1;2;13
8
7
353
9
45
159
15
67
218103842
3
1
12
Quarter
1
8
0
171
18
23308
218103849
(F) Staff (OD +10)
0;1;12;12;2003;7;1;2;13
8
7
353
9
46
159
15
67
218103842
3
1
15
Jo|Bastone
1
8
0
171
18
23308
218103849
(H) Sword (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
44
159
15
81
218103842
3
1
36
Takuba|Flamberge|Ken|Long|Tachi
1
8
0
171
18
23308
218103849
(H) Sword MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
44
159
15
48
218103842
3
1
13
Schlager
1
8
0
171
18
23308
218103849
(L) Sword (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
45
159
15
68
218103842
3
1
42
Dericost|Broad|Shamshir|Kaskara|Spada
1
8
0
171
18
23308
218103849
(L) Sword MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
45
159
15
37
218103842
3
1
9
Epee
1
8
0
171
18
23308
218103849
(F) Sword (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
46
159
15
68
218103842
3
1
36
Scimitar|Yaoji|Short|Sabra|Simi
1
8
0
171
18
23308
218103849
(F) Sword MS (OD +10)
0;1;12;12;2003;7;1;2;13
8
2
353
9
46
159
15
38
218103842
3
1
11
Rapier
1
8
0
171
18
23308
218103849
(H) UA (OD +10)
0;1;12;12;2003;7;1;2;13
8
1
353
9
44
159
15
69
218103842
3
1
18
Nekode|Cestus
1
8
0
171
18
23308
218103849
(L) UA (OD +10)
0;1;12;12;2003;7;1;2;13
8
1
353
9
45
159
15
58
218103842
3
1
19
Katar|Knuckles
1
8
0
171
18
23308
218103849
(F) UA (OD +10)
0;1;12;12;2003;7;1;2;13
8
1
353
9
46
159
15
58
218103842
3
1
15
Claw|Wraps
1
8
0
171
18
23308
218103849
(2H) Cleaving (OD +10)
0;1;7;2003;12;1;2;13
3
1
15
55
218103842
9
41
159
75
Nodachi|Shashqa|Spadone|Greataxe|Quadrelle|Khanda-handled|Tetsubo|Star
1
8
0
171
18
23308
218103849
(2H) Cleaving (OD +9)
0;1;7;2003;12;1;2;13
3
1
15
54
218103842
9
41
159
75
Nodachi|Shashqa|Spadone|Greataxe|Quadrelle|Khanda-handled|Tetsubo|Star
1
8
0
171
18
23308
218103849
(2H) Cleaving (OD +8)
0;1;7;2003;12;1;2;13
3
1
15
53
218103842
9
41
159
75
Nodachi|Shashqa|Spadone|Greataxe|Quadrelle|Khanda-handled|Tetsubo|Star
1
8
0
171
18
23308
218103849
(2H) Spear (OD +10)
0;1;7;2003;12;1;2;13
3
1
15
58
218103842
9
41
159
33
Assagai|Pike|Magari|Corsesca
1
8
0
171
18
23308
218103849
(M) Bow (OD +10)
0;1;12;7;2001;12;2;13
8
8
353
3
9
6
78.6
9
47
159
8
0
171
18
23308
218103849
(M) Xbow (OD +10)
0;1;12;7;2001;12;2;13
8
9
353
3
9
4
87
9
47
159
8
0
171
18
23308
218103849
(M) TW (OD +10)
0;1;12;7;2001;12;2;13
9
10
353
3
9
6
85.3
9
47
159
8
0
171
18
23308
218103849
(W) No Wield (29MD)
0;1;7;2005;13;13;13;1;13;2;13
4
31
10
1.29
29
10
375
160
10
355
160
10
330
160
27
Orb|Wand|Sceptre|Staff
1
10
385
160
8
0
171
18
23308
218103849
(W) No Wield (28MD)
0;1;7;2005;13;13;13;1;13;2;13
4
31
10
1.28
29
10
375
160
10
355
160
10
330
160
27
Orb|Wand|Sceptre|Staff
1
10
385
160
8
0
171
18
23308
218103849
(W) Void (OD +7)
0;1;7;2005;1;2;13
4
31
11
1.25
152
11
Nether
1
8
0
171
18
23308
218103849
(W) Void (OD +6)
0;1;7;2005;1;2;13
4
31
11
1.24
152
11
Nether
1
8
0
171
18
23308
218103849
(W) Void (20md + 4Mgcd)
0;1;7;5;1;2005;2;13
4
31
11
1.04
150
11
Nether
1
9
1.2
29
8
0
171
18
23308
218103849
(W) Void (29MD)
0;1;7;1;2005;2;13
4
31
11
Nether
1
10
1.29
29
8
0
171
18
23308
218103849
(W) War (OD +7)
0;1;7;2005;1;2;13
4
31
11
1.25
152
24
Baton|Sceptre|Staff
1
8
0
171
18
23308
218103849
SalvageCombine
11
1
0
0

View file

@ -0,0 +1,121 @@
UTL
1
90
***** Trophies *****
0;1;9999;1
6
true
24
leave this disabled
1
0;1;9999
6
true
** Aetheria **
0;1;1
16
do not edit
1
(T) Aetheria (5)
0;1;1;12
13
Aetheria
1
18
27704
218103849
(T) Aetheria (4+)
0;1;1;3
13
Aetheria
1
18
27703
218103849
(T) Aetheria (3+)
0;1;1;3;9999
13
Aetheria
1
18
27702
218103849
6
true
(T) Aetheria (All)
0;1;1;9999
23
Coalesced Aetheria
1
6
true
(T) Aetheria (Red only)
0;1;1;12;9999
23
Coalesced Aetheria
1
18
42636
218103808
6
true
0;1;9999
6
true
** Armor **
0;1;1
16
do not edit
1
(T) Rynthid Masks
0;1;1;7
12
Rynthid
1
3
2
0;1;9999
6
true
** Consumables **
0;1;1
16
do not edit
1
(T) Stamina Philtre
0;1;1
20
Stamina Philtre
1
(T) Health Philtre
0;1;1
19
Health Philtre
1
(T) Mana Philtre
0;1;1;9999
17
Mana Philtre
1
6
true
(T) Stamina Elixir

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,291 @@
1
CondAct
5
CType
AType
CData
AData
State
n
n
n
n
n
11
i
20
i
1
i
0
s
mp_primary
s
Default
i
1
i
2
i
0
s
/mp
s
Default
i
20
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/vt opt set enablenav true
i
1
s
turn_in_jaw
s
jaw_hunt
i
12
i
3
TABLE
2
k
v
n
n
2
s
n
s
Insatiable Eater Jaw
s
c
i
1
TABLE
2
K
V
n
n
1
i
2
s
/vt nav load to_fiun
s
jaw_hunt
i
7
i
3
i
0
TABLE
2
K
V
n
n
4
i
2
s
/vt nav load jaw_1_hunt
i
2
s
/vt opt set enablecombat true
i
2
s
/vt opt set enablelooting true
i
1
s
jaw_hunt
s
jaw_run
i
28
i
3
TABLE
2
k
v
n
n
2
s
p
s
You have solved this quest too recently!
s
c
s
TABLE
2
K
V
n
n
2
i
2
s
/vt nav load recallls
i
2
s
/vt opt set enablelooting false
s
kill_bella
i
1
i
3
i
0
TABLE
2
K
V
n
n
7
i
2
s
/vt nav load mp_primary
i
2
s
/vt opt set enablebuffing true
i
2
s
/vt opt set enablenav true
i
2
s
/vt opt set enablecombat true
i
2
s
/vt opt set enablelooting false
i
2
s
/vt opt set NavPriorityBoost false
i
2
s
/vt opt set navclosestoprange 0.008
s
mp_primary
i
20
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/vt nav load jaw_1
i
1
s
jaw_run
s
mp_primary
i
20
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/vt nav load to_bella
i
1
s
kill_bella
s
mp_secondary
i
20
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/vt nav load mp_secondary
i
1
s
mp_secondary
s
mp_trans
i
4
i
3
s
^Fiun Rehlyun.*
TABLE
2
K
V
n
n
2
i
2
s
/mp
i
1
s
mp_trans
s
turn_in_jaw

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,910 @@
1
CondAct
5
CType
AType
CData
AData
State
n
n
n
n
n
33
i
1
i
3
i
0
TABLE
2
K
V
n
n
2
i
7
TABLE
2
k
v
n
n
1
s
e
s
setvar[mssortstring,`CV,AS,EQ,TR-,OC,IC,AL-,EP,MX-`]
i
1
s
SortManaStones
s
Default
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 7
i
2
s
/ms set ocfilter manastone
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortManaStones
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortHealingKits
s
SortManaStones
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 7
i
2
s
/ms set ocfilter healingkit
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortHealingKits
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortMisc
s
SortHealingKits
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 2
i
2
s
/ms set ocfilter misc
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortMisc
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortGems
s
SortMisc
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 3
i
2
s
/ms set ocfilter gem
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortGems
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortWeapons
s
SortGems
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 1
i
2
s
/ms set ocfilter meleeweapon
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortWeapons
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortWands
s
SortWeapons
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 1
i
2
s
/ms set ocfilter wand
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortWands
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortSpellComps
s
SortWands
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest pack 8
i
2
s
/ms set ocfilter spellcomp
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortSpellComps
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortInventory
s
SortSpellComps
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source player
i
2
s
/ms set dest player
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortInventory
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack1
s
SortInventory
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 1
i
2
s
/ms set dest pack 1
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack1
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack2
s
SortPack1
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 2
i
2
s
/ms set dest pack 2
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack2
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack3
s
SortPack2
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 3
i
2
s
/ms set dest pack 3
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack3
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack4
s
SortPack3
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 4
i
2
s
/ms set dest pack 4
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack4
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack5
s
SortPack4
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 5
i
2
s
/ms set dest pack 5
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack5
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack6
s
SortPack5
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 6
i
2
s
/ms set dest pack 6
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack6
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack7
s
SortPack6
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 7
i
2
s
/ms set dest pack 7
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack7
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
SortPack8
s
SortPack7
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/ms set source pack 8
i
2
s
/ms set dest pack 8
i
2
s
/ms clear ocfilter
i
8
TABLE
2
k
v
n
n
1
s
e
s
`/ms set flags `+getvar[mssortstring]
i
2
s
/ms start
s
SortPack8
i
4
i
1
s
^You think\, \"done sorting\!\"$
s
AllDone
s
SortPack8

View file

@ -0,0 +1,554 @@
1
CondAct
5
CType
AType
CData
AData
State
n
n
n
n
n
42
i
1
i
2
i
0
s
/ub bc /vt setmetastate just_run_back
s
all_run_back
i
1
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/ub bc /ub use Luminous Crystal of Surging Strength
i
1
s
Default
s
strength
i
1
i
2
i
0
s
/ub bc /ub closestportal
s
closestportal
i
1
i
1
i
0
s
Default
s
closestportal
i
1
i
2
i
0
s
/vt nav load death_pause
s
death
i
1
i
2
i
0
s
/vt opt set enablenav true
s
death
i
7
i
1
i
0
s
run_back
s
death
i
1
i
0
i
0
i
0
s
Default
i
8
i
1
i
0
s
death
s
Default
i
1
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/ub bc /ub use Luminous Crystal of Towering Defense
i
1
s
Default
s
defence
i
1
i
3
i
0
TABLE
2
K
V
n
n
2
i
2
s
/ub bc /ub use Black Market Gem of Dispelling
i
1
s
Default
s
dispell
i
1
i
3
i
0
TABLE
2
K
V
n
n
2
i
8
TABLE
2
k
v
n
n
1
s
e
s
\/ub bc \/ub follow +wobjectgetname[wobjectgetplayer[]]
i
2
s
/ub bc /vt opt set enablenav true
s
follow
i
1
i
1
i
0
s
Default
s
follow
i
1
i
2
i
0
s
/ub bc /ub jumpsw 400
s
jump
i
1
i
1
i
0
s
Default
s
jump
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/vt nav load gauntlet_just_run
i
2
s
/vt opt set enablenav true
i
2
s
/vt opt set enablebuffing true
i
2
s
/vt opt set enablemeta true
i
2
s
/vt opt set enablecombat true
s
just_run_back
i
7
i
1
i
0
s
Default
s
just_run_back
i
1
i
2
i
0
s
/ub bc /vt meta load gauntlet_follower
s
load_follow
i
1
i
1
i
0
s
Default
s
load_follow
i
1
i
2
i
0
s
/ub bc /vt opt set enablenav false
s
nav_false
i
1
i
1
i
0
s
Default
s
nav_false
i
1
i
2
i
0
s
/ub bc /vt opt set enablenav true
s
nav_true
i
1
i
1
i
0
s
Default
s
nav_true
i
1
i
3
i
0
TABLE
2
K
V
n
n
5
i
2
s
/vt nav load gauntlet_run
i
2
s
/vt opt set enablenav true
i
2
s
/vt opt set enablebuffing true
i
2
s
/vt opt set enablemeta true
i
2
s
/vt opt set enablecombat true
s
run_back
i
7
i
1
i
0
s
Default
s
run_back
i
1
i
8
i
0
TABLE
2
k
v
n
n
1
s
e
s
\/ub bc \/ub follow +wobjectgetname[wobjectgetplayer[]]
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set enablelooting false
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set enablenav true
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set enablebuffing true
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set enablecombat true
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set attackdistance 0.125
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set navpriorityboost true
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set buffprofile_prots 2
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set buffprofile_banes 2
s
setup
i
1
i
2
i
0
s
/ub bc /vt forcebuff
s
setup
i
1
i
2
i
0
s
/ub bc /vt start
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set enablemeta true
s
setup
i
1
i
1
i
0
s
Default
s
setup
i
1
i
2
i
0
s
/ub bc /vt opt set SummonPets false
s
summon_false
i
1
i
1
i
0
s
Default
s
summon_false
i
1
i
2
i
0
s
/ub bc /vt opt set SummonPets true
s
summon_true
i
1
i
1
i
0
s
Default
s
summon_true

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
uTank2 NAV 1.2
4
13
4
59.1563772201538
-28.5892723083496
0.0500208298365275
0
/ah
3
59.1563772201538
-28.5892723083496
0.0500208298365275
0
22000
4
59.1563772201538
-28.5892723083496
0.0500208298365275
0
/tell Time according to alex, ab
3
59.1563772201538
-28.5892723083496
0.0500208298365275
0
30000
4
59.1563772201538
-28.5892723083496
0.0500208298365275
0
/ub use Gateway
0
-87.9797062555949
-60.4362569173177
0.265733496348063
0
0
-87.9643449147542
-60.3346110810836
0.230621592203776
0
0
-87.9498847007751
-60.1938330491384
0.185985358556112
0
0
-87.9534404754639
-60.1445933977763
0.175027068456014
0
0
-87.9548230806986
-60.0900212287903
0.175027068456014
0
0
-87.9550152778625
-60.0620187123617
0.175027068456014
0
0
-87.9489116032918
-60.0324022928874
0.175027068456014
0
0
-87.9241135279338
-59.9791566848755
0.175027068456014
0

View file

@ -0,0 +1,44 @@
uTank2 NAV 1.2
4
8
0
48.3606951395671
25.9085505803426
0.231929063796997
0
0
48.3884344100952
25.5719860394796
0.239678192138672
0
0
48.3782159169515
25.5435764312744
0.225020837783813
0
0
48.3625609079997
25.4953356901805
0.225020837783813
0
0
48.3672090530396
25.4595303853353
0.225020837783813
0
0
48.3880900065104
25.4410440921783
0.225020837783813
0
8
48.4019992192586
25.4926815191905
0.225020837783813
0
4
48.3987060546875
25.4926479816437
0.225020837783813
0
/ub give Blank Augmentation Gem to Brienne Carlus

View file

@ -0,0 +1,161 @@
uTank2 NAV 1.2
4
29
2
-71.8128362019857
-46.2284189224243
2.08333212261399E-05
0
2943
0
-94.7016312003136
-97.981881014506
0.367698383331299
0
6
-71.8128362019857
-46.2284189224243
2.08333212261399E-05
0
Obsidian Rim Portal
14
True
-94.6987583319346
-98.0068958282471
0.371145516633987
0
-65.5345490773519
-48.0928927580516
0.0821696281433106
0
0
-66.2971390088399
-48.0919455369314
0.0824445406595866
0
0
-68.2659324010213
-47.9679103851318
0.0901949644088745
0
0
-68.9330024560293
-47.9617745717367
0.0741503397623698
0
0
-68.9996176083883
-47.9868227322896
0.0811579465866089
0
0
-69.0741902987162
-47.9962577819824
0.0902631839116414
0
0
-69.1185588876406
-48.0084948221842
0.0896445353825887
0
0
-69.1932870864868
-48.0247398058573
0.0864912668863932
0
0
-69.2399808883667
-48.0406180699666
0.0826785326004028
0
0
-69.3729923248291
-48.0507068951925
0.0753742853800456
0
0
-69.502007261912
-48.0152909914653
0.0562341809272766
0
0
-69.6805796305339
-47.9529766718547
0.00605392009019852
0
0
-69.7465653419495
-47.9553860028585
0.000755888223648071
0
0
-69.917982506752
-47.9998155911764
0.00417213241259257
0
0
-70.4033851623535
-48.1885171890259
0.0103249351183573
0
0
-71.328177467982
-48.5185417175293
2.08333212261399E-05
0
0
-72.7273258845011
-47.8933919270833
0.0094555139541626
0
0
-72.7809668223063
-47.776501083374
0.0289373199144999
0
0
-72.7527559280395
-47.166915734609
0.135223134358724
0
0
-72.7196399370829
-47.071635723114
0.0760513146718343
0
0
-72.7042126337687
-47.0472258249919
0.0588250835736593
0
0
-72.6919200261434
-47.0329411188761
0.0555859247843424
0
0
-72.5977428436279
-46.9303064982096
0.0106916089852651
0
0
-71.9506707509359
-46.338755830129
2.08333212261399E-05
0
0
-71.8265404701233
-46.2414363861084
2.08333212261399E-05
0
6
-71.8128362019857
-46.2284189224243
2.08333212261399E-05
0
Empyrean Facility Upper Level
14
True
-71.8083083470662
-46.2096791585286
-0.000262499845121056

View file

@ -0,0 +1,133 @@
uTank2 NAV 1.2
4
22
4
0.675179147720337
13.5718362808228
0.521687507629395
0
/ah
3
0.675179147720337
13.5718362808228
0.521687507629395
0
15000
0
59.3342878341675
-28.5975779215495
0.0500208298365275
0
0
59.35896803538
-28.6749758720398
0.0500208298365275
0
0
59.37918065389
-28.7118357340495
0.0500208298365275
0
6
0.675179147720337
13.5718362808228
0.521687507629395
0
Portal to Town Network
14
True
59.3936458587647
-28.7256083488464
0.0508250035345554
0
-101.617960484823
-96.6229596773783
2.08333134651184E-05
0
0
-101.64374332428
-96.6113506952922
2.08333134651184E-05
0
0
-101.677829106649
-96.6077419598897
2.08333134651184E-05
0
0
-101.708999125163
-96.6393287976583
2.08333134651184E-05
0
0
-101.720591862996
-96.644443766276
2.08333134651184E-05
0
0
-101.724977588654
-96.6444894790649
2.08333134651184E-05
0
0
-101.766201734543
-96.642304166158
2.08333134651184E-05
0
0
-101.826050774256
-96.6380467732747
2.08333134651184E-05
0
0
-101.873989931742
-96.6189005851746
2.08333134651184E-05
0
0
-101.907649771372
-96.5925824801127
2.08333134651184E-05
0
0
-101.907772219181
-96.5846062819163
2.08333134651184E-05
0
6
0.675179147720337
13.5718362808228
0.521687507629395
0
Portal to Zaikhal
14
True
-101.90858749946
-96.5742208321889
-0.000262499845121056
0
0.684857130050659
13.498526652654
0.516687520345052
0
0
0.648467270533244
13.6382585525513
0.516687520345052
0
0
0.663638496398926
13.6434263865153
0.516687520345052
0
7
0.675179147720337
13.5718362808228
0.521687507629395
0
Jondor Torgren
37
True
0.675
13.6436941782633
0.516687512397766

View file

@ -0,0 +1,307 @@
uTank2 NAV 1.2
4
59
4
59.3306452433268
-28.5473848342896
0.0500208298365275
0
/ub equip load idle.utl
3
59.3306452433268
-28.5473848342896
0.0500208298365275
0
10000
4
59.3306452433268
-28.5473848342896
0.0500208298365275
0
/ub equip load quest.utl
3
59.3306452433268
-28.5473848342896
0.0500208298365275
0
10000
2
59.3306452433268
-28.5473848342896
0.0500208298365275
0
48
3
59.3306452433268
-28.5473848342896
0.0500208298365275
0
2000
0
-101.643393707275
17.8825289090474
2.08333134651184E-05
0
4
59.3306452433268
-28.5473848342896
0.0500208298365275
0
/ub jumpsw 300
0
-101.592045052846
17.8805678685506
-0.0999791701634725
0
0
-101.554651578267
17.8813594023387
-0.0999791701634725
0
0
-101.533706283569
17.8833907604218
-0.0999791701634725
0
0
-101.534181054433
17.8413492997487
-0.0999791701634725
0
0
-101.48626130422
17.841304953893
-0.0999791701634725
0
0
-101.490094470978
17.8813687324524
-0.0999791701634725
0
0
-101.407286643982
17.884686867396
-0.124979170163473
0
0
-101.441320260366
17.801603158315
-0.124979170163473
0
0
-101.466675154368
17.7969429810842
-0.124979170163473
0
0
-101.516472848256
17.8459821859996
-0.124979170163473
0
0
-101.531043752035
17.8853654225667
-0.124979170163473
0
0
-101.575432650248
17.8846518675486
-0.124979170163473
0
0
-101.575820668538
17.7591938654582
-0.149979162216187
0
0
-101.529988797506
17.7609985669454
-0.149979162216187
0
0
-101.53424466451
17.8423960208893
-0.174979162216187
0
0
-101.583576202393
17.8416724999746
-0.174979162216187
0
0
-101.57072356542
17.8728516896566
-0.174979162216187
0
0
-101.595848846436
17.8807149728139
-0.174979162216187
0
4
59.3306452433268
-28.5473848342896
0.0500208298365275
0
/ub jumpsw 300
0
-101.622127024333
17.8804373105367
-0.274979146321615
0
0
-101.616229724884
17.9339917182922
-0.274979146321615
0
0
-101.612587674459
17.9819168567657
-0.296296882629395
0
0
-101.615892442067
18.0119011123975
-0.299979146321615
0
0
-101.590025297801
18.0101968288422
-0.303131580352783
0
0
-101.529243914286
18.0071381568909
-0.324979146321615
0
0
-101.53581682841
17.9724334478378
-0.324979146321615
0
0
-101.572706063588
17.9642690896988
-0.324979146321615
0
0
-101.578296979268
17.9251905759176
-0.324979146321615
0
0
-101.61803188324
17.9257889827093
-0.324979146321615
0
0
-101.620800844828
17.9667853593826
-0.324979146321615
0
0
-101.617472012838
18.0454295317332
-0.349979146321615
0
0
-101.660903453827
18.0499082385407
-0.349979146321615
0
0
-101.658096440633
17.9865849812826
-0.374979146321615
0
0
-101.658587837219
17.9719900369644
-0.374979146321615
0
0
-101.69858379364
17.9644167820613
-0.374979146321615
0
0
-101.706780131658
17.9288707415263
-0.374979146321615
0
0
-101.743702141444
17.921234814326
-0.374979146321615
0
0
-101.775855763753
17.9226232131322
-0.374979146321615
0
0
-101.784734662374
17.9344542185465
-0.374979146321615
0
0
-101.78315264384
18.0072518110275
-0.349979146321615
0
0
-101.86580046018
18.008648399512
-0.374979146321615
0
0
-101.888455645243
18.0071597099304
-0.374979146321615
0
4
59.3306452433268
-28.5473848342896
0.0500208298365275
0
/ub jumpsw 300
0
-101.913387115796
18.0075169881185
-0.474979146321615
0
0
-101.889330867926
18.0084470907847
-0.474979146321615
0
0
-101.844996301333
17.9643644889196
-0.474979146321615
0
0
-101.825047651927
17.9635365645091
-0.474979146321615
0
0
-101.821242467562
17.9419899145762
-0.474979146321615
0
0
-101.786994679769
17.9041363716125
-0.474979146321615
0
0
-101.782102791468
17.8818953514099
-0.474979146321615
0
0
-101.747181431452
17.8816454569499
-0.474979146321615
0

View file

@ -0,0 +1,12 @@
1
Spells
4
SpellID
EndTime
Target
CastTime
n
n
n
n
0

View file

@ -0,0 +1,14 @@
1
CondAct
5
CType
AType
CData
AData
State
n
n
n
n
n
0

View file

@ -0,0 +1,3 @@
uTank2 NAV 1.2
1
0

View file

@ -0,0 +1,468 @@
8
AntiExtraBuffSpells
1
ExemplarId
n
0
AssistItems
2
Object
Type
n
n
2
s
Bread
i
3
s
Handy Healing Kit
i
0
BuffedItems
2
Object
Spell
n
n
11
i
-2147482735
i
1599
i
-2147482735
i
35
i
-2147482735
i
49
i
-2147482735
i
1587
i
-2147482739
i
1599
i
-2147482739
i
1475
i
-2147482739
i
3253
i
-2147482734
i
1599
i
-2147482734
i
35
i
-2147482734
i
49
i
-2147482734
i
1587
ExtraBuffSpells
1
ExemplarId
n
0
GemFoodItems
2
Name
Spell
n
n
2
s
Asheron's Benediction
i
3810
s
Blackmoor's Favor
i
3811
ItemUseSpecifiers
2
Object
Uses
y
n
0
MyMonsters
21
MonsterName
AttackPriority
DamageType
WeaponToUse
Imperil
Vuln
Yield
GravityW
Attack
Ring
Broadside
Fester
WeakeningCurse
FesteringCurse
Corruption
DestructiveCurse
Corrosion
Streak
SecondaryVuln
SecondaryEquip
PetDamageType
y
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
1
s
<DEFAULT>
i
1
i
8
i
-1
b
False
b
False
b
False
b
False
b
True
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
True
i
98
i
0
i
101
Settings
2
Setting
Value
y
n
1
s
RechargeHandlerSet
TABLE
5
Vital
HandlerString
MinPercent
MaxPercent
Stance
n
n
n
n
n
26
i
1
s
Stamina to Health
i
0
i
15
i
1
i
1
s
Mana to Health
i
0
i
15
i
1
i
1
s
Regular Spell
i
0
i
15
i
1
i
1
s
Recharge With Food
i
0
i
15
i
1
i
1
s
Kit Recharge
i
0
i
100
i
1
i
1
s
Stamina to Health
i
0
i
100
i
1
i
1
s
Mana to Health
i
0
i
100
i
1
i
1
s
Regular Spell
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
15
i
2
i
1
s
Kit Recharge
i
0
i
100
i
2
i
1
s
Recharge With Food
i
0
i
100
i
2
i
1
s
Stamina to Health
i
0
i
10
i
2
i
1
s
Regular Spell
i
0
i
100
i
2
i
2
s
Kit Recharge
i
0
i
100
i
1
i
2
s
Regular Spell
i
0
i
100
i
1
i
2
s
Recharge With Food
i
0
i
100
i
1
i
2
s
Kit Recharge
i
0
i
100
i
2
i
2
s
Recharge With Food
i
0
i
100
i
2
i
2
s
Regular Spell
i
0
i
100
i
2
i
3
s
Kit Recharge
i
0
i
100
i
1
i
3
s
Recharge With Food
i
0
i
100
i
1
i
3
s
Regular Spell
i
0
i
100
i
1
i
3
s
Kit Recharge
i
0
i
100
i
2
i
3
s
Recharge With Food
i
0
i
100
i
2
i
3
s
Regular Spell
i
0
i
100
i
2

View file

@ -0,0 +1,12 @@
1
Spells
4
SpellID
EndTime
Target
CastTime
n
n
n
n
0

View file

@ -0,0 +1,424 @@
8
AntiExtraBuffSpells
1
ExemplarId
n
0
AssistItems
2
Object
Type
n
n
2
s
Adept Healing Kit
i
0
s
Bread
i
3
BuffedItems
2
Object
Spell
n
n
0
ExtraBuffSpells
1
ExemplarId
n
0
GemFoodItems
2
Name
Spell
n
n
2
s
Asheron's Benediction
i
3810
s
Blackmoor's Favor
i
3811
ItemUseSpecifiers
2
Object
Uses
y
n
0
MyMonsters
21
MonsterName
AttackPriority
DamageType
WeaponToUse
Imperil
Vuln
Yield
GravityW
Attack
Ring
Broadside
Fester
WeakeningCurse
FesteringCurse
Corruption
DestructiveCurse
Corrosion
Streak
SecondaryVuln
SecondaryEquip
PetDamageType
y
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
1
s
<DEFAULT>
i
1
i
8
i
-1
b
False
b
False
b
False
b
False
b
True
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
True
i
98
i
0
i
101
Settings
2
Setting
Value
y
n
1
s
RechargeHandlerSet
TABLE
5
Vital
HandlerString
MinPercent
MaxPercent
Stance
n
n
n
n
n
26
i
1
s
Stamina to Health
i
0
i
15
i
1
i
1
s
Mana to Health
i
0
i
15
i
1
i
1
s
Regular Spell
i
0
i
15
i
1
i
1
s
Recharge With Food
i
0
i
15
i
1
i
1
s
Kit Recharge
i
0
i
100
i
1
i
1
s
Stamina to Health
i
0
i
100
i
1
i
1
s
Mana to Health
i
0
i
100
i
1
i
1
s
Regular Spell
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
15
i
2
i
1
s
Kit Recharge
i
0
i
100
i
2
i
1
s
Recharge With Food
i
0
i
100
i
2
i
1
s
Stamina to Health
i
0
i
10
i
2
i
1
s
Regular Spell
i
0
i
100
i
2
i
2
s
Kit Recharge
i
0
i
100
i
1
i
2
s
Regular Spell
i
0
i
100
i
1
i
2
s
Recharge With Food
i
0
i
100
i
1
i
2
s
Kit Recharge
i
0
i
100
i
2
i
2
s
Recharge With Food
i
0
i
100
i
2
i
2
s
Regular Spell
i
0
i
100
i
2
i
3
s
Kit Recharge
i
0
i
100
i
1
i
3
s
Recharge With Food
i
0
i
100
i
1
i
3
s
Regular Spell
i
0
i
100
i
1
i
3
s
Kit Recharge
i
0
i
100
i
2
i
3
s
Recharge With Food
i
0
i
100
i
2
i
3
s
Regular Spell
i
0
i
100
i
2

View file

@ -0,0 +1,12 @@
1
Spells
4
SpellID
EndTime
Target
CastTime
n
n
n
n
0

View file

@ -0,0 +1,468 @@
8
AntiExtraBuffSpells
1
ExemplarId
n
0
AssistItems
2
Object
Type
n
n
1
s
Mana Draught
i
5
BuffedItems
2
Object
Spell
n
n
10
i
-2147465511
i
1599
i
-2147465511
i
35
i
-2147465511
i
49
i
-2147465511
i
1587
i
-2147465453
i
1599
i
-2147465453
i
1475
i
-2147465453
i
3253
i
-2147482575
i
1599
i
-2147482575
i
35
i
-2147482575
i
49
ExtraBuffSpells
1
ExemplarId
n
0
GemFoodItems
2
Name
Spell
n
n
4
s
Asheron's Benediction
i
3810
s
Blackmoor's Favor
i
3811
s
White Sapphire
i
2053
s
Tourmaline
i
169
ItemUseSpecifiers
2
Object
Uses
y
n
0
MyMonsters
21
MonsterName
AttackPriority
DamageType
WeaponToUse
Imperil
Vuln
Yield
GravityW
Attack
Ring
Broadside
Fester
WeakeningCurse
FesteringCurse
Corruption
DestructiveCurse
Corrosion
Streak
SecondaryVuln
SecondaryEquip
PetDamageType
y
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
n
1
s
<DEFAULT>
i
1
i
8
i
-1
b
False
b
False
b
False
b
False
b
True
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
False
b
True
i
98
i
0
i
101
Settings
2
Setting
Value
y
n
1
s
RechargeHandlerSet
TABLE
5
Vital
HandlerString
MinPercent
MaxPercent
Stance
n
n
n
n
n
26
i
1
s
Stamina to Health
i
0
i
15
i
1
i
1
s
Mana to Health
i
0
i
15
i
1
i
1
s
Regular Spell
i
0
i
15
i
1
i
1
s
Recharge With Food
i
0
i
15
i
1
i
1
s
Kit Recharge
i
0
i
100
i
1
i
1
s
Stamina to Health
i
0
i
100
i
1
i
1
s
Mana to Health
i
0
i
100
i
1
i
1
s
Regular Spell
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
100
i
1
i
1
s
Recharge With Food
i
0
i
15
i
2
i
1
s
Kit Recharge
i
0
i
100
i
2
i
1
s
Recharge With Food
i
0
i
100
i
2
i
1
s
Stamina to Health
i
0
i
10
i
2
i
1
s
Regular Spell
i
0
i
100
i
2
i
2
s
Kit Recharge
i
0
i
100
i
1
i
2
s
Regular Spell
i
0
i
100
i
1
i
2
s
Recharge With Food
i
0
i
100
i
1
i
2
s
Kit Recharge
i
0
i
100
i
2
i
2
s
Recharge With Food
i
0
i
100
i
2
i
2
s
Regular Spell
i
0
i
100
i
2
i
3
s
Kit Recharge
i
0
i
100
i
1
i
3
s
Recharge With Food
i
0
i
100
i
1
i
3
s
Regular Spell
i
0
i
100
i
1
i
3
s
Kit Recharge
i
0
i
100
i
2
i
3
s
Recharge With Food
i
0
i
100
i
2
i
3
s
Regular Spell
i
0
i
100
i
2

View file

@ -0,0 +1,440 @@
using AcDream.Plugin.Abstractions;
namespace AcDream.Plugins.MossTank.Tests;
public sealed class MetafSerializerTests
{
private static readonly string FixturesRoot = Path.Combine(
AppContext.BaseDirectory, "Fixtures", "vtank");
private static string[] AllAfFixtures() => Directory.GetFiles(
Path.Combine(FixturesRoot, "af"), "*.af");
private static string[] NavOnlyAfFixtures() => Directory.GetFiles(
Path.Combine(FixturesRoot, "af"), "nav_*.af");
private static string[] MetaAfFixtures() => Directory.GetFiles(
Path.Combine(FixturesRoot, "af"), "*.af")
.Where(static path => !Path.GetFileName(path).StartsWith(
"nav_", StringComparison.Ordinal))
.ToArray();
public static TheoryData<string> AllAfFixtureData()
{
var data = new TheoryData<string>();
foreach (string path in AllAfFixtures())
data.Add(path);
return data;
}
public static TheoryData<string> MetaAfFixtureData()
{
var data = new TheoryData<string>();
foreach (string path in MetaAfFixtures())
data.Add(path);
return data;
}
public static TheoryData<string> NavOnlyAfFixtureData()
{
var data = new TheoryData<string>();
foreach (string path in NavOnlyAfFixtures())
data.Add(path);
return data;
}
// Proof (1): every .af under the fixture set parses without error.
[Theory]
[MemberData(nameof(MetaAfFixtureData))]
public void EveryMetaAfFixtureParses(string path)
{
string text = File.ReadAllText(path);
Assert.True(
MetafSerializer.TryLoadMeta(text, NoOpSpellCatalog.Instance, out MetaProfile profile, out string error),
$"{Path.GetFileName(path)}: {error}");
Assert.NotEmpty(profile.Rules);
}
[Theory]
[MemberData(nameof(NavOnlyAfFixtureData))]
public void EveryNavOnlyAfFixtureParses(string path)
{
string text = File.ReadAllText(path);
var target = new NavigationSettings();
Assert.True(
MetafSerializer.TryLoadNav(text, target, NoOpSpellCatalog.Instance, out string error),
$"{Path.GetFileName(path)}: {error}");
}
// Proof (2): parse -> write -> parse is identical (model equality; the
// writer's own byte-for-byte shape is proof (4), below).
[Theory]
[MemberData(nameof(MetaAfFixtureData))]
public void MetaParseWriteParseIsIdentical(string path)
{
string text = File.ReadAllText(path);
Assert.True(MetafSerializer.TryLoadMeta(
text, NoOpSpellCatalog.Instance, out MetaProfile first, out string error1), error1);
string rewritten = MetafSerializer.SaveMeta(first);
Assert.True(MetafSerializer.TryLoadMeta(
rewritten, NoOpSpellCatalog.Instance, out MetaProfile second, out string error2), error2);
AssertProfilesEqual(first, second);
}
[Theory]
[MemberData(nameof(NavOnlyAfFixtureData))]
public void NavParseWriteParseIsIdentical(string path)
{
string text = File.ReadAllText(path);
var first = new NavigationSettings();
Assert.True(MetafSerializer.TryLoadNav(
text, first, NoOpSpellCatalog.Instance, out string error1), error1);
string rewritten = MetafSerializer.SaveNav(first);
var second = new NavigationSettings();
Assert.True(MetafSerializer.TryLoadNav(
rewritten, second, NoOpSpellCatalog.Instance, out string error2), error2);
AssertNavigationEqual(first, second);
}
// Proof (3): for the met/ and nav/ samples that have a matching af/
// conversion, our model loaded from the binary import path equals our
// model loaded from metaf's own .af conversion.
public static TheoryData<string, string> MetMatchingAfPairs()
{
var data = new TheoryData<string, string>();
string metDir = Path.Combine(FixturesRoot, "met");
string afDir = Path.Combine(FixturesRoot, "af");
foreach (string metPath in Directory.GetFiles(metDir, "*.met"))
{
string name = Path.GetFileNameWithoutExtension(metPath);
string afPath = Path.Combine(afDir, name + ".af");
if (File.Exists(afPath))
data.Add(metPath, afPath);
}
return data;
}
[Theory]
[MemberData(nameof(MetMatchingAfPairs))]
public void BinaryImportMatchesMetafAfConversion(string metPath, string afPath)
{
string metText = File.ReadAllText(metPath);
Assert.True(
VtankMetaProfileSerializer.TryLoad(metText, out MetaProfile fromMet, out string metError),
$"{Path.GetFileName(metPath)}: {metError}");
string afText = File.ReadAllText(afPath);
Assert.True(
MetafSerializer.TryLoadMeta(afText, NoOpSpellCatalog.Instance, out MetaProfile fromAf, out string afError),
$"{Path.GetFileName(afPath)}: {afError}");
AssertProfilesEqual(fromMet, fromAf);
}
public static TheoryData<string, string> NavMatchingAfPairs()
{
var data = new TheoryData<string, string>();
string navDir = Path.Combine(FixturesRoot, "nav");
string afDir = Path.Combine(FixturesRoot, "af");
foreach (string navPath in Directory.GetFiles(navDir, "*.nav"))
{
string name = Path.GetFileNameWithoutExtension(navPath);
string afPath = Path.Combine(afDir, name + ".af");
if (File.Exists(afPath))
data.Add(navPath, afPath);
}
return data;
}
[Theory]
[MemberData(nameof(NavMatchingAfPairs))]
public void BinaryNavImportMatchesMetafAfConversion(string navPath, string afPath)
{
string navText = File.ReadAllText(navPath);
var fromNav = new NavigationSettings();
Assert.True(
VtankNavRouteSerializer.TryLoad(navText, fromNav, NoOpSpellCatalog.Instance, out string navError),
$"{Path.GetFileName(navPath)}: {navError}");
string afText = File.ReadAllText(afPath);
var fromAf = new NavigationSettings();
Assert.True(
MetafSerializer.TryLoadNav(afText, fromAf, NoOpSpellCatalog.Instance, out string afError),
$"{Path.GetFileName(afPath)}: {afError}");
AssertNavigationEqual(fromNav, fromAf);
}
// Proof (4): the writer's output is byte-identical to metaf's own
// canonical emission for at least five fixtures, after stripping "~~"
// comments (metaf's own auto-completion header and any inline
// annotations do not survive a parse -> model -> write round trip
// either, on the real metaf tool — confirmed empirically by feeding
// met/aphus.met through `py metaf_monolithic.py` twice during
// authoring: the only diff against the committed af/aphus.af fixture
// was two dropped inline "~~" comments and a trailing-newline nit).
public static TheoryData<string> ByteIdenticalFixtureData()
{
var data = new TheoryData<string>();
// bore_enhanced.af is committed but was hand-edited after generation
// (some IF:/DO: lines use a space instead of metaf's own tab
// separator, confirmed by diffing it against metaf's own
// af->met->af canonical round-trip during authoring) — excluded
// from this byte-identity proof for that reason; it still exercises
// every other proof (parse, parse-write-parse) normally.
//
// aphus.af, augments.af, lockandkey.af, and neftet.af are also
// excluded here: all four embed a "ptl"/"tlk" nav node inside an
// EmbedNav route, and this port's RouteWaypoint (pre-existing,
// shared with the binary VtankNavRouteSerializer) has a single
// Position field — matching VtankNavRouteSerializer's own
// established case-6/7 behavior of overwriting the "approach" xyz
// with the "reference" xyz on load. metaf's own model keeps both
// sets distinct, so a byte-identical round trip is architecturally
// impossible without widening RouteWaypoint, which is out of this
// slice's scope. All four still pass every other proof (parse,
// parse-write-parse, binary-vs-af model equality where a .met
// counterpart exists).
foreach (string name in new[]
{
"bella", "hunting", "gauntlet_leader", "empyrean_facility", "follower",
})
{
data.Add(Path.Combine(FixturesRoot, "af", name + ".af"));
}
return data;
}
[Theory]
[MemberData(nameof(ByteIdenticalFixtureData))]
public void WriterOutputMatchesMetafCanonicalEmission(string path)
{
string original = File.ReadAllText(path);
Assert.True(
MetafSerializer.TryLoadMeta(original, NoOpSpellCatalog.Instance, out MetaProfile profile, out string error),
error);
string rewritten = MetafSerializer.SaveMeta(profile);
string expected = StripComments(original);
string actual = StripComments(rewritten);
Assert.Equal(expected, actual);
}
private static string StripComments(string text)
{
var kept = new List<string>();
foreach (string rawLine in text.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n'))
{
string line = rawLine.TrimEnd();
if (line.TrimStart().StartsWith("~~", StringComparison.Ordinal))
continue;
int commentIndex = line.IndexOf("~~", StringComparison.Ordinal);
string trimmed = (commentIndex >= 0 ? line[..commentIndex] : line).TrimEnd();
if (trimmed.Length != 0)
kept.Add(trimmed);
}
return string.Join("\n", kept);
}
[Fact]
public void ExampleSortMetaBinaryImportMatchesAf()
{
string metText = File.ReadAllText(Path.Combine(FixturesRoot, "met", "example_sort_meta.met"));
Assert.True(VtankMetaProfileSerializer.TryLoad(metText, out MetaProfile fromMet, out string metError), metError);
string afText = File.ReadAllText(Path.Combine(FixturesRoot, "af", "example_sort_meta.af"));
Assert.True(
MetafSerializer.TryLoadMeta(afText, NoOpSpellCatalog.Instance, out MetaProfile fromAf, out string afError),
afError);
AssertProfilesEqual(fromMet, fromAf);
}
[Fact]
public void NestedAllAnyNotParsesCorrectly()
{
string af = string.Join("\r\n",
[
"STATE: {Default}",
"\tIF:\tAll",
"\t\t\tAlways",
"\t\t\tNot Death",
"\t\t\tAny",
"\t\t\t\tVendorOpen",
"\t\t\t\tVendorClosed",
"\t\tDO:\tDoAll",
"\t\t\t\tChat {hello}",
"\t\t\t\tSetState {Next}",
]) + "\r\n";
Assert.True(
MetafSerializer.TryLoadMeta(af, NoOpSpellCatalog.Instance, out MetaProfile profile, out string error),
error);
MetaRule rule = Assert.Single(profile.Rules);
Assert.Equal(MetaConditionKind.All, rule.Condition.Kind);
Assert.Equal(3, rule.Condition.Children.Count);
Assert.Equal(MetaConditionKind.Always, rule.Condition.Children[0].Kind);
Assert.Equal(MetaConditionKind.Not, rule.Condition.Children[1].Kind);
Assert.Equal(MetaConditionKind.CharacterDeath, rule.Condition.Children[1].Children[0].Kind);
Assert.Equal(MetaConditionKind.Any, rule.Condition.Children[2].Kind);
Assert.Equal(2, rule.Condition.Children[2].Children.Count);
Assert.Equal(MetaActionKind.All, rule.Action.Kind);
Assert.Equal(2, rule.Action.Children.Count);
Assert.Equal("hello", rule.Action.Children[0].Text);
Assert.Equal("Next", rule.Action.Children[1].Text);
}
[Fact]
public void SynthesizedGetOptFollowAndJumpFixtureRoundTrips()
{
// GetOpt, the "flw" nav node, and "jmp" never appear in any real
// fixture in metas/af (grep confirmed at slice-1 authoring time), so
// this small hand-authored fixture exercises them — validated as
// real metaf grammar via `py metaf_monolithic.py` during authoring
// (not re-run automatically here, since python is not guaranteed on
// the Ubuntu portable CI lane).
string af = string.Join("\r\n",
[
"STATE: {Default}",
"\tIF:\tAlways",
"\t\tDO:\tDoAll",
"\t\t\t\tGetOpt {AttackDistance} {myvar}",
"\t\t\t\tSetOpt {AttackDistance} {myvar}",
"NAV: myfollow follow",
"\tflw 00001234 {Some Monster}",
]) + "\r\n";
Assert.True(
MetafSerializer.TryLoadMeta(af, NoOpSpellCatalog.Instance, out MetaProfile profile, out string error),
error);
MetaRule rule = Assert.Single(profile.Rules);
MetaAction getOpt = rule.Action.Children[0];
MetaAction setOpt = rule.Action.Children[1];
Assert.Equal(MetaActionKind.GetVtankOption, getOpt.Kind);
Assert.Equal("AttackDistance", getOpt.Text);
Assert.Equal("myvar", getOpt.SecondaryText);
Assert.Equal(MetaActionKind.SetVtankOption, setOpt.Kind);
var nav = new NavigationSettings();
Assert.True(
MetafSerializer.TryLoadNav(af, nav, NoOpSpellCatalog.Instance, out string navError),
navError);
Assert.Equal(RouteMode.Target, nav.Mode);
Assert.Equal(0x00001234u, nav.FollowTargetObjectId);
Assert.Equal("Some Monster", nav.FollowTargetName);
}
[Fact]
public void JumpNodeClampsChargeMillisecondsTo2000()
{
const string af = """
NAV: j once
jmp 1 2 3 90 {True} 5000
""";
var target = new NavigationSettings();
Assert.True(MetafSerializer.TryLoadNav(af, target, NoOpSpellCatalog.Instance, out string error), error);
RouteWaypoint waypoint = Assert.Single(target.Waypoints);
Assert.Equal(RouteWaypointType.Jump, waypoint.Type);
Assert.Equal(2000, waypoint.JumpChargeMilliseconds);
Assert.True(waypoint.JumpRun);
Assert.Equal(90f, waypoint.JumpHeadingDegrees);
}
[Fact]
public void JumpNodeBelowClampPassesThroughUnchanged()
{
const string af = """
NAV: j once
jmp 1 2 3 90 {False} 500
""";
var target = new NavigationSettings();
Assert.True(MetafSerializer.TryLoadNav(af, target, NoOpSpellCatalog.Instance, out string error), error);
RouteWaypoint waypoint = Assert.Single(target.Waypoints);
Assert.Equal(500, waypoint.JumpChargeMilliseconds);
Assert.False(waypoint.JumpRun);
}
private static void AssertProfilesEqual(MetaProfile expected, MetaProfile actual)
{
Assert.Equal(expected.Rules.Count, actual.Rules.Count);
for (int i = 0; i < expected.Rules.Count; i++)
{
MetaRule a = expected.Rules[i];
MetaRule b = actual.Rules[i];
Assert.Equal(a.State, b.State);
AssertConditionsEqual(a.Condition, b.Condition);
AssertActionsEqual(a.Action, b.Action);
}
}
private static void AssertConditionsEqual(MetaCondition expected, MetaCondition actual)
{
Assert.Equal(expected.Kind, actual.Kind);
Assert.Equal(expected.Text, actual.Text);
Assert.Equal(expected.SecondaryText, actual.SecondaryText);
Assert.Equal(expected.Number, actual.Number, 6);
Assert.Equal(expected.SecondaryNumber, actual.SecondaryNumber, 6);
Assert.Equal(expected.TertiaryNumber, actual.TertiaryNumber, 6);
Assert.Equal(expected.Children.Count, actual.Children.Count);
for (int i = 0; i < expected.Children.Count; i++)
AssertConditionsEqual(expected.Children[i], actual.Children[i]);
}
private static void AssertActionsEqual(MetaAction expected, MetaAction actual)
{
Assert.Equal(expected.Kind, actual.Kind);
if (expected.Kind != MetaActionKind.LoadEmbeddedNavigationRoute)
Assert.Equal(expected.Text, actual.Text);
Assert.Equal(expected.SecondaryText, actual.SecondaryText);
Assert.Equal(expected.Number, actual.Number, 6);
Assert.Equal(expected.SecondaryNumber, actual.SecondaryNumber, 6);
Assert.Equal(expected.Children.Count, actual.Children.Count);
for (int i = 0; i < expected.Children.Count; i++)
AssertActionsEqual(expected.Children[i], actual.Children[i]);
}
private static void AssertNavigationEqual(NavigationSettings expected, NavigationSettings actual)
{
Assert.Equal(expected.Mode, actual.Mode);
if (expected.Mode == RouteMode.Target)
{
Assert.Equal(expected.FollowTargetObjectId, actual.FollowTargetObjectId);
Assert.Equal(expected.FollowTargetName, actual.FollowTargetName);
return;
}
Assert.Equal(expected.Waypoints.Count, actual.Waypoints.Count);
for (int i = 0; i < expected.Waypoints.Count; i++)
{
RouteWaypoint a = expected.Waypoints[i];
RouteWaypoint b = actual.Waypoints[i];
Assert.Equal(a.Type, b.Type);
Assert.Equal(a.Position.EastWest, b.Position.EastWest, 3);
Assert.Equal(a.Position.NorthSouth, b.Position.NorthSouth, 3);
Assert.Equal(a.Position.Elevation, b.Position.Elevation, 3);
Assert.Equal(a.ObjectId, b.ObjectId);
Assert.Equal(a.ObjectName, b.ObjectName);
Assert.Equal(a.Text, b.Text);
Assert.Equal(a.DurationMilliseconds, b.DurationMilliseconds);
// Recall waypoints are the one field-set that is genuinely
// asymmetric between the two formats with a no-op spell
// catalog: the binary .nav stores a spell ID and derives the
// name only via a successful catalog lookup (which NoOpSpellCatalog
// never provides), while .af stores the name literally and
// derives the ID the same (catalog-dependent) way in reverse.
// Comparing RecallSpellName/Id here would fail for reasons that
// have nothing to do with the .af port's correctness.
Assert.Equal(a.JumpHeadingDegrees, b.JumpHeadingDegrees, 3);
Assert.Equal(a.JumpRun, b.JumpRun);
Assert.Equal(a.JumpChargeMilliseconds, b.JumpChargeMilliseconds);
}
}
private sealed class NoOpSpellCatalog : ISpellCatalog
{
public static NoOpSpellCatalog Instance { get; } = new();
public IReadOnlyList<PluginSpellInfo> KnownSelfBuffs => [];
public bool TryGet(uint spellId, out PluginSpellInfo info)
{
info = default;
return false;
}
}
}

View file

@ -0,0 +1,81 @@
using AcDream.Plugin.Abstractions;
namespace AcDream.Plugins.MossTank.Tests;
/// <summary>
/// KB doc 05 section 2.2 / section-5 gap-4: VTClassic's
/// <c>ComputedItemInfo.GetBuffedLogValueKey</c>/<c>GetBuffedDoubleValueKey</c>
/// only add a spell bonus when the item already carries the base key; an
/// item lacking the key entirely must not receive the bonus.
/// </summary>
public sealed class VtankLootRequirementEvaluatorTests
{
// Spell 2604 grants +20 to IntValueKey 28 (VtankLootRequirementEvaluator's
// IntSpellBonuses table) — key 28 is not one of the named
// PluginInventoryItem fields, so it only "exists" via the raw property
// bag.
private const uint BonusIntKey = 28u;
private const uint BonusIntSpellId = 2604u;
[Fact]
public void BuffedIntRequirementDoesNotApplyBonusWhenBaseKeyIsAbsent()
{
PluginInventoryItem item = Item() with
{
AppraisedSpellIds = [BonusIntSpellId],
};
var properties = new PluginItemProperties(
Ints: new Dictionary<uint, int>(), // key 28 absent entirely
Int64s: new Dictionary<uint, long>(),
Bools: new Dictionary<uint, bool>(),
Floats: new Dictionary<uint, double>(),
Strings: new Dictionary<uint, string>(),
DataIds: new Dictionary<uint, uint>(),
InstanceIds: new Dictionary<uint, uint>());
// Type 2003 = BuffedLongValKeyGE: values[0]=threshold, values[1]=key.
// Pre-fix this would read base=0, add the +20 bonus unconditionally
// (20 >= 10 => true); the gate must keep it at the un-buffed base
// value (0 >= 10 => false) since the key never existed at all.
var requirement = new VtankLootRequirement
{
Type = 2003,
Payload = $"10\r\n{BonusIntKey}\r\n",
};
bool matched = VtankLootRequirementEvaluator.IsMatch(
[requirement], item, properties, host: null, out string? error);
Assert.Null(error);
Assert.False(matched);
}
[Fact]
public void BuffedIntRequirementAppliesBonusWhenBaseKeyExists()
{
PluginInventoryItem item = Item() with
{
AppraisedSpellIds = [BonusIntSpellId],
};
var properties = new PluginItemProperties(
Ints: new Dictionary<uint, int> { [BonusIntKey] = 0 }, // key exists, base 0
Int64s: new Dictionary<uint, long>(),
Bools: new Dictionary<uint, bool>(),
Floats: new Dictionary<uint, double>(),
Strings: new Dictionary<uint, string>(),
DataIds: new Dictionary<uint, uint>(),
InstanceIds: new Dictionary<uint, uint>());
var requirement = new VtankLootRequirement
{
Type = 2003,
Payload = $"10\r\n{BonusIntKey}\r\n",
};
// Base key exists (value 0) so the +20 bonus applies: 20 >= 10.
Assert.True(VtankLootRequirementEvaluator.IsMatch(
[requirement], item, properties, host: null, out string? error));
Assert.Null(error);
}
private static PluginInventoryItem Item() => new(
0u, 0u, "Test Item", 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
1, 0, 0, 0u, 0, 0, 0u, false, 0d, 0, 0, 0, 0d, 0, 0, 0);
}

View file

@ -0,0 +1,162 @@
using System.Globalization;
namespace AcDream.Plugins.MossTank.Tests;
public sealed class VtankSettingsProfileSerializerTests
{
private static readonly string FixturesRoot = Path.Combine(
AppContext.BaseDirectory, "Fixtures", "vtank");
public static TheoryData<string> UsdFixtureData()
{
var data = new TheoryData<string>();
foreach (string name in new[] { "defaultsettings", "owner-a", "owner-b", "owner-c" })
data.Add(Path.Combine(FixturesRoot, name + ".usd"));
return data;
}
private static VtankSettingsProfileSerializer.AllSettings NewSettings() => new()
{
Combat = new CombatSettings(),
Buffs = new BuffSettings(),
Vitals = new VitalSettings(),
Inventory = new InventorySettings(),
Navigation = new NavigationSettings(),
};
[Theory]
[MemberData(nameof(UsdFixtureData))]
public void EveryUsdFixtureLoads(string path)
{
string text = File.ReadAllText(path);
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
VtankDatabase document = VtankSettingsProfileSerializer.Load(text, settings);
Assert.NotNull(document.Find("Settings"));
}
// An untouched load -> save round trip must reproduce the exact bytes
// VTank itself wrote for every setting whose model faithfully carries
// VTank's own value range (Save() only overwrites a Settings row's
// Value cell when the live value actually differs from what was
// parsed, using a tolerance that absorbs float<->double formatting
// noise but not a real value change).
//
// One documented exception: "UseArcs" is a real, pre-existing,
// already-shipped simplification (MossTankPanel.cs:3000-3002,
// "usearcs" case) that collapses VTank's 3-way enum (1=No, 2=AtRange,
// 3=Yes) onto a single bool, matching ExpressionValue.IsTruthy's
// "!= 0" semantics for the *live* /vt-style setting path. A profile
// whose original value is exactly 1 (No) genuinely cannot round-trip
// byte-for-byte through that bool — Capture() must produce either 1 or
// 3, and both this serializer and the live SetMetaOption path treat 1
// and 3 identically on load (both truthy). This is intentionally
// reproduced here rather than diverging from the already-accepted
// live-path behavior; the assertion below normalizes UseArcs before
// comparing so the test still proves everything else is untouched.
[Theory]
[MemberData(nameof(UsdFixtureData))]
public void UntouchedRoundTripIsByteIdentical(string path)
{
string original = File.ReadAllText(path);
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
VtankDatabase document = VtankSettingsProfileSerializer.Load(original, settings);
string rewritten = VtankSettingsProfileSerializer.Save(document, settings);
Assert.Equal(NormalizeUseArcs(original), NormalizeUseArcs(rewritten));
}
private static string NormalizeUseArcs(string usd) => usd.Replace(
"UseArcs\r\ni\r\n1\r\n",
"UseArcs\r\ni\r\n3\r\n",
StringComparison.Ordinal);
[Fact]
public void DefaultSettingsUsdMatchesEveryCatalogDefault()
{
string text = File.ReadAllText(Path.Combine(FixturesRoot, "defaultsettings.usd"));
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
VtankSettingsProfileSerializer.Load(text, settings);
Assert.Equal(25, settings.Combat.HuntSkillExcessOverDifficulty);
Assert.True(settings.Combat.Enabled);
Assert.True(settings.Buffs.Enabled);
Assert.False(settings.Inventory.Loot.Enabled);
Assert.False(settings.Navigation.Enabled);
Assert.Equal(0.75, settings.Vitals.NormalHealth, 6);
Assert.Equal(0.50, settings.Vitals.NormalStamina, 6);
Assert.Equal(0.50, settings.Vitals.NormalMana, 6);
Assert.Equal(5f, settings.Combat.MaximumRange, 3);
Assert.Equal(2, (int)settings.Combat.AttackHeight);
Assert.Equal(TargetSelectionMethod.Both, settings.Combat.SelectionMethod);
Assert.Equal(1.9, settings.Vitals.StaminaToHealthMultiplier, 6);
Assert.Equal(2.8, settings.Vitals.ManaToHealthMultiplier, 6);
Assert.Equal("ALFCBPS", settings.Buffs.ProtectionElements);
Assert.Equal(2, settings.Buffs.ProtectionProfileMode);
Assert.Equal(30d, settings.Buffs.BuffCastRecastSeconds, 6);
Assert.Equal(80, settings.Buffs.BuffWithUntrainedItemSkill);
Assert.Equal(-50, settings.Navigation.DoorLockpickExcessThreshold);
Assert.Equal(34, settings.Vitals.DropToPeaceModeRetryCount);
// RechargeHandlerSet: the real 26-row nested table (KB doc 01 row
// 137 said "24 seed rows"; the live fixture has 26 — this is the
// corrected count).
Assert.Equal(26, settings.Vitals.RechargeHandlerRows.Count);
RechargeHandlerRow first = settings.Vitals.RechargeHandlerRows[0];
Assert.Equal(1, first.Vital); // Health
Assert.Equal("Stamina to Health", first.HandlerString);
Assert.Equal(0, first.MinPercent);
Assert.Equal(15, first.MaxPercent);
Assert.Equal(1, first.Stance); // magic
}
// Every one of the 137 catalog names must map onto exactly one field —
// proven by asserting Capture() never returns null for a known name
// (except the two names with no live write path — enablemeta, whose
// value is MetaEngine.Enabled, live session state not a stored setting;
// and rechargehandlerset, which VTank's own generic editor and
// /vt opt set both refuse to touch either, section 2 row 137).
[Fact]
public void Every137CatalogNameMapsToExactlyOneField()
{
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
var unmapped = new List<string>();
foreach (string name in VtankOptionCatalog.Names)
{
if (VtankSettingsProfileSerializer.Capture(name, settings) is null)
unmapped.Add(name);
}
Assert.Equal(["EnableMeta", "RechargeHandlerSet"], unmapped);
}
[Fact]
public void RechargeHandlerSetRoundTripsFromOwnerFixture()
{
string text = File.ReadAllText(Path.Combine(FixturesRoot, "owner-a.usd"));
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
VtankSettingsProfileSerializer.Load(text, settings);
Assert.NotEmpty(settings.Vitals.RechargeHandlerRows);
Assert.Contains(
settings.Vitals.RechargeHandlerRows,
static row => row.HandlerString == "Kit Recharge");
}
[Fact]
public void UnknownSettingsRowIsPreservedVerbatim()
{
string usd = SingleSettingUsd("SomeFutureSetting", "s", "future-value");
VtankSettingsProfileSerializer.AllSettings settings = NewSettings();
VtankDatabase document = VtankSettingsProfileSerializer.Load(usd, settings);
string rewritten = VtankSettingsProfileSerializer.Save(document, settings);
Assert.Equal(usd, rewritten);
}
private static string SingleSettingUsd(string name, string valueTag, string valueText)
{
var lines = new List<string>
{
"1", "Settings", "4", "Setting", "Value", "Description", "SettingType",
"y", "n", "n", "n", "1",
"s", name, valueTag, valueText, "s", string.Empty, "i", "1",
};
return string.Join("\r\n", lines) + "\r\n";
}
}