var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: !0 });
function _mergeNamespaces(n, m) {
  for (var i = 0; i < m.length; i++) {
    const e = m[i];
    if (typeof e != "string" && !Array.isArray(e)) {
      for (const k in e)
        if (k !== "default" && !(k in n)) {
          const d = Object.getOwnPropertyDescriptor(e, k);
          d && Object.defineProperty(n, k, d.get ? d : {
            enumerable: !0,
            get: () => e[k]
          });
        }
    }
  }
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
}
__name(_mergeNamespaces, "_mergeNamespaces");
var StatusConditionType = /* @__PURE__ */ ((StatusConditionType2) => (StatusConditionType2.Condition = "Condition", StatusConditionType2.Status = "Status", StatusConditionType2.Effect = "Effect", StatusConditionType2))(StatusConditionType || {}), StabOptions1 = /* @__PURE__ */ ((StabOptions12) => (StabOptions12.Cool = "Cool", StabOptions12.Repair = "Repair", StabOptions12))(StabOptions1 || {}), StabOptions2 = /* @__PURE__ */ ((StabOptions22) => (StabOptions22.Reload = "Reload", StabOptions22.ClearBurn = "ClearBurn", StabOptions22.ClearOwnCond = "ClearOwnCond", StabOptions22.ClearOtherCond = "ClearOtherCond", StabOptions22))(StabOptions2 || {}), EntryType = /* @__PURE__ */ ((EntryType2) => (EntryType2.CORE_BONUS = "core_bonus", EntryType2.DEPLOYABLE = "deployable", EntryType2.FRAME = "frame", EntryType2.MECH = "mech", EntryType2.LICENSE = "license", EntryType2.NPC = "npc", EntryType2.NPC_CLASS = "npc_class", EntryType2.NPC_TEMPLATE = "npc_template", EntryType2.NPC_FEATURE = "npc_feature", EntryType2.WEAPON_MOD = "weapon_mod", EntryType2.MECH_SYSTEM = "mech_system", EntryType2.MECH_WEAPON = "mech_weapon", EntryType2.ORGANIZATION = "organization", EntryType2.PILOT_ARMOR = "pilot_armor", EntryType2.PILOT_GEAR = "pilot_gear", EntryType2.PILOT_WEAPON = "pilot_weapon", EntryType2.PILOT = "pilot", EntryType2.RESERVE = "reserve", EntryType2.SKILL = "skill", EntryType2.STATUS = "status", EntryType2.TALENT = "talent", EntryType2.BOND = "bond", EntryType2))(EntryType || {});
function EntryTypeLidPrefix(type2) {
  switch (type2) {
    case "core_bonus":
      return "cb_";
    case "deployable":
      return "dep_";
    case "frame":
      return "mf_";
    case "mech":
      return "mech_";
    case "license":
      return "lic_";
    case "npc":
      return "npc_";
    case "npc_class":
      return "npcc_";
    case "npc_template":
      return "npct_";
    case "npc_feature":
      return "npcf_";
    case "weapon_mod":
      return "wm_";
    case "mech_system":
      return "ms_";
    case "mech_weapon":
      return "mw_";
    case "organization":
      return "org_";
    case "pilot_armor":
    case "pilot_gear":
    case "pilot_weapon":
      return "pg_";
    case "pilot":
      return "pilot_";
    case "reserve":
      return "reserve_";
    case "skill":
      return "sk_";
    case "status":
      return "";
    case "talent":
      return "t_";
    case "bond":
      return "bond_";
    default:
      return "";
  }
}
__name(EntryTypeLidPrefix, "EntryTypeLidPrefix");
var MountType = /* @__PURE__ */ ((MountType2) => (MountType2.Main = "Main", MountType2.Heavy = "Heavy", MountType2.AuxAux = "Aux/Aux", MountType2.Aux = "Aux", MountType2.MainAux = "Main/Aux", MountType2.Flex = "Flex", MountType2.Integrated = "Integrated", MountType2.Superheavy = "Superheavy", MountType2.Unknown = "Unknown", MountType2))(MountType || {}), NpcFeatureType = /* @__PURE__ */ ((NpcFeatureType2) => (NpcFeatureType2.Trait = "Trait", NpcFeatureType2.System = "System", NpcFeatureType2.Reaction = "Reaction", NpcFeatureType2.Weapon = "Weapon", NpcFeatureType2.Tech = "Tech", NpcFeatureType2))(NpcFeatureType || {}), NpcTechType = /* @__PURE__ */ ((NpcTechType2) => (NpcTechType2.Quick = "Quick", NpcTechType2.Full = "Full", NpcTechType2))(NpcTechType || {}), FittingSize = /* @__PURE__ */ ((FittingSize2) => (FittingSize2.Auxiliary = "Auxiliary", FittingSize2.Main = "Main", FittingSize2.Flex = "Flex", FittingSize2.Heavy = "Heavy", FittingSize2.Superheavy = "Superheavy", FittingSize2.Integrated = "Integrated", FittingSize2))(FittingSize || {});
function fittingsForMount(mount) {
  switch (mount) {
    case "Aux":
      return [
        "Auxiliary"
        /* Auxiliary */
      ];
    case "Aux/Aux":
      return [
        "Auxiliary",
        "Auxiliary"
        /* Auxiliary */
      ];
    case "Flex":
      return [
        "Flex",
        "Auxiliary"
        /* Auxiliary */
      ];
    case "Main":
      return [
        "Main"
        /* Main */
      ];
    case "Main/Aux":
      return [
        "Main",
        "Auxiliary"
        /* Auxiliary */
      ];
    case "Heavy":
      return [
        "Heavy"
        /* Heavy */
      ];
    case "Superheavy":
      return [
        "Superheavy"
        /* Superheavy */
      ];
    case "Integrated":
    case "Unknown":
      return [
        "Integrated"
        /* Integrated */
      ];
  }
}
__name(fittingsForMount, "fittingsForMount");
var WeaponSize = /* @__PURE__ */ ((WeaponSize2) => (WeaponSize2.Aux = "Auxiliary", WeaponSize2.Main = "Main", WeaponSize2.Heavy = "Heavy", WeaponSize2.Superheavy = "Superheavy", WeaponSize2))(WeaponSize || {}), WeaponType = /* @__PURE__ */ ((WeaponType2) => (WeaponType2.Rifle = "Rifle", WeaponType2.Cannon = "Cannon", WeaponType2.Launcher = "Launcher", WeaponType2.CQB = "CQB", WeaponType2.Nexus = "Nexus", WeaponType2.Melee = "Melee", WeaponType2))(WeaponType || {}), SystemType = /* @__PURE__ */ ((SystemType2) => (SystemType2.System = "System", SystemType2.AI = "AI", SystemType2.Shield = "Shield", SystemType2.Deployable = "Deployable", SystemType2.Drone = "Drone", SystemType2.Tech = "Tech", SystemType2.Armor = "Armor", SystemType2.FlightSystem = "Flight System", SystemType2.Integrated = "Integrated", SystemType2.Mod = "Mod", SystemType2))(SystemType || {}), FrameEffectUse = /* @__PURE__ */ ((FrameEffectUse2) => (FrameEffectUse2.Turn = "Turn", FrameEffectUse2.NextTurn = "Next Turn", FrameEffectUse2.Round = "Round", FrameEffectUse2.NextRound = "Next Round", FrameEffectUse2.Scene = "Scene", FrameEffectUse2.Encounter = "Encounter", FrameEffectUse2.Mission = "Mission", FrameEffectUse2.Unknown = "?", FrameEffectUse2))(FrameEffectUse || {}), ActivationType = /* @__PURE__ */ ((ActivationType2) => (ActivationType2.None = "None", ActivationType2.Passive = "Passive", ActivationType2.Quick = "Quick", ActivationType2.QuickTech = "Quick Tech", ActivationType2.Invade = "Invade", ActivationType2.Full = "Full", ActivationType2.FullTech = "Full Tech", ActivationType2.Other = "Other", ActivationType2.Reaction = "Reaction", ActivationType2.Protocol = "Protocol", ActivationType2.Free = "Free", ActivationType2))(ActivationType || {}), RangeType = /* @__PURE__ */ ((RangeType2) => (RangeType2.Range = "Range", RangeType2.Threat = "Threat", RangeType2.Thrown = "Thrown", RangeType2.Line = "Line", RangeType2.Cone = "Cone", RangeType2.Blast = "Blast", RangeType2.Burst = "Burst", RangeType2))(RangeType || {}), DamageType = /* @__PURE__ */ ((DamageType2) => (DamageType2.Kinetic = "Kinetic", DamageType2.Energy = "Energy", DamageType2.Explosive = "Explosive", DamageType2.Heat = "Heat", DamageType2.Burn = "Burn", DamageType2.Variable = "Variable", DamageType2))(DamageType || {}), AttackType = /* @__PURE__ */ ((AttackType2) => (AttackType2.Melee = "Melee", AttackType2.Ranged = "Ranged", AttackType2.Tech = "Tech", AttackType2))(AttackType || {}), MechType = /* @__PURE__ */ ((MechType2) => (MechType2.Balanced = "Balanced", MechType2.Artillery = "Artillery", MechType2.Striker = "Striker", MechType2.Controller = "Controller", MechType2.Support = "Support", MechType2.Defender = "Defender", MechType2.Specialty = "Specialty", MechType2))(MechType || {}), ReserveType = /* @__PURE__ */ ((ReserveType2) => (ReserveType2.Resources = "Resources", ReserveType2.Tactical = "Tactical", ReserveType2.Mech = "Mech", ReserveType2.Project = "Project", ReserveType2.Organization = "Organization", ReserveType2.Bonus = "Bonus", ReserveType2))(ReserveType || {}), OrgType = /* @__PURE__ */ ((OrgType2) => (OrgType2.Military = "Military", OrgType2.Scientific = "Scientific", OrgType2.Academic = "Academic", OrgType2.Criminal = "Criminal", OrgType2.Humanitarian = "Humanitarian", OrgType2.Industrial = "Industrial", OrgType2.Entertainment = "Entertainment", OrgType2.Political = "Political", OrgType2))(OrgType || {});
const AllSynergyLocations = [
  "any",
  // Acts as a wildcard
  "active_effects",
  "rest",
  "core_power",
  "weapon",
  "system",
  "deployable",
  "drone",
  "move",
  "boost",
  "other",
  "ram",
  "grapple",
  "tech_attack",
  "hp",
  "armor",
  "repair",
  "overshield",
  "burn",
  "structure",
  "heat",
  "stress",
  "overcharge",
  "skill_check",
  "overwatch",
  "skirmish",
  "barrage",
  "improvised_attack",
  "disengage",
  "stabilize",
  "tech",
  "lock_on",
  "bolster",
  "hase",
  "hull",
  "agility",
  "systems",
  "engineering",
  "brace",
  "cascade",
  "pilot_weapon"
];
var DeployableType = /* @__PURE__ */ ((DeployableType2) => (DeployableType2.Deployable = "Deployable", DeployableType2.Drone = "Drone", DeployableType2.Mine = "Mine", DeployableType2))(DeployableType || {}), ActivePeriod = /* @__PURE__ */ ((ActivePeriod2) => (ActivePeriod2.Turn = "Turn", ActivePeriod2.Round = "Round", ActivePeriod2.Encounter = "Encounter", ActivePeriod2.Scene = "Scene", ActivePeriod2.Mission = "Mission", ActivePeriod2.Unlimited = "Unlimited", ActivePeriod2))(ActivePeriod || {});
function makeWeaponTypeChecklist(types) {
  let override = types.length == 0;
  return {
    CQB: override || types.includes(
      "CQB"
      /* CQB */
    ),
    Cannon: override || types.includes(
      "Cannon"
      /* Cannon */
    ),
    Launcher: override || types.includes(
      "Launcher"
      /* Launcher */
    ),
    Melee: override || types.includes(
      "Melee"
      /* Melee */
    ),
    Nexus: override || types.includes(
      "Nexus"
      /* Nexus */
    ),
    Rifle: override || types.includes(
      "Rifle"
      /* Rifle */
    )
  };
}
__name(makeWeaponTypeChecklist, "makeWeaponTypeChecklist");
function makeWeaponSizeChecklist(types) {
  let override = types.length == 0;
  return {
    Auxiliary: override || types.includes(
      "Auxiliary"
      /* Aux */
    ),
    Heavy: override || types.includes(
      "Heavy"
      /* Heavy */
    ),
    Main: override || types.includes(
      "Main"
      /* Main */
    ),
    Superheavy: override || types.includes(
      "Superheavy"
      /* Superheavy */
    )
  };
}
__name(makeWeaponSizeChecklist, "makeWeaponSizeChecklist");
function makeSystemTypeChecklist(types) {
  let override = types.length == 0;
  return {
    System: override || types.includes(
      "System"
      /* System */
    ),
    AI: override || types.includes(
      "AI"
      /* AI */
    ),
    Shield: override || types.includes(
      "Shield"
      /* Shield */
    ),
    Deployable: override || types.includes(
      "Deployable"
      /* Deployable */
    ),
    Drone: override || types.includes(
      "Drone"
      /* Drone */
    ),
    Tech: override || types.includes(
      "Tech"
      /* Tech */
    ),
    Armor: override || types.includes(
      "Armor"
      /* Armor */
    ),
    "Flight System": override || types.includes(
      "Flight System"
      /* FlightSystem */
    ),
    Integrated: override || types.includes(
      "Integrated"
      /* Integrated */
    ),
    Mod: override || types.includes(
      "Mod"
      /* Mod */
    )
  };
}
__name(makeSystemTypeChecklist, "makeSystemTypeChecklist");
const ASCII = `
╭╮╱╱╭━━━┳━╮╱╭┳━━━┳━━━┳━━━╮ 
┃┃╱╱┃╭━╮┃┃╰╮┃┃╭━╮┃╭━━┫╭━╮┃ 
┃┃╱╱┃┃╱┃┃╭╮╰╯┃┃╱╰┫╰━━┫╰━╯┃ 
┃┃╱╭┫╰━╯┃┃╰╮┃┃┃╱╭┫╭━━┫╭╮╭╯ 
┃╰━╯┃╭━╮┃┃╱┃┃┃╰━╯┃╰━━┫┃┃╰╮ 
╰━━━┻╯╱╰┻╯╱╰━┻━━━┻━━━┻╯╰━╯`;
function WELCOME() {
  return `
  <div style="text-align: center;">
    <a href="https://massifpress.com/legal">
      <img style="max-width: 90%; border: none" src="https://massifpress.com/_next/image?url=%2Fimages%2Flegal%2Fpowered_by_Lancer-01.svg&w=640&q=75" alt="Powered by Lancer">
    </a>
  </div>

  <p><a href="https://github.com/Eranziel/foundryvtt-lancer/blob/master/CHANGELOG.md">CHANGELOG</a></p>
  
  <p>Check out the project wiki for 
  <a href="https://github.com/Eranziel/foundryvtt-lancer/wiki/FAQ">FAQ</a>, 
  <a href="https://github.com/Eranziel/foundryvtt-lancer/wiki/Resources">recommended modules</a>,
  and other information about how to use the system.</p>
  
  <p>@UUID[Compendium.lancer.lancer_info.JournalEntry.JDfVPzoWPOLyhCCa.JournalEntryPage.LVsmG9EfKH9VpVJX]{Legal & Acknowlegements}</p>
  <p>@UUID[Compendium.lancer.lancer_info.JournalEntry.JDfVPzoWPOLyhCCa.JournalEntryPage.gotpldNfOwLxauXi]{Migrating from Earlier Versions}</p>
  `;
}
__name(WELCOME, "WELCOME");
const LANCER = {
  ASCII,
  log_prefix: "LANCER |",
  setting_migration_version: "systemMigrationVersion",
  setting_core_data: "coreDataVersion",
  setting_lcps: "installedLCPs",
  setting_stock_icons: "keepStockIcons",
  // setting_welcome: "hideWelcome" as const, // Deprecated as of v2.7.0
  setting_floating_damage_numbers: "floatingNumbers",
  setting_ui_theme: "uiTheme",
  setting_compcon_login: "compconLogin",
  setting_status_icons: "statusIconConfig",
  setting_automation: "automationOptions",
  setting_automation_switch: "automationSwitch",
  setting_automation_attack: "attackSwitch",
  // Deprecated
  setting_actionTracker: "actionTracker",
  setting_pilot_oc_heat: "autoOCHeat",
  setting_overkill_heat: "autoOKillHeat",
  setting_auto_structure: "autoCalcStructure",
  setting_dsn_setup: "dsnSetup",
  setting_square_grid_diagonals: "squareGridDiagonals",
  setting_tag_config: "tagConfig"
  // setting_120: "warningFor120" as const, // Old setting, currently unused.
  // setting_beta_warning: "warningForBeta" as const, // Old setting, currently unused.
}, FRIENDLY_DOCUMENT_NAMES_SINGULAR = {
  [EntryType.CORE_BONUS]: "Core Bonus",
  [EntryType.DEPLOYABLE]: "Deployable",
  [EntryType.FRAME]: "Frame",
  [EntryType.LICENSE]: "License",
  [EntryType.MECH]: "Mech",
  [EntryType.MECH_SYSTEM]: "Mech System",
  [EntryType.MECH_WEAPON]: "Mech Weapon",
  [EntryType.NPC]: "Npc",
  [EntryType.NPC_CLASS]: "Npc Class",
  [EntryType.NPC_FEATURE]: "Npc Feature",
  [EntryType.NPC_TEMPLATE]: "Npc Template",
  [EntryType.ORGANIZATION]: "Organization",
  [EntryType.PILOT]: "Pilot Preset",
  [EntryType.PILOT_ARMOR]: "Pilot Armor",
  [EntryType.PILOT_GEAR]: "Pilot Gear",
  [EntryType.PILOT_WEAPON]: "Pilot Weapon",
  [EntryType.RESERVE]: "Reserve",
  [EntryType.SKILL]: "Skill",
  [EntryType.STATUS]: "Status/Condition",
  [EntryType.TALENT]: "Talent",
  [EntryType.BOND]: "Bond",
  [EntryType.WEAPON_MOD]: "Weapon Mod"
}, FRIENDLY_DOCUMENT_NAMES_PLURAL = {
  [EntryType.CORE_BONUS]: "Core Bonuses",
  [EntryType.DEPLOYABLE]: "Deployables",
  [EntryType.FRAME]: "Frames",
  [EntryType.LICENSE]: "Licenses",
  [EntryType.MECH]: "Mechs",
  [EntryType.MECH_SYSTEM]: "Mech Systems",
  [EntryType.MECH_WEAPON]: "Mech Weapons",
  [EntryType.NPC]: "Npcs",
  [EntryType.NPC_CLASS]: "Npc Classes",
  [EntryType.NPC_FEATURE]: "Npc Features",
  [EntryType.NPC_TEMPLATE]: "Npc Templates",
  [EntryType.ORGANIZATION]: "Organizations",
  [EntryType.PILOT]: "Pilot Presets",
  [EntryType.PILOT_ARMOR]: "Pilot Armor",
  [EntryType.PILOT_GEAR]: "Pilot Gear",
  [EntryType.PILOT_WEAPON]: "Pilot Weapons",
  [EntryType.RESERVE]: "Reserves",
  [EntryType.SKILL]: "Skills",
  [EntryType.STATUS]: "Statuses / Conditions",
  [EntryType.TALENT]: "Talents",
  [EntryType.BOND]: "Bonds",
  [EntryType.WEAPON_MOD]: "Weapon Mods"
};
function friendly_entrytype_name(type2, count) {
  return (count ?? 1) > 1 ? FRIENDLY_DOCUMENT_NAMES_PLURAL[type2] ?? `Unknown <${type2}>s` : FRIENDLY_DOCUMENT_NAMES_SINGULAR[type2] ?? `Unknown <${type2}>`;
}
__name(friendly_entrytype_name, "friendly_entrytype_name");
function TypeIcon(type2, macro) {
  const docType = ACTOR_TYPES.includes(type2) ? "Actor" : "Item";
  return getDocumentClass(docType).getDefaultArtwork({ type: type2 }).img;
}
__name(TypeIcon, "TypeIcon");
function replaceDefaultResource(current, ...replacements) {
  if (!(current != null && current.trim()) || current.includes("systems/lancer") || current == "icons/svg/mystery-man.svg") {
    for (let replacement of replacements)
      if (replacement != null && replacement.trim())
        return replacement;
    return current || "";
  }
  return current;
}
__name(replaceDefaultResource, "replaceDefaultResource");
const frameImageMap = {
  ATLAS: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-ATLAS.png",
  BALOR: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-BALOR.png",
  BARBAROSSA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-BARBAROSSA.png",
  "BLACK WITCH": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-BLACK WITCH.png",
  BLACKBEARD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-BLACKBEARD.png",
  CALENDULA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-RKF-CALENDULA.png",
  CALIBAN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-CALIBAN.png",
  "DEATH’S HEAD": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-DEATHS HEAD.png",
  DRAKE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-DRAKE.png",
  "DUSK WING": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-DUSK WING.png",
  EMPAKAAI: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-EMPAKAAI.png",
  EMPEROR: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-EMPEROR.png",
  ENKIDU: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-ENKIDU.png",
  EVEREST: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-GMS.png",
  GENGHIS: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-GENGHIS.png",
  GOBLIN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-GOBLIN-2-0.png",
  GORGON: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-GORGON.png",
  HYDRA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-HYDRA.png",
  ISKANDER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-ISKANDER-2-0.png",
  KIDD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-KIDD.png",
  KOBOLD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-KOBOLD.png",
  LANCASTER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-LANCASTER.png",
  LICH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-LICH.png",
  MANTICORE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-MANTICORE.png",
  METALMARK: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-METALMARK-2-0.png",
  MINOTAUR: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-MINOTAUR.png",
  MONARCH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-MONARCH.png",
  "MOURNING CLOAK": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-MOURNING CLOAK.png",
  NAPOLEON: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-NAPOLEON.png",
  NELSON: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-NELSON-2-0.png",
  ORCHIS: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-ORCHIS.png",
  PEGASUS: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Horus-PEGASUS-2-0.png",
  RALEIGH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-RALEIGH.png",
  SAGARMATHA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-GMS.png",
  SALADIN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-SALADIN.png",
  SHERMAN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-SHERMAN.png",
  STÖRTEBEKER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-STORTEBEKER.png",
  SUNZI: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-SUNZI.png",
  SWALLOWTAIL: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-SWALLOWTAIL-2-0.png",
  "SWALLOWTAIL (RANGER VARIANT)": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-RANGER-SWALLOWTAIL.png",
  TOKUGAWA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-TOKUGAWA.png",
  TORTUGA: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-TORTUGA.png",
  VICEROY: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-VICEROY.png",
  VLAD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-VLAD-2-0.png",
  "WHITE WITCH": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-SSC-WHITE WITCH.png",
  "“WORLDKILLER” GENGHIS MK I": "systems/lancer/assets/retrograde-minis/Retrograde-Minis-HA-GENGHIS-MK-I---WORLDKILLER.png",
  ZHENG: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-IPS-N-ZHENG.png",
  ACE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-ACE.png",
  AEGIS: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-AEGIS.png",
  ARCHER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-ARCHER.png",
  ASSASSIN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-ASSASSIN.png",
  ASSAULT: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-ASSAULT.png",
  AVENGER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-AVENGER.png",
  BARRICADE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-BARRICADE.png",
  BASTION: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-BASTION.png",
  BERSERKER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-BERSERKER.png",
  BOMBARD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-BOMBARD.png",
  BREACHER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-BREACHER.png",
  CATAPHRACT: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-CATAPHRACT.png",
  DEMOLISHER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-DEMOLISHER.png",
  ENGINEER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-ENGINEER.png",
  GOLIATH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-GOLIATH.png",
  HIVE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-HIVE.png",
  HORNET: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-HORNET.png",
  HUMAN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Misc-HUMAN.png",
  LEECH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-LEECH.png",
  LURKER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-LURKER.png",
  MIRAGE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-MIRAGE.png",
  MONSTROSITY: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Kaiju-RUGAM.png",
  OPERATOR: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-OPERATOR.png",
  PRIEST: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-PRIEST.png",
  PYRO: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-PYRO.png",
  RAINMAKER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-RAINMAKER.png",
  RONIN: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-RONIN.png",
  SCOURER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SCOURER.png",
  SCOUT: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SCOUT.png",
  SEEDER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SEEDER.png",
  SENTINEL: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SENTINEL.png",
  SNIPER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SNIPER.png",
  SPECTER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SPECTER.png",
  SPITE: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SPITE.png",
  STRIDER: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-STRIDER.png",
  SQUAD: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Misc-INFANTRY.png",
  SUPPORT: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-SUPPORT.png",
  TEMPEST: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-TEMPEST.png",
  WITCH: "systems/lancer/assets/retrograde-minis/Retrograde-Minis-Corpro-WITCH.png"
};
function frameToPath(name2) {
  return name2 ? frameImageMap[name2.trim().toUpperCase()] : null;
}
__name(frameToPath, "frameToPath");
const _ChangeWatchHelper = class _ChangeWatchHelper {
  constructor() {
    this.prior_value = null, this.prior_string = "", this.curr_value = null, this.curr_string = "", this.isDirty = !1;
  }
  // Clears dirty
  clean() {
    this.isDirty = !0;
  }
  /**
   * Set the value, returning true (and marking self as "dirty") if its different from our initial value
   * Initial call will never mark dirty bit
   * @param to
   */
  setValue(to) {
    let first = !1;
    return this.curr_string ? (this.prior_value = this.curr_value, this.prior_string = this.curr_string) : first = !0, this.curr_value = to, this.curr_string = JSON.stringify(to), first && (this.prior_string = this.curr_string, this.prior_value = this.curr_value), !first && !this.isDirty && (this.isDirty = this.curr_string != this.prior_string), this.isDirty;
  }
};
__name(_ChangeWatchHelper, "ChangeWatchHelper");
let ChangeWatchHelper = _ChangeWatchHelper;
function fixCCFormula(formula) {
  return formula.replaceAll("{ll}", "@level").replaceAll("{grit}", "@grit");
}
__name(fixCCFormula, "fixCCFormula");
function rollEvalSync(formula, data2) {
  let roll = new Roll(formula, data2);
  try {
    roll.evaluateSync();
  } catch {
    return 0;
  }
  return roll.total;
}
__name(rollEvalSync, "rollEvalSync");
function userOwnsActor(actor) {
  var _a19, _b;
  return actor.isOwner && !((_a19 = game.users) != null && _a19.players.some((u) => u.active && actor.testUserPermission(u, "OWNER")) && ((_b = game.user) != null && _b.isGM));
}
__name(userOwnsActor, "userOwnsActor");
async function tokenScrollText({ tokenId = "", content = "", style = {} } = {}, push = !1) {
  var _a19, _b;
  style = {
    anchor: CONST.TEXT_ANCHOR_POINTS.CENTER,
    direction: CONST.TEXT_ANCHOR_POINTS.TOP,
    fontSize: 28,
    fill: 16777215,
    stroke: 0,
    strokeThickness: 4,
    jitter: 0.25,
    ...style
  }, push && ((_a19 = game.socket) == null || _a19.emit(`system.${game.system.id}`, {
    action: "scrollText",
    data: { tokenId, content, style }
  }));
  const token = (_b = canvas.tokens) == null ? void 0 : _b.get(tokenId);
  token && await game.settings.get(game.system.id, LANCER.setting_floating_damage_numbers) && await canvas.interface.createScrollingText(token.center, content, style);
}
__name(tokenScrollText, "tokenScrollText");
const _HTMLEditDialog = class _HTMLEditDialog extends FormApplication {
  constructor(target, text_path, options, resolve_func) {
    super(
      {
        hasPerm: () => !0
        // We give it a dummy object because we don't want it messing with our shit
      },
      options
    ), this.target = target, this.text_path = text_path, this.text = resolveDotpath(target, text_path), this.resolve = resolve_func;
  }
  /* -------------------------------------------- */
  /** @override */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      template: `systems/${game.system.id}/templates/window/html_editor.hbs`,
      width: 650,
      height: "auto",
      resizable: !0,
      classes: ["lancer", "lancer-text-editor"],
      submitOnChange: !1,
      submitOnClose: !0,
      closeOnSubmit: !0
    });
  }
  /** @override
   * Expose our data
   */
  getData() {
    let new_data = {
      text: this.text
    };
    return foundry.utils.mergeObject(super.getData(), new_data);
  }
  /** @override */
  async _updateObject(_event, formData) {
    let new_text = formData.text;
    this.target.update({ [this.text_path]: new_text }).then(this.resolve);
  }
  /** @override
   * Want to resolve promise before closing
   */
  close(options) {
    return this.resolve(), super.close(options);
  }
  /* -------------------------------------------- */
  /**
   * A helper constructor function which displays the text edit dialog and returns a Promise once it's
   * workflow has been resolved.
   * @return {Promise}
   */
  static async edit_text(in_object, at_path) {
    return new Promise((resolve, _reject) => {
      new this(
        in_object,
        at_path,
        {
          title: "Edit Text"
        },
        resolve
      ).render(!0);
    });
  }
};
__name(_HTMLEditDialog, "HTMLEditDialog");
let HTMLEditDialog = _HTMLEditDialog, nanoid = /* @__PURE__ */ __name((size = 21) => crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => (byte &= 63, byte < 36 ? id += byte.toString(36) : byte < 62 ? id += (byte - 26).toString(36).toUpperCase() : byte > 62 ? id += "-" : id += "_", id), ""), "nanoid");
const DEFAULT_DESCRIPTION = "";
function BONUS() {
  return {
    lid: "unknown",
    val: "0",
    overwrite: !1,
    replace: !1,
    damage_types: {
      Burn: !0,
      Energy: !0,
      Explosive: !0,
      Heat: !0,
      Kinetic: !0,
      Variable: !0
    },
    range_types: {
      Blast: !0,
      Burst: !0,
      Cone: !0,
      Line: !0,
      Range: !0,
      Threat: !0,
      Thrown: !0
    },
    weapon_sizes: {
      Auxiliary: !0,
      Heavy: !0,
      Main: !0,
      Superheavy: !0
    },
    weapon_types: {
      CQB: !0,
      Cannon: !0,
      Launcher: !0,
      Melee: !0,
      Nexus: !0,
      Rifle: !0
    }
  };
}
__name(BONUS, "BONUS");
function ACTION() {
  return {
    name: "New action",
    lid: "act_" + nanoid(),
    activation: ActivationType.Quick,
    detail: DEFAULT_DESCRIPTION,
    // confirm: ["CONFIRM"],
    cost: 1,
    frequency: "",
    heat_cost: 0,
    init: "",
    damage: [],
    range: [],
    // log: "",
    mech: !0,
    pilot: !0,
    synergy_locations: [],
    terse: "Terse Description",
    trigger: "",
    tech_attack: !1
    // available_mounted: true,
  };
}
__name(ACTION, "ACTION");
function COUNTER() {
  return {
    lid: "count_" + nanoid(),
    name: "New Counter",
    min: 1,
    max: 6,
    default_value: 1,
    value: 1
  };
}
__name(COUNTER, "COUNTER");
function TAG() {
  return {
    lid: "tg_unknown",
    val: ""
  };
}
__name(TAG, "TAG");
function BOND_QUESTION() {
  return {
    question: DEFAULT_DESCRIPTION,
    options: [DEFAULT_DESCRIPTION]
  };
}
__name(BOND_QUESTION, "BOND_QUESTION");
function POWER() {
  return {
    name: "New Power",
    description: DEFAULT_DESCRIPTION,
    unlocked: !1,
    frequency: null,
    uses: null,
    veteran: !1,
    master: !1,
    prerequisite: null
  };
}
__name(POWER, "POWER");
function FRAME_TRAIT() {
  return {
    name: "New Trait",
    actions: [],
    bonuses: [],
    counters: [],
    synergies: [],
    deployables: [],
    integrated: [],
    description: DEFAULT_DESCRIPTION,
    use: FrameEffectUse.Unknown
  };
}
__name(FRAME_TRAIT, "FRAME_TRAIT");
function DAMAGE() {
  return {
    type: DamageType.Kinetic,
    val: "1d6"
  };
}
__name(DAMAGE, "DAMAGE");
function RANGE() {
  return {
    type: RangeType.Range,
    val: 5
  };
}
__name(RANGE, "RANGE");
function TALENT_RANK() {
  return {
    name: "New Rank",
    actions: [],
    bonuses: [],
    synergies: [],
    counters: [],
    deployables: [],
    description: DEFAULT_DESCRIPTION,
    exclusive: !1,
    integrated: []
  };
}
__name(TALENT_RANK, "TALENT_RANK");
function WEAPON_PROFILE() {
  return {
    name: "Standard Profile",
    actions: [],
    bonuses: [],
    counters: [],
    damage: [],
    description: DEFAULT_DESCRIPTION,
    effect: "",
    on_attack: "",
    on_crit: "",
    on_hit: "",
    range: [],
    synergies: [],
    tags: [],
    type: WeaponType.Rifle,
    barrageable: !0,
    cost: 1,
    skirmishable: !0
  };
}
__name(WEAPON_PROFILE, "WEAPON_PROFILE");
function WEAPON_MOUNT() {
  return {
    type: MountType.Main,
    bracing: !1,
    slots: [MOUNT_SLOT()]
  };
}
__name(WEAPON_MOUNT, "WEAPON_MOUNT");
function MOUNT_SLOT() {
  return {
    mod: null,
    size: FittingSize.Main,
    weapon: null
  };
}
__name(MOUNT_SLOT, "MOUNT_SLOT");
var top = "top", bottom = "bottom", right$2 = "right", left$2 = "left", auto = "auto", basePlacements = [top, bottom, right$2, left$2], start = "start", end = "end", clippingParents = "clippingParents", viewport = "viewport", popper = "popper", reference = "reference", variationPlacements = /* @__PURE__ */ basePlacements.reduce(function(acc, placement) {
  return acc.concat([placement + "-" + start, placement + "-" + end]);
}, []), placements = /* @__PURE__ */ [].concat(basePlacements, [auto]).reduce(function(acc, placement) {
  return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
}, []), beforeRead = "beforeRead", read = "read", afterRead = "afterRead", beforeMain = "beforeMain", main$1 = "main", afterMain = "afterMain", beforeWrite = "beforeWrite", write = "write", afterWrite = "afterWrite", modifierPhases = [beforeRead, read, afterRead, beforeMain, main$1, afterMain, beforeWrite, write, afterWrite];
function getNodeName(element) {
  return element ? (element.nodeName || "").toLowerCase() : null;
}
__name(getNodeName, "getNodeName");
function getWindow(node) {
  if (node == null)
    return window;
  if (node.toString() !== "[object Window]") {
    var ownerDocument = node.ownerDocument;
    return ownerDocument && ownerDocument.defaultView || window;
  }
  return node;
}
__name(getWindow, "getWindow");
function isElement$1(node) {
  var OwnElement = getWindow(node).Element;
  return node instanceof OwnElement || node instanceof Element;
}
__name(isElement$1, "isElement$1");
function isHTMLElement(node) {
  var OwnElement = getWindow(node).HTMLElement;
  return node instanceof OwnElement || node instanceof HTMLElement;
}
__name(isHTMLElement, "isHTMLElement");
function isShadowRoot(node) {
  if (typeof ShadowRoot > "u")
    return !1;
  var OwnElement = getWindow(node).ShadowRoot;
  return node instanceof OwnElement || node instanceof ShadowRoot;
}
__name(isShadowRoot, "isShadowRoot");
function applyStyles(_ref) {
  var state = _ref.state;
  Object.keys(state.elements).forEach(function(name2) {
    var style = state.styles[name2] || {}, attributes = state.attributes[name2] || {}, element = state.elements[name2];
    !isHTMLElement(element) || !getNodeName(element) || (Object.assign(element.style, style), Object.keys(attributes).forEach(function(name3) {
      var value = attributes[name3];
      value === !1 ? element.removeAttribute(name3) : element.setAttribute(name3, value === !0 ? "" : value);
    }));
  });
}
__name(applyStyles, "applyStyles");
function effect$2(_ref2) {
  var state = _ref2.state, initialStyles = {
    popper: {
      position: state.options.strategy,
      left: "0",
      top: "0",
      margin: "0"
    },
    arrow: {
      position: "absolute"
    },
    reference: {}
  };
  return Object.assign(state.elements.popper.style, initialStyles.popper), state.styles = initialStyles, state.elements.arrow && Object.assign(state.elements.arrow.style, initialStyles.arrow), function() {
    Object.keys(state.elements).forEach(function(name2) {
      var element = state.elements[name2], attributes = state.attributes[name2] || {}, styleProperties = Object.keys(state.styles.hasOwnProperty(name2) ? state.styles[name2] : initialStyles[name2]), style = styleProperties.reduce(function(style2, property) {
        return style2[property] = "", style2;
      }, {});
      !isHTMLElement(element) || !getNodeName(element) || (Object.assign(element.style, style), Object.keys(attributes).forEach(function(attribute) {
        element.removeAttribute(attribute);
      }));
    });
  };
}
__name(effect$2, "effect$2");
const applyStyles$1 = {
  name: "applyStyles",
  enabled: !0,
  phase: "write",
  fn: applyStyles,
  effect: effect$2,
  requires: ["computeStyles"]
};
function getBasePlacement$1(placement) {
  return placement.split("-")[0];
}
__name(getBasePlacement$1, "getBasePlacement$1");
var max = Math.max, min = Math.min, round = Math.round;
function getBoundingClientRect(element, includeScale) {
  includeScale === void 0 && (includeScale = !1);
  var rect = element.getBoundingClientRect(), scaleX = 1, scaleY = 1;
  if (isHTMLElement(element) && includeScale) {
    var offsetHeight = element.offsetHeight, offsetWidth = element.offsetWidth;
    offsetWidth > 0 && (scaleX = round(rect.width) / offsetWidth || 1), offsetHeight > 0 && (scaleY = round(rect.height) / offsetHeight || 1);
  }
  return {
    width: rect.width / scaleX,
    height: rect.height / scaleY,
    top: rect.top / scaleY,
    right: rect.right / scaleX,
    bottom: rect.bottom / scaleY,
    left: rect.left / scaleX,
    x: rect.left / scaleX,
    y: rect.top / scaleY
  };
}
__name(getBoundingClientRect, "getBoundingClientRect");
function getLayoutRect(element) {
  var clientRect = getBoundingClientRect(element), width = element.offsetWidth, height = element.offsetHeight;
  return Math.abs(clientRect.width - width) <= 1 && (width = clientRect.width), Math.abs(clientRect.height - height) <= 1 && (height = clientRect.height), {
    x: element.offsetLeft,
    y: element.offsetTop,
    width,
    height
  };
}
__name(getLayoutRect, "getLayoutRect");
function contains(parent, child) {
  var rootNode = child.getRootNode && child.getRootNode();
  if (parent.contains(child))
    return !0;
  if (rootNode && isShadowRoot(rootNode)) {
    var next = child;
    do {
      if (next && parent.isSameNode(next))
        return !0;
      next = next.parentNode || next.host;
    } while (next);
  }
  return !1;
}
__name(contains, "contains");
function getComputedStyle(element) {
  return getWindow(element).getComputedStyle(element);
}
__name(getComputedStyle, "getComputedStyle");
function isTableElement(element) {
  return ["table", "td", "th"].indexOf(getNodeName(element)) >= 0;
}
__name(isTableElement, "isTableElement");
function getDocumentElement(element) {
  return ((isElement$1(element) ? element.ownerDocument : (
    // $FlowFixMe[prop-missing]
    element.document
  )) || window.document).documentElement;
}
__name(getDocumentElement, "getDocumentElement");
function getParentNode(element) {
  return getNodeName(element) === "html" ? element : (
    // this is a quicker (but less type safe) way to save quite some bytes from the bundle
    // $FlowFixMe[incompatible-return]
    // $FlowFixMe[prop-missing]
    element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
    element.parentNode || // DOM Element detected
    (isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
    // $FlowFixMe[incompatible-call]: HTMLElement is a Node
    getDocumentElement(element)
  );
}
__name(getParentNode, "getParentNode");
function getTrueOffsetParent(element) {
  return !isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
  getComputedStyle(element).position === "fixed" ? null : element.offsetParent;
}
__name(getTrueOffsetParent, "getTrueOffsetParent");
function getContainingBlock(element) {
  var isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") !== -1, isIE = navigator.userAgent.indexOf("Trident") !== -1;
  if (isIE && isHTMLElement(element)) {
    var elementCss = getComputedStyle(element);
    if (elementCss.position === "fixed")
      return null;
  }
  var currentNode = getParentNode(element);
  for (isShadowRoot(currentNode) && (currentNode = currentNode.host); isHTMLElement(currentNode) && ["html", "body"].indexOf(getNodeName(currentNode)) < 0; ) {
    var css = getComputedStyle(currentNode);
    if (css.transform !== "none" || css.perspective !== "none" || css.contain === "paint" || ["transform", "perspective"].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === "filter" || isFirefox && css.filter && css.filter !== "none")
      return currentNode;
    currentNode = currentNode.parentNode;
  }
  return null;
}
__name(getContainingBlock, "getContainingBlock");
function getOffsetParent(element) {
  for (var window2 = getWindow(element), offsetParent = getTrueOffsetParent(element); offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === "static"; )
    offsetParent = getTrueOffsetParent(offsetParent);
  return offsetParent && (getNodeName(offsetParent) === "html" || getNodeName(offsetParent) === "body" && getComputedStyle(offsetParent).position === "static") ? window2 : offsetParent || getContainingBlock(element) || window2;
}
__name(getOffsetParent, "getOffsetParent");
function getMainAxisFromPlacement(placement) {
  return ["top", "bottom"].indexOf(placement) >= 0 ? "x" : "y";
}
__name(getMainAxisFromPlacement, "getMainAxisFromPlacement");
function within(min$1, value, max$1) {
  return max(min$1, min(value, max$1));
}
__name(within, "within");
function withinMaxClamp(min2, value, max2) {
  var v = within(min2, value, max2);
  return v > max2 ? max2 : v;
}
__name(withinMaxClamp, "withinMaxClamp");
function getFreshSideObject() {
  return {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  };
}
__name(getFreshSideObject, "getFreshSideObject");
function mergePaddingObject(paddingObject) {
  return Object.assign({}, getFreshSideObject(), paddingObject);
}
__name(mergePaddingObject, "mergePaddingObject");
function expandToHashMap(value, keys) {
  return keys.reduce(function(hashMap, key) {
    return hashMap[key] = value, hashMap;
  }, {});
}
__name(expandToHashMap, "expandToHashMap");
var toPaddingObject = /* @__PURE__ */ __name(function(padding, state) {
  return padding = typeof padding == "function" ? padding(Object.assign({}, state.rects, {
    placement: state.placement
  })) : padding, mergePaddingObject(typeof padding != "number" ? padding : expandToHashMap(padding, basePlacements));
}, "toPaddingObject");
function arrow(_ref) {
  var _state$modifiersData$, state = _ref.state, name2 = _ref.name, options = _ref.options, arrowElement = state.elements.arrow, popperOffsets2 = state.modifiersData.popperOffsets, basePlacement = getBasePlacement$1(state.placement), axis = getMainAxisFromPlacement(basePlacement), isVertical = [left$2, right$2].indexOf(basePlacement) >= 0, len = isVertical ? "height" : "width";
  if (!(!arrowElement || !popperOffsets2)) {
    var paddingObject = toPaddingObject(options.padding, state), arrowRect = getLayoutRect(arrowElement), minProp = axis === "y" ? top : left$2, maxProp = axis === "y" ? bottom : right$2, endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets2[axis] - state.rects.popper[len], startDiff = popperOffsets2[axis] - state.rects.reference[axis], arrowOffsetParent = getOffsetParent(arrowElement), clientSize = arrowOffsetParent ? axis === "y" ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0, centerToReference = endDiff / 2 - startDiff / 2, min2 = paddingObject[minProp], max2 = clientSize - arrowRect[len] - paddingObject[maxProp], center = clientSize / 2 - arrowRect[len] / 2 + centerToReference, offset2 = within(min2, center, max2), axisProp = axis;
    state.modifiersData[name2] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset2, _state$modifiersData$.centerOffset = offset2 - center, _state$modifiersData$);
  }
}
__name(arrow, "arrow");
function effect$1(_ref2) {
  var state = _ref2.state, options = _ref2.options, _options$element = options.element, arrowElement = _options$element === void 0 ? "[data-popper-arrow]" : _options$element;
  arrowElement != null && (typeof arrowElement == "string" && (arrowElement = state.elements.popper.querySelector(arrowElement), !arrowElement) || contains(state.elements.popper, arrowElement) && (state.elements.arrow = arrowElement));
}
__name(effect$1, "effect$1");
const arrow$1 = {
  name: "arrow",
  enabled: !0,
  phase: "main",
  fn: arrow,
  effect: effect$1,
  requires: ["popperOffsets"],
  requiresIfExists: ["preventOverflow"]
};
function getVariation(placement) {
  return placement.split("-")[1];
}
__name(getVariation, "getVariation");
var unsetSides = {
  top: "auto",
  right: "auto",
  bottom: "auto",
  left: "auto"
};
function roundOffsetsByDPR(_ref) {
  var x = _ref.x, y = _ref.y, win = window, dpr = win.devicePixelRatio || 1;
  return {
    x: round(x * dpr) / dpr || 0,
    y: round(y * dpr) / dpr || 0
  };
}
__name(roundOffsetsByDPR, "roundOffsetsByDPR");
function mapToStyles(_ref2) {
  var _Object$assign2, popper2 = _ref2.popper, popperRect = _ref2.popperRect, placement = _ref2.placement, variation = _ref2.variation, offsets = _ref2.offsets, position = _ref2.position, gpuAcceleration = _ref2.gpuAcceleration, adaptive = _ref2.adaptive, roundOffsets = _ref2.roundOffsets, isFixed = _ref2.isFixed, _offsets$x = offsets.x, x = _offsets$x === void 0 ? 0 : _offsets$x, _offsets$y = offsets.y, y = _offsets$y === void 0 ? 0 : _offsets$y, _ref3 = typeof roundOffsets == "function" ? roundOffsets({
    x,
    y
  }) : {
    x,
    y
  };
  x = _ref3.x, y = _ref3.y;
  var hasX = offsets.hasOwnProperty("x"), hasY = offsets.hasOwnProperty("y"), sideX = left$2, sideY = top, win = window;
  if (adaptive) {
    var offsetParent = getOffsetParent(popper2), heightProp = "clientHeight", widthProp = "clientWidth";
    if (offsetParent === getWindow(popper2) && (offsetParent = getDocumentElement(popper2), getComputedStyle(offsetParent).position !== "static" && position === "absolute" && (heightProp = "scrollHeight", widthProp = "scrollWidth")), offsetParent = offsetParent, placement === top || (placement === left$2 || placement === right$2) && variation === end) {
      sideY = bottom;
      var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : (
        // $FlowFixMe[prop-missing]
        offsetParent[heightProp]
      );
      y -= offsetY - popperRect.height, y *= gpuAcceleration ? 1 : -1;
    }
    if (placement === left$2 || (placement === top || placement === bottom) && variation === end) {
      sideX = right$2;
      var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : (
        // $FlowFixMe[prop-missing]
        offsetParent[widthProp]
      );
      x -= offsetX - popperRect.width, x *= gpuAcceleration ? 1 : -1;
    }
  }
  var commonStyles = Object.assign({
    position
  }, adaptive && unsetSides), _ref4 = roundOffsets === !0 ? roundOffsetsByDPR({
    x,
    y
  }) : {
    x,
    y
  };
  if (x = _ref4.x, y = _ref4.y, gpuAcceleration) {
    var _Object$assign;
    return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? "0" : "", _Object$assign[sideX] = hasX ? "0" : "", _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
  }
  return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : "", _Object$assign2[sideX] = hasX ? x + "px" : "", _Object$assign2.transform = "", _Object$assign2));
}
__name(mapToStyles, "mapToStyles");
function computeStyles(_ref5) {
  var state = _ref5.state, options = _ref5.options, _options$gpuAccelerat = options.gpuAcceleration, gpuAcceleration = _options$gpuAccelerat === void 0 ? !0 : _options$gpuAccelerat, _options$adaptive = options.adaptive, adaptive = _options$adaptive === void 0 ? !0 : _options$adaptive, _options$roundOffsets = options.roundOffsets, roundOffsets = _options$roundOffsets === void 0 ? !0 : _options$roundOffsets, commonStyles = {
    placement: getBasePlacement$1(state.placement),
    variation: getVariation(state.placement),
    popper: state.elements.popper,
    popperRect: state.rects.popper,
    gpuAcceleration,
    isFixed: state.options.strategy === "fixed"
  };
  state.modifiersData.popperOffsets != null && (state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
    offsets: state.modifiersData.popperOffsets,
    position: state.options.strategy,
    adaptive,
    roundOffsets
  })))), state.modifiersData.arrow != null && (state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
    offsets: state.modifiersData.arrow,
    position: "absolute",
    adaptive: !1,
    roundOffsets
  })))), state.attributes.popper = Object.assign({}, state.attributes.popper, {
    "data-popper-placement": state.placement
  });
}
__name(computeStyles, "computeStyles");
const computeStyles$1 = {
  name: "computeStyles",
  enabled: !0,
  phase: "beforeWrite",
  fn: computeStyles,
  data: {}
};
var passive = {
  passive: !0
};
function effect(_ref) {
  var state = _ref.state, instance = _ref.instance, options = _ref.options, _options$scroll = options.scroll, scroll = _options$scroll === void 0 ? !0 : _options$scroll, _options$resize = options.resize, resize = _options$resize === void 0 ? !0 : _options$resize, window2 = getWindow(state.elements.popper), scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
  return scroll && scrollParents.forEach(function(scrollParent) {
    scrollParent.addEventListener("scroll", instance.update, passive);
  }), resize && window2.addEventListener("resize", instance.update, passive), function() {
    scroll && scrollParents.forEach(function(scrollParent) {
      scrollParent.removeEventListener("scroll", instance.update, passive);
    }), resize && window2.removeEventListener("resize", instance.update, passive);
  };
}
__name(effect, "effect");
const eventListeners = {
  name: "eventListeners",
  enabled: !0,
  phase: "write",
  fn: /* @__PURE__ */ __name(function() {
  }, "fn"),
  effect,
  data: {}
};
var hash$1 = {
  left: "right",
  right: "left",
  bottom: "top",
  top: "bottom"
};
function getOppositePlacement(placement) {
  return placement.replace(/left|right|bottom|top/g, function(matched) {
    return hash$1[matched];
  });
}
__name(getOppositePlacement, "getOppositePlacement");
var hash = {
  start: "end",
  end: "start"
};
function getOppositeVariationPlacement(placement) {
  return placement.replace(/start|end/g, function(matched) {
    return hash[matched];
  });
}
__name(getOppositeVariationPlacement, "getOppositeVariationPlacement");
function getWindowScroll(node) {
  var win = getWindow(node), scrollLeft = win.pageXOffset, scrollTop = win.pageYOffset;
  return {
    scrollLeft,
    scrollTop
  };
}
__name(getWindowScroll, "getWindowScroll");
function getWindowScrollBarX(element) {
  return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
}
__name(getWindowScrollBarX, "getWindowScrollBarX");
function getViewportRect(element) {
  var win = getWindow(element), html = getDocumentElement(element), visualViewport = win.visualViewport, width = html.clientWidth, height = html.clientHeight, x = 0, y = 0;
  return visualViewport && (width = visualViewport.width, height = visualViewport.height, /^((?!chrome|android).)*safari/i.test(navigator.userAgent) || (x = visualViewport.offsetLeft, y = visualViewport.offsetTop)), {
    width,
    height,
    x: x + getWindowScrollBarX(element),
    y
  };
}
__name(getViewportRect, "getViewportRect");
function getDocumentRect(element) {
  var _element$ownerDocumen, html = getDocumentElement(element), winScroll = getWindowScroll(element), body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body, width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0), height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0), x = -winScroll.scrollLeft + getWindowScrollBarX(element), y = -winScroll.scrollTop;
  return getComputedStyle(body || html).direction === "rtl" && (x += max(html.clientWidth, body ? body.clientWidth : 0) - width), {
    width,
    height,
    x,
    y
  };
}
__name(getDocumentRect, "getDocumentRect");
function isScrollParent(element) {
  var _getComputedStyle = getComputedStyle(element), overflow = _getComputedStyle.overflow, overflowX = _getComputedStyle.overflowX, overflowY = _getComputedStyle.overflowY;
  return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
}
__name(isScrollParent, "isScrollParent");
function getScrollParent(node) {
  return ["html", "body", "#document"].indexOf(getNodeName(node)) >= 0 ? node.ownerDocument.body : isHTMLElement(node) && isScrollParent(node) ? node : getScrollParent(getParentNode(node));
}
__name(getScrollParent, "getScrollParent");
function listScrollParents(element, list) {
  var _element$ownerDocumen;
  list === void 0 && (list = []);
  var scrollParent = getScrollParent(element), isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body), win = getWindow(scrollParent), target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent, updatedList = list.concat(target);
  return isBody ? updatedList : (
    // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
    updatedList.concat(listScrollParents(getParentNode(target)))
  );
}
__name(listScrollParents, "listScrollParents");
function rectToClientRect(rect) {
  return Object.assign({}, rect, {
    left: rect.x,
    top: rect.y,
    right: rect.x + rect.width,
    bottom: rect.y + rect.height
  });
}
__name(rectToClientRect, "rectToClientRect");
function getInnerBoundingClientRect(element) {
  var rect = getBoundingClientRect(element);
  return rect.top = rect.top + element.clientTop, rect.left = rect.left + element.clientLeft, rect.bottom = rect.top + element.clientHeight, rect.right = rect.left + element.clientWidth, rect.width = element.clientWidth, rect.height = element.clientHeight, rect.x = rect.left, rect.y = rect.top, rect;
}
__name(getInnerBoundingClientRect, "getInnerBoundingClientRect");
function getClientRectFromMixedType(element, clippingParent) {
  return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isElement$1(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
}
__name(getClientRectFromMixedType, "getClientRectFromMixedType");
function getClippingParents(element) {
  var clippingParents2 = listScrollParents(getParentNode(element)), canEscapeClipping = ["absolute", "fixed"].indexOf(getComputedStyle(element).position) >= 0, clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
  return isElement$1(clipperElement) ? clippingParents2.filter(function(clippingParent) {
    return isElement$1(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== "body";
  }) : [];
}
__name(getClippingParents, "getClippingParents");
function getClippingRect(element, boundary, rootBoundary) {
  var mainClippingParents = boundary === "clippingParents" ? getClippingParents(element) : [].concat(boundary), clippingParents2 = [].concat(mainClippingParents, [rootBoundary]), firstClippingParent = clippingParents2[0], clippingRect = clippingParents2.reduce(function(accRect, clippingParent) {
    var rect = getClientRectFromMixedType(element, clippingParent);
    return accRect.top = max(rect.top, accRect.top), accRect.right = min(rect.right, accRect.right), accRect.bottom = min(rect.bottom, accRect.bottom), accRect.left = max(rect.left, accRect.left), accRect;
  }, getClientRectFromMixedType(element, firstClippingParent));
  return clippingRect.width = clippingRect.right - clippingRect.left, clippingRect.height = clippingRect.bottom - clippingRect.top, clippingRect.x = clippingRect.left, clippingRect.y = clippingRect.top, clippingRect;
}
__name(getClippingRect, "getClippingRect");
function computeOffsets(_ref) {
  var reference2 = _ref.reference, element = _ref.element, placement = _ref.placement, basePlacement = placement ? getBasePlacement$1(placement) : null, variation = placement ? getVariation(placement) : null, commonX = reference2.x + reference2.width / 2 - element.width / 2, commonY = reference2.y + reference2.height / 2 - element.height / 2, offsets;
  switch (basePlacement) {
    case top:
      offsets = {
        x: commonX,
        y: reference2.y - element.height
      };
      break;
    case bottom:
      offsets = {
        x: commonX,
        y: reference2.y + reference2.height
      };
      break;
    case right$2:
      offsets = {
        x: reference2.x + reference2.width,
        y: commonY
      };
      break;
    case left$2:
      offsets = {
        x: reference2.x - element.width,
        y: commonY
      };
      break;
    default:
      offsets = {
        x: reference2.x,
        y: reference2.y
      };
  }
  var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
  if (mainAxis != null) {
    var len = mainAxis === "y" ? "height" : "width";
    switch (variation) {
      case start:
        offsets[mainAxis] = offsets[mainAxis] - (reference2[len] / 2 - element[len] / 2);
        break;
      case end:
        offsets[mainAxis] = offsets[mainAxis] + (reference2[len] / 2 - element[len] / 2);
        break;
    }
  }
  return offsets;
}
__name(computeOffsets, "computeOffsets");
function detectOverflow(state, options) {
  options === void 0 && (options = {});
  var _options = options, _options$placement = _options.placement, placement = _options$placement === void 0 ? state.placement : _options$placement, _options$boundary = _options.boundary, boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, _options$rootBoundary = _options.rootBoundary, rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, _options$elementConte = _options.elementContext, elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, _options$altBoundary = _options.altBoundary, altBoundary = _options$altBoundary === void 0 ? !1 : _options$altBoundary, _options$padding = _options.padding, padding = _options$padding === void 0 ? 0 : _options$padding, paddingObject = mergePaddingObject(typeof padding != "number" ? padding : expandToHashMap(padding, basePlacements)), altContext = elementContext === popper ? reference : popper, popperRect = state.rects.popper, element = state.elements[altBoundary ? altContext : elementContext], clippingClientRect = getClippingRect(isElement$1(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary), referenceClientRect = getBoundingClientRect(state.elements.reference), popperOffsets2 = computeOffsets({
    reference: referenceClientRect,
    element: popperRect,
    strategy: "absolute",
    placement
  }), popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets2)), elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect, overflowOffsets = {
    top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
    bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
    left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
    right: elementClientRect.right - clippingClientRect.right + paddingObject.right
  }, offsetData = state.modifiersData.offset;
  if (elementContext === popper && offsetData) {
    var offset2 = offsetData[placement];
    Object.keys(overflowOffsets).forEach(function(key) {
      var multiply = [right$2, bottom].indexOf(key) >= 0 ? 1 : -1, axis = [top, bottom].indexOf(key) >= 0 ? "y" : "x";
      overflowOffsets[key] += offset2[axis] * multiply;
    });
  }
  return overflowOffsets;
}
__name(detectOverflow, "detectOverflow");
function computeAutoPlacement(state, options) {
  options === void 0 && (options = {});
  var _options = options, placement = _options.placement, boundary = _options.boundary, rootBoundary = _options.rootBoundary, padding = _options.padding, flipVariations = _options.flipVariations, _options$allowedAutoP = _options.allowedAutoPlacements, allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP, variation = getVariation(placement), placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function(placement2) {
    return getVariation(placement2) === variation;
  }) : basePlacements, allowedPlacements = placements$1.filter(function(placement2) {
    return allowedAutoPlacements.indexOf(placement2) >= 0;
  });
  allowedPlacements.length === 0 && (allowedPlacements = placements$1);
  var overflows = allowedPlacements.reduce(function(acc, placement2) {
    return acc[placement2] = detectOverflow(state, {
      placement: placement2,
      boundary,
      rootBoundary,
      padding
    })[getBasePlacement$1(placement2)], acc;
  }, {});
  return Object.keys(overflows).sort(function(a, b) {
    return overflows[a] - overflows[b];
  });
}
__name(computeAutoPlacement, "computeAutoPlacement");
function getExpandedFallbackPlacements(placement) {
  if (getBasePlacement$1(placement) === auto)
    return [];
  var oppositePlacement = getOppositePlacement(placement);
  return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
}
__name(getExpandedFallbackPlacements, "getExpandedFallbackPlacements");
function flip(_ref) {
  var state = _ref.state, options = _ref.options, name2 = _ref.name;
  if (!state.modifiersData[name2]._skip) {
    for (var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? !0 : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? !0 : _options$altAxis, specifiedFallbackPlacements = options.fallbackPlacements, padding = options.padding, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, _options$flipVariatio = options.flipVariations, flipVariations = _options$flipVariatio === void 0 ? !0 : _options$flipVariatio, allowedAutoPlacements = options.allowedAutoPlacements, preferredPlacement = state.options.placement, basePlacement = getBasePlacement$1(preferredPlacement), isBasePlacement = basePlacement === preferredPlacement, fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)), placements2 = [preferredPlacement].concat(fallbackPlacements).reduce(function(acc, placement2) {
      return acc.concat(getBasePlacement$1(placement2) === auto ? computeAutoPlacement(state, {
        placement: placement2,
        boundary,
        rootBoundary,
        padding,
        flipVariations,
        allowedAutoPlacements
      }) : placement2);
    }, []), referenceRect = state.rects.reference, popperRect = state.rects.popper, checksMap = /* @__PURE__ */ new Map(), makeFallbackChecks = !0, firstFittingPlacement = placements2[0], i = 0; i < placements2.length; i++) {
      var placement = placements2[i], _basePlacement = getBasePlacement$1(placement), isStartVariation = getVariation(placement) === start, isVertical = [top, bottom].indexOf(_basePlacement) >= 0, len = isVertical ? "width" : "height", overflow = detectOverflow(state, {
        placement,
        boundary,
        rootBoundary,
        altBoundary,
        padding
      }), mainVariationSide = isVertical ? isStartVariation ? right$2 : left$2 : isStartVariation ? bottom : top;
      referenceRect[len] > popperRect[len] && (mainVariationSide = getOppositePlacement(mainVariationSide));
      var altVariationSide = getOppositePlacement(mainVariationSide), checks = [];
      if (checkMainAxis && checks.push(overflow[_basePlacement] <= 0), checkAltAxis && checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0), checks.every(function(check) {
        return check;
      })) {
        firstFittingPlacement = placement, makeFallbackChecks = !1;
        break;
      }
      checksMap.set(placement, checks);
    }
    if (makeFallbackChecks)
      for (var numberOfChecks = flipVariations ? 3 : 1, _loop = /* @__PURE__ */ __name(function(_i2) {
        var fittingPlacement = placements2.find(function(placement2) {
          var checks2 = checksMap.get(placement2);
          if (checks2)
            return checks2.slice(0, _i2).every(function(check) {
              return check;
            });
        });
        if (fittingPlacement)
          return firstFittingPlacement = fittingPlacement, "break";
      }, "_loop"), _i = numberOfChecks; _i > 0; _i--) {
        var _ret = _loop(_i);
        if (_ret === "break")
          break;
      }
    state.placement !== firstFittingPlacement && (state.modifiersData[name2]._skip = !0, state.placement = firstFittingPlacement, state.reset = !0);
  }
}
__name(flip, "flip");
const flip$1 = {
  name: "flip",
  enabled: !0,
  phase: "main",
  fn: flip,
  requiresIfExists: ["offset"],
  data: {
    _skip: !1
  }
};
function getSideOffsets(overflow, rect, preventedOffsets) {
  return preventedOffsets === void 0 && (preventedOffsets = {
    x: 0,
    y: 0
  }), {
    top: overflow.top - rect.height - preventedOffsets.y,
    right: overflow.right - rect.width + preventedOffsets.x,
    bottom: overflow.bottom - rect.height + preventedOffsets.y,
    left: overflow.left - rect.width - preventedOffsets.x
  };
}
__name(getSideOffsets, "getSideOffsets");
function isAnySideFullyClipped(overflow) {
  return [top, right$2, bottom, left$2].some(function(side) {
    return overflow[side] >= 0;
  });
}
__name(isAnySideFullyClipped, "isAnySideFullyClipped");
function hide(_ref) {
  var state = _ref.state, name2 = _ref.name, referenceRect = state.rects.reference, popperRect = state.rects.popper, preventedOffsets = state.modifiersData.preventOverflow, referenceOverflow = detectOverflow(state, {
    elementContext: "reference"
  }), popperAltOverflow = detectOverflow(state, {
    altBoundary: !0
  }), referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect), popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets), isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets), hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
  state.modifiersData[name2] = {
    referenceClippingOffsets,
    popperEscapeOffsets,
    isReferenceHidden,
    hasPopperEscaped
  }, state.attributes.popper = Object.assign({}, state.attributes.popper, {
    "data-popper-reference-hidden": isReferenceHidden,
    "data-popper-escaped": hasPopperEscaped
  });
}
__name(hide, "hide");
const hide$1 = {
  name: "hide",
  enabled: !0,
  phase: "main",
  requiresIfExists: ["preventOverflow"],
  fn: hide
};
function distanceAndSkiddingToXY(placement, rects, offset2) {
  var basePlacement = getBasePlacement$1(placement), invertDistance = [left$2, top].indexOf(basePlacement) >= 0 ? -1 : 1, _ref = typeof offset2 == "function" ? offset2(Object.assign({}, rects, {
    placement
  })) : offset2, skidding = _ref[0], distance = _ref[1];
  return skidding = skidding || 0, distance = (distance || 0) * invertDistance, [left$2, right$2].indexOf(basePlacement) >= 0 ? {
    x: distance,
    y: skidding
  } : {
    x: skidding,
    y: distance
  };
}
__name(distanceAndSkiddingToXY, "distanceAndSkiddingToXY");
function offset(_ref2) {
  var state = _ref2.state, options = _ref2.options, name2 = _ref2.name, _options$offset = options.offset, offset2 = _options$offset === void 0 ? [0, 0] : _options$offset, data2 = placements.reduce(function(acc, placement) {
    return acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset2), acc;
  }, {}), _data$state$placement = data2[state.placement], x = _data$state$placement.x, y = _data$state$placement.y;
  state.modifiersData.popperOffsets != null && (state.modifiersData.popperOffsets.x += x, state.modifiersData.popperOffsets.y += y), state.modifiersData[name2] = data2;
}
__name(offset, "offset");
const offset$1 = {
  name: "offset",
  enabled: !0,
  phase: "main",
  requires: ["popperOffsets"],
  fn: offset
};
function popperOffsets(_ref) {
  var state = _ref.state, name2 = _ref.name;
  state.modifiersData[name2] = computeOffsets({
    reference: state.rects.reference,
    element: state.rects.popper,
    strategy: "absolute",
    placement: state.placement
  });
}
__name(popperOffsets, "popperOffsets");
const popperOffsets$1 = {
  name: "popperOffsets",
  enabled: !0,
  phase: "read",
  fn: popperOffsets,
  data: {}
};
function getAltAxis(axis) {
  return axis === "x" ? "y" : "x";
}
__name(getAltAxis, "getAltAxis");
function preventOverflow(_ref) {
  var state = _ref.state, options = _ref.options, name2 = _ref.name, _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? !0 : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? !1 : _options$altAxis, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, padding = options.padding, _options$tether = options.tether, tether = _options$tether === void 0 ? !0 : _options$tether, _options$tetherOffset = options.tetherOffset, tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset, overflow = detectOverflow(state, {
    boundary,
    rootBoundary,
    padding,
    altBoundary
  }), basePlacement = getBasePlacement$1(state.placement), variation = getVariation(state.placement), isBasePlacement = !variation, mainAxis = getMainAxisFromPlacement(basePlacement), altAxis = getAltAxis(mainAxis), popperOffsets2 = state.modifiersData.popperOffsets, referenceRect = state.rects.reference, popperRect = state.rects.popper, tetherOffsetValue = typeof tetherOffset == "function" ? tetherOffset(Object.assign({}, state.rects, {
    placement: state.placement
  })) : tetherOffset, normalizedTetherOffsetValue = typeof tetherOffsetValue == "number" ? {
    mainAxis: tetherOffsetValue,
    altAxis: tetherOffsetValue
  } : Object.assign({
    mainAxis: 0,
    altAxis: 0
  }, tetherOffsetValue), offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null, data2 = {
    x: 0,
    y: 0
  };
  if (popperOffsets2) {
    if (checkMainAxis) {
      var _offsetModifierState$, mainSide = mainAxis === "y" ? top : left$2, altSide = mainAxis === "y" ? bottom : right$2, len = mainAxis === "y" ? "height" : "width", offset2 = popperOffsets2[mainAxis], min$1 = offset2 + overflow[mainSide], max$1 = offset2 - overflow[altSide], additive = tether ? -popperRect[len] / 2 : 0, minLen = variation === start ? referenceRect[len] : popperRect[len], maxLen = variation === start ? -popperRect[len] : -referenceRect[len], arrowElement = state.elements.arrow, arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
        width: 0,
        height: 0
      }, arrowPaddingObject = state.modifiersData["arrow#persistent"] ? state.modifiersData["arrow#persistent"].padding : getFreshSideObject(), arrowPaddingMin = arrowPaddingObject[mainSide], arrowPaddingMax = arrowPaddingObject[altSide], arrowLen = within(0, referenceRect[len], arrowRect[len]), minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis, maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis, arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow), clientOffset = arrowOffsetParent ? mainAxis === "y" ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0, offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0, tetherMin = offset2 + minOffset - offsetModifierValue - clientOffset, tetherMax = offset2 + maxOffset - offsetModifierValue, preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset2, tether ? max(max$1, tetherMax) : max$1);
      popperOffsets2[mainAxis] = preventedOffset, data2[mainAxis] = preventedOffset - offset2;
    }
    if (checkAltAxis) {
      var _offsetModifierState$2, _mainSide = mainAxis === "x" ? top : left$2, _altSide = mainAxis === "x" ? bottom : right$2, _offset = popperOffsets2[altAxis], _len = altAxis === "y" ? "height" : "width", _min = _offset + overflow[_mainSide], _max = _offset - overflow[_altSide], isOriginSide = [top, left$2].indexOf(basePlacement) !== -1, _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0, _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis, _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max, _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
      popperOffsets2[altAxis] = _preventedOffset, data2[altAxis] = _preventedOffset - _offset;
    }
    state.modifiersData[name2] = data2;
  }
}
__name(preventOverflow, "preventOverflow");
const preventOverflow$1 = {
  name: "preventOverflow",
  enabled: !0,
  phase: "main",
  fn: preventOverflow,
  requiresIfExists: ["offset"]
};
function getHTMLElementScroll(element) {
  return {
    scrollLeft: element.scrollLeft,
    scrollTop: element.scrollTop
  };
}
__name(getHTMLElementScroll, "getHTMLElementScroll");
function getNodeScroll(node) {
  return node === getWindow(node) || !isHTMLElement(node) ? getWindowScroll(node) : getHTMLElementScroll(node);
}
__name(getNodeScroll, "getNodeScroll");
function isElementScaled(element) {
  var rect = element.getBoundingClientRect(), scaleX = round(rect.width) / element.offsetWidth || 1, scaleY = round(rect.height) / element.offsetHeight || 1;
  return scaleX !== 1 || scaleY !== 1;
}
__name(isElementScaled, "isElementScaled");
function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
  isFixed === void 0 && (isFixed = !1);
  var isOffsetParentAnElement = isHTMLElement(offsetParent), offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent), documentElement = getDocumentElement(offsetParent), rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled), scroll = {
    scrollLeft: 0,
    scrollTop: 0
  }, offsets = {
    x: 0,
    y: 0
  };
  return (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) && ((getNodeName(offsetParent) !== "body" || // https://github.com/popperjs/popper-core/issues/1078
  isScrollParent(documentElement)) && (scroll = getNodeScroll(offsetParent)), isHTMLElement(offsetParent) ? (offsets = getBoundingClientRect(offsetParent, !0), offsets.x += offsetParent.clientLeft, offsets.y += offsetParent.clientTop) : documentElement && (offsets.x = getWindowScrollBarX(documentElement))), {
    x: rect.left + scroll.scrollLeft - offsets.x,
    y: rect.top + scroll.scrollTop - offsets.y,
    width: rect.width,
    height: rect.height
  };
}
__name(getCompositeRect, "getCompositeRect");
function order(modifiers) {
  var map2 = /* @__PURE__ */ new Map(), visited = /* @__PURE__ */ new Set(), result = [];
  modifiers.forEach(function(modifier) {
    map2.set(modifier.name, modifier);
  });
  function sort(modifier) {
    visited.add(modifier.name);
    var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
    requires.forEach(function(dep) {
      if (!visited.has(dep)) {
        var depModifier = map2.get(dep);
        depModifier && sort(depModifier);
      }
    }), result.push(modifier);
  }
  return __name(sort, "sort"), modifiers.forEach(function(modifier) {
    visited.has(modifier.name) || sort(modifier);
  }), result;
}
__name(order, "order");
function orderModifiers(modifiers) {
  var orderedModifiers = order(modifiers);
  return modifierPhases.reduce(function(acc, phase) {
    return acc.concat(orderedModifiers.filter(function(modifier) {
      return modifier.phase === phase;
    }));
  }, []);
}
__name(orderModifiers, "orderModifiers");
function debounce$1(fn2) {
  var pending;
  return function() {
    return pending || (pending = new Promise(function(resolve) {
      Promise.resolve().then(function() {
        pending = void 0, resolve(fn2());
      });
    })), pending;
  };
}
__name(debounce$1, "debounce$1");
function mergeByName(modifiers) {
  var merged = modifiers.reduce(function(merged2, current) {
    var existing = merged2[current.name];
    return merged2[current.name] = existing ? Object.assign({}, existing, current, {
      options: Object.assign({}, existing.options, current.options),
      data: Object.assign({}, existing.data, current.data)
    }) : current, merged2;
  }, {});
  return Object.keys(merged).map(function(key) {
    return merged[key];
  });
}
__name(mergeByName, "mergeByName");
var DEFAULT_OPTIONS = {
  placement: "bottom",
  modifiers: [],
  strategy: "absolute"
};
function areValidElements() {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++)
    args[_key] = arguments[_key];
  return !args.some(function(element) {
    return !(element && typeof element.getBoundingClientRect == "function");
  });
}
__name(areValidElements, "areValidElements");
function popperGenerator(generatorOptions) {
  generatorOptions === void 0 && (generatorOptions = {});
  var _generatorOptions = generatorOptions, _generatorOptions$def = _generatorOptions.defaultModifiers, defaultModifiers2 = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, _generatorOptions$def2 = _generatorOptions.defaultOptions, defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
  return /* @__PURE__ */ __name(function(reference2, popper2, options) {
    options === void 0 && (options = defaultOptions);
    var state = {
      placement: "bottom",
      orderedModifiers: [],
      options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
      modifiersData: {},
      elements: {
        reference: reference2,
        popper: popper2
      },
      attributes: {},
      styles: {}
    }, effectCleanupFns = [], isDestroyed = !1, instance = {
      state,
      setOptions: /* @__PURE__ */ __name(function(setOptionsAction) {
        var options2 = typeof setOptionsAction == "function" ? setOptionsAction(state.options) : setOptionsAction;
        cleanupModifierEffects(), state.options = Object.assign({}, defaultOptions, state.options, options2), state.scrollParents = {
          reference: isElement$1(reference2) ? listScrollParents(reference2) : reference2.contextElement ? listScrollParents(reference2.contextElement) : [],
          popper: listScrollParents(popper2)
        };
        var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers2, state.options.modifiers)));
        return state.orderedModifiers = orderedModifiers.filter(function(m) {
          return m.enabled;
        }), runModifierEffects(), instance.update();
      }, "setOptions"),
      // Sync update – it will always be executed, even if not necessary. This
      // is useful for low frequency updates where sync behavior simplifies the
      // logic.
      // For high frequency updates (e.g. `resize` and `scroll` events), always
      // prefer the async Popper#update method
      forceUpdate: /* @__PURE__ */ __name(function() {
        if (!isDestroyed) {
          var _state$elements = state.elements, reference3 = _state$elements.reference, popper3 = _state$elements.popper;
          if (areValidElements(reference3, popper3)) {
            state.rects = {
              reference: getCompositeRect(reference3, getOffsetParent(popper3), state.options.strategy === "fixed"),
              popper: getLayoutRect(popper3)
            }, state.reset = !1, state.placement = state.options.placement, state.orderedModifiers.forEach(function(modifier) {
              return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
            });
            for (var index2 = 0; index2 < state.orderedModifiers.length; index2++) {
              if (state.reset === !0) {
                state.reset = !1, index2 = -1;
                continue;
              }
              var _state$orderedModifie = state.orderedModifiers[index2], fn2 = _state$orderedModifie.fn, _state$orderedModifie2 = _state$orderedModifie.options, _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, name2 = _state$orderedModifie.name;
              typeof fn2 == "function" && (state = fn2({
                state,
                options: _options,
                name: name2,
                instance
              }) || state);
            }
          }
        }
      }, "forceUpdate"),
      // Async and optimistically optimized update – it will not be executed if
      // not necessary (debounced to run at most once-per-tick)
      update: debounce$1(function() {
        return new Promise(function(resolve) {
          instance.forceUpdate(), resolve(state);
        });
      }),
      destroy: /* @__PURE__ */ __name(function() {
        cleanupModifierEffects(), isDestroyed = !0;
      }, "destroy")
    };
    if (!areValidElements(reference2, popper2))
      return instance;
    instance.setOptions(options).then(function(state2) {
      !isDestroyed && options.onFirstUpdate && options.onFirstUpdate(state2);
    });
    function runModifierEffects() {
      state.orderedModifiers.forEach(function(_ref3) {
        var name2 = _ref3.name, _ref3$options = _ref3.options, options2 = _ref3$options === void 0 ? {} : _ref3$options, effect3 = _ref3.effect;
        if (typeof effect3 == "function") {
          var cleanupFn = effect3({
            state,
            name: name2,
            instance,
            options: options2
          }), noopFn = /* @__PURE__ */ __name(function() {
          }, "noopFn");
          effectCleanupFns.push(cleanupFn || noopFn);
        }
      });
    }
    __name(runModifierEffects, "runModifierEffects");
    function cleanupModifierEffects() {
      effectCleanupFns.forEach(function(fn2) {
        return fn2();
      }), effectCleanupFns = [];
    }
    return __name(cleanupModifierEffects, "cleanupModifierEffects"), instance;
  }, "createPopper");
}
__name(popperGenerator, "popperGenerator");
var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1], createPopper = /* @__PURE__ */ popperGenerator({
  defaultModifiers
}), BOX_CLASS = "tippy-box", CONTENT_CLASS = "tippy-content", BACKDROP_CLASS = "tippy-backdrop", ARROW_CLASS = "tippy-arrow", SVG_ARROW_CLASS = "tippy-svg-arrow", TOUCH_OPTIONS = {
  passive: !0,
  capture: !0
}, TIPPY_DEFAULT_APPEND_TO = /* @__PURE__ */ __name(function() {
  return document.body;
}, "TIPPY_DEFAULT_APPEND_TO");
function getValueAtIndexOrReturn(value, index2, defaultValue) {
  if (Array.isArray(value)) {
    var v = value[index2];
    return v ?? (Array.isArray(defaultValue) ? defaultValue[index2] : defaultValue);
  }
  return value;
}
__name(getValueAtIndexOrReturn, "getValueAtIndexOrReturn");
function isType(value, type2) {
  var str = {}.toString.call(value);
  return str.indexOf("[object") === 0 && str.indexOf(type2 + "]") > -1;
}
__name(isType, "isType");
function invokeWithArgsOrReturn(value, args) {
  return typeof value == "function" ? value.apply(void 0, args) : value;
}
__name(invokeWithArgsOrReturn, "invokeWithArgsOrReturn");
function debounce(fn2, ms) {
  if (ms === 0)
    return fn2;
  var timeout;
  return function(arg) {
    clearTimeout(timeout), timeout = setTimeout(function() {
      fn2(arg);
    }, ms);
  };
}
__name(debounce, "debounce");
function splitBySpaces(value) {
  return value.split(/\s+/).filter(Boolean);
}
__name(splitBySpaces, "splitBySpaces");
function normalizeToArray(value) {
  return [].concat(value);
}
__name(normalizeToArray, "normalizeToArray");
function pushIfUnique(arr, value) {
  arr.indexOf(value) === -1 && arr.push(value);
}
__name(pushIfUnique, "pushIfUnique");
function unique(arr) {
  return arr.filter(function(item, index2) {
    return arr.indexOf(item) === index2;
  });
}
__name(unique, "unique");
function getBasePlacement(placement) {
  return placement.split("-")[0];
}
__name(getBasePlacement, "getBasePlacement");
function arrayFrom(value) {
  return [].slice.call(value);
}
__name(arrayFrom, "arrayFrom");
function removeUndefinedProps(obj) {
  return Object.keys(obj).reduce(function(acc, key) {
    return obj[key] !== void 0 && (acc[key] = obj[key]), acc;
  }, {});
}
__name(removeUndefinedProps, "removeUndefinedProps");
function div() {
  return document.createElement("div");
}
__name(div, "div");
function isElement(value) {
  return ["Element", "Fragment"].some(function(type2) {
    return isType(value, type2);
  });
}
__name(isElement, "isElement");
function isNodeList(value) {
  return isType(value, "NodeList");
}
__name(isNodeList, "isNodeList");
function isMouseEvent(value) {
  return isType(value, "MouseEvent");
}
__name(isMouseEvent, "isMouseEvent");
function isReferenceElement(value) {
  return !!(value && value._tippy && value._tippy.reference === value);
}
__name(isReferenceElement, "isReferenceElement");
function getArrayOfElements(value) {
  return isElement(value) ? [value] : isNodeList(value) ? arrayFrom(value) : Array.isArray(value) ? value : arrayFrom(document.querySelectorAll(value));
}
__name(getArrayOfElements, "getArrayOfElements");
function setTransitionDuration(els, value) {
  els.forEach(function(el) {
    el && (el.style.transitionDuration = value + "ms");
  });
}
__name(setTransitionDuration, "setTransitionDuration");
function setVisibilityState(els, state) {
  els.forEach(function(el) {
    el && el.setAttribute("data-state", state);
  });
}
__name(setVisibilityState, "setVisibilityState");
function getOwnerDocument(elementOrElements) {
  var _element$ownerDocumen, _normalizeToArray = normalizeToArray(elementOrElements), element = _normalizeToArray[0];
  return element != null && (_element$ownerDocumen = element.ownerDocument) != null && _element$ownerDocumen.body ? element.ownerDocument : document;
}
__name(getOwnerDocument, "getOwnerDocument");
function isCursorOutsideInteractiveBorder(popperTreeData, event) {
  var clientX = event.clientX, clientY = event.clientY;
  return popperTreeData.every(function(_ref) {
    var popperRect = _ref.popperRect, popperState = _ref.popperState, props = _ref.props, interactiveBorder = props.interactiveBorder, basePlacement = getBasePlacement(popperState.placement), offsetData = popperState.modifiersData.offset;
    if (!offsetData)
      return !0;
    var topDistance = basePlacement === "bottom" ? offsetData.top.y : 0, bottomDistance = basePlacement === "top" ? offsetData.bottom.y : 0, leftDistance = basePlacement === "right" ? offsetData.left.x : 0, rightDistance = basePlacement === "left" ? offsetData.right.x : 0, exceedsTop = popperRect.top - clientY + topDistance > interactiveBorder, exceedsBottom = clientY - popperRect.bottom - bottomDistance > interactiveBorder, exceedsLeft = popperRect.left - clientX + leftDistance > interactiveBorder, exceedsRight = clientX - popperRect.right - rightDistance > interactiveBorder;
    return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight;
  });
}
__name(isCursorOutsideInteractiveBorder, "isCursorOutsideInteractiveBorder");
function updateTransitionEndListener(box, action, listener) {
  var method = action + "EventListener";
  ["transitionend", "webkitTransitionEnd"].forEach(function(event) {
    box[method](event, listener);
  });
}
__name(updateTransitionEndListener, "updateTransitionEndListener");
function actualContains(parent, child) {
  for (var target = child; target; ) {
    var _target$getRootNode;
    if (parent.contains(target))
      return !0;
    target = target.getRootNode == null || (_target$getRootNode = target.getRootNode()) == null ? void 0 : _target$getRootNode.host;
  }
  return !1;
}
__name(actualContains, "actualContains");
var currentInput = {
  isTouch: !1
}, lastMouseMoveTime = 0;
function onDocumentTouchStart() {
  currentInput.isTouch || (currentInput.isTouch = !0, window.performance && document.addEventListener("mousemove", onDocumentMouseMove));
}
__name(onDocumentTouchStart, "onDocumentTouchStart");
function onDocumentMouseMove() {
  var now = performance.now();
  now - lastMouseMoveTime < 20 && (currentInput.isTouch = !1, document.removeEventListener("mousemove", onDocumentMouseMove)), lastMouseMoveTime = now;
}
__name(onDocumentMouseMove, "onDocumentMouseMove");
function onWindowBlur() {
  var activeElement = document.activeElement;
  if (isReferenceElement(activeElement)) {
    var instance = activeElement._tippy;
    activeElement.blur && !instance.state.isVisible && activeElement.blur();
  }
}
__name(onWindowBlur, "onWindowBlur");
function bindGlobalEventListeners() {
  document.addEventListener("touchstart", onDocumentTouchStart, TOUCH_OPTIONS), window.addEventListener("blur", onWindowBlur);
}
__name(bindGlobalEventListeners, "bindGlobalEventListeners");
var isBrowser = typeof window < "u" && typeof document < "u", isIE11 = isBrowser ? (
  // @ts-ignore
  !!window.msCrypto
) : !1, pluginProps = {
  animateFill: !1,
  followCursor: !1,
  inlinePositioning: !1,
  sticky: !1
}, renderProps = {
  allowHTML: !1,
  animation: "fade",
  arrow: !0,
  content: "",
  inertia: !1,
  maxWidth: 350,
  role: "tooltip",
  theme: "",
  zIndex: 9999
}, defaultProps = Object.assign({
  appendTo: TIPPY_DEFAULT_APPEND_TO,
  aria: {
    content: "auto",
    expanded: "auto"
  },
  delay: 0,
  duration: [300, 250],
  getReferenceClientRect: null,
  hideOnClick: !0,
  ignoreAttributes: !1,
  interactive: !1,
  interactiveBorder: 2,
  interactiveDebounce: 0,
  moveTransition: "",
  offset: [0, 10],
  onAfterUpdate: /* @__PURE__ */ __name(function() {
  }, "onAfterUpdate"),
  onBeforeUpdate: /* @__PURE__ */ __name(function() {
  }, "onBeforeUpdate"),
  onCreate: /* @__PURE__ */ __name(function() {
  }, "onCreate"),
  onDestroy: /* @__PURE__ */ __name(function() {
  }, "onDestroy"),
  onHidden: /* @__PURE__ */ __name(function() {
  }, "onHidden"),
  onHide: /* @__PURE__ */ __name(function() {
  }, "onHide"),
  onMount: /* @__PURE__ */ __name(function() {
  }, "onMount"),
  onShow: /* @__PURE__ */ __name(function() {
  }, "onShow"),
  onShown: /* @__PURE__ */ __name(function() {
  }, "onShown"),
  onTrigger: /* @__PURE__ */ __name(function() {
  }, "onTrigger"),
  onUntrigger: /* @__PURE__ */ __name(function() {
  }, "onUntrigger"),
  onClickOutside: /* @__PURE__ */ __name(function() {
  }, "onClickOutside"),
  placement: "top",
  plugins: [],
  popperOptions: {},
  render: null,
  showOnCreate: !1,
  touch: !0,
  trigger: "mouseenter focus",
  triggerTarget: null
}, pluginProps, renderProps), defaultKeys = Object.keys(defaultProps), setDefaultProps = /* @__PURE__ */ __name(function(partialProps) {
  var keys = Object.keys(partialProps);
  keys.forEach(function(key) {
    defaultProps[key] = partialProps[key];
  });
}, "setDefaultProps");
function getExtendedPassedProps(passedProps) {
  var plugins = passedProps.plugins || [], pluginProps2 = plugins.reduce(function(acc, plugin) {
    var name2 = plugin.name, defaultValue = plugin.defaultValue;
    if (name2) {
      var _name;
      acc[name2] = passedProps[name2] !== void 0 ? passedProps[name2] : (_name = defaultProps[name2]) != null ? _name : defaultValue;
    }
    return acc;
  }, {});
  return Object.assign({}, passedProps, pluginProps2);
}
__name(getExtendedPassedProps, "getExtendedPassedProps");
function getDataAttributeProps(reference2, plugins) {
  var propKeys = plugins ? Object.keys(getExtendedPassedProps(Object.assign({}, defaultProps, {
    plugins
  }))) : defaultKeys, props = propKeys.reduce(function(acc, key) {
    var valueAsString = (reference2.getAttribute("data-tippy-" + key) || "").trim();
    if (!valueAsString)
      return acc;
    if (key === "content")
      acc[key] = valueAsString;
    else
      try {
        acc[key] = JSON.parse(valueAsString);
      } catch {
        acc[key] = valueAsString;
      }
    return acc;
  }, {});
  return props;
}
__name(getDataAttributeProps, "getDataAttributeProps");
function evaluateProps(reference2, props) {
  var out = Object.assign({}, props, {
    content: invokeWithArgsOrReturn(props.content, [reference2])
  }, props.ignoreAttributes ? {} : getDataAttributeProps(reference2, props.plugins));
  return out.aria = Object.assign({}, defaultProps.aria, out.aria), out.aria = {
    expanded: out.aria.expanded === "auto" ? props.interactive : out.aria.expanded,
    content: out.aria.content === "auto" ? props.interactive ? null : "describedby" : out.aria.content
  }, out;
}
__name(evaluateProps, "evaluateProps");
var innerHTML = /* @__PURE__ */ __name(function() {
  return "innerHTML";
}, "innerHTML");
function dangerouslySetInnerHTML(element, html) {
  element[innerHTML()] = html;
}
__name(dangerouslySetInnerHTML, "dangerouslySetInnerHTML");
function createArrowElement(value) {
  var arrow2 = div();
  return value === !0 ? arrow2.className = ARROW_CLASS : (arrow2.className = SVG_ARROW_CLASS, isElement(value) ? arrow2.appendChild(value) : dangerouslySetInnerHTML(arrow2, value)), arrow2;
}
__name(createArrowElement, "createArrowElement");
function setContent(content, props) {
  isElement(props.content) ? (dangerouslySetInnerHTML(content, ""), content.appendChild(props.content)) : typeof props.content != "function" && (props.allowHTML ? dangerouslySetInnerHTML(content, props.content) : content.textContent = props.content);
}
__name(setContent, "setContent");
function getChildren(popper2) {
  var box = popper2.firstElementChild, boxChildren = arrayFrom(box.children);
  return {
    box,
    content: boxChildren.find(function(node) {
      return node.classList.contains(CONTENT_CLASS);
    }),
    arrow: boxChildren.find(function(node) {
      return node.classList.contains(ARROW_CLASS) || node.classList.contains(SVG_ARROW_CLASS);
    }),
    backdrop: boxChildren.find(function(node) {
      return node.classList.contains(BACKDROP_CLASS);
    })
  };
}
__name(getChildren, "getChildren");
function render(instance) {
  var popper2 = div(), box = div();
  box.className = BOX_CLASS, box.setAttribute("data-state", "hidden"), box.setAttribute("tabindex", "-1");
  var content = div();
  content.className = CONTENT_CLASS, content.setAttribute("data-state", "hidden"), setContent(content, instance.props), popper2.appendChild(box), box.appendChild(content), onUpdate(instance.props, instance.props);
  function onUpdate(prevProps, nextProps) {
    var _getChildren = getChildren(popper2), box2 = _getChildren.box, content2 = _getChildren.content, arrow2 = _getChildren.arrow;
    nextProps.theme ? box2.setAttribute("data-theme", nextProps.theme) : box2.removeAttribute("data-theme"), typeof nextProps.animation == "string" ? box2.setAttribute("data-animation", nextProps.animation) : box2.removeAttribute("data-animation"), nextProps.inertia ? box2.setAttribute("data-inertia", "") : box2.removeAttribute("data-inertia"), box2.style.maxWidth = typeof nextProps.maxWidth == "number" ? nextProps.maxWidth + "px" : nextProps.maxWidth, nextProps.role ? box2.setAttribute("role", nextProps.role) : box2.removeAttribute("role"), (prevProps.content !== nextProps.content || prevProps.allowHTML !== nextProps.allowHTML) && setContent(content2, instance.props), nextProps.arrow ? arrow2 ? prevProps.arrow !== nextProps.arrow && (box2.removeChild(arrow2), box2.appendChild(createArrowElement(nextProps.arrow))) : box2.appendChild(createArrowElement(nextProps.arrow)) : arrow2 && box2.removeChild(arrow2);
  }
  return __name(onUpdate, "onUpdate"), {
    popper: popper2,
    onUpdate
  };
}
__name(render, "render");
render.$$tippy = !0;
var idCounter = 1, mouseMoveListeners = [], mountedInstances = [];
function createTippy(reference2, passedProps) {
  var props = evaluateProps(reference2, Object.assign({}, defaultProps, getExtendedPassedProps(removeUndefinedProps(passedProps)))), showTimeout, hideTimeout, scheduleHideAnimationFrame, isVisibleFromClick = !1, didHideDueToDocumentMouseDown = !1, didTouchMove = !1, ignoreOnFirstUpdate = !1, lastTriggerEvent, currentTransitionEndListener, onFirstUpdate, listeners = [], debouncedOnMouseMove = debounce(onMouseMove, props.interactiveDebounce), currentTarget, id = idCounter++, popperInstance = null, plugins = unique(props.plugins), state = {
    // Is the instance currently enabled?
    isEnabled: !0,
    // Is the tippy currently showing and not transitioning out?
    isVisible: !1,
    // Has the instance been destroyed?
    isDestroyed: !1,
    // Is the tippy currently mounted to the DOM?
    isMounted: !1,
    // Has the tippy finished transitioning in?
    isShown: !1
  }, instance = {
    // properties
    id,
    reference: reference2,
    popper: div(),
    popperInstance,
    props,
    state,
    plugins,
    // methods
    clearDelayTimeouts,
    setProps,
    setContent: setContent2,
    show,
    hide: hide2,
    hideWithInteractivity,
    enable,
    disable,
    unmount,
    destroy
  };
  if (!props.render)
    return instance;
  var _props$render = props.render(instance), popper2 = _props$render.popper, onUpdate = _props$render.onUpdate;
  popper2.setAttribute("data-tippy-root", ""), popper2.id = "tippy-" + instance.id, instance.popper = popper2, reference2._tippy = instance, popper2._tippy = instance;
  var pluginsHooks = plugins.map(function(plugin) {
    return plugin.fn(instance);
  }), hasAriaExpanded = reference2.hasAttribute("aria-expanded");
  return addListeners(), handleAriaExpandedAttribute(), handleStyles(), invokeHook("onCreate", [instance]), props.showOnCreate && scheduleShow(), popper2.addEventListener("mouseenter", function() {
    instance.props.interactive && instance.state.isVisible && instance.clearDelayTimeouts();
  }), popper2.addEventListener("mouseleave", function() {
    instance.props.interactive && instance.props.trigger.indexOf("mouseenter") >= 0 && getDocument().addEventListener("mousemove", debouncedOnMouseMove);
  }), instance;
  function getNormalizedTouchSettings() {
    var touch = instance.props.touch;
    return Array.isArray(touch) ? touch : [touch, 0];
  }
  __name(getNormalizedTouchSettings, "getNormalizedTouchSettings");
  function getIsCustomTouchBehavior() {
    return getNormalizedTouchSettings()[0] === "hold";
  }
  __name(getIsCustomTouchBehavior, "getIsCustomTouchBehavior");
  function getIsDefaultRenderFn() {
    var _instance$props$rende;
    return !!((_instance$props$rende = instance.props.render) != null && _instance$props$rende.$$tippy);
  }
  __name(getIsDefaultRenderFn, "getIsDefaultRenderFn");
  function getCurrentTarget() {
    return currentTarget || reference2;
  }
  __name(getCurrentTarget, "getCurrentTarget");
  function getDocument() {
    var parent = getCurrentTarget().parentNode;
    return parent ? getOwnerDocument(parent) : document;
  }
  __name(getDocument, "getDocument");
  function getDefaultTemplateChildren() {
    return getChildren(popper2);
  }
  __name(getDefaultTemplateChildren, "getDefaultTemplateChildren");
  function getDelay(isShow) {
    return instance.state.isMounted && !instance.state.isVisible || currentInput.isTouch || lastTriggerEvent && lastTriggerEvent.type === "focus" ? 0 : getValueAtIndexOrReturn(instance.props.delay, isShow ? 0 : 1, defaultProps.delay);
  }
  __name(getDelay, "getDelay");
  function handleStyles(fromHide) {
    fromHide === void 0 && (fromHide = !1), popper2.style.pointerEvents = instance.props.interactive && !fromHide ? "" : "none", popper2.style.zIndex = "" + instance.props.zIndex;
  }
  __name(handleStyles, "handleStyles");
  function invokeHook(hook, args, shouldInvokePropsHook) {
    if (shouldInvokePropsHook === void 0 && (shouldInvokePropsHook = !0), pluginsHooks.forEach(function(pluginHooks) {
      pluginHooks[hook] && pluginHooks[hook].apply(pluginHooks, args);
    }), shouldInvokePropsHook) {
      var _instance$props;
      (_instance$props = instance.props)[hook].apply(_instance$props, args);
    }
  }
  __name(invokeHook, "invokeHook");
  function handleAriaContentAttribute() {
    var aria = instance.props.aria;
    if (aria.content) {
      var attr = "aria-" + aria.content, id2 = popper2.id, nodes = normalizeToArray(instance.props.triggerTarget || reference2);
      nodes.forEach(function(node) {
        var currentValue = node.getAttribute(attr);
        if (instance.state.isVisible)
          node.setAttribute(attr, currentValue ? currentValue + " " + id2 : id2);
        else {
          var nextValue = currentValue && currentValue.replace(id2, "").trim();
          nextValue ? node.setAttribute(attr, nextValue) : node.removeAttribute(attr);
        }
      });
    }
  }
  __name(handleAriaContentAttribute, "handleAriaContentAttribute");
  function handleAriaExpandedAttribute() {
    if (!(hasAriaExpanded || !instance.props.aria.expanded)) {
      var nodes = normalizeToArray(instance.props.triggerTarget || reference2);
      nodes.forEach(function(node) {
        instance.props.interactive ? node.setAttribute("aria-expanded", instance.state.isVisible && node === getCurrentTarget() ? "true" : "false") : node.removeAttribute("aria-expanded");
      });
    }
  }
  __name(handleAriaExpandedAttribute, "handleAriaExpandedAttribute");
  function cleanupInteractiveMouseListeners() {
    getDocument().removeEventListener("mousemove", debouncedOnMouseMove), mouseMoveListeners = mouseMoveListeners.filter(function(listener) {
      return listener !== debouncedOnMouseMove;
    });
  }
  __name(cleanupInteractiveMouseListeners, "cleanupInteractiveMouseListeners");
  function onDocumentPress(event) {
    if (!(currentInput.isTouch && (didTouchMove || event.type === "mousedown"))) {
      var actualTarget = event.composedPath && event.composedPath()[0] || event.target;
      if (!(instance.props.interactive && actualContains(popper2, actualTarget))) {
        if (normalizeToArray(instance.props.triggerTarget || reference2).some(function(el) {
          return actualContains(el, actualTarget);
        })) {
          if (currentInput.isTouch || instance.state.isVisible && instance.props.trigger.indexOf("click") >= 0)
            return;
        } else
          invokeHook("onClickOutside", [instance, event]);
        instance.props.hideOnClick === !0 && (instance.clearDelayTimeouts(), instance.hide(), didHideDueToDocumentMouseDown = !0, setTimeout(function() {
          didHideDueToDocumentMouseDown = !1;
        }), instance.state.isMounted || removeDocumentPress());
      }
    }
  }
  __name(onDocumentPress, "onDocumentPress");
  function onTouchMove() {
    didTouchMove = !0;
  }
  __name(onTouchMove, "onTouchMove");
  function onTouchStart() {
    didTouchMove = !1;
  }
  __name(onTouchStart, "onTouchStart");
  function addDocumentPress() {
    var doc = getDocument();
    doc.addEventListener("mousedown", onDocumentPress, !0), doc.addEventListener("touchend", onDocumentPress, TOUCH_OPTIONS), doc.addEventListener("touchstart", onTouchStart, TOUCH_OPTIONS), doc.addEventListener("touchmove", onTouchMove, TOUCH_OPTIONS);
  }
  __name(addDocumentPress, "addDocumentPress");
  function removeDocumentPress() {
    var doc = getDocument();
    doc.removeEventListener("mousedown", onDocumentPress, !0), doc.removeEventListener("touchend", onDocumentPress, TOUCH_OPTIONS), doc.removeEventListener("touchstart", onTouchStart, TOUCH_OPTIONS), doc.removeEventListener("touchmove", onTouchMove, TOUCH_OPTIONS);
  }
  __name(removeDocumentPress, "removeDocumentPress");
  function onTransitionedOut(duration, callback) {
    onTransitionEnd(duration, function() {
      !instance.state.isVisible && popper2.parentNode && popper2.parentNode.contains(popper2) && callback();
    });
  }
  __name(onTransitionedOut, "onTransitionedOut");
  function onTransitionedIn(duration, callback) {
    onTransitionEnd(duration, callback);
  }
  __name(onTransitionedIn, "onTransitionedIn");
  function onTransitionEnd(duration, callback) {
    var box = getDefaultTemplateChildren().box;
    function listener(event) {
      event.target === box && (updateTransitionEndListener(box, "remove", listener), callback());
    }
    if (__name(listener, "listener"), duration === 0)
      return callback();
    updateTransitionEndListener(box, "remove", currentTransitionEndListener), updateTransitionEndListener(box, "add", listener), currentTransitionEndListener = listener;
  }
  __name(onTransitionEnd, "onTransitionEnd");
  function on(eventType, handler, options) {
    options === void 0 && (options = !1);
    var nodes = normalizeToArray(instance.props.triggerTarget || reference2);
    nodes.forEach(function(node) {
      node.addEventListener(eventType, handler, options), listeners.push({
        node,
        eventType,
        handler,
        options
      });
    });
  }
  __name(on, "on");
  function addListeners() {
    getIsCustomTouchBehavior() && (on("touchstart", onTrigger2, {
      passive: !0
    }), on("touchend", onMouseLeave, {
      passive: !0
    })), splitBySpaces(instance.props.trigger).forEach(function(eventType) {
      if (eventType !== "manual")
        switch (on(eventType, onTrigger2), eventType) {
          case "mouseenter":
            on("mouseleave", onMouseLeave);
            break;
          case "focus":
            on(isIE11 ? "focusout" : "blur", onBlurOrFocusOut);
            break;
          case "focusin":
            on("focusout", onBlurOrFocusOut);
            break;
        }
    });
  }
  __name(addListeners, "addListeners");
  function removeListeners() {
    listeners.forEach(function(_ref) {
      var node = _ref.node, eventType = _ref.eventType, handler = _ref.handler, options = _ref.options;
      node.removeEventListener(eventType, handler, options);
    }), listeners = [];
  }
  __name(removeListeners, "removeListeners");
  function onTrigger2(event) {
    var _lastTriggerEvent, shouldScheduleClickHide = !1;
    if (!(!instance.state.isEnabled || isEventListenerStopped(event) || didHideDueToDocumentMouseDown)) {
      var wasFocused = ((_lastTriggerEvent = lastTriggerEvent) == null ? void 0 : _lastTriggerEvent.type) === "focus";
      lastTriggerEvent = event, currentTarget = event.currentTarget, handleAriaExpandedAttribute(), !instance.state.isVisible && isMouseEvent(event) && mouseMoveListeners.forEach(function(listener) {
        return listener(event);
      }), event.type === "click" && (instance.props.trigger.indexOf("mouseenter") < 0 || isVisibleFromClick) && instance.props.hideOnClick !== !1 && instance.state.isVisible ? shouldScheduleClickHide = !0 : scheduleShow(event), event.type === "click" && (isVisibleFromClick = !shouldScheduleClickHide), shouldScheduleClickHide && !wasFocused && scheduleHide(event);
    }
  }
  __name(onTrigger2, "onTrigger");
  function onMouseMove(event) {
    var target = event.target, isCursorOverReferenceOrPopper = getCurrentTarget().contains(target) || popper2.contains(target);
    if (!(event.type === "mousemove" && isCursorOverReferenceOrPopper)) {
      var popperTreeData = getNestedPopperTree().concat(popper2).map(function(popper3) {
        var _instance$popperInsta, instance2 = popper3._tippy, state2 = (_instance$popperInsta = instance2.popperInstance) == null ? void 0 : _instance$popperInsta.state;
        return state2 ? {
          popperRect: popper3.getBoundingClientRect(),
          popperState: state2,
          props
        } : null;
      }).filter(Boolean);
      isCursorOutsideInteractiveBorder(popperTreeData, event) && (cleanupInteractiveMouseListeners(), scheduleHide(event));
    }
  }
  __name(onMouseMove, "onMouseMove");
  function onMouseLeave(event) {
    var shouldBail = isEventListenerStopped(event) || instance.props.trigger.indexOf("click") >= 0 && isVisibleFromClick;
    if (!shouldBail) {
      if (instance.props.interactive) {
        instance.hideWithInteractivity(event);
        return;
      }
      scheduleHide(event);
    }
  }
  __name(onMouseLeave, "onMouseLeave");
  function onBlurOrFocusOut(event) {
    instance.props.trigger.indexOf("focusin") < 0 && event.target !== getCurrentTarget() || instance.props.interactive && event.relatedTarget && popper2.contains(event.relatedTarget) || scheduleHide(event);
  }
  __name(onBlurOrFocusOut, "onBlurOrFocusOut");
  function isEventListenerStopped(event) {
    return currentInput.isTouch ? getIsCustomTouchBehavior() !== event.type.indexOf("touch") >= 0 : !1;
  }
  __name(isEventListenerStopped, "isEventListenerStopped");
  function createPopperInstance() {
    destroyPopperInstance();
    var _instance$props2 = instance.props, popperOptions = _instance$props2.popperOptions, placement = _instance$props2.placement, offset2 = _instance$props2.offset, getReferenceClientRect = _instance$props2.getReferenceClientRect, moveTransition = _instance$props2.moveTransition, arrow2 = getIsDefaultRenderFn() ? getChildren(popper2).arrow : null, computedReference = getReferenceClientRect ? {
      getBoundingClientRect: getReferenceClientRect,
      contextElement: getReferenceClientRect.contextElement || getCurrentTarget()
    } : reference2, tippyModifier = {
      name: "$$tippy",
      enabled: !0,
      phase: "beforeWrite",
      requires: ["computeStyles"],
      fn: /* @__PURE__ */ __name(function(_ref2) {
        var state2 = _ref2.state;
        if (getIsDefaultRenderFn()) {
          var _getDefaultTemplateCh = getDefaultTemplateChildren(), box = _getDefaultTemplateCh.box;
          ["placement", "reference-hidden", "escaped"].forEach(function(attr) {
            attr === "placement" ? box.setAttribute("data-placement", state2.placement) : state2.attributes.popper["data-popper-" + attr] ? box.setAttribute("data-" + attr, "") : box.removeAttribute("data-" + attr);
          }), state2.attributes.popper = {};
        }
      }, "fn")
    }, modifiers = [{
      name: "offset",
      options: {
        offset: offset2
      }
    }, {
      name: "preventOverflow",
      options: {
        padding: {
          top: 2,
          bottom: 2,
          left: 5,
          right: 5
        }
      }
    }, {
      name: "flip",
      options: {
        padding: 5
      }
    }, {
      name: "computeStyles",
      options: {
        adaptive: !moveTransition
      }
    }, tippyModifier];
    getIsDefaultRenderFn() && arrow2 && modifiers.push({
      name: "arrow",
      options: {
        element: arrow2,
        padding: 3
      }
    }), modifiers.push.apply(modifiers, (popperOptions == null ? void 0 : popperOptions.modifiers) || []), instance.popperInstance = createPopper(computedReference, popper2, Object.assign({}, popperOptions, {
      placement,
      onFirstUpdate,
      modifiers
    }));
  }
  __name(createPopperInstance, "createPopperInstance");
  function destroyPopperInstance() {
    instance.popperInstance && (instance.popperInstance.destroy(), instance.popperInstance = null);
  }
  __name(destroyPopperInstance, "destroyPopperInstance");
  function mount() {
    var appendTo = instance.props.appendTo, parentNode, node = getCurrentTarget();
    instance.props.interactive && appendTo === TIPPY_DEFAULT_APPEND_TO || appendTo === "parent" ? parentNode = node.parentNode : parentNode = invokeWithArgsOrReturn(appendTo, [node]), parentNode.contains(popper2) || parentNode.appendChild(popper2), instance.state.isMounted = !0, createPopperInstance();
  }
  __name(mount, "mount");
  function getNestedPopperTree() {
    return arrayFrom(popper2.querySelectorAll("[data-tippy-root]"));
  }
  __name(getNestedPopperTree, "getNestedPopperTree");
  function scheduleShow(event) {
    instance.clearDelayTimeouts(), event && invokeHook("onTrigger", [instance, event]), addDocumentPress();
    var delay = getDelay(!0), _getNormalizedTouchSe = getNormalizedTouchSettings(), touchValue = _getNormalizedTouchSe[0], touchDelay = _getNormalizedTouchSe[1];
    currentInput.isTouch && touchValue === "hold" && touchDelay && (delay = touchDelay), delay ? showTimeout = setTimeout(function() {
      instance.show();
    }, delay) : instance.show();
  }
  __name(scheduleShow, "scheduleShow");
  function scheduleHide(event) {
    if (instance.clearDelayTimeouts(), invokeHook("onUntrigger", [instance, event]), !instance.state.isVisible) {
      removeDocumentPress();
      return;
    }
    if (!(instance.props.trigger.indexOf("mouseenter") >= 0 && instance.props.trigger.indexOf("click") >= 0 && ["mouseleave", "mousemove"].indexOf(event.type) >= 0 && isVisibleFromClick)) {
      var delay = getDelay(!1);
      delay ? hideTimeout = setTimeout(function() {
        instance.state.isVisible && instance.hide();
      }, delay) : scheduleHideAnimationFrame = requestAnimationFrame(function() {
        instance.hide();
      });
    }
  }
  __name(scheduleHide, "scheduleHide");
  function enable() {
    instance.state.isEnabled = !0;
  }
  __name(enable, "enable");
  function disable() {
    instance.hide(), instance.state.isEnabled = !1;
  }
  __name(disable, "disable");
  function clearDelayTimeouts() {
    clearTimeout(showTimeout), clearTimeout(hideTimeout), cancelAnimationFrame(scheduleHideAnimationFrame);
  }
  __name(clearDelayTimeouts, "clearDelayTimeouts");
  function setProps(partialProps) {
    if (!instance.state.isDestroyed) {
      invokeHook("onBeforeUpdate", [instance, partialProps]), removeListeners();
      var prevProps = instance.props, nextProps = evaluateProps(reference2, Object.assign({}, prevProps, removeUndefinedProps(partialProps), {
        ignoreAttributes: !0
      }));
      instance.props = nextProps, addListeners(), prevProps.interactiveDebounce !== nextProps.interactiveDebounce && (cleanupInteractiveMouseListeners(), debouncedOnMouseMove = debounce(onMouseMove, nextProps.interactiveDebounce)), prevProps.triggerTarget && !nextProps.triggerTarget ? normalizeToArray(prevProps.triggerTarget).forEach(function(node) {
        node.removeAttribute("aria-expanded");
      }) : nextProps.triggerTarget && reference2.removeAttribute("aria-expanded"), handleAriaExpandedAttribute(), handleStyles(), onUpdate && onUpdate(prevProps, nextProps), instance.popperInstance && (createPopperInstance(), getNestedPopperTree().forEach(function(nestedPopper) {
        requestAnimationFrame(nestedPopper._tippy.popperInstance.forceUpdate);
      })), invokeHook("onAfterUpdate", [instance, partialProps]);
    }
  }
  __name(setProps, "setProps");
  function setContent2(content) {
    instance.setProps({
      content
    });
  }
  __name(setContent2, "setContent");
  function show() {
    var isAlreadyVisible = instance.state.isVisible, isDestroyed = instance.state.isDestroyed, isDisabled = !instance.state.isEnabled, isTouchAndTouchDisabled = currentInput.isTouch && !instance.props.touch, duration = getValueAtIndexOrReturn(instance.props.duration, 0, defaultProps.duration);
    if (!(isAlreadyVisible || isDestroyed || isDisabled || isTouchAndTouchDisabled) && !getCurrentTarget().hasAttribute("disabled") && (invokeHook("onShow", [instance], !1), instance.props.onShow(instance) !== !1)) {
      if (instance.state.isVisible = !0, getIsDefaultRenderFn() && (popper2.style.visibility = "visible"), handleStyles(), addDocumentPress(), instance.state.isMounted || (popper2.style.transition = "none"), getIsDefaultRenderFn()) {
        var _getDefaultTemplateCh2 = getDefaultTemplateChildren(), box = _getDefaultTemplateCh2.box, content = _getDefaultTemplateCh2.content;
        setTransitionDuration([box, content], 0);
      }
      onFirstUpdate = /* @__PURE__ */ __name(function() {
        var _instance$popperInsta2;
        if (!(!instance.state.isVisible || ignoreOnFirstUpdate)) {
          if (ignoreOnFirstUpdate = !0, popper2.offsetHeight, popper2.style.transition = instance.props.moveTransition, getIsDefaultRenderFn() && instance.props.animation) {
            var _getDefaultTemplateCh3 = getDefaultTemplateChildren(), _box = _getDefaultTemplateCh3.box, _content = _getDefaultTemplateCh3.content;
            setTransitionDuration([_box, _content], duration), setVisibilityState([_box, _content], "visible");
          }
          handleAriaContentAttribute(), handleAriaExpandedAttribute(), pushIfUnique(mountedInstances, instance), (_instance$popperInsta2 = instance.popperInstance) == null || _instance$popperInsta2.forceUpdate(), invokeHook("onMount", [instance]), instance.props.animation && getIsDefaultRenderFn() && onTransitionedIn(duration, function() {
            instance.state.isShown = !0, invokeHook("onShown", [instance]);
          });
        }
      }, "onFirstUpdate"), mount();
    }
  }
  __name(show, "show");
  function hide2() {
    var isAlreadyHidden = !instance.state.isVisible, isDestroyed = instance.state.isDestroyed, isDisabled = !instance.state.isEnabled, duration = getValueAtIndexOrReturn(instance.props.duration, 1, defaultProps.duration);
    if (!(isAlreadyHidden || isDestroyed || isDisabled) && (invokeHook("onHide", [instance], !1), instance.props.onHide(instance) !== !1)) {
      if (instance.state.isVisible = !1, instance.state.isShown = !1, ignoreOnFirstUpdate = !1, isVisibleFromClick = !1, getIsDefaultRenderFn() && (popper2.style.visibility = "hidden"), cleanupInteractiveMouseListeners(), removeDocumentPress(), handleStyles(!0), getIsDefaultRenderFn()) {
        var _getDefaultTemplateCh4 = getDefaultTemplateChildren(), box = _getDefaultTemplateCh4.box, content = _getDefaultTemplateCh4.content;
        instance.props.animation && (setTransitionDuration([box, content], duration), setVisibilityState([box, content], "hidden"));
      }
      handleAriaContentAttribute(), handleAriaExpandedAttribute(), instance.props.animation ? getIsDefaultRenderFn() && onTransitionedOut(duration, instance.unmount) : instance.unmount();
    }
  }
  __name(hide2, "hide");
  function hideWithInteractivity(event) {
    getDocument().addEventListener("mousemove", debouncedOnMouseMove), pushIfUnique(mouseMoveListeners, debouncedOnMouseMove), debouncedOnMouseMove(event);
  }
  __name(hideWithInteractivity, "hideWithInteractivity");
  function unmount() {
    instance.state.isVisible && instance.hide(), instance.state.isMounted && (destroyPopperInstance(), getNestedPopperTree().forEach(function(nestedPopper) {
      nestedPopper._tippy.unmount();
    }), popper2.parentNode && popper2.parentNode.removeChild(popper2), mountedInstances = mountedInstances.filter(function(i) {
      return i !== instance;
    }), instance.state.isMounted = !1, invokeHook("onHidden", [instance]));
  }
  __name(unmount, "unmount");
  function destroy() {
    instance.state.isDestroyed || (instance.clearDelayTimeouts(), instance.unmount(), removeListeners(), delete reference2._tippy, instance.state.isDestroyed = !0, invokeHook("onDestroy", [instance]));
  }
  __name(destroy, "destroy");
}
__name(createTippy, "createTippy");
function tippy$1(targets, optionalProps) {
  optionalProps === void 0 && (optionalProps = {});
  var plugins = defaultProps.plugins.concat(optionalProps.plugins || []);
  bindGlobalEventListeners();
  var passedProps = Object.assign({}, optionalProps, {
    plugins
  }), elements = getArrayOfElements(targets), instances = elements.reduce(function(acc, reference2) {
    var instance = reference2 && createTippy(reference2, passedProps);
    return instance && acc.push(instance), acc;
  }, []);
  return isElement(targets) ? instances[0] : instances;
}
__name(tippy$1, "tippy$1");
tippy$1.defaultProps = defaultProps;
tippy$1.setDefaultProps = setDefaultProps;
tippy$1.currentInput = currentInput;
Object.assign({}, applyStyles$1, {
  effect: /* @__PURE__ */ __name(function(_ref) {
    var state = _ref.state, initialStyles = {
      popper: {
        position: state.options.strategy,
        left: "0",
        top: "0",
        margin: "0"
      },
      arrow: {
        position: "absolute"
      },
      reference: {}
    };
    Object.assign(state.elements.popper.style, initialStyles.popper), state.styles = initialStyles, state.elements.arrow && Object.assign(state.elements.arrow.style, initialStyles.arrow);
  }, "effect")
});
tippy$1.setDefaultProps({
  render
});
function lookupOwnedDeployables(owner, filter) {
  if (owner.is_deployable())
    return {};
  if (owner.isToken)
    return {};
  let foundDeployables = game.actors.filter((a) => {
    var _a19;
    return !!(a.is_deployable() && ((_a19 = a.system.owner) == null ? void 0 : _a19.id) === owner.uuid);
  }), result = {};
  for (let dep of foundDeployables)
    (!filter || filter.includes(dep.system.lid)) && (result[dep.system.lid] = dep);
  return result;
}
__name(lookupOwnedDeployables, "lookupOwnedDeployables");
function slugify(name2, dash = "_") {
  return name2.trim().replace(/[:\\\/-\s]+/g, dash).toLowerCase();
}
__name(slugify, "slugify");
function randomString(length) {
  let result = "";
  const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
  for (let i = 0; i < length; i++) {
    const randomInd = Math.floor(Math.random() * characters.length);
    result += characters.charAt(randomInd);
  }
  return result;
}
__name(randomString, "randomString");
const defaultPlaceholder = "// MISSING ENTRY //";
function inc_if(val, test) {
  return test ? val : "";
}
__name(inc_if, "inc_if");
function lancerDiceRoll(roll, tooltip, icon) {
  const iconHTML = icon ? `<i class="${icon}"></i>` : "", tooltipHTML = tooltip ? `<div style="text-align: left;">${tooltip}</div>` : "";
  return `
<div class="dice-roll lancer-dice-roll collapse">
  <div class="dice-result">
    <div class="dice-formula lancer-dice-formula flexrow">
      <span style="text-align: left; margin-left: 5px;">${roll.formula}</span>
      <span class="dice-total lancer-dice-total major">${roll.total}</span>${iconHTML}
    </div>
    ${tooltipHTML}
  </div>
</div>
  `;
}
__name(lancerDiceRoll, "lancerDiceRoll");
function selected(truthytest) {
  return truthytest ? "selected" : "";
}
__name(selected, "selected");
function array_path_edit_changes(target, flat_path, value, mode) {
  flat_path = formatDotpath(flat_path);
  let split = flat_path.split("."), tail = split.splice(split.length - 1)[0], lead = split.join("."), index2 = parseInt(tail), array2 = resolveDotpath(target, lead);
  if (Array.isArray(array2) && !Number.isNaN(index2)) {
    if (index2 > array2.length && (index2 = array2.length), index2 < 0 && (index2 = array2.length + index2 + 1, index2 < 0 && (index2 = 0)), mode == "delete")
      return {
        path: lead,
        new_val: [...array2.slice(0, index2), ...array2.slice(index2 + 1)]
        // Drop element at index
      };
    if (mode == "insert")
      return {
        path: lead,
        new_val: [...array2.slice(0, index2), value, ...array2.slice(index2)]
        // Insert element at index
      };
    throw new Error("Invalid path edit mode " + mode);
  } else
    throw new Error(`Unable to insert array item "${lead}[${tail}]": not an array (or not a valid index)`);
}
__name(array_path_edit_changes, "array_path_edit_changes");
const _IconFactory = class _IconFactory {
  constructor(args) {
    if (this.classes = [], this.icon_prefix = "", args.light && this.classes.push("i--light"), args.dark && this.classes.push("i--dark"), this.classes.push(`i--${args.size ?? "m"}`), args.icon_set) {
      let split = args.icon_set.split(",");
      split.length > 1 ? (this.classes.push(split[0]), this.icon_prefix = split[1].trim() + "-") : this.classes.push(args.icon_set);
    }
  }
  // Produces an icon with the given glyph using configured classes
  r(icon) {
    return `<i class="${this.classes.join(" ")} ${this.icon_prefix}${icon}"> </i>`;
  }
};
__name(_IconFactory, "IconFactory");
let IconFactory = _IconFactory;
function effectBox(title, text, options) {
  if (text) {
    const flowButton = options != null && options.flow ? `<div class="action-flow-container flexrow">
        <a class="effect-flow lancer-button"><i class="cci cci-free-action i--sm"></i><span>USE</span></a>
        <hr class="vsep">
      </div>` : "";
    return `
      <div class="effect-box ${(options == null ? void 0 : options.add_classes) || ""}">
        <span class="effect-title clipped-bot">${title}</span>
        <span class="effect-text" style="padding: 0 0.5em 0.5em 0.5em;">
          ${flowButton}
          ${text}
        </span>
      </div>
      `;
  } else
    return "";
}
__name(effectBox, "effectBox");
function spDisplay(sp) {
  const sp_num = parseInt(sp.toString());
  if (isNaN(sp_num))
    return "";
  let icons = "";
  for (let i = 0; i < sp_num; i++)
    icons += '<i class="cci cci-system-point i--s"> </i>';
  return `<div class="sp-wrapper">
            ${icons}
            <span class="medium" style="padding: 5px;">${sp} SYSTEM POINTS</span>
          </div>`;
}
__name(spDisplay, "spDisplay");
function activationIcon(activation) {
  switch (activation) {
    case ActivationType.Quick:
      return "cci cci-activation-quick";
    case ActivationType.Full:
      return "cci cci-activation-full";
    case ActivationType.Invade:
    case ActivationType.QuickTech:
      return "cci cci-tech-quick";
    case ActivationType.FullTech:
      return "cci cci-tech-full";
    case ActivationType.Reaction:
      return "cci cci-reaction";
    case ActivationType.Protocol:
      return "cci cci-protocol";
    case ActivationType.Free:
    case ActivationType.Passive:
    default:
      return "cci cci-free-action";
  }
}
__name(activationIcon, "activationIcon");
function activationStyle(activation) {
  switch (activation) {
    case ActivationType.Quick:
      return "lancer-quick";
    case ActivationType.Full:
      return "lancer-full";
    case ActivationType.Invade:
    case ActivationType.QuickTech:
    case ActivationType.FullTech:
      return "lancer-tech";
    case ActivationType.Reaction:
      return "lancer-reaction";
    case ActivationType.Protocol:
      return "lancer-protocol";
    case ActivationType.Free:
      return "lancer-free";
    case ActivationType.Passive:
    default:
      return "lancer-secondary";
  }
}
__name(activationStyle, "activationStyle");
function manufacturerStyle(mfr, border) {
  let manufacturer = slugify(mfr, "-");
  return ["gms", "ips-n", "ssc", "horus", "ha"].includes(manufacturer) || (manufacturer = "primary"), `lancer${border ? "-border" : ""}-${manufacturer}`;
}
__name(manufacturerStyle, "manufacturerStyle");
function safe_json_parse(str) {
  try {
    return JSON.parse(str);
  } catch {
    return null;
  }
}
__name(safe_json_parse, "safe_json_parse");
function formatDotpath(path) {
  return path.replace(/\[/g, ".").replace(/]/g, "");
}
__name(formatDotpath, "formatDotpath");
function stepwiseResolveDotpath(obj, dotpath) {
  let pathlets = formatDotpath(dotpath).split("."), result = [
    {
      pathlet: null,
      val: obj
    }
  ];
  for (let pathlet of pathlets)
    obj = obj == null ? void 0 : obj[pathlet], result.push({
      pathlet,
      val: obj
    });
  return result;
}
__name(stepwiseResolveDotpath, "stepwiseResolveDotpath");
function drilldownDocument(rootDoc, path) {
  let steps = stepwiseResolveDotpath(rootDoc, path);
  for (let i = steps.length - 1; i >= 0; i--) {
    let step = steps[i];
    if (step.val instanceof foundry.abstract.Document) {
      let sub_path = steps.slice(i + 1).map((v) => v.pathlet).join(".");
      return { sub_doc: step.val, sub_path, terminus: steps[steps.length - 1].val };
    }
  }
  throw new Error("Drilldown document must have at least one document in its path");
}
__name(drilldownDocument, "drilldownDocument");
function resolveDotpath(obj, dotpath, default_ = null, opts) {
  let path = stepwiseResolveDotpath(obj, dotpath), item;
  return opts != null && opts.shorten_by ? item = path[path.length - 1 - opts.shorten_by] : item = path[path.length - 1], item.val === void 0 ? default_ : item.val;
}
__name(resolveDotpath, "resolveDotpath");
function helper_root_doc(options) {
  var _a19;
  let root = (_a19 = options.data) == null ? void 0 : _a19.root;
  return root.item ?? root.actor;
}
__name(helper_root_doc, "helper_root_doc");
const RESOLVE_FAIL = Symbol("Fail");
function resolveHelperDotpath(options, path, default_ = null, try_parent = !1) {
  var _a19;
  if (try_parent) {
    let data2 = options.data;
    for (; data2; ) {
      let resolved = resolveDotpath(data2 == null ? void 0 : data2.root, path, RESOLVE_FAIL);
      if (resolved != RESOLVE_FAIL)
        return resolved;
      data2 = data2._parent;
    }
    return default_;
  } else
    return resolveDotpath((_a19 = options.data) == null ? void 0 : _a19.root, path, default_);
}
__name(resolveHelperDotpath, "resolveHelperDotpath");
function extendHelper(orig_options, overrides, defaults2 = {}) {
  return {
    fn: orig_options.fn,
    inverse: orig_options.inverse,
    hash: {
      ...defaults2,
      ...orig_options.hash,
      ...overrides
    },
    data: orig_options.data
  };
}
__name(extendHelper, "extendHelper");
function spoofHelper(fake_data) {
  let fail_callback = /* @__PURE__ */ __name(() => {
    throw new Error("spoofHelper is not sufficient here.");
  }, "fail_callback");
  return {
    fn: fail_callback,
    inverse: fail_callback,
    hash: {},
    data: fake_data
  };
}
__name(spoofHelper, "spoofHelper");
function handleGenControls(html, doc, post_hook) {
  html.find(".gen-control").off("click").on("click", async (event) => {
    var _a19, _b;
    event.stopPropagation();
    let elt = event.currentTarget, raw_val = elt.dataset.actionValue, val;
    if (raw_val) {
      let result = await parse_control_val(raw_val);
      if (result.success)
        val = result.val;
      else {
        console.error(`Gen control failed: Bad data-action-value: ${raw_val}`);
        return;
      }
    }
    let path = elt.dataset.path, docOverride = null, dd;
    if (elt.dataset.uuid) {
      if (docOverride = await fromUuid(elt.dataset.uuid), !docOverride)
        return (_a19 = ui.notifications) == null ? void 0 : _a19.error("Bad uuid: " + elt.dataset.uuid);
      dd = drilldownDocument(docOverride, path);
    } else
      dd = drilldownDocument(doc, path);
    let ctx = {
      // Base
      elt,
      path,
      action: elt.dataset.action,
      raw_val: elt.dataset.actionValue,
      base_document: doc,
      // Derived
      path_target: dd.terminus,
      parsed_val: val,
      target_document: dd.sub_doc,
      relative_path: dd.sub_path
    };
    if (ctx.path ? ctx.action ? dd.sub_doc || console.error("Gen control failed: target document does not exist") : console.error("Gen control failed: missing action") : console.error("Gen control failed: missing path"), ctx.action == "delete")
      (_b = ctx.path_target) == null || _b.delete();
    else if (ctx.action == "splice") {
      let changes = array_path_edit_changes(ctx.target_document, ctx.relative_path, null, "delete");
      await ctx.target_document.update({ [changes.path]: changes.new_val });
    } else if (ctx.action == "null")
      await ctx.target_document.update({ [ctx.relative_path]: null });
    else if (ctx.action == "set" && ctx.parsed_val !== void 0)
      await ctx.target_document.update({ [ctx.relative_path]: ctx.parsed_val });
    else if (ctx.action == "append") {
      let changes = array_path_edit_changes(ctx.target_document, ctx.relative_path + "[-1]", val, "insert");
      await ctx.target_document.update({ [changes.path]: changes.new_val });
    } else if (ctx.action == "insert") {
      let changes = array_path_edit_changes(ctx.target_document, ctx.relative_path, val, "insert");
      await ctx.target_document.update({ [changes.path]: changes.new_val });
    } else
      console.error("Unknown gen control action: " + ctx.action);
    post_hook && post_hook(ctx);
  });
}
__name(handleGenControls, "handleGenControls");
async function parse_control_val(raw_val) {
  let match = raw_val.match(/\((.*?)\)(.*)/);
  if (match) {
    let type2 = match[1], val = match[2];
    switch (type2) {
      case "string":
        return { success: !0, val };
      case "int":
        let parsed_int = parseInt(val);
        if (!Number.isNaN(parsed_int))
          return { success: !0, val: parsed_int };
        break;
      case "float":
        let parsed_float = parseFloat(val);
        if (!Number.isNaN(parsed_float))
          return { success: !0, val: parsed_float };
        break;
      case "bool":
        if (val == "true")
          return { success: !0, val: !0 };
        if (val == "false")
          return { success: !0, val: !1 };
      case "struct":
        return control_structs(val);
    }
  }
  return { success: !1, val: null };
}
__name(parse_control_val, "parse_control_val");
async function control_structs(key) {
  switch (key) {
    case "empty_array":
      return { success: !0, val: [] };
    case "string":
      return { success: !0, val: "" };
    case "npc_stat_array":
      return { success: !0, val: [0, 0, 0] };
    case "frame_trait":
      return { success: !0, val: FRAME_TRAIT() };
    case "bonus":
      return { success: !0, val: BONUS() };
    case "action":
      return { success: !0, val: ACTION() };
    case "counter":
      return { success: !0, val: COUNTER() };
    case "tag":
      return { success: !0, val: TAG() };
    case "bond_question":
      return { success: !0, val: BOND_QUESTION() };
    case "power":
      return { success: !0, val: POWER() };
    case "mount_type":
      return { success: !0, val: MountType.Main };
    case "range":
      return { success: !0, val: RANGE() };
    case "damage":
      return { success: !0, val: DAMAGE() };
    case "wep_mount":
      return { success: !0, val: WEAPON_MOUNT() };
    case "weapon_profile":
      return { success: !0, val: WEAPON_PROFILE() };
    case "talent_rank":
      return { success: !0, val: TALENT_RANK() };
    case "WeaponSize":
      return { success: !0, val: WeaponSize.Main };
    case "WeaponType":
      return { success: !0, val: WeaponType.Rifle };
    case "ActivationType":
      return { success: !0, val: ActivationType.Quick };
  }
  return { success: !1, val: null };
}
__name(control_structs, "control_structs");
function std_input(path, type2, options) {
  let input_classes = options.hash.classes || "", label = options.hash.label || "", label_classes = options.hash.label_classes || "", default_val = "" + (options.hash.default ?? ""), value = options.hash.value;
  value == null && (value = resolveHelperDotpath(options, path) ?? default_val);
  let html_type = type2.toLowerCase(), data_type = type2 == "Password" || type2 == "Text" ? "String" : type2, placeholder = type2 == "Text" || type2 == "String" ? `placeholder="${defaultPlaceholder}"` : "", input = `<input class="grow ${input_classes}" name="${path}" value="${value}" type="${html_type}" data-dtype="${data_type}" ${placeholder}/>`;
  return label ? `
    <label class="flexrow no-wrap flex-center ${label_classes}">
      <span class="no-grow" style="padding: 2px 5px;">${label}</span> 
      ${input}
    </label>` : input;
}
__name(std_input, "std_input");
function std_text_input(path, options) {
  return std_input(path, "Text", options);
}
__name(std_text_input, "std_text_input");
function std_password_input(path, options) {
  return std_input(path, "Password", options);
}
__name(std_password_input, "std_password_input");
function std_num_input(path, options) {
  return std_input(path, "Number", options);
}
__name(std_num_input, "std_num_input");
function std_x_of_y(x_path, x, y, add_classes = "") {
  return ` <div class="flexrow flex-center no-wrap ${add_classes}">
              <input class="lancer-stat" type="number" name="${x_path}" value="${x}" data-dtype="Number" style="justify-content: left"/>
              <span>/</span>
              <span class="lancer-stat" style="justify-content: left"> ${y}</span>
            </div>`;
}
__name(std_x_of_y, "std_x_of_y");
function std_checkbox(path, options) {
  let input_classes = options.hash.classes || "", label = options.hash.label || "", label_classes = options.hash.label_classes || "", default_val = !!options.hash.default, value = options.hash.value;
  value == null && (value = resolveHelperDotpath(options, path) ?? default_val);
  let input = `<input class="${input_classes}" name="${path}" ${inc_if("checked", value)} type="checkbox" />`;
  return label ? `
    <label class="flexrow flex-center ${label_classes}">
      <span class="no-grow" style="padding: 2px 5px;">${label}</span>
      ${input}
    </label>` : input;
}
__name(std_checkbox, "std_checkbox");
function std_enum_select(path, enum_, options) {
  let entries = Object.entries(enum_);
  options.hash.presorted || entries.sort((a, b) => a[0].localeCompare(b[0]));
  let select_classes = options.hash.select_classes || "", label_classes = options.hash.label_classes || "", default_val = options.hash.default;
  default_val == null && (default_val = entries[0][1]);
  let value = options.hash.value;
  value == null && (value = resolveHelperDotpath(options, path, default_val));
  let currentVal = restrict_enum(enum_, default_val, value), choices = [];
  for (let choice of entries)
    choices.push(
      `<option value="${choice[1]}" ${selected(choice[1] === currentVal)}>${choice[0].toUpperCase()}</option>`
    );
  let select = `
      <select name="${path}" class="${select_classes}" data-type="String" style="height: 2em; align-self: center; margin: 4px;" >
        ${choices.join("")}
      </select>`;
  return options.hash.label ? `<label class="flexrow flex-center no-wrap ${label_classes}">
      ${options.hash.label}
      ${select}
    </label>` : select;
}
__name(std_enum_select, "std_enum_select");
function popout_editor_button(path) {
  return `<a class="fas fa-edit popout-text-edit-button" data-path="${path}"> </a>`;
}
__name(popout_editor_button, "popout_editor_button");
function handlePopoutTextEditor(html, root_doc) {
  html.find(".popout-text-edit-button").on("click", async (evt) => {
    evt.stopPropagation();
    const path = evt.currentTarget.dataset.path;
    if (path) {
      let dd = drilldownDocument(root_doc, path);
      await HTMLEditDialog.edit_text(dd.sub_doc, dd.sub_path);
    }
  });
}
__name(handlePopoutTextEditor, "handlePopoutTextEditor");
function safe_html_helper(orig) {
  let doc = document.createElement("div");
  doc.innerHTML = orig, orig = doc.innerHTML;
  let bad = /on[a-zA-Z\-]+=".*?"/g;
  return orig = orig.replace(bad, ""), orig || defaultPlaceholder;
}
__name(safe_html_helper, "safe_html_helper");
function large_textbox_card(title, text_path, options) {
  let resolved = resolveHelperDotpath(options, text_path, "");
  return `
  <div class="card full clipped">
    <div class="lancer-header lancer-primary">
      <span>${title}</span>
      ${popout_editor_button(text_path)}
    </div>
    <div class="desc-text">
      ${safe_html_helper((resolved == null ? void 0 : resolved.trim()) || defaultPlaceholder)}
    </div>
  </div>
  `;
}
__name(large_textbox_card, "large_textbox_card");
function saveCancelButtons() {
  return `<div class="dialog-buttons">
        <button data-button="confirm">
            <i class="fas fa-save"></i>
            Save
        </button>
        <button data-button="cancel">
            <i class="fas fa-times"></i>
            Cancel
        </button>
    </div>`;
}
__name(saveCancelButtons, "saveCancelButtons");
function createContextMenu(parent, options, onSelectAny) {
  let menu = $('<div class="lancer-context-menu flexcol" />');
  for (let o of options) {
    let ro = $(`<div class="lancer-context-item">${o.icon ?? ""}${o.name}</div>`);
    ro.on("click", () => {
      o.callback(parent), onSelectAny && onSelectAny();
    }), menu.append(ro);
  }
  return menu[0];
}
__name(createContextMenu, "createContextMenu");
function tippyContextMenu(targets, event_types, options) {
  targets.each((_, _target) => {
    let target = $(_target), curr_options = options.filter((o) => o.condition ? o.condition === !0 || o.condition(target) : !0);
    if (!curr_options.length)
      return;
    const instance = tippy$1(_target, {
      appendTo: () => document.body,
      // "parent",
      placement: "bottom",
      trigger: "manual",
      interactive: !0,
      allowHTML: !0,
      theme: "lancer-large"
    });
    let content = createContextMenu(target, curr_options, () => instance.hide());
    instance.setContent(content), target.on(event_types, async (event) => {
      event.stopPropagation(), event.preventDefault(), instance.show();
    });
  });
}
__name(tippyContextMenu, "tippyContextMenu");
function restrict_choices(choices, default_choice, provided) {
  if (!provided)
    return default_choice;
  let lcp = provided.toLowerCase();
  for (let caseFix of choices)
    if (caseFix.toLowerCase() == lcp)
      return caseFix;
  return default_choice;
}
__name(restrict_choices, "restrict_choices");
function list_enum(enum_) {
  return Object.keys(enum_).map((k) => enum_[k]);
}
__name(list_enum, "list_enum");
function restrict_enum(enum_, default_choice, provided) {
  let choices = list_enum(enum_);
  return restrict_choices(choices, default_choice, provided);
}
__name(restrict_enum, "restrict_enum");
function hex_array(curr, max2, path, classes) {
  return [...Array(max2)].map((_ele, index2) => {
    const available = index2 + 1 <= curr;
    return `<a><i class="${classes ?? ""} mdi ${available ? "mdi-hexagon-slice-6" : "mdi-hexagon-outline"} theme--light" data-available="${available}" data-path="${path}"></i></a>`;
  });
}
__name(hex_array, "hex_array");
const fields$z = foundry.data.fields, _Range = class _Range {
  constructor(data2) {
    this.type = data2.type, this.val = data2.val;
  }
  save() {
    return {
      type: this.type,
      val: this.val
    };
  }
  copy() {
    return new _Range(this.save());
  }
  // A simple text output. Perhaps unnecessary - kept from compcon
  get formatted() {
    return `${this.type} ${this.val}`;
  }
  get icon() {
    return _Range.IconFor(this.type);
  }
  get discord_emoji() {
    return _Range.DiscordEmojiFor(this.type);
  }
  // Returns the discord emoji corresponding to the provided range type
  static DiscordEmojiFor(rt) {
    switch (rt) {
      case RangeType.Range:
      case RangeType.Threat:
      case RangeType.Thrown:
        return `:cc_${rt.toLowerCase()}:`;
    }
    return `:cc_aoe_${rt.toLowerCase()}:`;
  }
  static IconFor(rt) {
    return `cci-${rt.toLowerCase()}`;
  }
  // Convert a range type array to a checklist. If no range types provided, assume all
  static MakeChecklist(ranges) {
    let override = ranges.length == 0;
    return {
      Blast: override || ranges.includes(RangeType.Blast),
      Burst: override || ranges.includes(RangeType.Burst),
      Cone: override || ranges.includes(RangeType.Cone),
      Line: override || ranges.includes(RangeType.Line),
      Range: override || ranges.includes(RangeType.Range),
      Thrown: override || ranges.includes(RangeType.Thrown),
      Threat: override || ranges.includes(RangeType.Threat)
    };
  }
  // Undo the above conversion
  static FlattenChecklist(ranges) {
    return Object.keys(ranges).filter((r) => ranges[r]);
  }
  // Combine two arrays of damage. Does not edit originals
  static CombineLists(base, additions) {
    let result = base.map((d) => d.copy());
    for (let added_range of additions) {
      let to_be_modified = result.find((result_d) => result_d.type == added_range.type);
      to_be_modified ? to_be_modified.val += added_range.val : result.push(added_range.copy());
    }
    return result;
  }
};
__name(_Range, "Range");
let Range = _Range;
const _RangeField = class _RangeField extends fields$z.SchemaField {
  constructor(options = {}) {
    super(
      {
        type: new fields$z.StringField({ choices: Object.values(RangeType), initial: RangeType.Range }),
        val: new fields$z.NumberField({ min: 0, integer: !0, initial: 1, nullable: !1 })
      },
      options
    );
  }
  /** @override */
  initialize(value, model) {
    return new Range(value);
  }
  migrateSource(sourceData, fieldData) {
    return typeof fieldData.val == "string" && (fieldData.val = parseInt(fieldData.val) || 1), fieldData.type && (fieldData.type = restrict_enum(RangeType, RangeType.Range, fieldData.type)), super.migrateSource(sourceData, fieldData);
  }
  /** @override */
  _cast(value) {
    return value instanceof Range ? value.save() : super._cast(value);
  }
};
__name(_RangeField, "RangeField");
let RangeField = _RangeField;
function unpackRange(data2) {
  var _a19, _b;
  return {
    type: ((_a19 = data2.type) == null ? void 0 : _a19.capitalize()) ?? RangeType.Range,
    val: Number.parseInt(((_b = data2.val) == null ? void 0 : _b.toString()) ?? "0") || 0
  };
}
__name(unpackRange, "unpackRange");
function coarseLIDtoUUID(lid) {
  var _a19, _b;
  let actor = (_a19 = game.data.actors) == null ? void 0 : _a19.find((x) => {
    var _a20;
    return ((_a20 = x.system) == null ? void 0 : _a20.lid) == lid;
  });
  if (actor != null && actor._id)
    return `Actor.${actor._id}`;
  let item = (_b = game.data.items) == null ? void 0 : _b.find((x) => {
    var _a20;
    return ((_a20 = x.system) == null ? void 0 : _a20.lid) == lid;
  });
  return item != null && item._id ? `Item.${item._id}` : null;
}
__name(coarseLIDtoUUID, "coarseLIDtoUUID");
function regRefToUuid(doc_type, rr) {
  return rr ? typeof rr == "string" ? rr : !rr.id && rr.fallback_lid ? coarseLIDtoUUID(rr.fallback_lid) : !rr.id || !rr.reg_name || rr.reg_name == "comp_core" ? null : rr.reg_name == "game" ? `${doc_type}.${rr.id}` : rr.reg_name.startsWith("game|") ? `Actor.${rr.reg_name.split("game|")[1]}.Item.${rr.id}` : (console.error("Failed to process regref", rr), null) : null;
}
__name(regRefToUuid, "regRefToUuid");
function regRefToId(doc_type, rr) {
  let base = regRefToUuid(doc_type, rr);
  if (base) {
    let parts = base.split(".");
    return parts[parts.length - 1];
  }
  return null;
}
__name(regRefToId, "regRefToId");
function regRefToLid(rr) {
  return rr ? typeof rr == "string" ? rr : rr.fallback_lid || null : null;
}
__name(regRefToLid, "regRefToLid");
function convertNpcStats(raw_data) {
  let stats = [], key_map = {
    activations: "activations",
    agility: "agi",
    agi: "agi",
    armor: "armor",
    edef: "edef",
    evade: "evasion",
    evasion: "evasion",
    engineering: "eng",
    eng: "eng",
    heatcap: "heatcap",
    hp: "hp",
    hull: "hull",
    save: "save",
    sensor: "sensor_range",
    sensor_range: "sensor_range",
    size: "size",
    speed: "speed",
    stress: "stress",
    structure: "structure",
    systems: "sys",
    sys: "sys"
  };
  for (let i = 0; i < 3; i++) {
    const giv = /* @__PURE__ */ __name((key) => {
      let x = raw_data[key] ?? null;
      if (!(typeof x == "number" || Array.isArray(x)))
        return null;
      x = Array.isArray(x) ? x : [x], x = x.length == 0 ? [0] : x;
      let y = i >= x.length ? x[x.length - 1] : x[i], z = Array.isArray(y) ? y[0] : y;
      return typeof z != "number" ? null : z;
    }, "giv");
    let record = {};
    for (let k of Object.keys(raw_data)) {
      let v = giv(k);
      v && (record[key_map[k]] = v);
    }
    stats.push(record);
  }
  return stats;
}
__name(convertNpcStats, "convertNpcStats");
const fields$y = foundry.data.fields, _LancerDataModel = class _LancerDataModel extends foundry.abstract.TypeDataModel {
  /**
   * Create a full update payload, e.g. to preserve arrays
   * @param update_data the update data to apply
   */
  full_update_data(update_data) {
    const system = foundry.utils.duplicate(this._source);
    return fancy_merge_data({ system }, update_data);
  }
  prepareBaseData() {
    this.finalize_tasks();
  }
  /**
   * Add a job to this model to be called pre-finalize
   */
  add_pre_finalize_task(task) {
    this._pre_finalize_tasks ?? (this._pre_finalize_tasks = []), this._pre_finalize_tasks.push(task);
  }
  /**
   * Call this in prepare data to finalize our jobs
   */
  finalize_tasks() {
    var _a19;
    (_a19 = this._pre_finalize_tasks) == null || _a19.forEach((x) => x()), this._pre_finalize_tasks = [];
  }
};
__name(_LancerDataModel, "LancerDataModel");
let LancerDataModel = _LancerDataModel;
function fancy_merge_data(full_source_data, update_data) {
  if (full_source_data == null)
    throw new Error("Cannot merge with null or undefined - try again");
  if (typeof full_source_data == "number" || typeof full_source_data == "string" || typeof full_source_data == "boolean")
    return update_data;
  for (let [k, v] of Object.entries(update_data)) {
    k = formatDotpath(k);
    const del = k.startsWith("-=");
    del && (k = k.slice(2));
    const di = k.indexOf(".");
    if (di != -1) {
      if (del)
        throw new Error("'-=' in dotpath must go at penultimate pathlet. E.x. 'system.whatever.-=val'");
      const fore = k.slice(0, di), aft = k.slice(di + 1), prior = full_source_data[fore];
      prior ? full_source_data[fore] = fancy_merge_data(prior, { [aft]: v }) : full_source_data[fore] = { [aft]: v };
    } else
      del ? Array.isArray(full_source_data) ? full_source_data.splice(parseInt(k), 1) : typeof full_source_data == "object" ? delete full_source_data[k] : console.warn("'-=' in update may only target Object or Array items") : full_source_data[k] = v;
  }
  return full_source_data;
}
__name(fancy_merge_data, "fancy_merge_data");
const _LIDField = class _LIDField extends fields$y.StringField {
  /** @override */
  _cast(value) {
    var _a19;
    const rrtl = regRefToLid(value);
    return rrtl || (value.lid && (value = value.lid), (_a19 = value.system) != null && _a19.lid && (value = value.system.lid), console.warn("If passing an object as a value for an LIDField, object must have an `lid` or `system.lid` property"), value);
  }
  _validateType(value) {
    try {
      super._validateType(value);
    } catch {
      return new foundry.data.validation.DataModelValidationFailure({
        invalidValue: value,
        message: `Not a valid LID ${value}`
      });
    }
  }
};
__name(_LIDField, "LIDField");
let LIDField = _LIDField;
const _EmbeddedRefField = class _EmbeddedRefField extends fields$y.StringField {
  /**
   * @param {StringFieldOptions} options  Options which configure the behavior of the field
   */
  constructor(document_type, options = {}) {
    super(options), this.document_type = document_type, this.allowed_types = options.allowed_types ?? null;
  }
  /** @inheritdoc */
  static get _defaults() {
    return foundry.utils.mergeObject(super._defaults, {
      initial: null,
      blank: !1,
      trim: !0,
      nullable: !0
    });
  }
  /** @override */
  _cast(value) {
    const rrti = regRefToId(this.document_type, value);
    return rrti || (value != null && value.id && (value = value.id), (value == null ? void 0 : value.value) !== void 0 && (value = value.value), value != null && value.id && (value = value.id), value);
  }
  /** @inheritdoc */
  initialize(value, model) {
    if (super.initialize, !value)
      return null;
    const shell = {
      id: value
    };
    return model.add_pre_finalize_task(() => {
      var _a19;
      const sub = ((_a19 = model == null ? void 0 : model.parent) == null ? void 0 : _a19.getEmbeddedDocument(this.document_type, value)) ?? null;
      sub ? this.allowed_types && sub instanceof LancerItem && !this.allowed_types.includes(sub.type) ? (console.log(
        `Failed to resolve embedded ref: Wrong type ${sub.type} not in ${this.allowed_types.join("|")}`,
        model,
        value
      ), shell.status = "missing", shell.value = null) : (shell.status = "resolved", shell.value = sub) : (console.log("Failed to resolve embedded ref: ID not found.", model, value), shell.status = "missing", shell.value = null);
    }), shell;
  }
};
__name(_EmbeddedRefField, "EmbeddedRefField");
let EmbeddedRefField = _EmbeddedRefField;
const _SyncUUIDRefField = class _SyncUUIDRefField extends fields$y.StringField {
  /**
   * @param {StringFieldOptions} options  Options which configure the behavior of the field
   */
  constructor(document_type, options = {}) {
    super(options), this.document_type = document_type, this.allowed_types = options.allowed_types ?? null;
  }
  /** @inheritdoc */
  static get _defaults() {
    return foundry.utils.mergeObject(super._defaults, {
      initial: null,
      blank: !1,
      trim: !0,
      nullable: !0
    });
  }
  /** @override */
  _cast(value) {
    const rrtu = regRefToUuid(this.document_type, value);
    return rrtu || (value != null && value.uuid && (value = value.uuid), (value == null ? void 0 : value.value) !== void 0 && (value = value.value), value != null && value.uuid && (value = value.uuid), value);
  }
  /** @override */
  _validateType(value) {
    try {
      if (super._validateType(value), value)
        return foundry.utils.parseUuid(value), !0;
    } catch {
      return new foundry.data.validation.DataModelValidationFailure({
        invalidValue: value,
        message: `Not a valid uuid ${value}`
      });
    }
  }
  /** @inheritdoc */
  initialize(value, model) {
    if (!value)
      return null;
    const shell = {
      id: value
    };
    return model.add_pre_finalize_task(() => {
      const syncRes = fromUuidSync(value);
      syncRes ? this.allowed_types && !this.allowed_types.includes(syncRes.type) ? (console.error(
        `Failed to resolve uuid ref: Wrong type ${syncRes.type} not in ${this.allowed_types.join("|")}`,
        model,
        value
      ), shell.status = "missing", shell.value = null) : (shell.status = "resolved", Object.defineProperty(shell, "value", {
        value: syncRes,
        enumerable: !1
      })) : (console.error(`Failed to resolve uuid ref: Not found ${value}`, model, value), shell.status = "missing", shell.value = null);
    }), shell;
  }
};
__name(_SyncUUIDRefField, "SyncUUIDRefField");
let SyncUUIDRefField = _SyncUUIDRefField;
const _FakeBoundedNumberField = class _FakeBoundedNumberField extends fields$y.NumberField {
  constructor(options = {}) {
    super(options);
  }
  /** @override */
  initialize(value, _model) {
    var _a19, _b;
    return {
      min: ((_a19 = this.options) == null ? void 0 : _a19.min) ?? 0,
      max: ((_b = this.options) == null ? void 0 : _b.max) ?? 0,
      value
    };
  }
  /** @override */
  _cast(value) {
    return typeof value == "object" && (value = value.value ?? 0), super._cast(value);
  }
};
__name(_FakeBoundedNumberField, "FakeBoundedNumberField");
let FakeBoundedNumberField = _FakeBoundedNumberField;
var _a;
const _FullBoundedNumberField = (_a = class extends fields$y.SchemaField {
  constructor(options = {}) {
    super(
      {
        min: new fields$y.NumberField({ integer: !0, nullable: !1, initial: (options == null ? void 0 : options.min) ?? 0 }),
        max: new fields$y.NumberField({
          integer: !0,
          nullable: !1,
          initial: (options == null ? void 0 : options.max) ?? _a.defaultMax
        }),
        value: new fields$y.NumberField({ integer: !0, nullable: !1, initial: (options == null ? void 0 : options.initialValue) ?? 0 })
      },
      options
    );
  }
  /** @override */
  initialize(value, _model) {
    var _a19, _b, _c;
    return {
      min: value.min ?? ((_a19 = this.options) == null ? void 0 : _a19.min) ?? 0,
      max: value.max ?? ((_b = this.options) == null ? void 0 : _b.max) ?? value.value ?? _a.defaultMax,
      value: value.value ?? ((_c = this.options) == null ? void 0 : _c.initial) ?? 0
    };
  }
  /** @override */
  _cast(value) {
    var _a19, _b, _c, _d, _e, _f;
    if (typeof value == "number" && (value = { value, min: ((_a19 = this.options) == null ? void 0 : _a19.min) ?? 0, max: ((_b = this.options) == null ? void 0 : _b.max) ?? _a.defaultMax }), typeof value == "string") {
      let strValue = _a.defaultValue;
      try {
        strValue = parseFloat(value);
      } catch {
        console.warn(`Failed to parse number from string ${value}`);
      }
      value = {
        value: strValue,
        min: ((_c = this.options) == null ? void 0 : _c.min) ?? 0,
        max: ((_d = this.options) == null ? void 0 : _d.max) ?? _a.defaultMax
      };
    }
    return (value.min == null || value.min == null) && (value.min = ((_e = this.options) == null ? void 0 : _e.min) ?? 0), (value.max == null || value.max == null) && (value.max = ((_f = this.options) == null ? void 0 : _f.max) ?? value.value ?? _a.defaultMax), super._cast(value);
  }
}, __name(_a, "_FullBoundedNumberField"), _a);
_FullBoundedNumberField.defaultValue = 10;
_FullBoundedNumberField.defaultMax = 10;
let FullBoundedNumberField = _FullBoundedNumberField;
const _ChecklistField = class _ChecklistField extends fields$y.SchemaField {
  constructor(target_enum, options = {}) {
    const scaffold = {};
    for (let val of Object.values(target_enum))
      scaffold[val] = new fields$y.BooleanField({ initial: !0 });
    super(scaffold, options);
  }
};
__name(_ChecklistField, "ChecklistField");
let ChecklistField = _ChecklistField;
const _DamageTypeChecklistField = class _DamageTypeChecklistField extends ChecklistField {
  constructor(options = {}) {
    super(DamageType, options);
  }
};
__name(_DamageTypeChecklistField, "DamageTypeChecklistField");
let DamageTypeChecklistField = _DamageTypeChecklistField;
const _RangeTypeChecklistField = class _RangeTypeChecklistField extends ChecklistField {
  constructor(options = {}) {
    super(RangeType, options);
  }
};
__name(_RangeTypeChecklistField, "RangeTypeChecklistField");
let RangeTypeChecklistField = _RangeTypeChecklistField;
const _WeaponTypeChecklistField = class _WeaponTypeChecklistField extends ChecklistField {
  constructor(options = {}) {
    super(WeaponType, options);
  }
};
__name(_WeaponTypeChecklistField, "WeaponTypeChecklistField");
let WeaponTypeChecklistField = _WeaponTypeChecklistField;
const _WeaponSizeChecklistField = class _WeaponSizeChecklistField extends ChecklistField {
  constructor(options = {}) {
    super(WeaponSize, options);
  }
};
__name(_WeaponSizeChecklistField, "WeaponSizeChecklistField");
let WeaponSizeChecklistField = _WeaponSizeChecklistField;
const _SystemTypeChecklistField = class _SystemTypeChecklistField extends ChecklistField {
  constructor(options = {}) {
    super(SystemType, options);
  }
};
__name(_SystemTypeChecklistField, "SystemTypeChecklistField");
let SystemTypeChecklistField = _SystemTypeChecklistField;
const _NpcStatBlockField = class _NpcStatBlockField extends fields$y.SchemaField {
  constructor(options) {
    const nullable = options.nullable;
    super(
      {
        activations: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 1 }),
        armor: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        hp: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 10 }),
        evasion: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 5 }),
        edef: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 8 }),
        heatcap: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        speed: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 3 }),
        sensor_range: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 10 }),
        save: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 10 }),
        hull: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        agi: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        sys: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        eng: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 0 }),
        size: new fields$y.NumberField({ integer: !1, nullable, minimum: 0.5, initial: nullable ? null : 1 }),
        structure: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 1 }),
        stress: new fields$y.NumberField({ integer: !0, nullable, initial: nullable ? null : 1 })
      },
      options
    );
  }
};
__name(_NpcStatBlockField, "NpcStatBlockField");
let NpcStatBlockField = _NpcStatBlockField;
const _ControlledLengthArrayField = class _ControlledLengthArrayField extends fields$y.ArrayField {
  // Constructor demands options
  constructor(element, options) {
    if (super(element, options), !Number.isInteger(options.length))
      throw new TypeError("ControlledLengthArrayField requires an integer 'length' option!");
  }
  /** @override */
  _cast(value) {
    if (value = super._cast(value), !Array.isArray(value))
      return value;
    for (; value.length < this.options.length; ) {
      const new_elt = typeof this.element.initial == "function" ? this.element.initial() : this.element.initial;
      value.push(foundry.utils.duplicate(new_elt));
    }
    return !this.options.overflow && value.length > this.options.length && (value = value.slice(0, this.options.length)), value;
  }
};
__name(_ControlledLengthArrayField, "ControlledLengthArrayField");
let ControlledLengthArrayField = _ControlledLengthArrayField;
const fields$x = foundry.data.fields, PLACEHOLDER = "...", _Tag = class _Tag {
  // Decent first guess
  constructor(data2) {
    this.name = PLACEHOLDER, this.description = "Tag not found", this.hidden = !1, this.lid = data2.lid, this.val = data2.val;
    let assocTag = game.settings.get(game.system.id, LANCER.setting_tag_config)[data2.lid];
    assocTag && (this.name = assocTag.name, this.description = assocTag.description, this.hidden = assocTag.hidden);
  }
  get num_val() {
    let parsed = Number.parseInt(this.val);
    return Number.isNaN(parsed) ? null : parsed;
  }
  /**
   * Helper funciton to interpolate the correct value from tags with values matching
   * the pattern {number/number/number}
   * @param tag A tag with a value
   * @param tier The NPC tier to get the value for
   * @returns The string for the requested tier from the tag value
   */
  tierVal(tier) {
    if (!this.val)
      return "";
    const tieredValRegex = /^{(\d*)\/(\d*)\/(\d*)}$/i, matchTiers = this.val.match(tieredValRegex);
    return !matchTiers || !matchTiers.length || !matchTiers[0] || !matchTiers[tier] ? this.val : matchTiers[tier];
  }
  save() {
    return {
      lid: this.lid,
      val: this.val
    };
  }
  copy() {
    return new _Tag(this.save());
  }
  get should_show() {
    return !this.hidden;
  }
  get is_unique() {
    return this.lid === "tg_unique";
  }
  get is_ai() {
    return this.lid === "tg_ai";
  }
  get is_ap() {
    return this.lid === "tg_ap";
  }
  get is_limited() {
    return this.lid === "tg_limited";
  }
  get is_loading() {
    return this.lid === "tg_loading";
  }
  get is_recharge() {
    return this.lid === "tg_recharge";
  }
  get is_indestructible() {
    return this.lid === "tg_indestructible";
  }
  get is_smart() {
    return this.lid === "tg_smart";
  }
  get is_seeking() {
    return this.lid === "tg_seeking";
  }
  get is_overkill() {
    return this.lid === "tg_overkill";
  }
  get is_accurate() {
    return this.lid === "tg_accurate";
  }
  get is_inaccurate() {
    return this.lid === "tg_inaccurate";
  }
  get is_reliable() {
    return this.lid === "tg_reliable";
  }
  get is_selfheat() {
    return this.lid === "tg_heat_self";
  }
  get is_knockback() {
    return this.lid === "tg_knockback";
  }
  get is_overshield() {
    return this.lid === "tg_overshield";
  }
  get is_cascaderesistant() {
    return this.lid === "tg_no_cascade";
  }
  get is_ordnance() {
    return this.lid === "tg_ordnance";
  }
  static MergeTags(...tag_arrays) {
    if (!tag_arrays.length)
      return [];
    let result = [], cache = {};
    for (let add_tag of tag_arrays.flat()) {
      let clone = cache[add_tag.lid];
      if (clone)
        add_tag.is_reliable || add_tag.is_selfheat || add_tag.is_knockback || add_tag.is_overshield ? clone.val = ((clone.num_val ?? 0) + (add_tag.num_val ?? 0)).toString() : add_tag.is_accurate || add_tag.is_inaccurate ? result.push(add_tag.copy()) : add_tag.is_limited ? clone.val = Math.min(clone.num_val ?? 0, add_tag.num_val ?? 0).toString() : add_tag.is_recharge && (clone.val = Math.max(clone.num_val ?? 0, add_tag.num_val ?? 0).toString());
      else {
        let d = add_tag.copy();
        cache[add_tag.lid] = d, result.push(d);
      }
    }
    return result;
  }
};
__name(_Tag, "Tag");
let Tag = _Tag;
const _TagField = class _TagField extends fields$x.SchemaField {
  constructor(options = {}) {
    super(
      {
        lid: new LIDField(),
        val: new fields$x.StringField({ nullable: !1 })
      },
      options
    );
  }
  /** @override */
  initialize(value, model) {
    return new Tag(value);
  }
  /** @override */
  _cast(value) {
    return value.num_val && (value.val = String(value.num_val)), super._cast(value);
  }
  migrateSource(sourceData, fieldData) {
    return typeof (fieldData == null ? void 0 : fieldData.tag) == "object" && (fieldData.lid = fieldData.tag.fallback_lid), super.migrateSource(sourceData, fieldData);
  }
};
__name(_TagField, "TagField");
let TagField = _TagField;
function unpackTagTemplate(data2) {
  return {
    description: data2.description,
    filter_ignore: data2.filter_ignore ?? !1,
    hidden: data2.hidden ?? !1,
    lid: data2.id,
    name: data2.name
  };
}
__name(unpackTagTemplate, "unpackTagTemplate");
function unpackTag(data2) {
  return {
    lid: data2.id,
    val: (data2.val ?? "").toString()
  };
}
__name(unpackTag, "unpackTag");
const FRAME_STAT_PRIORITY = 10, BONUS_STAT_PRIORITY = 20, PILOT_STAT_PRIORITY = 30, FEATURE_OVERRIDE_PRIORITY = 50;
function frameInnateEffect(frame) {
  let changes = [
    "armor",
    "edef",
    "evasion",
    "save",
    "sensor_range",
    "size",
    "speed",
    "tech_attack"
  ].map((key) => ({
    key: `system.${key}`,
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats[key]
  }));
  return changes.push({
    key: "system.hp.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.hp
  }), changes.push({
    key: "system.structure.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.structure
  }), changes.push({
    key: "system.stress.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.stress
  }), changes.push({
    key: "system.heat.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.heatcap
  }), changes.push({
    key: "system.repairs.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.repcap
  }), changes.push({
    key: "system.loadout.sp.max",
    mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
    priority: FRAME_STAT_PRIORITY,
    value: frame.system.stats.sp
  }), {
    flags: { lancer: { ephemeral: !0 } },
    name: frame.name,
    img: frame.img,
    origin: frame.uuid,
    transfer: !0,
    changes
  };
}
__name(frameInnateEffect, "frameInnateEffect");
function pilotInnateEffects(pilot) {
  if (!pilot.is_pilot())
    throw new Error("Cannot create pilot innate effect for non-pilot actor");
  let mech_effect = new LancerActiveEffect(
    {
      name: "Pilot → Mech Bonuses",
      changes: [
        // HASE
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.hull",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.hull.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.hp.max",
          priority: PILOT_STAT_PRIORITY,
          value: (2 * pilot.system.hull + pilot.system.grit).toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.repairs.max",
          priority: PILOT_STAT_PRIORITY,
          value: Math.floor(pilot.system.hull / 2).toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.agi",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.agi.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.evasion",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.agi.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.speed",
          priority: PILOT_STAT_PRIORITY,
          value: Math.floor(pilot.system.agi / 2).toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.sys",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.sys.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.edef",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.sys.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.tech_attack",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.sys.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.save",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.grit.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.loadout.sp.max",
          priority: PILOT_STAT_PRIORITY,
          value: (Math.floor(pilot.system.sys / 2) + pilot.system.grit).toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.eng",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.eng.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.heat.max",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.eng.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.ADD,
          key: "system.loadout.limited_bonus",
          priority: PILOT_STAT_PRIORITY,
          value: Math.floor(pilot.system.eng / 2).toString()
        },
        // More basic pilot info
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.grit",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.grit.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.level",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.level.toString()
        }
      ],
      // @ts-expect-error v12 property renamed
      img: pilot.img,
      origin: pilot.uuid,
      flags: {
        lancer: {
          target_type: EntryType.MECH,
          ephemeral: !0
        }
      }
    },
    {
      parent: pilot
    }
  ), deployable_effect = new LancerActiveEffect(
    {
      name: "Pilot → Deployable Bonuses",
      changes: [
        // Much simpler
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.grit",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.grit.toString()
        },
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.level",
          priority: PILOT_STAT_PRIORITY,
          value: pilot.system.level.toString()
        }
      ],
      // @ts-expect-error
      img: pilot.img,
      origin: pilot.uuid,
      flags: {
        lancer: {
          target_type: EntryType.DEPLOYABLE,
          ephemeral: !0
        }
      }
    },
    {
      parent: pilot
    }
  );
  return [mech_effect, deployable_effect];
}
__name(pilotInnateEffects, "pilotInnateEffects");
function npcInnateEffects(npc) {
  if (!npc.is_npc())
    throw new Error("Cannot create NPC innate effect for non-NPC actor");
  return [new LancerActiveEffect(
    {
      name: "NPC → Deployable Bonuses",
      changes: [
        // Much simpler
        {
          mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
          key: "system.grit",
          priority: PILOT_STAT_PRIORITY,
          value: npc.system.tier.toString()
        }
      ],
      // @ts-expect-error v12 property renamed
      img: npc.img,
      origin: npc.uuid,
      flags: {
        lancer: {
          target_type: EntryType.DEPLOYABLE,
          ephemeral: !0
        }
      }
    },
    {
      parent: npc
    }
  )];
}
__name(npcInnateEffects, "npcInnateEffects");
const npc_keys = [
  // Can be taken as is
  "activations",
  "armor",
  "evasion",
  "edef",
  "speed",
  "sensor_range",
  "save",
  "hull",
  "agi",
  "sys",
  "eng",
  "size",
  // Handled specially
  "hp",
  "heatcap",
  "structure",
  "stress"
];
function makeNpcBonus(stat, value, mode, priority) {
  switch (stat) {
    case "hp":
      return {
        key: "system.hp.max",
        mode,
        priority,
        value
      };
    case "heatcap":
      return {
        key: "system.heat.max",
        mode,
        priority,
        value
      };
    case "structure":
      return {
        key: "system.structure.max",
        mode,
        priority,
        value
      };
    case "stress":
      return {
        key: "system.stress.max",
        mode,
        priority,
        value
      };
    default:
      return {
        key: `system.${stat}`,
        mode,
        priority,
        value
      };
  }
}
__name(makeNpcBonus, "makeNpcBonus");
function npcClassInnateEffect(class_) {
  var _a19;
  let tier = ((_a19 = class_ == null ? void 0 : class_.actor) == null ? void 0 : _a19.system.tier) ?? 1, bs = class_.system.base_stats[tier - 1], changes = npc_keys.map(
    (key) => makeNpcBonus(key, bs[key], CONST.ACTIVE_EFFECT_MODES.OVERRIDE, FRAME_STAT_PRIORITY)
  );
  return {
    flags: { lancer: { ephemeral: !0 } },
    name: class_.name,
    img: class_.img,
    origin: class_.uuid,
    transfer: !0,
    changes
  };
}
__name(npcClassInnateEffect, "npcClassInnateEffect");
function npcFeatureBonusEffects(feature) {
  let changes = [];
  for (let key of npc_keys) {
    let value = feature.system.bonus[key];
    value !== null && changes.push(makeNpcBonus(key, value, CONST.ACTIVE_EFFECT_MODES.ADD, BONUS_STAT_PRIORITY));
  }
  return changes.length ? {
    flags: { lancer: { ephemeral: !0 } },
    name: `${feature.name} - bonuses`,
    img: feature.img,
    origin: feature.uuid,
    transfer: !0,
    changes
  } : null;
}
__name(npcFeatureBonusEffects, "npcFeatureBonusEffects");
function npcFeatureOverrideEffects(feature) {
  let changes = [];
  for (let key of npc_keys) {
    let value = feature.system.override[key];
    value !== null && changes.push(makeNpcBonus(key, value, CONST.ACTIVE_EFFECT_MODES.OVERRIDE, FEATURE_OVERRIDE_PRIORITY));
  }
  return changes.length ? {
    flags: { lancer: { ephemeral: !0 } },
    name: `${feature.name} - overrides`,
    img: feature.img,
    origin: feature.uuid,
    transfer: !0,
    changes
  } : null;
}
__name(npcFeatureOverrideEffects, "npcFeatureOverrideEffects");
function convertBonus(item, name2, bonus) {
  const uuid = item.uuid, owner = item.actor;
  if (bonus.lid == "damage" || bonus.lid == "range")
    return {
      name: name2,
      flags: {
        // @ts-ignore Kill me (infinite recursion in types)
        [game.system.id]: {
          target_type: EntryType.MECH,
          ephemeral: !0
        }
      },
      changes: [
        {
          mode: AE_MODE_APPEND_JSON,
          value: JSON.stringify(bonus),
          priority: 50,
          key: "system.bonuses.weapon_bonuses"
        }
      ],
      transfer: !0,
      disabled: !1,
      origin: uuid
    };
  let changes = [], target_type, mode = bonus.replace || bonus.overwrite ? CONST.ACTIVE_EFFECT_MODES.OVERRIDE : CONST.ACTIVE_EFFECT_MODES.ADD, priority = bonus.replace || bonus.overwrite ? 50 : BONUS_STAT_PRIORITY, value = bonus.val;
  if (value.includes("{ll}")) {
    const ll = `${owner != null && owner.is_pilot() || owner != null && owner.is_mech() ? owner.system.level : 0}`;
    value = value.replace("{ll}", ll);
  }
  if (value.includes("{grit}")) {
    const grit = `${owner != null && owner.is_pilot() || owner != null && owner.is_mech() ? owner.system.grit : 0}`;
    value = value.replace("{grit}", grit);
  }
  switch ((value.includes("-") || value.includes("+")) && (value = `${rollEvalSync(value)}`), bonus.lid) {
    case "hp":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.hp.max" });
      break;
    case "armor":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.armor" });
      break;
    case "structure":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.structure.max" });
      break;
    case "stress":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.stress.max" });
      break;
    case "heatcap":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.heat.max" });
      break;
    case "repcap":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.repairs.max" });
      break;
    case "speed":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.speed" });
      break;
    case "evasion":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.evasion" });
      break;
    case "edef":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.edef" });
      break;
    case "sensor":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.sensor_range" });
      break;
    case "attack":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.bonuses.flat.range_attack" });
      break;
    case "tech_attack":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.tech_attack" });
      break;
    case "grapple":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.bonuses.flat.grapple" });
      break;
    case "ram":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.bonuses.flat.ram" });
      break;
    case "save":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.save" });
      break;
    case "sp":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.loadout.sp.max" });
      break;
    case "size":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.size" });
      break;
    case "ai_cap":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.ai.max" });
      break;
    case "cheap_struct":
      target_type = EntryType.MECH, changes.push({
        mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
        value: "1",
        priority,
        key: "system.structure_repair_cost"
      });
      break;
    case "cheap_stress":
      target_type = EntryType.MECH, changes.push({
        mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE,
        value: "1",
        priority,
        key: "system.stress_repair_cost"
      });
      break;
    case "overcharge":
      target_type = EntryType.MECH, changes.push({ mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE, value, priority, key: "system.overcharge_sequence" });
      break;
    case "limited_bonus":
      target_type = EntryType.MECH, changes.push({ mode, value, priority, key: "system.loadout.limited_bonus" });
      break;
    case "pilot_hp":
      target_type = EntryType.PILOT, changes.push({ mode, value, priority, key: "system.hp.max" });
      break;
    case "pilot_armor":
      target_type = EntryType.PILOT, changes.push({ mode, value, priority, key: "system.armor" });
      break;
    case "pilot_evasion":
      target_type = EntryType.PILOT, changes.push({ mode, value, priority, key: "system.evasion" });
      break;
    case "pilot_edef":
      target_type = EntryType.PILOT, changes.push({ mode, value, priority, key: "system.edef" });
      break;
    case "pilot_speed":
      target_type = EntryType.PILOT, changes.push({ mode, value, priority, key: "system.speed" });
      break;
    case "deployable_hp":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.hp_bonus" });
      break;
    case "deployable_size":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.size" });
      break;
    case "deployable_armor":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.armor" });
      break;
    case "deployable_evasion":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.evasion" });
      break;
    case "deployable_edef":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.edef" });
      break;
    case "deployable_sensor_range":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.sensor_range" });
      break;
    case "deployable_tech_attack":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.tech_attack_bonus" });
      break;
    case "deployable_save":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.save" });
      break;
    case "deployable_speed":
      target_type = "only_deployable", changes.push({ mode, value, priority, key: "system.speed" });
      break;
    case "drone_hp":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.hp_bonus" });
      break;
    case "drone_size":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.size" });
      break;
    case "drone_armor":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.armor" });
      break;
    case "drone_evasion":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.evasion" });
      break;
    case "drone_edef":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.edef" });
      break;
    case "drone_sensor_range":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.sensor_range" });
      break;
    case "drone_tech_attack":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.tech_attack_bonus" });
      break;
    case "drone_save":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.save" });
      break;
    case "drone_speed":
      target_type = "only_drone", changes.push({ mode, value, priority, key: "system.speed" });
      break;
    default:
      return console.warn(`Bonus of type ${bonus.lid} not yet supported. Please fix or remove it. Source: ${uuid}`), null;
  }
  return {
    name: name2,
    flags: {
      [game.system.id]: {
        target_type,
        ephemeral: !0
      }
    },
    changes,
    transfer: !0,
    disabled: !1,
    origin: uuid
  };
}
__name(convertBonus, "convertBonus");
function bonusAffectsWeapon(weapon, bonus) {
  var _a19, _b;
  if (!weapon.is_mech_weapon())
    return !1;
  let sel_prof = weapon.system.active_profile;
  return !(((_a19 = bonus.weapon_sizes) == null ? void 0 : _a19[weapon.system.size]) === !1 || ((_b = bonus.weapon_types) == null ? void 0 : _b[sel_prof.type]) === !1 || !sel_prof.damage.some((d) => {
    var _a20;
    return ((_a20 = bonus.damage_types) == null ? void 0 : _a20[d.type]) === !0;
  }) || !sel_prof.range.some((d) => {
    var _a20;
    return ((_a20 = bonus.range_types) == null ? void 0 : _a20[d.type]) === !0;
  }));
}
__name(bonusAffectsWeapon, "bonusAffectsWeapon");
const fields$w = foundry.data.fields, _Damage = class _Damage {
  constructor(data2) {
    this.type = data2.type, this.val = data2.val;
  }
  save() {
    return {
      type: this.type,
      val: this.val
    };
  }
  copy() {
    return new _Damage(this.save());
  }
  // Methods / getters / Various formatting options
  get icon() {
    return _Damage.IconFor(this.type);
  }
  get text() {
    return `${this.val} ${this.type} Damage`;
  }
  get discord_emoji() {
    return _Damage.DiscordEmojiFor(this.type);
  }
  get color() {
    return _Damage.ColorFor(this.type);
  }
  // Returns the css font icon corresponding to the provided damage type
  static IconFor(dt) {
    return `cci-${dt.toLowerCase()}`;
  }
  static DiscordEmojiFor(dt) {
    return `:cc_damage_${dt.toLowerCase()}:`;
  }
  // Returns the css color name corresponding to the provided damage type
  static ColorFor(dt) {
    return `damage--${dt.toLowerCase()}`;
  }
  // Convert a damage type array to a checklist. If no damage types provided, assume all
  static MakeChecklist(damages) {
    let override = damages.length == 0;
    return {
      Burn: override || damages.includes(DamageType.Burn),
      Energy: override || damages.includes(DamageType.Energy),
      Explosive: override || damages.includes(DamageType.Explosive),
      Heat: override || damages.includes(DamageType.Heat),
      Kinetic: override || damages.includes(DamageType.Kinetic),
      Variable: override || damages.includes(DamageType.Variable)
    };
  }
  // Undo the above conversion
  static FlattenChecklist(damages) {
    return Object.keys(damages).filter((d) => damages[d]);
  }
  // Combine two arrays of damage. Does not edit originals
  static CombineLists(base, addition) {
    let result = base.map((d) => d.copy());
    for (let add of addition) {
      let to_be_modified = result.find((result_d) => result_d.type == add.type);
      if (to_be_modified)
        try {
          let base_formula = new Roll(to_be_modified.val), add_formula = new Roll(add.val);
          for (let add_term of add_formula.terms) {
            let added = !1;
            for (let base_term of base_formula.terms)
              if (add_term.number && base_term.number && add_term.faces === base_term.faces) {
                base_term.number += add_term.number, added = !0;
                break;
              }
            !added && !add_term.operator && (base_formula = new Roll(base_formula.formula + " + " + add_term.formula));
          }
          to_be_modified.val = base_formula.formula;
        } catch {
          to_be_modified.val += ` + ${add.val}`;
        }
      else
        result.push(add.copy());
    }
    return result;
  }
};
__name(_Damage, "Damage");
let Damage = _Damage;
const _DamageField = class _DamageField extends fields$w.SchemaField {
  constructor(options = {}) {
    super(
      {
        type: new fields$w.StringField({ choices: Object.values(DamageType), initial: DamageType.Kinetic }),
        val: new fields$w.StringField({ initial: "1d6", nullable: !1, required: !0, trim: !0 })
      },
      options
    );
  }
  /** @override */
  initialize(value, model) {
    return new Damage(value);
  }
  migrateSource(sourceData, fieldData) {
    return fieldData.type && (fieldData.type = restrict_enum(DamageType, DamageType.Kinetic, fieldData.type)), super.migrateSource(sourceData, fieldData);
  }
  /** @override */
  _cast(value) {
    return value instanceof Damage ? value.save() : super._cast(value);
  }
};
__name(_DamageField, "DamageField");
let DamageField = _DamageField;
function unpackDamage(data2) {
  var _a19, _b;
  return {
    type: (_a19 = data2.type) == null ? void 0 : _a19.capitalize(),
    val: ((_b = data2.val) == null ? void 0 : _b.toString()) ?? "1"
  };
}
__name(unpackDamage, "unpackDamage");
globalThis && globalThis.__spreadArray;
var isLeft$1 = /* @__PURE__ */ __name(function(ma) {
  return ma._tag === "Left";
}, "isLeft$1"), left$1 = /* @__PURE__ */ __name(function(e) {
  return { _tag: "Left", left: e };
}, "left$1"), right$1 = /* @__PURE__ */ __name(function(a) {
  return { _tag: "Right", right: a };
}, "right$1"), left = left$1, right = right$1, map = /* @__PURE__ */ __name(function(f) {
  return function(fa) {
    return isLeft(fa) ? fa : right(f(fa.right));
  };
}, "map"), isLeft = isLeft$1, __extends = globalThis && globalThis.__extends || function() {
  var extendStatics = /* @__PURE__ */ __name(function(d, b) {
    return extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
      d2.__proto__ = b2;
    } || function(d2, b2) {
      for (var p in b2)
        Object.prototype.hasOwnProperty.call(b2, p) && (d2[p] = b2[p]);
    }, extendStatics(d, b);
  }, "extendStatics");
  return function(d, b) {
    extendStatics(d, b);
    function __() {
      this.constructor = d;
    }
    __name(__, "__"), d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  };
}(), __assign = globalThis && globalThis.__assign || function() {
  return __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p in s)
        Object.prototype.hasOwnProperty.call(s, p) && (t[p] = s[p]);
    }
    return t;
  }, __assign.apply(this, arguments);
};
globalThis && globalThis.__spreadArrays;
var failures = left, failure = /* @__PURE__ */ __name(function(value, context, message) {
  return failures([{ value, context, message }]);
}, "failure"), success = right, Type = (
  /** @class */
  function() {
    function Type2(name2, is, validate, encode2) {
      this.name = name2, this.is = is, this.validate = validate, this.encode = encode2, this.decode = this.decode.bind(this);
    }
    return __name(Type2, "Type"), Type2.prototype.pipe = function(ab, name2) {
      var _this = this;
      return name2 === void 0 && (name2 = "pipe(" + this.name + ", " + ab.name + ")"), new Type2(name2, ab.is, function(i, c) {
        var e = _this.validate(i, c);
        return isLeft(e) ? e : ab.validate(e.right, c);
      }, this.encode === identity && ab.encode === identity ? identity : function(b) {
        return _this.encode(ab.encode(b));
      });
    }, Type2.prototype.asDecoder = function() {
      return this;
    }, Type2.prototype.asEncoder = function() {
      return this;
    }, Type2.prototype.decode = function(i) {
      return this.validate(i, [{ key: "", type: this, actual: i }]);
    }, Type2;
  }()
), identity = /* @__PURE__ */ __name(function(a) {
  return a;
}, "identity");
function getFunctionName(f) {
  return f.displayName || f.name || "<function" + f.length + ">";
}
__name(getFunctionName, "getFunctionName");
function appendContext(c, key, decoder, actual) {
  for (var len = c.length, r = Array(len + 1), i = 0; i < len; i++)
    r[i] = c[i];
  return r[len] = { key, type: decoder, actual }, r;
}
__name(appendContext, "appendContext");
function pushAll(xs, ys) {
  for (var l = ys.length, i = 0; i < l; i++)
    xs.push(ys[i]);
}
__name(pushAll, "pushAll");
var hasOwnProperty = Object.prototype.hasOwnProperty;
function getNameFromProps(props) {
  return Object.keys(props).map(function(k) {
    return k + ": " + props[k].name;
  }).join(", ");
}
__name(getNameFromProps, "getNameFromProps");
function useIdentity(codecs) {
  for (var i = 0; i < codecs.length; i++)
    if (codecs[i].encode !== identity)
      return !1;
  return !0;
}
__name(useIdentity, "useIdentity");
function getInterfaceTypeName(props) {
  return "{ " + getNameFromProps(props) + " }";
}
__name(getInterfaceTypeName, "getInterfaceTypeName");
function getUnionName(codecs) {
  return "(" + codecs.map(function(type2) {
    return type2.name;
  }).join(" | ") + ")";
}
__name(getUnionName, "getUnionName");
function isNonEmpty(as) {
  return as.length > 0;
}
__name(isNonEmpty, "isNonEmpty");
var emptyTags = {};
function intersect(a, b) {
  for (var r = [], _i = 0, a_1 = a; _i < a_1.length; _i++) {
    var v = a_1[_i];
    b.indexOf(v) !== -1 && r.push(v);
  }
  return r;
}
__name(intersect, "intersect");
function mergeTags(a, b) {
  if (a === emptyTags)
    return b;
  if (b === emptyTags)
    return a;
  var r = Object.assign({}, a);
  for (var k in b)
    if (a.hasOwnProperty(k)) {
      var intersection_1 = intersect(a[k], b[k]);
      if (isNonEmpty(intersection_1))
        r[k] = intersection_1;
      else {
        r = emptyTags;
        break;
      }
    } else
      r[k] = b[k];
  return r;
}
__name(mergeTags, "mergeTags");
function intersectTags(a, b) {
  if (a === emptyTags || b === emptyTags)
    return emptyTags;
  var r = emptyTags;
  for (var k in a)
    if (b.hasOwnProperty(k)) {
      var intersection_2 = intersect(a[k], b[k]);
      intersection_2.length === 0 && (r === emptyTags && (r = {}), r[k] = a[k].concat(b[k]));
    }
  return r;
}
__name(intersectTags, "intersectTags");
function isLiteralC(codec) {
  return codec._tag === "LiteralType";
}
__name(isLiteralC, "isLiteralC");
function isTypeC(codec) {
  return codec._tag === "InterfaceType";
}
__name(isTypeC, "isTypeC");
function isStrictC(codec) {
  return codec._tag === "StrictType";
}
__name(isStrictC, "isStrictC");
function isExactC(codec) {
  return codec._tag === "ExactType";
}
__name(isExactC, "isExactC");
function isRefinementC(codec) {
  return codec._tag === "RefinementType";
}
__name(isRefinementC, "isRefinementC");
function isIntersectionC(codec) {
  return codec._tag === "IntersectionType";
}
__name(isIntersectionC, "isIntersectionC");
function isUnionC(codec) {
  return codec._tag === "UnionType";
}
__name(isUnionC, "isUnionC");
function isRecursiveC(codec) {
  return codec._tag === "RecursiveType";
}
__name(isRecursiveC, "isRecursiveC");
var lazyCodecs = [];
function getTags(codec) {
  if (lazyCodecs.indexOf(codec) !== -1)
    return emptyTags;
  if (isTypeC(codec) || isStrictC(codec)) {
    var index2 = emptyTags;
    for (var k in codec.props) {
      var prop = codec.props[k];
      isLiteralC(prop) && (index2 === emptyTags && (index2 = {}), index2[k] = [prop.value]);
    }
    return index2;
  } else {
    if (isExactC(codec) || isRefinementC(codec))
      return getTags(codec.type);
    if (isIntersectionC(codec))
      return codec.types.reduce(function(tags2, codec2) {
        return mergeTags(tags2, getTags(codec2));
      }, emptyTags);
    if (isUnionC(codec))
      return codec.types.slice(1).reduce(function(tags2, codec2) {
        return intersectTags(tags2, getTags(codec2));
      }, getTags(codec.types[0]));
    if (isRecursiveC(codec)) {
      lazyCodecs.push(codec);
      var tags = getTags(codec.type);
      return lazyCodecs.pop(), tags;
    }
  }
  return emptyTags;
}
__name(getTags, "getTags");
function getIndex(codecs) {
  var tags = getTags(codecs[0]), keys = Object.keys(tags), len = codecs.length, _loop_1 = /* @__PURE__ */ __name(function(k2) {
    for (var all = tags[k2].slice(), index2 = [tags[k2]], i = 1; i < len; i++) {
      var codec = codecs[i], ctags = getTags(codec), values = ctags[k2];
      if (values === void 0)
        return "continue-keys";
      if (values.some(function(v) {
        return all.indexOf(v) !== -1;
      }))
        return "continue-keys";
      all.push.apply(all, values), index2.push(values);
    }
    return { value: [k2, index2] };
  }, "_loop_1");
  keys:
    for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
      var k = keys_1[_i], state_1 = _loop_1(k);
      if (typeof state_1 == "object")
        return state_1.value;
      switch (state_1) {
        case "continue-keys":
          continue keys;
      }
    }
}
__name(getIndex, "getIndex");
var NullType = (
  /** @class */
  function(_super) {
    __extends(NullType2, _super);
    function NullType2() {
      var _this = _super.call(this, "null", function(u) {
        return u === null;
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "NullType", _this;
    }
    return __name(NullType2, "NullType"), NullType2;
  }(Type)
);
new NullType();
var UndefinedType = (
  /** @class */
  function(_super) {
    __extends(UndefinedType2, _super);
    function UndefinedType2() {
      var _this = _super.call(this, "undefined", function(u) {
        return u === void 0;
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "UndefinedType", _this;
    }
    return __name(UndefinedType2, "UndefinedType"), UndefinedType2;
  }(Type)
), undefinedType = new UndefinedType(), VoidType = (
  /** @class */
  function(_super) {
    __extends(VoidType2, _super);
    function VoidType2() {
      var _this = _super.call(this, "void", undefinedType.is, undefinedType.validate, identity) || this;
      return _this._tag = "VoidType", _this;
    }
    return __name(VoidType2, "VoidType"), VoidType2;
  }(Type)
);
new VoidType();
var UnknownType = (
  /** @class */
  function(_super) {
    __extends(UnknownType2, _super);
    function UnknownType2() {
      var _this = _super.call(this, "unknown", function(_) {
        return !0;
      }, success, identity) || this;
      return _this._tag = "UnknownType", _this;
    }
    return __name(UnknownType2, "UnknownType"), UnknownType2;
  }(Type)
);
new UnknownType();
var StringType = (
  /** @class */
  function(_super) {
    __extends(StringType2, _super);
    function StringType2() {
      var _this = _super.call(this, "string", function(u) {
        return typeof u == "string";
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "StringType", _this;
    }
    return __name(StringType2, "StringType"), StringType2;
  }(Type)
), string = new StringType(), NumberType = (
  /** @class */
  function(_super) {
    __extends(NumberType2, _super);
    function NumberType2() {
      var _this = _super.call(this, "number", function(u) {
        return typeof u == "number";
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "NumberType", _this;
    }
    return __name(NumberType2, "NumberType"), NumberType2;
  }(Type)
), number = new NumberType(), BigIntType = (
  /** @class */
  function(_super) {
    __extends(BigIntType2, _super);
    function BigIntType2() {
      var _this = _super.call(
        this,
        "bigint",
        // tslint:disable-next-line: valid-typeof
        function(u) {
          return typeof u == "bigint";
        },
        function(u, c) {
          return _this.is(u) ? success(u) : failure(u, c);
        },
        identity
      ) || this;
      return _this._tag = "BigIntType", _this;
    }
    return __name(BigIntType2, "BigIntType"), BigIntType2;
  }(Type)
);
new BigIntType();
var BooleanType = (
  /** @class */
  function(_super) {
    __extends(BooleanType2, _super);
    function BooleanType2() {
      var _this = _super.call(this, "boolean", function(u) {
        return typeof u == "boolean";
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "BooleanType", _this;
    }
    return __name(BooleanType2, "BooleanType"), BooleanType2;
  }(Type)
), boolean = new BooleanType(), AnyArrayType = (
  /** @class */
  function(_super) {
    __extends(AnyArrayType2, _super);
    function AnyArrayType2() {
      var _this = _super.call(this, "UnknownArray", Array.isArray, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "AnyArrayType", _this;
    }
    return __name(AnyArrayType2, "AnyArrayType"), AnyArrayType2;
  }(Type)
), UnknownArray = new AnyArrayType(), AnyDictionaryType = (
  /** @class */
  function(_super) {
    __extends(AnyDictionaryType2, _super);
    function AnyDictionaryType2() {
      var _this = _super.call(this, "UnknownRecord", function(u) {
        var s = Object.prototype.toString.call(u);
        return s === "[object Object]" || s === "[object Window]";
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "AnyDictionaryType", _this;
    }
    return __name(AnyDictionaryType2, "AnyDictionaryType"), AnyDictionaryType2;
  }(Type)
), UnknownRecord = new AnyDictionaryType(), LiteralType = (
  /** @class */
  function(_super) {
    __extends(LiteralType2, _super);
    function LiteralType2(name2, is, validate, encode2, value) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.value = value, _this._tag = "LiteralType", _this;
    }
    return __name(LiteralType2, "LiteralType"), LiteralType2;
  }(Type)
);
function literal(value, name2) {
  name2 === void 0 && (name2 = JSON.stringify(value));
  var is = /* @__PURE__ */ __name(function(u) {
    return u === value;
  }, "is");
  return new LiteralType(name2, is, function(u, c) {
    return is(u) ? success(value) : failure(u, c);
  }, identity, value);
}
__name(literal, "literal");
(function(_super) {
  __extends(KeyofType, _super);
  function KeyofType(name2, is, validate, encode2, keys) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.keys = keys, _this._tag = "KeyofType", _this;
  }
  return __name(KeyofType, "KeyofType"), KeyofType;
})(Type);
var RefinementType = (
  /** @class */
  function(_super) {
    __extends(RefinementType2, _super);
    function RefinementType2(name2, is, validate, encode2, type2, predicate) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.type = type2, _this.predicate = predicate, _this._tag = "RefinementType", _this;
    }
    return __name(RefinementType2, "RefinementType"), RefinementType2;
  }(Type)
);
function brand(codec, predicate, name2) {
  return refinement(codec, predicate, name2);
}
__name(brand, "brand");
brand(number, function(n) {
  return Number.isInteger(n);
}, "Int");
var RecursiveType = (
  /** @class */
  function(_super) {
    __extends(RecursiveType2, _super);
    function RecursiveType2(name2, is, validate, encode2, runDefinition) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.runDefinition = runDefinition, _this._tag = "RecursiveType", _this;
    }
    return __name(RecursiveType2, "RecursiveType"), RecursiveType2;
  }(Type)
);
Object.defineProperty(RecursiveType.prototype, "type", {
  get: function() {
    return this.runDefinition();
  },
  enumerable: !0,
  configurable: !0
});
var ArrayType = (
  /** @class */
  function(_super) {
    __extends(ArrayType2, _super);
    function ArrayType2(name2, is, validate, encode2, type2) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.type = type2, _this._tag = "ArrayType", _this;
    }
    return __name(ArrayType2, "ArrayType"), ArrayType2;
  }(Type)
);
function array(item, name2) {
  return name2 === void 0 && (name2 = "Array<" + item.name + ">"), new ArrayType(name2, function(u) {
    return UnknownArray.is(u) && u.every(item.is);
  }, function(u, c) {
    var e = UnknownArray.validate(u, c);
    if (isLeft(e))
      return e;
    for (var us = e.right, len = us.length, as = us, errors = [], i = 0; i < len; i++) {
      var ui2 = us[i], result = item.validate(ui2, appendContext(c, String(i), item, ui2));
      if (isLeft(result))
        pushAll(errors, result.left);
      else {
        var ai = result.right;
        ai !== ui2 && (as === us && (as = us.slice()), as[i] = ai);
      }
    }
    return errors.length > 0 ? failures(errors) : success(as);
  }, item.encode === identity ? identity : function(a) {
    return a.map(item.encode);
  }, item);
}
__name(array, "array");
var InterfaceType = (
  /** @class */
  function(_super) {
    __extends(InterfaceType2, _super);
    function InterfaceType2(name2, is, validate, encode2, props) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.props = props, _this._tag = "InterfaceType", _this;
    }
    return __name(InterfaceType2, "InterfaceType"), InterfaceType2;
  }(Type)
);
function type(props, name2) {
  name2 === void 0 && (name2 = getInterfaceTypeName(props));
  var keys = Object.keys(props), types = keys.map(function(key) {
    return props[key];
  }), len = keys.length;
  return new InterfaceType(name2, function(u) {
    if (UnknownRecord.is(u)) {
      for (var i = 0; i < len; i++) {
        var k = keys[i], uk = u[k];
        if (uk === void 0 && !hasOwnProperty.call(u, k) || !types[i].is(uk))
          return !1;
      }
      return !0;
    }
    return !1;
  }, function(u, c) {
    var e = UnknownRecord.validate(u, c);
    if (isLeft(e))
      return e;
    for (var o = e.right, a = o, errors = [], i = 0; i < len; i++) {
      var k = keys[i], ak = a[k], type_1 = types[i], result = type_1.validate(ak, appendContext(c, k, type_1, ak));
      if (isLeft(result))
        pushAll(errors, result.left);
      else {
        var vak = result.right;
        (vak !== ak || vak === void 0 && !hasOwnProperty.call(a, k)) && (a === o && (a = __assign({}, o)), a[k] = vak);
      }
    }
    return errors.length > 0 ? failures(errors) : success(a);
  }, useIdentity(types) ? identity : function(a) {
    for (var s = __assign({}, a), i = 0; i < len; i++) {
      var k = keys[i], encode2 = types[i].encode;
      encode2 !== identity && (s[k] = encode2(a[k]));
    }
    return s;
  }, props);
}
__name(type, "type");
(function(_super) {
  __extends(PartialType, _super);
  function PartialType(name2, is, validate, encode2, props) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.props = props, _this._tag = "PartialType", _this;
  }
  return __name(PartialType, "PartialType"), PartialType;
})(Type);
(function(_super) {
  __extends(DictionaryType, _super);
  function DictionaryType(name2, is, validate, encode2, domain, codomain) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.domain = domain, _this.codomain = codomain, _this._tag = "DictionaryType", _this;
  }
  return __name(DictionaryType, "DictionaryType"), DictionaryType;
})(Type);
var UnionType = (
  /** @class */
  function(_super) {
    __extends(UnionType2, _super);
    function UnionType2(name2, is, validate, encode2, types) {
      var _this = _super.call(this, name2, is, validate, encode2) || this;
      return _this.types = types, _this._tag = "UnionType", _this;
    }
    return __name(UnionType2, "UnionType"), UnionType2;
  }(Type)
);
function union(codecs, name2) {
  name2 === void 0 && (name2 = getUnionName(codecs));
  var index2 = getIndex(codecs);
  if (index2 !== void 0 && codecs.length > 0) {
    var tag_1 = index2[0], groups_1 = index2[1], len_1 = groups_1.length, find_1 = /* @__PURE__ */ __name(function(value) {
      for (var i = 0; i < len_1; i++)
        if (groups_1[i].indexOf(value) !== -1)
          return i;
    }, "find_1");
    return new TaggedUnionType(name2, function(u) {
      if (UnknownRecord.is(u)) {
        var i = find_1(u[tag_1]);
        return i !== void 0 ? codecs[i].is(u) : !1;
      }
      return !1;
    }, function(u, c) {
      var e = UnknownRecord.validate(u, c);
      if (isLeft(e))
        return e;
      var r = e.right, i = find_1(r[tag_1]);
      if (i === void 0)
        return failure(u, c);
      var codec = codecs[i];
      return codec.validate(r, appendContext(c, String(i), codec, r));
    }, useIdentity(codecs) ? identity : function(a) {
      var i = find_1(a[tag_1]);
      if (i === void 0)
        throw new Error("no codec found to encode value in union codec " + name2);
      return codecs[i].encode(a);
    }, codecs, tag_1);
  } else
    return new UnionType(name2, function(u) {
      return codecs.some(function(type2) {
        return type2.is(u);
      });
    }, function(u, c) {
      for (var errors = [], i = 0; i < codecs.length; i++) {
        var codec = codecs[i], result = codec.validate(u, appendContext(c, String(i), codec, u));
        if (isLeft(result))
          pushAll(errors, result.left);
        else
          return success(result.right);
      }
      return failures(errors);
    }, useIdentity(codecs) ? identity : function(a) {
      for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) {
        var codec = codecs_1[_i];
        if (codec.is(a))
          return codec.encode(a);
      }
      throw new Error("no codec found to encode value in union type " + name2);
    }, codecs);
}
__name(union, "union");
(function(_super) {
  __extends(IntersectionType, _super);
  function IntersectionType(name2, is, validate, encode2, types) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.types = types, _this._tag = "IntersectionType", _this;
  }
  return __name(IntersectionType, "IntersectionType"), IntersectionType;
})(Type);
(function(_super) {
  __extends(TupleType, _super);
  function TupleType(name2, is, validate, encode2, types) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.types = types, _this._tag = "TupleType", _this;
  }
  return __name(TupleType, "TupleType"), TupleType;
})(Type);
(function(_super) {
  __extends(ReadonlyType, _super);
  function ReadonlyType(name2, is, validate, encode2, type2) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.type = type2, _this._tag = "ReadonlyType", _this;
  }
  return __name(ReadonlyType, "ReadonlyType"), ReadonlyType;
})(Type);
(function(_super) {
  __extends(ReadonlyArrayType, _super);
  function ReadonlyArrayType(name2, is, validate, encode2, type2) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.type = type2, _this._tag = "ReadonlyArrayType", _this;
  }
  return __name(ReadonlyArrayType, "ReadonlyArrayType"), ReadonlyArrayType;
})(Type);
(function(_super) {
  __extends(ExactType, _super);
  function ExactType(name2, is, validate, encode2, type2) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.type = type2, _this._tag = "ExactType", _this;
  }
  return __name(ExactType, "ExactType"), ExactType;
})(Type);
var FunctionType = (
  /** @class */
  function(_super) {
    __extends(FunctionType2, _super);
    function FunctionType2() {
      var _this = _super.call(
        this,
        "Function",
        // tslint:disable-next-line:strict-type-predicates
        function(u) {
          return typeof u == "function";
        },
        function(u, c) {
          return _this.is(u) ? success(u) : failure(u, c);
        },
        identity
      ) || this;
      return _this._tag = "FunctionType", _this;
    }
    return __name(FunctionType2, "FunctionType"), FunctionType2;
  }(Type)
);
new FunctionType();
var TaggedUnionType = (
  /** @class */
  function(_super) {
    __extends(TaggedUnionType2, _super);
    function TaggedUnionType2(name2, is, validate, encode2, codecs, tag) {
      var _this = _super.call(this, name2, is, validate, encode2, codecs) || this;
      return _this.tag = tag, _this;
    }
    return __name(TaggedUnionType2, "TaggedUnionType"), TaggedUnionType2;
  }(UnionType)
), NeverType = (
  /** @class */
  function(_super) {
    __extends(NeverType2, _super);
    function NeverType2() {
      var _this = _super.call(
        this,
        "never",
        function(_) {
          return !1;
        },
        function(u, c) {
          return failure(u, c);
        },
        /* istanbul ignore next */
        function() {
          throw new Error("cannot encode never");
        }
      ) || this;
      return _this._tag = "NeverType", _this;
    }
    return __name(NeverType2, "NeverType"), NeverType2;
  }(Type)
);
new NeverType();
var AnyType = (
  /** @class */
  function(_super) {
    __extends(AnyType2, _super);
    function AnyType2() {
      var _this = _super.call(this, "any", function(_) {
        return !0;
      }, success, identity) || this;
      return _this._tag = "AnyType", _this;
    }
    return __name(AnyType2, "AnyType"), AnyType2;
  }(Type)
);
new AnyType();
var ObjectType = (
  /** @class */
  function(_super) {
    __extends(ObjectType2, _super);
    function ObjectType2() {
      var _this = _super.call(this, "object", function(u) {
        return u !== null && typeof u == "object";
      }, function(u, c) {
        return _this.is(u) ? success(u) : failure(u, c);
      }, identity) || this;
      return _this._tag = "ObjectType", _this;
    }
    return __name(ObjectType2, "ObjectType"), ObjectType2;
  }(Type)
);
new ObjectType();
function refinement(codec, predicate, name2) {
  return name2 === void 0 && (name2 = "(" + codec.name + " | " + getFunctionName(predicate) + ")"), new RefinementType(name2, function(u) {
    return codec.is(u) && predicate(u);
  }, function(i, c) {
    var e = codec.validate(i, c);
    if (isLeft(e))
      return e;
    var a = e.right;
    return predicate(a) ? success(a) : failure(a, c);
  }, codec.encode, codec, predicate);
}
__name(refinement, "refinement");
refinement(number, Number.isInteger, "Integer");
(function(_super) {
  __extends(StrictType, _super);
  function StrictType(name2, is, validate, encode2, props) {
    var _this = _super.call(this, name2, is, validate, encode2) || this;
    return _this.props = props, _this._tag = "StrictType", _this;
  }
  return __name(StrictType, "StrictType"), StrictType;
})(Type);
function unwrap(e) {
  if (isLeft(e))
    throw e.left;
  return e.right;
}
__name(unwrap, "unwrap");
function enclass(codec, Constructor) {
  return new Type(
    Constructor.name,
    (v) => v instanceof Constructor,
    (data2) => map((d) => new Constructor(d))(codec.decode(data2)),
    (inst) => codec.encode(inst.raw)
  );
}
__name(enclass, "enclass");
function stateless(name2, predicate, synthesise) {
  return new Type(
    name2,
    predicate,
    (_) => right(synthesise()),
    (_) => null
  );
}
__name(stateless, "stateless");
function encode(t2, codec) {
  return codec.encode(t2);
}
__name(encode, "encode");
function decode(r, codec) {
  return unwrap(codec.decode(r));
}
__name(decode, "decode");
var _a2;
const _Invisibility = (_a2 = class {
  // these methods are for easy class codecs via `enclass`
  constructor(ser) {
    this.uiElement = "checkbox", this.slug = "invisibility", this.humanLabel = "Invisible (*)", this.category = "diff", this.visible = !0, this.disabled = !1, this.rollPrecedence = -9999, this.data = ser;
  }
  get raw() {
    return this.data;
  }
  // as you may have guessed, the codec just stores the enum
  static get codec() {
    return enclass(union([literal(-1), literal(0), literal(1)]), _a2);
  }
  // store a reference to the current token when rehydrated
  hydrate(_d, t2) {
    t2 && (this.token = t2.target);
  }
  // invisibility operates on the target level, whether we know the target or not
  static perUnknownTarget() {
    return new _a2(
      0
      /* NoForce */
    );
  }
  static perTarget(item) {
    let ret = _a2.perUnknownTarget();
    return ret.token = item, ret;
  }
  // assume targets aren't invisible if we don't know about them
  // otherwise, go get the status effects and check them
  get tokenInvisible() {
    var _a19;
    return this.token ? !!((_a19 = this.token.actor) != null && _a19.system.statuses.invisible) : !1;
  }
  // our uiState is whether we're treating the current target as invisible
  get uiState() {
    return this.data == 0 ? this.tokenInvisible : !!(this.data + 1);
  }
  // toggling invisibility to what the token isn't is interpreted as a force
  // toggling invisibility to whatever the token is is interpreted as not wanting to force
  set uiState(newState) {
    this.tokenInvisible == newState ? this.data = 0 : newState ? this.data = 1 : this.data = -1;
  }
  // the effect to have on the roll
  // 1d2even resolves to either 0 or 1 successes, so multiplying works great
  modifyRoll(roll) {
    return this.uiState ? `{${roll}} * (1dc[👻 invisibility])` : roll;
  }
  // after _everything_
}, __name(_a2, "_Invisibility"), _a2);
_Invisibility.slug = "invisibility";
_Invisibility.category = "diff";
let Invisibility = _Invisibility;
function adjacentSpotter(actor) {
  if (!actor.is_mech())
    return !1;
  let token = actor.getActiveTokens()[0];
  const aabb = new PIXI.Rectangle(
    token.bounds.x - 2 * canvas.grid.sizeX,
    token.bounds.y - 2 * canvas.grid.sizeY,
    token.bounds.right + 4 * canvas.grid.sizeX,
    token.bounds.bottom + 4 * canvas.grid.sizeY
  );
  return canvas.tokens.quadtree.getObjects(aabb, {
    // @ts-expect-error Quadtree not set specific enough in types
    collisionTest: (o) => {
      var _a19, _b, _c, _d, _e;
      if (!((_a19 = o.t.actor) != null && _a19.is_mech()) || o.t === token || !((_c = (_b = o.t.actor.system.pilot) == null ? void 0 : _b.value) != null && _c.itemTypes.talent.some((t) => t.system.lid === "t_spotter")))
        return !1;
      const range = (((_e = (_d = o.t.actor.system.pilot) == null ? void 0 : _d.value) == null ? void 0 : _e.itemTypes.talent.some((t) => t.system.lid === "t_house_guard")) ?? !1 ? 2 : 1) + 0.1;
      return o.t.document.computeRange(token.document) <= range;
    }
  }).size >= 1;
}
__name(adjacentSpotter, "adjacentSpotter");
function spotter() {
  return {
    actor: null,
    target: null,
    uiElement: "checkbox",
    slug: "spotter",
    category: "acc",
    humanLabel: "Spotter (*)",
    get uiState() {
      var _a19;
      return !!(this.actor && ((_a19 = this.target) != null && _a19.usingLockOn) && adjacentSpotter(this.actor));
    },
    set uiState(_v) {
    },
    disabled: !0,
    get visible() {
      var _a19;
      return !!((_a19 = this.target) != null && _a19.usingLockOn);
    },
    modifyRoll(roll) {
      return this.uiState ? `{${roll},${roll}}kh[🎯 spotter]` : roll;
    },
    rollPrecedence: -100,
    // after numeric modifiers
    hydrate(data2, target) {
      this.actor = data2.lancerActor || null, this.target = target || null;
    }
  };
}
__name(spotter, "spotter");
const Spotter = {
  slug: "spotter",
  category: "acc",
  codec: stateless(
    "Spotter",
    (t) => typeof t == "object" && (t == null ? void 0 : t.slug) == "spotter",
    spotter
  ),
  perTarget(_t) {
    return spotter();
  }
}, Spotter$1 = Spotter;
var __accessCheck$5 = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck$5"), __privateGet$1 = /* @__PURE__ */ __name((obj, member, getter) => (__accessCheck$5(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)), "__privateGet$1"), __privateAdd$5 = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd$5"), __privateSet$1 = /* @__PURE__ */ __name((obj, member, value, setter) => (__accessCheck$5(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value), "__privateSet$1"), _data$1, _weapon$1, _weapon2$1, _base$1;
let coverSchema = union([literal(0), literal(1), literal(2)]);
var _a3;
const _AccDiffHudWeapon = (_a3 = class {
  constructor(obj) {
    __privateAdd$5(this, _data$1, void 0), this.accurate = obj.accurate, this.inaccurate = obj.inaccurate, this.seeking = obj.seeking, this.engaged = obj.engaged, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      accurate: boolean,
      inaccurate: boolean,
      seeking: boolean,
      engaged: boolean,
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a3);
  }
  get raw() {
    return {
      accurate: this.accurate,
      inaccurate: this.inaccurate,
      seeking: this.seeking,
      engaged: this.engaged,
      plugins: this.plugins
    };
  }
  get impaired() {
    var _a19, _b, _c;
    return !!((_c = (_b = (_a19 = __privateGet$1(this, _data$1)) == null ? void 0 : _a19.lancerActor) == null ? void 0 : _b.system) != null && _c.statuses.impaired);
  }
  get engagedStatus() {
    var _a19, _b, _c;
    return !!((_c = (_b = (_a19 = __privateGet$1(this, _data$1)) == null ? void 0 : _a19.lancerActor) == null ? void 0 : _b.system) != null && _c.statuses.engaged);
  }
  total(cover) {
    return (this.accurate ? 1 : 0) - (this.inaccurate ? 1 : 0) - (this.seeking ? 0 : cover) - (this.impaired ? 1 : 0) - (this.engaged ? 1 : 0);
  }
  hydrate(d) {
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d);
    __privateSet$1(this, _data$1, d);
  }
}, __name(_a3, "_AccDiffHudWeapon"), _a3);
_data$1 = /* @__PURE__ */ new WeakMap();
_AccDiffHudWeapon.pluginSchema = {};
let AccDiffHudWeapon = _AccDiffHudWeapon;
var _a4;
const _AccDiffHudBase = (_a4 = class {
  constructor(obj) {
    __privateAdd$5(this, _weapon$1, void 0), this.grit = obj.grit, this.flatBonus = obj.flatBonus, this.accuracy = obj.accuracy, this.difficulty = obj.difficulty, this.cover = obj.cover, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      grit: number,
      flatBonus: number,
      accuracy: number,
      difficulty: number,
      cover: coverSchema,
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a4);
  }
  get raw() {
    return {
      grit: this.grit,
      flatBonus: this.flatBonus,
      accuracy: this.accuracy,
      difficulty: this.difficulty,
      cover: this.cover,
      plugins: this.plugins
    };
  }
  hydrate(d) {
    __privateSet$1(this, _weapon$1, d.weapon);
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d, this);
  }
  get total() {
    return this.accuracy - this.difficulty + __privateGet$1(this, _weapon$1).total(this.cover);
  }
}, __name(_a4, "_AccDiffHudBase"), _a4);
_weapon$1 = /* @__PURE__ */ new WeakMap();
_AccDiffHudBase.pluginSchema = {};
let AccDiffHudBase = _AccDiffHudBase;
var _a5;
const _AccDiffHudTarget = (_a5 = class {
  constructor(obj) {
    __privateAdd$5(this, _weapon2$1, void 0), __privateAdd$5(this, _base$1, void 0);
    let target = canvas.scene.tokens.get(obj.target_id);
    if (!target)
      throw ui.notifications.error("Trying to access tokens from a different scene!"), new Error("Token not found");
    this.target = target.object, this.accuracy = obj.accuracy, this.difficulty = obj.difficulty, this.cover = obj.cover, this.consumeLockOn = obj.consumeLockOn, this.prone = obj.prone, this.stunned = obj.stunned, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      target_id: string,
      accuracy: number,
      difficulty: number,
      cover: coverSchema,
      consumeLockOn: boolean,
      prone: boolean,
      stunned: boolean,
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a5);
  }
  get raw() {
    return {
      target_id: this.target.id,
      accuracy: this.accuracy,
      difficulty: this.difficulty,
      cover: this.cover,
      consumeLockOn: this.consumeLockOn,
      prone: this.prone,
      stunned: this.stunned,
      plugins: this.plugins
    };
  }
  static fromParams(t2) {
    var _a19, _b, _c, _d;
    let cover = 0;
    (_a19 = t2.actor) != null && _a19.statuses.has("cover_hard") ? cover = 2 : (_b = t2.actor) != null && _b.statuses.has("cover_soft") && (cover = 1);
    let ret = {
      target_id: t2.id,
      accuracy: 0,
      difficulty: 0,
      cover,
      consumeLockOn: !0,
      prone: ((_c = t2.actor) == null ? void 0 : _c.system.statuses.prone) || !1,
      stunned: ((_d = t2.actor) == null ? void 0 : _d.system.statuses.stunned) || !1,
      plugins: {}
    };
    for (let plugin of AccDiffHudData.targetedPlugins)
      ret.plugins[plugin.slug] = encode(plugin.perTarget(t2), plugin.codec);
    return decode(ret, _a5.codec);
  }
  hydrate(d) {
    __privateSet$1(this, _weapon2$1, d.weapon), __privateSet$1(this, _base$1, d.base);
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d, this);
  }
  get usingLockOn() {
    return this.consumeLockOn && this.lockOnAvailable || null;
  }
  get lockOnAvailable() {
    var _a19;
    return !!((_a19 = this.target.actor) != null && _a19.system.statuses.lockon);
  }
  get total() {
    let raw = this.accuracy - this.difficulty + __privateGet$1(this, _weapon2$1).total(this.cover) + __privateGet$1(this, _base$1).accuracy - __privateGet$1(this, _base$1).difficulty, lockon = this.usingLockOn ? 1 : 0, prone = this.prone ? 1 : 0;
    return raw + lockon + prone;
  }
}, __name(_a5, "_AccDiffHudTarget"), _a5);
_weapon2$1 = /* @__PURE__ */ new WeakMap();
_base$1 = /* @__PURE__ */ new WeakMap();
_AccDiffHudTarget.pluginSchema = {};
let AccDiffHudTarget = _AccDiffHudTarget;
var _a6;
const _AccDiffHudData = (_a6 = class {
  // not persisted, needs to be hydrated
  static get schema() {
    return {
      title: string,
      weapon: AccDiffHudWeapon.codec,
      base: AccDiffHudBase.codec,
      targets: array(AccDiffHudTarget.codec)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a6);
  }
  constructor(obj) {
    this.title = obj.title, this.weapon = obj.weapon, this.base = obj.base, this.targets = obj.targets, this.hydrate();
  }
  hydrate(runtimeData) {
    runtimeData instanceof LancerItem ? (this.lancerItem = runtimeData, this.lancerActor = runtimeData.actor ?? void 0) : this.lancerActor = runtimeData ?? void 0, this.weapon.hydrate(this), this.base.hydrate(this);
    for (let target of this.targets)
      target.hydrate(this);
  }
  replaceTargets(ts) {
    let oldTargets = {};
    for (let data2 of this.targets)
      oldTargets[data2.target.id] = data2;
    this.targets = ts.map((t2) => {
      const oldTarget = oldTargets[t2.id], newTarget = AccDiffHudTarget.fromParams(t2);
      return oldTargets[t2.id] && (newTarget.accuracy = oldTarget.accuracy, newTarget.difficulty = oldTarget.difficulty, newTarget.consumeLockOn = oldTarget.consumeLockOn, newTarget.plugins = oldTarget.plugins), newTarget;
    });
    for (let target of this.targets)
      target.hydrate(this);
    return this;
  }
  get raw() {
    return {
      title: this.title,
      weapon: this.weapon,
      base: this.base,
      targets: this.targets
    };
  }
  // Decode from a serialized object, optionally populating remaining data from an item
  static fromObject(obj, runtimeData) {
    let ret = decode(obj, _a6.codec);
    return ret.hydrate(runtimeData), ret;
  }
  toObject() {
    return encode(this, _a6.codec);
  }
  static registerPlugin(plugin) {
    plugin.perRoll && (AccDiffHudWeapon.pluginSchema[plugin.slug] = plugin.codec), plugin.perUnknownTarget && (AccDiffHudBase.pluginSchema[plugin.slug] = plugin.codec), plugin.perTarget && (AccDiffHudTarget.pluginSchema[plugin.slug] = plugin.codec, this.targetedPlugins.push(plugin)), this.plugins.push(plugin);
  }
  static fromParams(runtimeData, tags, title, targets, grit, flat, starting) {
    let weapon = {
      accurate: !1,
      inaccurate: !1,
      seeking: !1,
      engaged: !1,
      plugins: {}
    };
    starting ? typeof starting == "number" && (starting = starting >= 0 ? [starting, 0] : [0, -starting]) : starting = [0, 0];
    for (let tag of tags || [])
      switch (tag.lid) {
        case "tg_accurate":
          weapon.accurate = !0;
          break;
        case "tg_inaccurate":
          weapon.inaccurate = !0;
          break;
        case "tg_seeking":
          weapon.seeking = !0;
          break;
      }
    let base = {
      grit: grit || 0,
      flatBonus: flat || 0,
      cover: 0,
      accuracy: starting[0],
      difficulty: starting[1],
      plugins: {}
    }, obj = {
      title: title || "Accuracy and Difficulty",
      weapon,
      base,
      targets: (targets || []).map((t2) => {
        var _a19, _b, _c, _d;
        let cover = 0;
        (_a19 = t2.actor) != null && _a19.statuses.has("cover_hard") ? cover = 2 : (_b = t2.actor) != null && _b.statuses.has("cover_soft") && (cover = 1);
        let ret = {
          target_id: t2.id,
          accuracy: 0,
          difficulty: 0,
          cover,
          consumeLockOn: !0,
          prone: ((_c = t2.actor) == null ? void 0 : _c.system.statuses.prone) || !1,
          stunned: ((_d = t2.actor) == null ? void 0 : _d.system.statuses.stunned) || !1,
          plugins: {}
        };
        for (let plugin of this.targetedPlugins)
          ret.plugins[plugin.slug] = encode(plugin.perTarget(t2), plugin.codec);
        return ret;
      })
    };
    for (let plugin of this.plugins)
      plugin.perRoll && (obj.weapon.plugins[plugin.slug] = encode(plugin.perRoll(runtimeData), plugin.codec)), plugin.perUnknownTarget && (obj.base.plugins[plugin.slug] = encode(plugin.perUnknownTarget(), plugin.codec));
    return _a6.fromObject(obj, runtimeData);
  }
}, __name(_a6, "_AccDiffHudData"), _a6);
_AccDiffHudData.plugins = [];
_AccDiffHudData.targetedPlugins = [];
let AccDiffHudData = _AccDiffHudData;
AccDiffHudData.registerPlugin(Invisibility);
AccDiffHudData.registerPlugin(Spotter$1);
let hud, activeCallbacks = {
  hase: null,
  attack: null,
  damage: null,
  struct: null,
  stress: null
};
async function attach() {
  if (!hud) {
    let HUDZone = (await import("./SlidingHUDZone-bea5c98f.mjs")).default;
    hud = new HUDZone({
      target: document.body
    });
    for (let key of ["attack", "damage", "hase", "struct", "stress"])
      hud.$on(`${key}.submit`, (ev) => {
        var _a19;
        (_a19 = activeCallbacks[key]) == null || _a19[0](ev.detail), activeCallbacks[key] = null;
      }), hud.$on(`${key}.cancel`, () => {
        var _a19;
        (_a19 = activeCallbacks[key]) == null || _a19[1](), activeCallbacks[key] = null;
      });
  }
  return hud;
}
__name(attach, "attach");
async function openSlidingHud(key, data2) {
  return (await attach()).open(key, data2), new Promise((resolve, reject) => {
    activeCallbacks[key] = [resolve, reject];
  });
}
__name(openSlidingHud, "openSlidingHud");
async function fade(dir = "out") {
  (await attach()).fade(dir);
}
__name(fade, "fade");
const index$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  attach,
  fade,
  openSlidingHud
}, Symbol.toStringTag, { value: "Module" }));
async function checkForHit(tech, roll, target) {
  let sysData = target.system, def = tech ? sysData.edef || 8 : sysData.evasion || 5;
  return (roll.total ?? 0) >= def;
}
__name(checkForHit, "checkForHit");
function gridDist(token1, token2) {
  var _a19, _b;
  let c1 = token1.center, c2 = token2.center, ray = new Ray(c1, c2);
  return (_b = (_a19 = canvas == null ? void 0 : canvas.grid) == null ? void 0 : _a19.grid) == null ? void 0 : _b.measureDistances([{ ray }], { gridSpaces: !0 })[0];
}
__name(gridDist, "gridDist");
async function renderTemplateStep(actor, template, templateData, flags) {
  var _a19, _b, _c;
  templateData._uuid = nanoid();
  const html = await renderTemplate(template, templateData), aggregate = [];
  return templateData.roll && aggregate.push(templateData.roll), templateData.result && aggregate.push(templateData.result.roll), (((_a19 = templateData.attack_results) == null ? void 0 : _a19.length) ?? 0) > 0 && aggregate.push(...templateData.attack_results.map((a) => a.roll)), (((_b = templateData.crit_damage_results) == null ? void 0 : _b.length) ?? 0) > 0 ? aggregate.push(...templateData.crit_damage_results.map((d) => d.roll)) : (((_c = templateData.damage_results) == null ? void 0 : _c.length) ?? 0) > 0 && aggregate.push(...templateData.damage_results.map((d) => d.roll)), templateData.self_heat_result && aggregate.push(templateData.self_heat_result.roll), createChatMessageStep(actor, html, aggregate, flags);
}
__name(renderTemplateStep, "renderTemplateStep");
async function createChatMessageStep(actor, html, rolls, flags) {
  rolls && !Array.isArray(rolls) && (rolls = [rolls]);
  let chat_data = {
    type: CONST.CHAT_MESSAGE_STYLES.IC,
    rolls,
    speaker: {
      actor,
      token: actor == null ? void 0 : actor.token,
      alias: actor != null && actor.token ? actor.token.name : null
    },
    content: html,
    flags: flags ? { lancer: flags } : void 0
  };
  rolls || delete chat_data.rolls;
  const cm = await ChatMessage.implementation.create(chat_data);
  cm == null || cm.render();
}
__name(createChatMessageStep, "createChatMessageStep");
const lp$g = LANCER.log_prefix;
var _a7;
const _Flow = (_a7 = class {
  constructor(uuid, data2) {
    let item = null, actor = null;
    if (typeof uuid == "string") {
      const resolved = fromUuidSync(uuid);
      if (resolved instanceof LancerItem)
        item = resolved;
      else if (resolved instanceof LancerActor)
        actor = resolved;
      else
        throw new TypeError("Flow argument 'uuid' must resolve to an Item or an Actor.");
    } else if (uuid instanceof LancerItem)
      item = uuid;
    else if (uuid instanceof LancerActor)
      actor = uuid;
    else
      throw new TypeError("Flow argument 'uuid' must be a valid UUID string, an Item, or an Actor.");
    if (item && !actor && (actor = item.parent, !actor))
      throw new TypeError(
        "Flow argument 'uuid' was given an Item which is not owned by an Actor. Only owned Items can be used in Flows."
      );
    if (!actor)
      throw new TypeError("Flow argument 'uuid' did not resolve to an Actor.");
    this.state = {
      name: this.constructor.name,
      actor,
      item,
      currentStep: "",
      data: data2
    };
  }
  /**
   * Retrieve a step function from the global registry in game.lancer.flowSteps.
   * @param stepKey The key of the step to retrieve
   * @returns The step with the given key, or null if no such step exists.
   */
  static getStep(stepKey) {
    return game.lancer.flowSteps.get(stepKey) ?? null;
  }
  /**
   * Retrieve a step function from the global registry in game.lancer.flowSteps.
   * Convenience access to the static method.
   * @param stepKey The key of the step to retrieve
   * @returns The step with the given key, or null if no such step exists.
   */
  getStep(stepKey) {
    return _a7.getStep(stepKey);
  }
  /**
   * Insert a step into the step array, to be executed before an existing step
   * @param key Existing step key to insert newKey before
   * @param newKey New step key
   */
  static insertStepBefore(key, newKey) {
    const keyIndex = this.steps.indexOf(key);
    keyIndex == -1 && this.steps.push(newKey), this.steps.splice(keyIndex, 0, newKey);
  }
  /**
   * Insert a step into the step array, to be executed after an existing step
   * @param key Existing step key to insert newKey after
   * @param newKey New step key
   */
  static insertStepAfter(key, newKey) {
    const keyIndex = this.steps.indexOf(key);
    keyIndex == -1 && this.steps.push(newKey), this.steps.splice(keyIndex + 1, 0, newKey);
  }
  /**
   * Remove the given step from the steps to execute
   * @param key Existing step key to delete
   */
  static removeStep(key) {
    const keyIndex = this.steps.indexOf(key);
    this.steps.splice(keyIndex, 1);
  }
  /**
   * Start the flow. Each step is awaited in the order they were inserted to the map.
   * @param data Initial data for the specific flow to populate its state.data.
   */
  async begin(data2) {
    this.state.data = data2 || this.state.data, Hooks.callAll(`lancer.preFlow.${this.constructor.name}`, this);
    for (const key of this.constructor.steps) {
      console.log(`${lp$g} running flow step ${key}`), this.state.currentStep = key;
      const step = this.getStep(key);
      if (!step)
        return ui.notifications.error(`Lancer flow error: ${key} is not a valid step`), console.log(`${lp$g} Flow aborted when ${key} was not found. All steps in this flow:`, this.constructor.steps), !1;
      if (step instanceof _a7) {
        if (await step.begin() === !1)
          return console.log(`${lp$g} flow aborted when ${key} returned false`), Hooks.callAll(`lancer.postFlow.${this.constructor.name}`, this, !1), !1;
      } else if (await step(this.state, data2) === !1)
        return console.log(`${lp$g} flow aborted when ${key} returned false`), Hooks.callAll(`lancer.postFlow.${this.constructor.name}`, this, !1), !1;
    }
    return Hooks.callAll(`lancer.postFlow.${this.constructor.name}`, this, !0), !0;
  }
  /**
   * Generate a JSON string representing this Flow instance.
   * This is a generic implementation, some Flows will reimplement as needed.
   * @returns JSON string representing this Flow instance.
   */
  // TODO: is this used for anything?
  serialize() {
    return JSON.stringify({
      name: this.state.name,
      uuid: this.state.item ? this.state.item.uuid : this.state.actor.uuid,
      data: this.state.data
    });
  }
  /**
   * Consume a serialized Flow state JSON to create a hydrated Flow instance
   * This is a generic implementation, some Flows will reimplement as needed.
   * @param json Serialized JSON string of the flow.
   * @returns A new Flow constructed from the JSON data.
   */
  // TODO: is this used for anything?
  static deserialize(json) {
    const hydrated = JSON.parse(json);
    return new _a7(hydrated.uuid, hydrated.data);
  }
}, __name(_a7, "_Flow"), _a7);
_Flow.steps = ["emptyStep"];
let Flow = _Flow;
var LancerFlowState;
((LancerFlowState2) => {
  function isStatRoll(data2) {
    return data2.type === "stat";
  }
  __name(isStatRoll, "isStatRoll"), LancerFlowState2.isStatRoll = isStatRoll;
  function isAttackRoll(data2) {
    return data2.type === "attack";
  }
  __name(isAttackRoll, "isAttackRoll"), LancerFlowState2.isAttackRoll = isAttackRoll;
  function isWeaponRoll(data2) {
    return data2.type === "weapon";
  }
  __name(isWeaponRoll, "isWeaponRoll"), LancerFlowState2.isWeaponRoll = isWeaponRoll;
  function isTechRoll(data2) {
    return data2.type === "tech";
  }
  __name(isTechRoll, "isTechRoll"), LancerFlowState2.isTechRoll = isTechRoll;
  function isActionRoll(data2) {
    return data2.type === "action";
  }
  __name(isActionRoll, "isActionRoll"), LancerFlowState2.isActionRoll = isActionRoll, ((BasicFlowType2) => {
    BasicFlowType2.FullRepair = "FullRepair", BasicFlowType2.Stabilize = "Stabilize", BasicFlowType2.Overheat = "Overheat", BasicFlowType2.Structure = "Structure", BasicFlowType2.Burn = "Burn", BasicFlowType2.Overcharge = "Overcharge", BasicFlowType2.BasicAttack = "BasicAttack", BasicFlowType2.Damage = "Damage", BasicFlowType2.TechAttack = "TechAttack";
  })(LancerFlowState2.BasicFlowType || (LancerFlowState2.BasicFlowType = {}));
})(LancerFlowState || (LancerFlowState = {}));
const lp$f = LANCER.log_prefix;
function rollStr(bonus, total) {
  let modStr = "";
  if (total != 0) {
    let sign = total > 0 ? "+" : "-", abs = Math.abs(total), roll = abs == 1 ? "1d6" : `${abs}d6kh1`;
    modStr = ` ${sign} ${roll}`;
  }
  return `1d20 + ${bonus}${modStr}`;
}
__name(rollStr, "rollStr");
function applyPluginsToRoll(str, plugins) {
  return plugins.sort((p, q) => q.rollPrecedence - p.rollPrecedence).reduce((acc, p) => p.modifyRoll(acc), str);
}
__name(applyPluginsToRoll, "applyPluginsToRoll");
function attackRolls(flat_bonus, acc_diff) {
  let perRoll = Object.values(acc_diff.weapon.plugins), base = perRoll.concat(Object.values(acc_diff.base.plugins));
  return {
    roll: applyPluginsToRoll(rollStr(flat_bonus, acc_diff.base.total), base),
    targeted: acc_diff.targets.map((tad) => {
      let perTarget = perRoll.concat(Object.values(tad.plugins));
      return {
        target: tad.target,
        roll: applyPluginsToRoll(rollStr(flat_bonus, tad.total), perTarget),
        usedLockOn: tad.usingLockOn
      };
    })
  };
}
__name(attackRolls, "attackRolls");
function registerAttackSteps(flowSteps) {
  flowSteps.set("initAttackData", initAttackData), flowSteps.set("checkWeaponLoaded", checkWeaponLoaded), flowSteps.set("setAttackTags", setAttackTags), flowSteps.set("setAttackEffects", setAttackEffects), flowSteps.set("setAttackTargets", setAttackTargets), flowSteps.set("showAttackHUD", showAttackHUD), flowSteps.set("rollAttacks", rollAttacks), flowSteps.set("clearTargets", clearTargets), flowSteps.set("printAttackCard", printAttackCard);
}
__name(registerAttackSteps, "registerAttackSteps");
const _BasicAttackFlow = class _BasicAttackFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "attack",
      title: (data2 == null ? void 0 : data2.title) || "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) || "",
      grit: (data2 == null ? void 0 : data2.grit) || 0,
      flat_bonus: (data2 == null ? void 0 : data2.flat_bonus) || 0,
      attack_type: (data2 == null ? void 0 : data2.attack_type) || AttackType.Melee,
      action: (data2 == null ? void 0 : data2.action) || null,
      is_smart: (data2 == null ? void 0 : data2.is_smart) || !1,
      attack_rolls: (data2 == null ? void 0 : data2.attack_rolls) || { roll: "", targeted: [] },
      attack_results: (data2 == null ? void 0 : data2.attack_results) || [],
      hit_results: (data2 == null ? void 0 : data2.hit_results) || [],
      reroll_data: (data2 == null ? void 0 : data2.reroll_data) || "",
      tags: (data2 == null ? void 0 : data2.tags) || []
    };
    super(uuid, initialData), this.name = "BasicAttackFlow";
  }
};
__name(_BasicAttackFlow, "BasicAttackFlow");
let BasicAttackFlow = _BasicAttackFlow;
BasicAttackFlow.steps = [
  "initAttackData",
  "setAttackTags",
  "setAttackEffects",
  "setAttackTargets",
  "showAttackHUD",
  "rollAttacks",
  "applySelfHeat",
  "printAttackCard"
];
const _WeaponAttackFlow = class _WeaponAttackFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "weapon",
      title: (data2 == null ? void 0 : data2.title) || "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) || "",
      grit: (data2 == null ? void 0 : data2.grit) || 0,
      flat_bonus: (data2 == null ? void 0 : data2.flat_bonus) || 0,
      attack_type: (data2 == null ? void 0 : data2.attack_type) || AttackType.Melee,
      action: (data2 == null ? void 0 : data2.action) || null,
      is_smart: (data2 == null ? void 0 : data2.is_smart) || !1,
      attack_rolls: (data2 == null ? void 0 : data2.attack_rolls) || { roll: "", targeted: [] },
      attack_results: (data2 == null ? void 0 : data2.attack_results) || [],
      hit_results: (data2 == null ? void 0 : data2.hit_results) || [],
      reroll_data: (data2 == null ? void 0 : data2.reroll_data) || "",
      tags: (data2 == null ? void 0 : data2.tags) || []
    };
    if (super(uuid, initialData), !this.state.item)
      throw new TypeError("WeaponAttackFlow requires an Item, but none was provided");
  }
  async begin(data2) {
    return !this.state.item || !this.state.item.is_weapon() ? (console.log(`${lp$f} WeaponAttackFlow aborted - no weapon provided!`), !1) : await super.begin(data2);
  }
};
__name(_WeaponAttackFlow, "WeaponAttackFlow");
let WeaponAttackFlow = _WeaponAttackFlow;
WeaponAttackFlow.steps = [
  "initAttackData",
  "checkItemDestroyed",
  "checkWeaponLoaded",
  "checkItemLimited",
  "checkItemCharged",
  "setAttackTags",
  "setAttackEffects",
  "setAttackTargets",
  "showAttackHUD",
  "rollAttacks",
  "applySelfHeat",
  "updateItemAfterAction",
  "printAttackCard"
  // TODO: Start damage flow after attack
  // "applyDamage"
];
async function initAttackData(state, options) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j;
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  if (state.item) {
    if (state.data.title = (options == null ? void 0 : options.title) || state.data.title || state.item.name, state.item.is_mech_weapon()) {
      if (!state.actor.is_mech())
        return (_a19 = ui.notifications) == null || _a19.warn("Non-mech cannot fire a mech weapon!"), !1;
      if (!((_b = state.actor.system.pilot) != null && _b.value))
        return (_c = ui.notifications) == null || _c.warn("Cannot fire a weapon on a non-piloted mech!"), !1;
      let profile = state.item.system.active_profile;
      return state.data.attack_type = profile.type === WeaponType.Melee ? AttackType.Melee : AttackType.Ranged, state.data.attack_type === AttackType.Ranged && (state.data.flat_bonus = state.actor.system.bonuses.flat.ranged_attack || 0), state.data.grit = state.actor.system.grit, ((_e = (_d = state.actor.system.loadout.frame) == null ? void 0 : _d.value) == null ? void 0 : _e.system.lid) == "mf_deaths_head" && state.item.system.active_profile.range.some((r) => r.type !== RangeType.Threat) && (state.data.flat_bonus += 1), state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
        state.item,
        profile.all_tags,
        state.data.title,
        Array.from(game.user.targets),
        state.data.grit,
        state.data.flat_bonus
      ), !0;
    } else {
      if (state.item.is_mech_system())
        return state.actor.is_mech() ? (_g = state.actor.system.pilot) != null && _g.value ? (state.data.grit = state.actor.system.tech_attack, state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
          state.item,
          state.item.system.tags,
          state.data.title,
          Array.from(game.user.targets),
          state.data.grit,
          state.data.flat_bonus
        ), !0) : ((_h = ui.notifications) == null || _h.warn("Cannot use a system on a non-piloted mech!"), !1) : ((_f = ui.notifications) == null || _f.warn("Non-mech cannot use a mech system!"), !1);
      if (state.item.is_npc_feature()) {
        if (!state.actor.is_npc())
          return (_i = ui.notifications) == null || _i.warn("Non-NPC cannot fire an NPC weapon!"), !1;
        let tier_index = (state.item.system.tier_override || state.actor.system.tier) - 1, asWeapon = state.item.system;
        return state.data.attack_type = asWeapon.weapon_type === WeaponType.Melee ? AttackType.Melee : AttackType.Ranged, state.data.grit = asWeapon.attack_bonus[tier_index] ?? 0, state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
          state.item,
          asWeapon.tags,
          state.data.title,
          Array.from(game.user.targets),
          state.data.grit,
          state.data.flat_bonus,
          asWeapon.accuracy[tier_index] ?? 0
        ), !0;
      } else if (state.item.is_pilot_weapon())
        return state.actor.is_pilot() ? (state.data.attack_type = state.item.system.range.some((r) => ![RangeType.Threat, RangeType.Thrown].includes(r.type)) ? AttackType.Ranged : AttackType.Melee, state.item.system, state.data.grit = state.actor.system.grit, state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
          state.item,
          state.item.system.tags,
          state.data.title,
          Array.from(game.user.targets),
          state.data.grit,
          state.data.flat_bonus
        ), !0) : ((_j = ui.notifications) == null || _j.warn("Non-pilot cannot fire a pilot weapon!"), !1);
    }
    return ui.notifications.error(`Error in attack flow - ${state.item.name} is an invalid type!`), !1;
  } else {
    const isTech = LancerFlowState.isTechRoll(state.data), defaultTitle = isTech ? "TECH ATTACK" : "BASIC ATTACK";
    return state.data.title = (options == null ? void 0 : options.title) ?? defaultTitle, state.data.attack_type = isTech ? AttackType.Tech : AttackType.Melee, state.data.flat_bonus = 0, state.actor.is_pilot() || state.actor.is_mech() || state.actor.is_deployable() ? isTech ? state.data.grit = state.actor.system.tech_attack : state.data.grit = state.actor.system.grit : state.actor.is_npc() && (state.data.grit = isTech ? state.actor.system.sys : state.actor.system.tier), state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
      state.actor,
      [],
      state.data.title,
      Array.from(game.user.targets),
      state.data.grit,
      state.data.flat_bonus
    ), !0;
  }
}
__name(initAttackData, "initAttackData");
async function checkWeaponLoaded(state) {
  const { limited_loading, attacks } = game.settings.get(game.system.id, LANCER.setting_automation);
  return !limited_loading && attacks ? !0 : !state.item || !state.item.is_mech_weapon() && !state.item.is_pilot_weapon() && !state.item.is_npc_feature() ? !1 : state.item.isLoading() && !state.item.system.loaded ? (ui.notifications.warn(`Weapon ${state.item.name} is not loaded!`), !1) : !0;
}
__name(checkWeaponLoaded, "checkWeaponLoaded");
async function setAttackTags(state, options) {
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  if (!state.item)
    return !0;
  let success2 = !1;
  if (state.item.is_mech_weapon()) {
    let profile = state.item.system.active_profile;
    state.data.tags = profile.all_tags, success2 = !0;
  } else
    state.data.tags = state.item.getTags() ?? [], success2 = !0;
  if (success2 && state.data.tags) {
    const selfHeatTags = state.data.tags.filter((t) => t.is_selfheat);
    selfHeatTags && selfHeatTags.length && (state.data.self_heat = selfHeatTags[0].val);
    const smartTags = state.data.tags.filter((t) => t.is_smart);
    smartTags && smartTags.length && (state.data.is_smart = !0);
  }
  return success2;
}
__name(setAttackTags, "setAttackTags");
async function setAttackEffects(state, options) {
  var _a19, _b, _c;
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  if (!state.item)
    return !0;
  if (state.item.is_mech_weapon()) {
    let profile = state.item.system.active_profile;
    return state.data.effect = profile.effect, state.data.on_attack = profile.on_attack, state.data.on_hit = profile.on_hit, state.data.on_crit = profile.on_crit, !0;
  } else {
    if (state.item.is_mech_system())
      return state.data.effect = ((_a19 = state.data.action) == null ? void 0 : _a19.detail) ?? state.item.system.effect, !0;
    if (state.item.is_talent())
      return state.data.effect = ((_b = state.data.action) == null ? void 0 : _b.detail) ?? "", !0;
    if (state.item.is_frame())
      return state.data.effect = ((_c = state.data.action) == null ? void 0 : _c.detail) ?? state.item.system.core_system.active_effect, !0;
    if (state.item.is_npc_feature()) {
      let asWeapon = state.item.system;
      return state.data.effect = asWeapon.effect, state.data.on_hit = asWeapon.on_hit, !0;
    } else if (state.item.is_pilot_weapon())
      return state.data.effect = state.item.system.effect, !0;
  }
  return ui.notifications.error(`Error in attack flow - ${state.item.name} is an invalid type!`), !1;
}
__name(setAttackEffects, "setAttackEffects");
async function setAttackTargets(state, options) {
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  return !0;
}
__name(setAttackTargets, "setAttackTargets");
async function showAttackHUD(state, options) {
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  try {
    state.data.acc_diff = await openSlidingHud("attack", state.data.acc_diff), state.data.grit = state.data.acc_diff.base.grit, state.data.flat_bonus = state.data.acc_diff.base.flatBonus;
  } catch {
    return !1;
  }
  return !0;
}
__name(showAttackHUD, "showAttackHUD");
async function rollAttacks(state, options) {
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  if (!state.data.acc_diff)
    throw new TypeError("Accuracy/difficulty data missing!");
  if (state.data.attack_rolls = attackRolls(state.data.grit + state.data.flat_bonus, state.data.acc_diff), game.settings.get(game.system.id, LANCER.setting_automation).attacks && state.data.attack_rolls.targeted.length > 0) {
    let data2 = await Promise.all(
      state.data.attack_rolls.targeted.map(async (targetingData) => {
        var _a19, _b, _c;
        let target = targetingData.target, actor = target.actor, attack_roll = await new Roll(targetingData.roll).evaluate();
        attack_roll.dice.forEach((d) => d.options.rollOrder = 1);
        const attack_tt = await attack_roll.getTooltip();
        return targetingData.usedLockOn && game.user.isGM && ((_a19 = targetingData.target.actor) == null || _a19.effectHelper.removeActiveEffect("lockon")), {
          attack: { roll: attack_roll, tt: attack_tt },
          hit: {
            target,
            total: String(attack_roll.total).padStart(2, "0"),
            usedLockOn: !!targetingData.usedLockOn,
            hit: await checkForHit(((_b = state.data) == null ? void 0 : _b.is_smart) ?? !1, attack_roll, actor),
            crit: ((_c = state.data) == null ? void 0 : _c.attack_type) !== AttackType.Tech && (attack_roll.total || 0) >= 20
          }
        };
      })
    );
    return state.data.attack_results = data2.map((d) => d.attack), state.data.hit_results = data2.map((d) => d.hit), !0;
  } else {
    let attack_roll = await new Roll(state.data.attack_rolls.roll).evaluate();
    const attack_tt = await attack_roll.getTooltip();
    return state.data.attack_results = [{ roll: attack_roll, tt: attack_tt }], state.data.hit_results = [], !0;
  }
}
__name(rollAttacks, "rollAttacks");
async function clearTargets(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Flow state missing!");
  for (const t of ((_a19 = game.user) == null ? void 0 : _a19.targets) || [])
    t.setTarget(!1, { releaseOthers: !1 });
  return !0;
}
__name(clearTargets, "clearTargets");
async function printAttackCard(state, options) {
  var _a19, _b, _c;
  if (!state.data)
    throw new TypeError("Attack flow state missing!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/attack-card.hbs`, flags = {
    attackData: {
      origin: state.actor.id,
      attackerUuid: state.actor.uuid,
      attackerItemUuid: (_a19 = state.item) == null ? void 0 : _a19.uuid,
      targets: state.data.hit_results.map((hr) => ({
        id: hr.target.document.id,
        uuid: hr.target.document.uuid,
        setConditions: hr.usedLockOn ? { lockon: !hr.usedLockOn } : void 0,
        total: hr.total,
        hit: hr.hit,
        crit: hr.crit
      }))
    }
  };
  state.data.defense = state.data.is_smart ? "E-DEF" : "EVASION";
  const hitResultsWithRolls = [];
  for (const [index2, hitResult] of state.data.hit_results.entries())
    hitResultsWithRolls.push({
      ...hitResult,
      ...state.data.attack_results[index2]
    });
  const templateData = {
    ...state.data,
    hit_results: hitResultsWithRolls,
    item_uuid: (_b = state.item) == null ? void 0 : _b.uuid,
    profile: (_c = state.item) == null ? void 0 : _c.currentProfile()
  };
  return await renderTemplateStep(state.actor, template, templateData, flags), !0;
}
__name(printAttackCard, "printAttackCard");
Hooks.on("createChatMessage", async (cm, options, id) => {
  var _a19, _b;
  if (!((_b = (_a19 = game.users) == null ? void 0 : _a19.activeGM) != null && _b.isSelf))
    return;
  const atkData = cm.getFlag(game.system.id, "attackData");
  !atkData || !atkData.targets || atkData.targets.forEach((target) => {
    var _a20, _b2;
    const tokenActor = (_b2 = (_a20 = game.canvas.scene) == null ? void 0 : _a20.tokens.find((token) => token.uuid === target.uuid)) == null ? void 0 : _b2.actor;
    if (!tokenActor)
      return;
    const statusToRemove = [];
    for (const [stat, val] of Object.entries(target.setConditions || {}))
      val ? console.log(`(Not) Applying ${stat} to Token ${target.uuid}`) : (console.log(`Removing ${stat} from Token ${target.uuid}`), statusToRemove.push(stat));
    tokenActor == null || tokenActor.effectHelper.removeActiveEffects(statusToRemove);
  });
});
function registerTechAttackSteps(flowSteps) {
  flowSteps.set("initTechAttackData", initTechAttackData), flowSteps.set("printTechAttackCard", printTechAttackCard);
}
__name(registerTechAttackSteps, "registerTechAttackSteps");
const _TechAttackFlow = class _TechAttackFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "tech",
      title: (data2 == null ? void 0 : data2.title) || "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) || "",
      grit: (data2 == null ? void 0 : data2.grit) || 0,
      flat_bonus: (data2 == null ? void 0 : data2.flat_bonus) || 0,
      attack_type: (data2 == null ? void 0 : data2.attack_type) || AttackType.Tech,
      action: (data2 == null ? void 0 : data2.action) || null,
      is_smart: !0,
      // Tech attacks always target e-def
      invade: (data2 == null ? void 0 : data2.invade) || !1,
      effect: (data2 == null ? void 0 : data2.effect) || "",
      attack_rolls: (data2 == null ? void 0 : data2.attack_rolls) || { roll: "", targeted: [] },
      attack_results: (data2 == null ? void 0 : data2.attack_results) || [],
      hit_results: (data2 == null ? void 0 : data2.hit_results) || [],
      reroll_data: (data2 == null ? void 0 : data2.reroll_data) || "",
      tags: (data2 == null ? void 0 : data2.tags) || []
    };
    super(uuid, initialData);
  }
};
__name(_TechAttackFlow, "TechAttackFlow");
let TechAttackFlow = _TechAttackFlow;
TechAttackFlow.steps = [
  "initTechAttackData",
  "checkItemDestroyed",
  "checkItemLimited",
  "checkItemCharged",
  "setAttackTags",
  "setAttackEffects",
  "setAttackTargets",
  "showAttackHUD",
  "rollAttacks",
  "applySelfHeat",
  "updateItemAfterAction",
  "printTechAttackCard"
];
function commonMechTechAttackInit(state, options) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Tech attack flow state missing!");
  if (!state.item)
    throw new TypeError("Tech attack flow state missing item!");
  options != null && options.action_path && (state.data.action = resolveDotpath(state.item, options.action_path)), state.data.grit = state.actor.system.tech_attack, state.data.action && (state.data.title = state.data.action.name == ActivationType.Invade ? `INVADE // ${state.data.action.name}` : state.data.action.name, state.data.effect = state.data.action.detail), state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
    state.item,
    state.item.getTags() ?? [],
    state.data.title,
    Array.from(game.user.targets),
    state.data.grit,
    state.data.flat_bonus,
    // TODO: is there a bonus we can check for this type of effect?
    // Add 1 accuracy for all you goblins
    state.actor.is_mech() && ((_b = (_a19 = state.actor.system.loadout.frame) == null ? void 0 : _a19.value) == null ? void 0 : _b.system.lid) == "mf_goblin" ? 1 : 0
  );
}
__name(commonMechTechAttackInit, "commonMechTechAttackInit");
async function initTechAttackData(state, options) {
  var _a19, _b, _c, _d, _e, _f, _g;
  if (!state.data)
    throw new TypeError("Tech attack flow state missing!");
  if (state.item) {
    if (state.data.title = (options == null ? void 0 : options.title) || state.data.title || state.item.name, state.data.attack_type = AttackType.Tech, state.item.is_npc_feature()) {
      if (!state.actor.is_npc())
        return (_a19 = ui.notifications) == null || _a19.warn("Non-NPC cannot use an NPC system!"), !1;
      let tier_index = state.item.system.tier_override || state.actor.system.tier - 1, asTech = state.item.system, acc = asTech.accuracy ? asTech.accuracy[tier_index] ?? 0 : 0;
      return state.data.grit = asTech.attack_bonus ? asTech.attack_bonus[tier_index] ?? 0 : 0, state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
        state.item,
        asTech.tags,
        state.data.title,
        Array.from(game.user.targets),
        state.data.grit,
        state.data.flat_bonus,
        acc
      ), !0;
    } else {
      if (state.item.is_mech_system() || state.item.is_frame())
        return state.actor.is_mech() ? (_c = state.actor.system.pilot) != null && _c.value ? (commonMechTechAttackInit(state, options), state.data.tags = state.item.getTags() ?? void 0, !state.data.action && !state.data.effect && (state.item.is_mech_system() ? state.data.effect = state.item.system.effect : state.data.effect = state.item.system.core_system.active_effect), !0) : ((_d = ui.notifications) == null || _d.warn("Cannot use a system on a non-piloted mech!"), !1) : ((_b = ui.notifications) == null || _b.warn("Non-mech cannot use a mech system!"), !1);
      if (state.item.is_talent())
        return state.actor.is_pilot() ? (_f = state.actor.system.active_mech) != null && _f.value ? (state.actor = state.actor.system.active_mech.value, commonMechTechAttackInit(state, options), !0) : ((_g = ui.notifications) == null || _g.warn("Cannot use a talent without an active mech!"), !1) : ((_e = ui.notifications) == null || _e.warn("Non-pilot cannot use a pilot talent!"), !1);
    }
    return ui.notifications.error(`Error in tech attack flow - ${state.item.name} is an invalid type!`), !1;
  } else
    return !state.actor.is_mech() && !state.actor.is_npc() ? (ui.notifications.error("Error rolling tech attack macro (not a valid tech attacker)."), !1) : (state.data.title = (options == null ? void 0 : options.title) ?? "TECH ATTACK", state.data.attack_type = AttackType.Tech, state.data.flat_bonus = state.actor.system.bonuses.flat.tech_attack || 0, state.actor.is_pilot() || state.actor.is_mech() ? state.data.grit = state.actor.system.tech_attack : state.actor.is_npc() && (state.data.grit = state.actor.system.sys), state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(
      state.actor,
      [],
      state.data.title,
      Array.from(game.user.targets),
      state.data.grit,
      state.data.flat_bonus
    ), !0);
}
__name(initTechAttackData, "initTechAttackData");
async function printTechAttackCard(state, options) {
  var _a19, _b, _c;
  if (!state.data)
    throw new TypeError("Tech attack flow state missing!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/tech-attack-card.hbs`, flags = {
    attackData: {
      origin: state.actor.id,
      attackerUuid: state.actor.uuid,
      attackerItemUuid: (_a19 = state.item) == null ? void 0 : _a19.uuid,
      invade: state.data.invade,
      targets: state.data.hit_results.map((hr) => ({
        id: hr.target.document.id,
        uuid: hr.target.document.uuid,
        setConditions: hr.usedLockOn ? { lockon: !hr.usedLockOn } : void 0,
        total: hr.total,
        hit: hr.hit,
        crit: hr.crit
      }))
    }
  }, hitResultsWithRolls = [];
  for (const [index2, hitResult] of state.data.hit_results.entries())
    hitResultsWithRolls.push({
      ...hitResult,
      ...state.data.attack_results[index2]
    });
  const templateData = {
    ...state.data,
    hit_results: hitResultsWithRolls,
    item_uuid: (_b = state.item) == null ? void 0 : _b.uuid,
    profile: (_c = state.item) == null ? void 0 : _c.currentProfile()
  };
  return await renderTemplateStep(state.actor, template, templateData, flags), !0;
}
__name(printTechAttackCard, "printTechAttackCard");
const fields$v = foundry.data.fields, _PowerField = class _PowerField extends fields$v.SchemaField {
  constructor(options = {}) {
    super(
      {
        name: new fields$v.StringField({ nullable: !1 }),
        description: new fields$v.StringField({ nullable: !1 }),
        unlocked: new fields$v.BooleanField(),
        frequency: new fields$v.StringField({ required: !1, nullable: !0 }),
        uses: new fields$v.SchemaField(
          {
            min: new fields$v.NumberField({ integer: !0, initial: 0 }),
            max: new fields$v.NumberField({ integer: !0, initial: 0 }),
            value: new fields$v.NumberField({ integer: !0, initial: 0 })
          },
          { required: !1, nullable: !0 }
        ),
        veteran: new fields$v.BooleanField(),
        master: new fields$v.BooleanField(),
        prerequisite: new fields$v.StringField({ required: !1, nullable: !0 })
      },
      options
    );
  }
};
__name(_PowerField, "PowerField");
let PowerField = _PowerField;
function parsePowerUses(frequency) {
  if (!frequency)
    return null;
  const parts = frequency.split("/");
  if (parts.length !== 2)
    return null;
  try {
    return {
      min: 0,
      max: parseInt(parts[0]),
      value: parseInt(parts[0])
    };
  } catch {
    return null;
  }
}
__name(parsePowerUses, "parsePowerUses");
function fixupPowerUses(power) {
  let fixed = { ...power };
  if (!power.frequency)
    return fixed.uses = null, fixed;
  const parts = power.frequency.split("/");
  if (parts.length !== 2)
    return fixed.uses = null, fixed;
  if (power.uses || (fixed.uses = parsePowerUses(power.frequency)), !fixed.uses)
    return fixed;
  try {
    const max2 = parseInt(parts[0]);
    fixed.uses = {
      min: fixed.uses.min ?? 0,
      max: max2,
      value: fixed.uses.value ?? max2
    };
  } catch {
  }
  return fixed;
}
__name(fixupPowerUses, "fixupPowerUses");
function unpackPower(data2) {
  return {
    name: data2.name,
    description: data2.description,
    unlocked: !1,
    frequency: data2.frequency || null,
    uses: parsePowerUses(data2.frequency),
    veteran: data2.veteran || !1,
    master: data2.master || !1,
    prerequisite: data2.prerequisite || null
  };
}
__name(unpackPower, "unpackPower");
const lp$e = LANCER.log_prefix;
function registerBondPowerSteps(flowSteps) {
  flowSteps.set("initPowerData", initPowerData), flowSteps.set("updatePowerUses", updatePowerUses), flowSteps.set("printPowerCard", printPowerCard);
}
__name(registerBondPowerSteps, "registerBondPowerSteps");
const _BondPowerFlow = class _BondPowerFlow extends Flow {
  constructor(uuid, data2) {
    if ((data2 == null ? void 0 : data2.powerIndex) === void 0 || (data2 == null ? void 0 : data2.powerIndex) === null || typeof (data2 == null ? void 0 : data2.powerIndex) != "number" || (data2 == null ? void 0 : data2.powerIndex) < 0)
      throw new Error("Bond Power Flow requires a valid power index to be provided in data!");
    const initialData = {
      title: (data2 == null ? void 0 : data2.title) ?? "",
      powerIndex: data2 == null ? void 0 : data2.powerIndex,
      description: (data2 == null ? void 0 : data2.description) ?? ""
    };
    super(uuid, initialData);
  }
  async begin(data2) {
    return !this.state.item || !this.state.item.is_bond() ? (console.log(`${lp$e} BondPowerFlow aborted - no bond item provided!`), !1) : (!this.state.data || this.state.data.powerIndex < 0 || this.state.data.powerIndex >= this.state.item.system.powers.length) && (!data2 || data2.powerIndex < 0 || data2.powerIndex >= this.state.item.system.powers.length) ? (console.log(`${lp$e} BondPowerFlow aborted - invalid power index provided!`), !1) : await super.begin(data2);
  }
};
__name(_BondPowerFlow, "BondPowerFlow");
let BondPowerFlow = _BondPowerFlow;
BondPowerFlow.steps = ["initPowerData", "updatePowerUses", "printPowerCard"];
async function initPowerData(state, options) {
  if (!state.data)
    throw new TypeError("Bond Power flow state missing!");
  if (!state.item || !state.item.is_bond())
    throw new TypeError("Bond Power flow item is not a bond!");
  state.data.powerIndex = (options == null ? void 0 : options.powerIndex) ?? state.data.powerIndex;
  const power = state.item.system.powers[state.data.powerIndex];
  return state.data.title = (options == null ? void 0 : options.name) || power.name || state.data.title, state.data.description = (options == null ? void 0 : options.description) || power.description || state.data.description, !0;
}
__name(initPowerData, "initPowerData");
async function updatePowerUses(state, options) {
  if (!state.data)
    throw new TypeError("Bond Power flow state missing!");
  if (!state.item || !state.item.is_bond())
    throw new TypeError("Bond Power flow item is not a bond!");
  if (state.item && game.settings.get(game.system.id, LANCER.setting_automation).limited_loading) {
    const power = state.item.system.powers[state.data.powerIndex];
    if (power.uses) {
      let item_changes = { [`system.powers.${state.data.powerIndex}.uses.value`]: power.uses.value - 1 };
      await state.item.update(item_changes);
    }
  }
  return !0;
}
__name(updatePowerUses, "updatePowerUses");
async function printPowerCard(state, options) {
  if (!state.data)
    throw new TypeError("Bond Power flow state missing!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/generic-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printPowerCard, "printPowerCard");
function handleDocDropping(items, drop_handler, allow_drop, hover_handler) {
  items.each((_, _item) => {
    let item = $(_item);
    item.on("dragover", (event) => {
      if (!GlobalDragPreview)
        return !0;
      if (!allow_drop || allow_drop(GlobalDragPreview, item, event))
        return event.preventDefault(), !1;
    }), item.on("dragenter", (event) => GlobalDragPreview && (!allow_drop || allow_drop(GlobalDragPreview, item, event)) ? (event.preventDefault(), hover_handler && hover_handler("enter", GlobalDragPreview, item, event), !1) : !0), hover_handler && item.on("dragleave", (event) => {
      GlobalDragPreview && (!allow_drop || allow_drop(GlobalDragPreview, item, event)) && hover_handler("leave", GlobalDragPreview, item, event);
    }), item.on("drop", (event) => {
      var _a19, _b;
      if ((_b = (_a19 = event.originalEvent) == null ? void 0 : _a19.dataTransfer) != null && _b.getData("text/plain"))
        if (GlobalDragPreview) {
          let rdd = GlobalDragPreview;
          (!allow_drop || allow_drop(rdd, item, event)) && (event.stopImmediatePropagation(), event.preventDefault(), drop_handler(rdd, item, event));
        } else
          event.stopImmediatePropagation(), event.preventDefault(), resolveNativeDrop(event.originalEvent.dataTransfer.getData("text/plain")).then((rdd) => {
            rdd && (!allow_drop || allow_drop(rdd, item, event)) && drop_handler(rdd, item, event);
          });
    });
  });
}
__name(handleDocDropping, "handleDocDropping");
function handleDragging(items, data_transfer_func, start_stop_func) {
  typeof items == "string" && (items = $(items)), items.prop("draggable", !0), items.each((_, _item) => {
    let item = $(_item);
    item.on("dragstart", (event) => {
      event.originalEvent.dataTransfer.clearData(), event.originalEvent.dataTransfer.setData("text/plain", data_transfer_func(item, event)), event.stopPropagation(), event.stopImmediatePropagation(), start_stop_func && start_stop_func("start", item, event);
    }), item.on("dragend", (event) => {
      start_stop_func && start_stop_func("stop", item, event);
    });
  });
}
__name(handleDragging, "handleDragging");
var DroppableFlowType = /* @__PURE__ */ ((DroppableFlowType2) => (DroppableFlowType2.BASIC = "lancer-flow-button", DroppableFlowType2.STAT = "roll-stat", DroppableFlowType2.ATTACK = "roll-attack", DroppableFlowType2.DAMAGE = "roll-damage", DroppableFlowType2.TECH_ATTACK = "roll-tech", DroppableFlowType2.CHAT = "chat-flow-button", DroppableFlowType2.SKILL = "skill-flow", DroppableFlowType2.BOND_POWER = "bond-power-flow", DroppableFlowType2.EFFECT = "effect-flow", DroppableFlowType2.ACTIVATION = "activation-flow", DroppableFlowType2.CORE_ACTIVE = "core_system.activation-flow", DroppableFlowType2))(DroppableFlowType || {});
async function resolveNativeDrop(drop) {
  if (typeof drop == "string" && (drop = safe_json_parse(drop)), drop) {
    if (drop.type == "Actor") {
      let document2 = await LancerActor.fromUuid(drop.uuid);
      return document2 ? {
        type: "Actor",
        document: document2
      } : null;
    } else if (drop.type == "Item") {
      let document2 = await LancerItem.fromUuid(drop.uuid);
      return document2 ? {
        type: "Item",
        document: document2
      } : null;
    } else if (drop.type == "JournalEntry") {
      let document2 = await JournalEntry.fromDropData(drop);
      return document2 ? {
        type: "JournalEntry",
        document: document2
      } : null;
    } else if (drop.type == "Macro") {
      let document2 = await Macro.fromDropData(drop);
      return document2 ? {
        type: "Macro",
        document: document2
      } : null;
    }
  } else {
    let document2 = await fromUuid(drop);
    if (!document2)
      return null;
    if (document2 instanceof LancerActor)
      return {
        type: "Actor",
        document: document2
      };
    if (document2 instanceof LancerItem)
      return {
        type: "Item",
        document: document2
      };
    if (document2 instanceof Macro)
      return {
        type: "Macro",
        document: document2
      };
    if (document2 instanceof JournalEntry)
      return {
        type: "JournalEntry",
        document: document2
      };
  }
  return null;
}
__name(resolveNativeDrop, "resolveNativeDrop");
let GlobalDragPreview = null;
function dragging_class(for_type) {
  return `dragging-${for_type}`;
}
__name(dragging_class, "dragging_class");
function setGlobalDrag(to) {
  if (((GlobalDragPreview == null ? void 0 : GlobalDragPreview.type) == "Actor" || (GlobalDragPreview == null ? void 0 : GlobalDragPreview.type) == "Item") && $("body").removeClass(dragging_class(GlobalDragPreview.document.type)), to instanceof LancerActor)
    GlobalDragPreview = {
      document: to,
      type: "Actor"
    };
  else if (to instanceof LancerItem)
    GlobalDragPreview = {
      document: to,
      type: "Item"
    };
  else if (to instanceof Macro)
    GlobalDragPreview = {
      document: to,
      type: "Macro"
    };
  else if (to instanceof Scene)
    GlobalDragPreview = {
      document: to,
      type: "Scene"
    };
  else if (to == null) {
    GlobalDragPreview = null;
    return;
  }
  ((GlobalDragPreview == null ? void 0 : GlobalDragPreview.type) == "Actor" || (GlobalDragPreview == null ? void 0 : GlobalDragPreview.type) == "Item") && $("body").addClass(dragging_class(GlobalDragPreview.document.type));
}
__name(setGlobalDrag, "setGlobalDrag");
function applyGlobalDragListeners() {
  let body = document.getElementsByTagName("body")[0], cancel_token = { canceled: !1 };
  body.addEventListener(
    "dragstart",
    (evt) => {
      var _a19, _b, _c;
      let target = evt.target, uuid = "";
      if ((_a19 = target == null ? void 0 : target.dataset) != null && _a19.uuid)
        uuid = target.dataset.uuid;
      else if ((_b = target == null ? void 0 : target.dataset) != null && _b.documentId) {
        let sbt = $(target).parents(".sidebar-tab")[0];
        if ((_c = sbt == null ? void 0 : sbt.dataset) != null && _c.tab) {
          let tab = sbt.dataset.tab;
          uuid = `${tab.charAt(0).capitalize()}${tab.slice(1, tab.length - 1)}.${target.dataset.documentId}`;
        } else {
          let cd = $(target).parents(".compendium.directory")[0];
          cd && (uuid = `Compendium.${cd.dataset.pack}.${target.dataset.documentId}`);
        }
      } else
        return;
      let cancel_token_copy = cancel_token;
      fromUuid(uuid).then(async (doc) => {
        await new Promise((resolve) => setTimeout(resolve, 50)), cancel_token_copy.canceled || setGlobalDrag(doc);
      });
    },
    {
      capture: !0,
      // We don't want people preventing us from seeing this!
      passive: !0
      // Improves performance. We only want to watch
    }
  );
  const endListener = /* @__PURE__ */ __name(() => {
    setGlobalDrag(null), cancel_token.canceled = !0, cancel_token = { canceled: !1 };
  }, "endListener");
  body.addEventListener("dragend", endListener, {
    capture: !0,
    // Same as above
    passive: !0
  }), body.addEventListener("drop", endListener, {
    capture: !0,
    // Same as above
    passive: !0
  });
}
__name(applyGlobalDragListeners, "applyGlobalDragListeners");
const _TargetedEditForm = class _TargetedEditForm extends FormApplication {
  constructor(target, value_path, options = {}, resolve_func) {
    super(
      {
        hasPerm: () => !0
      },
      options
    ), this.target = target, this.value_path = value_path, this.value = resolveDotpath(target, value_path), this.resolve = resolve_func;
  }
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html);
  }
  // Enables summoning of this form
  static handle(html, selector, root_doc) {
    html.find(selector).on("click", async (evt) => {
      evt.stopPropagation();
      const path = evt.currentTarget.dataset.path;
      if (path) {
        let dd = drilldownDocument(root_doc, path);
        return this.edit(dd.sub_doc, dd.sub_path);
      }
    });
  }
  /* -------------------------------------------- */
  // Override this to set child
  /** @override */
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      width: 400,
      height: "auto",
      classes: ["lancer", "targeted-form-editor"],
      submitOnChange: !1,
      submitOnClose: !0,
      closeOnSubmit: !0
      // title and template should be provided by child
    };
  }
  // Override this to add any auxillary data
  /** @override
   * Expose our data
   */
  getData() {
    return {
      ...super.getData(),
      value: this.value,
      path: this.value_path
    };
  }
  // Override this - this should return the object that should be updated at path
  fixupForm(form_data) {
    return form_data;
  }
  /** @override */
  async _updateObject(event, form_data) {
    var _a19;
    if (((_a19 = event.submitter) == null ? void 0 : _a19.dataset.button) == "cancel")
      return;
    form_data = this.fixupForm(form_data);
    let new_result = {};
    for (let [k, v] of Object.entries(form_data))
      new_result[`${this.value_path}.${k}`] = v;
    return this.target.update(new_result).then(this.resolve);
  }
  /* -------------------------------------------- */
  /**
   * A helper constructor function which displays the bonus editor and returns a Promise once it's
   * workflow has been resolved.
   * @param doc Document to edit
   * @param path Where on the document the tag lies
   * @returns
   */
  static async edit(doc, path) {
    return new Promise((resolve, _reject) => {
      new this(doc, path, {}, resolve).render(!0);
    });
  }
};
__name(_TargetedEditForm, "TargetedEditForm");
let TargetedEditForm = _TargetedEditForm;
const _TagEditForm = class _TagEditForm extends TargetedEditForm {
  /** @override */
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      template: `systems/${game.system.id}/templates/window/tag.hbs`,
      classes: ["lancer", "tag-editor"],
      title: "Tag Editing",
      submitOnClose: !1
    };
  }
  getData() {
    let tc = game.settings.get(game.system.id, LANCER.setting_tag_config), lid_options = {};
    return Object.entries(tc).forEach((tag) => lid_options[tag[1].name] = tag[0]), {
      ...super.getData(),
      lid: super.getData().value.lid,
      // Compat thing for std-select
      lid_options
    };
  }
};
__name(_TagEditForm, "TagEditForm");
let TagEditForm = _TagEditForm;
function attachTagTooltips(html) {
  html.find(".compact-tag").each((_, el) => {
    tippy$1(el, {
      placement: "top",
      theme: "lancer-large"
    });
  });
}
__name(attachTagTooltips, "attachTagTooltips");
function handleTagEditButtons(html, doc) {
  html.find(".tag-edit-button").on("click", (ev) => {
    var _a19;
    ev.stopPropagation();
    const path = (_a19 = ev.currentTarget) == null ? void 0 : _a19.dataset.path;
    if (!path) {
      ui.notifications.error("Tag edit button missing data-path attribute");
      return;
    }
    TagEditForm.edit(doc, path);
  });
}
__name(handleTagEditButtons, "handleTagEditButtons");
function compactTag(tagPath, tag, editable = !0) {
  return tagView(tagPath, tag, !0, editable);
}
__name(compactTag, "compactTag");
function largeTag(tagPath, tag, editable = !0) {
  return tagView(tagPath, tag, !1, editable);
}
__name(largeTag, "largeTag");
function tagView(tagPath, tag, compact = !0, editable = !0) {
  let interpolatedName = tag.name.replace("{VAL}", `${tag.val ?? "?"}`), interpolatedDescription = tag.description.replace("{VAL}", `${tag.val ?? "?"}`) ?? "";
  return `<div
    class="${editable ? "editable-tag-instance" : ""} ${compact ? "compact-tag flexrow" : "large-tag"}"
    ${editable ? `data-path="${tagPath}"` : ""}
    ${compact ? `data-tippy-content="${interpolatedDescription}"` : ""}
  >
    ${compact ? `
    <i class="mdi mdi-label i--s i--light"></i>
    <span style="margin: 3px;" >${interpolatedName}</span>` : `
    <div class="tag-header flexrow">
      <i class="mdi mdi-label i--s i--light"></i>
      <span style="margin: 3px;" >${interpolatedName}</span>
      ${editable ? `
      <div class="tag-controls">
        <a class="tag-edit-button fas fa-edit" data-path="${tagPath}"></a>
        <a class="gen-control fas fa-trash" data-action="splice" data-path="${tagPath}"></a>
      </div>` : ""}
    </div>
    <div class="tag-description">${interpolatedDescription}</div>`}
  </div>`;
}
__name(tagView, "tagView");
function compactTagListHBS(tagArrayPath, options) {
  let tags = options.hash.tags ?? resolveHelperDotpath(options, tagArrayPath) ?? [];
  return compactTagList(tags, tagArrayPath, { editable: resolveHelperDotpath(options, "editable", !1, !0) });
}
__name(compactTagListHBS, "compactTagListHBS");
function largeTagListHBS(tagArrayPath, options) {
  let tags = options.hash.tags ?? resolveHelperDotpath(options, tagArrayPath) ?? [];
  return largeTagList(tags, tagArrayPath, { editable: resolveHelperDotpath(options, "editable", !1, !0) });
}
__name(largeTagListHBS, "largeTagListHBS");
function compactTagList(tags, tagArrayPath, options) {
  return tagList(tags, tagArrayPath, { compact: !0, ...options });
}
__name(compactTagList, "compactTagList");
function largeTagList(tags, tagArrayPath, options) {
  return tagList(tags, tagArrayPath, { compact: !1, ...options });
}
__name(largeTagList, "largeTagList");
function tagList(tags, tagArrayPath, options) {
  const compact = (options == null ? void 0 : options.compact) ?? !0;
  let processedTags = [];
  for (let i = 0; i < tags.length; i++) {
    let tag = tags[i];
    if (!tag.hidden) {
      let affixedPath = `${tagArrayPath}.${i}`;
      processedTags.push(
        compact ? compactTag(affixedPath, tag, options == null ? void 0 : options.editable) : largeTag(affixedPath, tag, options == null ? void 0 : options.editable)
      );
    }
  }
  return options != null && options.editable ? `<div class="${compact ? "compact" : "large"}-tag-row tag-list-append" data-path="${tagArrayPath}">
      ${processedTags.join("")}
    </div>` : processedTags.length ? `<div class="${compact ? "compact" : "large"}-tag-row">
      ${processedTags.join("")}
    </div>` : "";
}
__name(tagList, "tagList");
function itemEditTags(path, header, options) {
  return `
  <div class="card full">
    <div class="lancer-header lancer-primary major">
      <span>${header}</span>
      ${inc_if(
    `<a class="gen-control fas fa-plus" data-action="append" data-path="${path}" data-action-value="(struct)tag"></a>`,
    resolveHelperDotpath(options, "editable", !1, !0)
  )}
    </div>
    ${largeTagListHBS(path, options)}
  </div>`;
}
__name(itemEditTags, "itemEditTags");
const _CollapseHandler = class _CollapseHandler {
  constructor() {
    this.state = /* @__PURE__ */ new Map();
  }
  // Toggle the specified collapsible, returning new state
  toggle(id) {
    let curr = this.state.get(id) ?? !1;
    return this.state.set(id, !curr), !curr;
  }
  // Get whether a state should be expanded
  get(id) {
    return this.state.get(id) ?? !1;
  }
};
__name(_CollapseHandler, "CollapseHandler");
let CollapseHandler = _CollapseHandler;
function collapseID(collapse, doc, no_inc) {
  let doc_id;
  doc instanceof foundry.abstract.Document ? doc_id = doc.id ?? "ephem" : typeof doc == "string" ? doc_id = doc : doc_id = "uncat", collapse[doc_id] == null && (collapse[doc_id] = 0);
  let collapse_index;
  return no_inc ? collapse_index = collapse[doc_id] : collapse_index = ++collapse[doc_id], `${doc_id}_${collapse_index}`;
}
__name(collapseID, "collapseID");
function collapseButton(collapse, doc, no_increment = !1) {
  return collapse ? `<i class="mdi mdi-unfold-less-horizontal collapse-trigger collapse-icon" data-collapse-id="${collapseID(
    collapse,
    doc,
    no_increment
  )}"> </i>` : "";
}
__name(collapseButton, "collapseButton");
function collapseParam(collapse, doc, no_increment = !1) {
  return collapse ? `data-collapse-id="${collapseID(collapse, doc, no_increment)}"` : "";
}
__name(collapseParam, "collapseParam");
function applyCollapseListeners(html) {
  html.find(".collapse-trigger").on("click", handleCollapse);
}
__name(applyCollapseListeners, "applyCollapseListeners");
const handleCollapse = /* @__PURE__ */ __name((ev) => {
  ev.stopPropagation();
  let prefix = "lancer-collapse", id = ev.currentTarget.getAttribute("data-collapse-id"), collapse = document.querySelector(`.collapse[data-collapse-id="${id}"]`);
  collapse != null && collapse.classList.contains("collapsed") ? (collapse.classList.remove("collapsed"), sessionStorage.setItem(`${prefix}-${id}`, "opened")) : (collapse == null || collapse.classList.add("collapsed"), sessionStorage.setItem(`${prefix}-${id}`, "closed"));
}, "handleCollapse");
function initializeCollapses(html) {
  html.find(".collapse").each((_index, section) => {
    let id = section.getAttribute("data-collapse-id");
    if (id) {
      let ssv = sessionStorage.getItem("lancer-collapse-" + id);
      ssv == "opened" ? section.classList.remove("collapsed") : ssv == "closed" && section.classList.add("collapsed");
    }
  });
}
__name(initializeCollapses, "initializeCollapses");
function mechSystemViewHBS(system_path, helperOptions, options) {
  resolveHelperDotpath(helperOptions, "collapse");
  let doc = resolveHelperDotpath(helperOptions, system_path);
  return doc ? mechSystemView(doc, system_path, options) : "";
}
__name(mechSystemViewHBS, "mechSystemViewHBS");
function mechSystemView(doc, system_path, options) {
  system_path = system_path ?? `system.systems.${doc.uuid}`;
  let icon, sp, contextMenu, actions, deployables, eff;
  if ([SystemType.Deployable, SystemType.Drone, SystemType.Mod, SystemType.System, SystemType.Tech].includes(doc.system.type) ? doc.system.type === SystemType.Tech ? icon = `cci cci-${slugify(doc.system.type, "-")}-quick i--m` : icon = `cci cci-${slugify(doc.system.type, "-")} i--m` : icon = "cci cci-system i--m", sp = spDisplay(doc.system.sp ?? 0), contextMenu = `<a class="lancer-context-menu" data-path="${system_path}"">
    <i class="fas fa-ellipsis-v"></i>
  </a>`, doc.system.effect && (eff = effectBox("EFFECT", doc.system.effect, { flow: !(options != null && options.nonInteractive) || !1 })), doc.system.actions.length && (actions = buildActionArrayHTML(doc, "system.actions", options)), doc.system.deployables.length && doc.actor) {
    const deployablesMap = lookupOwnedDeployables(doc.actor, doc.system.deployables);
    deployables = buildDeployablesArray(doc, deployablesMap, options);
  }
  let limited = "";
  return doc.isLimited() && (limited = `<div class="uses-wrapper">${limitedUsesIndicator(doc, system_path + ".value", options)}</div>`), `<${options != null && options.div ? "div" : "li"}
    class="ref set card clipped-top lancer-system lancer-border-system ${doc.system.type === SystemType.Tech ? "tech-item" : ""}"
    data-item-id="${doc.id}"
    ${ref_params(doc)}
    style="margin: 0.3em;"
  >
    <div class="lancer-header lancer-system ${doc.system.destroyed ? "destroyed" : ""}" style="grid-area: 1/1/2/3; display: flex">
      <i class="${doc.system.destroyed ? "mdi mdi-cog" : icon}"> </i>
      ${options != null && options.nonInteractive ? "" : '<a class="chat-flow-button"><i class="mdi mdi-message"></i></a>'}
      <span class="minor grow">${doc.name}</span>
      ${options != null && options.nonInteractive ? "" : collapseButton(null, doc)}
      <div class="ref-controls">
        ${options != null && options.nonInteractive ? "" : contextMenu}
      </div>
    </div>
    <div class="collapse" ${collapseParam(null, doc, !0)} style="padding: 0.5em">
      ${limited}
      ${eff || ""}
      ${actions || ""}
      ${deployables || ""}
      <div class="${options != null && options.vertical ? "flexcol" : "flexrow"}">
        ${sp}
        ${compactTagList(doc.system.tags, system_path + ".system.tags", {
    editable: !((options == null ? void 0 : options.nonInteractive) ?? !1)
  })}
      </div>
    </div>
  </${options != null && options.div ? "div" : "li"}>`;
}
__name(mechSystemView, "mechSystemView");
function weaponMount(mount_path, options) {
  var _a19, _b, _c, _d;
  let mech = resolveHelperDotpath(options, "actor"), mount = resolveHelperDotpath(options, mount_path);
  if (mount.bracing)
    return ` 
    <div class="mount card" >
      <div class="lancer-header lancer-primary mount-type-ctx-root" data-path="${mount_path}">
        <span>${mount.type} Weapon Mount</span>
        <a class="gen-control fas fa-trash" data-action="splice" data-path="${mount_path}"></a>
        <a class="reset-weapon-mount-button fas fa-redo" data-path="${mount_path}"></a>
      </div>
      <div class="lancer-body">
        <span class="major">LOCKED: BRACING</span>
      </div>
    </div>`;
  let slots = mount.slots.map(
    (slot, index2) => mechLoadoutWeaponSlot(
      `${mount_path}.slots.${index2}.weapon.value`,
      `${mount_path}.slots.${index2}.mod.value`,
      slot.size,
      options
    )
  );
  mount.type === "Flex" && mount.slots.length === 1 && ((_b = (_a19 = mount.slots[0].weapon) == null ? void 0 : _a19.value) == null ? void 0 : _b.system.size) === WeaponSize.Aux && slots.push(
    mechLoadoutWeaponSlot(
      `${mount_path}.slots.1.weapon.value`,
      `${mount_path}.slots.1.mod.value`,
      FittingSize.Auxiliary,
      options
    )
  );
  let err = mech.loadoutHelper.validateMount(mount) ?? "";
  return !err && mount.type === "Flex" && ((_d = (_c = mount.slots[0].weapon) == null ? void 0 : _c.value) == null ? void 0 : _d.system.size) === "Main" && (slots = [slots[0]]), ` 
    <div class="mount card" >
      <div class="lancer-header lancer-primary mount-type-ctx-root" data-path="${mount_path}">
        <span>${mount.type} Weapon Mount</span>
        <a class="gen-control fas fa-trash" data-action="splice" data-path="${mount_path}"></a>
        <a class="reset-weapon-mount-button fas fa-redo" data-path="${mount_path}"></a>
      </div>
      ${inc_if(`<span class="lancer-header lancer-primary error">${err.toUpperCase()}</span>`, err)}
      <div class="lancer-body">
        ${slots.join("")}
      </div>
    </div>`;
}
__name(weaponMount, "weaponMount");
function allWeaponMountView(loadout_path, options) {
  const weapon_mounts = resolveHelperDotpath(options, loadout_path).weapon_mounts.map(
    (_wep, index2) => weaponMount(`${loadout_path}.weapon_mounts.${index2}`, options)
  );
  return `
    <div class="lancer-header lancer-dark-gray loadout-category submajor">
      <i class="mdi mdi-unfold-less-horizontal collapse-trigger collapse-icon" data-collapse-id="weapons"></i>   
      <span>MOUNTED WEAPONS</span>
      <a class="gen-control fas fa-plus" data-action="append" data-path="${loadout_path}.weapon_mounts" data-action-value="(struct)wep_mount"></a>
      <a class="reset-all-weapon-mounts-button fas fa-redo" data-path="${loadout_path}.weapon_mounts"></a>
    </div>
    <div class="wraprow double collapse" data-collapse-id="weapons" style="margin-bottom: 0.75em">
      ${weapon_mounts.join("")}
    </div>
    `;
}
__name(allWeaponMountView, "allWeaponMountView");
function allMechSystemsView(loadout_path, options) {
  let loadout = resolveHelperDotpath(options, loadout_path);
  const system_views = loadout.systems.map(
    (_sys, index2) => mechSystemViewHBS(`${loadout_path}.systems.${index2}.value`, options)
  );
  return `
    <div class="lancer-header lancer-dark-gray loadout-category submajor">
      <i class="mdi mdi-unfold-less-horizontal collapse-trigger collapse-icon" data-collapse-id="systems"></i>    
      <span>MOUNTED SYSTEMS</span>
      <span style="flex-grow: 0">
        <i class="cci cci-system-point i--m"></i>
        ${loadout.sp.value} / ${loadout.sp.max} SP USED
      </span>
    </div>
    <div class="flexcol collapse" data-collapse-id="systems">
      ${system_views.join("")}
    </div>
    `;
}
__name(allMechSystemsView, "allMechSystemsView");
function mechLoadout(options) {
  const loadout_path = "system.loadout";
  return `
    <div class="flexcol">
        ${allWeaponMountView(loadout_path, options)}
        ${allMechSystemsView(loadout_path, options)}
    </div>`;
}
__name(mechLoadout, "mechLoadout");
function pilotSlot(data_path, options) {
  var _a19;
  let pilot;
  if (options.hash.value)
    pilot = options.hash.value;
  else if (pilot = resolveHelperDotpath(options, data_path), !pilot)
    return simple_ref_slot(data_path, [EntryType.PILOT], options);
  return `<div class="pilot-summary">
    <img class="ref set pilot click-open" 
         ${ref_params(pilot, data_path)} 
         data-accept-types="${EntryType.PILOT}"
         style="height: 100%" src="${pilot.img || "systems/lancer/assets/icons/pilot.svg"}"/>
    <div class="lancer-header lancer-primary license-level">
      <span>LL${((_a19 = pilot.system) == null ? void 0 : _a19.level) || "[--]"}</span>
    </div>
</div>`;
}
__name(pilotSlot, "pilotSlot");
function frameView(frame_path, core_energy, options) {
  let frame = resolveHelperDotpath(options, frame_path);
  return frame ? `
    <div class="card mech-frame ${ref_params(frame)}">
      <span class="lancer-header ${manufacturerStyle(frame.system.manufacturer)} submajor clipped-top">
        ${frame.system.manufacturer} ${frame.name}
      </span>
      <div class="wraprow double">
        <div class="frame-traits flexcol">
          ${frameTraits(frame_path, options)}
        </div>
        ${frame.system.core_system ? buildCoreSysHTML(frame_path, core_energy, options) : ""}
      </div>
    </div>
    ` : simple_ref_slot(frame_path, [EntryType.FRAME], options);
}
__name(frameView, "frameView");
function buildCoreSysHTML(frame_path, core_energy, options) {
  let frame = resolveHelperDotpath(options, frame_path), tags = compactTagListHBS(`${frame_path}.core_system.tags`, options), core = frame.system.core_system, passive2 = "";
  (core.passive_effect !== "" || core.passive_actions.length > 0 || core.passive_bonuses.length > 0) && (passive2 = `<div class="frame-passive">${framePassive(frame)}</div>`);
  let deployables = "";
  core.deployables.length && (deployables = buildDeployablesArrayHBS(frame, "system.core_system.deployables", options, { vertical: !0 }));
  const mfrBorder = manufacturerStyle(frame.system.manufacturer, !0), mfrStyle = manufacturerStyle(frame.system.manufacturer);
  return `<div class="core-wrapper ${mfrBorder} frame-coresys card clipped-top" style="padding: 0;">
    <div class="lancer-header ${mfrStyle} coresys-title">
      <span>${core.name}</span><span> // </span><span>CORE</span>
      <i 
        class="mdi mdi-unfold-less-horizontal collapse-trigger collapse-icon" 
        data-collapse-id="${frame.id}_core" > 
      </i>
    </div>
    <div class="collapse" data-collapse-id="${frame.id}_core">
      <div class="frame-active">${frameActive(frame_path, core_energy, options)}</div>
      ${passive2}
      ${deployables}
      ${tags}
    </div>
  </div>`;
}
__name(buildCoreSysHTML, "buildCoreSysHTML");
function frameTraits(frame_path, options) {
  let frame = resolveHelperDotpath(options, frame_path);
  return frame.system.traits.map((trait, index2) => {
    let actionHTML = buildActionArrayHTML(frame, `system.traits.${index2}.actions`), depHTML = buildDeployablesArrayHBS(frame, `system.traits.${index2}.deployables`, options, { vertical: !0 });
    return `<div class="frame-trait clipped-top">
    <div
      class="lancer-header ${manufacturerStyle(frame.system.manufacturer)} submajor frame-trait-header"
    >
      <a class="chat-flow-button" data-uuid="${frame.uuid}" data-type="trait" data-index="${index2}">
        <i class="mdi mdi-message"></i>
      </a>
      <span class="minor grow">${trait.name}</span>
    </div>
    <div class="lancer-body">
      <div class="effect-text">${trait.description || defaultPlaceholder}</div>
      ${actionHTML || ""}
      ${depHTML || ""}
    </div>
  </div>`;
  }).join("");
}
__name(frameTraits, "frameTraits");
function frameActive(frame_path, core_energy, options) {
  const frame = resolveHelperDotpath(options, frame_path), core = frame.system.core_system, activeName = core.active_actions.length ? core.active_actions[0].name : core.name, actionHTML = buildActionArrayHTML(frame, "system.core_system.active_actions", {
    hideChip: core.active_actions.length <= 1
  }), depHTML = buildDeployablesArrayHBS(frame, "system.core.deployables", options, { vertical: !0 }), theme = core_energy ? manufacturerStyle(frame.system.manufacturer) : "lancer-light-gray", activationClass = `activation-${slugify(core.activation, "-")}`, activationThemeClass = core_energy ? activationStyle(core.activation) : "lancer-light-gray";
  return `
  <div class="core-active-wrapper clipped-top lancer-border-bonus">
    <div class="lancer-header ${theme} clipped-top submajor">
      <div class="grow">
        <span>${core.active_name}</span><span> // </span><span>ACTIVE</span>
      </div>
    </div>
    <div class="lancer-body">
      <div class="effect-text">
        ${core.active_effect ?? ""}
      </div>
      ${actionHTML || ""}
      ${depHTML || ""}
      <div class="core-active-activate">
        <a
          class="activation-chip activation-flow lancer-button ${activationClass} ${activationThemeClass}"
          data-uuid="${frame.uuid}" data-path="system.core_system"
        >
          <i class="cci cci-corebonus i--l"></i>
          <b class="active-name">${activeName.toUpperCase()}</b>
          <i class="${activationIcon(core.activation)} i--l"></i>
        </a>
      </div>
    </div>
  </div>
  `;
}
__name(frameActive, "frameActive");
function framePassive(frame) {
  let core = frame.system.core_system, actionHTML = buildActionArrayHTML(frame, "system.core_system.passive_actions");
  return `
  <div class="core-passive-wrapper clipped-top lancer-border-bonus">
    <div class="lancer-header ${manufacturerStyle(frame.system.manufacturer)} clipped-top submajor">
      <a class="chat-flow-button" data-uuid="${frame.uuid}" data-type="passive">
        <i class="mdi mdi-message"></i>
      </a>
      <div class="grow">
        <span>${core.passive_name ?? ""}</span><span> // </span><span>PASSIVE</span>
      </div>
    </div>
    <div class="lancer-body">
      <div class="effect-text">
        ${core.passive_effect ?? ""}
      </div>
      ${actionHTML ?? ""}
    </div>
  </div>
  `;
}
__name(framePassive, "framePassive");
function talent_view(talent_path, options) {
  var _a19, _b;
  let collapse = resolveHelperDotpath(options, "collapse"), talent = resolveHelperDotpath(options, talent_path);
  if (!talent)
    return "";
  let retStr = `<li class="card clipped-top lancer-border-talent talent-compact ref set" ${ref_params(talent)}>
        <div class="lancer-header lancer-talent submajor" style="grid-area: 1/1/2/4">
          <i class="cci cci-talent i--m"></i>
          <div class="balancer"></div><div class="balancer"></div>
          <span class="major">${talent.name}</span>
          ${collapseButton(collapse, talent)}
          <div class="ref-controls">
            <a class="lancer-context-menu" data-path="${talent_path}"">
              <i class="fas fa-ellipsis-v"></i>
            </a>
          </div>
        </div>
      <ul class="collapse talent-ranks" ${collapseParam(collapse, talent, !0)} style="grid-area: 2/1/3/3">`;
  for (var i = 0; i < talent.system.curr_rank; i++) {
    let talent_actions = "";
    talent.system.ranks[i].actions && (talent_actions = buildActionArrayHTML(talent, `system.ranks.${i}.actions`));
    let sepBorder = i < talent.system.curr_rank - 1 ? "lancer-border-talent talent-rank-sep-border" : "";
    retStr += `<li class="talent-rank-compact card clipped ${sepBorder}" style="padding: 5px;">
        <i class="cci cci-rank-${i + 1} i--l i--dark" style="grid-area: rank; padding: 0;"></i>
        <a
          class="chat-flow-button lancer-button lancer-talent"
          data-uuid="${talent.uuid}"
          data-rank="${i}"
          style="grid-area: chat; height: fit-content; align-self: center;"
        >
          <i class="mdi mdi-message"></i>
        </a>
        <span class="major" style="grid-area: title">${(_a19 = talent.system.ranks[i]) == null ? void 0 : _a19.name}</span>
        <div class="effect-text" style="grid-area: desc">
        ${(_b = talent.system.ranks[i]) == null ? void 0 : _b.description}
        ${talent_actions}
        </div>
        </li>`;
  }
  return retStr += `</ul>
      </li>`, retStr;
}
__name(talent_view, "talent_view");
function skillView(skill_path, options) {
  let skill = resolveHelperDotpath(options, skill_path);
  return skill ? `
      <li class="card clipped skill-compact ref set" ${ref_params(skill)}>
        <div class="lancer-header lancer-trait medium clipped-top" style="grid-area: 1/1/2/3">
          <i class="cci cci-skill i--m i--dark"> </i>
          <a class="chat-flow-button"><i class="mdi mdi-message"></i></a>
          <span class="major modifier-name">${skill.name}</span>
          <div class="ref-controls">
            <a class="lancer-context-menu" data-path="${skill_path}">
              <i class="fas fa-ellipsis-v"></i>
            </a>
          </div>
        </div>
        <a class="flexrow skill-flow lancer-button" style="grid-area: 2/1/3/2;">
          <i class="fas fa-dice-d20 i--sm i--dark"></i>
          <div class="major roll-modifier" style="align-self: center">+${skill.system.curr_rank * 2}</div>
        </a>
        <div class="desc-text" style="grid-area: 2/2/3/3">${skill.system.description}</div>
      </li>` : "";
}
__name(skillView, "skillView");
function coreBonusView(item_path, options) {
  let coreBonus = resolveHelperDotpath(options, item_path), collapse = resolveHelperDotpath(options, "collapse");
  return coreBonus ? `
      <li class="card clipped-top lancer-border-bonus ref set" ${ref_params(coreBonus)}>
        <div class="lancer-header lancer-bonus medium" style="grid-area: 1/1/2/3">
          <i class="cci cci-corebonus i--m i--dark"> </i>
          <a class="chat-flow-button">
            <i class="mdi mdi-message"></i>
          </a>
          <span class="major modifier-name">${coreBonus.name}</span>
          ${collapseButton(collapse, coreBonus)}
          <div class="ref-controls">
            <a class="lancer-context-menu" data-path="${item_path}">
              <i class="fas fa-ellipsis-v"></i>
            </a>
          </div>
        </div>
        <div class="collapse" ${collapseParam(collapse, coreBonus, !0)} style="padding: 0.5em">
          <div class="desc-text" style="grid-area: 2/2/3/3">${coreBonus.system.description}</div>
          ${effectBox("Effect", coreBonus.system.effect)}
        </div>
      </li>` : "";
}
__name(coreBonusView, "coreBonusView");
function ref_params(doc, path) {
  return path ? ` data-uuid="${doc.uuid}" data-path="${path}" ` : ` data-uuid="${doc.uuid}" `;
}
__name(ref_params, "ref_params");
function simple_ref_slot(path = "", accept_types, _options) {
  let flat_types, arr_types;
  Array.isArray(accept_types) ? (arr_types = accept_types, flat_types = accept_types.join(" ")) : (arr_types = accept_types.split(" "), flat_types = accept_types);
  let doc = _options.hash.value ?? resolveHelperDotpath(_options, path);
  if (!doc || doc.status == "missing") {
    let icons = (arr_types || ["dummy"]).filter((t) => t).map((t) => `<img class="ref-icon" src="${TypeIcon(t)}"></img>`);
    return `<div class="ref ref-card slot" 
                 data-accept-types="${flat_types}"
                 data-path="${path}">
          ${icons.join(" ")}
          <span class="major">Empty</span>
      </div>`;
  } else
    return doc.then !== void 0 ? "<span>ASYNC not handled yet</span>" : `<div class="ref ref-card set click-open" 
                  data-accept-types="${flat_types}"
                  data-path="${path}"
                  ${ref_params(doc)}
                  >
          <img class="ref-icon" src="${doc.img}"></img>
          <span class="major">${doc.name}</span>
      </div>`;
}
__name(simple_ref_slot, "simple_ref_slot");
async function click_evt_open_ref(event) {
  var _a19;
  event.preventDefault(), event.stopPropagation();
  const elt = event.currentTarget.closest(".ref"), doc = await resolve_ref_element(elt);
  doc && ((_a19 = doc.sheet) == null || _a19.render(!0, { focus: !0 }));
}
__name(click_evt_open_ref, "click_evt_open_ref");
async function resolve_ref_element(elt) {
  if (elt.dataset.uuid) {
    let found = await fromUuid(elt.dataset.uuid);
    if (found && (found instanceof LancerItem || found instanceof LancerActor || found instanceof LancerActiveEffect)) {
      if (elt.dataset.activeEffectIndex) {
        let x = parseInt(elt.dataset.activeEffectIndex), i = 0;
        for (let effect3 of found.allApplicableEffects()) {
          if (x == i)
            return effect3;
          i++;
        }
        return null;
      }
      return found;
    } else
      found && console.warn(`Ref element pointed at a ${found.documentName} - unsupported`);
    return null;
  } else
    return null;
}
__name(resolve_ref_element, "resolve_ref_element");
function refPortrait(img, img_path, item, _options) {
  return `<img class="profile-img ref set" src="${img}" data-edit="${img_path}" ${ref_params(
    item
  )} width="100" height="100" />`;
}
__name(refPortrait, "refPortrait");
function itemPreview(item_path, trash_action, options) {
  let doc = options.hash.item ?? resolveHelperDotpath(options, item_path);
  return doc ? doc.is_mech_system() ? mechSystemViewHBS(item_path, options) : doc.is_mech_weapon() ? mechWeaponDisplay(item_path, null, options) : doc.is_weapon_mod() ? weaponModView(item_path, null, options) : doc.is_talent() ? talent_view(item_path, options) : doc.is_skill() ? skillView(item_path, options) : doc.is_core_bonus() ? coreBonusView(item_path, options) : doc.is_license() ? licenseRefView(item_path, options) : doc.is_npc_feature() ? npcFeatureView(item_path, options) : doc.is_frame() ? framePreview(item_path, options) : `
      <div class="ref set ref-card click-open" 
              ${ref_params(doc)}>
        <img class="ref-icon" src="${doc.img}"></img>
        <span class="major">${doc.name}</span>
        <hr class="vsep"> 
        <div class="ref-controls">
          <a class="lancer-context-menu" data-path="${item_path}">
            <i class="fas fa-ellipsis-v"></i>
          </a>
        </div>
      </div>` : (console.error(`Unable to resolve ${item_path} in `, options.data), "<span>err</span>");
}
__name(itemPreview, "itemPreview");
function limitedUsesIndicator(item, path, options) {
  const uses = item.system.uses, nonInteractive = options != null && options.nonInteractive ? "non-interactive" : "", hexes = hex_array(uses.value, uses.max, path, "uses-hex");
  return `<div class="clipped card limited-card ${nonInteractive}"><span>USES</span> ${hexes.join("")}</div>`;
}
__name(limitedUsesIndicator, "limitedUsesIndicator");
function loadingIndicator(item, path, options) {
  if (!item.is_weapon())
    return "";
  const loaded = item.system.loaded, nonInteractive = options != null && options.nonInteractive ? "non-interactive" : "", hexes = hex_array(loaded ? 1 : 0, 1, path, "loaded-hex");
  return `<div class="clipped card limited-card ${nonInteractive}"><span>LOADED</span> ${hexes.join("")}</div>`;
}
__name(loadingIndicator, "loadingIndicator");
function chargedIndicator(item, path, options) {
  const charged = item.system.charged, nonInteractive = options != null && options.nonInteractive ? "non-interactive" : "", hexes = hex_array(charged ? 1 : 0, 1, path, "charged-hex");
  return `<div class="clipped card charged-box ${nonInteractive}">
    <span style="margin:4px;">CHARGED</span>
    ${hexes.join("")}
  </div>`;
}
__name(chargedIndicator, "chargedIndicator");
function reserveUsesIndicator(path, options) {
  let used = resolveHelperDotpath(options, path);
  return `<div class="clipped card limited-card"><span>USES</span> ${hex_array(used ? 0 : 1, 1, path, "uses-hex").join("")}</div>`;
}
__name(reserveUsesIndicator, "reserveUsesIndicator");
function lidItemList(itemArrayPath, values, allowedTypes, options) {
  let lids = resolveHelperDotpath(options, itemArrayPath, []), trash = options.hash.trash ?? null, previews = Array.from(lids).map(
    (_, i) => itemPreview(`${itemArrayPath}.${i}`, trash, extendHelper(options, { item: values[i], isRef: !0 }))
  );
  return previews.length || previews.push('<div class="card clipped" style="justify-content: center;">DROP NPC FEATURES HERE</div>'), `
    <div class="flexcol lid-list" 
      data-path="${itemArrayPath}" 
      data-accept-types="${allowedTypes}">
      ${dropIndicator(allowedTypes)}
      ${previews.join("")}
    </div>`;
}
__name(lidItemList, "lidItemList");
function dropIndicator(allowed_types, options) {
  return `<div class="line-drop-target ${allowed_types.split(",").map((t) => `drop-target-${t}`).join(" ")}">DROP HERE</div>`;
}
__name(dropIndicator, "dropIndicator");
function handleRefClickOpen(html) {
  $(html).find(".ref.set.click-open, .ref.set .click-open").on("click", click_evt_open_ref);
}
__name(handleRefClickOpen, "handleRefClickOpen");
function handleDocListDropping(html, root_doc) {
  handleDocDropping(html.find(".ref-list"), async (rdd, evt) => {
    if (!(rdd.type == "Actor" || rdd.type == "Item"))
      return;
    let path = evt[0].dataset.path, allowed_items_raw = evt[0].dataset.acceptTypes ?? "";
    if (!(allowed_items_raw && !allowed_items_raw.includes(rdd.document.type)) && path) {
      let dd = drilldownDocument(root_doc, path), array2 = dd.terminus;
      if (Array.isArray(array2)) {
        let changes = array_path_edit_changes(dd.sub_doc, dd.sub_path + ".-1", rdd.document, "insert");
        dd.sub_doc.update({ [changes.path]: changes.new_val });
      }
    }
  });
}
__name(handleDocListDropping, "handleDocListDropping");
function handleLIDListDropping(html, root_doc) {
  handleDocDropping(html.find(".lid-list"), async (rdd, evt) => {
    if (!(rdd.type == "Actor" || rdd.type == "Item"))
      return;
    let path = evt[0].dataset.path, allowed_items_raw = evt[0].dataset.acceptTypes ?? "";
    if (!(allowed_items_raw && !allowed_items_raw.includes(rdd.document.type)) && path) {
      let dd = drilldownDocument(root_doc, path), array2 = dd.terminus;
      if (Array.isArray(array2)) {
        let lid = rdd.document.system.lid, changes = array_path_edit_changes(dd.sub_doc, dd.sub_path + ".-1", lid, "insert");
        dd.sub_doc.update({ [changes.path]: changes.new_val });
      } else if (array2 instanceof Set) {
        let lid = rdd.document.system.lid;
        array2.add(lid), dd.sub_doc.update({ [dd.sub_path]: Array.from(array2) });
      }
    }
  });
}
__name(handleLIDListDropping, "handleLIDListDropping");
function handleUsesInteraction(html, doc) {
  html.find(".uses-hex").on("click", async (ev) => {
    ev.stopPropagation();
    const uuid = ev.currentTarget.closest(".set[data-uuid*='Item']").dataset.uuid, params = ev.currentTarget.dataset;
    if (!uuid)
      return;
    const item = await fromUuid(uuid), available = params.available === "true";
    if (item.is_reserve())
      item.update({ "system.used": available });
    else {
      let newUses = item.system.uses.value;
      available ? newUses = Math.max(newUses - 1, item.system.uses.min) : newUses = Math.min(newUses + 1, item.system.uses.max), item.update({ "system.uses": newUses });
    }
  });
}
__name(handleUsesInteraction, "handleUsesInteraction");
function handleLoadedInteraction(html, _doc) {
  html.find(".loaded-hex").on("click", async (ev) => {
    ev.stopPropagation();
    const uuid = ev.currentTarget.closest(".set[data-uuid*='Item']").dataset.uuid;
    if (!uuid)
      return;
    const item = await fromUuid(uuid);
    item.is_weapon() && item.update({ "system.loaded": !item.system.loaded });
  });
}
__name(handleLoadedInteraction, "handleLoadedInteraction");
function handleChargedInteraction(html, _doc) {
  html.find(".charged-hex").on("click", async (ev) => {
    ev.stopPropagation();
    const uuid = ev.currentTarget.closest(".set[data-uuid*='Item']").dataset.uuid;
    if (!uuid)
      return;
    const item = await fromUuid(uuid);
    item.update({ "system.charged": !item.system.charged });
  });
}
__name(handleChargedInteraction, "handleChargedInteraction");
function handleRefDragging(html) {
  handleDragging(html.find(".ref.set"), (source, evt) => {
    let uuid = evt.currentTarget.dataset.uuid;
    if (!uuid || !(uuid.includes("Item.") || uuid.includes("Actor.") || uuid.includes("Token.")))
      throw console.error("Unable to properly drag ref", source, evt.currentTarget), new Error("Drag error");
    let result = {
      type: uuid.includes("Item.") ? "Item" : "Actor",
      uuid
    };
    return JSON.stringify(result);
  });
}
__name(handleRefDragging, "handleRefDragging");
function handleRefSlotDropping(html, root_doc, pre_finalize_drop) {
  handleDocDropping(html.find(".ref.drop-settable"), async (drop, dest, evt) => {
    pre_finalize_drop && (drop = await pre_finalize_drop(drop));
    let path = dest[0].dataset.path, types = dest[0].dataset.acceptTypes, val = drop.document;
    if (!(types && !types.includes(drop.document.type ?? "err")) && path) {
      let dd = drilldownDocument(
        root_doc,
        path.endsWith(".value") ? path.slice(0, path.length - 6) : path
      ), updateData = {};
      if (path.includes("loadout") && dd.sub_doc instanceof LancerActor) {
        if (dd.sub_doc.is_pilot()) {
          let cl = dd.sub_doc.system._source.loadout;
          cl.armor.some((x) => x == val.id) && (updateData["system.loadout.armor"] = cl.armor.map((x) => x == val.id ? null : x)), cl.gear.some((x) => x == val.id) && (updateData["system.loadout.gear"] = cl.gear.map((x) => x == val.id ? null : x)), cl.weapons.some((x) => x == val.id) && (updateData["system.loadout.weapons"] = cl.weapons.map((x) => x == val.id ? null : x));
        } else if (dd.sub_doc.is_mech()) {
          let cl = dd.sub_doc.system._source.loadout;
          cl.systems.some((x) => x == val.id) && (updateData["system.loadout.systems"] = cl.systems.map((x) => x == val.id ? null : x)), cl.weapon_mounts.some((x) => x.slots.some((y) => y.weapon == val.id || y.mod == val.id)) && (updateData["system.loadout.weapon_mounts"] = cl.weapon_mounts.map((wm) => ({
            slots: wm.slots.map((s) => ({
              weapon: s.weapon == val.id ? null : s.weapon,
              mod: s.mod == val.id ? null : s.mod,
              size: s.size
            })),
            bracing: wm.bracing,
            type: wm.type
          })));
        }
      }
      updateData[dd.sub_path] = val.id, dd.sub_doc.update(updateData);
    }
  });
}
__name(handleRefSlotDropping, "handleRefSlotDropping");
function actionTypeSelector(a_type, data_target) {
  const a = a_type ? a_type.toLowerCase() : ActivationType.None.toLowerCase();
  let html = '<div class="flexrow flex-center" style="padding: 5px; flex-wrap: nowrap;">';
  return html += actionTypeIcon(a_type), html += `<select name="${data_target}" data-type="String" style="height: 2em;float: right" >
    <option value="${ActivationType.None}" ${a === ActivationType.None.toLowerCase() ? "selected" : ""}>NONE</option>
    <option value="${ActivationType.Full}" ${a === ActivationType.Full.toLowerCase() ? "selected" : ""}>FULL</option>
    <option value="${ActivationType.Quick}" ${a === ActivationType.Quick.toLowerCase() ? "selected" : ""}>QUICK</option>
    <option value="${ActivationType.Reaction}" ${a === ActivationType.Reaction.toLowerCase() ? "selected" : ""}>REACTION</option>
    <option value="${ActivationType.Protocol}" ${a === ActivationType.Protocol.toLowerCase() ? "selected" : ""}>PROTOCOL</option>
    <option value="${ActivationType.Passive}" ${a === ActivationType.Passive.toLowerCase() ? "selected" : ""}>PASSIVE</option>
    <option value="${ActivationType.Other}" ${a === ActivationType.Other.toLowerCase() ? "selected" : ""}>OTHER</option>
  </select>
  </div>`, html;
}
__name(actionTypeSelector, "actionTypeSelector");
function npcFeatureScaffold(path, npc_feature, body, options) {
  let feature_class = `lancer-${slugify(npc_feature.system.type, "-")}`, icon = `cci-${slugify(npc_feature.system.type, "-")}`;
  npc_feature.system.type === NpcFeatureType.Tech && (icon += "-quick");
  let macro_button = "";
  return npc_feature.system.type !== NpcFeatureType.Weapon && (macro_button = '<a class="chat-flow-button"><i class="mdi mdi-message"></i></a>'), `
  <div class="set ref card ${feature_class}" data-item-id="${npc_feature.id}" ${ref_params(npc_feature)}>
    <div class="flexrow lancer-header clipped-top ${npc_feature.system.destroyed ? "destroyed" : ""}">
      <i class="${npc_feature.system.destroyed ? "mdi mdi-cog" : `cci ${icon} i--m i--light`}"> </i>
      ${macro_button}
      <span class="minor grow">${npc_feature.name}</span>
      <a class="lancer-context-menu" data-path="${path}" ${options.hash.isRef ? `data-uuid=${npc_feature.uuid}` : ""}>
        <i class="fas fa-ellipsis-v"></i>
      </a>
    </div>
    ${body}
  </div>`;
}
__name(npcFeatureScaffold, "npcFeatureScaffold");
function npcReactionView(path, options) {
  let npcFeature = options.hash.item ?? resolveHelperDotpath(options, path);
  return npcFeature ? (options.hash.tags = npcFeature.system.tags, npcFeatureScaffold(
    path,
    npcFeature,
    `<div class="flexcol lancer-body">
      ${npcFeature.system.tags.find((tag) => tag.lid === "tg_limited") ? limitedUsesIndicator(npcFeature, path) : ""}
      ${npcFeature.system.tags.find((tag) => tag.lid === "tg_recharge") ? chargedIndicator(npcFeature, path) : ""}
      ${effectBox("TRIGGER", npcFeature.system.trigger, { flow: !0 })}
      ${effectBox("EFFECT", npcFeature.system.effect)}
      ${compactTagListHBS(path + ".system.tags", options)}
    </div>`,
    options
  )) : "";
}
__name(npcReactionView, "npcReactionView");
function npcSystemTraitView(path, options) {
  let npcFeature = options.hash.item ?? resolveHelperDotpath(options, path);
  return npcFeature ? (options.hash.tags = npcFeature.system.tags, npcFeatureScaffold(
    path,
    npcFeature,
    `<div class="flexcol lancer-body">
      ${npcFeature.system.tags.find((tag) => tag.lid === "tg_limited") ? limitedUsesIndicator(npcFeature, path) : ""}
      ${npcFeature.system.tags.find((tag) => tag.lid === "tg_recharge") ? chargedIndicator(npcFeature, path) : ""}
      ${effectBox("EFFECT", npcFeature.system.effect, { flow: !0 })}
      ${compactTagListHBS(path + ".system.tags", options)}
    </div>`,
    options
  )) : "";
}
__name(npcSystemTraitView, "npcSystemTraitView");
function npcTechView(path, options) {
  let npcFeature = options.hash.item ?? resolveHelperDotpath(options, path);
  if (!npcFeature)
    return "";
  options.hash.tags = npcFeature.system.tags;
  let featureData = npcFeature.system, tierIndex = (options.hash.tier ?? 1) - 1, sep = '<hr class="vsep">', subheaderItems = [], subheader2Items = [];
  return featureData.tech_attack && subheaderItems.push(
    `<a class="roll-tech lancer-button" data-tooltip="Roll an attack with this system">
        <i class="fas fa-dice-d20 i--m"></i>
      </a>`
  ), featureData.tech_attack && featureData.attack_bonus && featureData.attack_bonus[tierIndex] && subheaderItems.push(npcAttackBonusView(featureData.attack_bonus[tierIndex], "ATTACK")), featureData.tech_attack && featureData.accuracy && featureData.accuracy[tierIndex] && subheaderItems.push(npcAccuracyView(featureData.accuracy[tierIndex])), featureData.tags.find((tag) => tag.is_recharge) && subheaderItems.push(chargedIndicator(npcFeature, path)), npcFeature.system.tags.some((t) => t.is_limited) && subheader2Items.push(limitedUsesIndicator(npcFeature, path)), npcFeatureScaffold(
    path,
    npcFeature,
    `
    <div class="lancer-body flex-col">
      <div class="flexrow">
        ${subheaderItems.join(sep)}
      </div>
      <div class="flexrow no-wrap">
        ${subheader2Items.join()}
      </div>
      <div class="flexcol" style="padding: 0 10px;">
        ${effectBox("EFFECT", featureData.effect, { flow: !featureData.tech_attack })}
        ${compactTagListHBS(path + ".system.tags", options)}
      </div>
    </div>
    `,
    options
  );
}
__name(npcTechView, "npcTechView");
function npcWeaponView(path, options) {
  let npcFeature = options.hash.item ?? resolveHelperDotpath(options, path);
  if (!npcFeature || !npcFeature.is_weapon())
    return "";
  options.hash.tags = npcFeature.system.tags;
  let featureData = npcFeature.system, tierIndex = (options.hash.tier ?? 1) - 1, sep = '<hr class="vsep">', subheaderItems = [
    `<a class="roll-attack lancer-button no-grow" data-tooltip="Roll an attack with this weapon">
      <i class="fas fa-dice-d20 i--m i--dark"></i>
    </a>`
  ], subheader2Items = [];
  return featureData.attack_bonus[tierIndex] && subheaderItems.push(npcAttackBonusView(featureData.attack_bonus[tierIndex])), featureData.accuracy[tierIndex] && subheaderItems.push(npcAccuracyView(featureData.accuracy[tierIndex])), featureData.range.length && subheaderItems.push(rangeArrayView(featureData.range, options)), featureData.damage[tierIndex] && featureData.damage[tierIndex].length && subheaderItems.push(damageArrayView(featureData.damage[tierIndex], { ...options, rollable: !0 })), featureData.tags.find((t) => t.is_recharge) && subheader2Items.push(chargedIndicator(npcFeature, path)), npcFeature.system.tags.some((t) => t.is_loading) && subheader2Items.push(loadingIndicator(npcFeature, path)), npcFeature.system.tags.some((t) => t.is_limited) && subheader2Items.push(limitedUsesIndicator(npcFeature, path)), npcFeatureScaffold(
    path,
    npcFeature,
    `
    <div class="lancer-body flex-col">
      <div class="flexrow no-wrap">
        ${subheaderItems.join(sep)}
      </div>
      <div class="flexrow no-wrap">
        ${subheader2Items.join()}
      </div>
      <div>
        <span>${featureData.weapon_type} // ${npcFeature.system.origin.name} ${npcFeature.system.origin.type} Feature</span>
      </div>
      ${effectBox("ON HIT", featureData.on_hit)}
      ${effectBox("EFFECT", featureData.effect)}
      ${compactTagListHBS(path + ".system.tags", options)}
    </div>
    `,
    options
  );
}
__name(npcWeaponView, "npcWeaponView");
function promptText(title, prefill = "") {
  return new Promise((succ, _rej) => {
    new Dialog(
      {
        title,
        content: ` 
          <div class="form-group">  
            <input id="textval" type="text" style="width: 100%;" value="${prefill}"></input>
          </div>
          <hr>
        `,
        buttons: {
          confirm: {
            label: "Confirm",
            callback: async (dialog_html) => {
              let new_val = $(dialog_html).find("#textval")[0].value;
              succ(new_val);
            }
          }
        },
        close: () => succ(null),
        default: "confirm"
      },
      {
        classes: ["lancer"]
      }
    ).render(!0);
  });
}
__name(promptText, "promptText");
const _CounterEditForm = class _CounterEditForm extends TargetedEditForm {
  /* -------------------------------------------- */
  /** @override */
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      template: `systems/${game.system.id}/templates/window/counter.hbs`,
      classes: ["lancer", "counter-editor"],
      title: "Counter Editing"
    };
  }
  /** @override */
  fixupForm(form_data) {
    var _a19;
    let name2 = form_data.name, min2 = form_data.min, max2 = form_data.max, value = form_data.value, invalid = [min2, max2, value].find((x) => Number.isNaN(x));
    if (invalid !== void 0) {
      let message = `${invalid} is not a valid numeric value`;
      throw (_a19 = ui.notifications) == null || _a19.error(message), new Error(message);
    }
    return name2 = name2.trim(), max2 < min2 && (max2 = min2), value < min2 && (value = min2), value > max2 && (value = max2), { name: name2, min: min2, max: max2, value };
  }
};
__name(_CounterEditForm, "CounterEditForm");
let CounterEditForm = _CounterEditForm;
function weaponSizeSelector(path, options) {
  return options.hash.presorted = !0, options.hash.default || (options.hash.default = WeaponSize.Main), std_enum_select(path, WeaponSize, options);
}
__name(weaponSizeSelector, "weaponSizeSelector");
function weaponTypeSelector(path, options) {
  return options.hash.default || (options.hash.default = WeaponType.Rifle), std_enum_select(path, WeaponType, options);
}
__name(weaponTypeSelector, "weaponTypeSelector");
function rangeEditor(path, options) {
  let range = resolveHelperDotpath(options, path);
  if (!range)
    return "";
  let icon_html = `<i class="cci ${range.icon} i--m i--dark"></i>`, type_options = extendHelper(options, { value: range.type }, { default: RangeType.Range }), range_type_selector = std_enum_select(path + ".type", RangeType, type_options), value_options = extendHelper(options, { value: range.val }), value_input = std_text_input(path + ".val", value_options), delete_button = `<a class="gen-control" data-action="splice" data-path="${path}" style="margin: 4px;"><i class="fas fa-trash"></i></a>`;
  return `<div class="flexrow flex-center" style="padding: 5px;">
    ${icon_html}
    ${range_type_selector}
    ${value_input}
    ${delete_button}
  </div>
  `;
}
__name(rangeEditor, "rangeEditor");
function damageEditor(path, options) {
  options.hash.presorted = !0;
  let damage = resolveHelperDotpath(options, path);
  if (!damage)
    return "";
  let icon_html = `<i class="cci ${damage.icon} i--m"></i>`, type_options = extendHelper(options, { value: damage.type }, { default: DamageType.Kinetic }), damage_type_selector = std_enum_select(path + ".type", DamageType, type_options), value_options = extendHelper(options, { value: damage.val }), value_input = std_text_input(path + ".val", value_options), delete_button = `<a class="gen-control" data-action="splice" data-path="${path}" style="margin: 4px;"><i class="fas fa-trash"></i></a>`;
  return `<div class="flexrow flex-center" style="padding: 5px;">
    ${icon_html}
    ${damage_type_selector}
    ${value_input}
    ${delete_button}
  </div>
  `;
}
__name(damageEditor, "damageEditor");
function damageArrayView(damages, options) {
  let classes = options.hash.classes || "", results = [];
  const openTag = options.rollable ? `<a
      class="flexrow no-grow compact-damage roll-damage lancer-button ${classes}"
      style="max-width: min-content;"
      data-tooltip="Roll damage for this weapon without attacking"
    >` : `<div class="flexrow no-grow compact-damage ${classes}">`, closeTag = options.rollable ? "</a>" : "</div>";
  for (let damage of damages) {
    let damage_item = `<span class="compact-damage">
      <i class="cci ${damage.icon} i--m i--dark damage--${damage.type.toLowerCase()}"></i>
      ${damage.val}</span>`;
    results.push(damage_item);
  }
  return `${openTag}${results.join(" ")}${closeTag}`;
}
__name(damageArrayView, "damageArrayView");
function rangeArrayView(ranges, options) {
  let classes = options.hash.classes || "", results = [];
  for (let range of ranges) {
    let range_item = `<span class="compact-range" data-tooltip="${range.type}"><i class="cci ${range.icon} i--m i--dark"></i>${range.val}</span>`;
    results.push(range_item);
  }
  return `<div class="flexrow no-grow compact-range ${classes}">${results.join(" ")}</div>`;
}
__name(rangeArrayView, "rangeArrayView");
function npcAttackBonusView(atk, txt = "ATTACK") {
  return `<div class="compact-acc" data-tooltip="Flat attack bonus">
    <i style="margin-right: 5px;" class="cci cci-reticule i--m"></i>
    <span class="medium"> ${atk < 0 ? "-" : "+"}${atk} ${txt}</span>
  </div>`;
}
__name(npcAttackBonusView, "npcAttackBonusView");
function npcAccuracyView(acc) {
  let icon, text;
  if (acc > 0)
    icon = "accuracy", text = `+${acc} ACCURACY`;
  else if (acc < 0)
    icon = "difficulty", text = `${acc} DIFFICULTY`;
  else
    return "";
  return `<div class="compact-acc" data-tooltip="Innate Accuracy/Difficulty">
      <i style="margin-right: 5px" class="cci cci-${icon} i--m"></i>
      <span class="medium">${text}</span>
    </div>`;
}
__name(npcAccuracyView, "npcAccuracyView");
function systemTypeSelector(path, options) {
  return std_enum_select(path, SystemType, extendHelper(options, {}, { default: SystemType.System }));
}
__name(systemTypeSelector, "systemTypeSelector");
function usesControl(uses_path, max_uses, options) {
  const curr_uses = resolveHelperDotpath(options, uses_path, 0);
  return `
    <div class="card clipped">
      <span class="lancer-header lancer-primary"> USES </span>
      ${std_x_of_y(uses_path, curr_uses, max_uses)}
    </div>
    `;
}
__name(usesControl, "usesControl");
function npcFeatureView(npc_feature_path, options) {
  let feature = options.hash.item ?? resolveHelperDotpath(options, npc_feature_path);
  if (!feature)
    return "";
  switch (feature.system.type) {
    case "Reaction":
      return npcReactionView(npc_feature_path, options);
    case "System":
    case "Trait":
      return npcSystemTraitView(npc_feature_path, options);
    case "Tech":
      return npcTechView(npc_feature_path, options);
    case "Weapon":
      return npcWeaponView(npc_feature_path, options);
    default:
      return "bad feature";
  }
}
__name(npcFeatureView, "npcFeatureView");
function bonusesDisplay(bonuses_path, edit, options) {
  let bonuses_array = resolveHelperDotpath(options, bonuses_path, []), items = [];
  for (let i = 0; i < bonuses_array.length; i++) {
    let bonus = bonuses_array[i], delete_button = `<a class="gen-control" data-action="splice" data-path="${bonuses_path}.${i}"><i class="fas fa-trash"></i></a>`, title = `<span class="grow">${bonus.lid}</span> ${inc_if(delete_button, edit)}`, boxed = `
      <div class="bonus ${inc_if("editable", edit)}" data-path="${bonuses_path}.${i}">
        ${effectBox(title, bonus.val)}
      </div>
    `;
    items.push(boxed);
  }
  return `
    <div class="card bonus-list">
      <div class="lancer-header lancer-bonus">
        <span class="left">// Bonuses</span>
        ${inc_if(
    `<a class="gen-control fas fa-plus" data-action="append" data-path="${bonuses_path}" data-action-value="(struct)bonus"></a>`,
    edit
  )}
      </div>
      ${items.join(`
`)}
    </div>
    `;
}
__name(bonusesDisplay, "bonusesDisplay");
function bondPower(bond_path, power_index, options) {
  let bond = resolveHelperDotpath(options, bond_path), power = bond == null ? void 0 : bond.system.powers[power_index];
  if (!bond || !power)
    return "";
  let body = `<span class="desc-text">${power.description}</span>`;
  return `
    <div class="card clipped bond-power" data-uuid="${bond.uuid}" data-power-index="${power_index}">
      <div class="lancer-header lancer-primary medium clipped-top">
        <i class="cci cci-trait i--m"></i>
        <a class="bond-power-flow"><i class="mdi mdi-message"></i></a>
        <span>${power.name}</span>
        ${power.veteran ? '<i class="mdi mdi-alpha-v-box i--sm"></i>' : ""}
        ${power.master ? '<i class="mdi mdi-alpha-m-box i--sm"></i>' : ""}
      </div>
      ${power.uses ? `<div class="flexrow">
            ${body}
            ${power.uses && power.uses.max ? bondPowerUsesIndicator(bond, power_index, `${bond_path}.system.powers.${power_index}`) : ""}
          </div>` : `${body}`}
    </div>
  `;
}
__name(bondPower, "bondPower");
function pilotArmorSlot(armor_path, options) {
  var _a19, _b, _c, _d, _e;
  let armor = resolveHelperDotpath(options, armor_path);
  if (!armor)
    return `<div class="${EntryType.PILOT_ARMOR} ref drop-settable card" 
                        data-path="${armor_path}" 
                        data-accept-types="${EntryType.PILOT_ARMOR}">
          <img class="ref-icon" src="${TypeIcon(EntryType.PILOT_ARMOR)}"></img>
          <span class="major">Equip armor</span>
      </div>`;
  let bonuses = armor.system.bonuses, armor_val = ((_a19 = bonuses.find((b) => b.lid == "pilot_armor")) == null ? void 0 : _a19.val) ?? "0", speed_val = ((_b = bonuses.find((b) => b.lid == "pilot_speed")) == null ? void 0 : _b.val) ?? "0", edef_val = ((_c = bonuses.find((b) => b.lid == "pilot_edef")) == null ? void 0 : _c.val) ?? "0", eva_val = ((_d = bonuses.find((b) => b.lid == "pilot_evasion")) == null ? void 0 : _d.val) ?? "0", hp_val = ((_e = bonuses.find((b) => b.lid == "pilot_hp")) == null ? void 0 : _e.val) ?? "0";
  const description2 = armor.system.description || "";
  let effect3 = armor.system.effect ? effectBox("Effect", armor.system.effect) : "", actions = "";
  return armor.system.actions.length && (actions = buildActionArrayHTML(armor, "system.actions")), `<div class="set ref drop-settable card clipped-top pilot-armor-compact item lancer-border-primary" 
                ${ref_params(armor, armor_path)} 
                data-accept-types="${EntryType.PILOT_ARMOR}"
                >
            <div class="lancer-header lancer-primary">
              <i class="mdi mdi-shield-outline i--m i--light"> </i>
              <span class="minor">${armor.name}</span>
              <a class="lancer-context-menu" data-path="${armor_path}"">
                <i class="fas fa-ellipsis-v"></i>
              </a>
            </div>
            <div class="flexrow" style="align-items: center; padding: 5px">
              <div class="compact-stat">
                <i class="mdi mdi-shield-outline i--s i--dark"></i>
                <span class="minor">${armor_val}</span>
              </div>
              <div class="compact-stat">
                <i class="mdi mdi-heart i--s i--dark"></i>
                <span class="minor">+${hp_val}</span>
              </div>
              <div class="compact-stat">
                <i class="cci cci-edef i--s i--dark"></i>
                <span class="minor">${edef_val}</span>
              </div>
              <div class="compact-stat">
                <i class="cci cci-evasion i--s i--dark"></i>
                <span class="minor">${eva_val}</span>
              </div>
              <div class="compact-stat">
                <i class="mdi mdi-arrow-right-bold-hexagon-outline i--s i--dark"></i>
                <span class="minor">${speed_val}</span>
              </div>
            </div>
            <div class="pilot-gear-body flexcol">
              ${description2}
              ${effect3}
              ${actions}
              ${compactTagListHBS(armor_path + ".system.tags", options)}
            </div>
          </div>`;
}
__name(pilotArmorSlot, "pilotArmorSlot");
function pilotWeaponRefview(weapon_path, options) {
  let weapon = resolveHelperDotpath(options, weapon_path);
  if (!weapon)
    return `<div class="${EntryType.PILOT_WEAPON} ref drop-settable card flexrow" 
                        data-path="${weapon_path}" 
                        data-accept-types="${EntryType.PILOT_WEAPON}">
          <img class="ref-icon" src="${TypeIcon(EntryType.PILOT_WEAPON)}"></img>
          <span class="major">Equip weapon</span>
      </div>`;
  let loading = "";
  weapon.system.tags.some((t) => t.is_loading) && (loading = loadingIndicator(weapon, weapon_path));
  let limited = "";
  weapon.system.tags.some((t) => t.is_limited) && limitedUsesIndicator(weapon, weapon_path);
  let effect3 = weapon.system.effect ? effectBox("Effect", weapon.system.effect) : "", actions = "";
  return weapon.system.actions.length && (actions = buildActionArrayHTML(weapon, "system.actions")), `<div class="set ${EntryType.PILOT_WEAPON} ref drop-settable card clipped-top pilot-weapon-compact item lancer-border-weapon"
    ${ref_params(weapon, weapon_path)} 
    data-accept-types="${EntryType.PILOT_WEAPON}"
  >
    <div class="lancer-header lancer-weapon">
      <i class="cci cci-weapon i--m i--light"> </i>
      <span class="minor">${weapon.name}</span>
              <a class="lancer-context-menu" data-path="${weapon_path}"">
                <i class="fas fa-ellipsis-v"></i>
              </a>
    </div>
    <div class="pilot-gear-body flexcol">
      <div class="flexrow">
        <a
          class="flexrow roll-attack lancer-button"
          style="max-width: min-content;"
          data-tooltip="Roll an attack with this weapon"
        >
          <i class="fas fa-dice-d20 i--sm i--dark"></i>
        </a>
        ${rangeArrayView(weapon.system.range, options)}
        <hr class="vsep">
        ${damageArrayView(weapon.system.damage, { ...options, rollable: !0 })}
        
        ${inc_if('<hr class="vsep"><div class="uses-wrapper">', loading || limited)}
        ${loading}
        ${limited}
        ${inc_if("</div>", loading || limited)}
      </div>

      ${effect3}
      ${actions}
      ${compactTagListHBS(weapon_path + ".system.tags", options)}
    </div>
  </div>`;
}
__name(pilotWeaponRefview, "pilotWeaponRefview");
function pilotGearRefview(gear_path, options) {
  var _a19;
  let gear = resolveDotpath((_a19 = options.data) == null ? void 0 : _a19.root, gear_path);
  if (!gear)
    return `<div class="${EntryType.PILOT_GEAR} ref drop-settable card flexrow" 
                        data-path="${gear_path}" 
                        data-accept-types="${EntryType.PILOT_GEAR}">
          <img class="ref-icon" src="${TypeIcon(EntryType.PILOT_GEAR)}"></img>
          <span class="major">Equip gear</span>
      </div>`;
  let uses = "";
  gear.getLimitedBase() && (uses = limitedUsesIndicator(gear, gear_path));
  let effect3 = gear.system.effect ? effectBox("Effect", gear.system.effect) : "", actions = "";
  return gear.system.actions.length && (actions = buildActionArrayHTML(gear, "system.actions")), `<div class="set ${EntryType.PILOT_GEAR} ref drop-settable card clipped-top item lancer-border-system"
    ${ref_params(gear, gear_path)} 
    data-accept-types="${EntryType.PILOT_GEAR}"
  >
    <div class="lancer-header lancer-system">
      <i class="cci cci-generic-item i--m"> </i>
      <a class="chat-flow-button"><i class="mdi mdi-message"></i></a>
      <span class="minor">${gear.name}</span>
      <a class="lancer-context-menu" data-path="${gear_path}"">
        <i class="fas fa-ellipsis-v"></i>
      </a>
    </div>
    <div class="pilot-gear-body flexcol">
      <div class="flexrow">
        <div class="effect-text" style=" padding: 5px">
          ${gear.system.description || ""}
        </div>
        ${uses}
      </div>
      ${effect3}
      ${actions}
      ${compactTagListHBS(gear_path + ".system.tags", options)}
    </div>
  </div>`;
}
__name(pilotGearRefview, "pilotGearRefview");
function bondPowerUsesIndicator(item, power_index, path) {
  const power = item.system.powers[power_index];
  return power.uses ? `<div class="clipped card limited-card">
    <div class="flexcol"><span>USES</span><div>${hex_array(power.uses.value, power.uses.max, path, "power-uses-hex").join("")}</div></div>
  </div>` : "";
}
__name(bondPowerUsesIndicator, "bondPowerUsesIndicator");
function reserveRefView(reserve_path, options) {
  let reserve = resolveHelperDotpath(options, reserve_path);
  if (!reserve)
    return `<div class="${EntryType.RESERVE} ref drop-settable card flexrow"
                        data-path="${reserve_path}"
                        data-accept-types="${EntryType.RESERVE}">
          <img class="ref-icon" src="${TypeIcon(EntryType.RESERVE)}"></img>
          <span class="major">Equip reserve</span>
      </div>`;
  let icon = "";
  const resTypes = [
    ReserveType.Mech,
    ReserveType.Organization,
    ReserveType.Project,
    ReserveType.Resources,
    ReserveType.Tactical,
    "Resource",
    // machine-mind bug? Reserves from Comp/Con are Resource instead of Resources
    "Bonus"
  ];
  switch (resTypes.includes(reserve.system.type) ? reserve.system.type : resTypes.includes(reserve.system.label) ? reserve.system.label : reserve.system.type) {
    case "Bonus":
      icon = "cci cci-accuracy";
      break;
    case ReserveType.Mech:
      icon = "cci cci-reserve-mech";
      break;
    case ReserveType.Organization:
      icon = "mdi mdi-account-multiple";
      break;
    case ReserveType.Project:
      icon = "cci cci-orbital";
      break;
    case ReserveType.Resources:
    case "Resource":
      icon = "cci cci-reserve-resource";
      break;
    case ReserveType.Tactical:
      icon = "cci cci-reserve-tac";
      break;
    default:
      icon = "cci cci-reserve-tac";
      break;
  }
  let uses = "";
  reserve.system.consumable && (uses = reserveUsesIndicator(`${reserve_path}.system.used`, options));
  let actions = reserve.system.actions.length > 0 ? buildActionArrayHTML(reserve, "system.actions") : "";
  return `<div class="set ${EntryType.RESERVE} ref drop-settable card clipped-top item lancer-border-trait"
                ${ref_params(reserve, reserve_path)} >
    <div class="lancer-header lancer-trait">
      <i class="${icon} i--m"> </i>
      <a class="chat-flow-button"><i class="mdi mdi-message"></i></a>
      <span class="minor">${reserve.name}</span>
      <a class="lancer-context-menu" data-path="${reserve_path}"">
        <i class="fas fa-ellipsis-v"></i>
      </a>
    </div>
    <div class="flexcol">
      <div class="flexrow">
        <div class="effect-text" style=" padding: 5px">
          ${reserve.system.description}
        </div>
        ${actions}
        ${uses}
      </div>
    </div>
  </div>`;
}
__name(reserveRefView, "reserveRefView");
function mechLoadoutWeaponSlot(weapon_path, mod_path, size, options) {
  if (resolveHelperDotpath(options, weapon_path))
    return mechWeaponDisplay(weapon_path, mod_path, options);
  {
    const slotSize = size ? size === FittingSize.Flex ? `${FittingSize.Main} || ${FittingSize.Auxiliary}` : size : "any";
    return `
      <div class="${EntryType.MECH_WEAPON} ref slot drop-settable card flexrow" 
           data-path="${weapon_path}" 
           data-accept-types="${EntryType.MECH_WEAPON}">
        <img class="ref-icon" src="${TypeIcon(EntryType.MECH_WEAPON)}"></img>
        <span class="major">Insert ${slotSize} weapon</span>
      </div>`;
  }
}
__name(mechLoadoutWeaponSlot, "mechLoadoutWeaponSlot");
function mechWeaponDisplay(weapon_path, mod_path, options) {
  resolveHelperDotpath(options, "actor");
  let weapon = resolveHelperDotpath(options, weapon_path), mod_text = mod_path ? weaponModView(mod_path, weapon_path, options) : "", collapse = resolveHelperDotpath(options, "collapse");
  if (!weapon)
    return "";
  let profiles = "";
  if (weapon.system.profiles.length > 1) {
    profiles = '<div class="flexrow weapon-profile-wrapper">';
    for (let i = 0; i < weapon.system.profiles.length; i++) {
      let p = weapon.system.profiles[i];
      profiles += `<a class="gen-control weapon-profile ${i === weapon.system.selected_profile_index ? "selected-profile" : ""}"
data-action="set" data-action-value="(int)${i}" data-path="${weapon_path}.system.selected_profile_index">
<span class="minor">${p.name}</span>
</a>`;
    }
    profiles += "</div>";
  }
  let sp = spDisplay(weapon.system.sp ?? 0), profile = weapon.system.active_profile, profile_path = `${weapon_path}.system.profiles.${weapon.system.selected_profile_index}`, loading = "";
  weapon.system.all_tags.some((t) => t.is_loading) && (loading = loadingIndicator(weapon, weapon_path));
  let effect3 = profile.effect ? effectBox("Effect", profile.effect) : "", on_attack = profile.on_attack ? effectBox("On Attack", profile.on_attack) : "", on_hit = profile.on_hit ? effectBox("On Hit", profile.on_hit) : "", on_crit = profile.on_crit ? effectBox("On Crit", profile.on_crit) : "", actions = weapon.system.actions.length > 0 ? buildActionArrayHTML(weapon, "system.actions") : "";
  actions += profile.actions.length > 0 ? buildActionArrayHTML(weapon, `system.profiles.${weapon.system.selected_profile_index}.actions`) : "";
  let limited = "";
  return weapon.isLimited() && (limited = limitedUsesIndicator(weapon, weapon_path)), `
  <div class="mech-weapon-wrapper${mod_text ? "-modded" : ""}">
    <div class="ref set drop-settable ${EntryType.MECH_WEAPON} flexcol item"
                  ${ref_params(weapon, weapon_path)}
                  data-accept-types="${EntryType.MECH_WEAPON}"
                  style="max-height: fit-content;">
      <div class="lancer-header lancer-weapon ${weapon.system.destroyed ? "destroyed" : ""}">
        <i class="${weapon.system.destroyed ? "mdi mdi-cog" : "cci cci-weapon i--m i--light"}"> </i>
        <a class="chat-flow-button"><i class="mdi mdi-message"></i></a>
        <span class="minor" >
          ${weapon.name} // ${weapon.system.size.toUpperCase()} ${profile.type.toUpperCase()}
        </span>
        ${collapseButton(collapse, weapon)}
        <a class="lancer-context-menu" data-path="${weapon_path}">
          <i class="fas fa-ellipsis-v"></i>
        </a>
      </div> 
      <div class="lancer-body collapse" ${collapseParam(collapse, weapon, !0)}>
        ${weapon.system.sp ? sp : ""}
        ${profiles}
        <div class="flexrow" style="text-align: left; white-space: nowrap;">
          <a class="roll-attack lancer-button" data-tooltip="Roll an attack with this weapon">
            <i class="fas fa-dice-d20 i--m i--dark"></i>
          </a>
          <hr class="vsep">
          ${rangeArrayView(profile.all_range, options)}
          <hr class="vsep">
          ${damageArrayView(profile.all_damage, { ...options, rollable: !0 })}

          ${inc_if('<hr class="vsep"><div class="uses-wrapper">', loading || limited)}
          <!-- Loading toggle, if we are loading-->
          ${loading}
          <!-- Limited toggle if we are limited-->
          ${limited}
          ${inc_if("</div>", loading || limited)}
        </div>
        
        <div class="flexcol">
          ${effect3}
          ${on_attack}
          ${on_hit}
          ${on_crit}
          ${actions}
          ${compactTagListHBS(profile_path + ".all_tags", options)}
        </div>
        ${mod_text}
      </div>
    </div>
  </div>`;
}
__name(mechWeaponDisplay, "mechWeaponDisplay");
function weaponModView(mod_path, weapon_path, options) {
  let mod = resolveHelperDotpath(options, mod_path);
  if (weapon_path && resolveHelperDotpath(options, weapon_path), !mod)
    return `<div class="${EntryType.WEAPON_MOD} ref slot drop-settable card flexrow"
        data-path="${mod_path}"
        data-accept-types="${EntryType.WEAPON_MOD}">
      <i class="cci cci-weaponmod i--m i--light"> </i>
      <span>No Mod Installed</span>
    </div>`;
  let sp = mod.system.sp ? spDisplay(mod.system.sp) : "", limited = mod.system.tags.some((t) => t.is_limited) ? limitedUsesIndicator(mod, mod_path) : "", added_range = "";
  mod.system.added_range.length && (added_range = `
      <div class="effect-box">
        <div class="effect-title clipped-bot">ADDED RANGE</div>
        ${rangeArrayView(mod.system.added_range, options)}
      </div>`);
  let added_damage = "";
  mod.system.added_damage.length && (added_damage = `
      <div class="effect-box">
        <div class="effect-title clipped-bot">ADDED DAMAGE</div>
        ${damageArrayView(mod.system.added_damage, options)}
      </div>`);
  let effect3 = mod.system.effect ? effectBox("Effect", mod.system.effect, { flow: !0 }) : "", bonuses = mod.system.bonuses.length > 0 ? bonusesDisplay(`${mod_path}.system.bonuses`, !1, options) : "", added_tags = "";
  mod.system.added_tags.length && (added_tags = `
    <div class="effect-box">
      <span class="effect-title clipped-bot">ADDED TAGS</span>
      ${compactTagListHBS(mod_path + ".system.added_tags", options)}
    </div>
    `);
  let tags = mod.system.tags.length ? compactTagListHBS(`${mod_path}.system.tags`, options) : "", actions = "";
  return mod.system.actions.length && (actions = buildActionArrayHTML(mod, "system.actions")), `
  <div class="set flexcol clipped-top ref ${EntryType.WEAPON_MOD} drop-settable" ${ref_params(
    mod,
    mod_path
  )} data-accept-types="${EntryType.WEAPON_MOD}">
    <div class="lancer-header lancer-mod">
      <i class="cci cci-weaponmod i--m i--light"> </i>
      <span class="minor">${mod.name}</span>
      <a class="lancer-context-menu" data-path="${mod_path}">
        <i class="fas fa-ellipsis-v"></i>
      </a>
    </div>
    <div class="lancer-body">
      <div class="flexrow">
        ${limited}
        ${sp}
      </div>
      <div class="flexrow">
        ${added_range}
        ${added_damage}
      </div>
      ${effect3}
      ${bonuses}
      ${actions}
      ${added_tags}
      ${tags}
    </div>
  </div>`;
}
__name(weaponModView, "weaponModView");
function licenseRefView(item_path, options) {
  let license2 = resolveHelperDotpath(options, item_path);
  const mfr = manufacturerStyle(license2.system.manufacturer);
  return `
    <li class="card clipped ref set" ${ref_params(license2)}>
      <div class="lancer-header ${mfr} medium clipped-top" style="grid-area: 1/1/2/3">
        <i class="cci cci-license i--m i--dark"> </i>
        <div class="major modifier-name">${license2.name} ${license2.system.curr_rank}</div>
        <div class="ref-controls">
          <a class="lancer-context-menu" data-path="${item_path}"">
            <i class="fas fa-ellipsis-v"></i>
          </a>
        </div>
      </div>
    </li>`;
}
__name(licenseRefView, "licenseRefView");
function framePreview(path, options) {
  let frame = resolveHelperDotpath(options, path);
  if (frame) {
    let frame_img = encodeURI(frameToPath(frame.name) ?? "systems/lancer/assets/icons/frame.svg");
    return `
    <li class="card clipped ref set click-open" ${ref_params(frame)}>
      <div class="compact-frame medium flexrow">
        <span class="img-bar" style="background-image: url(${frame_img})"></span>
        <div class="major modifier-name i--light">${frame.system.manufacturer} ${frame.name}</div>
        <div class="ref-controls">
          <a class="lancer-context-menu" data-path="${path}"">
            <i class="fas fa-ellipsis-v i--light"></i>
          </a>
        </div>
      </div>
    </li>`;
  } else
    return "";
}
__name(framePreview, "framePreview");
function npcClassRefView(npc_class, item_path) {
  var _a19;
  if (npc_class) {
    let frame_img = encodeURI(npc_class.img ?? "systems/lancer/assets/icons/npc_class.svg");
    return `
    <div class="card clipped ref set click-open" ${ref_params(npc_class)}>
      <div class="compact-class medium flexrow">
        <span class="img-bar" style="background-image: url(${frame_img})"></span>
        <div class="major modifier-name i--light">${npc_class.name} // ${(_a19 = npc_class.system.role) == null ? void 0 : _a19.toUpperCase()}</div>
        <div class="ref-controls">
          <a class="lancer-context-menu" data-path="${item_path}"">
            <i class="fas fa-ellipsis-v i--light"></i>
          </a>
        </div>
      </div>
    </div>`;
  } else
    return "";
}
__name(npcClassRefView, "npcClassRefView");
function npcTemplateRefView(template, item_path) {
  return template ? `
    <div class="card clipped ref set click-open" ${ref_params(template)}>
      <div class="compact-template medium flexrow">
        <span class="img-bar" style="background-image: url(${template.img})"></span>
        <div class="major modifier-name i--light">${template.name}</div>
        <div class="ref-controls">
          <a class="lancer-context-menu" data-path="${item_path}"">
            <i class="fas fa-ellipsis-v i--light"></i>
          </a>
        </div>
      </div>
    </div>` : "";
}
__name(npcTemplateRefView, "npcTemplateRefView");
function actionTypeIcon(a_type) {
  const a = a_type ? a_type.toLowerCase() : ActivationType.None.toLowerCase();
  let html = "";
  switch (a) {
    case ActivationType.Full.toLowerCase():
      html += '<i class="cci cci-activation-full i--m"></i>';
      break;
    case ActivationType.Quick.toLowerCase():
      html += '<i class="cci cci-activation-quick i--m"></i>';
      break;
    case ActivationType.Reaction.toLowerCase():
      html += '<i class="cci cci-reaction i--m"></i>';
      break;
    case ActivationType.Protocol.toLowerCase():
      html += '<i class="cci cci-protocol i--m"></i>';
      break;
    case ActivationType.Free.toLowerCase():
      html += '<i class="cci cci-free-action i--m"></i>';
      break;
    case ActivationType.FullTech.toLowerCase():
      html += '<i class="cci cci-tech-full i--m"></i>';
      break;
    case ActivationType.QuickTech.toLowerCase():
    case ActivationType.Invade.toLowerCase():
      html += '<i class="cci cci-tech-quick i--m"></i>';
      break;
  }
  return html;
}
__name(actionTypeIcon, "actionTypeIcon");
function buildActionHTML(doc, path, options) {
  var _a19;
  let action = resolveDotpath(doc, path);
  if (!action)
    return "";
  let detailText, chip, tags, editor;
  options != null && options.hideChip ? chip = "" : (chip = buildChipHTML(
    action.activation,
    { uuid: doc.uuid, path },
    { nonInteractive: options == null ? void 0 : options.nonInteractive }
  ), chip = `<div class="action-flow-container">${chip}<hr class="vsep"></div>`);
  let editDetails = options != null && options.editable ? `<a class="fas fa-edit popout-text-edit-button" data-path="${path}.detail"></a>` : "";
  return action.trigger ? detailText = `
      <div class="action-detail ${options != null && options.full ? "" : "collapsed"}">
        <hr class="hsep">
        <div>
          ${chip}
          <div>
            <div class="overline">${game.i18n.localize("lancer.chat-card.label.trigger")}</div> 
            ${action.trigger || defaultPlaceholder}
            <div class="overline">${game.i18n.localize("lancer.chat-card.label.effect")} ${editDetails}</div>
            ${action.detail || defaultPlaceholder}
          </div>
        </div>
      </div>` : detailText = `
      <div class="action-detail">
        <hr class="hsep">
        ${chip}
        ${editDetails}
        ${action.detail || defaultPlaceholder}
      </div>`, options != null && options.editable && (editor = `
    <div class="action-editor-wrapper">
      <a class="gen-control" data-uuid="${doc.uuid}" data-action="splice" data-path="${path}"><i class="fas fa-trash"></i></a>
      <a class="action-editor fas fa-edit" data-path="${path}"></a>
    </div>`), options != null && options.tags && doc instanceof LancerItem && doc.getTags() && (tags = compactTagListHBS("tags", spoofHelper({ tags: doc.getTags() }))), `
  <div class="action-wrapper">
    <div class="title-wrapper flexrow">
      ${actionTypeIcon(action.activation)}
      <span class="action-title collapse-trigger">
        ${((_a19 = action.name) == null ? void 0 : _a19.toUpperCase()) ?? doc.name}
      </span>
      ${editor ?? ""}
    </div>
    ${detailText ?? ""}
    ${tags ?? ""}
  </div>
  `;
}
__name(buildActionHTML, "buildActionHTML");
function buildActionArrayHTML(doc, path, options) {
  return resolveDotpath(doc, path, []).map((_, i) => buildActionHTML(doc, `${path}.${i}`, options)).join("");
}
__name(buildActionArrayHTML, "buildActionArrayHTML");
function buildDeployablesArrayHBS(item, array_path, helperOptions, options) {
  let lids = resolveDotpath(item, array_path, []), deps = {};
  return lids.forEach((lid) => {
    let dep = resolveHelperDotpath(helperOptions, `deployables.${lid}`);
    dep && (deps[lid] = dep);
  }), buildDeployablesArray(item, deps, options);
}
__name(buildDeployablesArrayHBS, "buildDeployablesArrayHBS");
function buildDeployablesArray(item, deployables, options) {
  let cards = [];
  for (const [lid, dep] of Object.entries(deployables))
    dep ? cards.push(
      buildDeployableHTML(
        dep,
        {
          item,
          path: `deployables.${lid}`
        },
        options
      )
    ) : cards.push(`<span>Unresolved deployabled LID "${lid}". Re-import + Set yourself as its owner</span>`);
  return cards.join("");
}
__name(buildDeployablesArray, "buildDeployablesArray");
function buildDeployableHTML(dep, source, options) {
  let detailText, chips = [], actionText, actionChips = [];
  return detailText = `
    <div class="deployable-detail">
      ${dep.system.detail}
    </div>`, [
    { label: "ACTIVATE", action: dep.system.activation },
    { label: "DEACTIVATE", action: dep.system.deactivation },
    { label: "RECALL", action: dep.system.recall },
    { label: "REDEPLOY", action: dep.system.redeploy }
  ].filter((a) => !!a.action).forEach((a) => {
    chips.push(
      buildChipHTML(
        a.action,
        {
          label: a.label,
          uuid: source ? source.item.uuid : void 0
          // path: a.path,
        },
        options
      )
    );
  }), dep.system.actions.length && (actionText = '<hr class="hsep">', dep.system.actions.forEach((_, i) => {
    actionText += buildActionHTML(dep, `system.actions.${i}`, {
      full: !0,
      nonInteractive: options == null ? void 0 : options.nonInteractive
    });
  })), `
  <div class="deployable-wrapper ref set ${options != null && options.vertical ? "vertical" : ""}" ${ref_params(dep)}>
    <img class="deployable-thumbnail" src="${encodeURI(dep.img)}">
    <div style="grid-area: title" class="title-wrapper">
      <span class="deployable-title click-open">
        ${dep.name ? dep.name.toUpperCase() : ""}
      </span>
      <hr class="hsep">
    </div>
    <div class="deployable-activations">
      <div class="flexcol">
        <div class="flexrow">
          ${chips.join(`</div>
<div class="flexrow">`)}
        </div>
      </div>
      ${options != null && options.vertical ? "" : '<hr class="vsep">'}
    </div>
    <div style="grid-area: desc">${detailText || ""}</div>
    ${actionText ? `
          <div style="grid-area: action">${actionText}</div>
          <div style="grid-area: action-chip">${actionChips.join(`
`)}</div>
          ` : ""}
  </div>
  `;
}
__name(buildDeployableHTML, "buildDeployableHTML");
function buildChipHTML(activation, flowData, options) {
  const activationClass = `activation-${slugify(activation, "-")}`, themeClass = activationStyle(activation), interactiveClass = options != null && options.nonInteractive ? "noninteractive" : "", label = `${flowData != null && flowData.label ? `${flowData.label.toUpperCase()} - ` : `${options != null && options.nonInteractive ? "" : "USE "}`}${activation.toUpperCase()}`;
  if (flowData && flowData.uuid && flowData.path !== void 0) {
    flowData.icon || (flowData.icon = `<i class="${activationIcon(activation)} i--sm"></i>`);
    let data2 = `data-uuid=${flowData.uuid} data-path="${flowData.path}"`;
    return `
    <a
      class="activation-flow lancer-button activation-chip ${activationClass} ${themeClass} ${interactiveClass}"
      ${data2}
    >
      ${flowData.icon ? flowData.icon : ""}
      ${label}
    </a>`;
  } else
    return `
    <div class="activation-chip ${activationClass} lancer-chip ${themeClass}">
      ${flowData != null && flowData.icon ? flowData.icon : ""}
      ${label}
    </div>`;
}
__name(buildChipHTML, "buildChipHTML");
function buildCounterHTML(data2, path, options) {
  let hexes = [...Array(data2.max)].map((_ele, index2) => {
    const available = index2 + 1 <= data2.value;
    return `<i class="counter-hex mdi ${available ? "mdi-hexagon-slice-6" : "mdi-hexagon-outline"} theme--light" data-available="${available}" data-path="${path}"></i>`;
  });
  return `
  <div class="card clipped-bot counter-wrapper" data-path="${path}">
    ${buildCounterHeader(data2, path, options)}
    <div class="flexrow flex-center no-wrap">
      <button class="clicker-minus-button hex" type="button">‒</button>
      ${hexes.join("")}
      <button class="clicker-plus-button hex" type="button">+</button>
    </div>
  </div>`;
}
__name(buildCounterHTML, "buildCounterHTML");
function buildCounterHeader(data2, path, options) {
  const contextMenu = options != null && options.noContextMenu ? "" : `<a class="lancer-context-menu" data-path="${path}" data-can-delete="${options != null && options.canDelete ? options.canDelete : !1}">
        <i class="fas fa-ellipsis-v"></i>
      </a>`;
  return `
    <div class="lancer-header lancer-primary">
      <span>// ${data2.name} //</span>
      ${contextMenu}
    </div>`;
}
__name(buildCounterHeader, "buildCounterHeader");
function buildCounterArrayHTML(counters, path, fully_editable) {
  let counter_detail = "", counter_arr;
  function isCounters(array2) {
    return !("counter" in array2[0]);
  }
  if (__name(isCounters, "isCounters"), counters.length > 0)
    if (isCounters(counters))
      for (let i = 0; i < counters.length; i++)
        counter_detail = counter_detail.concat(buildCounterHTML(counters[i], path.concat(`.${i}`)));
    else {
      counter_arr = counters.map((x) => x.counter);
      for (let i = 0; i < counters.length; i++)
        counter_detail = counter_detail.concat(buildCounterHTML(counter_arr[i], path.concat(`.${i}.counter`)));
    }
  return `
  <div class="card clipped double">
    <div class="lancer-header lancer-primary submajor ">
      COUNTERS
      <a class="gen-control fas fa-plus" data-action="append" data-path="${path}"
       data-action-value="(struct)counter"></a>
    </div>
    ${counter_detail}
  </div>`;
}
__name(buildCounterArrayHTML, "buildCounterArrayHTML");
function genericCounter(name2, data2, path) {
  const counterData = {
    name: name2,
    min: data2.min,
    max: data2.max,
    value: data2.value,
    default_value: data2.min,
    lid: ""
  };
  return buildCounterHTML(counterData, path, { noContextMenu: !0 });
}
__name(genericCounter, "genericCounter");
async function _updateCounterData(root_doc, path, delta) {
  let dd = drilldownDocument(root_doc, path);
  const counter = dd.terminus, min2 = counter.min || 0, max2 = counter.max || 6;
  let new_val = counter.value + delta;
  new_val < min2 && (new_val = min2), new_val > max2 && (new_val = max2), dd.sub_doc.update({ [dd.sub_path + ".value"]: new_val });
}
__name(_updateCounterData, "_updateCounterData");
function handleInputPlusMinusButtons(html, root_doc) {
  const mod_handler = /* @__PURE__ */ __name((delta) => async (evt) => {
    evt.stopPropagation();
    const elt = $(evt.currentTarget).siblings("input")[0], path = elt.name;
    if (path) {
      let dd = drilldownDocument(root_doc, path);
      dd.sub_doc.update({ [dd.sub_path]: elt.valueAsNumber + delta });
    }
  }, "mod_handler");
  html.find('button[class*="clicker-minus-button"].input-update').on("click", mod_handler(-1)), html.find('button[class*="clicker-plus-button"].input-update').on("click", mod_handler(1));
}
__name(handleInputPlusMinusButtons, "handleInputPlusMinusButtons");
function handleCounterInteraction(html, root_doc) {
  html.find(".counter-hex").on("click", async (evt) => {
    evt.stopPropagation();
    const elt = evt.currentTarget, path = elt.dataset.path, available = elt.dataset.available === "true";
    path && _updateCounterData(root_doc, path, available ? -1 : 1);
  });
  const mod_handler = /* @__PURE__ */ __name((delta) => async (evt) => {
    evt.stopPropagation();
    const path = $(evt.currentTarget).siblings(".counter-hex")[0].dataset.path;
    path && _updateCounterData(root_doc, path, delta);
  }, "mod_handler");
  html.find('button[class*="clicker-minus-button"].hex').on("click", mod_handler(-1)), html.find('button[class*="clicker-plus-button"].hex').on("click", mod_handler(1));
}
__name(handleCounterInteraction, "handleCounterInteraction");
function handlePowerUsesInteraction(html, doc) {
  html.find(".power-uses-hex").on("click", async (ev) => {
    ev.stopPropagation();
    const params = ev.currentTarget.dataset;
    if (params.path) {
      const pathParts = params.path.split("."), powerIndex = parseInt(pathParts[pathParts.length - 1]), item = drilldownDocument(doc, params.path).sub_doc, power = item.system.powers[powerIndex], available = params.available === "true";
      if (!item || !power || !power.uses)
        return;
      let newUses = power.uses.value;
      available ? newUses = Math.max(newUses - 1, power.uses.min) : newUses = Math.min(newUses + 1, power.uses.max), item.update({ [`system.powers.${powerIndex}.uses.value`]: newUses });
    }
  });
}
__name(handlePowerUsesInteraction, "handlePowerUsesInteraction");
function handleContextMenus(html, doc, view_only = !1) {
  _handleContextMenus(html, ".lancer-context-menu", "click", doc, view_only), _handleContextMenus(html, ".weapon-profile-tab", "contextmenu", doc, view_only), _handleContextMenus(html, ".tag-list-append > .editable-tag-instance.compact-tag", "contextmenu", doc, view_only);
}
__name(handleContextMenus, "handleContextMenus");
function _handleContextMenus(html, selector, event, doc, view_only) {
  const path = /* @__PURE__ */ __name((html2) => html2[0].dataset.path || null, "path"), dd = /* @__PURE__ */ __name((html2) => path(html2) ? drilldownDocument(doc, path(html2)) : null, "dd");
  let all = [
    {
      name: view_only ? "View" : "Edit",
      icon: view_only ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-edit"></i>',
      callback: (html2) => {
        var _a19;
        const uuid = html2.closest(".set")[0].dataset.uuid;
        let found_doc = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        if (found_doc) {
          let sheet = found_doc.sheet;
          sheet != null && sheet.rendered ? sheet.maximize().then(() => sheet.bringToTop()) : sheet == null || sheet.render(!0);
        }
      },
      condition: (html2) => {
        var _a19;
        return ((_a19 = dd(html2)) == null ? void 0 : _a19.terminus) instanceof foundry.abstract.Document;
      }
    },
    {
      name: view_only ? "View" : "Edit",
      icon: view_only ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-edit"></i>',
      callback: (html2) => {
        const uuid = html2[0].dataset.uuid;
        if (!uuid)
          return;
        let found_doc = fromUuidSync(uuid);
        if (found_doc) {
          let sheet = found_doc.sheet;
          sheet != null && sheet.rendered ? sheet.maximize().then(() => sheet.bringToTop()) : sheet == null || sheet.render(!0);
        }
      },
      // Normal edit is not visible, and this item has a uuid.
      condition: (html2) => {
        const uuid = html2[0].dataset.uuid;
        return uuid ? fromUuidSync(uuid) instanceof LancerItem : !1;
      }
    },
    {
      name: view_only ? "View" : "Edit",
      icon: view_only ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-edit"></i>',
      callback: (html2) => {
        let effects = [...doc.allApplicableEffects()], index2 = parseInt(html2[0].dataset.activeEffectIndex ?? "-1");
        if (effects[index2]) {
          let sheet = effects[index2].sheet;
          sheet != null && sheet.rendered ? sheet.maximize().then(() => sheet.bringToTop()) : sheet == null || sheet.render(!0);
        }
      },
      condition: (html2) => html2[0].dataset.activeEffectIndex != null
    },
    {
      name: "Edit",
      icon: '<i class="fas fa-edit"></i>',
      callback: (html2) => {
        CounterEditForm.edit(doc, path(html2));
      },
      condition: (html2) => {
        var _a19, _b, _c;
        return !view_only && (!!((_a19 = path(html2)) != null && _a19.includes("counters")) || !!((_b = path(html2)) != null && _b.includes("burdens")) || !!((_c = path(html2)) != null && _c.includes("clocks")));
      }
      // Crude but effective
    },
    {
      name: "Edit",
      icon: '<i class="fas fa-edit"></i>',
      callback: (html2) => {
        TagEditForm.edit(doc, path(html2));
      },
      condition: (html2) => {
        const p = path(html2);
        return !view_only && !(p != null && p.includes("system.loadout")) && !(p != null && p.includes("itemTypes")) && !(p != null && p.includes("system.base_features")) && !(p != null && p.includes("system.optional_features")) && !!(p != null && p.includes("tags"));
      }
    },
    {
      name: "Mark Repaired",
      icon: '<i class="fas fa-fw fa-wrench"></i>',
      callback: (html2) => {
        var _a19;
        const uuid = html2.closest(".set")[0].dataset.uuid;
        let item = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        item == null || item.update({ "system.destroyed": !item.system.destroyed });
      },
      condition: (html2) => {
        var _a19;
        const refElement = html2.closest(".set")[0];
        if (!refElement)
          return !1;
        const uuid = refElement.dataset.uuid;
        let item = null;
        try {
          item = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        } catch {
        }
        return !view_only && item instanceof LancerItem && (item.is_mech_system() || item.is_mech_weapon() || item.is_npc_feature()) && item.system.destroyed;
      }
    },
    {
      name: "Mark Destroyed",
      icon: '<i class="cci cci-eclipse"></i>',
      callback: (html2) => {
        var _a19;
        const uuid = html2.closest(".set")[0].dataset.uuid;
        let item = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        item == null || item.update({ "system.destroyed": !item.system.destroyed });
      },
      condition: (html2) => {
        var _a19;
        const refElement = html2.closest(".set")[0];
        if (!refElement)
          return !1;
        const uuid = refElement.dataset.uuid;
        let item = null;
        try {
          item = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        } catch {
        }
        return !view_only && item instanceof LancerItem && (item.is_mech_system() || item.is_mech_weapon() || item.is_npc_feature()) && !item.system.destroyed;
      }
    },
    {
      name: "Rename",
      icon: '<i class="fas fa-fw fa-edit"></i>',
      callback: async (html2) => {
        let full_path = path(html2) + html2[0].dataset.renameSubpath, old_val = drilldownDocument(doc, full_path).terminus, new_val = await promptText("Rename profile", old_val);
        new_val && doc.update({
          [full_path]: new_val
        });
      },
      condition: (html2) => {
        var _a19;
        return !!(!view_only && html2[0].dataset.renameSubpath && ((_a19 = dd(html2)) != null && _a19.terminus));
      }
    },
    {
      name: "Remove",
      icon: '<i class="fas fa-fw fa-trash"></i>',
      callback: (html2) => {
        let dd_ = dd(html2);
        if (dd_) {
          let change = array_path_edit_changes(dd_.sub_doc, dd_.sub_path, null, "delete");
          dd_.sub_doc.update({ [change.path]: change.new_val });
        }
      },
      condition: (html2) => {
        let p = path(html2);
        return !!(!view_only && (!(p != null && p.includes("system.loadout")) && !(p != null && p.includes("itemTypes")) && !(p != null && p.includes("system.base_features")) && !(p != null && p.includes("system.optional_features")) && (p != null && p.includes("tags")) || p != null && p.includes("counters") || p != null && p.includes("bond_state.burdens") || p != null && p.includes("bond_state.clocks") || p != null && p.substring(0, p.length - 2).endsWith("profiles")));
      }
    },
    {
      name: "Delete Document",
      icon: '<i class="fas fa-fw fa-trash"></i>',
      callback: async (html2) => {
        var _a19;
        const uuid = html2.closest(".set")[0].dataset.uuid;
        let item = null;
        try {
          item = uuid ? fromUuidSync(uuid) : (_a19 = dd(html2)) == null ? void 0 : _a19.terminus;
        } catch {
        }
        item instanceof LancerItem && doc instanceof LancerActor && doc.removeClassFeatures(item), item == null || item.delete();
      },
      condition: (html2) => {
        var _a19;
        return !view_only && ((_a19 = dd(html2)) == null ? void 0 : _a19.terminus) instanceof foundry.abstract.Document;
      }
    },
    {
      name: "Unlink",
      icon: '<i class="fas fa-times"></i>',
      callback: async (html2) => {
        doc.update({ [path(html2)]: null });
      },
      condition: (html2) => {
        if (view_only)
          return !1;
        let p = path(html2);
        return !!((p != null && p.startsWith("system.base_features") || p != null && p.startsWith("system.optional_features")) && !(p != null && p.includes("system.tags")));
      }
    }
  ];
  tippyContextMenu(html.find(selector), event, all);
}
__name(_handleContextMenus, "_handleContextMenus");
function registerActivationSteps(flowSteps) {
  flowSteps.set("initActivationData", initActivationData), flowSteps.set("printActionUseCard", printActionUseCard);
}
__name(registerActivationSteps, "registerActivationSteps");
const _ActivationFlow = class _ActivationFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "action",
      title: (data2 == null ? void 0 : data2.title) || "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) || "",
      acc: (data2 == null ? void 0 : data2.acc) || 0,
      action_path: (data2 == null ? void 0 : data2.action_path) || "",
      action: (data2 == null ? void 0 : data2.action) || null,
      self_heat: (data2 == null ? void 0 : data2.self_heat) || void 0,
      detail: (data2 == null ? void 0 : data2.detail) || "",
      tags: (data2 == null ? void 0 : data2.tags) || []
    };
    super(uuid, initialData);
  }
};
__name(_ActivationFlow, "ActivationFlow");
let ActivationFlow = _ActivationFlow;
ActivationFlow.steps = [
  // TODO: if a system or action is not provided, prompt the user to select one?
  // Or would it be better to have a separate UI for that before the flow starts?
  "initActivationData",
  "checkItemDestroyed",
  "checkItemLimited",
  "checkItemCharged",
  // Does anything need to be done here?
  // TODO: template placer for grenades?
  // TODO: damage roller for grenades and mines?
  // TODO: parse detail for save prompts?
  "applySelfHeat",
  "updateItemAfterAction",
  // TODO: deduct action from actor's action tracker
  "printActionUseCard"
];
async function initActivationData(state, options) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Activation flow state missing!");
  if (state.item) {
    if (state.data.action_path = (options == null ? void 0 : options.action_path) || state.data.action_path || "system.actions.0", !state.data.action) {
      if (state.data.action = resolveDotpath(state.item, state.data.action_path), !state.data.action)
        throw new Error(`Failed to resolve action ${state.data.action_path}`);
      state.data.title = (_a19 = state.data.action) == null ? void 0 : _a19.name;
    }
    state.data.title = (options == null ? void 0 : options.title) || state.data.title || ((_b = state.data.action) == null ? void 0 : _b.name) || state.item.name || "UNKNOWN ACTION";
    let detail_text = state.data.detail || "";
    !detail_text && state.data.action && (state.data.action.init && (detail_text += `<p><b>INIT</b></p><p>${state.data.action.init}</p>`), state.data.action.trigger && (detail_text += `<p><b>TRIGGER</b></p><p>${state.data.action.trigger}</p>`), detail_text ? detail_text += `<p><b>EFFECT</b></p><p>${state.data.action.detail}</p>` : detail_text += state.data.action.detail || ""), state.data.detail = detail_text, state.data.tags = state.item.getTags() ?? [];
    const selfHeatTags = state.data.tags.filter((t) => t.is_selfheat);
    return selfHeatTags && selfHeatTags.length && (state.data.self_heat = selfHeatTags[0].val), state.data.action.tech_attack || state.data.action.activation == ActivationType.Invade ? (new TechAttackFlow(state.item, {
      title: state.data.title,
      invade: state.data.action.activation == ActivationType.Invade,
      attack_type: AttackType.Tech,
      action: state.data.action,
      effect: state.data.action.detail,
      tags: state.item.is_mech_system() || state.item.is_mech_system() || state.item.is_npc_feature() ? state.item.system.tags : []
    }).begin(), !1) : !0;
  } else
    return !1;
}
__name(initActivationData, "initActivationData");
async function printActionUseCard(state, options) {
  var _a19, _b, _c;
  if (!state.data)
    throw new TypeError("Activation flow state missing!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/activation-card.hbs`, flags = {
    actionData: {
      actor: state.actor.id,
      system: ((_a19 = state.item) == null ? void 0 : _a19.id) || void 0,
      action: state.data.action
    }
  };
  let data2 = {
    title: state.data.title,
    action_chip: state.data.action ? buildChipHTML(state.data.action.activation, {}) : "",
    description: state.data.detail,
    roll: (_b = state.data.self_heat_result) == null ? void 0 : _b.roll,
    roll_tt: (_c = state.data.self_heat_result) == null ? void 0 : _c.tt,
    roll_icon: "cci cci-heat i--m damage--heat",
    tags: state.data.tags
  };
  return await renderTemplateStep(state.actor, template, data2, flags), !0;
}
__name(printActionUseCard, "printActionUseCard");
const lp$d = LANCER.log_prefix;
function registerCoreActiveSteps(flowSteps) {
  flowSteps.set("checkCorePower", checkCorePower), flowSteps.set("consumeCorePower", consumeCorePower);
}
__name(registerCoreActiveSteps, "registerCoreActiveSteps");
const _CoreActiveFlow = class _CoreActiveFlow extends ActivationFlow {
  constructor(uuid, data2) {
    super(uuid, data2);
  }
};
__name(_CoreActiveFlow, "CoreActiveFlow");
let CoreActiveFlow = _CoreActiveFlow;
CoreActiveFlow.steps = [
  "initActivationData",
  "checkItemDestroyed",
  "checkItemLimited",
  "checkItemCharged",
  "checkCorePower",
  "applySelfHeat",
  "updateItemAfterAction",
  "consumeCorePower",
  // TODO: deduct action from actor's action tracker
  "printActionUseCard"
];
async function checkCorePower(state) {
  if (!state.actor || !state.actor.is_mech())
    throw new TypeError("Cannot consume core power on a non-mech!");
  return state.actor.system.core_energy == 0 ? (ui.notifications.warn("No core power remaining on this frame!"), !1) : !0;
}
__name(checkCorePower, "checkCorePower");
async function consumeCorePower(state) {
  if (!state.actor || !state.actor.is_mech())
    throw new TypeError("Cannot consume core power on a non-mech!");
  state.actor.update({ "system.core_energy": 0 }), console.log(`${lp$d} Automatically consumed core power for ${state.actor.system.lid}`);
}
__name(consumeCorePower, "consumeCorePower");
function registerStatSteps(flowSteps) {
  flowSteps.set("initStatRollData", initStatRollData), flowSteps.set("showStatRollHUD", showStatRollHUD), flowSteps.set("rollCheck", rollCheck), flowSteps.set("printStatRollCard", printStatRollCard);
}
__name(registerStatSteps, "registerStatSteps");
const _StatRollFlow = class _StatRollFlow extends Flow {
  constructor(uuid, data2) {
    const state = {
      type: "stat",
      title: (data2 == null ? void 0 : data2.title) ?? "",
      path: (data2 == null ? void 0 : data2.path) ?? "system.hull",
      // We need to pick some kind of default
      bonus: (data2 == null ? void 0 : data2.bonus) ?? 0,
      acc_diff: (data2 == null ? void 0 : data2.acc_diff) ?? void 0,
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "1d20",
      effect: (data2 == null ? void 0 : data2.effect) ?? void 0
    };
    !state.title && uuid instanceof LancerItem && (state.title = uuid.name), super(uuid, state);
  }
};
__name(_StatRollFlow, "StatRollFlow");
let StatRollFlow = _StatRollFlow;
StatRollFlow.steps = ["initStatRollData", "showStatRollHUD", "rollCheck", "printStatRollCard"];
async function initStatRollData(state, options) {
  if (!state.data)
    throw new TypeError("Stat roll flow state missing!");
  if (state.item) {
    if (!state.item.is_skill())
      throw new TypeError("Invalid item for stat roll flow!");
    if (!state.actor.is_pilot())
      throw new TypeError("Non-pilots can't roll skill triggers!");
    return state.data.title = (options == null ? void 0 : options.title) || state.data.title || state.item.name, state.data.path = "system.curr_rank", state.data.bonus = state.item.system.curr_rank * 2, state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(state.actor, void 0, state.data.title), !0;
  } else {
    let pathParts = state.data.path.split(".");
    return state.data.title = (options == null ? void 0 : options.title) || state.data.title || pathParts[pathParts.length - 1].toUpperCase(), state.data.bonus = resolveDotpath(state.actor, state.data.path), state.data.acc_diff = options != null && options.acc_diff ? AccDiffHudData.fromObject(options.acc_diff) : AccDiffHudData.fromParams(state.actor, void 0, state.data.title), state.data.effect = void 0, !0;
  }
}
__name(initStatRollData, "initStatRollData");
async function showStatRollHUD(state) {
  if (!state.data)
    throw new TypeError("Stat roll flow state missing!");
  try {
    state.data.acc_diff = await openSlidingHud("hase", state.data.acc_diff);
  } catch {
    return !1;
  }
  let acc_str = state.data.acc_diff.base.total != 0 ? ` + ${state.data.acc_diff.base.total}d6kh1` : "";
  return state.data.roll_str = `1d20+${state.data.bonus || 0}${acc_str}`, !0;
}
__name(showStatRollHUD, "showStatRollHUD");
async function rollCheck(state) {
  if (!state.data)
    throw new TypeError("Stat roll flow state missing!");
  if (!state.data.acc_diff)
    throw new TypeError("Stat roll acc/diff data missing!");
  let roll = await new Roll(state.data.roll_str).evaluate();
  return state.data.result = {
    roll,
    tt: await roll.getTooltip()
  }, !0;
}
__name(rollCheck, "rollCheck");
async function printStatRollCard(state) {
  if (!state.data)
    throw new TypeError("Stat roll flow state missing!");
  const template = `systems/${game.system.id}/templates/chat/stat-roll-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printStatRollCard, "printStatRollCard");
function registerSystemSteps(flowSteps) {
  flowSteps.set("initSystemUseData", initSystemUseData), flowSteps.set("printSystemCard", printSystemCard);
}
__name(registerSystemSteps, "registerSystemSteps");
const _SystemFlow = class _SystemFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      title: (data2 == null ? void 0 : data2.title) || "",
      type: (data2 == null ? void 0 : data2.type) || null,
      effect: (data2 == null ? void 0 : data2.effect) || "",
      tags: (data2 == null ? void 0 : data2.tags) || void 0
    };
    super(uuid, initialData);
  }
};
__name(_SystemFlow, "SystemFlow");
let SystemFlow = _SystemFlow;
SystemFlow.steps = [
  "initSystemUseData",
  "checkItemDestroyed",
  "checkItemLimited",
  "checkItemCharged",
  // TODO: check for targets and prompt for saves
  // "setSaveTargets",
  // "rollSaves",
  "applySelfHeat",
  "updateItemAfterAction",
  "printSystemCard"
];
async function initSystemUseData(state) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  if (!state.item || !state.item.is_mech_system() && !state.item.is_weapon_mod() && !state.item.is_npc_feature())
    throw new TypeError("Only mech systems, mods, and NPC features can do system flows!");
  state.data.title = state.data.title || state.item.name, state.data.type || (state.item.is_mech_system() ? state.data.type = SystemType.System : state.item.is_weapon_mod() ? state.data.type = SystemType.Mod : state.data.type = state.item.system.type), !state.data.effect && state.item.is_npc_feature() ? state.item.system.type === NpcFeatureType.Reaction ? state.data.effect = `<p><b>TRIGGER</b></p><p>${state.item.system.trigger}</p><p><b>EFFECT</b></p><p>${state.item.system.effect}</p>` : state.data.effect = state.item.system.effect : state.data.effect = state.data.effect || state.item.system.effect, state.data.tags = state.data.tags || state.item.system.tags;
  const selfHeat = state.item.system.tags.find((t) => t.is_selfheat);
  return selfHeat && (state.data.self_heat = selfHeat.val || "1"), !0;
}
__name(initSystemUseData, "initSystemUseData");
async function printSystemCard(state, options) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  if (!state.item || !state.item.is_mech_system() && !state.item.is_weapon_mod() && !state.item.is_npc_feature())
    throw new TypeError("Only mech systems, mods, and NPC features can do system flows!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/system-card.hbs`, flags = {
    // TODO: forced save data here
    // attackData: {
    //   origin: state.actor.id,
    //   targets: state.data.attack_rolls.targeted.map(t => {
    //     return { id: t.target.id, setConditions: !!t.usedLockOn ? { lockon: !t.usedLockOn } : undefined };
    //   }),
    // },
  };
  return await renderTemplateStep(state.actor, template, state.data, flags), !0;
}
__name(printSystemCard, "printSystemCard");
const _AppliedDamage = class _AppliedDamage {
  constructor(damageData) {
    this.Kinetic = this.sum_damage(damageData, DamageType.Kinetic), this.Energy = this.sum_damage(damageData, DamageType.Energy), this.Explosive = this.sum_damage(damageData, DamageType.Explosive), this.Burn = this.sum_damage(damageData, DamageType.Burn), this.Heat = this.sum_damage(damageData, DamageType.Heat), this.Variable = this.sum_damage(damageData, DamageType.Variable);
  }
  sum_damage(damageData, damageType) {
    return damageData.reduce((sum, d) => sum + (d.type === damageType ? parseInt(d.val) : 0), 0);
  }
};
__name(_AppliedDamage, "AppliedDamage");
let AppliedDamage = _AppliedDamage;
var __accessCheck$4 = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck$4"), __privateGet = /* @__PURE__ */ __name((obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)), "__privateGet"), __privateAdd$4 = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd$4"), __privateSet = /* @__PURE__ */ __name((obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value), "__privateSet"), _data, _weapon, _weapon2, _base, HitQuality = /* @__PURE__ */ ((HitQuality2) => (HitQuality2[HitQuality2.Miss = 0] = "Miss", HitQuality2[HitQuality2.Hit = 1] = "Hit", HitQuality2[HitQuality2.Crit = 2] = "Crit", HitQuality2))(HitQuality || {});
union([literal(0), literal(1), literal(2)]);
function ensureDamageType(d) {
  return {
    type: Object.keys(DamageType).includes(d.type) ? d.type : DamageType.Kinetic,
    val: d.val
  };
}
__name(ensureDamageType, "ensureDamageType");
var _a8;
const _DamageHudWeapon = (_a8 = class {
  constructor(obj) {
    __privateAdd$4(this, _data, void 0);
    const objectDamage = obj.damage.map(ensureDamageType), objBonusDamage = obj.bonusDamage.map(ensureDamageType);
    this.damage = objectDamage, this.bonusDamage = objBonusDamage, this.reliable = obj.reliable, this.reliableValue = obj.reliableValue, this.overkill = obj.overkill, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      // TODO: how do you define an io-ts array schema using a TS type?
      // `type` should be a DamageType
      damage: array(type({ type: string, val: string })),
      bonusDamage: array(type({ type: string, val: string })),
      reliable: boolean,
      reliableValue: number,
      overkill: boolean,
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a8);
  }
  get raw() {
    return {
      damage: this.damage,
      bonusDamage: this.bonusDamage,
      reliable: this.reliable,
      reliableValue: this.reliableValue,
      overkill: this.overkill,
      plugins: this.plugins
    };
  }
  // TODO: refactor to damage specs
  // total(cover: number) {
  //   return (this.accurate ? 1 : 0) - (this.inaccurate ? 1 : 0) - (this.seeking ? 0 : cover) - (this.impaired ? 1 : 0);
  // }
  hydrate(d) {
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d);
    __privateSet(this, _data, d);
  }
  get total() {
    return { damage: this.damage, bonusDamage: this.bonusDamage };
  }
  static parseReliableVal(tag, source) {
    var _a19;
    if (!tag.val)
      return 0;
    let tier = 1;
    source && (source instanceof LancerItem && ((_a19 = source.actor) != null && _a19.is_npc()) ? tier = source.actor.system.tier : source instanceof LancerActor && source.is_npc() && (tier = source.system.tier));
    const tierValNum = parseInt(tag.tierVal(tier));
    return Number.isNaN(tierValNum) ? 0 : tierValNum;
  }
}, __name(_a8, "_DamageHudWeapon"), _a8);
_data = /* @__PURE__ */ new WeakMap();
_DamageHudWeapon.pluginSchema = {};
let DamageHudWeapon = _DamageHudWeapon;
var _a9;
const _DamageHudBase = (_a9 = class {
  constructor(obj) {
    __privateAdd$4(this, _weapon, void 0);
    const objectDamage = obj.damage.map(ensureDamageType), objBonusDamage = obj.bonusDamage.map(ensureDamageType);
    this.ap = obj.ap, this.paracausal = obj.paracausal, this.halfDamage = obj.halfDamage, this.damage = objectDamage, this.bonusDamage = objBonusDamage, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      ap: boolean,
      paracausal: boolean,
      halfDamage: boolean,
      // TODO: how do you define an io-ts array schema using a TS type?
      // `type` should be a DamageType
      damage: array(type({ type: string, val: string })),
      bonusDamage: array(type({ type: string, val: string })),
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a9);
  }
  get raw() {
    return {
      ap: this.ap,
      paracausal: this.paracausal,
      halfDamage: this.halfDamage,
      damage: this.damage,
      bonusDamage: this.bonusDamage,
      plugins: this.plugins
    };
  }
  hydrate(d) {
    __privateSet(this, _weapon, d.weapon);
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d, this);
  }
  get total() {
    var _a19;
    const weaponTotal = ((_a19 = __privateGet(this, _weapon)) == null ? void 0 : _a19.total) || { damage: [], bonusDamage: [] };
    return {
      damage: weaponTotal.damage.concat(this.damage),
      bonusDamage: weaponTotal.bonusDamage.concat(this.bonusDamage)
    };
  }
}, __name(_a9, "_DamageHudBase"), _a9);
_weapon = /* @__PURE__ */ new WeakMap();
_DamageHudBase.pluginSchema = {};
let DamageHudBase = _DamageHudBase;
var _a10;
const _DamageHudTarget = (_a10 = class {
  constructor(obj) {
    __privateAdd$4(this, _weapon2, void 0), __privateAdd$4(this, _base, void 0);
    let target = canvas.scene.tokens.get(obj.target_id);
    if (!target)
      throw ui.notifications.error("Trying to access tokens from a different scene!"), new Error("Token not found");
    const objBonusDamage = obj.bonusDamage.map(ensureDamageType);
    this.target = target.object, this.quality = obj.quality, this.ap = obj.ap, this.paracausal = obj.paracausal, this.halfDamage = obj.halfDamage, this.bonusDamage = objBonusDamage, this.plugins = obj.plugins;
  }
  static get schema() {
    return {
      target_id: string,
      quality: number,
      ap: boolean,
      paracausal: boolean,
      halfDamage: boolean,
      bonusDamage: array(type({ type: string, val: string })),
      plugins: type(this.pluginSchema)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a10);
  }
  get raw() {
    return {
      target_id: this.target.id,
      quality: this.quality,
      ap: this.ap,
      paracausal: this.paracausal,
      halfDamage: this.halfDamage,
      bonusDamage: this.bonusDamage,
      plugins: this.plugins
    };
  }
  static fromParams(t2, data2) {
    let ret = {
      target_id: t2.id,
      quality: (data2 == null ? void 0 : data2.quality) ?? 1,
      ap: (data2 == null ? void 0 : data2.ap) || !1,
      paracausal: (data2 == null ? void 0 : data2.paracausal) || !1,
      halfDamage: (data2 == null ? void 0 : data2.halfDamage) || !1,
      bonusDamage: (data2 == null ? void 0 : data2.bonusDamage) || [],
      plugins: {}
    };
    for (let plugin of DamageHudData.targetedPlugins)
      ret.plugins[plugin.slug] = encode(plugin.perTarget(t2), plugin.codec);
    return decode(ret, _a10.codec);
  }
  hydrate(d) {
    __privateSet(this, _weapon2, d.weapon), __privateSet(this, _base, d.base);
    for (let key of Object.keys(this.plugins))
      this.plugins[key].hydrate(d, this);
  }
  get total() {
    const baseTotal = __privateGet(this, _base).total;
    return {
      damage: baseTotal,
      bonusDamage: this.bonusDamage.concat(baseTotal.bonusDamage)
    };
  }
}, __name(_a10, "_DamageHudTarget"), _a10);
_weapon2 = /* @__PURE__ */ new WeakMap();
_base = /* @__PURE__ */ new WeakMap();
_DamageHudTarget.pluginSchema = {};
let DamageHudTarget = _DamageHudTarget;
const _DamageHudHitResult = class _DamageHudHitResult {
  static get schema() {
    return {
      target: string,
      total: string,
      usedLockOn: boolean,
      hit: boolean,
      crit: boolean
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _DamageHudHitResult);
  }
  constructor(obj) {
    this.target = obj.target, this.total = obj.total, this.usedLockOn = obj.usedLockOn, this.hit = obj.hit, this.crit = obj.crit;
  }
  get raw() {
    return {
      target: this.target,
      total: this.total,
      usedLockOn: this.usedLockOn,
      hit: this.hit,
      crit: this.crit
    };
  }
};
__name(_DamageHudHitResult, "DamageHudHitResult");
let DamageHudHitResult = _DamageHudHitResult;
var _a11;
const _DamageHudData = (_a11 = class {
  // not persisted, needs to be hydrated
  static get schema() {
    return {
      title: string,
      weapon: union([DamageHudWeapon.codec, undefinedType]),
      base: DamageHudBase.codec,
      hitResults: array(DamageHudHitResult.codec),
      targets: array(DamageHudTarget.codec)
    };
  }
  static get schemaCodec() {
    return type(this.schema);
  }
  static get codec() {
    return enclass(this.schemaCodec, _a11);
  }
  constructor(obj) {
    this.title = obj.title, this.weapon = obj.weapon || void 0, this.base = obj.base, this.hitResults = obj.hitResults, this.targets = obj.targets, this.hydrate();
  }
  hydrate(runtimeData) {
    var _a19;
    runtimeData instanceof LancerItem ? (this.lancerItem = runtimeData, this.lancerActor = runtimeData.actor ?? void 0) : this.lancerActor = runtimeData ?? void 0, (_a19 = this.weapon) == null || _a19.hydrate(this), this.base.hydrate(this);
    for (let target of this.targets)
      target.hydrate(this);
  }
  replaceTargets(ts) {
    let oldTargets = {};
    for (let data2 of this.targets)
      oldTargets[data2.target.id] = data2;
    this.targets = ts.map(
      (t2) => oldTargets[t2.id] ?? DamageHudTarget.fromParams(t2, { quality: this.getHitQuality(t2) })
    );
    for (let target of this.targets)
      target.hydrate(this);
    return this;
  }
  get raw() {
    return {
      title: this.title,
      weapon: this.weapon,
      base: this.base,
      hitResults: this.hitResults,
      targets: this.targets
    };
  }
  // Decode from a serialized object, optionally populating remaining data from an item
  static fromObject(obj, runtimeData) {
    let ret = decode(obj, _a11.codec);
    return ret.hydrate(runtimeData), ret;
  }
  toObject() {
    return encode(this, _a11.codec);
  }
  static registerPlugin(plugin) {
    plugin.perRoll && (DamageHudWeapon.pluginSchema[plugin.slug] = plugin.codec), plugin.perUnknownTarget && (DamageHudBase.pluginSchema[plugin.slug] = plugin.codec), plugin.perTarget && (DamageHudTarget.pluginSchema[plugin.slug] = plugin.codec, this.targetedPlugins.push(plugin)), this.plugins.push(plugin);
  }
  static getHitQuality(t2, hitResults) {
    if (!hitResults || !hitResults.length)
      return 1;
    const hit = (hitResults || []).find((hr) => hr.target === t2.document.uuid);
    return hit ? hit.crit ? 2 : hit.hit ? 1 : 0 : 1;
  }
  getHitQuality(t2) {
    return _a11.getHitQuality(t2, this.hitResults);
  }
  static fromParams(runtimeData, data2) {
    var _a19, _b;
    let weapon = {
      damage: [],
      bonusDamage: [],
      reliable: !1,
      reliableValue: 0,
      overkill: !1,
      plugins: {}
    }, base = {
      ap: (data2 == null ? void 0 : data2.ap) ?? !1,
      paracausal: (data2 == null ? void 0 : data2.paracausal) ?? !1,
      halfDamage: (data2 == null ? void 0 : data2.halfDamage) ?? !1,
      damage: ((_a19 = data2 == null ? void 0 : data2.starting) == null ? void 0 : _a19.damage) ?? [],
      bonusDamage: ((_b = data2 == null ? void 0 : data2.starting) == null ? void 0 : _b.bonusDamage) ?? [],
      plugins: {}
    };
    for (let tag of (data2 == null ? void 0 : data2.tags) || [])
      switch (tag.lid) {
        case "tg_ap":
          base.ap = !0;
          break;
        case "tg_overkill":
          weapon.overkill = !0;
          break;
        case "tg_reliable":
          weapon.reliable = !0, weapon.reliableValue = DamageHudWeapon.parseReliableVal(tag, runtimeData);
      }
    if (runtimeData instanceof LancerItem)
      if (runtimeData.is_mech_weapon()) {
        const profile = runtimeData.system.active_profile;
        weapon.damage = profile.damage, weapon.bonusDamage = profile.bonus_damage;
      } else if (runtimeData.is_npc_feature() && runtimeData.system.type === NpcFeatureType.Weapon) {
        const actor = runtimeData.actor, tier = ((actor == null ? void 0 : actor.system.tier) || 1) - 1;
        weapon.damage = runtimeData.system.damage[tier];
      } else
        runtimeData.is_pilot_weapon() && (weapon.damage = runtimeData.system.damage);
    const hitResults = ((data2 == null ? void 0 : data2.hitResults) || []).map(
      (hr) => new DamageHudHitResult({ ...hr, target: hr.target.document.uuid })
    );
    let obj = {
      title: data2 != null && data2.title ? data2.title : "Damage Roll",
      weapon,
      base,
      hitResults,
      targets: ((data2 == null ? void 0 : data2.targets) || []).map((t2) => {
        let ret = {
          target_id: t2.id,
          quality: _a11.getHitQuality(t2, hitResults),
          ap: base.ap,
          paracausal: base.paracausal,
          halfDamage: base.halfDamage,
          bonusDamage: [],
          plugins: {}
        };
        for (let plugin of this.targetedPlugins)
          ret.plugins[plugin.slug] = encode(plugin.perTarget(t2), plugin.codec);
        return ret;
      })
    };
    for (let plugin of this.plugins)
      plugin.perRoll && obj.weapon && (obj.weapon.plugins[plugin.slug] = encode(plugin.perRoll(runtimeData), plugin.codec)), plugin.perUnknownTarget && (obj.base.plugins[plugin.slug] = encode(plugin.perUnknownTarget(), plugin.codec));
    return _a11.fromObject(obj, runtimeData);
  }
}, __name(_a11, "_DamageHudData"), _a11);
_DamageHudData.plugins = [];
_DamageHudData.targetedPlugins = [];
let DamageHudData = _DamageHudData;
function cubesBySize({
  size,
  alt,
  columns
}) {
  if (size = Math.ceil(size), size % 2 === 1) {
    let l = Math.floor(size / 2), res = [];
    for (let q = -l; q <= l; ++q)
      for (let r = Math.max(-l, -q - l); r <= Math.min(l, -q + l); ++r)
        res.push({ q, r, s: -q - r });
    return res;
  } else
    return cubesBySize({ size: size + 1, alt, columns }).filter((c) => !(c.r >= 0 && (Math.abs(c.q) + Math.abs(c.r) + Math.abs(c.s)) / 2 === size / 2)).map((c) => !alt && !columns ? c : !alt && columns ? { q: c.r, r: c.s, s: c.q } : alt && columns ? { q: -c.r, r: -c.s, s: -c.q } : { q: -c.q, r: -c.r, s: -c.s });
}
__name(cubesBySize, "cubesBySize");
function altOrientation(token) {
  return (token.document.hexagonalShape & 1) === 1;
}
__name(altOrientation, "altOrientation");
const _LancerTokenDocument = class _LancerTokenDocument extends TokenDocument {
  async _preCreate(...[data2, options, user]) {
    var _a19;
    if (game.settings.get(game.system.id, LANCER.setting_automation).token_size && // @ts-expect-error Figure out how to define flags
    !this.getFlag(game.system.id, "manual_token_size")) {
      const new_size = Math.max(1, ((_a19 = this.actor) == null ? void 0 : _a19.system.size) ?? 1);
      this.updateSource({ width: new_size, height: new_size });
    }
    return super._preCreate(data2, options, user);
  }
  _onRelatedUpdate(update, options) {
    if (super._onRelatedUpdate(update, options), game.settings.get(game.system.id, LANCER.setting_automation).token_size && // @ts-expect-error Figure out how to define flags
    !this.getFlag(game.system.id, "manual_token_size")) {
      let new_size = this.actor ? Math.max(1, this.actor.system.size) : void 0;
      this.isOwner && this.id && new_size !== void 0 && (this.width !== new_size || this.height !== new_size) && this.update({ width: new_size, height: new_size });
    }
  }
  /**
   * Calculate the range between this and other, accounting for occupied spaces
   * and size
   * @param other   Target to check against
   * @returns The range in grid units.
   */
  computeRange(other) {
    var _a19;
    const grid = ((_a19 = this.parent) == null ? void 0 : _a19.grid) ?? canvas.grid;
    if (!grid || !canvas.ready)
      throw new Error("Canvas not ready");
    if (!this.object || !other.object)
      throw new Error("Tokens not drawn to canvas");
    if (grid.isGridless)
      return grid.measurePath([this.object.center, other.object.center], {}).distance - (this.width + other.width) / 2 + 1;
    {
      const distances = this.object.getOccupiedSpaces().flatMap((s) => other.object.getOccupiedSpaces().map((t) => grid.measurePath([s, t], {}).spaces));
      return Math.min(...distances);
    }
  }
};
__name(_LancerTokenDocument, "LancerTokenDocument");
let LancerTokenDocument = _LancerTokenDocument;
function getBasis(token) {
  const symmetrical = token.document.width === token.document.height, even = symmetrical && (token.document.width ?? 0) % 2 == 0;
  if (!symmetrical || !even)
    return token.center;
  const col = canvas.grid.columns, alt = altOrientation(token), pt = { ...token.center };
  return col ? pt.x = pt.x + (alt ? -1 : 1) * canvas.grid.sizeX / 2 : pt.y = pt.y + (alt ? -1 : 1) * canvas.grid.sizeY / 2, pt;
}
__name(getBasis, "getBasis");
const _LancerToken = class _LancerToken extends Token {
  constructor(document2) {
    super(document2), this._spaces = {
      at: { x: -1, y: -1 },
      spaces: []
    };
  }
  /** @override */
  getShape() {
    const size = this.getSize();
    return canvas.grid.isGridless && size.width === size.height ? new PIXI.Circle(size.width / 2, size.height / 2, size.width / 2) : super.getShape();
  }
  /**
   * Returns a Set of Points corresponding to the grid space center points that
   * the token occupies.
   */
  getOccupiedSpaces() {
    var _a19, _b;
    let pos = { x: this.x, y: this.y };
    if ((Math.floor(pos.x) !== Math.floor(this._spaces.at.x) || Math.floor(pos.y) !== Math.floor(this._spaces.at.y)) && (this._spaces.at = { ...pos }, this._spaces.spaces = []), this._spaces.spaces.length === 0)
      if ((_a19 = canvas.grid) != null && _a19.isHexagonal) {
        const regular = this.document.width === this.document.height, basis = getBasis(this), base_cube = canvas.grid.pointToCube(basis), cubes = cubesBySize({
          // @ts-expect-error
          size: regular ? this.document.width : 1,
          alt: altOrientation(this),
          // @ts-expect-error
          columns: canvas.grid.columns
        }).map((c) => ({
          q: c.q + base_cube.q,
          r: c.r + base_cube.r,
          s: c.s + base_cube.s
        }));
        this._spaces.spaces = cubes.map((c) => canvas.grid.cubeToPoint(c));
      } else if ((_b = canvas.grid) != null && _b.isSquare)
        for (let i = 0; i < this.document.width; ++i)
          for (let j = 0; j < this.document.height; ++j)
            this._spaces.spaces.push({
              x: this.position.x + (i + 0.5) * canvas.grid.sizeX,
              y: this.position.y + (j + 0.5) * canvas.grid.sizeY
            });
      else
        this._spaces.spaces.push({ ...this.center });
    return this._spaces.spaces.map((p) => ({ ...p }));
  }
};
__name(_LancerToken, "LancerToken");
let LancerToken = _LancerToken;
function extendTokenConfig(...[app, html, _data2]) {
  const { token_size } = game.settings.get(game.system.id, LANCER.setting_automation);
  if (!token_size)
    return;
  const manual = app.object.getFlag(game.system.id, "manual_token_size") ?? !1;
  html.find("[name=width]").closest(".form-group").before(`
    <div class="form-group slim">
      <label>${game.i18n.localize("lancer.tokenConfig.manual_token_size.label")}</label>
      <div class="form-fields">
        <input type="checkbox"
          name="flags.${game.system.id}.manual_token_size"
          ${manual ? "checked" : ""}
        >
      </div>
      <p class="hint">${game.i18n.localize("lancer.tokenConfig.manual_token_size.hint")}</p>
    </div>`);
  const toggle_inputs = /* @__PURE__ */ __name((ev) => {
    const checked = ev.target.checked;
    html.find("[name=width]").prop("disabled", !checked), html.find("[name=height]").prop("disabled", !checked);
  }, "toggle_inputs");
  html.find(`[name='flags.${game.system.id}.manual_token_size']`).on("change", toggle_inputs), html.find("[name=width]").prop("disabled", !manual), html.find("[name=height]").prop("disabled", !manual), app.setPosition();
}
__name(extendTokenConfig, "extendTokenConfig");
function registerDamageSteps(flowSteps) {
  flowSteps.set("initDamageData", initDamageData), flowSteps.set("setDamageTags", setDamageTags), flowSteps.set("setDamageTargets", setDamageTargets), flowSteps.set("showDamageHUD", showDamageHUD), flowSteps.set("rollReliable", rollReliable), flowSteps.set("rollNormalDamage", rollNormalDamage), flowSteps.set("rollCritDamage", rollCritDamage), flowSteps.set("applyOverkillHeat", applyOverkillHeat), flowSteps.set("printDamageCard", printDamageCard);
}
__name(registerDamageSteps, "registerDamageSteps");
const _DamageRollFlow = class _DamageRollFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "damage",
      title: (data2 == null ? void 0 : data2.title) || "Damage Roll",
      configurable: (data2 == null ? void 0 : data2.configurable) !== void 0 ? data2.configurable : !0,
      add_burn: (data2 == null ? void 0 : data2.add_burn) !== void 0 ? data2.add_burn : !0,
      invade: (data2 == null ? void 0 : data2.invade) || !1,
      tags: (data2 == null ? void 0 : data2.tags) || [],
      ap: (data2 == null ? void 0 : data2.ap) || !1,
      paracausal: (data2 == null ? void 0 : data2.paracausal) || !1,
      half_damage: (data2 == null ? void 0 : data2.half_damage) || !1,
      overkill: (data2 == null ? void 0 : data2.overkill) || !1,
      reliable: (data2 == null ? void 0 : data2.reliable) || !1,
      hit_results: (data2 == null ? void 0 : data2.hit_results) || [],
      has_normal_hit: (data2 == null ? void 0 : data2.has_normal_hit) || !1,
      has_crit_hit: (data2 == null ? void 0 : data2.has_crit_hit) || !1,
      damage: (data2 == null ? void 0 : data2.damage) || [],
      bonus_damage: (data2 == null ? void 0 : data2.bonus_damage) || [],
      damage_results: [],
      crit_damage_results: [],
      damage_total: 0,
      crit_total: 0,
      targets: []
    };
    super(uuid, initialData);
  }
};
__name(_DamageRollFlow, "DamageRollFlow");
let DamageRollFlow = _DamageRollFlow;
DamageRollFlow.steps = [
  "initDamageData",
  "setDamageTags",
  "setDamageTargets",
  "showDamageHUD",
  "rollReliable",
  "rollNormalDamage",
  "rollCritDamage",
  "applyOverkillHeat",
  "printDamageCard"
];
async function initDamageData(state) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  return state.data.hit_results = state.data.hit_results.map((hr) => {
    var _a19;
    let target = hr.target;
    if (target instanceof LancerTokenDocument) {
      const tokens = ((_a19 = target.actor) == null ? void 0 : _a19.getActiveTokens()) || [];
      if (!tokens.length)
        return null;
      target = tokens[0];
    } else if (!(target instanceof LancerToken))
      return null;
    return {
      ...hr,
      target
    };
  }).filter((hr) => hr !== null), state.data.has_normal_hit = state.data.hit_results.length === 0 || state.data.hit_results.some((hit) => hit.hit && !hit.crit), state.data.has_crit_hit = state.data.hit_results.length > 0 && state.data.hit_results.some((hit) => hit.crit), !0;
}
__name(initDamageData, "initDamageData");
async function setDamageTags(state) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  if (!state.item)
    return !0;
  if (state.item.is_mech_weapon()) {
    const profile = state.item.system.active_profile;
    state.data.tags = profile.all_tags;
  } else if (state.item.is_mech_system())
    state.data.tags = state.item.system.tags;
  else if (state.item.is_frame())
    state.data.tags = state.item.system.core_system.tags;
  else if (state.item.is_talent())
    state.data.tags = [];
  else if (state.item.is_npc_feature() && state.item.system.type === "Weapon")
    state.data.tags = state.item.system.tags;
  else if (state.item.is_pilot_weapon())
    state.data.tags = state.item.system.tags;
  else
    return ui.notifications.warn(`Item ${state.item.id} can't deal damage!`), !1;
  state.data.ap = !!state.data.tags.find((t) => t.is_ap), state.data.overkill = !!state.data.tags.find((t) => t.is_overkill);
  const reliableTag = state.data.tags.find((t) => t.is_reliable);
  if (reliableTag) {
    state.data.reliable = !0;
    const reliableVal = parseInt(reliableTag.tierVal(state.actor.is_npc() && state.actor.system.tier || 1) || "0");
    state.data.reliable_val = reliableVal;
  }
  return !0;
}
__name(setDamageTags, "setDamageTags");
async function setDamageTargets(state) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  for (const hr of state.data.hit_results)
    hr.target instanceof LancerToken && hr.target.setTarget(!0, { releaseOthers: !1 });
  return !0;
}
__name(setDamageTargets, "setDamageTargets");
async function showDamageHUD(state) {
  var _a19, _b, _c;
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  try {
    state.data.damage_hud_data = DamageHudData.fromParams(state.item ?? state.actor, {
      tags: state.data.tags,
      title: state.data.title,
      targets: Array.from(game.user.targets),
      hitResults: state.data.hit_results,
      ap: state.data.ap,
      paracausal: state.data.paracausal,
      halfDamage: state.data.half_damage,
      starting: { damage: state.data.damage, bonusDamage: state.data.bonus_damage }
    }), state.data.damage_hud_data = await openSlidingHud("damage", state.data.damage_hud_data), state.data.hit_results = state.data.hit_results.filter((hr) => {
      var _a20, _b2;
      return (_b2 = (_a20 = state.data) == null ? void 0 : _a20.damage_hud_data) == null ? void 0 : _b2.targets.some((t) => hr.target.id === t.target.id);
    }).map((hr) => {
      var _a20, _b2;
      const hudTarget = (_b2 = (_a20 = state.data) == null ? void 0 : _a20.damage_hud_data) == null ? void 0 : _b2.targets.find((t) => hr.target.id === t.target.id);
      return {
        ...hr,
        hit: hudTarget.quality === HitQuality.Hit,
        crit: hudTarget.quality === HitQuality.Crit
      };
    });
    for (const t of state.data.damage_hud_data.targets)
      state.data.hit_results.some((hr) => hr.target.id === t.target.id) || state.data.hit_results.push({
        target: t.target,
        total: "10",
        hit: t.quality === HitQuality.Hit,
        crit: t.quality === HitQuality.Crit,
        usedLockOn: !1
      });
    state.data.has_normal_hit = state.data.hit_results.length === 0 || state.data.hit_results.some((hr) => hr.hit && !hr.crit), state.data.has_crit_hit = state.data.hit_results.some((hr) => hr.crit), state.data.ap = state.data.damage_hud_data.base.ap, state.data.paracausal = state.data.damage_hud_data.base.paracausal, state.data.half_damage = state.data.damage_hud_data.base.halfDamage, state.data.overkill = ((_a19 = state.data.damage_hud_data.weapon) == null ? void 0 : _a19.overkill) ?? !1, state.data.reliable = ((_b = state.data.damage_hud_data.weapon) == null ? void 0 : _b.reliable) ?? !1, state.data.reliable && (state.data.reliable_val = ((_c = state.data.damage_hud_data.weapon) == null ? void 0 : _c.reliableValue) ?? 0);
  } catch {
    return !1;
  }
  return !0;
}
__name(showDamageHUD, "showDamageHUD");
async function _rollDamage(damage, bonus, overkill, target) {
  if (!damage.val || damage.val == "0")
    return null;
  let damageRoll = new Roll(damage.val);
  overkill && damageRoll.terms.forEach((term) => {
    term instanceof foundry.dice.terms.Die && (term.modifiers = ["x1", `kh${term.number}`].concat(term.modifiers));
  }), await damageRoll.evaluate(), damageRoll.dice.forEach((d) => d.options.rollOrder = 2);
  const tooltip = await damageRoll.getTooltip();
  return {
    roll: damageRoll,
    tt: tooltip,
    d_type: damage.type,
    bonus,
    target
  };
}
__name(_rollDamage, "_rollDamage");
function _collectBonusDamage(state) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  if (!state.data.damage_hud_data)
    throw new TypeError("Damage configuration missing!");
  const total = duplicate(state.data.bonus_damage);
  for (const hudTarget of state.data.damage_hud_data.targets) {
    const hudTargetBonusDamage = hudTarget.bonusDamage.map((d) => ({
      ...d,
      target: hudTarget.target
    }));
    total.push(...hudTargetBonusDamage);
  }
  return total;
}
__name(_collectBonusDamage, "_collectBonusDamage");
function _minReliable(damage, reliable) {
  const rawTotal = damage.reduce((acc, d) => acc + d.amount, 0), reliableTotal = reliable.reduce((acc, d) => acc + d.amount, 0);
  return rawTotal >= reliableTotal ? damage : reliable;
}
__name(_minReliable, "_minReliable");
function _halveDamage(damage) {
  return damage.map((d) => ({ type: d.type, amount: Math.ceil(d.amount / 2) }));
}
__name(_halveDamage, "_halveDamage");
async function rollReliable(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  if (!state.data.damage_hud_data)
    throw new TypeError("Damage configuration missing!");
  const totalDamage = state.data.damage_hud_data.base.total;
  state.data.damage = totalDamage.damage, state.data.bonus_damage = totalDamage.bonusDamage ?? [], state.data.reliable_val = ((_a19 = state.data.damage_hud_data.weapon) == null ? void 0 : _a19.reliableValue) ?? 0;
  const allBonusDamage = _collectBonusDamage(state);
  if (!state.data.damage.length && !allBonusDamage.length && !state.data.reliable_val)
    return (_b = ui.notifications) == null || _b.warn("No damage configured, skipping the roll."), !1;
  if (state.data.reliable && state.data.reliable_val) {
    state.data.reliable_results = state.data.reliable_results || [];
    for (const x of state.data.damage ?? []) {
      if (!x.val || x.val == "0")
        continue;
      const damageType = x.type === DamageType.Variable ? DamageType.Kinetic : x.type, result = await _rollDamage({ type: damageType, val: state.data.reliable_val.toString() }, !1, !1);
      if (result) {
        state.data.reliable_results.push(result), state.data.reliable_total = result.roll.total;
        break;
      }
    }
    for (const hitTarget of state.data.hit_results)
      if (!hitTarget.hit && !hitTarget.crit) {
        const hudTarget = state.data.damage_hud_data.targets.find((t) => t.target.id === hitTarget.target.id), halfDamage = hudTarget ? hudTarget.halfDamage : state.data.half_damage, rolledDamage = state.data.reliable_results.map((dr) => ({ type: dr.d_type, amount: dr.roll.total || 0 }));
        state.data.targets.push({
          target: hitTarget.target,
          damage: halfDamage ? _halveDamage(rolledDamage) : rolledDamage,
          hit: hitTarget.hit,
          crit: hitTarget.crit,
          ap: hudTarget ? hudTarget.ap : state.data.ap,
          paracausal: hudTarget ? hudTarget.paracausal : state.data.paracausal,
          half_damage: halfDamage
        });
      }
  }
  return !0;
}
__name(rollReliable, "rollReliable");
async function rollNormalDamage(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  if (!state.data.damage_hud_data)
    throw new TypeError("Damage configuration missing!");
  const multiTarget = state.data.damage_hud_data.targets.length > 1, allBonusDamage = _collectBonusDamage(state);
  if (state.data.has_normal_hit || state.data.has_crit_hit) {
    for (const x of state.data.damage ?? []) {
      const result = await _rollDamage(x, !1, state.data.overkill);
      result && state.data.damage_results.push(result);
    }
    for (const x of allBonusDamage ?? []) {
      const result = await _rollDamage(x, !0, state.data.overkill, x.target);
      result && (result.bonus = !0, x.target && (result.target = x.target), state.data.damage_results.push(result));
    }
    for (const hitTarget of state.data.hit_results)
      if (hitTarget.hit && !hitTarget.crit) {
        const targetDamage = [];
        for (const dr of state.data.damage_results)
          dr.target && dr.target.document.uuid !== hitTarget.target.document.uuid || (multiTarget && dr.bonus && !dr.target ? targetDamage.push({ type: dr.d_type, amount: Math.ceil((dr.roll.total || 0) / 2) }) : targetDamage.push({ type: dr.d_type, amount: dr.roll.total || 0 }));
        const hudTarget = state.data.damage_hud_data.targets.find((t) => t.target.id === hitTarget.target.id), halfDamage = hudTarget ? hudTarget.halfDamage : state.data.half_damage, actualDamage = _minReliable(
          targetDamage,
          ((_a19 = state.data.reliable_results) == null ? void 0 : _a19.map((rr) => ({ type: rr.d_type, amount: rr.roll.total || 0 }))) || []
        );
        state.data.targets.push({
          target: hitTarget.target,
          damage: halfDamage ? _halveDamage(actualDamage) : actualDamage,
          hit: hitTarget.hit,
          crit: hitTarget.crit,
          ap: hudTarget ? hudTarget.ap : state.data.ap,
          paracausal: hudTarget ? hudTarget.paracausal : state.data.paracausal,
          half_damage: halfDamage
        });
      }
  }
  return !0;
}
__name(rollNormalDamage, "rollNormalDamage");
async function rollCritDamage(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  if (!state.data.damage_hud_data)
    throw new TypeError("Damage configuration missing!");
  const multiTarget = state.data.damage_hud_data.targets.length > 1;
  if (state.data.has_crit_hit) {
    if (state.actor.is_npc())
      state.data.crit_damage_results = state.data.damage_results;
    else {
      const hitResults = (_a19 = state.data) == null ? void 0 : _a19.hit_results, critDamage = await Promise.all(
        state.data.damage_results.map(async (result) => {
          var _a20;
          if (result.target && hitResults && !((_a20 = hitResults.find((hr) => {
            var _a21, _b2, _c, _d;
            return (((_b2 = (_a21 = result.target) == null ? void 0 : _a21.document) == null ? void 0 : _b2.uuid) ?? null) === ((_d = (_c = hr.target) == null ? void 0 : _c.document) == null ? void 0 : _d.uuid);
          })) != null && _a20.crit))
            return null;
          const c_roll = await getCritRoll(result.roll);
          c_roll.dice.forEach((d) => d.options.rollOrder = 2);
          const tt = await c_roll.getTooltip();
          return {
            roll: c_roll,
            tt,
            d_type: result.d_type,
            bonus: result.bonus,
            target: result.target
          };
        })
      );
      state.data.crit_damage_results = critDamage.filter((r) => r !== null);
    }
    for (const hitTarget of state.data.hit_results) {
      if (!hitTarget.crit)
        continue;
      const targetDamage = [];
      for (const dr of state.data.crit_damage_results)
        dr.target && dr.target.document.uuid !== hitTarget.target.document.uuid || (multiTarget && dr.bonus && !dr.target ? targetDamage.push({ type: dr.d_type, amount: Math.ceil((dr.roll.total || 0) / 2) }) : targetDamage.push({ type: dr.d_type, amount: dr.roll.total || 0 }));
      const hudTarget = state.data.damage_hud_data.targets.find((t) => t.target.id === hitTarget.target.id), halfDamage = hudTarget ? hudTarget.halfDamage : state.data.half_damage, actualDamage = _minReliable(
        targetDamage,
        ((_b = state.data.reliable_results) == null ? void 0 : _b.map((rr) => ({ type: rr.d_type, amount: rr.roll.total || 0 }))) || []
      );
      state.data.targets.push({
        target: hitTarget.target,
        damage: halfDamage ? _halveDamage(actualDamage) : actualDamage,
        hit: hitTarget.hit,
        crit: hitTarget.crit,
        ap: hudTarget ? hudTarget.ap : state.data.ap,
        paracausal: hudTarget ? hudTarget.paracausal : state.data.paracausal,
        half_damage: hudTarget ? hudTarget.halfDamage : state.data.half_damage
      });
    }
  }
  return state.data.damage_results = state.data.has_normal_hit ? state.data.damage_results : [], !0;
}
__name(rollCritDamage, "rollCritDamage");
async function applyOverkillHeat(state) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  return state.data.overkill && (state.data.overkill_heat = 0, (state.data.has_crit_hit ? state.data.crit_damage_results : state.data.damage_results).forEach((result) => {
    result.roll.terms.forEach((p) => {
      p instanceof foundry.dice.terms.DiceTerm && p.results.forEach((r) => {
        r.exploded && (state.data.overkill_heat += 1);
      });
    });
  }), (state.actor.is_mech() || state.actor.is_npc() || state.actor.is_deployable()) && state.actor.system.heat.max > 0 && await state.actor.update({ "system.heat.value": state.actor.system.heat.value + state.data.overkill_heat })), !0;
}
__name(applyOverkillHeat, "applyOverkillHeat");
async function printDamageCard(state, options) {
  if (!state.data)
    throw new TypeError("Damage flow state missing!");
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/damage-card.hbs`, flags = {
    damageData: {
      // Targets need to be replaced with their UUIDs to avoid circular references
      damageResults: state.data.damage_results.map((dr) => {
        var _a19;
        return {
          ...dr,
          target: (_a19 = dr.target) == null ? void 0 : _a19.document.uuid
        };
      }),
      critDamageResults: state.data.crit_damage_results.map((dr) => {
        var _a19;
        return {
          ...dr,
          target: (_a19 = dr.target) == null ? void 0 : _a19.document.uuid
        };
      }),
      targetDamageResults: state.data.targets.map((t) => ({
        ...t,
        target: t.target.document.uuid
      })),
      ap: state.data.ap,
      paracausal: state.data.paracausal,
      half_damage: state.data.half_damage
    }
  };
  return await renderTemplateStep(state.actor, template, state.data, flags), !0;
}
__name(printDamageCard, "printDamageCard");
async function getCritRoll(normal) {
  const t_roll = new Roll(normal.formula);
  await t_roll.evaluate();
  const dice_rolls = Array(normal.terms.length), keep_dice = Array(normal.terms.length).fill(0);
  normal.terms.forEach((term, i) => {
    var _a19;
    if (term instanceof foundry.dice.terms.Die) {
      const termDie = term;
      dice_rolls[i] = termDie.results.map((r) => ({ ...r }));
      const kh = parseInt(((_a19 = termDie.modifiers.find((m) => m.startsWith("kh"))) == null ? void 0 : _a19.substr(2)) ?? "0");
      keep_dice[i] = kh || termDie.number || 0;
    }
  }), t_roll.terms.forEach((term, i) => {
    term instanceof foundry.dice.terms.Die && dice_rolls[i].push(...term.results);
  });
  const actives = Array(normal.terms.length).fill([]);
  dice_rolls.forEach((dice, i) => {
    actives[i] = dice.filter((d) => d.active).sort((a, b) => a.result - b.result);
  }), actives.forEach(
    (dice, i) => dice.forEach((d, j) => {
      d.active = j >= keep_dice[i], d.discarded = j < keep_dice[i];
    })
  );
  const terms = normal.terms.map((t, i) => {
    if (t instanceof foundry.dice.terms.Die) {
      const tDie = t;
      return new foundry.dice.terms.Die({
        ...t,
        modifiers: tDie.modifiers.filter((m) => m.startsWith("kh")).length ? tDie.modifiers : [...tDie.modifiers, `kh${tDie.number}`],
        results: dice_rolls[i],
        number: (tDie.number || 0) * 2
      });
    } else
      return t instanceof foundry.dice.terms.OperatorTerm && (t._evaluated = !0), t;
  });
  return Roll.fromTerms(terms);
}
__name(getCritRoll, "getCritRoll");
async function rollDamageCallback(event) {
  var _a19, _b, _c, _d, _e, _f, _g, _h;
  const chatMessageElement = event.currentTarget.closest(".chat-message.message");
  if (!chatMessageElement) {
    (_a19 = ui.notifications) == null || _a19.error("Damage roll button not in chat message");
    return;
  }
  const chatMessage = (_b = game.messages) == null ? void 0 : _b.get(chatMessageElement.dataset.messageId), attackData = (_c = chatMessage == null ? void 0 : chatMessage.flags.lancer) == null ? void 0 : _c.attackData;
  if (!chatMessage || !attackData) {
    (_d = ui.notifications) == null || _d.error("Damage roll button has no attack data available");
    return;
  }
  const actor = await fromUuid(attackData.attackerUuid);
  if (!actor) {
    (_e = ui.notifications) == null || _e.error("Invalid attacker for damage roll");
    return;
  }
  if (!actor.isOwner) {
    (_f = ui.notifications) == null || _f.error(`You do not own ${actor.name}, so you cannot roll damage for them`);
    return;
  }
  const item = await fromUuid(attackData.attackerItemUuid || "");
  if (item && item.parent !== actor) {
    (_g = ui.notifications) == null || _g.error(`Item ${item.uuid} is not owned by actor ${actor.uuid}!`);
    return;
  }
  const hit_results = [];
  for (const t of attackData.targets) {
    const target = await fromUuid(t.uuid);
    if (!target || target.documentName !== "Token") {
      (_h = ui.notifications) == null || _h.error("Invalid target for damage roll");
      continue;
    }
    let usedLockOn = !1;
    t.setConditions && (usedLockOn = t.setConditions.lockOn === !1), hit_results.push({
      target,
      total: t.total,
      usedLockOn,
      hit: t.hit,
      crit: t.crit
    });
  }
  const damage = [], bonus_damage = [];
  attackData.invade && damage.push({ type: DamageType.Heat, val: "2" }), new DamageRollFlow(item ? item.uuid : attackData.attackerUuid, {
    title: `${(item == null ? void 0 : item.name) || actor.name} DAMAGE`,
    configurable: !0,
    invade: attackData.invade,
    hit_results,
    has_normal_hit: hit_results.some((hr) => hr.hit && !hr.crit),
    has_crit_hit: hit_results.some((hr) => hr.crit),
    damage,
    bonus_damage
  }).begin();
}
__name(rollDamageCallback, "rollDamageCallback");
async function applyDamage(event) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i;
  const chatMessageElement = event.currentTarget.closest(".chat-message.message");
  if (!chatMessageElement) {
    (_a19 = ui.notifications) == null || _a19.error("Damage application button not in chat message");
    return;
  }
  const chatMessage = (_b = game.messages) == null ? void 0 : _b.get(chatMessageElement.dataset.messageId), damageData = (_c = chatMessage == null ? void 0 : chatMessage.flags.lancer) == null ? void 0 : _c.damageData;
  if (!chatMessage || !damageData) {
    (_d = ui.notifications) == null || _d.error("Damage application button has no damage data available");
    return;
  }
  const hydratedDamageTargets = damageData.targetDamageResults.map((tdr) => {
    const target2 = fromUuidSync(tdr.target);
    return !target2 || !(target2 instanceof LancerTokenDocument) ? null : {
      ...tdr,
      target: target2
    };
  }).filter((t) => t !== null), buttonGroup = event.currentTarget.closest(".lancer-damage-button-group");
  if (!buttonGroup) {
    (_e = ui.notifications) == null || _e.error("No target for damage application");
    return;
  }
  const data2 = buttonGroup.dataset;
  if (!data2.target) {
    (_f = ui.notifications) == null || _f.error("No target for damage application");
    return;
  }
  let multiple = 1;
  const multipleSelect = buttonGroup.querySelector("select");
  multipleSelect && (multiple = parseFloat(multipleSelect.value), multiple = Number.isNaN(multiple) ? 1 : multiple);
  const addBurn = data2.addBurn === "true";
  data2.crit, data2.hit;
  const target = await fromUuid(data2.target);
  if (!target || !(target instanceof LancerTokenDocument)) {
    (_g = ui.notifications) == null || _g.error("Invalid target UUID for damage application");
    return;
  }
  const actor = target.actor;
  if (!actor || !(actor instanceof LancerActor)) {
    (_h = ui.notifications) == null || _h.error("Invalid target for damage application, no actor found");
    return;
  }
  if (!actor.isOwner) {
    (_i = ui.notifications) == null || _i.error("You cannot apply damage to an actor you do not own");
    return;
  }
  const targetDamage = hydratedDamageTargets.find((tdr) => {
    var _a20;
    return ((_a20 = tdr == null ? void 0 : tdr.target) == null ? void 0 : _a20.uuid) === data2.target;
  });
  targetDamage && await actor.damageCalc(
    new AppliedDamage(targetDamage.damage.map((d) => new Damage({ type: d.type, val: d.amount.toString() }))),
    { multiple, addBurn, ap: targetDamage.ap, paracausal: targetDamage.paracausal }
  );
}
__name(applyDamage, "applyDamage");
async function undoDamage(event) {
  var _a19, _b, _c, _d, _e, _f, _g;
  const chatMessageElement = event.currentTarget.closest(".chat-message.message");
  if (!chatMessageElement) {
    (_a19 = ui.notifications) == null || _a19.error("Damage undo button not in chat message");
    return;
  }
  const chatMessage = (_b = game.messages) == null ? void 0 : _b.get(chatMessageElement.dataset.messageId);
  if (!chatMessage) {
    (_c = ui.notifications) == null || _c.error("Damage undo button has no chat message");
    return;
  }
  const target = await fromUuid((_d = event.currentTarget.dataset) == null ? void 0 : _d.uuid);
  if (!target || !(target instanceof LancerActor)) {
    (_e = ui.notifications) == null || _e.error("Damage undo button has no target");
    return;
  }
  if (!target.isOwner) {
    (_f = ui.notifications) == null || _f.error("You cannot undo damage to an actor you do not own");
    return;
  }
  const overshieldDelta = parseInt(event.currentTarget.dataset.overshieldDelta), hpDelta = parseInt(event.currentTarget.dataset.hpDelta), burnDelta = event.currentTarget.dataset.addBurn === "true" ? parseInt(event.currentTarget.dataset.burnDelta) : 0, heatDelta = parseInt(event.currentTarget.dataset.heatDelta);
  if (!overshieldDelta && !hpDelta && !burnDelta && !heatDelta) {
    (_g = ui.notifications) == null || _g.error("Damage undo button has no damage to undo!");
    return;
  }
  const updateData = {
    system: {
      "overshield.value": target.system.overshield.value + overshieldDelta,
      "hp.value": target.system.hp.value + hpDelta,
      burn: target.system.burn - burnDelta
    }
  };
  (target.is_mech() || target.is_npc() || target.is_deployable()) && (updateData.system["heat.value"] = target.system.heat.value - heatDelta);
  const cmDoc = new DOMParser().parseFromString(chatMessage.content, "text/html");
  cmDoc.querySelectorAll(".lancer-damage-undo").forEach((el) => el.remove()), cmDoc.querySelectorAll("span").forEach((el) => el.classList.add("strikethrough"));
  const newChatMessageContent = cmDoc.body.innerHTML;
  await target.update(updateData), await chatMessage.update({ content: newChatMessageContent });
}
__name(undoDamage, "undoDamage");
var commonjsGlobal = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
function getDefaultExportFromCjs(x) {
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
}
__name(getDefaultExportFromCjs, "getDefaultExportFromCjs");
function getAugmentedNamespace(n) {
  if (n.__esModule)
    return n;
  var f = n.default;
  if (typeof f == "function") {
    var a = /* @__PURE__ */ __name(function a2() {
      return this instanceof a2 ? Reflect.construct(f, arguments, this.constructor) : f.apply(this, arguments);
    }, "a");
    a.prototype = f.prototype;
  } else
    a = {};
  return Object.defineProperty(a, "__esModule", { value: !0 }), Object.keys(n).forEach(function(k) {
    var d = Object.getOwnPropertyDescriptor(n, k);
    Object.defineProperty(a, k, d.get ? d : {
      enumerable: !0,
      get: function() {
        return n[k];
      }
    });
  }), a;
}
__name(getAugmentedNamespace, "getAugmentedNamespace");
function commonjsRequire(path) {
  throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
}
__name(commonjsRequire, "commonjsRequire");
var jszip_min = { exports: {} };
/*!

JSZip v3.10.1 - A JavaScript class for generating and reading zip files
<http://stuartk.com/jszip>

(c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown.

JSZip uses the library pako released under the MIT license :
https://github.com/nodeca/pako/blob/main/LICENSE
*/
(function(module, exports) {
  (function(e) {
    module.exports = e();
  })(function() {
    return (/* @__PURE__ */ __name(function s(a, o, h) {
      function u(r, e2) {
        if (!o[r]) {
          if (!a[r]) {
            var t = typeof commonjsRequire == "function" && commonjsRequire;
            if (!e2 && t)
              return t(r, !0);
            if (l)
              return l(r, !0);
            var n = new Error("Cannot find module '" + r + "'");
            throw n.code = "MODULE_NOT_FOUND", n;
          }
          var i = o[r] = { exports: {} };
          a[r][0].call(i.exports, function(e3) {
            var t2 = a[r][1][e3];
            return u(t2 || e3);
          }, i, i.exports, s, a, o, h);
        }
        return o[r].exports;
      }
      __name(u, "u");
      for (var l = typeof commonjsRequire == "function" && commonjsRequire, e = 0; e < h.length; e++)
        u(h[e]);
      return u;
    }, "s"))({ 1: [function(e, t, r) {
      var d = e("./utils"), c = e("./support"), p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
      r.encode = function(e2) {
        for (var t2, r2, n, i, s, a, o, h = [], u = 0, l = e2.length, f = l, c2 = d.getTypeOf(e2) !== "string"; u < e2.length; )
          f = l - u, n = c2 ? (t2 = e2[u++], r2 = u < l ? e2[u++] : 0, u < l ? e2[u++] : 0) : (t2 = e2.charCodeAt(u++), r2 = u < l ? e2.charCodeAt(u++) : 0, u < l ? e2.charCodeAt(u++) : 0), i = t2 >> 2, s = (3 & t2) << 4 | r2 >> 4, a = 1 < f ? (15 & r2) << 2 | n >> 6 : 64, o = 2 < f ? 63 & n : 64, h.push(p.charAt(i) + p.charAt(s) + p.charAt(a) + p.charAt(o));
        return h.join("");
      }, r.decode = function(e2) {
        var t2, r2, n, i, s, a, o = 0, h = 0, u = "data:";
        if (e2.substr(0, u.length) === u)
          throw new Error("Invalid base64 input, it looks like a data url.");
        var l, f = 3 * (e2 = e2.replace(/[^A-Za-z0-9+/=]/g, "")).length / 4;
        if (e2.charAt(e2.length - 1) === p.charAt(64) && f--, e2.charAt(e2.length - 2) === p.charAt(64) && f--, f % 1 != 0)
          throw new Error("Invalid base64 input, bad content length.");
        for (l = c.uint8array ? new Uint8Array(0 | f) : new Array(0 | f); o < e2.length; )
          t2 = p.indexOf(e2.charAt(o++)) << 2 | (i = p.indexOf(e2.charAt(o++))) >> 4, r2 = (15 & i) << 4 | (s = p.indexOf(e2.charAt(o++))) >> 2, n = (3 & s) << 6 | (a = p.indexOf(e2.charAt(o++))), l[h++] = t2, s !== 64 && (l[h++] = r2), a !== 64 && (l[h++] = n);
        return l;
      };
    }, { "./support": 30, "./utils": 32 }], 2: [function(e, t, r) {
      var n = e("./external"), i = e("./stream/DataWorker"), s = e("./stream/Crc32Probe"), a = e("./stream/DataLengthProbe");
      function o(e2, t2, r2, n2, i2) {
        this.compressedSize = e2, this.uncompressedSize = t2, this.crc32 = r2, this.compression = n2, this.compressedContent = i2;
      }
      __name(o, "o"), o.prototype = { getContentWorker: function() {
        var e2 = new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")), t2 = this;
        return e2.on("end", function() {
          if (this.streamInfo.data_length !== t2.uncompressedSize)
            throw new Error("Bug : uncompressed data size mismatch");
        }), e2;
      }, getCompressedWorker: function() {
        return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize", this.compressedSize).withStreamInfo("uncompressedSize", this.uncompressedSize).withStreamInfo("crc32", this.crc32).withStreamInfo("compression", this.compression);
      } }, o.createWorkerFrom = function(e2, t2, r2) {
        return e2.pipe(new s()).pipe(new a("uncompressedSize")).pipe(t2.compressWorker(r2)).pipe(new a("compressedSize")).withStreamInfo("compression", t2);
      }, t.exports = o;
    }, { "./external": 6, "./stream/Crc32Probe": 25, "./stream/DataLengthProbe": 26, "./stream/DataWorker": 27 }], 3: [function(e, t, r) {
      var n = e("./stream/GenericWorker");
      r.STORE = { magic: "\0\0", compressWorker: function() {
        return new n("STORE compression");
      }, uncompressWorker: function() {
        return new n("STORE decompression");
      } }, r.DEFLATE = e("./flate");
    }, { "./flate": 7, "./stream/GenericWorker": 28 }], 4: [function(e, t, r) {
      var n = e("./utils"), o = function() {
        for (var e2, t2 = [], r2 = 0; r2 < 256; r2++) {
          e2 = r2;
          for (var n2 = 0; n2 < 8; n2++)
            e2 = 1 & e2 ? 3988292384 ^ e2 >>> 1 : e2 >>> 1;
          t2[r2] = e2;
        }
        return t2;
      }();
      t.exports = function(e2, t2) {
        return e2 !== void 0 && e2.length ? n.getTypeOf(e2) !== "string" ? function(e3, t3, r2, n2) {
          var i = o, s = n2 + r2;
          e3 ^= -1;
          for (var a = n2; a < s; a++)
            e3 = e3 >>> 8 ^ i[255 & (e3 ^ t3[a])];
          return -1 ^ e3;
        }(0 | t2, e2, e2.length, 0) : function(e3, t3, r2, n2) {
          var i = o, s = n2 + r2;
          e3 ^= -1;
          for (var a = n2; a < s; a++)
            e3 = e3 >>> 8 ^ i[255 & (e3 ^ t3.charCodeAt(a))];
          return -1 ^ e3;
        }(0 | t2, e2, e2.length, 0) : 0;
      };
    }, { "./utils": 32 }], 5: [function(e, t, r) {
      r.base64 = !1, r.binary = !1, r.dir = !1, r.createFolders = !0, r.date = null, r.compression = null, r.compressionOptions = null, r.comment = null, r.unixPermissions = null, r.dosPermissions = null;
    }, {}], 6: [function(e, t, r) {
      var n = null;
      n = typeof Promise < "u" ? Promise : e("lie"), t.exports = { Promise: n };
    }, { lie: 37 }], 7: [function(e, t, r) {
      var n = typeof Uint8Array < "u" && typeof Uint16Array < "u" && typeof Uint32Array < "u", i = e("pako"), s = e("./utils"), a = e("./stream/GenericWorker"), o = n ? "uint8array" : "array";
      function h(e2, t2) {
        a.call(this, "FlateWorker/" + e2), this._pako = null, this._pakoAction = e2, this._pakoOptions = t2, this.meta = {};
      }
      __name(h, "h"), r.magic = "\b\0", s.inherits(h, a), h.prototype.processChunk = function(e2) {
        this.meta = e2.meta, this._pako === null && this._createPako(), this._pako.push(s.transformTo(o, e2.data), !1);
      }, h.prototype.flush = function() {
        a.prototype.flush.call(this), this._pako === null && this._createPako(), this._pako.push([], !0);
      }, h.prototype.cleanUp = function() {
        a.prototype.cleanUp.call(this), this._pako = null;
      }, h.prototype._createPako = function() {
        this._pako = new i[this._pakoAction]({ raw: !0, level: this._pakoOptions.level || -1 });
        var t2 = this;
        this._pako.onData = function(e2) {
          t2.push({ data: e2, meta: t2.meta });
        };
      }, r.compressWorker = function(e2) {
        return new h("Deflate", e2);
      }, r.uncompressWorker = function() {
        return new h("Inflate", {});
      };
    }, { "./stream/GenericWorker": 28, "./utils": 32, pako: 38 }], 8: [function(e, t, r) {
      function A(e2, t2) {
        var r2, n2 = "";
        for (r2 = 0; r2 < t2; r2++)
          n2 += String.fromCharCode(255 & e2), e2 >>>= 8;
        return n2;
      }
      __name(A, "A");
      function n(e2, t2, r2, n2, i2, s2) {
        var a, o, h = e2.file, u = e2.compression, l = s2 !== O.utf8encode, f = I.transformTo("string", s2(h.name)), c = I.transformTo("string", O.utf8encode(h.name)), d = h.comment, p = I.transformTo("string", s2(d)), m = I.transformTo("string", O.utf8encode(d)), _ = c.length !== h.name.length, g = m.length !== d.length, b = "", v = "", y = "", w = h.dir, k = h.date, x = { crc32: 0, compressedSize: 0, uncompressedSize: 0 };
        t2 && !r2 || (x.crc32 = e2.crc32, x.compressedSize = e2.compressedSize, x.uncompressedSize = e2.uncompressedSize);
        var S = 0;
        t2 && (S |= 8), l || !_ && !g || (S |= 2048);
        var z = 0, C = 0;
        w && (z |= 16), i2 === "UNIX" ? (C = 798, z |= function(e3, t3) {
          var r3 = e3;
          return e3 || (r3 = t3 ? 16893 : 33204), (65535 & r3) << 16;
        }(h.unixPermissions, w)) : (C = 20, z |= function(e3) {
          return 63 & (e3 || 0);
        }(h.dosPermissions)), a = k.getUTCHours(), a <<= 6, a |= k.getUTCMinutes(), a <<= 5, a |= k.getUTCSeconds() / 2, o = k.getUTCFullYear() - 1980, o <<= 4, o |= k.getUTCMonth() + 1, o <<= 5, o |= k.getUTCDate(), _ && (v = A(1, 1) + A(B(f), 4) + c, b += "up" + A(v.length, 2) + v), g && (y = A(1, 1) + A(B(p), 4) + m, b += "uc" + A(y.length, 2) + y);
        var E = "";
        return E += `
\0`, E += A(S, 2), E += u.magic, E += A(a, 2), E += A(o, 2), E += A(x.crc32, 4), E += A(x.compressedSize, 4), E += A(x.uncompressedSize, 4), E += A(f.length, 2), E += A(b.length, 2), { fileRecord: R.LOCAL_FILE_HEADER + E + f + b, dirRecord: R.CENTRAL_FILE_HEADER + A(C, 2) + E + A(p.length, 2) + "\0\0\0\0" + A(z, 4) + A(n2, 4) + f + b + p };
      }
      __name(n, "n");
      var I = e("../utils"), i = e("../stream/GenericWorker"), O = e("../utf8"), B = e("../crc32"), R = e("../signature");
      function s(e2, t2, r2, n2) {
        i.call(this, "ZipFileWorker"), this.bytesWritten = 0, this.zipComment = t2, this.zipPlatform = r2, this.encodeFileName = n2, this.streamFiles = e2, this.accumulate = !1, this.contentBuffer = [], this.dirRecords = [], this.currentSourceOffset = 0, this.entriesCount = 0, this.currentFile = null, this._sources = [];
      }
      __name(s, "s"), I.inherits(s, i), s.prototype.push = function(e2) {
        var t2 = e2.meta.percent || 0, r2 = this.entriesCount, n2 = this._sources.length;
        this.accumulate ? this.contentBuffer.push(e2) : (this.bytesWritten += e2.data.length, i.prototype.push.call(this, { data: e2.data, meta: { currentFile: this.currentFile, percent: r2 ? (t2 + 100 * (r2 - n2 - 1)) / r2 : 100 } }));
      }, s.prototype.openedSource = function(e2) {
        this.currentSourceOffset = this.bytesWritten, this.currentFile = e2.file.name;
        var t2 = this.streamFiles && !e2.file.dir;
        if (t2) {
          var r2 = n(e2, t2, !1, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
          this.push({ data: r2.fileRecord, meta: { percent: 0 } });
        } else
          this.accumulate = !0;
      }, s.prototype.closedSource = function(e2) {
        this.accumulate = !1;
        var t2 = this.streamFiles && !e2.file.dir, r2 = n(e2, t2, !0, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
        if (this.dirRecords.push(r2.dirRecord), t2)
          this.push({ data: function(e3) {
            return R.DATA_DESCRIPTOR + A(e3.crc32, 4) + A(e3.compressedSize, 4) + A(e3.uncompressedSize, 4);
          }(e2), meta: { percent: 100 } });
        else
          for (this.push({ data: r2.fileRecord, meta: { percent: 0 } }); this.contentBuffer.length; )
            this.push(this.contentBuffer.shift());
        this.currentFile = null;
      }, s.prototype.flush = function() {
        for (var e2 = this.bytesWritten, t2 = 0; t2 < this.dirRecords.length; t2++)
          this.push({ data: this.dirRecords[t2], meta: { percent: 100 } });
        var r2 = this.bytesWritten - e2, n2 = function(e3, t3, r3, n3, i2) {
          var s2 = I.transformTo("string", i2(n3));
          return R.CENTRAL_DIRECTORY_END + "\0\0\0\0" + A(e3, 2) + A(e3, 2) + A(t3, 4) + A(r3, 4) + A(s2.length, 2) + s2;
        }(this.dirRecords.length, r2, e2, this.zipComment, this.encodeFileName);
        this.push({ data: n2, meta: { percent: 100 } });
      }, s.prototype.prepareNextSource = function() {
        this.previous = this._sources.shift(), this.openedSource(this.previous.streamInfo), this.isPaused ? this.previous.pause() : this.previous.resume();
      }, s.prototype.registerPrevious = function(e2) {
        this._sources.push(e2);
        var t2 = this;
        return e2.on("data", function(e3) {
          t2.processChunk(e3);
        }), e2.on("end", function() {
          t2.closedSource(t2.previous.streamInfo), t2._sources.length ? t2.prepareNextSource() : t2.end();
        }), e2.on("error", function(e3) {
          t2.error(e3);
        }), this;
      }, s.prototype.resume = function() {
        return !!i.prototype.resume.call(this) && (!this.previous && this._sources.length ? (this.prepareNextSource(), !0) : this.previous || this._sources.length || this.generatedError ? void 0 : (this.end(), !0));
      }, s.prototype.error = function(e2) {
        var t2 = this._sources;
        if (!i.prototype.error.call(this, e2))
          return !1;
        for (var r2 = 0; r2 < t2.length; r2++)
          try {
            t2[r2].error(e2);
          } catch {
          }
        return !0;
      }, s.prototype.lock = function() {
        i.prototype.lock.call(this);
        for (var e2 = this._sources, t2 = 0; t2 < e2.length; t2++)
          e2[t2].lock();
      }, t.exports = s;
    }, { "../crc32": 4, "../signature": 23, "../stream/GenericWorker": 28, "../utf8": 31, "../utils": 32 }], 9: [function(e, t, r) {
      var u = e("../compressions"), n = e("./ZipFileWorker");
      r.generateWorker = function(e2, a, t2) {
        var o = new n(a.streamFiles, t2, a.platform, a.encodeFileName), h = 0;
        try {
          e2.forEach(function(e3, t3) {
            h++;
            var r2 = function(e4, t4) {
              var r3 = e4 || t4, n3 = u[r3];
              if (!n3)
                throw new Error(r3 + " is not a valid compression method !");
              return n3;
            }(t3.options.compression, a.compression), n2 = t3.options.compressionOptions || a.compressionOptions || {}, i = t3.dir, s = t3.date;
            t3._compressWorker(r2, n2).withStreamInfo("file", { name: e3, dir: i, date: s, comment: t3.comment || "", unixPermissions: t3.unixPermissions, dosPermissions: t3.dosPermissions }).pipe(o);
          }), o.entriesCount = h;
        } catch (e3) {
          o.error(e3);
        }
        return o;
      };
    }, { "../compressions": 3, "./ZipFileWorker": 8 }], 10: [function(e, t, r) {
      function n() {
        if (!(this instanceof n))
          return new n();
        if (arguments.length)
          throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
        this.files = /* @__PURE__ */ Object.create(null), this.comment = null, this.root = "", this.clone = function() {
          var e2 = new n();
          for (var t2 in this)
            typeof this[t2] != "function" && (e2[t2] = this[t2]);
          return e2;
        };
      }
      __name(n, "n"), (n.prototype = e("./object")).loadAsync = e("./load"), n.support = e("./support"), n.defaults = e("./defaults"), n.version = "3.10.1", n.loadAsync = function(e2, t2) {
        return new n().loadAsync(e2, t2);
      }, n.external = e("./external"), t.exports = n;
    }, { "./defaults": 5, "./external": 6, "./load": 11, "./object": 15, "./support": 30 }], 11: [function(e, t, r) {
      var u = e("./utils"), i = e("./external"), n = e("./utf8"), s = e("./zipEntries"), a = e("./stream/Crc32Probe"), l = e("./nodejsUtils");
      function f(n2) {
        return new i.Promise(function(e2, t2) {
          var r2 = n2.decompressed.getContentWorker().pipe(new a());
          r2.on("error", function(e3) {
            t2(e3);
          }).on("end", function() {
            r2.streamInfo.crc32 !== n2.decompressed.crc32 ? t2(new Error("Corrupted zip : CRC32 mismatch")) : e2();
          }).resume();
        });
      }
      __name(f, "f"), t.exports = function(e2, o) {
        var h = this;
        return o = u.extend(o || {}, { base64: !1, checkCRC32: !1, optimizedBinaryString: !1, createFolders: !1, decodeFileName: n.utf8decode }), l.isNode && l.isStream(e2) ? i.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file.")) : u.prepareContent("the loaded zip file", e2, !0, o.optimizedBinaryString, o.base64).then(function(e3) {
          var t2 = new s(o);
          return t2.load(e3), t2;
        }).then(function(e3) {
          var t2 = [i.Promise.resolve(e3)], r2 = e3.files;
          if (o.checkCRC32)
            for (var n2 = 0; n2 < r2.length; n2++)
              t2.push(f(r2[n2]));
          return i.Promise.all(t2);
        }).then(function(e3) {
          for (var t2 = e3.shift(), r2 = t2.files, n2 = 0; n2 < r2.length; n2++) {
            var i2 = r2[n2], s2 = i2.fileNameStr, a2 = u.resolve(i2.fileNameStr);
            h.file(a2, i2.decompressed, { binary: !0, optimizedBinaryString: !0, date: i2.date, dir: i2.dir, comment: i2.fileCommentStr.length ? i2.fileCommentStr : null, unixPermissions: i2.unixPermissions, dosPermissions: i2.dosPermissions, createFolders: o.createFolders }), i2.dir || (h.file(a2).unsafeOriginalName = s2);
          }
          return t2.zipComment.length && (h.comment = t2.zipComment), h;
        });
      };
    }, { "./external": 6, "./nodejsUtils": 14, "./stream/Crc32Probe": 25, "./utf8": 31, "./utils": 32, "./zipEntries": 33 }], 12: [function(e, t, r) {
      var n = e("../utils"), i = e("../stream/GenericWorker");
      function s(e2, t2) {
        i.call(this, "Nodejs stream input adapter for " + e2), this._upstreamEnded = !1, this._bindStream(t2);
      }
      __name(s, "s"), n.inherits(s, i), s.prototype._bindStream = function(e2) {
        var t2 = this;
        (this._stream = e2).pause(), e2.on("data", function(e3) {
          t2.push({ data: e3, meta: { percent: 0 } });
        }).on("error", function(e3) {
          t2.isPaused ? this.generatedError = e3 : t2.error(e3);
        }).on("end", function() {
          t2.isPaused ? t2._upstreamEnded = !0 : t2.end();
        });
      }, s.prototype.pause = function() {
        return !!i.prototype.pause.call(this) && (this._stream.pause(), !0);
      }, s.prototype.resume = function() {
        return !!i.prototype.resume.call(this) && (this._upstreamEnded ? this.end() : this._stream.resume(), !0);
      }, t.exports = s;
    }, { "../stream/GenericWorker": 28, "../utils": 32 }], 13: [function(e, t, r) {
      var i = e("readable-stream").Readable;
      function n(e2, t2, r2) {
        i.call(this, t2), this._helper = e2;
        var n2 = this;
        e2.on("data", function(e3, t3) {
          n2.push(e3) || n2._helper.pause(), r2 && r2(t3);
        }).on("error", function(e3) {
          n2.emit("error", e3);
        }).on("end", function() {
          n2.push(null);
        });
      }
      __name(n, "n"), e("../utils").inherits(n, i), n.prototype._read = function() {
        this._helper.resume();
      }, t.exports = n;
    }, { "../utils": 32, "readable-stream": 16 }], 14: [function(e, t, r) {
      t.exports = { isNode: typeof Buffer < "u", newBufferFrom: function(e2, t2) {
        if (Buffer.from && Buffer.from !== Uint8Array.from)
          return Buffer.from(e2, t2);
        if (typeof e2 == "number")
          throw new Error('The "data" argument must not be a number');
        return new Buffer(e2, t2);
      }, allocBuffer: function(e2) {
        if (Buffer.alloc)
          return Buffer.alloc(e2);
        var t2 = new Buffer(e2);
        return t2.fill(0), t2;
      }, isBuffer: function(e2) {
        return Buffer.isBuffer(e2);
      }, isStream: function(e2) {
        return e2 && typeof e2.on == "function" && typeof e2.pause == "function" && typeof e2.resume == "function";
      } };
    }, {}], 15: [function(e, t, r) {
      function s(e2, t2, r2) {
        var n2, i2 = u.getTypeOf(t2), s2 = u.extend(r2 || {}, f);
        s2.date = s2.date || /* @__PURE__ */ new Date(), s2.compression !== null && (s2.compression = s2.compression.toUpperCase()), typeof s2.unixPermissions == "string" && (s2.unixPermissions = parseInt(s2.unixPermissions, 8)), s2.unixPermissions && 16384 & s2.unixPermissions && (s2.dir = !0), s2.dosPermissions && 16 & s2.dosPermissions && (s2.dir = !0), s2.dir && (e2 = g(e2)), s2.createFolders && (n2 = _(e2)) && b.call(this, n2, !0);
        var a2 = i2 === "string" && s2.binary === !1 && s2.base64 === !1;
        r2 && r2.binary !== void 0 || (s2.binary = !a2), (t2 instanceof c && t2.uncompressedSize === 0 || s2.dir || !t2 || t2.length === 0) && (s2.base64 = !1, s2.binary = !0, t2 = "", s2.compression = "STORE", i2 = "string");
        var o2 = null;
        o2 = t2 instanceof c || t2 instanceof l ? t2 : p.isNode && p.isStream(t2) ? new m(e2, t2) : u.prepareContent(e2, t2, s2.binary, s2.optimizedBinaryString, s2.base64);
        var h2 = new d(e2, o2, s2);
        this.files[e2] = h2;
      }
      __name(s, "s");
      var i = e("./utf8"), u = e("./utils"), l = e("./stream/GenericWorker"), a = e("./stream/StreamHelper"), f = e("./defaults"), c = e("./compressedObject"), d = e("./zipObject"), o = e("./generate"), p = e("./nodejsUtils"), m = e("./nodejs/NodejsStreamInputAdapter"), _ = /* @__PURE__ */ __name(function(e2) {
        e2.slice(-1) === "/" && (e2 = e2.substring(0, e2.length - 1));
        var t2 = e2.lastIndexOf("/");
        return 0 < t2 ? e2.substring(0, t2) : "";
      }, "_"), g = /* @__PURE__ */ __name(function(e2) {
        return e2.slice(-1) !== "/" && (e2 += "/"), e2;
      }, "g"), b = /* @__PURE__ */ __name(function(e2, t2) {
        return t2 = t2 !== void 0 ? t2 : f.createFolders, e2 = g(e2), this.files[e2] || s.call(this, e2, null, { dir: !0, createFolders: t2 }), this.files[e2];
      }, "b");
      function h(e2) {
        return Object.prototype.toString.call(e2) === "[object RegExp]";
      }
      __name(h, "h");
      var n = { load: function() {
        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
      }, forEach: function(e2) {
        var t2, r2, n2;
        for (t2 in this.files)
          n2 = this.files[t2], (r2 = t2.slice(this.root.length, t2.length)) && t2.slice(0, this.root.length) === this.root && e2(r2, n2);
      }, filter: function(r2) {
        var n2 = [];
        return this.forEach(function(e2, t2) {
          r2(e2, t2) && n2.push(t2);
        }), n2;
      }, file: function(e2, t2, r2) {
        if (arguments.length !== 1)
          return e2 = this.root + e2, s.call(this, e2, t2, r2), this;
        if (h(e2)) {
          var n2 = e2;
          return this.filter(function(e3, t3) {
            return !t3.dir && n2.test(e3);
          });
        }
        var i2 = this.files[this.root + e2];
        return i2 && !i2.dir ? i2 : null;
      }, folder: function(r2) {
        if (!r2)
          return this;
        if (h(r2))
          return this.filter(function(e3, t3) {
            return t3.dir && r2.test(e3);
          });
        var e2 = this.root + r2, t2 = b.call(this, e2), n2 = this.clone();
        return n2.root = t2.name, n2;
      }, remove: function(r2) {
        r2 = this.root + r2;
        var e2 = this.files[r2];
        if (e2 || (r2.slice(-1) !== "/" && (r2 += "/"), e2 = this.files[r2]), e2 && !e2.dir)
          delete this.files[r2];
        else
          for (var t2 = this.filter(function(e3, t3) {
            return t3.name.slice(0, r2.length) === r2;
          }), n2 = 0; n2 < t2.length; n2++)
            delete this.files[t2[n2].name];
        return this;
      }, generate: function() {
        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
      }, generateInternalStream: function(e2) {
        var t2, r2 = {};
        try {
          if ((r2 = u.extend(e2 || {}, { streamFiles: !1, compression: "STORE", compressionOptions: null, type: "", platform: "DOS", comment: null, mimeType: "application/zip", encodeFileName: i.utf8encode })).type = r2.type.toLowerCase(), r2.compression = r2.compression.toUpperCase(), r2.type === "binarystring" && (r2.type = "string"), !r2.type)
            throw new Error("No output type specified.");
          u.checkSupport(r2.type), r2.platform !== "darwin" && r2.platform !== "freebsd" && r2.platform !== "linux" && r2.platform !== "sunos" || (r2.platform = "UNIX"), r2.platform === "win32" && (r2.platform = "DOS");
          var n2 = r2.comment || this.comment || "";
          t2 = o.generateWorker(this, r2, n2);
        } catch (e3) {
          (t2 = new l("error")).error(e3);
        }
        return new a(t2, r2.type || "string", r2.mimeType);
      }, generateAsync: function(e2, t2) {
        return this.generateInternalStream(e2).accumulate(t2);
      }, generateNodeStream: function(e2, t2) {
        return (e2 = e2 || {}).type || (e2.type = "nodebuffer"), this.generateInternalStream(e2).toNodejsStream(t2);
      } };
      t.exports = n;
    }, { "./compressedObject": 2, "./defaults": 5, "./generate": 9, "./nodejs/NodejsStreamInputAdapter": 12, "./nodejsUtils": 14, "./stream/GenericWorker": 28, "./stream/StreamHelper": 29, "./utf8": 31, "./utils": 32, "./zipObject": 35 }], 16: [function(e, t, r) {
      t.exports = e("stream");
    }, { stream: void 0 }], 17: [function(e, t, r) {
      var n = e("./DataReader");
      function i(e2) {
        n.call(this, e2);
        for (var t2 = 0; t2 < this.data.length; t2++)
          e2[t2] = 255 & e2[t2];
      }
      __name(i, "i"), e("../utils").inherits(i, n), i.prototype.byteAt = function(e2) {
        return this.data[this.zero + e2];
      }, i.prototype.lastIndexOfSignature = function(e2) {
        for (var t2 = e2.charCodeAt(0), r2 = e2.charCodeAt(1), n2 = e2.charCodeAt(2), i2 = e2.charCodeAt(3), s = this.length - 4; 0 <= s; --s)
          if (this.data[s] === t2 && this.data[s + 1] === r2 && this.data[s + 2] === n2 && this.data[s + 3] === i2)
            return s - this.zero;
        return -1;
      }, i.prototype.readAndCheckSignature = function(e2) {
        var t2 = e2.charCodeAt(0), r2 = e2.charCodeAt(1), n2 = e2.charCodeAt(2), i2 = e2.charCodeAt(3), s = this.readData(4);
        return t2 === s[0] && r2 === s[1] && n2 === s[2] && i2 === s[3];
      }, i.prototype.readData = function(e2) {
        if (this.checkOffset(e2), e2 === 0)
          return [];
        var t2 = this.data.slice(this.zero + this.index, this.zero + this.index + e2);
        return this.index += e2, t2;
      }, t.exports = i;
    }, { "../utils": 32, "./DataReader": 18 }], 18: [function(e, t, r) {
      var n = e("../utils");
      function i(e2) {
        this.data = e2, this.length = e2.length, this.index = 0, this.zero = 0;
      }
      __name(i, "i"), i.prototype = { checkOffset: function(e2) {
        this.checkIndex(this.index + e2);
      }, checkIndex: function(e2) {
        if (this.length < this.zero + e2 || e2 < 0)
          throw new Error("End of data reached (data length = " + this.length + ", asked index = " + e2 + "). Corrupted zip ?");
      }, setIndex: function(e2) {
        this.checkIndex(e2), this.index = e2;
      }, skip: function(e2) {
        this.setIndex(this.index + e2);
      }, byteAt: function() {
      }, readInt: function(e2) {
        var t2, r2 = 0;
        for (this.checkOffset(e2), t2 = this.index + e2 - 1; t2 >= this.index; t2--)
          r2 = (r2 << 8) + this.byteAt(t2);
        return this.index += e2, r2;
      }, readString: function(e2) {
        return n.transformTo("string", this.readData(e2));
      }, readData: function() {
      }, lastIndexOfSignature: function() {
      }, readAndCheckSignature: function() {
      }, readDate: function() {
        var e2 = this.readInt(4);
        return new Date(Date.UTC(1980 + (e2 >> 25 & 127), (e2 >> 21 & 15) - 1, e2 >> 16 & 31, e2 >> 11 & 31, e2 >> 5 & 63, (31 & e2) << 1));
      } }, t.exports = i;
    }, { "../utils": 32 }], 19: [function(e, t, r) {
      var n = e("./Uint8ArrayReader");
      function i(e2) {
        n.call(this, e2);
      }
      __name(i, "i"), e("../utils").inherits(i, n), i.prototype.readData = function(e2) {
        this.checkOffset(e2);
        var t2 = this.data.slice(this.zero + this.index, this.zero + this.index + e2);
        return this.index += e2, t2;
      }, t.exports = i;
    }, { "../utils": 32, "./Uint8ArrayReader": 21 }], 20: [function(e, t, r) {
      var n = e("./DataReader");
      function i(e2) {
        n.call(this, e2);
      }
      __name(i, "i"), e("../utils").inherits(i, n), i.prototype.byteAt = function(e2) {
        return this.data.charCodeAt(this.zero + e2);
      }, i.prototype.lastIndexOfSignature = function(e2) {
        return this.data.lastIndexOf(e2) - this.zero;
      }, i.prototype.readAndCheckSignature = function(e2) {
        return e2 === this.readData(4);
      }, i.prototype.readData = function(e2) {
        this.checkOffset(e2);
        var t2 = this.data.slice(this.zero + this.index, this.zero + this.index + e2);
        return this.index += e2, t2;
      }, t.exports = i;
    }, { "../utils": 32, "./DataReader": 18 }], 21: [function(e, t, r) {
      var n = e("./ArrayReader");
      function i(e2) {
        n.call(this, e2);
      }
      __name(i, "i"), e("../utils").inherits(i, n), i.prototype.readData = function(e2) {
        if (this.checkOffset(e2), e2 === 0)
          return new Uint8Array(0);
        var t2 = this.data.subarray(this.zero + this.index, this.zero + this.index + e2);
        return this.index += e2, t2;
      }, t.exports = i;
    }, { "../utils": 32, "./ArrayReader": 17 }], 22: [function(e, t, r) {
      var n = e("../utils"), i = e("../support"), s = e("./ArrayReader"), a = e("./StringReader"), o = e("./NodeBufferReader"), h = e("./Uint8ArrayReader");
      t.exports = function(e2) {
        var t2 = n.getTypeOf(e2);
        return n.checkSupport(t2), t2 !== "string" || i.uint8array ? t2 === "nodebuffer" ? new o(e2) : i.uint8array ? new h(n.transformTo("uint8array", e2)) : new s(n.transformTo("array", e2)) : new a(e2);
      };
    }, { "../support": 30, "../utils": 32, "./ArrayReader": 17, "./NodeBufferReader": 19, "./StringReader": 20, "./Uint8ArrayReader": 21 }], 23: [function(e, t, r) {
      r.LOCAL_FILE_HEADER = "PK", r.CENTRAL_FILE_HEADER = "PK", r.CENTRAL_DIRECTORY_END = "PK", r.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x07", r.ZIP64_CENTRAL_DIRECTORY_END = "PK", r.DATA_DESCRIPTOR = "PK\x07\b";
    }, {}], 24: [function(e, t, r) {
      var n = e("./GenericWorker"), i = e("../utils");
      function s(e2) {
        n.call(this, "ConvertWorker to " + e2), this.destType = e2;
      }
      __name(s, "s"), i.inherits(s, n), s.prototype.processChunk = function(e2) {
        this.push({ data: i.transformTo(this.destType, e2.data), meta: e2.meta });
      }, t.exports = s;
    }, { "../utils": 32, "./GenericWorker": 28 }], 25: [function(e, t, r) {
      var n = e("./GenericWorker"), i = e("../crc32");
      function s() {
        n.call(this, "Crc32Probe"), this.withStreamInfo("crc32", 0);
      }
      __name(s, "s"), e("../utils").inherits(s, n), s.prototype.processChunk = function(e2) {
        this.streamInfo.crc32 = i(e2.data, this.streamInfo.crc32 || 0), this.push(e2);
      }, t.exports = s;
    }, { "../crc32": 4, "../utils": 32, "./GenericWorker": 28 }], 26: [function(e, t, r) {
      var n = e("../utils"), i = e("./GenericWorker");
      function s(e2) {
        i.call(this, "DataLengthProbe for " + e2), this.propName = e2, this.withStreamInfo(e2, 0);
      }
      __name(s, "s"), n.inherits(s, i), s.prototype.processChunk = function(e2) {
        if (e2) {
          var t2 = this.streamInfo[this.propName] || 0;
          this.streamInfo[this.propName] = t2 + e2.data.length;
        }
        i.prototype.processChunk.call(this, e2);
      }, t.exports = s;
    }, { "../utils": 32, "./GenericWorker": 28 }], 27: [function(e, t, r) {
      var n = e("../utils"), i = e("./GenericWorker");
      function s(e2) {
        i.call(this, "DataWorker");
        var t2 = this;
        this.dataIsReady = !1, this.index = 0, this.max = 0, this.data = null, this.type = "", this._tickScheduled = !1, e2.then(function(e3) {
          t2.dataIsReady = !0, t2.data = e3, t2.max = e3 && e3.length || 0, t2.type = n.getTypeOf(e3), t2.isPaused || t2._tickAndRepeat();
        }, function(e3) {
          t2.error(e3);
        });
      }
      __name(s, "s"), n.inherits(s, i), s.prototype.cleanUp = function() {
        i.prototype.cleanUp.call(this), this.data = null;
      }, s.prototype.resume = function() {
        return !!i.prototype.resume.call(this) && (!this._tickScheduled && this.dataIsReady && (this._tickScheduled = !0, n.delay(this._tickAndRepeat, [], this)), !0);
      }, s.prototype._tickAndRepeat = function() {
        this._tickScheduled = !1, this.isPaused || this.isFinished || (this._tick(), this.isFinished || (n.delay(this._tickAndRepeat, [], this), this._tickScheduled = !0));
      }, s.prototype._tick = function() {
        if (this.isPaused || this.isFinished)
          return !1;
        var e2 = null, t2 = Math.min(this.max, this.index + 16384);
        if (this.index >= this.max)
          return this.end();
        switch (this.type) {
          case "string":
            e2 = this.data.substring(this.index, t2);
            break;
          case "uint8array":
            e2 = this.data.subarray(this.index, t2);
            break;
          case "array":
          case "nodebuffer":
            e2 = this.data.slice(this.index, t2);
        }
        return this.index = t2, this.push({ data: e2, meta: { percent: this.max ? this.index / this.max * 100 : 0 } });
      }, t.exports = s;
    }, { "../utils": 32, "./GenericWorker": 28 }], 28: [function(e, t, r) {
      function n(e2) {
        this.name = e2 || "default", this.streamInfo = {}, this.generatedError = null, this.extraStreamInfo = {}, this.isPaused = !0, this.isFinished = !1, this.isLocked = !1, this._listeners = { data: [], end: [], error: [] }, this.previous = null;
      }
      __name(n, "n"), n.prototype = { push: function(e2) {
        this.emit("data", e2);
      }, end: function() {
        if (this.isFinished)
          return !1;
        this.flush();
        try {
          this.emit("end"), this.cleanUp(), this.isFinished = !0;
        } catch (e2) {
          this.emit("error", e2);
        }
        return !0;
      }, error: function(e2) {
        return !this.isFinished && (this.isPaused ? this.generatedError = e2 : (this.isFinished = !0, this.emit("error", e2), this.previous && this.previous.error(e2), this.cleanUp()), !0);
      }, on: function(e2, t2) {
        return this._listeners[e2].push(t2), this;
      }, cleanUp: function() {
        this.streamInfo = this.generatedError = this.extraStreamInfo = null, this._listeners = [];
      }, emit: function(e2, t2) {
        if (this._listeners[e2])
          for (var r2 = 0; r2 < this._listeners[e2].length; r2++)
            this._listeners[e2][r2].call(this, t2);
      }, pipe: function(e2) {
        return e2.registerPrevious(this);
      }, registerPrevious: function(e2) {
        if (this.isLocked)
          throw new Error("The stream '" + this + "' has already been used.");
        this.streamInfo = e2.streamInfo, this.mergeStreamInfo(), this.previous = e2;
        var t2 = this;
        return e2.on("data", function(e3) {
          t2.processChunk(e3);
        }), e2.on("end", function() {
          t2.end();
        }), e2.on("error", function(e3) {
          t2.error(e3);
        }), this;
      }, pause: function() {
        return !this.isPaused && !this.isFinished && (this.isPaused = !0, this.previous && this.previous.pause(), !0);
      }, resume: function() {
        if (!this.isPaused || this.isFinished)
          return !1;
        var e2 = this.isPaused = !1;
        return this.generatedError && (this.error(this.generatedError), e2 = !0), this.previous && this.previous.resume(), !e2;
      }, flush: function() {
      }, processChunk: function(e2) {
        this.push(e2);
      }, withStreamInfo: function(e2, t2) {
        return this.extraStreamInfo[e2] = t2, this.mergeStreamInfo(), this;
      }, mergeStreamInfo: function() {
        for (var e2 in this.extraStreamInfo)
          Object.prototype.hasOwnProperty.call(this.extraStreamInfo, e2) && (this.streamInfo[e2] = this.extraStreamInfo[e2]);
      }, lock: function() {
        if (this.isLocked)
          throw new Error("The stream '" + this + "' has already been used.");
        this.isLocked = !0, this.previous && this.previous.lock();
      }, toString: function() {
        var e2 = "Worker " + this.name;
        return this.previous ? this.previous + " -> " + e2 : e2;
      } }, t.exports = n;
    }, {}], 29: [function(e, t, r) {
      var h = e("../utils"), i = e("./ConvertWorker"), s = e("./GenericWorker"), u = e("../base64"), n = e("../support"), a = e("../external"), o = null;
      if (n.nodestream)
        try {
          o = e("../nodejs/NodejsStreamOutputAdapter");
        } catch {
        }
      function l(e2, o2) {
        return new a.Promise(function(t2, r2) {
          var n2 = [], i2 = e2._internalType, s2 = e2._outputType, a2 = e2._mimeType;
          e2.on("data", function(e3, t3) {
            n2.push(e3), o2 && o2(t3);
          }).on("error", function(e3) {
            n2 = [], r2(e3);
          }).on("end", function() {
            try {
              var e3 = function(e4, t3, r3) {
                switch (e4) {
                  case "blob":
                    return h.newBlob(h.transformTo("arraybuffer", t3), r3);
                  case "base64":
                    return u.encode(t3);
                  default:
                    return h.transformTo(e4, t3);
                }
              }(s2, function(e4, t3) {
                var r3, n3 = 0, i3 = null, s3 = 0;
                for (r3 = 0; r3 < t3.length; r3++)
                  s3 += t3[r3].length;
                switch (e4) {
                  case "string":
                    return t3.join("");
                  case "array":
                    return Array.prototype.concat.apply([], t3);
                  case "uint8array":
                    for (i3 = new Uint8Array(s3), r3 = 0; r3 < t3.length; r3++)
                      i3.set(t3[r3], n3), n3 += t3[r3].length;
                    return i3;
                  case "nodebuffer":
                    return Buffer.concat(t3);
                  default:
                    throw new Error("concat : unsupported type '" + e4 + "'");
                }
              }(i2, n2), a2);
              t2(e3);
            } catch (e4) {
              r2(e4);
            }
            n2 = [];
          }).resume();
        });
      }
      __name(l, "l");
      function f(e2, t2, r2) {
        var n2 = t2;
        switch (t2) {
          case "blob":
          case "arraybuffer":
            n2 = "uint8array";
            break;
          case "base64":
            n2 = "string";
        }
        try {
          this._internalType = n2, this._outputType = t2, this._mimeType = r2, h.checkSupport(n2), this._worker = e2.pipe(new i(n2)), e2.lock();
        } catch (e3) {
          this._worker = new s("error"), this._worker.error(e3);
        }
      }
      __name(f, "f"), f.prototype = { accumulate: function(e2) {
        return l(this, e2);
      }, on: function(e2, t2) {
        var r2 = this;
        return e2 === "data" ? this._worker.on(e2, function(e3) {
          t2.call(r2, e3.data, e3.meta);
        }) : this._worker.on(e2, function() {
          h.delay(t2, arguments, r2);
        }), this;
      }, resume: function() {
        return h.delay(this._worker.resume, [], this._worker), this;
      }, pause: function() {
        return this._worker.pause(), this;
      }, toNodejsStream: function(e2) {
        if (h.checkSupport("nodestream"), this._outputType !== "nodebuffer")
          throw new Error(this._outputType + " is not supported by this method");
        return new o(this, { objectMode: this._outputType !== "nodebuffer" }, e2);
      } }, t.exports = f;
    }, { "../base64": 1, "../external": 6, "../nodejs/NodejsStreamOutputAdapter": 13, "../support": 30, "../utils": 32, "./ConvertWorker": 24, "./GenericWorker": 28 }], 30: [function(e, t, r) {
      if (r.base64 = !0, r.array = !0, r.string = !0, r.arraybuffer = typeof ArrayBuffer < "u" && typeof Uint8Array < "u", r.nodebuffer = typeof Buffer < "u", r.uint8array = typeof Uint8Array < "u", typeof ArrayBuffer > "u")
        r.blob = !1;
      else {
        var n = new ArrayBuffer(0);
        try {
          r.blob = new Blob([n], { type: "application/zip" }).size === 0;
        } catch {
          try {
            var i = new (self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder)();
            i.append(n), r.blob = i.getBlob("application/zip").size === 0;
          } catch {
            r.blob = !1;
          }
        }
      }
      try {
        r.nodestream = !!e("readable-stream").Readable;
      } catch {
        r.nodestream = !1;
      }
    }, { "readable-stream": 16 }], 31: [function(e, t, s) {
      for (var o = e("./utils"), h = e("./support"), r = e("./nodejsUtils"), n = e("./stream/GenericWorker"), u = new Array(256), i = 0; i < 256; i++)
        u[i] = 252 <= i ? 6 : 248 <= i ? 5 : 240 <= i ? 4 : 224 <= i ? 3 : 192 <= i ? 2 : 1;
      u[254] = u[254] = 1;
      function a() {
        n.call(this, "utf-8 decode"), this.leftOver = null;
      }
      __name(a, "a");
      function l() {
        n.call(this, "utf-8 encode");
      }
      __name(l, "l"), s.utf8encode = function(e2) {
        return h.nodebuffer ? r.newBufferFrom(e2, "utf-8") : function(e3) {
          var t2, r2, n2, i2, s2, a2 = e3.length, o2 = 0;
          for (i2 = 0; i2 < a2; i2++)
            (64512 & (r2 = e3.charCodeAt(i2))) == 55296 && i2 + 1 < a2 && (64512 & (n2 = e3.charCodeAt(i2 + 1))) == 56320 && (r2 = 65536 + (r2 - 55296 << 10) + (n2 - 56320), i2++), o2 += r2 < 128 ? 1 : r2 < 2048 ? 2 : r2 < 65536 ? 3 : 4;
          for (t2 = h.uint8array ? new Uint8Array(o2) : new Array(o2), i2 = s2 = 0; s2 < o2; i2++)
            (64512 & (r2 = e3.charCodeAt(i2))) == 55296 && i2 + 1 < a2 && (64512 & (n2 = e3.charCodeAt(i2 + 1))) == 56320 && (r2 = 65536 + (r2 - 55296 << 10) + (n2 - 56320), i2++), r2 < 128 ? t2[s2++] = r2 : (r2 < 2048 ? t2[s2++] = 192 | r2 >>> 6 : (r2 < 65536 ? t2[s2++] = 224 | r2 >>> 12 : (t2[s2++] = 240 | r2 >>> 18, t2[s2++] = 128 | r2 >>> 12 & 63), t2[s2++] = 128 | r2 >>> 6 & 63), t2[s2++] = 128 | 63 & r2);
          return t2;
        }(e2);
      }, s.utf8decode = function(e2) {
        return h.nodebuffer ? o.transformTo("nodebuffer", e2).toString("utf-8") : function(e3) {
          var t2, r2, n2, i2, s2 = e3.length, a2 = new Array(2 * s2);
          for (t2 = r2 = 0; t2 < s2; )
            if ((n2 = e3[t2++]) < 128)
              a2[r2++] = n2;
            else if (4 < (i2 = u[n2]))
              a2[r2++] = 65533, t2 += i2 - 1;
            else {
              for (n2 &= i2 === 2 ? 31 : i2 === 3 ? 15 : 7; 1 < i2 && t2 < s2; )
                n2 = n2 << 6 | 63 & e3[t2++], i2--;
              1 < i2 ? a2[r2++] = 65533 : n2 < 65536 ? a2[r2++] = n2 : (n2 -= 65536, a2[r2++] = 55296 | n2 >> 10 & 1023, a2[r2++] = 56320 | 1023 & n2);
            }
          return a2.length !== r2 && (a2.subarray ? a2 = a2.subarray(0, r2) : a2.length = r2), o.applyFromCharCode(a2);
        }(e2 = o.transformTo(h.uint8array ? "uint8array" : "array", e2));
      }, o.inherits(a, n), a.prototype.processChunk = function(e2) {
        var t2 = o.transformTo(h.uint8array ? "uint8array" : "array", e2.data);
        if (this.leftOver && this.leftOver.length) {
          if (h.uint8array) {
            var r2 = t2;
            (t2 = new Uint8Array(r2.length + this.leftOver.length)).set(this.leftOver, 0), t2.set(r2, this.leftOver.length);
          } else
            t2 = this.leftOver.concat(t2);
          this.leftOver = null;
        }
        var n2 = function(e3, t3) {
          var r3;
          for ((t3 = t3 || e3.length) > e3.length && (t3 = e3.length), r3 = t3 - 1; 0 <= r3 && (192 & e3[r3]) == 128; )
            r3--;
          return r3 < 0 || r3 === 0 ? t3 : r3 + u[e3[r3]] > t3 ? r3 : t3;
        }(t2), i2 = t2;
        n2 !== t2.length && (h.uint8array ? (i2 = t2.subarray(0, n2), this.leftOver = t2.subarray(n2, t2.length)) : (i2 = t2.slice(0, n2), this.leftOver = t2.slice(n2, t2.length))), this.push({ data: s.utf8decode(i2), meta: e2.meta });
      }, a.prototype.flush = function() {
        this.leftOver && this.leftOver.length && (this.push({ data: s.utf8decode(this.leftOver), meta: {} }), this.leftOver = null);
      }, s.Utf8DecodeWorker = a, o.inherits(l, n), l.prototype.processChunk = function(e2) {
        this.push({ data: s.utf8encode(e2.data), meta: e2.meta });
      }, s.Utf8EncodeWorker = l;
    }, { "./nodejsUtils": 14, "./stream/GenericWorker": 28, "./support": 30, "./utils": 32 }], 32: [function(e, t, a) {
      var o = e("./support"), h = e("./base64"), r = e("./nodejsUtils"), u = e("./external");
      function n(e2) {
        return e2;
      }
      __name(n, "n");
      function l(e2, t2) {
        for (var r2 = 0; r2 < e2.length; ++r2)
          t2[r2] = 255 & e2.charCodeAt(r2);
        return t2;
      }
      __name(l, "l"), e("setimmediate"), a.newBlob = function(t2, r2) {
        a.checkSupport("blob");
        try {
          return new Blob([t2], { type: r2 });
        } catch {
          try {
            var n2 = new (self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder)();
            return n2.append(t2), n2.getBlob(r2);
          } catch {
            throw new Error("Bug : can't construct the Blob.");
          }
        }
      };
      var i = { stringifyByChunk: function(e2, t2, r2) {
        var n2 = [], i2 = 0, s2 = e2.length;
        if (s2 <= r2)
          return String.fromCharCode.apply(null, e2);
        for (; i2 < s2; )
          t2 === "array" || t2 === "nodebuffer" ? n2.push(String.fromCharCode.apply(null, e2.slice(i2, Math.min(i2 + r2, s2)))) : n2.push(String.fromCharCode.apply(null, e2.subarray(i2, Math.min(i2 + r2, s2)))), i2 += r2;
        return n2.join("");
      }, stringifyByChar: function(e2) {
        for (var t2 = "", r2 = 0; r2 < e2.length; r2++)
          t2 += String.fromCharCode(e2[r2]);
        return t2;
      }, applyCanBeUsed: { uint8array: function() {
        try {
          return o.uint8array && String.fromCharCode.apply(null, new Uint8Array(1)).length === 1;
        } catch {
          return !1;
        }
      }(), nodebuffer: function() {
        try {
          return o.nodebuffer && String.fromCharCode.apply(null, r.allocBuffer(1)).length === 1;
        } catch {
          return !1;
        }
      }() } };
      function s(e2) {
        var t2 = 65536, r2 = a.getTypeOf(e2), n2 = !0;
        if (r2 === "uint8array" ? n2 = i.applyCanBeUsed.uint8array : r2 === "nodebuffer" && (n2 = i.applyCanBeUsed.nodebuffer), n2)
          for (; 1 < t2; )
            try {
              return i.stringifyByChunk(e2, r2, t2);
            } catch {
              t2 = Math.floor(t2 / 2);
            }
        return i.stringifyByChar(e2);
      }
      __name(s, "s");
      function f(e2, t2) {
        for (var r2 = 0; r2 < e2.length; r2++)
          t2[r2] = e2[r2];
        return t2;
      }
      __name(f, "f"), a.applyFromCharCode = s;
      var c = {};
      c.string = { string: n, array: function(e2) {
        return l(e2, new Array(e2.length));
      }, arraybuffer: function(e2) {
        return c.string.uint8array(e2).buffer;
      }, uint8array: function(e2) {
        return l(e2, new Uint8Array(e2.length));
      }, nodebuffer: function(e2) {
        return l(e2, r.allocBuffer(e2.length));
      } }, c.array = { string: s, array: n, arraybuffer: function(e2) {
        return new Uint8Array(e2).buffer;
      }, uint8array: function(e2) {
        return new Uint8Array(e2);
      }, nodebuffer: function(e2) {
        return r.newBufferFrom(e2);
      } }, c.arraybuffer = { string: function(e2) {
        return s(new Uint8Array(e2));
      }, array: function(e2) {
        return f(new Uint8Array(e2), new Array(e2.byteLength));
      }, arraybuffer: n, uint8array: function(e2) {
        return new Uint8Array(e2);
      }, nodebuffer: function(e2) {
        return r.newBufferFrom(new Uint8Array(e2));
      } }, c.uint8array = { string: s, array: function(e2) {
        return f(e2, new Array(e2.length));
      }, arraybuffer: function(e2) {
        return e2.buffer;
      }, uint8array: n, nodebuffer: function(e2) {
        return r.newBufferFrom(e2);
      } }, c.nodebuffer = { string: s, array: function(e2) {
        return f(e2, new Array(e2.length));
      }, arraybuffer: function(e2) {
        return c.nodebuffer.uint8array(e2).buffer;
      }, uint8array: function(e2) {
        return f(e2, new Uint8Array(e2.length));
      }, nodebuffer: n }, a.transformTo = function(e2, t2) {
        if (t2 = t2 || "", !e2)
          return t2;
        a.checkSupport(e2);
        var r2 = a.getTypeOf(t2);
        return c[r2][e2](t2);
      }, a.resolve = function(e2) {
        for (var t2 = e2.split("/"), r2 = [], n2 = 0; n2 < t2.length; n2++) {
          var i2 = t2[n2];
          i2 === "." || i2 === "" && n2 !== 0 && n2 !== t2.length - 1 || (i2 === ".." ? r2.pop() : r2.push(i2));
        }
        return r2.join("/");
      }, a.getTypeOf = function(e2) {
        return typeof e2 == "string" ? "string" : Object.prototype.toString.call(e2) === "[object Array]" ? "array" : o.nodebuffer && r.isBuffer(e2) ? "nodebuffer" : o.uint8array && e2 instanceof Uint8Array ? "uint8array" : o.arraybuffer && e2 instanceof ArrayBuffer ? "arraybuffer" : void 0;
      }, a.checkSupport = function(e2) {
        if (!o[e2.toLowerCase()])
          throw new Error(e2 + " is not supported by this platform");
      }, a.MAX_VALUE_16BITS = 65535, a.MAX_VALUE_32BITS = -1, a.pretty = function(e2) {
        var t2, r2, n2 = "";
        for (r2 = 0; r2 < (e2 || "").length; r2++)
          n2 += "\\x" + ((t2 = e2.charCodeAt(r2)) < 16 ? "0" : "") + t2.toString(16).toUpperCase();
        return n2;
      }, a.delay = function(e2, t2, r2) {
        setImmediate(function() {
          e2.apply(r2 || null, t2 || []);
        });
      }, a.inherits = function(e2, t2) {
        function r2() {
        }
        __name(r2, "r"), r2.prototype = t2.prototype, e2.prototype = new r2();
      }, a.extend = function() {
        var e2, t2, r2 = {};
        for (e2 = 0; e2 < arguments.length; e2++)
          for (t2 in arguments[e2])
            Object.prototype.hasOwnProperty.call(arguments[e2], t2) && r2[t2] === void 0 && (r2[t2] = arguments[e2][t2]);
        return r2;
      }, a.prepareContent = function(r2, e2, n2, i2, s2) {
        return u.Promise.resolve(e2).then(function(n3) {
          return o.blob && (n3 instanceof Blob || ["[object File]", "[object Blob]"].indexOf(Object.prototype.toString.call(n3)) !== -1) && typeof FileReader < "u" ? new u.Promise(function(t2, r3) {
            var e3 = new FileReader();
            e3.onload = function(e4) {
              t2(e4.target.result);
            }, e3.onerror = function(e4) {
              r3(e4.target.error);
            }, e3.readAsArrayBuffer(n3);
          }) : n3;
        }).then(function(e3) {
          var t2 = a.getTypeOf(e3);
          return t2 ? (t2 === "arraybuffer" ? e3 = a.transformTo("uint8array", e3) : t2 === "string" && (s2 ? e3 = h.decode(e3) : n2 && i2 !== !0 && (e3 = function(e4) {
            return l(e4, o.uint8array ? new Uint8Array(e4.length) : new Array(e4.length));
          }(e3))), e3) : u.Promise.reject(new Error("Can't read the data of '" + r2 + "'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?"));
        });
      };
    }, { "./base64": 1, "./external": 6, "./nodejsUtils": 14, "./support": 30, setimmediate: 54 }], 33: [function(e, t, r) {
      var n = e("./reader/readerFor"), i = e("./utils"), s = e("./signature"), a = e("./zipEntry"), o = e("./support");
      function h(e2) {
        this.files = [], this.loadOptions = e2;
      }
      __name(h, "h"), h.prototype = { checkSignature: function(e2) {
        if (!this.reader.readAndCheckSignature(e2)) {
          this.reader.index -= 4;
          var t2 = this.reader.readString(4);
          throw new Error("Corrupted zip or bug: unexpected signature (" + i.pretty(t2) + ", expected " + i.pretty(e2) + ")");
        }
      }, isSignature: function(e2, t2) {
        var r2 = this.reader.index;
        this.reader.setIndex(e2);
        var n2 = this.reader.readString(4) === t2;
        return this.reader.setIndex(r2), n2;
      }, readBlockEndOfCentral: function() {
        this.diskNumber = this.reader.readInt(2), this.diskWithCentralDirStart = this.reader.readInt(2), this.centralDirRecordsOnThisDisk = this.reader.readInt(2), this.centralDirRecords = this.reader.readInt(2), this.centralDirSize = this.reader.readInt(4), this.centralDirOffset = this.reader.readInt(4), this.zipCommentLength = this.reader.readInt(2);
        var e2 = this.reader.readData(this.zipCommentLength), t2 = o.uint8array ? "uint8array" : "array", r2 = i.transformTo(t2, e2);
        this.zipComment = this.loadOptions.decodeFileName(r2);
      }, readBlockZip64EndOfCentral: function() {
        this.zip64EndOfCentralSize = this.reader.readInt(8), this.reader.skip(4), this.diskNumber = this.reader.readInt(4), this.diskWithCentralDirStart = this.reader.readInt(4), this.centralDirRecordsOnThisDisk = this.reader.readInt(8), this.centralDirRecords = this.reader.readInt(8), this.centralDirSize = this.reader.readInt(8), this.centralDirOffset = this.reader.readInt(8), this.zip64ExtensibleData = {};
        for (var e2, t2, r2, n2 = this.zip64EndOfCentralSize - 44; 0 < n2; )
          e2 = this.reader.readInt(2), t2 = this.reader.readInt(4), r2 = this.reader.readData(t2), this.zip64ExtensibleData[e2] = { id: e2, length: t2, value: r2 };
      }, readBlockZip64EndOfCentralLocator: function() {
        if (this.diskWithZip64CentralDirStart = this.reader.readInt(4), this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8), this.disksCount = this.reader.readInt(4), 1 < this.disksCount)
          throw new Error("Multi-volumes zip are not supported");
      }, readLocalFiles: function() {
        var e2, t2;
        for (e2 = 0; e2 < this.files.length; e2++)
          t2 = this.files[e2], this.reader.setIndex(t2.localHeaderOffset), this.checkSignature(s.LOCAL_FILE_HEADER), t2.readLocalPart(this.reader), t2.handleUTF8(), t2.processAttributes();
      }, readCentralDir: function() {
        var e2;
        for (this.reader.setIndex(this.centralDirOffset); this.reader.readAndCheckSignature(s.CENTRAL_FILE_HEADER); )
          (e2 = new a({ zip64: this.zip64 }, this.loadOptions)).readCentralPart(this.reader), this.files.push(e2);
        if (this.centralDirRecords !== this.files.length && this.centralDirRecords !== 0 && this.files.length === 0)
          throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
      }, readEndOfCentral: function() {
        var e2 = this.reader.lastIndexOfSignature(s.CENTRAL_DIRECTORY_END);
        if (e2 < 0)
          throw this.isSignature(0, s.LOCAL_FILE_HEADER) ? new Error("Corrupted zip: can't find end of central directory") : new Error("Can't find end of central directory : is this a zip file ? If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html");
        this.reader.setIndex(e2);
        var t2 = e2;
        if (this.checkSignature(s.CENTRAL_DIRECTORY_END), this.readBlockEndOfCentral(), this.diskNumber === i.MAX_VALUE_16BITS || this.diskWithCentralDirStart === i.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === i.MAX_VALUE_16BITS || this.centralDirRecords === i.MAX_VALUE_16BITS || this.centralDirSize === i.MAX_VALUE_32BITS || this.centralDirOffset === i.MAX_VALUE_32BITS) {
          if (this.zip64 = !0, (e2 = this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR)) < 0)
            throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");
          if (this.reader.setIndex(e2), this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR), this.readBlockZip64EndOfCentralLocator(), !this.isSignature(this.relativeOffsetEndOfZip64CentralDir, s.ZIP64_CENTRAL_DIRECTORY_END) && (this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_END), this.relativeOffsetEndOfZip64CentralDir < 0))
            throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");
          this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir), this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_END), this.readBlockZip64EndOfCentral();
        }
        var r2 = this.centralDirOffset + this.centralDirSize;
        this.zip64 && (r2 += 20, r2 += 12 + this.zip64EndOfCentralSize);
        var n2 = t2 - r2;
        if (0 < n2)
          this.isSignature(t2, s.CENTRAL_FILE_HEADER) || (this.reader.zero = n2);
        else if (n2 < 0)
          throw new Error("Corrupted zip: missing " + Math.abs(n2) + " bytes.");
      }, prepareReader: function(e2) {
        this.reader = n(e2);
      }, load: function(e2) {
        this.prepareReader(e2), this.readEndOfCentral(), this.readCentralDir(), this.readLocalFiles();
      } }, t.exports = h;
    }, { "./reader/readerFor": 22, "./signature": 23, "./support": 30, "./utils": 32, "./zipEntry": 34 }], 34: [function(e, t, r) {
      var n = e("./reader/readerFor"), s = e("./utils"), i = e("./compressedObject"), a = e("./crc32"), o = e("./utf8"), h = e("./compressions"), u = e("./support");
      function l(e2, t2) {
        this.options = e2, this.loadOptions = t2;
      }
      __name(l, "l"), l.prototype = { isEncrypted: function() {
        return (1 & this.bitFlag) == 1;
      }, useUTF8: function() {
        return (2048 & this.bitFlag) == 2048;
      }, readLocalPart: function(e2) {
        var t2, r2;
        if (e2.skip(22), this.fileNameLength = e2.readInt(2), r2 = e2.readInt(2), this.fileName = e2.readData(this.fileNameLength), e2.skip(r2), this.compressedSize === -1 || this.uncompressedSize === -1)
          throw new Error("Bug or corrupted zip : didn't get enough information from the central directory (compressedSize === -1 || uncompressedSize === -1)");
        if ((t2 = function(e3) {
          for (var t3 in h)
            if (Object.prototype.hasOwnProperty.call(h, t3) && h[t3].magic === e3)
              return h[t3];
          return null;
        }(this.compressionMethod)) === null)
          throw new Error("Corrupted zip : compression " + s.pretty(this.compressionMethod) + " unknown (inner file : " + s.transformTo("string", this.fileName) + ")");
        this.decompressed = new i(this.compressedSize, this.uncompressedSize, this.crc32, t2, e2.readData(this.compressedSize));
      }, readCentralPart: function(e2) {
        this.versionMadeBy = e2.readInt(2), e2.skip(2), this.bitFlag = e2.readInt(2), this.compressionMethod = e2.readString(2), this.date = e2.readDate(), this.crc32 = e2.readInt(4), this.compressedSize = e2.readInt(4), this.uncompressedSize = e2.readInt(4);
        var t2 = e2.readInt(2);
        if (this.extraFieldsLength = e2.readInt(2), this.fileCommentLength = e2.readInt(2), this.diskNumberStart = e2.readInt(2), this.internalFileAttributes = e2.readInt(2), this.externalFileAttributes = e2.readInt(4), this.localHeaderOffset = e2.readInt(4), this.isEncrypted())
          throw new Error("Encrypted zip are not supported");
        e2.skip(t2), this.readExtraFields(e2), this.parseZIP64ExtraField(e2), this.fileComment = e2.readData(this.fileCommentLength);
      }, processAttributes: function() {
        this.unixPermissions = null, this.dosPermissions = null;
        var e2 = this.versionMadeBy >> 8;
        this.dir = !!(16 & this.externalFileAttributes), e2 == 0 && (this.dosPermissions = 63 & this.externalFileAttributes), e2 == 3 && (this.unixPermissions = this.externalFileAttributes >> 16 & 65535), this.dir || this.fileNameStr.slice(-1) !== "/" || (this.dir = !0);
      }, parseZIP64ExtraField: function() {
        if (this.extraFields[1]) {
          var e2 = n(this.extraFields[1].value);
          this.uncompressedSize === s.MAX_VALUE_32BITS && (this.uncompressedSize = e2.readInt(8)), this.compressedSize === s.MAX_VALUE_32BITS && (this.compressedSize = e2.readInt(8)), this.localHeaderOffset === s.MAX_VALUE_32BITS && (this.localHeaderOffset = e2.readInt(8)), this.diskNumberStart === s.MAX_VALUE_32BITS && (this.diskNumberStart = e2.readInt(4));
        }
      }, readExtraFields: function(e2) {
        var t2, r2, n2, i2 = e2.index + this.extraFieldsLength;
        for (this.extraFields || (this.extraFields = {}); e2.index + 4 < i2; )
          t2 = e2.readInt(2), r2 = e2.readInt(2), n2 = e2.readData(r2), this.extraFields[t2] = { id: t2, length: r2, value: n2 };
        e2.setIndex(i2);
      }, handleUTF8: function() {
        var e2 = u.uint8array ? "uint8array" : "array";
        if (this.useUTF8())
          this.fileNameStr = o.utf8decode(this.fileName), this.fileCommentStr = o.utf8decode(this.fileComment);
        else {
          var t2 = this.findExtraFieldUnicodePath();
          if (t2 !== null)
            this.fileNameStr = t2;
          else {
            var r2 = s.transformTo(e2, this.fileName);
            this.fileNameStr = this.loadOptions.decodeFileName(r2);
          }
          var n2 = this.findExtraFieldUnicodeComment();
          if (n2 !== null)
            this.fileCommentStr = n2;
          else {
            var i2 = s.transformTo(e2, this.fileComment);
            this.fileCommentStr = this.loadOptions.decodeFileName(i2);
          }
        }
      }, findExtraFieldUnicodePath: function() {
        var e2 = this.extraFields[28789];
        if (e2) {
          var t2 = n(e2.value);
          return t2.readInt(1) !== 1 || a(this.fileName) !== t2.readInt(4) ? null : o.utf8decode(t2.readData(e2.length - 5));
        }
        return null;
      }, findExtraFieldUnicodeComment: function() {
        var e2 = this.extraFields[25461];
        if (e2) {
          var t2 = n(e2.value);
          return t2.readInt(1) !== 1 || a(this.fileComment) !== t2.readInt(4) ? null : o.utf8decode(t2.readData(e2.length - 5));
        }
        return null;
      } }, t.exports = l;
    }, { "./compressedObject": 2, "./compressions": 3, "./crc32": 4, "./reader/readerFor": 22, "./support": 30, "./utf8": 31, "./utils": 32 }], 35: [function(e, t, r) {
      function n(e2, t2, r2) {
        this.name = e2, this.dir = r2.dir, this.date = r2.date, this.comment = r2.comment, this.unixPermissions = r2.unixPermissions, this.dosPermissions = r2.dosPermissions, this._data = t2, this._dataBinary = r2.binary, this.options = { compression: r2.compression, compressionOptions: r2.compressionOptions };
      }
      __name(n, "n");
      var s = e("./stream/StreamHelper"), i = e("./stream/DataWorker"), a = e("./utf8"), o = e("./compressedObject"), h = e("./stream/GenericWorker");
      n.prototype = { internalStream: function(e2) {
        var t2 = null, r2 = "string";
        try {
          if (!e2)
            throw new Error("No output type specified.");
          var n2 = (r2 = e2.toLowerCase()) === "string" || r2 === "text";
          r2 !== "binarystring" && r2 !== "text" || (r2 = "string"), t2 = this._decompressWorker();
          var i2 = !this._dataBinary;
          i2 && !n2 && (t2 = t2.pipe(new a.Utf8EncodeWorker())), !i2 && n2 && (t2 = t2.pipe(new a.Utf8DecodeWorker()));
        } catch (e3) {
          (t2 = new h("error")).error(e3);
        }
        return new s(t2, r2, "");
      }, async: function(e2, t2) {
        return this.internalStream(e2).accumulate(t2);
      }, nodeStream: function(e2, t2) {
        return this.internalStream(e2 || "nodebuffer").toNodejsStream(t2);
      }, _compressWorker: function(e2, t2) {
        if (this._data instanceof o && this._data.compression.magic === e2.magic)
          return this._data.getCompressedWorker();
        var r2 = this._decompressWorker();
        return this._dataBinary || (r2 = r2.pipe(new a.Utf8EncodeWorker())), o.createWorkerFrom(r2, e2, t2);
      }, _decompressWorker: function() {
        return this._data instanceof o ? this._data.getContentWorker() : this._data instanceof h ? this._data : new i(this._data);
      } };
      for (var u = ["asText", "asBinary", "asNodeBuffer", "asUint8Array", "asArrayBuffer"], l = function() {
        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
      }, f = 0; f < u.length; f++)
        n.prototype[u[f]] = l;
      t.exports = n;
    }, { "./compressedObject": 2, "./stream/DataWorker": 27, "./stream/GenericWorker": 28, "./stream/StreamHelper": 29, "./utf8": 31 }], 36: [function(e, l, t) {
      (function(t2) {
        var r, n, e2 = t2.MutationObserver || t2.WebKitMutationObserver;
        if (e2) {
          var i = 0, s = new e2(u), a = t2.document.createTextNode("");
          s.observe(a, { characterData: !0 }), r = /* @__PURE__ */ __name(function() {
            a.data = i = ++i % 2;
          }, "r");
        } else if (t2.setImmediate || t2.MessageChannel === void 0)
          r = "document" in t2 && "onreadystatechange" in t2.document.createElement("script") ? function() {
            var e3 = t2.document.createElement("script");
            e3.onreadystatechange = function() {
              u(), e3.onreadystatechange = null, e3.parentNode.removeChild(e3), e3 = null;
            }, t2.document.documentElement.appendChild(e3);
          } : function() {
            setTimeout(u, 0);
          };
        else {
          var o = new t2.MessageChannel();
          o.port1.onmessage = u, r = /* @__PURE__ */ __name(function() {
            o.port2.postMessage(0);
          }, "r");
        }
        var h = [];
        function u() {
          var e3, t3;
          n = !0;
          for (var r2 = h.length; r2; ) {
            for (t3 = h, h = [], e3 = -1; ++e3 < r2; )
              t3[e3]();
            r2 = h.length;
          }
          n = !1;
        }
        __name(u, "u"), l.exports = function(e3) {
          h.push(e3) !== 1 || n || r();
        };
      }).call(this, typeof commonjsGlobal < "u" ? commonjsGlobal : typeof self < "u" ? self : typeof window < "u" ? window : {});
    }, {}], 37: [function(e, t, r) {
      var i = e("immediate");
      function u() {
      }
      __name(u, "u");
      var l = {}, s = ["REJECTED"], a = ["FULFILLED"], n = ["PENDING"];
      function o(e2) {
        if (typeof e2 != "function")
          throw new TypeError("resolver must be a function");
        this.state = n, this.queue = [], this.outcome = void 0, e2 !== u && d(this, e2);
      }
      __name(o, "o");
      function h(e2, t2, r2) {
        this.promise = e2, typeof t2 == "function" && (this.onFulfilled = t2, this.callFulfilled = this.otherCallFulfilled), typeof r2 == "function" && (this.onRejected = r2, this.callRejected = this.otherCallRejected);
      }
      __name(h, "h");
      function f(t2, r2, n2) {
        i(function() {
          var e2;
          try {
            e2 = r2(n2);
          } catch (e3) {
            return l.reject(t2, e3);
          }
          e2 === t2 ? l.reject(t2, new TypeError("Cannot resolve promise with itself")) : l.resolve(t2, e2);
        });
      }
      __name(f, "f");
      function c(e2) {
        var t2 = e2 && e2.then;
        if (e2 && (typeof e2 == "object" || typeof e2 == "function") && typeof t2 == "function")
          return function() {
            t2.apply(e2, arguments);
          };
      }
      __name(c, "c");
      function d(t2, e2) {
        var r2 = !1;
        function n2(e3) {
          r2 || (r2 = !0, l.reject(t2, e3));
        }
        __name(n2, "n");
        function i2(e3) {
          r2 || (r2 = !0, l.resolve(t2, e3));
        }
        __name(i2, "i");
        var s2 = p(function() {
          e2(i2, n2);
        });
        s2.status === "error" && n2(s2.value);
      }
      __name(d, "d");
      function p(e2, t2) {
        var r2 = {};
        try {
          r2.value = e2(t2), r2.status = "success";
        } catch (e3) {
          r2.status = "error", r2.value = e3;
        }
        return r2;
      }
      __name(p, "p"), (t.exports = o).prototype.finally = function(t2) {
        if (typeof t2 != "function")
          return this;
        var r2 = this.constructor;
        return this.then(function(e2) {
          return r2.resolve(t2()).then(function() {
            return e2;
          });
        }, function(e2) {
          return r2.resolve(t2()).then(function() {
            throw e2;
          });
        });
      }, o.prototype.catch = function(e2) {
        return this.then(null, e2);
      }, o.prototype.then = function(e2, t2) {
        if (typeof e2 != "function" && this.state === a || typeof t2 != "function" && this.state === s)
          return this;
        var r2 = new this.constructor(u);
        return this.state !== n ? f(r2, this.state === a ? e2 : t2, this.outcome) : this.queue.push(new h(r2, e2, t2)), r2;
      }, h.prototype.callFulfilled = function(e2) {
        l.resolve(this.promise, e2);
      }, h.prototype.otherCallFulfilled = function(e2) {
        f(this.promise, this.onFulfilled, e2);
      }, h.prototype.callRejected = function(e2) {
        l.reject(this.promise, e2);
      }, h.prototype.otherCallRejected = function(e2) {
        f(this.promise, this.onRejected, e2);
      }, l.resolve = function(e2, t2) {
        var r2 = p(c, t2);
        if (r2.status === "error")
          return l.reject(e2, r2.value);
        var n2 = r2.value;
        if (n2)
          d(e2, n2);
        else {
          e2.state = a, e2.outcome = t2;
          for (var i2 = -1, s2 = e2.queue.length; ++i2 < s2; )
            e2.queue[i2].callFulfilled(t2);
        }
        return e2;
      }, l.reject = function(e2, t2) {
        e2.state = s, e2.outcome = t2;
        for (var r2 = -1, n2 = e2.queue.length; ++r2 < n2; )
          e2.queue[r2].callRejected(t2);
        return e2;
      }, o.resolve = function(e2) {
        return e2 instanceof this ? e2 : l.resolve(new this(u), e2);
      }, o.reject = function(e2) {
        var t2 = new this(u);
        return l.reject(t2, e2);
      }, o.all = function(e2) {
        var r2 = this;
        if (Object.prototype.toString.call(e2) !== "[object Array]")
          return this.reject(new TypeError("must be an array"));
        var n2 = e2.length, i2 = !1;
        if (!n2)
          return this.resolve([]);
        for (var s2 = new Array(n2), a2 = 0, t2 = -1, o2 = new this(u); ++t2 < n2; )
          h2(e2[t2], t2);
        return o2;
        function h2(e3, t3) {
          r2.resolve(e3).then(function(e4) {
            s2[t3] = e4, ++a2 !== n2 || i2 || (i2 = !0, l.resolve(o2, s2));
          }, function(e4) {
            i2 || (i2 = !0, l.reject(o2, e4));
          });
        }
      }, o.race = function(e2) {
        var t2 = this;
        if (Object.prototype.toString.call(e2) !== "[object Array]")
          return this.reject(new TypeError("must be an array"));
        var r2 = e2.length, n2 = !1;
        if (!r2)
          return this.resolve([]);
        for (var i2 = -1, s2 = new this(u); ++i2 < r2; )
          a2 = e2[i2], t2.resolve(a2).then(function(e3) {
            n2 || (n2 = !0, l.resolve(s2, e3));
          }, function(e3) {
            n2 || (n2 = !0, l.reject(s2, e3));
          });
        var a2;
        return s2;
      };
    }, { immediate: 36 }], 38: [function(e, t, r) {
      var n = {};
      (0, e("./lib/utils/common").assign)(n, e("./lib/deflate"), e("./lib/inflate"), e("./lib/zlib/constants")), t.exports = n;
    }, { "./lib/deflate": 39, "./lib/inflate": 40, "./lib/utils/common": 41, "./lib/zlib/constants": 44 }], 39: [function(e, t, r) {
      var a = e("./zlib/deflate"), o = e("./utils/common"), h = e("./utils/strings"), i = e("./zlib/messages"), s = e("./zlib/zstream"), u = Object.prototype.toString, l = 0, f = -1, c = 0, d = 8;
      function p(e2) {
        if (!(this instanceof p))
          return new p(e2);
        this.options = o.assign({ level: f, method: d, chunkSize: 16384, windowBits: 15, memLevel: 8, strategy: c, to: "" }, e2 || {});
        var t2 = this.options;
        t2.raw && 0 < t2.windowBits ? t2.windowBits = -t2.windowBits : t2.gzip && 0 < t2.windowBits && t2.windowBits < 16 && (t2.windowBits += 16), this.err = 0, this.msg = "", this.ended = !1, this.chunks = [], this.strm = new s(), this.strm.avail_out = 0;
        var r2 = a.deflateInit2(this.strm, t2.level, t2.method, t2.windowBits, t2.memLevel, t2.strategy);
        if (r2 !== l)
          throw new Error(i[r2]);
        if (t2.header && a.deflateSetHeader(this.strm, t2.header), t2.dictionary) {
          var n2;
          if (n2 = typeof t2.dictionary == "string" ? h.string2buf(t2.dictionary) : u.call(t2.dictionary) === "[object ArrayBuffer]" ? new Uint8Array(t2.dictionary) : t2.dictionary, (r2 = a.deflateSetDictionary(this.strm, n2)) !== l)
            throw new Error(i[r2]);
          this._dict_set = !0;
        }
      }
      __name(p, "p");
      function n(e2, t2) {
        var r2 = new p(t2);
        if (r2.push(e2, !0), r2.err)
          throw r2.msg || i[r2.err];
        return r2.result;
      }
      __name(n, "n"), p.prototype.push = function(e2, t2) {
        var r2, n2, i2 = this.strm, s2 = this.options.chunkSize;
        if (this.ended)
          return !1;
        n2 = t2 === ~~t2 ? t2 : t2 === !0 ? 4 : 0, typeof e2 == "string" ? i2.input = h.string2buf(e2) : u.call(e2) === "[object ArrayBuffer]" ? i2.input = new Uint8Array(e2) : i2.input = e2, i2.next_in = 0, i2.avail_in = i2.input.length;
        do {
          if (i2.avail_out === 0 && (i2.output = new o.Buf8(s2), i2.next_out = 0, i2.avail_out = s2), (r2 = a.deflate(i2, n2)) !== 1 && r2 !== l)
            return this.onEnd(r2), !(this.ended = !0);
          i2.avail_out !== 0 && (i2.avail_in !== 0 || n2 !== 4 && n2 !== 2) || (this.options.to === "string" ? this.onData(h.buf2binstring(o.shrinkBuf(i2.output, i2.next_out))) : this.onData(o.shrinkBuf(i2.output, i2.next_out)));
        } while ((0 < i2.avail_in || i2.avail_out === 0) && r2 !== 1);
        return n2 === 4 ? (r2 = a.deflateEnd(this.strm), this.onEnd(r2), this.ended = !0, r2 === l) : n2 !== 2 || (this.onEnd(l), !(i2.avail_out = 0));
      }, p.prototype.onData = function(e2) {
        this.chunks.push(e2);
      }, p.prototype.onEnd = function(e2) {
        e2 === l && (this.options.to === "string" ? this.result = this.chunks.join("") : this.result = o.flattenChunks(this.chunks)), this.chunks = [], this.err = e2, this.msg = this.strm.msg;
      }, r.Deflate = p, r.deflate = n, r.deflateRaw = function(e2, t2) {
        return (t2 = t2 || {}).raw = !0, n(e2, t2);
      }, r.gzip = function(e2, t2) {
        return (t2 = t2 || {}).gzip = !0, n(e2, t2);
      };
    }, { "./utils/common": 41, "./utils/strings": 42, "./zlib/deflate": 46, "./zlib/messages": 51, "./zlib/zstream": 53 }], 40: [function(e, t, r) {
      var c = e("./zlib/inflate"), d = e("./utils/common"), p = e("./utils/strings"), m = e("./zlib/constants"), n = e("./zlib/messages"), i = e("./zlib/zstream"), s = e("./zlib/gzheader"), _ = Object.prototype.toString;
      function a(e2) {
        if (!(this instanceof a))
          return new a(e2);
        this.options = d.assign({ chunkSize: 16384, windowBits: 0, to: "" }, e2 || {});
        var t2 = this.options;
        t2.raw && 0 <= t2.windowBits && t2.windowBits < 16 && (t2.windowBits = -t2.windowBits, t2.windowBits === 0 && (t2.windowBits = -15)), !(0 <= t2.windowBits && t2.windowBits < 16) || e2 && e2.windowBits || (t2.windowBits += 32), 15 < t2.windowBits && t2.windowBits < 48 && !(15 & t2.windowBits) && (t2.windowBits |= 15), this.err = 0, this.msg = "", this.ended = !1, this.chunks = [], this.strm = new i(), this.strm.avail_out = 0;
        var r2 = c.inflateInit2(this.strm, t2.windowBits);
        if (r2 !== m.Z_OK)
          throw new Error(n[r2]);
        this.header = new s(), c.inflateGetHeader(this.strm, this.header);
      }
      __name(a, "a");
      function o(e2, t2) {
        var r2 = new a(t2);
        if (r2.push(e2, !0), r2.err)
          throw r2.msg || n[r2.err];
        return r2.result;
      }
      __name(o, "o"), a.prototype.push = function(e2, t2) {
        var r2, n2, i2, s2, a2, o2, h = this.strm, u = this.options.chunkSize, l = this.options.dictionary, f = !1;
        if (this.ended)
          return !1;
        n2 = t2 === ~~t2 ? t2 : t2 === !0 ? m.Z_FINISH : m.Z_NO_FLUSH, typeof e2 == "string" ? h.input = p.binstring2buf(e2) : _.call(e2) === "[object ArrayBuffer]" ? h.input = new Uint8Array(e2) : h.input = e2, h.next_in = 0, h.avail_in = h.input.length;
        do {
          if (h.avail_out === 0 && (h.output = new d.Buf8(u), h.next_out = 0, h.avail_out = u), (r2 = c.inflate(h, m.Z_NO_FLUSH)) === m.Z_NEED_DICT && l && (o2 = typeof l == "string" ? p.string2buf(l) : _.call(l) === "[object ArrayBuffer]" ? new Uint8Array(l) : l, r2 = c.inflateSetDictionary(this.strm, o2)), r2 === m.Z_BUF_ERROR && f === !0 && (r2 = m.Z_OK, f = !1), r2 !== m.Z_STREAM_END && r2 !== m.Z_OK)
            return this.onEnd(r2), !(this.ended = !0);
          h.next_out && (h.avail_out !== 0 && r2 !== m.Z_STREAM_END && (h.avail_in !== 0 || n2 !== m.Z_FINISH && n2 !== m.Z_SYNC_FLUSH) || (this.options.to === "string" ? (i2 = p.utf8border(h.output, h.next_out), s2 = h.next_out - i2, a2 = p.buf2string(h.output, i2), h.next_out = s2, h.avail_out = u - s2, s2 && d.arraySet(h.output, h.output, i2, s2, 0), this.onData(a2)) : this.onData(d.shrinkBuf(h.output, h.next_out)))), h.avail_in === 0 && h.avail_out === 0 && (f = !0);
        } while ((0 < h.avail_in || h.avail_out === 0) && r2 !== m.Z_STREAM_END);
        return r2 === m.Z_STREAM_END && (n2 = m.Z_FINISH), n2 === m.Z_FINISH ? (r2 = c.inflateEnd(this.strm), this.onEnd(r2), this.ended = !0, r2 === m.Z_OK) : n2 !== m.Z_SYNC_FLUSH || (this.onEnd(m.Z_OK), !(h.avail_out = 0));
      }, a.prototype.onData = function(e2) {
        this.chunks.push(e2);
      }, a.prototype.onEnd = function(e2) {
        e2 === m.Z_OK && (this.options.to === "string" ? this.result = this.chunks.join("") : this.result = d.flattenChunks(this.chunks)), this.chunks = [], this.err = e2, this.msg = this.strm.msg;
      }, r.Inflate = a, r.inflate = o, r.inflateRaw = function(e2, t2) {
        return (t2 = t2 || {}).raw = !0, o(e2, t2);
      }, r.ungzip = o;
    }, { "./utils/common": 41, "./utils/strings": 42, "./zlib/constants": 44, "./zlib/gzheader": 47, "./zlib/inflate": 49, "./zlib/messages": 51, "./zlib/zstream": 53 }], 41: [function(e, t, r) {
      var n = typeof Uint8Array < "u" && typeof Uint16Array < "u" && typeof Int32Array < "u";
      r.assign = function(e2) {
        for (var t2 = Array.prototype.slice.call(arguments, 1); t2.length; ) {
          var r2 = t2.shift();
          if (r2) {
            if (typeof r2 != "object")
              throw new TypeError(r2 + "must be non-object");
            for (var n2 in r2)
              r2.hasOwnProperty(n2) && (e2[n2] = r2[n2]);
          }
        }
        return e2;
      }, r.shrinkBuf = function(e2, t2) {
        return e2.length === t2 ? e2 : e2.subarray ? e2.subarray(0, t2) : (e2.length = t2, e2);
      };
      var i = { arraySet: function(e2, t2, r2, n2, i2) {
        if (t2.subarray && e2.subarray)
          e2.set(t2.subarray(r2, r2 + n2), i2);
        else
          for (var s2 = 0; s2 < n2; s2++)
            e2[i2 + s2] = t2[r2 + s2];
      }, flattenChunks: function(e2) {
        var t2, r2, n2, i2, s2, a;
        for (t2 = n2 = 0, r2 = e2.length; t2 < r2; t2++)
          n2 += e2[t2].length;
        for (a = new Uint8Array(n2), t2 = i2 = 0, r2 = e2.length; t2 < r2; t2++)
          s2 = e2[t2], a.set(s2, i2), i2 += s2.length;
        return a;
      } }, s = { arraySet: function(e2, t2, r2, n2, i2) {
        for (var s2 = 0; s2 < n2; s2++)
          e2[i2 + s2] = t2[r2 + s2];
      }, flattenChunks: function(e2) {
        return [].concat.apply([], e2);
      } };
      r.setTyped = function(e2) {
        e2 ? (r.Buf8 = Uint8Array, r.Buf16 = Uint16Array, r.Buf32 = Int32Array, r.assign(r, i)) : (r.Buf8 = Array, r.Buf16 = Array, r.Buf32 = Array, r.assign(r, s));
      }, r.setTyped(n);
    }, {}], 42: [function(e, t, r) {
      var h = e("./common"), i = !0, s = !0;
      try {
        String.fromCharCode.apply(null, [0]);
      } catch {
        i = !1;
      }
      try {
        String.fromCharCode.apply(null, new Uint8Array(1));
      } catch {
        s = !1;
      }
      for (var u = new h.Buf8(256), n = 0; n < 256; n++)
        u[n] = 252 <= n ? 6 : 248 <= n ? 5 : 240 <= n ? 4 : 224 <= n ? 3 : 192 <= n ? 2 : 1;
      function l(e2, t2) {
        if (t2 < 65537 && (e2.subarray && s || !e2.subarray && i))
          return String.fromCharCode.apply(null, h.shrinkBuf(e2, t2));
        for (var r2 = "", n2 = 0; n2 < t2; n2++)
          r2 += String.fromCharCode(e2[n2]);
        return r2;
      }
      __name(l, "l"), u[254] = u[254] = 1, r.string2buf = function(e2) {
        var t2, r2, n2, i2, s2, a = e2.length, o = 0;
        for (i2 = 0; i2 < a; i2++)
          (64512 & (r2 = e2.charCodeAt(i2))) == 55296 && i2 + 1 < a && (64512 & (n2 = e2.charCodeAt(i2 + 1))) == 56320 && (r2 = 65536 + (r2 - 55296 << 10) + (n2 - 56320), i2++), o += r2 < 128 ? 1 : r2 < 2048 ? 2 : r2 < 65536 ? 3 : 4;
        for (t2 = new h.Buf8(o), i2 = s2 = 0; s2 < o; i2++)
          (64512 & (r2 = e2.charCodeAt(i2))) == 55296 && i2 + 1 < a && (64512 & (n2 = e2.charCodeAt(i2 + 1))) == 56320 && (r2 = 65536 + (r2 - 55296 << 10) + (n2 - 56320), i2++), r2 < 128 ? t2[s2++] = r2 : (r2 < 2048 ? t2[s2++] = 192 | r2 >>> 6 : (r2 < 65536 ? t2[s2++] = 224 | r2 >>> 12 : (t2[s2++] = 240 | r2 >>> 18, t2[s2++] = 128 | r2 >>> 12 & 63), t2[s2++] = 128 | r2 >>> 6 & 63), t2[s2++] = 128 | 63 & r2);
        return t2;
      }, r.buf2binstring = function(e2) {
        return l(e2, e2.length);
      }, r.binstring2buf = function(e2) {
        for (var t2 = new h.Buf8(e2.length), r2 = 0, n2 = t2.length; r2 < n2; r2++)
          t2[r2] = e2.charCodeAt(r2);
        return t2;
      }, r.buf2string = function(e2, t2) {
        var r2, n2, i2, s2, a = t2 || e2.length, o = new Array(2 * a);
        for (r2 = n2 = 0; r2 < a; )
          if ((i2 = e2[r2++]) < 128)
            o[n2++] = i2;
          else if (4 < (s2 = u[i2]))
            o[n2++] = 65533, r2 += s2 - 1;
          else {
            for (i2 &= s2 === 2 ? 31 : s2 === 3 ? 15 : 7; 1 < s2 && r2 < a; )
              i2 = i2 << 6 | 63 & e2[r2++], s2--;
            1 < s2 ? o[n2++] = 65533 : i2 < 65536 ? o[n2++] = i2 : (i2 -= 65536, o[n2++] = 55296 | i2 >> 10 & 1023, o[n2++] = 56320 | 1023 & i2);
          }
        return l(o, n2);
      }, r.utf8border = function(e2, t2) {
        var r2;
        for ((t2 = t2 || e2.length) > e2.length && (t2 = e2.length), r2 = t2 - 1; 0 <= r2 && (192 & e2[r2]) == 128; )
          r2--;
        return r2 < 0 || r2 === 0 ? t2 : r2 + u[e2[r2]] > t2 ? r2 : t2;
      };
    }, { "./common": 41 }], 43: [function(e, t, r) {
      t.exports = function(e2, t2, r2, n) {
        for (var i = 65535 & e2 | 0, s = e2 >>> 16 & 65535 | 0, a = 0; r2 !== 0; ) {
          for (r2 -= a = 2e3 < r2 ? 2e3 : r2; s = s + (i = i + t2[n++] | 0) | 0, --a; )
            ;
          i %= 65521, s %= 65521;
        }
        return i | s << 16 | 0;
      };
    }, {}], 44: [function(e, t, r) {
      t.exports = { Z_NO_FLUSH: 0, Z_PARTIAL_FLUSH: 1, Z_SYNC_FLUSH: 2, Z_FULL_FLUSH: 3, Z_FINISH: 4, Z_BLOCK: 5, Z_TREES: 6, Z_OK: 0, Z_STREAM_END: 1, Z_NEED_DICT: 2, Z_ERRNO: -1, Z_STREAM_ERROR: -2, Z_DATA_ERROR: -3, Z_BUF_ERROR: -5, Z_NO_COMPRESSION: 0, Z_BEST_SPEED: 1, Z_BEST_COMPRESSION: 9, Z_DEFAULT_COMPRESSION: -1, Z_FILTERED: 1, Z_HUFFMAN_ONLY: 2, Z_RLE: 3, Z_FIXED: 4, Z_DEFAULT_STRATEGY: 0, Z_BINARY: 0, Z_TEXT: 1, Z_UNKNOWN: 2, Z_DEFLATED: 8 };
    }, {}], 45: [function(e, t, r) {
      var o = function() {
        for (var e2, t2 = [], r2 = 0; r2 < 256; r2++) {
          e2 = r2;
          for (var n = 0; n < 8; n++)
            e2 = 1 & e2 ? 3988292384 ^ e2 >>> 1 : e2 >>> 1;
          t2[r2] = e2;
        }
        return t2;
      }();
      t.exports = function(e2, t2, r2, n) {
        var i = o, s = n + r2;
        e2 ^= -1;
        for (var a = n; a < s; a++)
          e2 = e2 >>> 8 ^ i[255 & (e2 ^ t2[a])];
        return -1 ^ e2;
      };
    }, {}], 46: [function(e, t, r) {
      var h, c = e("../utils/common"), u = e("./trees"), d = e("./adler32"), p = e("./crc32"), n = e("./messages"), l = 0, f = 4, m = 0, _ = -2, g = -1, b = 4, i = 2, v = 8, y = 9, s = 286, a = 30, o = 19, w = 2 * s + 1, k = 15, x = 3, S = 258, z = S + x + 1, C = 42, E = 113, A = 1, I = 2, O = 3, B = 4;
      function R(e2, t2) {
        return e2.msg = n[t2], t2;
      }
      __name(R, "R");
      function T(e2) {
        return (e2 << 1) - (4 < e2 ? 9 : 0);
      }
      __name(T, "T");
      function D(e2) {
        for (var t2 = e2.length; 0 <= --t2; )
          e2[t2] = 0;
      }
      __name(D, "D");
      function F(e2) {
        var t2 = e2.state, r2 = t2.pending;
        r2 > e2.avail_out && (r2 = e2.avail_out), r2 !== 0 && (c.arraySet(e2.output, t2.pending_buf, t2.pending_out, r2, e2.next_out), e2.next_out += r2, t2.pending_out += r2, e2.total_out += r2, e2.avail_out -= r2, t2.pending -= r2, t2.pending === 0 && (t2.pending_out = 0));
      }
      __name(F, "F");
      function N(e2, t2) {
        u._tr_flush_block(e2, 0 <= e2.block_start ? e2.block_start : -1, e2.strstart - e2.block_start, t2), e2.block_start = e2.strstart, F(e2.strm);
      }
      __name(N, "N");
      function U(e2, t2) {
        e2.pending_buf[e2.pending++] = t2;
      }
      __name(U, "U");
      function P(e2, t2) {
        e2.pending_buf[e2.pending++] = t2 >>> 8 & 255, e2.pending_buf[e2.pending++] = 255 & t2;
      }
      __name(P, "P");
      function L(e2, t2) {
        var r2, n2, i2 = e2.max_chain_length, s2 = e2.strstart, a2 = e2.prev_length, o2 = e2.nice_match, h2 = e2.strstart > e2.w_size - z ? e2.strstart - (e2.w_size - z) : 0, u2 = e2.window, l2 = e2.w_mask, f2 = e2.prev, c2 = e2.strstart + S, d2 = u2[s2 + a2 - 1], p2 = u2[s2 + a2];
        e2.prev_length >= e2.good_match && (i2 >>= 2), o2 > e2.lookahead && (o2 = e2.lookahead);
        do
          if (u2[(r2 = t2) + a2] === p2 && u2[r2 + a2 - 1] === d2 && u2[r2] === u2[s2] && u2[++r2] === u2[s2 + 1]) {
            s2 += 2, r2++;
            do
              ;
            while (u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && u2[++s2] === u2[++r2] && s2 < c2);
            if (n2 = S - (c2 - s2), s2 = c2 - S, a2 < n2) {
              if (e2.match_start = t2, o2 <= (a2 = n2))
                break;
              d2 = u2[s2 + a2 - 1], p2 = u2[s2 + a2];
            }
          }
        while ((t2 = f2[t2 & l2]) > h2 && --i2 != 0);
        return a2 <= e2.lookahead ? a2 : e2.lookahead;
      }
      __name(L, "L");
      function j(e2) {
        var t2, r2, n2, i2, s2, a2, o2, h2, u2, l2, f2 = e2.w_size;
        do {
          if (i2 = e2.window_size - e2.lookahead - e2.strstart, e2.strstart >= f2 + (f2 - z)) {
            for (c.arraySet(e2.window, e2.window, f2, f2, 0), e2.match_start -= f2, e2.strstart -= f2, e2.block_start -= f2, t2 = r2 = e2.hash_size; n2 = e2.head[--t2], e2.head[t2] = f2 <= n2 ? n2 - f2 : 0, --r2; )
              ;
            for (t2 = r2 = f2; n2 = e2.prev[--t2], e2.prev[t2] = f2 <= n2 ? n2 - f2 : 0, --r2; )
              ;
            i2 += f2;
          }
          if (e2.strm.avail_in === 0)
            break;
          if (a2 = e2.strm, o2 = e2.window, h2 = e2.strstart + e2.lookahead, u2 = i2, l2 = void 0, l2 = a2.avail_in, u2 < l2 && (l2 = u2), r2 = l2 === 0 ? 0 : (a2.avail_in -= l2, c.arraySet(o2, a2.input, a2.next_in, l2, h2), a2.state.wrap === 1 ? a2.adler = d(a2.adler, o2, l2, h2) : a2.state.wrap === 2 && (a2.adler = p(a2.adler, o2, l2, h2)), a2.next_in += l2, a2.total_in += l2, l2), e2.lookahead += r2, e2.lookahead + e2.insert >= x)
            for (s2 = e2.strstart - e2.insert, e2.ins_h = e2.window[s2], e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[s2 + 1]) & e2.hash_mask; e2.insert && (e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[s2 + x - 1]) & e2.hash_mask, e2.prev[s2 & e2.w_mask] = e2.head[e2.ins_h], e2.head[e2.ins_h] = s2, s2++, e2.insert--, !(e2.lookahead + e2.insert < x)); )
              ;
        } while (e2.lookahead < z && e2.strm.avail_in !== 0);
      }
      __name(j, "j");
      function Z(e2, t2) {
        for (var r2, n2; ; ) {
          if (e2.lookahead < z) {
            if (j(e2), e2.lookahead < z && t2 === l)
              return A;
            if (e2.lookahead === 0)
              break;
          }
          if (r2 = 0, e2.lookahead >= x && (e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[e2.strstart + x - 1]) & e2.hash_mask, r2 = e2.prev[e2.strstart & e2.w_mask] = e2.head[e2.ins_h], e2.head[e2.ins_h] = e2.strstart), r2 !== 0 && e2.strstart - r2 <= e2.w_size - z && (e2.match_length = L(e2, r2)), e2.match_length >= x)
            if (n2 = u._tr_tally(e2, e2.strstart - e2.match_start, e2.match_length - x), e2.lookahead -= e2.match_length, e2.match_length <= e2.max_lazy_match && e2.lookahead >= x) {
              for (e2.match_length--; e2.strstart++, e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[e2.strstart + x - 1]) & e2.hash_mask, r2 = e2.prev[e2.strstart & e2.w_mask] = e2.head[e2.ins_h], e2.head[e2.ins_h] = e2.strstart, --e2.match_length != 0; )
                ;
              e2.strstart++;
            } else
              e2.strstart += e2.match_length, e2.match_length = 0, e2.ins_h = e2.window[e2.strstart], e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[e2.strstart + 1]) & e2.hash_mask;
          else
            n2 = u._tr_tally(e2, 0, e2.window[e2.strstart]), e2.lookahead--, e2.strstart++;
          if (n2 && (N(e2, !1), e2.strm.avail_out === 0))
            return A;
        }
        return e2.insert = e2.strstart < x - 1 ? e2.strstart : x - 1, t2 === f ? (N(e2, !0), e2.strm.avail_out === 0 ? O : B) : e2.last_lit && (N(e2, !1), e2.strm.avail_out === 0) ? A : I;
      }
      __name(Z, "Z");
      function W(e2, t2) {
        for (var r2, n2, i2; ; ) {
          if (e2.lookahead < z) {
            if (j(e2), e2.lookahead < z && t2 === l)
              return A;
            if (e2.lookahead === 0)
              break;
          }
          if (r2 = 0, e2.lookahead >= x && (e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[e2.strstart + x - 1]) & e2.hash_mask, r2 = e2.prev[e2.strstart & e2.w_mask] = e2.head[e2.ins_h], e2.head[e2.ins_h] = e2.strstart), e2.prev_length = e2.match_length, e2.prev_match = e2.match_start, e2.match_length = x - 1, r2 !== 0 && e2.prev_length < e2.max_lazy_match && e2.strstart - r2 <= e2.w_size - z && (e2.match_length = L(e2, r2), e2.match_length <= 5 && (e2.strategy === 1 || e2.match_length === x && 4096 < e2.strstart - e2.match_start) && (e2.match_length = x - 1)), e2.prev_length >= x && e2.match_length <= e2.prev_length) {
            for (i2 = e2.strstart + e2.lookahead - x, n2 = u._tr_tally(e2, e2.strstart - 1 - e2.prev_match, e2.prev_length - x), e2.lookahead -= e2.prev_length - 1, e2.prev_length -= 2; ++e2.strstart <= i2 && (e2.ins_h = (e2.ins_h << e2.hash_shift ^ e2.window[e2.strstart + x - 1]) & e2.hash_mask, r2 = e2.prev[e2.strstart & e2.w_mask] = e2.head[e2.ins_h], e2.head[e2.ins_h] = e2.strstart), --e2.prev_length != 0; )
              ;
            if (e2.match_available = 0, e2.match_length = x - 1, e2.strstart++, n2 && (N(e2, !1), e2.strm.avail_out === 0))
              return A;
          } else if (e2.match_available) {
            if ((n2 = u._tr_tally(e2, 0, e2.window[e2.strstart - 1])) && N(e2, !1), e2.strstart++, e2.lookahead--, e2.strm.avail_out === 0)
              return A;
          } else
            e2.match_available = 1, e2.strstart++, e2.lookahead--;
        }
        return e2.match_available && (n2 = u._tr_tally(e2, 0, e2.window[e2.strstart - 1]), e2.match_available = 0), e2.insert = e2.strstart < x - 1 ? e2.strstart : x - 1, t2 === f ? (N(e2, !0), e2.strm.avail_out === 0 ? O : B) : e2.last_lit && (N(e2, !1), e2.strm.avail_out === 0) ? A : I;
      }
      __name(W, "W");
      function M(e2, t2, r2, n2, i2) {
        this.good_length = e2, this.max_lazy = t2, this.nice_length = r2, this.max_chain = n2, this.func = i2;
      }
      __name(M, "M");
      function H() {
        this.strm = null, this.status = 0, this.pending_buf = null, this.pending_buf_size = 0, this.pending_out = 0, this.pending = 0, this.wrap = 0, this.gzhead = null, this.gzindex = 0, this.method = v, this.last_flush = -1, this.w_size = 0, this.w_bits = 0, this.w_mask = 0, this.window = null, this.window_size = 0, this.prev = null, this.head = null, this.ins_h = 0, this.hash_size = 0, this.hash_bits = 0, this.hash_mask = 0, this.hash_shift = 0, this.block_start = 0, this.match_length = 0, this.prev_match = 0, this.match_available = 0, this.strstart = 0, this.match_start = 0, this.lookahead = 0, this.prev_length = 0, this.max_chain_length = 0, this.max_lazy_match = 0, this.level = 0, this.strategy = 0, this.good_match = 0, this.nice_match = 0, this.dyn_ltree = new c.Buf16(2 * w), this.dyn_dtree = new c.Buf16(2 * (2 * a + 1)), this.bl_tree = new c.Buf16(2 * (2 * o + 1)), D(this.dyn_ltree), D(this.dyn_dtree), D(this.bl_tree), this.l_desc = null, this.d_desc = null, this.bl_desc = null, this.bl_count = new c.Buf16(k + 1), this.heap = new c.Buf16(2 * s + 1), D(this.heap), this.heap_len = 0, this.heap_max = 0, this.depth = new c.Buf16(2 * s + 1), D(this.depth), this.l_buf = 0, this.lit_bufsize = 0, this.last_lit = 0, this.d_buf = 0, this.opt_len = 0, this.static_len = 0, this.matches = 0, this.insert = 0, this.bi_buf = 0, this.bi_valid = 0;
      }
      __name(H, "H");
      function G(e2) {
        var t2;
        return e2 && e2.state ? (e2.total_in = e2.total_out = 0, e2.data_type = i, (t2 = e2.state).pending = 0, t2.pending_out = 0, t2.wrap < 0 && (t2.wrap = -t2.wrap), t2.status = t2.wrap ? C : E, e2.adler = t2.wrap === 2 ? 0 : 1, t2.last_flush = l, u._tr_init(t2), m) : R(e2, _);
      }
      __name(G, "G");
      function K(e2) {
        var t2 = G(e2);
        return t2 === m && function(e3) {
          e3.window_size = 2 * e3.w_size, D(e3.head), e3.max_lazy_match = h[e3.level].max_lazy, e3.good_match = h[e3.level].good_length, e3.nice_match = h[e3.level].nice_length, e3.max_chain_length = h[e3.level].max_chain, e3.strstart = 0, e3.block_start = 0, e3.lookahead = 0, e3.insert = 0, e3.match_length = e3.prev_length = x - 1, e3.match_available = 0, e3.ins_h = 0;
        }(e2.state), t2;
      }
      __name(K, "K");
      function Y(e2, t2, r2, n2, i2, s2) {
        if (!e2)
          return _;
        var a2 = 1;
        if (t2 === g && (t2 = 6), n2 < 0 ? (a2 = 0, n2 = -n2) : 15 < n2 && (a2 = 2, n2 -= 16), i2 < 1 || y < i2 || r2 !== v || n2 < 8 || 15 < n2 || t2 < 0 || 9 < t2 || s2 < 0 || b < s2)
          return R(e2, _);
        n2 === 8 && (n2 = 9);
        var o2 = new H();
        return (e2.state = o2).strm = e2, o2.wrap = a2, o2.gzhead = null, o2.w_bits = n2, o2.w_size = 1 << o2.w_bits, o2.w_mask = o2.w_size - 1, o2.hash_bits = i2 + 7, o2.hash_size = 1 << o2.hash_bits, o2.hash_mask = o2.hash_size - 1, o2.hash_shift = ~~((o2.hash_bits + x - 1) / x), o2.window = new c.Buf8(2 * o2.w_size), o2.head = new c.Buf16(o2.hash_size), o2.prev = new c.Buf16(o2.w_size), o2.lit_bufsize = 1 << i2 + 6, o2.pending_buf_size = 4 * o2.lit_bufsize, o2.pending_buf = new c.Buf8(o2.pending_buf_size), o2.d_buf = 1 * o2.lit_bufsize, o2.l_buf = 3 * o2.lit_bufsize, o2.level = t2, o2.strategy = s2, o2.method = r2, K(e2);
      }
      __name(Y, "Y"), h = [new M(0, 0, 0, 0, function(e2, t2) {
        var r2 = 65535;
        for (r2 > e2.pending_buf_size - 5 && (r2 = e2.pending_buf_size - 5); ; ) {
          if (e2.lookahead <= 1) {
            if (j(e2), e2.lookahead === 0 && t2 === l)
              return A;
            if (e2.lookahead === 0)
              break;
          }
          e2.strstart += e2.lookahead, e2.lookahead = 0;
          var n2 = e2.block_start + r2;
          if ((e2.strstart === 0 || e2.strstart >= n2) && (e2.lookahead = e2.strstart - n2, e2.strstart = n2, N(e2, !1), e2.strm.avail_out === 0) || e2.strstart - e2.block_start >= e2.w_size - z && (N(e2, !1), e2.strm.avail_out === 0))
            return A;
        }
        return e2.insert = 0, t2 === f ? (N(e2, !0), e2.strm.avail_out === 0 ? O : B) : (e2.strstart > e2.block_start && (N(e2, !1), e2.strm.avail_out), A);
      }), new M(4, 4, 8, 4, Z), new M(4, 5, 16, 8, Z), new M(4, 6, 32, 32, Z), new M(4, 4, 16, 16, W), new M(8, 16, 32, 32, W), new M(8, 16, 128, 128, W), new M(8, 32, 128, 256, W), new M(32, 128, 258, 1024, W), new M(32, 258, 258, 4096, W)], r.deflateInit = function(e2, t2) {
        return Y(e2, t2, v, 15, 8, 0);
      }, r.deflateInit2 = Y, r.deflateReset = K, r.deflateResetKeep = G, r.deflateSetHeader = function(e2, t2) {
        return e2 && e2.state ? e2.state.wrap !== 2 ? _ : (e2.state.gzhead = t2, m) : _;
      }, r.deflate = function(e2, t2) {
        var r2, n2, i2, s2;
        if (!e2 || !e2.state || 5 < t2 || t2 < 0)
          return e2 ? R(e2, _) : _;
        if (n2 = e2.state, !e2.output || !e2.input && e2.avail_in !== 0 || n2.status === 666 && t2 !== f)
          return R(e2, e2.avail_out === 0 ? -5 : _);
        if (n2.strm = e2, r2 = n2.last_flush, n2.last_flush = t2, n2.status === C)
          if (n2.wrap === 2)
            e2.adler = 0, U(n2, 31), U(n2, 139), U(n2, 8), n2.gzhead ? (U(n2, (n2.gzhead.text ? 1 : 0) + (n2.gzhead.hcrc ? 2 : 0) + (n2.gzhead.extra ? 4 : 0) + (n2.gzhead.name ? 8 : 0) + (n2.gzhead.comment ? 16 : 0)), U(n2, 255 & n2.gzhead.time), U(n2, n2.gzhead.time >> 8 & 255), U(n2, n2.gzhead.time >> 16 & 255), U(n2, n2.gzhead.time >> 24 & 255), U(n2, n2.level === 9 ? 2 : 2 <= n2.strategy || n2.level < 2 ? 4 : 0), U(n2, 255 & n2.gzhead.os), n2.gzhead.extra && n2.gzhead.extra.length && (U(n2, 255 & n2.gzhead.extra.length), U(n2, n2.gzhead.extra.length >> 8 & 255)), n2.gzhead.hcrc && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending, 0)), n2.gzindex = 0, n2.status = 69) : (U(n2, 0), U(n2, 0), U(n2, 0), U(n2, 0), U(n2, 0), U(n2, n2.level === 9 ? 2 : 2 <= n2.strategy || n2.level < 2 ? 4 : 0), U(n2, 3), n2.status = E);
          else {
            var a2 = v + (n2.w_bits - 8 << 4) << 8;
            a2 |= (2 <= n2.strategy || n2.level < 2 ? 0 : n2.level < 6 ? 1 : n2.level === 6 ? 2 : 3) << 6, n2.strstart !== 0 && (a2 |= 32), a2 += 31 - a2 % 31, n2.status = E, P(n2, a2), n2.strstart !== 0 && (P(n2, e2.adler >>> 16), P(n2, 65535 & e2.adler)), e2.adler = 1;
          }
        if (n2.status === 69)
          if (n2.gzhead.extra) {
            for (i2 = n2.pending; n2.gzindex < (65535 & n2.gzhead.extra.length) && (n2.pending !== n2.pending_buf_size || (n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), F(e2), i2 = n2.pending, n2.pending !== n2.pending_buf_size)); )
              U(n2, 255 & n2.gzhead.extra[n2.gzindex]), n2.gzindex++;
            n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), n2.gzindex === n2.gzhead.extra.length && (n2.gzindex = 0, n2.status = 73);
          } else
            n2.status = 73;
        if (n2.status === 73)
          if (n2.gzhead.name) {
            i2 = n2.pending;
            do {
              if (n2.pending === n2.pending_buf_size && (n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), F(e2), i2 = n2.pending, n2.pending === n2.pending_buf_size)) {
                s2 = 1;
                break;
              }
              s2 = n2.gzindex < n2.gzhead.name.length ? 255 & n2.gzhead.name.charCodeAt(n2.gzindex++) : 0, U(n2, s2);
            } while (s2 !== 0);
            n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), s2 === 0 && (n2.gzindex = 0, n2.status = 91);
          } else
            n2.status = 91;
        if (n2.status === 91)
          if (n2.gzhead.comment) {
            i2 = n2.pending;
            do {
              if (n2.pending === n2.pending_buf_size && (n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), F(e2), i2 = n2.pending, n2.pending === n2.pending_buf_size)) {
                s2 = 1;
                break;
              }
              s2 = n2.gzindex < n2.gzhead.comment.length ? 255 & n2.gzhead.comment.charCodeAt(n2.gzindex++) : 0, U(n2, s2);
            } while (s2 !== 0);
            n2.gzhead.hcrc && n2.pending > i2 && (e2.adler = p(e2.adler, n2.pending_buf, n2.pending - i2, i2)), s2 === 0 && (n2.status = 103);
          } else
            n2.status = 103;
        if (n2.status === 103 && (n2.gzhead.hcrc ? (n2.pending + 2 > n2.pending_buf_size && F(e2), n2.pending + 2 <= n2.pending_buf_size && (U(n2, 255 & e2.adler), U(n2, e2.adler >> 8 & 255), e2.adler = 0, n2.status = E)) : n2.status = E), n2.pending !== 0) {
          if (F(e2), e2.avail_out === 0)
            return n2.last_flush = -1, m;
        } else if (e2.avail_in === 0 && T(t2) <= T(r2) && t2 !== f)
          return R(e2, -5);
        if (n2.status === 666 && e2.avail_in !== 0)
          return R(e2, -5);
        if (e2.avail_in !== 0 || n2.lookahead !== 0 || t2 !== l && n2.status !== 666) {
          var o2 = n2.strategy === 2 ? function(e3, t3) {
            for (var r3; ; ) {
              if (e3.lookahead === 0 && (j(e3), e3.lookahead === 0)) {
                if (t3 === l)
                  return A;
                break;
              }
              if (e3.match_length = 0, r3 = u._tr_tally(e3, 0, e3.window[e3.strstart]), e3.lookahead--, e3.strstart++, r3 && (N(e3, !1), e3.strm.avail_out === 0))
                return A;
            }
            return e3.insert = 0, t3 === f ? (N(e3, !0), e3.strm.avail_out === 0 ? O : B) : e3.last_lit && (N(e3, !1), e3.strm.avail_out === 0) ? A : I;
          }(n2, t2) : n2.strategy === 3 ? function(e3, t3) {
            for (var r3, n3, i3, s3, a3 = e3.window; ; ) {
              if (e3.lookahead <= S) {
                if (j(e3), e3.lookahead <= S && t3 === l)
                  return A;
                if (e3.lookahead === 0)
                  break;
              }
              if (e3.match_length = 0, e3.lookahead >= x && 0 < e3.strstart && (n3 = a3[i3 = e3.strstart - 1]) === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3]) {
                s3 = e3.strstart + S;
                do
                  ;
                while (n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && n3 === a3[++i3] && i3 < s3);
                e3.match_length = S - (s3 - i3), e3.match_length > e3.lookahead && (e3.match_length = e3.lookahead);
              }
              if (e3.match_length >= x ? (r3 = u._tr_tally(e3, 1, e3.match_length - x), e3.lookahead -= e3.match_length, e3.strstart += e3.match_length, e3.match_length = 0) : (r3 = u._tr_tally(e3, 0, e3.window[e3.strstart]), e3.lookahead--, e3.strstart++), r3 && (N(e3, !1), e3.strm.avail_out === 0))
                return A;
            }
            return e3.insert = 0, t3 === f ? (N(e3, !0), e3.strm.avail_out === 0 ? O : B) : e3.last_lit && (N(e3, !1), e3.strm.avail_out === 0) ? A : I;
          }(n2, t2) : h[n2.level].func(n2, t2);
          if (o2 !== O && o2 !== B || (n2.status = 666), o2 === A || o2 === O)
            return e2.avail_out === 0 && (n2.last_flush = -1), m;
          if (o2 === I && (t2 === 1 ? u._tr_align(n2) : t2 !== 5 && (u._tr_stored_block(n2, 0, 0, !1), t2 === 3 && (D(n2.head), n2.lookahead === 0 && (n2.strstart = 0, n2.block_start = 0, n2.insert = 0))), F(e2), e2.avail_out === 0))
            return n2.last_flush = -1, m;
        }
        return t2 !== f ? m : n2.wrap <= 0 ? 1 : (n2.wrap === 2 ? (U(n2, 255 & e2.adler), U(n2, e2.adler >> 8 & 255), U(n2, e2.adler >> 16 & 255), U(n2, e2.adler >> 24 & 255), U(n2, 255 & e2.total_in), U(n2, e2.total_in >> 8 & 255), U(n2, e2.total_in >> 16 & 255), U(n2, e2.total_in >> 24 & 255)) : (P(n2, e2.adler >>> 16), P(n2, 65535 & e2.adler)), F(e2), 0 < n2.wrap && (n2.wrap = -n2.wrap), n2.pending !== 0 ? m : 1);
      }, r.deflateEnd = function(e2) {
        var t2;
        return e2 && e2.state ? (t2 = e2.state.status) !== C && t2 !== 69 && t2 !== 73 && t2 !== 91 && t2 !== 103 && t2 !== E && t2 !== 666 ? R(e2, _) : (e2.state = null, t2 === E ? R(e2, -3) : m) : _;
      }, r.deflateSetDictionary = function(e2, t2) {
        var r2, n2, i2, s2, a2, o2, h2, u2, l2 = t2.length;
        if (!e2 || !e2.state || (s2 = (r2 = e2.state).wrap) === 2 || s2 === 1 && r2.status !== C || r2.lookahead)
          return _;
        for (s2 === 1 && (e2.adler = d(e2.adler, t2, l2, 0)), r2.wrap = 0, l2 >= r2.w_size && (s2 === 0 && (D(r2.head), r2.strstart = 0, r2.block_start = 0, r2.insert = 0), u2 = new c.Buf8(r2.w_size), c.arraySet(u2, t2, l2 - r2.w_size, r2.w_size, 0), t2 = u2, l2 = r2.w_size), a2 = e2.avail_in, o2 = e2.next_in, h2 = e2.input, e2.avail_in = l2, e2.next_in = 0, e2.input = t2, j(r2); r2.lookahead >= x; ) {
          for (n2 = r2.strstart, i2 = r2.lookahead - (x - 1); r2.ins_h = (r2.ins_h << r2.hash_shift ^ r2.window[n2 + x - 1]) & r2.hash_mask, r2.prev[n2 & r2.w_mask] = r2.head[r2.ins_h], r2.head[r2.ins_h] = n2, n2++, --i2; )
            ;
          r2.strstart = n2, r2.lookahead = x - 1, j(r2);
        }
        return r2.strstart += r2.lookahead, r2.block_start = r2.strstart, r2.insert = r2.lookahead, r2.lookahead = 0, r2.match_length = r2.prev_length = x - 1, r2.match_available = 0, e2.next_in = o2, e2.input = h2, e2.avail_in = a2, r2.wrap = s2, m;
      }, r.deflateInfo = "pako deflate (from Nodeca project)";
    }, { "../utils/common": 41, "./adler32": 43, "./crc32": 45, "./messages": 51, "./trees": 52 }], 47: [function(e, t, r) {
      t.exports = function() {
        this.text = 0, this.time = 0, this.xflags = 0, this.os = 0, this.extra = null, this.extra_len = 0, this.name = "", this.comment = "", this.hcrc = 0, this.done = !1;
      };
    }, {}], 48: [function(e, t, r) {
      t.exports = function(e2, t2) {
        var r2, n, i, s, a, o, h, u, l, f, c, d, p, m, _, g, b, v, y, w, k, x, S, z, C;
        r2 = e2.state, n = e2.next_in, z = e2.input, i = n + (e2.avail_in - 5), s = e2.next_out, C = e2.output, a = s - (t2 - e2.avail_out), o = s + (e2.avail_out - 257), h = r2.dmax, u = r2.wsize, l = r2.whave, f = r2.wnext, c = r2.window, d = r2.hold, p = r2.bits, m = r2.lencode, _ = r2.distcode, g = (1 << r2.lenbits) - 1, b = (1 << r2.distbits) - 1;
        e:
          do {
            p < 15 && (d += z[n++] << p, p += 8, d += z[n++] << p, p += 8), v = m[d & g];
            t:
              for (; ; ) {
                if (d >>>= y = v >>> 24, p -= y, (y = v >>> 16 & 255) === 0)
                  C[s++] = 65535 & v;
                else {
                  if (!(16 & y)) {
                    if (!(64 & y)) {
                      v = m[(65535 & v) + (d & (1 << y) - 1)];
                      continue t;
                    }
                    if (32 & y) {
                      r2.mode = 12;
                      break e;
                    }
                    e2.msg = "invalid literal/length code", r2.mode = 30;
                    break e;
                  }
                  w = 65535 & v, (y &= 15) && (p < y && (d += z[n++] << p, p += 8), w += d & (1 << y) - 1, d >>>= y, p -= y), p < 15 && (d += z[n++] << p, p += 8, d += z[n++] << p, p += 8), v = _[d & b];
                  r:
                    for (; ; ) {
                      if (d >>>= y = v >>> 24, p -= y, !(16 & (y = v >>> 16 & 255))) {
                        if (!(64 & y)) {
                          v = _[(65535 & v) + (d & (1 << y) - 1)];
                          continue r;
                        }
                        e2.msg = "invalid distance code", r2.mode = 30;
                        break e;
                      }
                      if (k = 65535 & v, p < (y &= 15) && (d += z[n++] << p, (p += 8) < y && (d += z[n++] << p, p += 8)), h < (k += d & (1 << y) - 1)) {
                        e2.msg = "invalid distance too far back", r2.mode = 30;
                        break e;
                      }
                      if (d >>>= y, p -= y, (y = s - a) < k) {
                        if (l < (y = k - y) && r2.sane) {
                          e2.msg = "invalid distance too far back", r2.mode = 30;
                          break e;
                        }
                        if (S = c, (x = 0) === f) {
                          if (x += u - y, y < w) {
                            for (w -= y; C[s++] = c[x++], --y; )
                              ;
                            x = s - k, S = C;
                          }
                        } else if (f < y) {
                          if (x += u + f - y, (y -= f) < w) {
                            for (w -= y; C[s++] = c[x++], --y; )
                              ;
                            if (x = 0, f < w) {
                              for (w -= y = f; C[s++] = c[x++], --y; )
                                ;
                              x = s - k, S = C;
                            }
                          }
                        } else if (x += f - y, y < w) {
                          for (w -= y; C[s++] = c[x++], --y; )
                            ;
                          x = s - k, S = C;
                        }
                        for (; 2 < w; )
                          C[s++] = S[x++], C[s++] = S[x++], C[s++] = S[x++], w -= 3;
                        w && (C[s++] = S[x++], 1 < w && (C[s++] = S[x++]));
                      } else {
                        for (x = s - k; C[s++] = C[x++], C[s++] = C[x++], C[s++] = C[x++], 2 < (w -= 3); )
                          ;
                        w && (C[s++] = C[x++], 1 < w && (C[s++] = C[x++]));
                      }
                      break;
                    }
                }
                break;
              }
          } while (n < i && s < o);
        n -= w = p >> 3, d &= (1 << (p -= w << 3)) - 1, e2.next_in = n, e2.next_out = s, e2.avail_in = n < i ? i - n + 5 : 5 - (n - i), e2.avail_out = s < o ? o - s + 257 : 257 - (s - o), r2.hold = d, r2.bits = p;
      };
    }, {}], 49: [function(e, t, r) {
      var I = e("../utils/common"), O = e("./adler32"), B = e("./crc32"), R = e("./inffast"), T = e("./inftrees"), D = 1, F = 2, N = 0, U = -2, P = 1, n = 852, i = 592;
      function L(e2) {
        return (e2 >>> 24 & 255) + (e2 >>> 8 & 65280) + ((65280 & e2) << 8) + ((255 & e2) << 24);
      }
      __name(L, "L");
      function s() {
        this.mode = 0, this.last = !1, this.wrap = 0, this.havedict = !1, this.flags = 0, this.dmax = 0, this.check = 0, this.total = 0, this.head = null, this.wbits = 0, this.wsize = 0, this.whave = 0, this.wnext = 0, this.window = null, this.hold = 0, this.bits = 0, this.length = 0, this.offset = 0, this.extra = 0, this.lencode = null, this.distcode = null, this.lenbits = 0, this.distbits = 0, this.ncode = 0, this.nlen = 0, this.ndist = 0, this.have = 0, this.next = null, this.lens = new I.Buf16(320), this.work = new I.Buf16(288), this.lendyn = null, this.distdyn = null, this.sane = 0, this.back = 0, this.was = 0;
      }
      __name(s, "s");
      function a(e2) {
        var t2;
        return e2 && e2.state ? (t2 = e2.state, e2.total_in = e2.total_out = t2.total = 0, e2.msg = "", t2.wrap && (e2.adler = 1 & t2.wrap), t2.mode = P, t2.last = 0, t2.havedict = 0, t2.dmax = 32768, t2.head = null, t2.hold = 0, t2.bits = 0, t2.lencode = t2.lendyn = new I.Buf32(n), t2.distcode = t2.distdyn = new I.Buf32(i), t2.sane = 1, t2.back = -1, N) : U;
      }
      __name(a, "a");
      function o(e2) {
        var t2;
        return e2 && e2.state ? ((t2 = e2.state).wsize = 0, t2.whave = 0, t2.wnext = 0, a(e2)) : U;
      }
      __name(o, "o");
      function h(e2, t2) {
        var r2, n2;
        return e2 && e2.state ? (n2 = e2.state, t2 < 0 ? (r2 = 0, t2 = -t2) : (r2 = 1 + (t2 >> 4), t2 < 48 && (t2 &= 15)), t2 && (t2 < 8 || 15 < t2) ? U : (n2.window !== null && n2.wbits !== t2 && (n2.window = null), n2.wrap = r2, n2.wbits = t2, o(e2))) : U;
      }
      __name(h, "h");
      function u(e2, t2) {
        var r2, n2;
        return e2 ? (n2 = new s(), (e2.state = n2).window = null, (r2 = h(e2, t2)) !== N && (e2.state = null), r2) : U;
      }
      __name(u, "u");
      var l, f, c = !0;
      function j(e2) {
        if (c) {
          var t2;
          for (l = new I.Buf32(512), f = new I.Buf32(32), t2 = 0; t2 < 144; )
            e2.lens[t2++] = 8;
          for (; t2 < 256; )
            e2.lens[t2++] = 9;
          for (; t2 < 280; )
            e2.lens[t2++] = 7;
          for (; t2 < 288; )
            e2.lens[t2++] = 8;
          for (T(D, e2.lens, 0, 288, l, 0, e2.work, { bits: 9 }), t2 = 0; t2 < 32; )
            e2.lens[t2++] = 5;
          T(F, e2.lens, 0, 32, f, 0, e2.work, { bits: 5 }), c = !1;
        }
        e2.lencode = l, e2.lenbits = 9, e2.distcode = f, e2.distbits = 5;
      }
      __name(j, "j");
      function Z(e2, t2, r2, n2) {
        var i2, s2 = e2.state;
        return s2.window === null && (s2.wsize = 1 << s2.wbits, s2.wnext = 0, s2.whave = 0, s2.window = new I.Buf8(s2.wsize)), n2 >= s2.wsize ? (I.arraySet(s2.window, t2, r2 - s2.wsize, s2.wsize, 0), s2.wnext = 0, s2.whave = s2.wsize) : (n2 < (i2 = s2.wsize - s2.wnext) && (i2 = n2), I.arraySet(s2.window, t2, r2 - n2, i2, s2.wnext), (n2 -= i2) ? (I.arraySet(s2.window, t2, r2 - n2, n2, 0), s2.wnext = n2, s2.whave = s2.wsize) : (s2.wnext += i2, s2.wnext === s2.wsize && (s2.wnext = 0), s2.whave < s2.wsize && (s2.whave += i2))), 0;
      }
      __name(Z, "Z"), r.inflateReset = o, r.inflateReset2 = h, r.inflateResetKeep = a, r.inflateInit = function(e2) {
        return u(e2, 15);
      }, r.inflateInit2 = u, r.inflate = function(e2, t2) {
        var r2, n2, i2, s2, a2, o2, h2, u2, l2, f2, c2, d, p, m, _, g, b, v, y, w, k, x, S, z, C = 0, E = new I.Buf8(4), A = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
        if (!e2 || !e2.state || !e2.output || !e2.input && e2.avail_in !== 0)
          return U;
        (r2 = e2.state).mode === 12 && (r2.mode = 13), a2 = e2.next_out, i2 = e2.output, h2 = e2.avail_out, s2 = e2.next_in, n2 = e2.input, o2 = e2.avail_in, u2 = r2.hold, l2 = r2.bits, f2 = o2, c2 = h2, x = N;
        e:
          for (; ; )
            switch (r2.mode) {
              case P:
                if (r2.wrap === 0) {
                  r2.mode = 13;
                  break;
                }
                for (; l2 < 16; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if (2 & r2.wrap && u2 === 35615) {
                  E[r2.check = 0] = 255 & u2, E[1] = u2 >>> 8 & 255, r2.check = B(r2.check, E, 2, 0), l2 = u2 = 0, r2.mode = 2;
                  break;
                }
                if (r2.flags = 0, r2.head && (r2.head.done = !1), !(1 & r2.wrap) || (((255 & u2) << 8) + (u2 >> 8)) % 31) {
                  e2.msg = "incorrect header check", r2.mode = 30;
                  break;
                }
                if ((15 & u2) != 8) {
                  e2.msg = "unknown compression method", r2.mode = 30;
                  break;
                }
                if (l2 -= 4, k = 8 + (15 & (u2 >>>= 4)), r2.wbits === 0)
                  r2.wbits = k;
                else if (k > r2.wbits) {
                  e2.msg = "invalid window size", r2.mode = 30;
                  break;
                }
                r2.dmax = 1 << k, e2.adler = r2.check = 1, r2.mode = 512 & u2 ? 10 : 12, l2 = u2 = 0;
                break;
              case 2:
                for (; l2 < 16; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if (r2.flags = u2, (255 & r2.flags) != 8) {
                  e2.msg = "unknown compression method", r2.mode = 30;
                  break;
                }
                if (57344 & r2.flags) {
                  e2.msg = "unknown header flags set", r2.mode = 30;
                  break;
                }
                r2.head && (r2.head.text = u2 >> 8 & 1), 512 & r2.flags && (E[0] = 255 & u2, E[1] = u2 >>> 8 & 255, r2.check = B(r2.check, E, 2, 0)), l2 = u2 = 0, r2.mode = 3;
              case 3:
                for (; l2 < 32; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                r2.head && (r2.head.time = u2), 512 & r2.flags && (E[0] = 255 & u2, E[1] = u2 >>> 8 & 255, E[2] = u2 >>> 16 & 255, E[3] = u2 >>> 24 & 255, r2.check = B(r2.check, E, 4, 0)), l2 = u2 = 0, r2.mode = 4;
              case 4:
                for (; l2 < 16; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                r2.head && (r2.head.xflags = 255 & u2, r2.head.os = u2 >> 8), 512 & r2.flags && (E[0] = 255 & u2, E[1] = u2 >>> 8 & 255, r2.check = B(r2.check, E, 2, 0)), l2 = u2 = 0, r2.mode = 5;
              case 5:
                if (1024 & r2.flags) {
                  for (; l2 < 16; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  r2.length = u2, r2.head && (r2.head.extra_len = u2), 512 & r2.flags && (E[0] = 255 & u2, E[1] = u2 >>> 8 & 255, r2.check = B(r2.check, E, 2, 0)), l2 = u2 = 0;
                } else
                  r2.head && (r2.head.extra = null);
                r2.mode = 6;
              case 6:
                if (1024 & r2.flags && (o2 < (d = r2.length) && (d = o2), d && (r2.head && (k = r2.head.extra_len - r2.length, r2.head.extra || (r2.head.extra = new Array(r2.head.extra_len)), I.arraySet(r2.head.extra, n2, s2, d, k)), 512 & r2.flags && (r2.check = B(r2.check, n2, d, s2)), o2 -= d, s2 += d, r2.length -= d), r2.length))
                  break e;
                r2.length = 0, r2.mode = 7;
              case 7:
                if (2048 & r2.flags) {
                  if (o2 === 0)
                    break e;
                  for (d = 0; k = n2[s2 + d++], r2.head && k && r2.length < 65536 && (r2.head.name += String.fromCharCode(k)), k && d < o2; )
                    ;
                  if (512 & r2.flags && (r2.check = B(r2.check, n2, d, s2)), o2 -= d, s2 += d, k)
                    break e;
                } else
                  r2.head && (r2.head.name = null);
                r2.length = 0, r2.mode = 8;
              case 8:
                if (4096 & r2.flags) {
                  if (o2 === 0)
                    break e;
                  for (d = 0; k = n2[s2 + d++], r2.head && k && r2.length < 65536 && (r2.head.comment += String.fromCharCode(k)), k && d < o2; )
                    ;
                  if (512 & r2.flags && (r2.check = B(r2.check, n2, d, s2)), o2 -= d, s2 += d, k)
                    break e;
                } else
                  r2.head && (r2.head.comment = null);
                r2.mode = 9;
              case 9:
                if (512 & r2.flags) {
                  for (; l2 < 16; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  if (u2 !== (65535 & r2.check)) {
                    e2.msg = "header crc mismatch", r2.mode = 30;
                    break;
                  }
                  l2 = u2 = 0;
                }
                r2.head && (r2.head.hcrc = r2.flags >> 9 & 1, r2.head.done = !0), e2.adler = r2.check = 0, r2.mode = 12;
                break;
              case 10:
                for (; l2 < 32; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                e2.adler = r2.check = L(u2), l2 = u2 = 0, r2.mode = 11;
              case 11:
                if (r2.havedict === 0)
                  return e2.next_out = a2, e2.avail_out = h2, e2.next_in = s2, e2.avail_in = o2, r2.hold = u2, r2.bits = l2, 2;
                e2.adler = r2.check = 1, r2.mode = 12;
              case 12:
                if (t2 === 5 || t2 === 6)
                  break e;
              case 13:
                if (r2.last) {
                  u2 >>>= 7 & l2, l2 -= 7 & l2, r2.mode = 27;
                  break;
                }
                for (; l2 < 3; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                switch (r2.last = 1 & u2, l2 -= 1, 3 & (u2 >>>= 1)) {
                  case 0:
                    r2.mode = 14;
                    break;
                  case 1:
                    if (j(r2), r2.mode = 20, t2 !== 6)
                      break;
                    u2 >>>= 2, l2 -= 2;
                    break e;
                  case 2:
                    r2.mode = 17;
                    break;
                  case 3:
                    e2.msg = "invalid block type", r2.mode = 30;
                }
                u2 >>>= 2, l2 -= 2;
                break;
              case 14:
                for (u2 >>>= 7 & l2, l2 -= 7 & l2; l2 < 32; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if ((65535 & u2) != (u2 >>> 16 ^ 65535)) {
                  e2.msg = "invalid stored block lengths", r2.mode = 30;
                  break;
                }
                if (r2.length = 65535 & u2, l2 = u2 = 0, r2.mode = 15, t2 === 6)
                  break e;
              case 15:
                r2.mode = 16;
              case 16:
                if (d = r2.length) {
                  if (o2 < d && (d = o2), h2 < d && (d = h2), d === 0)
                    break e;
                  I.arraySet(i2, n2, s2, d, a2), o2 -= d, s2 += d, h2 -= d, a2 += d, r2.length -= d;
                  break;
                }
                r2.mode = 12;
                break;
              case 17:
                for (; l2 < 14; ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if (r2.nlen = 257 + (31 & u2), u2 >>>= 5, l2 -= 5, r2.ndist = 1 + (31 & u2), u2 >>>= 5, l2 -= 5, r2.ncode = 4 + (15 & u2), u2 >>>= 4, l2 -= 4, 286 < r2.nlen || 30 < r2.ndist) {
                  e2.msg = "too many length or distance symbols", r2.mode = 30;
                  break;
                }
                r2.have = 0, r2.mode = 18;
              case 18:
                for (; r2.have < r2.ncode; ) {
                  for (; l2 < 3; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  r2.lens[A[r2.have++]] = 7 & u2, u2 >>>= 3, l2 -= 3;
                }
                for (; r2.have < 19; )
                  r2.lens[A[r2.have++]] = 0;
                if (r2.lencode = r2.lendyn, r2.lenbits = 7, S = { bits: r2.lenbits }, x = T(0, r2.lens, 0, 19, r2.lencode, 0, r2.work, S), r2.lenbits = S.bits, x) {
                  e2.msg = "invalid code lengths set", r2.mode = 30;
                  break;
                }
                r2.have = 0, r2.mode = 19;
              case 19:
                for (; r2.have < r2.nlen + r2.ndist; ) {
                  for (; g = (C = r2.lencode[u2 & (1 << r2.lenbits) - 1]) >>> 16 & 255, b = 65535 & C, !((_ = C >>> 24) <= l2); ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  if (b < 16)
                    u2 >>>= _, l2 -= _, r2.lens[r2.have++] = b;
                  else {
                    if (b === 16) {
                      for (z = _ + 2; l2 < z; ) {
                        if (o2 === 0)
                          break e;
                        o2--, u2 += n2[s2++] << l2, l2 += 8;
                      }
                      if (u2 >>>= _, l2 -= _, r2.have === 0) {
                        e2.msg = "invalid bit length repeat", r2.mode = 30;
                        break;
                      }
                      k = r2.lens[r2.have - 1], d = 3 + (3 & u2), u2 >>>= 2, l2 -= 2;
                    } else if (b === 17) {
                      for (z = _ + 3; l2 < z; ) {
                        if (o2 === 0)
                          break e;
                        o2--, u2 += n2[s2++] << l2, l2 += 8;
                      }
                      l2 -= _, k = 0, d = 3 + (7 & (u2 >>>= _)), u2 >>>= 3, l2 -= 3;
                    } else {
                      for (z = _ + 7; l2 < z; ) {
                        if (o2 === 0)
                          break e;
                        o2--, u2 += n2[s2++] << l2, l2 += 8;
                      }
                      l2 -= _, k = 0, d = 11 + (127 & (u2 >>>= _)), u2 >>>= 7, l2 -= 7;
                    }
                    if (r2.have + d > r2.nlen + r2.ndist) {
                      e2.msg = "invalid bit length repeat", r2.mode = 30;
                      break;
                    }
                    for (; d--; )
                      r2.lens[r2.have++] = k;
                  }
                }
                if (r2.mode === 30)
                  break;
                if (r2.lens[256] === 0) {
                  e2.msg = "invalid code -- missing end-of-block", r2.mode = 30;
                  break;
                }
                if (r2.lenbits = 9, S = { bits: r2.lenbits }, x = T(D, r2.lens, 0, r2.nlen, r2.lencode, 0, r2.work, S), r2.lenbits = S.bits, x) {
                  e2.msg = "invalid literal/lengths set", r2.mode = 30;
                  break;
                }
                if (r2.distbits = 6, r2.distcode = r2.distdyn, S = { bits: r2.distbits }, x = T(F, r2.lens, r2.nlen, r2.ndist, r2.distcode, 0, r2.work, S), r2.distbits = S.bits, x) {
                  e2.msg = "invalid distances set", r2.mode = 30;
                  break;
                }
                if (r2.mode = 20, t2 === 6)
                  break e;
              case 20:
                r2.mode = 21;
              case 21:
                if (6 <= o2 && 258 <= h2) {
                  e2.next_out = a2, e2.avail_out = h2, e2.next_in = s2, e2.avail_in = o2, r2.hold = u2, r2.bits = l2, R(e2, c2), a2 = e2.next_out, i2 = e2.output, h2 = e2.avail_out, s2 = e2.next_in, n2 = e2.input, o2 = e2.avail_in, u2 = r2.hold, l2 = r2.bits, r2.mode === 12 && (r2.back = -1);
                  break;
                }
                for (r2.back = 0; g = (C = r2.lencode[u2 & (1 << r2.lenbits) - 1]) >>> 16 & 255, b = 65535 & C, !((_ = C >>> 24) <= l2); ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if (g && !(240 & g)) {
                  for (v = _, y = g, w = b; g = (C = r2.lencode[w + ((u2 & (1 << v + y) - 1) >> v)]) >>> 16 & 255, b = 65535 & C, !(v + (_ = C >>> 24) <= l2); ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  u2 >>>= v, l2 -= v, r2.back += v;
                }
                if (u2 >>>= _, l2 -= _, r2.back += _, r2.length = b, g === 0) {
                  r2.mode = 26;
                  break;
                }
                if (32 & g) {
                  r2.back = -1, r2.mode = 12;
                  break;
                }
                if (64 & g) {
                  e2.msg = "invalid literal/length code", r2.mode = 30;
                  break;
                }
                r2.extra = 15 & g, r2.mode = 22;
              case 22:
                if (r2.extra) {
                  for (z = r2.extra; l2 < z; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  r2.length += u2 & (1 << r2.extra) - 1, u2 >>>= r2.extra, l2 -= r2.extra, r2.back += r2.extra;
                }
                r2.was = r2.length, r2.mode = 23;
              case 23:
                for (; g = (C = r2.distcode[u2 & (1 << r2.distbits) - 1]) >>> 16 & 255, b = 65535 & C, !((_ = C >>> 24) <= l2); ) {
                  if (o2 === 0)
                    break e;
                  o2--, u2 += n2[s2++] << l2, l2 += 8;
                }
                if (!(240 & g)) {
                  for (v = _, y = g, w = b; g = (C = r2.distcode[w + ((u2 & (1 << v + y) - 1) >> v)]) >>> 16 & 255, b = 65535 & C, !(v + (_ = C >>> 24) <= l2); ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  u2 >>>= v, l2 -= v, r2.back += v;
                }
                if (u2 >>>= _, l2 -= _, r2.back += _, 64 & g) {
                  e2.msg = "invalid distance code", r2.mode = 30;
                  break;
                }
                r2.offset = b, r2.extra = 15 & g, r2.mode = 24;
              case 24:
                if (r2.extra) {
                  for (z = r2.extra; l2 < z; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  r2.offset += u2 & (1 << r2.extra) - 1, u2 >>>= r2.extra, l2 -= r2.extra, r2.back += r2.extra;
                }
                if (r2.offset > r2.dmax) {
                  e2.msg = "invalid distance too far back", r2.mode = 30;
                  break;
                }
                r2.mode = 25;
              case 25:
                if (h2 === 0)
                  break e;
                if (d = c2 - h2, r2.offset > d) {
                  if ((d = r2.offset - d) > r2.whave && r2.sane) {
                    e2.msg = "invalid distance too far back", r2.mode = 30;
                    break;
                  }
                  p = d > r2.wnext ? (d -= r2.wnext, r2.wsize - d) : r2.wnext - d, d > r2.length && (d = r2.length), m = r2.window;
                } else
                  m = i2, p = a2 - r2.offset, d = r2.length;
                for (h2 < d && (d = h2), h2 -= d, r2.length -= d; i2[a2++] = m[p++], --d; )
                  ;
                r2.length === 0 && (r2.mode = 21);
                break;
              case 26:
                if (h2 === 0)
                  break e;
                i2[a2++] = r2.length, h2--, r2.mode = 21;
                break;
              case 27:
                if (r2.wrap) {
                  for (; l2 < 32; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 |= n2[s2++] << l2, l2 += 8;
                  }
                  if (c2 -= h2, e2.total_out += c2, r2.total += c2, c2 && (e2.adler = r2.check = r2.flags ? B(r2.check, i2, c2, a2 - c2) : O(r2.check, i2, c2, a2 - c2)), c2 = h2, (r2.flags ? u2 : L(u2)) !== r2.check) {
                    e2.msg = "incorrect data check", r2.mode = 30;
                    break;
                  }
                  l2 = u2 = 0;
                }
                r2.mode = 28;
              case 28:
                if (r2.wrap && r2.flags) {
                  for (; l2 < 32; ) {
                    if (o2 === 0)
                      break e;
                    o2--, u2 += n2[s2++] << l2, l2 += 8;
                  }
                  if (u2 !== (4294967295 & r2.total)) {
                    e2.msg = "incorrect length check", r2.mode = 30;
                    break;
                  }
                  l2 = u2 = 0;
                }
                r2.mode = 29;
              case 29:
                x = 1;
                break e;
              case 30:
                x = -3;
                break e;
              case 31:
                return -4;
              case 32:
              default:
                return U;
            }
        return e2.next_out = a2, e2.avail_out = h2, e2.next_in = s2, e2.avail_in = o2, r2.hold = u2, r2.bits = l2, (r2.wsize || c2 !== e2.avail_out && r2.mode < 30 && (r2.mode < 27 || t2 !== 4)) && Z(e2, e2.output, e2.next_out, c2 - e2.avail_out) ? (r2.mode = 31, -4) : (f2 -= e2.avail_in, c2 -= e2.avail_out, e2.total_in += f2, e2.total_out += c2, r2.total += c2, r2.wrap && c2 && (e2.adler = r2.check = r2.flags ? B(r2.check, i2, c2, e2.next_out - c2) : O(r2.check, i2, c2, e2.next_out - c2)), e2.data_type = r2.bits + (r2.last ? 64 : 0) + (r2.mode === 12 ? 128 : 0) + (r2.mode === 20 || r2.mode === 15 ? 256 : 0), (f2 == 0 && c2 === 0 || t2 === 4) && x === N && (x = -5), x);
      }, r.inflateEnd = function(e2) {
        if (!e2 || !e2.state)
          return U;
        var t2 = e2.state;
        return t2.window && (t2.window = null), e2.state = null, N;
      }, r.inflateGetHeader = function(e2, t2) {
        var r2;
        return e2 && e2.state && 2 & (r2 = e2.state).wrap ? ((r2.head = t2).done = !1, N) : U;
      }, r.inflateSetDictionary = function(e2, t2) {
        var r2, n2 = t2.length;
        return e2 && e2.state ? (r2 = e2.state).wrap !== 0 && r2.mode !== 11 ? U : r2.mode === 11 && O(1, t2, n2, 0) !== r2.check ? -3 : Z(e2, t2, n2, n2) ? (r2.mode = 31, -4) : (r2.havedict = 1, N) : U;
      }, r.inflateInfo = "pako inflate (from Nodeca project)";
    }, { "../utils/common": 41, "./adler32": 43, "./crc32": 45, "./inffast": 48, "./inftrees": 50 }], 50: [function(e, t, r) {
      var D = e("../utils/common"), F = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0], N = [16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78], U = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0], P = [16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64];
      t.exports = function(e2, t2, r2, n, i, s, a, o) {
        var h, u, l, f, c, d, p, m, _, g = o.bits, b = 0, v = 0, y = 0, w = 0, k = 0, x = 0, S = 0, z = 0, C = 0, E = 0, A = null, I = 0, O = new D.Buf16(16), B = new D.Buf16(16), R = null, T = 0;
        for (b = 0; b <= 15; b++)
          O[b] = 0;
        for (v = 0; v < n; v++)
          O[t2[r2 + v]]++;
        for (k = g, w = 15; 1 <= w && O[w] === 0; w--)
          ;
        if (w < k && (k = w), w === 0)
          return i[s++] = 20971520, i[s++] = 20971520, o.bits = 1, 0;
        for (y = 1; y < w && O[y] === 0; y++)
          ;
        for (k < y && (k = y), b = z = 1; b <= 15; b++)
          if (z <<= 1, (z -= O[b]) < 0)
            return -1;
        if (0 < z && (e2 === 0 || w !== 1))
          return -1;
        for (B[1] = 0, b = 1; b < 15; b++)
          B[b + 1] = B[b] + O[b];
        for (v = 0; v < n; v++)
          t2[r2 + v] !== 0 && (a[B[t2[r2 + v]]++] = v);
        if (d = e2 === 0 ? (A = R = a, 19) : e2 === 1 ? (A = F, I -= 257, R = N, T -= 257, 256) : (A = U, R = P, -1), b = y, c = s, S = v = E = 0, l = -1, f = (C = 1 << (x = k)) - 1, e2 === 1 && 852 < C || e2 === 2 && 592 < C)
          return 1;
        for (; ; ) {
          for (p = b - S, _ = a[v] < d ? (m = 0, a[v]) : a[v] > d ? (m = R[T + a[v]], A[I + a[v]]) : (m = 96, 0), h = 1 << b - S, y = u = 1 << x; i[c + (E >> S) + (u -= h)] = p << 24 | m << 16 | _ | 0, u !== 0; )
            ;
          for (h = 1 << b - 1; E & h; )
            h >>= 1;
          if (h !== 0 ? (E &= h - 1, E += h) : E = 0, v++, --O[b] == 0) {
            if (b === w)
              break;
            b = t2[r2 + a[v]];
          }
          if (k < b && (E & f) !== l) {
            for (S === 0 && (S = k), c += y, z = 1 << (x = b - S); x + S < w && !((z -= O[x + S]) <= 0); )
              x++, z <<= 1;
            if (C += 1 << x, e2 === 1 && 852 < C || e2 === 2 && 592 < C)
              return 1;
            i[l = E & f] = k << 24 | x << 16 | c - s | 0;
          }
        }
        return E !== 0 && (i[c + E] = b - S << 24 | 64 << 16 | 0), o.bits = k, 0;
      };
    }, { "../utils/common": 41 }], 51: [function(e, t, r) {
      t.exports = { 2: "need dictionary", 1: "stream end", 0: "", "-1": "file error", "-2": "stream error", "-3": "data error", "-4": "insufficient memory", "-5": "buffer error", "-6": "incompatible version" };
    }, {}], 52: [function(e, t, r) {
      var i = e("../utils/common"), o = 0, h = 1;
      function n(e2) {
        for (var t2 = e2.length; 0 <= --t2; )
          e2[t2] = 0;
      }
      __name(n, "n");
      var s = 0, a = 29, u = 256, l = u + 1 + a, f = 30, c = 19, _ = 2 * l + 1, g = 15, d = 16, p = 7, m = 256, b = 16, v = 17, y = 18, w = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0], k = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13], x = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7], S = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], z = new Array(2 * (l + 2));
      n(z);
      var C = new Array(2 * f);
      n(C);
      var E = new Array(512);
      n(E);
      var A = new Array(256);
      n(A);
      var I = new Array(a);
      n(I);
      var O, B, R, T = new Array(f);
      function D(e2, t2, r2, n2, i2) {
        this.static_tree = e2, this.extra_bits = t2, this.extra_base = r2, this.elems = n2, this.max_length = i2, this.has_stree = e2 && e2.length;
      }
      __name(D, "D");
      function F(e2, t2) {
        this.dyn_tree = e2, this.max_code = 0, this.stat_desc = t2;
      }
      __name(F, "F");
      function N(e2) {
        return e2 < 256 ? E[e2] : E[256 + (e2 >>> 7)];
      }
      __name(N, "N");
      function U(e2, t2) {
        e2.pending_buf[e2.pending++] = 255 & t2, e2.pending_buf[e2.pending++] = t2 >>> 8 & 255;
      }
      __name(U, "U");
      function P(e2, t2, r2) {
        e2.bi_valid > d - r2 ? (e2.bi_buf |= t2 << e2.bi_valid & 65535, U(e2, e2.bi_buf), e2.bi_buf = t2 >> d - e2.bi_valid, e2.bi_valid += r2 - d) : (e2.bi_buf |= t2 << e2.bi_valid & 65535, e2.bi_valid += r2);
      }
      __name(P, "P");
      function L(e2, t2, r2) {
        P(e2, r2[2 * t2], r2[2 * t2 + 1]);
      }
      __name(L, "L");
      function j(e2, t2) {
        for (var r2 = 0; r2 |= 1 & e2, e2 >>>= 1, r2 <<= 1, 0 < --t2; )
          ;
        return r2 >>> 1;
      }
      __name(j, "j");
      function Z(e2, t2, r2) {
        var n2, i2, s2 = new Array(g + 1), a2 = 0;
        for (n2 = 1; n2 <= g; n2++)
          s2[n2] = a2 = a2 + r2[n2 - 1] << 1;
        for (i2 = 0; i2 <= t2; i2++) {
          var o2 = e2[2 * i2 + 1];
          o2 !== 0 && (e2[2 * i2] = j(s2[o2]++, o2));
        }
      }
      __name(Z, "Z");
      function W(e2) {
        var t2;
        for (t2 = 0; t2 < l; t2++)
          e2.dyn_ltree[2 * t2] = 0;
        for (t2 = 0; t2 < f; t2++)
          e2.dyn_dtree[2 * t2] = 0;
        for (t2 = 0; t2 < c; t2++)
          e2.bl_tree[2 * t2] = 0;
        e2.dyn_ltree[2 * m] = 1, e2.opt_len = e2.static_len = 0, e2.last_lit = e2.matches = 0;
      }
      __name(W, "W");
      function M(e2) {
        8 < e2.bi_valid ? U(e2, e2.bi_buf) : 0 < e2.bi_valid && (e2.pending_buf[e2.pending++] = e2.bi_buf), e2.bi_buf = 0, e2.bi_valid = 0;
      }
      __name(M, "M");
      function H(e2, t2, r2, n2) {
        var i2 = 2 * t2, s2 = 2 * r2;
        return e2[i2] < e2[s2] || e2[i2] === e2[s2] && n2[t2] <= n2[r2];
      }
      __name(H, "H");
      function G(e2, t2, r2) {
        for (var n2 = e2.heap[r2], i2 = r2 << 1; i2 <= e2.heap_len && (i2 < e2.heap_len && H(t2, e2.heap[i2 + 1], e2.heap[i2], e2.depth) && i2++, !H(t2, n2, e2.heap[i2], e2.depth)); )
          e2.heap[r2] = e2.heap[i2], r2 = i2, i2 <<= 1;
        e2.heap[r2] = n2;
      }
      __name(G, "G");
      function K(e2, t2, r2) {
        var n2, i2, s2, a2, o2 = 0;
        if (e2.last_lit !== 0)
          for (; n2 = e2.pending_buf[e2.d_buf + 2 * o2] << 8 | e2.pending_buf[e2.d_buf + 2 * o2 + 1], i2 = e2.pending_buf[e2.l_buf + o2], o2++, n2 === 0 ? L(e2, i2, t2) : (L(e2, (s2 = A[i2]) + u + 1, t2), (a2 = w[s2]) !== 0 && P(e2, i2 -= I[s2], a2), L(e2, s2 = N(--n2), r2), (a2 = k[s2]) !== 0 && P(e2, n2 -= T[s2], a2)), o2 < e2.last_lit; )
            ;
        L(e2, m, t2);
      }
      __name(K, "K");
      function Y(e2, t2) {
        var r2, n2, i2, s2 = t2.dyn_tree, a2 = t2.stat_desc.static_tree, o2 = t2.stat_desc.has_stree, h2 = t2.stat_desc.elems, u2 = -1;
        for (e2.heap_len = 0, e2.heap_max = _, r2 = 0; r2 < h2; r2++)
          s2[2 * r2] !== 0 ? (e2.heap[++e2.heap_len] = u2 = r2, e2.depth[r2] = 0) : s2[2 * r2 + 1] = 0;
        for (; e2.heap_len < 2; )
          s2[2 * (i2 = e2.heap[++e2.heap_len] = u2 < 2 ? ++u2 : 0)] = 1, e2.depth[i2] = 0, e2.opt_len--, o2 && (e2.static_len -= a2[2 * i2 + 1]);
        for (t2.max_code = u2, r2 = e2.heap_len >> 1; 1 <= r2; r2--)
          G(e2, s2, r2);
        for (i2 = h2; r2 = e2.heap[1], e2.heap[1] = e2.heap[e2.heap_len--], G(e2, s2, 1), n2 = e2.heap[1], e2.heap[--e2.heap_max] = r2, e2.heap[--e2.heap_max] = n2, s2[2 * i2] = s2[2 * r2] + s2[2 * n2], e2.depth[i2] = (e2.depth[r2] >= e2.depth[n2] ? e2.depth[r2] : e2.depth[n2]) + 1, s2[2 * r2 + 1] = s2[2 * n2 + 1] = i2, e2.heap[1] = i2++, G(e2, s2, 1), 2 <= e2.heap_len; )
          ;
        e2.heap[--e2.heap_max] = e2.heap[1], function(e3, t3) {
          var r3, n3, i3, s3, a3, o3, h3 = t3.dyn_tree, u3 = t3.max_code, l2 = t3.stat_desc.static_tree, f2 = t3.stat_desc.has_stree, c2 = t3.stat_desc.extra_bits, d2 = t3.stat_desc.extra_base, p2 = t3.stat_desc.max_length, m2 = 0;
          for (s3 = 0; s3 <= g; s3++)
            e3.bl_count[s3] = 0;
          for (h3[2 * e3.heap[e3.heap_max] + 1] = 0, r3 = e3.heap_max + 1; r3 < _; r3++)
            p2 < (s3 = h3[2 * h3[2 * (n3 = e3.heap[r3]) + 1] + 1] + 1) && (s3 = p2, m2++), h3[2 * n3 + 1] = s3, u3 < n3 || (e3.bl_count[s3]++, a3 = 0, d2 <= n3 && (a3 = c2[n3 - d2]), o3 = h3[2 * n3], e3.opt_len += o3 * (s3 + a3), f2 && (e3.static_len += o3 * (l2[2 * n3 + 1] + a3)));
          if (m2 !== 0) {
            do {
              for (s3 = p2 - 1; e3.bl_count[s3] === 0; )
                s3--;
              e3.bl_count[s3]--, e3.bl_count[s3 + 1] += 2, e3.bl_count[p2]--, m2 -= 2;
            } while (0 < m2);
            for (s3 = p2; s3 !== 0; s3--)
              for (n3 = e3.bl_count[s3]; n3 !== 0; )
                u3 < (i3 = e3.heap[--r3]) || (h3[2 * i3 + 1] !== s3 && (e3.opt_len += (s3 - h3[2 * i3 + 1]) * h3[2 * i3], h3[2 * i3 + 1] = s3), n3--);
          }
        }(e2, t2), Z(s2, u2, e2.bl_count);
      }
      __name(Y, "Y");
      function X(e2, t2, r2) {
        var n2, i2, s2 = -1, a2 = t2[1], o2 = 0, h2 = 7, u2 = 4;
        for (a2 === 0 && (h2 = 138, u2 = 3), t2[2 * (r2 + 1) + 1] = 65535, n2 = 0; n2 <= r2; n2++)
          i2 = a2, a2 = t2[2 * (n2 + 1) + 1], ++o2 < h2 && i2 === a2 || (o2 < u2 ? e2.bl_tree[2 * i2] += o2 : i2 !== 0 ? (i2 !== s2 && e2.bl_tree[2 * i2]++, e2.bl_tree[2 * b]++) : o2 <= 10 ? e2.bl_tree[2 * v]++ : e2.bl_tree[2 * y]++, s2 = i2, u2 = (o2 = 0) === a2 ? (h2 = 138, 3) : i2 === a2 ? (h2 = 6, 3) : (h2 = 7, 4));
      }
      __name(X, "X");
      function V(e2, t2, r2) {
        var n2, i2, s2 = -1, a2 = t2[1], o2 = 0, h2 = 7, u2 = 4;
        for (a2 === 0 && (h2 = 138, u2 = 3), n2 = 0; n2 <= r2; n2++)
          if (i2 = a2, a2 = t2[2 * (n2 + 1) + 1], !(++o2 < h2 && i2 === a2)) {
            if (o2 < u2)
              for (; L(e2, i2, e2.bl_tree), --o2 != 0; )
                ;
            else
              i2 !== 0 ? (i2 !== s2 && (L(e2, i2, e2.bl_tree), o2--), L(e2, b, e2.bl_tree), P(e2, o2 - 3, 2)) : o2 <= 10 ? (L(e2, v, e2.bl_tree), P(e2, o2 - 3, 3)) : (L(e2, y, e2.bl_tree), P(e2, o2 - 11, 7));
            s2 = i2, u2 = (o2 = 0) === a2 ? (h2 = 138, 3) : i2 === a2 ? (h2 = 6, 3) : (h2 = 7, 4);
          }
      }
      __name(V, "V"), n(T);
      var q = !1;
      function J(e2, t2, r2, n2) {
        P(e2, (s << 1) + (n2 ? 1 : 0), 3), function(e3, t3, r3, n3) {
          M(e3), n3 && (U(e3, r3), U(e3, ~r3)), i.arraySet(e3.pending_buf, e3.window, t3, r3, e3.pending), e3.pending += r3;
        }(e2, t2, r2, !0);
      }
      __name(J, "J"), r._tr_init = function(e2) {
        q || (function() {
          var e3, t2, r2, n2, i2, s2 = new Array(g + 1);
          for (n2 = r2 = 0; n2 < a - 1; n2++)
            for (I[n2] = r2, e3 = 0; e3 < 1 << w[n2]; e3++)
              A[r2++] = n2;
          for (A[r2 - 1] = n2, n2 = i2 = 0; n2 < 16; n2++)
            for (T[n2] = i2, e3 = 0; e3 < 1 << k[n2]; e3++)
              E[i2++] = n2;
          for (i2 >>= 7; n2 < f; n2++)
            for (T[n2] = i2 << 7, e3 = 0; e3 < 1 << k[n2] - 7; e3++)
              E[256 + i2++] = n2;
          for (t2 = 0; t2 <= g; t2++)
            s2[t2] = 0;
          for (e3 = 0; e3 <= 143; )
            z[2 * e3 + 1] = 8, e3++, s2[8]++;
          for (; e3 <= 255; )
            z[2 * e3 + 1] = 9, e3++, s2[9]++;
          for (; e3 <= 279; )
            z[2 * e3 + 1] = 7, e3++, s2[7]++;
          for (; e3 <= 287; )
            z[2 * e3 + 1] = 8, e3++, s2[8]++;
          for (Z(z, l + 1, s2), e3 = 0; e3 < f; e3++)
            C[2 * e3 + 1] = 5, C[2 * e3] = j(e3, 5);
          O = new D(z, w, u + 1, l, g), B = new D(C, k, 0, f, g), R = new D(new Array(0), x, 0, c, p);
        }(), q = !0), e2.l_desc = new F(e2.dyn_ltree, O), e2.d_desc = new F(e2.dyn_dtree, B), e2.bl_desc = new F(e2.bl_tree, R), e2.bi_buf = 0, e2.bi_valid = 0, W(e2);
      }, r._tr_stored_block = J, r._tr_flush_block = function(e2, t2, r2, n2) {
        var i2, s2, a2 = 0;
        0 < e2.level ? (e2.strm.data_type === 2 && (e2.strm.data_type = function(e3) {
          var t3, r3 = 4093624447;
          for (t3 = 0; t3 <= 31; t3++, r3 >>>= 1)
            if (1 & r3 && e3.dyn_ltree[2 * t3] !== 0)
              return o;
          if (e3.dyn_ltree[18] !== 0 || e3.dyn_ltree[20] !== 0 || e3.dyn_ltree[26] !== 0)
            return h;
          for (t3 = 32; t3 < u; t3++)
            if (e3.dyn_ltree[2 * t3] !== 0)
              return h;
          return o;
        }(e2)), Y(e2, e2.l_desc), Y(e2, e2.d_desc), a2 = function(e3) {
          var t3;
          for (X(e3, e3.dyn_ltree, e3.l_desc.max_code), X(e3, e3.dyn_dtree, e3.d_desc.max_code), Y(e3, e3.bl_desc), t3 = c - 1; 3 <= t3 && e3.bl_tree[2 * S[t3] + 1] === 0; t3--)
            ;
          return e3.opt_len += 3 * (t3 + 1) + 5 + 5 + 4, t3;
        }(e2), i2 = e2.opt_len + 3 + 7 >>> 3, (s2 = e2.static_len + 3 + 7 >>> 3) <= i2 && (i2 = s2)) : i2 = s2 = r2 + 5, r2 + 4 <= i2 && t2 !== -1 ? J(e2, t2, r2, n2) : e2.strategy === 4 || s2 === i2 ? (P(e2, 2 + (n2 ? 1 : 0), 3), K(e2, z, C)) : (P(e2, 4 + (n2 ? 1 : 0), 3), function(e3, t3, r3, n3) {
          var i3;
          for (P(e3, t3 - 257, 5), P(e3, r3 - 1, 5), P(e3, n3 - 4, 4), i3 = 0; i3 < n3; i3++)
            P(e3, e3.bl_tree[2 * S[i3] + 1], 3);
          V(e3, e3.dyn_ltree, t3 - 1), V(e3, e3.dyn_dtree, r3 - 1);
        }(e2, e2.l_desc.max_code + 1, e2.d_desc.max_code + 1, a2 + 1), K(e2, e2.dyn_ltree, e2.dyn_dtree)), W(e2), n2 && M(e2);
      }, r._tr_tally = function(e2, t2, r2) {
        return e2.pending_buf[e2.d_buf + 2 * e2.last_lit] = t2 >>> 8 & 255, e2.pending_buf[e2.d_buf + 2 * e2.last_lit + 1] = 255 & t2, e2.pending_buf[e2.l_buf + e2.last_lit] = 255 & r2, e2.last_lit++, t2 === 0 ? e2.dyn_ltree[2 * r2]++ : (e2.matches++, t2--, e2.dyn_ltree[2 * (A[r2] + u + 1)]++, e2.dyn_dtree[2 * N(t2)]++), e2.last_lit === e2.lit_bufsize - 1;
      }, r._tr_align = function(e2) {
        P(e2, 2, 3), L(e2, m, z), function(e3) {
          e3.bi_valid === 16 ? (U(e3, e3.bi_buf), e3.bi_buf = 0, e3.bi_valid = 0) : 8 <= e3.bi_valid && (e3.pending_buf[e3.pending++] = 255 & e3.bi_buf, e3.bi_buf >>= 8, e3.bi_valid -= 8);
        }(e2);
      };
    }, { "../utils/common": 41 }], 53: [function(e, t, r) {
      t.exports = function() {
        this.input = null, this.next_in = 0, this.avail_in = 0, this.total_in = 0, this.output = null, this.next_out = 0, this.avail_out = 0, this.total_out = 0, this.msg = "", this.state = null, this.data_type = 2, this.adler = 0;
      };
    }, {}], 54: [function(e, t, r) {
      (function(e2) {
        (function(r2, n) {
          if (!r2.setImmediate) {
            var i, s, t2, a, o = 1, h = {}, u = !1, l = r2.document, e3 = Object.getPrototypeOf && Object.getPrototypeOf(r2);
            e3 = e3 && e3.setTimeout ? e3 : r2, i = {}.toString.call(r2.process) === "[object process]" ? function(e4) {
              process.nextTick(function() {
                c(e4);
              });
            } : function() {
              if (r2.postMessage && !r2.importScripts) {
                var e4 = !0, t3 = r2.onmessage;
                return r2.onmessage = function() {
                  e4 = !1;
                }, r2.postMessage("", "*"), r2.onmessage = t3, e4;
              }
            }() ? (a = "setImmediate$" + Math.random() + "$", r2.addEventListener ? r2.addEventListener("message", d, !1) : r2.attachEvent("onmessage", d), function(e4) {
              r2.postMessage(a + e4, "*");
            }) : r2.MessageChannel ? ((t2 = new MessageChannel()).port1.onmessage = function(e4) {
              c(e4.data);
            }, function(e4) {
              t2.port2.postMessage(e4);
            }) : l && "onreadystatechange" in l.createElement("script") ? (s = l.documentElement, function(e4) {
              var t3 = l.createElement("script");
              t3.onreadystatechange = function() {
                c(e4), t3.onreadystatechange = null, s.removeChild(t3), t3 = null;
              }, s.appendChild(t3);
            }) : function(e4) {
              setTimeout(c, 0, e4);
            }, e3.setImmediate = function(e4) {
              typeof e4 != "function" && (e4 = new Function("" + e4));
              for (var t3 = new Array(arguments.length - 1), r3 = 0; r3 < t3.length; r3++)
                t3[r3] = arguments[r3 + 1];
              var n2 = { callback: e4, args: t3 };
              return h[o] = n2, i(o), o++;
            }, e3.clearImmediate = f;
          }
          function f(e4) {
            delete h[e4];
          }
          __name(f, "f");
          function c(e4) {
            if (u)
              setTimeout(c, 0, e4);
            else {
              var t3 = h[e4];
              if (t3) {
                u = !0;
                try {
                  (function(e5) {
                    var t4 = e5.callback, r3 = e5.args;
                    switch (r3.length) {
                      case 0:
                        t4();
                        break;
                      case 1:
                        t4(r3[0]);
                        break;
                      case 2:
                        t4(r3[0], r3[1]);
                        break;
                      case 3:
                        t4(r3[0], r3[1], r3[2]);
                        break;
                      default:
                        t4.apply(n, r3);
                    }
                  })(t3);
                } finally {
                  f(e4), u = !1;
                }
              }
            }
          }
          __name(c, "c");
          function d(e4) {
            e4.source === r2 && typeof e4.data == "string" && e4.data.indexOf(a) === 0 && c(+e4.data.slice(a.length));
          }
          __name(d, "d");
        })(typeof self > "u" ? e2 === void 0 ? this : e2 : self);
      }).call(this, typeof commonjsGlobal < "u" ? commonjsGlobal : typeof self < "u" ? self : typeof window < "u" ? window : {});
    }, {}] }, {}, [10])(10);
  });
})(jszip_min);
var jszip_minExports = jszip_min.exports;
const JSZip = /* @__PURE__ */ getDefaultExportFromCjs(jszip_minExports), CORE_BREW_ID = "core";
function isValidManifest(obj) {
  return typeof obj == "object" && "name" in obj && typeof obj.name == "string" && "author" in obj && typeof obj.author == "string" && "version" in obj && typeof obj.version == "string";
}
__name(isValidManifest, "isValidManifest");
function generateLcpSummary(cp) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
  const data2 = cp.data ? cp.data : cp;
  return {
    ...cp.manifest,
    item_prefix: "",
    bonds: ((_a19 = data2.bonds) == null ? void 0 : _a19.length) ?? 0,
    skills: ((_b = data2.skills) == null ? void 0 : _b.length) ?? 0,
    talents: ((_c = data2.talents) == null ? void 0 : _c.length) ?? 0,
    reserves: ((_d = data2.reserves) == null ? void 0 : _d.length) ?? 0,
    gear: ((_e = data2.pilotGear) == null ? void 0 : _e.length) ?? 0,
    frames: ((_f = data2.frames) == null ? void 0 : _f.length) ?? 0,
    systems: ((_g = data2.systems) == null ? void 0 : _g.length) ?? 0,
    weapons: ((_h = data2.weapons) == null ? void 0 : _h.length) ?? 0,
    mods: ((_i = data2.mods) == null ? void 0 : _i.length) ?? 0,
    npc_classes: ((_j = data2.npcClasses) == null ? void 0 : _j.length) ?? 0,
    npc_templates: ((_k = data2.npcTemplates) == null ? void 0 : _k.length) ?? 0,
    npc_features: ((_l = data2.npcFeatures) == null ? void 0 : _l.length) ?? 0
  };
}
__name(generateLcpSummary, "generateLcpSummary");
function generateMultiLcpSummary(manifest, cps) {
  return cps.reduce(
    (acc, lcp) => {
      var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
      return lcp.data && (acc.bonds += ((_a19 = lcp.data.bonds) == null ? void 0 : _a19.length) ?? 0, acc.skills += ((_b = lcp.data.skills) == null ? void 0 : _b.length) ?? 0, acc.talents += ((_c = lcp.data.talents) == null ? void 0 : _c.length) ?? 0, acc.reserves += ((_d = lcp.data.reserves) == null ? void 0 : _d.length) ?? 0, acc.gear += ((_e = lcp.data.pilotGear) == null ? void 0 : _e.length) ?? 0, acc.frames += ((_f = lcp.data.frames) == null ? void 0 : _f.length) ?? 0, acc.systems += ((_g = lcp.data.systems) == null ? void 0 : _g.length) ?? 0, acc.weapons += ((_h = lcp.data.weapons) == null ? void 0 : _h.length) ?? 0, acc.mods += ((_i = lcp.data.mods) == null ? void 0 : _i.length) ?? 0, acc.npc_classes += ((_j = lcp.data.npcClasses) == null ? void 0 : _j.length) ?? 0, acc.npc_templates += ((_k = lcp.data.npcTemplates) == null ? void 0 : _k.length) ?? 0, acc.npc_features += ((_l = lcp.data.npcFeatures) == null ? void 0 : _l.length) ?? 0), acc;
    },
    {
      ...manifest,
      bonds: 0,
      skills: 0,
      talents: 0,
      reserves: 0,
      gear: 0,
      frames: 0,
      systems: 0,
      weapons: 0,
      mods: 0,
      npc_classes: 0,
      npc_templates: 0,
      npc_features: 0
    }
  );
}
__name(generateMultiLcpSummary, "generateMultiLcpSummary");
function getPackageVersion(manifest) {
  return manifest.version;
}
__name(getPackageVersion, "getPackageVersion");
function getTitle(manifest) {
  return manifest.name;
}
__name(getTitle, "getTitle");
function getAuthor(manifest) {
  return manifest.author;
}
__name(getAuthor, "getAuthor");
function getInstalledVersion(manifest, lcpIndex) {
  var _a19, _b;
  return ((_b = (_a19 = lcpIndex.index) == null ? void 0 : _a19.find((m) => m.name === manifest.name)) == null ? void 0 : _b.version) || "--";
}
__name(getInstalledVersion, "getInstalledVersion");
function getUrl(manifest) {
  return manifest.website || "";
}
__name(getUrl, "getUrl");
async function readZipJSON(zip, filename) {
  const file = zip.file(filename);
  if (!file)
    return null;
  const text = await file.async("text");
  return JSON.parse(text);
}
__name(readZipJSON, "readZipJSON");
async function getPackID(manifest) {
  return `${manifest.author}/${manifest.name}`;
}
__name(getPackID, "getPackID");
async function getZipData(zip, filename) {
  let readResult;
  try {
    readResult = await readZipJSON(zip, filename);
  } catch (e) {
    console.error(`Error reading file ${filename} from package, skipping. Error follows:`), console.trace(e), readResult = null;
  }
  return readResult || [];
}
__name(getZipData, "getZipData");
function generateItemID(type2, name2, manifest) {
  const sanitizedName = name2.replace(/[ \/-]/g, "_").replace(/[^A-Za-z0-9_]/g, "").toLowerCase();
  return manifest != null && manifest.item_prefix ? `${manifest.item_prefix}__${type2}_${sanitizedName}` : `${type2}__${sanitizedName}`;
}
__name(generateItemID, "generateItemID");
async function parseContentPack(binString) {
  const zip = await JSZip.loadAsync(binString), manifest = await readZipJSON(zip, "lcp_manifest.json");
  if (!manifest)
    throw new Error("Content pack has no manifest");
  if (!isValidManifest(manifest))
    throw new Error("Content manifest is invalid");
  function generateIDs(data2, dataPrefix) {
    if (dataPrefix)
      for (let d of data2)
        d.id = d.id || generateItemID(dataPrefix, d.name);
    return data2;
  }
  __name(generateIDs, "generateIDs");
  const coreBonuses = generateIDs(
    await getZipData(zip, "core_bonuses.json"),
    EntryTypeLidPrefix(EntryType.CORE_BONUS)
  ), frames = generateIDs(
    await getZipData(zip, "frames.json"),
    EntryTypeLidPrefix(EntryType.FRAME)
  ), weapons = generateIDs(
    await getZipData(zip, "weapons.json"),
    EntryTypeLidPrefix(EntryType.MECH_WEAPON)
  ), systems = generateIDs(
    await getZipData(zip, "systems.json"),
    EntryTypeLidPrefix(EntryType.MECH_SYSTEM)
  ), mods = generateIDs(
    await getZipData(zip, "mods.json"),
    EntryTypeLidPrefix(EntryType.WEAPON_MOD)
  ), pilotGear = generateIDs(
    await getZipData(zip, "pilot_gear.json"),
    EntryTypeLidPrefix(EntryType.PILOT_GEAR)
  ), skills = generateIDs(
    await getZipData(zip, "skills.json"),
    EntryTypeLidPrefix(EntryType.SKILL)
  ), talents = generateIDs(
    await getZipData(zip, "talents.json"),
    EntryTypeLidPrefix(EntryType.TALENT)
  ), bonds = generateIDs(await getZipData(zip, "bonds.json"), EntryTypeLidPrefix(EntryType.BOND)), reserves = generateIDs(
    await getZipData(zip, "reserves.json"),
    EntryTypeLidPrefix(EntryType.RESERVE)
  ), tags = generateIDs(await getZipData(zip, "tags.json"), "tg_"), statuses = generateIDs(
    (await getZipData(zip, "statuses.json")).map((status) => ({
      id: status.name.toLowerCase(),
      ...status
    })),
    EntryTypeLidPrefix(EntryType.STATUS)
  ), npcClasses = generateIDs(
    await readZipJSON(zip, "npc_classes.json") || [],
    EntryTypeLidPrefix(EntryType.NPC_CLASS)
  ), npcFeatures = generateIDs(
    await readZipJSON(zip, "npc_features.json") || [],
    EntryTypeLidPrefix(EntryType.NPC_FEATURE)
  ), npcTemplates = generateIDs(
    await readZipJSON(zip, "npc_templates.json") || [],
    EntryTypeLidPrefix(EntryType.NPC_TEMPLATE)
  );
  return {
    id: await getPackID(manifest),
    active: !1,
    manifest,
    data: {
      coreBonuses,
      frames,
      weapons,
      systems,
      mods,
      pilotGear,
      skills,
      talents,
      bonds,
      reserves,
      tags,
      statuses,
      npcClasses,
      npcFeatures,
      npcTemplates
    }
  };
}
__name(parseContentPack, "parseContentPack");
function convertNpmDataToContentPack(data2, id, manifest) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
  if (!data2.lcp_manifest && !manifest)
    throw new Error("No manifest provided for content pack.");
  const removePlaceholders = /* @__PURE__ */ __name((x) => !x.id || !x.id.startsWith("missing_"), "removePlaceholders");
  return {
    id,
    active: !0,
    manifest: data2.lcp_manifest || manifest,
    data: {
      coreBonuses: (_a19 = data2.core_bonuses) == null ? void 0 : _a19.filter(removePlaceholders),
      frames: (_b = data2.frames) == null ? void 0 : _b.filter(removePlaceholders),
      weapons: (_c = data2.weapons) == null ? void 0 : _c.filter(removePlaceholders),
      systems: (_d = data2.systems) == null ? void 0 : _d.filter(removePlaceholders),
      mods: (_e = data2.mods) == null ? void 0 : _e.filter(removePlaceholders),
      pilotGear: (_f = data2.pilot_gear) == null ? void 0 : _f.filter(removePlaceholders),
      skills: (_g = data2.skills) == null ? void 0 : _g.filter(removePlaceholders),
      talents: (_h = data2.talents) == null ? void 0 : _h.filter(removePlaceholders),
      bonds: (_i = data2.bonds) == null ? void 0 : _i.filter(removePlaceholders),
      reserves: (_j = data2.reserves) == null ? void 0 : _j.filter(removePlaceholders),
      tags: (_k = data2.tags) == null ? void 0 : _k.filter(removePlaceholders),
      statuses: (_l = data2.statuses) == null ? void 0 : _l.filter(removePlaceholders),
      npcClasses: (_m = data2.npc_classes) == null ? void 0 : _m.filter(removePlaceholders),
      npcFeatures: (_n = data2.npc_features) == null ? void 0 : _n.filter(removePlaceholders),
      npcTemplates: (_o = data2.npc_templates) == null ? void 0 : _o.filter(removePlaceholders)
    }
  };
}
__name(convertNpmDataToContentPack, "convertNpmDataToContentPack");
async function getBaseContentPack() {
  const lancerDataPackage = await Promise.resolve().then(() => _package$1), lancerData2 = await Promise.resolve().then(() => index$1), author2 = "Massif Press", name2 = "Lancer Core Book Data", version2 = lancerDataPackage.version, url = "https://massif-press.itch.io/corebook-pdf-free", manifest = {
    author: author2,
    item_prefix: "",
    // Don't want one
    name: name2,
    version: version2,
    website: url,
    image_url: "https://img.itch.zone/aW1hZ2UvNDIyNjI3LzI1MDY2NTMuanBn/347x500/6cEGFF.jpg"
  };
  return {
    id: CORE_BREW_ID,
    title: name2,
    author: author2,
    availableVersion: version2,
    currentVersion: game.settings.get("lancer", LANCER.setting_core_data) || "--",
    url,
    cp: convertNpmDataToContentPack(lancerData2, CORE_BREW_ID, manifest)
  };
}
__name(getBaseContentPack, "getBaseContentPack");
async function massifContentPacks() {
  return [
    {
      id: "long-rim",
      manifest: await import("./lcp_manifest-42a7ccc2.mjs"),
      // @ts-expect-error Help welcome!
      cpData: await import("./index-f6cac143.mjs").then((n) => n.i)
    },
    {
      id: "wallflower",
      manifest: await import("./lcp_manifest-c88bbaae.mjs"),
      // @ts-expect-error
      cpData: await import("./index-2f4f0f3c.mjs").then((n) => n.i)
    },
    {
      id: "ktb",
      manifest: await import("./lcp_manifest-329ecc60.mjs"),
      // @ts-expect-error
      cpData: await import("./index-4a385dd8.mjs").then((n) => n.i)
    },
    {
      id: "osr",
      manifest: await import("./lcp_manifest-1598353f.mjs"),
      // @ts-expect-error
      cpData: await import("./index-a01acd41.mjs").then((n) => n.i)
    },
    {
      id: "dustgrave",
      manifest: await import("./lcp_manifest-049e52a0.mjs"),
      // @ts-expect-error
      cpData: await import("./index-f4cc1fa4.mjs").then((n) => n.i)
    },
    {
      id: "ssmr",
      manifest: await import("./lcp_manifest-decf8182.mjs"),
      // @ts-expect-error
      cpData: await import("./index-04a29b2c.mjs").then((n) => n.i)
    },
    {
      id: "ows",
      manifest: await import("./lcp_manifest-76f82706.mjs"),
      // @ts-expect-error
      cpData: await import("./index-c4b75ba0.mjs").then((n) => n.i)
    },
    {
      id: "sotw",
      manifest: await import("./lcp_manifest-3ec5d453.mjs"),
      // @ts-expect-error
      cpData: await import("./index-da14d98d.mjs").then((n) => n.i)
    }
  ];
}
__name(massifContentPacks, "massifContentPacks");
async function getOfficialData(lcpIndex) {
  const coreData = await getBaseContentPack(), massifContent = await massifContentPacks(), nonCoreContent = (await Promise.all(
    massifContent.map(async (content) => !content.manifest || !content.cpData ? null : {
      id: content.id,
      title: getTitle(content.manifest),
      author: getAuthor(content.manifest),
      availableVersion: getPackageVersion(content.manifest),
      currentVersion: lcpIndex ? getInstalledVersion(content.manifest, lcpIndex) : "--",
      url: getUrl(content.manifest),
      cp: convertNpmDataToContentPack(content.cpData, content.id, content.manifest)
    })
  )).filter((c) => c !== null);
  return [coreData, ...nonCoreContent];
}
__name(getOfficialData, "getOfficialData");
function mergeOfficialDataAndLcpIndex(officialData, lcpIndex) {
  const indexData = lcpIndex.index.filter((lcp) => !officialData.find((odLcp) => lcp.name === odLcp.title && lcp.author === odLcp.author)).map((lcp) => ({
    ...lcp,
    title: lcp.name,
    id: lcp.name.replace(/\s/g, "-").toLowerCase(),
    availableVersion: "",
    currentVersion: lcp.version
  }));
  return [...officialData, ...indexData];
}
__name(mergeOfficialDataAndLcpIndex, "mergeOfficialDataAndLcpIndex");
const lp$c = LANCER.log_prefix;
var _a12;
const _LancerItem = (_a12 = class extends Item {
  static getDefaultArtwork(itemData2) {
    const model = CONFIG.Item.dataModels[(itemData2 == null ? void 0 : itemData2.type) ?? "base"];
    return (model == null ? void 0 : model.getDefaultArtwork) instanceof Function ? model.getDefaultArtwork(itemData2) : { img: (model == null ? void 0 : model.DEFAULT_ICON) ?? this.DEFAULT_ICON };
  }
  /**
   * Returns all ranges for the item that match the provided range types
   */
  rangesFor(types) {
    const filter = new Set(types);
    switch (this.type) {
      case EntryType.MECH_WEAPON:
        const p = this.system.selected_profile_index;
        return this.system.profiles[p].range.filter((r) => filter.has(r.type));
      case EntryType.PILOT_WEAPON:
        return this.system.range.filter((r) => filter.has(r.type));
      case EntryType.NPC_FEATURE:
        return this.system.type !== NpcFeatureType.Weapon ? [] : this.system.range.filter((r) => filter.has(r.type));
      default:
        return [];
    }
  }
  currentProfile() {
    var _a19, _b, _c, _d, _e;
    const result = {
      range: []
    };
    if (this.is_mech_weapon()) {
      const p = this.system.selected_profile_index;
      result.range.push(...this.system.profiles[p].range), result.damage = result.damage ?? [], result.damage.push(...this.system.profiles[p].damage);
    } else if (this.is_pilot_weapon())
      result.range.push(...this.system.range), result.damage = result.damage ?? [], result.damage.push(...this.system.damage);
    else if (this.is_npc_feature() && (this.system.type === NpcFeatureType.Weapon || this.system.type === NpcFeatureType.Tech)) {
      let tier = 0;
      this.actor && (tier = (this.actor.system.tier ?? 1) - 1), this.system.type === NpcFeatureType.Weapon ? (result.range.push(...this.system.range), result.damage = result.damage ?? [], result.damage.push(...this.system.damage[tier])) : result.range.push({ type: RangeType.Range, val: ((_a19 = this.actor) == null ? void 0 : _a19.system.sensor_range) || 5 }), result.accuracy = this.system.accuracy ? this.system.accuracy[tier] : 0, result.attack = this.system.attack_bonus ? this.system.attack_bonus[tier] : 0;
    } else
      this.is_mech_system() || this.is_frame() ? result.range.push({ type: RangeType.Range, val: ((_b = this.actor) == null ? void 0 : _b.system.sensor_range) || 5 }) : this.is_talent() && result.range.push({
        type: RangeType.Range,
        val: ((_e = (_d = (_c = this.actor) == null ? void 0 : _c.system.active_mech) == null ? void 0 : _d.value) == null ? void 0 : _e.system.sensor_range) || 5
      });
    return result;
  }
  /** Sets this item to its default equipped state */
  _resetEquipped() {
    switch (this.type) {
      case EntryType.MECH_SYSTEM:
      case EntryType.MECH_WEAPON:
      case EntryType.WEAPON_MOD:
      case EntryType.FRAME:
      case EntryType.PILOT_GEAR:
      case EntryType.PILOT_ARMOR:
      case EntryType.PILOT_WEAPON:
        this.system.equipped = !1;
        break;
      default:
        this.system.equipped = !0;
        break;
    }
  }
  /**
   * Perform preliminary item preparation.
   * Set equipped to its initial value (to be later finalized)
   * Set active weapon profile
   * Set limited max based on tags
   */
  prepareBaseData() {
    if (super.prepareBaseData(), !!ITEM_TYPES.includes(this.type)) {
      if (this.is_mech_weapon()) {
        this.system.all_base_tags = this.system.profiles.flatMap((p) => p.tags), this.system.all_tags = [], this.system.active_profile = this.system.profiles[this.system.selected_profile_index] ?? this.system.profiles[0];
        for (let p of this.system.profiles)
          p.bonus_tags = [], p.bonus_range = [], p.bonus_damage = [], p.all_tags = [], p.all_range = [], p.all_damage = [];
      } else if (this.is_npc_feature())
        this.system.lid === "" && (this.system.lid = this.id), this.system.type === NpcFeatureType.Weapon && (!this.system.damage || this.system.damage.length < 3) && (this.system.damage = [[], [], []]);
      else if (this.is_talent()) {
        let unlocked_ranks = this.system.ranks.slice(0, this.system.curr_rank);
        this.system.actions = unlocked_ranks.flatMap((a) => a.actions), this.system.bonuses = unlocked_ranks.flatMap((a) => a.bonuses), this.system.counters = unlocked_ranks.flatMap((a) => a.counters), this.system.synergies = unlocked_ranks.flatMap((a) => a.synergies);
      } else
        this.is_bond() && (this.system.powers = this.system.powers.map((p) => fixupPowerUses(p)));
      this.actor || this.prepareFinalAttributes();
    }
  }
  /**
   * Method used by mech weapons (and perhaps some other miscellaneous items???) to prepare their individual stats
   * using bonuses.
   *
   * Note that it is still necessary that items without actors call this in order to prepare weapon tags
   */
  prepareFinalAttributes() {
    var _a19, _b, _c;
    if (this.is_mech_weapon())
      for (let profile of this.system.profiles) {
        this.system.mod && (profile.bonus_damage.push(...this.system.mod.system.added_damage), profile.bonus_range.push(...this.system.mod.system.added_range), profile.bonus_tags.push(...this.system.mod.system.added_tags));
        for (let b of ((_a19 = this.actor) == null ? void 0 : _a19.system.bonuses.weapon_bonuses) || [])
          bonusAffectsWeapon(this, b) && (b.lid == "damage" ? profile.bonus_damage.push(
            new Damage({
              type: ((_b = profile.damage[0]) == null ? void 0 : _b.type) ?? DamageType.Variable,
              val: b.val
            })
          ) : b.lid == "range" && (this.system.active_profile.type == WeaponType.Melee ? profile.bonus_range.push(
            new Range({
              type: RangeType.Threat,
              val: parseInt(b.val) ?? 0
            })
          ) : profile.bonus_range.push(
            new Range({
              type: RangeType.Range,
              val: parseInt(b.val) ?? 0
            })
          )));
        profile.bonus_damage = Damage.CombineLists([], profile.bonus_damage), profile.bonus_range = Range.CombineLists([], profile.bonus_range), profile.all_damage = Damage.CombineLists(profile.damage, profile.bonus_damage), profile.all_range = Range.CombineLists(profile.range, profile.bonus_range), profile.all_tags = Tag.MergeTags(profile.tags, profile.bonus_tags), this.system.all_tags = Tag.MergeTags(this.system.all_tags, profile.all_tags);
      }
    let lim_tag = (this.getTags() ?? []).find((t) => t.is_limited);
    lim_tag && this._hasUses() && (this.system.uses.max = lim_tag.num_val ?? 0), (_c = this.actor) != null && _c.is_mech() && this._hasUses() && this.system.uses.max && (this.system.uses.max += this.actor.system.loadout.limited_bonus);
  }
  /** @override
   * Want to preserve our arrays
   */
  async update(data2, options = {}) {
    return data2 = this.system.full_update_data(data2), super.update(data2, options);
  }
  /**
   * Generates the effect data for this items bonuses and innate effects (such as those from armor, a frame, etc).
   * Generates no effects if item is destroyed, or unequipped.
   * Result will be a mix of
   * - Bonus effects (aka from compcon Bonus type bonuses)
   * - Innate effects (e.x. the statistical affect of a frames base stats)
   * Result is a temporary ActiveEffect document - it is not persisted to DB
   */
  _generateEphemeralEffects() {
    var _a19;
    if (this.destroyed === !0 || !this.isEquipped())
      return [];
    let effects = [], bonus_groups = [];
    switch (this.type) {
      case EntryType.FRAME:
        let frame = this;
        bonus_groups.push({
          group: frame.system.core_system.passive_name || frame.system.core_system.name,
          bonuses: frame.system.core_system.passive_bonuses
        });
        for (let trait of frame.system.traits)
          bonus_groups.push({
            group: trait.name,
            bonuses: trait.bonuses
          });
        effects.push(frameInnateEffect(this));
        break;
      case EntryType.NPC_CLASS:
        effects.push(npcClassInnateEffect(this));
        break;
      case EntryType.NPC_FEATURE:
        let be = npcFeatureBonusEffects(this), oe = npcFeatureOverrideEffects(this);
        be && effects.push(be), oe && effects.push(oe);
        break;
      case EntryType.PILOT_ARMOR:
      case EntryType.PILOT_GEAR:
      case EntryType.PILOT_WEAPON:
      case EntryType.MECH_SYSTEM:
      case EntryType.WEAPON_MOD:
      case EntryType.CORE_BONUS:
      case EntryType.TALENT:
        bonus_groups.push({ bonuses: this.system.bonuses });
        break;
      case EntryType.MECH_WEAPON:
        let tamw = this;
        bonus_groups.push({
          group: tamw.system.active_profile.name || ((_a19 = tamw.system.active_profile) == null ? void 0 : _a19.name),
          bonuses: tamw.system.active_profile.bonuses
        });
        break;
    }
    return effects.push(
      ...bonus_groups.flatMap((bg) => bg.bonuses.map((b) => convertBonus(this, bg.group ? `${this.name} - ${bg.group}` : this.name, b))).filter((b) => b)
    ), effects.map((e) => new LancerActiveEffect(e, { parent: this }));
  }
  /** @inheritdoc */
  static async _onDeleteOperation() {
  }
  async _preCreate(...[data2, options, user]) {
    var _a19, _b;
    if (await super._preCreate(data2, options, user) === !1)
      return !1;
    if (!((_a19 = data2 == null ? void 0 : data2._stats) != null && _a19.createdTime)) {
      if ((_b = data2.system) != null && _b.lid) {
        console.log(`${lp$c} New ${this.type} has data provided from an import, skipping default init.`);
        return;
      }
      console.log(`${lp$c} Initializing new ${this.type}`), console.log(this.name), this.updateSource({
        system: {
          lid: `${generateItemID(EntryTypeLidPrefix(this.type), this.name)}-${randomString(8)}`
        }
      });
    }
  }
  // Typeguards
  is_core_bonus() {
    return this.type === EntryType.CORE_BONUS;
  }
  is_frame() {
    return this.type === EntryType.FRAME;
  }
  is_license() {
    return this.type === EntryType.LICENSE;
  }
  is_mech_system() {
    return this.type === EntryType.MECH_SYSTEM;
  }
  is_mech_weapon() {
    return this.type === EntryType.MECH_WEAPON;
  }
  is_npc_class() {
    return this.type === EntryType.NPC_CLASS;
  }
  is_npc_feature() {
    return this.type === EntryType.NPC_FEATURE;
  }
  is_npc_template() {
    return this.type === EntryType.NPC_TEMPLATE;
  }
  is_organization() {
    return this.type === EntryType.ORGANIZATION;
  }
  is_pilot_armor() {
    return this.type === EntryType.PILOT_ARMOR;
  }
  is_pilot_gear() {
    return this.type === EntryType.PILOT_GEAR;
  }
  is_pilot_weapon() {
    return this.type === EntryType.PILOT_WEAPON;
  }
  is_reserve() {
    return this.type === EntryType.RESERVE;
  }
  is_skill() {
    return this.type === EntryType.SKILL;
  }
  is_status() {
    return this.type === EntryType.STATUS;
  }
  is_talent() {
    return this.type === EntryType.TALENT;
  }
  is_bond() {
    return this.type === EntryType.BOND;
  }
  is_weapon_mod() {
    return this.type === EntryType.WEAPON_MOD;
  }
  is_weapon() {
    return this.is_mech_weapon() || this.is_pilot_weapon() || this.is_npc_feature() && this.system.type === "Weapon";
  }
  // Quick checkers/getters
  getTags() {
    return this.is_pilot_armor() || this.is_pilot_gear() || this.is_pilot_weapon() || this.is_mech_system() || this.is_npc_feature() || this.is_weapon_mod() || this.is_core_bonus() ? this.system.tags : this.is_mech_weapon() ? this.system.active_profile.all_tags : this.is_frame() ? this.system.core_system.tags : null;
  }
  getBonuses() {
    return this.is_pilot_armor() || this.is_pilot_gear() || this.is_pilot_weapon() || this.is_mech_system() || this.is_core_bonus() ? this.system.bonuses : this.is_mech_weapon() ? this.system.active_profile.bonuses : this.is_frame() ? this.actor && this.actor.system.core_active ? [...this.system.core_system.passive_bonuses, ...this.system.core_system.active_bonuses] : this.system.core_system.passive_bonuses : null;
  }
  // Returns this items limit tag value
  getLimitedBase() {
    var _a19;
    let lim_tag = (_a19 = this.getTags()) == null ? void 0 : _a19.find((t) => t.is_limited);
    return lim_tag ? lim_tag.num_val : null;
  }
  // Returns true & type info if this item tracks uses (whether or not it has the limited tag)
  _hasUses() {
    return this.system.uses !== void 0;
  }
  // Returns true & type info if this has the limited tag
  isLimited() {
    return this._hasUses() && this.system.uses.max > 0;
  }
  // Returns true if this has the loading tag
  isLoading() {
    return (this.getTags() ?? []).some((t) => t.is_loading);
  }
  isRecharge() {
    return (this.getTags() ?? []).some((t) => t.is_recharge);
  }
  isUnique() {
    return (this.getTags() ?? []).some((t) => t.is_unique);
  }
  isAI() {
    return (this.getTags() ?? []).some((t) => t.is_ai);
  }
  isSmart() {
    return (this.getTags() ?? []).some((t) => t.is_smart);
  }
  isAP() {
    return (this.getTags() ?? []).some((t) => t.is_ap);
  }
  isOverkill() {
    return (this.getTags() ?? []).some((t) => t.is_overkill);
  }
  isReliable() {
    return (this.getTags() ?? []).some((t) => t.is_reliable);
  }
  // Returns true & type information if this item has action data
  hasActions() {
    return this.system.actions !== void 0;
  }
  // Returns true either if this is equipped, or if equipping has no meaning. False if not on an actor
  isEquipped() {
    let eq = this.system.equipped;
    return this.actor ? eq : !1;
  }
  // Checks that the provided document is not null, and is a lancer actor
  static async fromUuid(x, messagePrefix) {
    var _a19, _b;
    if (x instanceof _a12)
      return x;
    if (x = await fromUuid(x), !x) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Item ${x} not found.`;
      throw (_a19 = ui.notifications) == null || _a19.error(message), new Error(message);
    }
    if (!(x instanceof _a12)) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Document ${x} not an item.`;
      throw (_b = ui.notifications) == null || _b.error(message), new Error(message);
    }
    return x;
  }
  // Checks that the provided document is not null, and is a lancer actor
  static fromUuidSync(x, messagePrefix) {
    var _a19, _b;
    if (x instanceof _a12)
      return x;
    if (x = fromUuidSync(x), !x) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Item ${x} not found.`;
      throw (_a19 = ui.notifications) == null || _a19.error(message), new Error(message);
    }
    if (!(x instanceof _a12)) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Document ${x} not an item.`;
      throw (_b = ui.notifications) == null || _b.error(message), new Error(message);
    }
    return x;
  }
  async beginWeaponAttackFlow() {
    if (!this.is_mech_weapon() && !this.is_npc_feature() && !this.is_pilot_weapon()) {
      ui.notifications.error(`Item ${this.id} cannot attack as it is not a weapon!`);
      return;
    }
    await new WeaponAttackFlow(this).begin(), console.log("Finished attack flow");
  }
  async beginTechAttackFlow() {
    if (!this.is_mech_system() && !this.is_npc_feature()) {
      ui.notifications.error(`Item ${this.id} cannot attack as it is not a system!`);
      return;
    }
    await new TechAttackFlow(this).begin();
  }
  async beginDamageFlow() {
    if (!this.is_mech_weapon() && !this.is_npc_feature() && !this.is_pilot_weapon()) {
      ui.notifications.error(`Item ${this.id} cannot roll damage as it is not a weapon!`);
      return;
    }
    await new DamageRollFlow(this, { title: `${this.name} damage` }).begin();
  }
  async beginSystemFlow() {
    if (!this.is_mech_system() && !this.is_weapon_mod() && !this.is_npc_feature()) {
      ui.notifications.error(`Item ${this.id} is not a mech system, weapon mod, or NPC feature!`);
      return;
    }
    await new SystemFlow(this).begin();
  }
  async beginActivationFlow(path) {
    if (!path) {
      if (!this.system.actions || this.system.actions.length < 1) {
        ui.notifications.error(`Item ${this.id} has no actions, how did you even get here?`);
        return;
      }
      path = "system.actions.0";
    }
    let flow;
    if (this.is_frame() && path === "system.core_system") {
      this.beginCoreActiveFlow(path);
      return;
    } else
      flow = new ActivationFlow(this, { action_path: path });
    await flow.begin(), console.log("Finished activation flow");
  }
  async beginCoreActiveFlow(path) {
    var _a19;
    if (!this.is_frame()) {
      ui.notifications.error(`Item ${this.id} is not a mech frame!`);
      return;
    }
    path = path ?? "system.core_system", console.log("Core system activation flow on path", path);
    const actionName = ((_a19 = this.system.core_system.active_actions[0]) == null ? void 0 : _a19.name) ?? this.system.core_system.active_name, action = {
      lid: this.system.lid + "_core_system",
      name: `CORE ACTIVATION :: ${actionName}`,
      activation: this.system.core_system.activation,
      detail: this.system.core_system.active_effect,
      // The rest doesn't matter, give it some defaults
      cost: 0,
      frequency: "",
      init: "",
      trigger: "",
      terse: "",
      pilot: !1,
      mech: !0,
      tech_attack: !1,
      heat_cost: 0,
      synergy_locations: [],
      damage: [],
      range: []
    };
    await new CoreActiveFlow(this, { action, action_path: path }).begin();
  }
  async beginSkillFlow() {
    if (!this.is_skill()) {
      ui.notifications.error(`Item ${this.id} is not a skill!`);
      return;
    }
    await new StatRollFlow(this, { path: "system.curr_rank" }).begin();
  }
  async beginBondPowerFlow(powerIndex) {
    if (!this.is_bond()) {
      ui.notifications.error(`Item ${this.id} has no bond powers!`);
      return;
    }
    await new BondPowerFlow(this, { powerIndex }).begin();
  }
  async refreshPowers() {
    if (!this.is_bond()) {
      ui.notifications.error(`Item ${this.id} has no bond powers!`);
      return;
    }
    for (let i = 0; i < this.system.powers.length; i++) {
      const p = this.system.powers[i];
      p.uses && await this.update({ [`system.powers.${i}.uses.value`]: p.uses.max });
    }
  }
}, __name(_a12, "_LancerItem"), _a12);
_LancerItem.DEFAULT_ICON = "systems/lancer/assets/icons/generic_item.svg";
let LancerItem = _LancerItem;
const ITEM_TYPES = [
  EntryType.CORE_BONUS,
  EntryType.FRAME,
  EntryType.LICENSE,
  EntryType.MECH_WEAPON,
  EntryType.MECH_SYSTEM,
  EntryType.NPC_CLASS,
  EntryType.NPC_TEMPLATE,
  EntryType.NPC_FEATURE,
  EntryType.PILOT_ARMOR,
  EntryType.PILOT_WEAPON,
  EntryType.PILOT_GEAR,
  EntryType.RESERVE,
  EntryType.SKILL,
  EntryType.STATUS,
  EntryType.TALENT,
  EntryType.BOND,
  EntryType.WEAPON_MOD
], lp$b = LANCER.log_prefix, baselineStatuses = [
  {
    id: "resistance_burn",
    name: "lancer.statusIconsNames.resistance_burn",
    img: "systems/lancer/assets/icons/white/resistance_burn.svg"
  },
  {
    id: "resistance_energy",
    name: "lancer.statusIconsNames.resistance_energy",
    img: "systems/lancer/assets/icons/white/resistance_energy.svg"
  },
  {
    id: "resistance_explosive",
    name: "lancer.statusIconsNames.resistance_explosive",
    img: "systems/lancer/assets/icons/white/resistance_explosive.svg"
  },
  {
    id: "resistance_heat",
    name: "lancer.statusIconsNames.resistance_heat",
    img: "systems/lancer/assets/icons/white/resistance_heat.svg"
  },
  {
    id: "resistance_kinetic",
    name: "lancer.statusIconsNames.resistance_kinetic",
    img: "systems/lancer/assets/icons/white/resistance_kinetic.svg"
  },
  {
    id: "cover_hard",
    name: "lancer.statusIconsNames.cover_hard",
    img: "systems/lancer/assets/icons/white/cover_hard.svg"
  },
  {
    id: "cover_soft",
    name: "lancer.statusIconsNames.cover_soft",
    img: "systems/lancer/assets/icons/white/cover_soft.svg"
  }
], defaultStatuses = [
  {
    id: "immobilized",
    name: "lancer.statusIconsNames.immobilized",
    img: "systems/lancer/assets/icons/white/condition_immobilized.svg"
  },
  {
    id: "impaired",
    name: "lancer.statusIconsNames.impaired",
    img: "systems/lancer/assets/icons/white/condition_impaired.svg"
  },
  {
    id: "jammed",
    name: "lancer.statusIconsNames.jammed",
    img: "systems/lancer/assets/icons/white/condition_jammed.svg"
  },
  {
    id: "lockon",
    name: "lancer.statusIconsNames.lockon",
    img: "systems/lancer/assets/icons/white/condition_lockon.svg"
  },
  {
    id: "shredded",
    name: "lancer.statusIconsNames.shredded",
    img: "systems/lancer/assets/icons/white/condition_shredded.svg"
  },
  {
    id: "slow",
    name: "lancer.statusIconsNames.slow",
    img: "systems/lancer/assets/icons/white/condition_slow.svg"
  },
  {
    id: "stunned",
    name: "lancer.statusIconsNames.stunned",
    img: "systems/lancer/assets/icons/white/condition_stunned.svg"
  },
  {
    id: "dangerzone",
    name: "lancer.statusIconsNames.dangerzone",
    img: "systems/lancer/assets/icons/white/status_dangerzone.svg"
  },
  {
    id: "downandout",
    name: "lancer.statusIconsNames.downandout",
    img: "systems/lancer/assets/icons/white/status_downandout.svg"
  },
  {
    id: "engaged",
    name: "lancer.statusIconsNames.engaged",
    img: "systems/lancer/assets/icons/white/status_engaged.svg"
  },
  {
    id: "exposed",
    name: "lancer.statusIconsNames.exposed",
    img: "systems/lancer/assets/icons/white/status_exposed.svg"
  },
  {
    id: "hidden",
    name: "lancer.statusIconsNames.hidden",
    img: "systems/lancer/assets/icons/white/status_hidden.svg"
  },
  {
    id: "invisible",
    name: "lancer.statusIconsNames.invisible",
    img: "systems/lancer/assets/icons/white/status_invisible.svg"
  },
  {
    id: "intangible",
    name: "lancer.statusIconsNames.intangible",
    img: "systems/lancer/assets/icons/white/status_intangible.svg"
  },
  {
    id: "prone",
    name: "lancer.statusIconsNames.prone",
    img: "systems/lancer/assets/icons/white/status_prone.svg"
  },
  {
    id: "shutdown",
    name: "lancer.statusIconsNames.shutdown",
    img: "systems/lancer/assets/icons/white/status_shutdown.svg"
  },
  {
    id: "bolster",
    name: "lancer.statusIconsNames.bolster",
    img: "icons/svg/upgrade.svg"
  },
  {
    id: "npc_tier_1",
    name: "lancer.statusIconsNames.npc_tier_1",
    img: "systems/lancer/assets/icons/white/npc_tier_1.svg"
  },
  {
    id: "npc_tier_2",
    name: "lancer.statusIconsNames.npc_tier_2",
    img: "systems/lancer/assets/icons/white/npc_tier_2.svg"
  },
  {
    id: "npc_tier_3",
    name: "lancer.statusIconsNames.npc_tier_3",
    img: "systems/lancer/assets/icons/white/npc_tier_3.svg"
  },
  {
    id: "flying",
    name: "lancer.statusIconsNames.flying",
    img: "icons/svg/wing.svg"
  }
], cancerConditionsStatus = [
  {
    id: "bolster",
    name: "lancer.statusIconsNames.bolster",
    img: "icons/svg/upgrade.svg"
  },
  {
    id: "burn",
    name: "lancer.statusIconsNames.burn",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/burn.webp"
  },
  {
    id: "dangerzone",
    name: "lancer.statusIconsNames.dangerzone",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/dangerzone.webp"
  },
  {
    id: "downandout",
    name: "lancer.statusIconsNames.downandout",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/downandout.svg"
  },
  {
    id: "engaged",
    name: "lancer.statusIconsNames.engaged",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/engaged.webp"
  },
  {
    id: "exposed",
    name: "lancer.statusIconsNames.exposed",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/exposed.webp"
  },
  {
    id: "flying",
    name: "lancer.statusIconsNames.flying",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/flying.webp"
  },
  {
    id: "hidden",
    name: "lancer.statusIconsNames.hidden",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/hidden.webp"
  },
  {
    id: "immobilized",
    name: "lancer.statusIconsNames.immobilized",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/immobilized.svg"
  },
  {
    id: "impaired",
    name: "lancer.statusIconsNames.impaired",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/impaired.svg"
  },
  {
    id: "invisible",
    name: "lancer.statusIconsNames.invisible",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/invisible.svg"
  },
  {
    id: "jammed",
    name: "lancer.statusIconsNames.jammed",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/jammed.svg"
  },
  {
    id: "lockon",
    name: "lancer.statusIconsNames.lockon",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/lockon.svg"
  },
  {
    id: "prone",
    name: "lancer.statusIconsNames.prone",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/prone.webp"
  },
  {
    id: "shredded",
    name: "lancer.statusIconsNames.shredded",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/shredded.svg"
  },
  {
    id: "shutdown",
    name: "lancer.statusIconsNames.shutdown",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/shutdown.svg"
  },
  {
    id: "slow",
    name: "lancer.statusIconsNames.slow",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/slowed.svg"
  },
  {
    id: "stunned",
    name: "lancer.statusIconsNames.stunned",
    img: "systems/lancer/assets/icons/alt-status/cancercondstat/stunned.svg"
  }
], cancerNPCTemplates = [
  {
    id: "commander",
    name: "lancer.statusIconsNames.commander",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/commander.webp"
  },
  {
    id: "elite",
    name: "lancer.statusIconsNames.elite",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/elite.webp"
  },
  {
    id: "exotic",
    name: "lancer.statusIconsNames.exotic",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/exotic.webp"
  },
  {
    id: "grunt",
    name: "lancer.statusIconsNames.grunt",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/grunt.webp"
  },
  {
    id: "mercenary",
    name: "lancer.statusIconsNames.mercenary",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/mercenary.webp"
  },
  {
    id: "pirate",
    name: "lancer.statusIconsNames.pirate",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/pirate.webp"
  },
  {
    id: "rpv",
    name: "lancer.statusIconsNames.rpv",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/rpv.webp"
  },
  {
    id: "ship",
    name: "lancer.statusIconsNames.ship",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/ship.webp"
  },
  {
    id: "spacer",
    name: "lancer.statusIconsNames.spacer",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/spacer.webp"
  },
  {
    id: "ultra",
    name: "lancer.statusIconsNames.ultra",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/ultra.webp"
  },
  {
    id: "vehicle",
    name: "lancer.statusIconsNames.vehicle",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/vehicle.webp"
  },
  {
    id: "veteran",
    name: "lancer.statusIconsNames.veteran",
    img: "systems/lancer/assets/icons/alt-status/cancernpc/veteran.webp"
  }
], hayleyConditionsStatus = [
  {
    id: "bolster",
    name: "lancer.statusIconsNames.bolster",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/bolster.webp"
  },
  {
    id: "downandout",
    name: "lancer.statusIconsNames.downandout",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/downandout.webp"
  },
  {
    id: "exposed",
    name: "lancer.statusIconsNames.exposed",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/exposed.webp"
  },
  {
    id: "grappled",
    name: "lancer.statusIconsNames.grappled",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/grappled.webp"
  },
  {
    id: "hidden",
    name: "lancer.statusIconsNames.hidden",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/hidden.webp"
  },
  {
    id: "immobilized",
    name: "lancer.statusIconsNames.immobilized",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/immobilized.webp"
  },
  {
    id: "impaired",
    name: "lancer.statusIconsNames.impaired",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/impaired.webp"
  },
  {
    id: "invisible",
    name: "lancer.statusIconsNames.invisible",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/invisible.webp"
  },
  {
    id: "intangible",
    name: "lancer.statusIconsNames.intangible",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/intangible.webp"
  },
  {
    id: "jammed",
    name: "lancer.statusIconsNames.jammed",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/jammed.webp"
  },
  {
    id: "lockon",
    name: "lancer.statusIconsNames.lockon",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/lockon.webp"
  },
  {
    id: "prone",
    name: "lancer.statusIconsNames.prone",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/prone.webp"
  },
  {
    id: "shredded",
    name: "lancer.statusIconsNames.shredded",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/shredded.webp"
  },
  {
    id: "shutdown",
    name: "lancer.statusIconsNames.shutdown",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/shutdown.webp"
  },
  {
    id: "slow",
    name: "lancer.statusIconsNames.slow",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/slowed.webp"
  },
  {
    id: "stunned",
    name: "lancer.statusIconsNames.stunned",
    img: "systems/lancer/assets/icons/alt-status/hayleycondstat/stunned.webp"
  },
  {
    id: "flying",
    name: "lancer.statusIconsNames.flying",
    img: "systems/lancer/assets/icons/alt-status/hayleyutil/flying.webp"
  }
], hayleyPC = [
  {
    id: "aceso",
    name: "lancer.statusIconsNames.aceso",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/aceso.webp"
  },
  {
    id: "camus_razor",
    name: "lancer.statusIconsNames.camus_razor",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/camus-razor.webp"
  },
  {
    id: "chains_of_prometheus",
    name: "lancer.statusIconsNames.chains_of_prometheus",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/chains-of-prometheus.webp"
  },
  {
    id: "clamp_bomb",
    name: "lancer.statusIconsNames.clamp_bomb",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/clamp-bomb.webp"
  },
  {
    id: "dimensional_shackles",
    name: "lancer.statusIconsNames.dimensional_shackles",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/dimensional-shackles.webp"
  },
  {
    id: "dominions_breadth",
    name: "lancer.statusIconsNames.dominions_breadth",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/dominions-breadth.webp"
  },
  {
    id: "duat_gate",
    name: "lancer.statusIconsNames.duat_gate",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/duat-gate.webp"
  },
  {
    id: "excommunicate",
    name: "lancer.statusIconsNames.excommunicate",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/excommunicate.webp"
  },
  {
    id: "fade_cloak",
    name: "lancer.statusIconsNames.fade_cloak",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/fade-cloak.webp"
  },
  {
    id: "flaw_minus",
    name: "lancer.statusIconsNames.flaw_minus",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/flaw-minus.webp"
  },
  {
    id: "flaw_plus",
    name: "lancer.statusIconsNames.flaw_plus",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/flaw-plus.webp"
  },
  {
    id: "gravity",
    name: "lancer.statusIconsNames.gravity",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/gravity.webp"
  },
  {
    id: "haste",
    name: "lancer.statusIconsNames.haste",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/haste.webp"
  },
  {
    id: "hunter_lock",
    name: "lancer.statusIconsNames.hunter_lock",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/hunter-lock.webp"
  },
  {
    id: "hyperdense_armor",
    name: "lancer.statusIconsNames.hyperdense_armor",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/hyperdense-armor.webp"
  },
  {
    id: "imperial_eye",
    name: "lancer.statusIconsNames.imperial_eye",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/imperial-eye.webp"
  },
  {
    id: "kraul_grapple",
    name: "lancer.statusIconsNames.kraul_grapple",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/kraul-grapple.webp"
  },
  {
    id: "metahook",
    name: "lancer.statusIconsNames.metahook",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/metahook.webp"
  },
  {
    id: "molten_puncture",
    name: "lancer.statusIconsNames.molten_puncture",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/molten-puncture.webp"
  },
  {
    id: "retort_loop",
    name: "lancer.statusIconsNames.retort_loop",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/retort-loop.webp"
  },
  {
    id: "shahnameh",
    name: "lancer.statusIconsNames.shahnameh",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/shahnameh.webp"
  },
  {
    id: "stasis",
    name: "lancer.statusIconsNames.stasis",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/stasis.webp"
  },
  {
    id: "supercharger",
    name: "lancer.statusIconsNames.supercharger",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/supercharger.webp"
  },
  {
    id: "sympathetic_shield",
    name: "lancer.statusIconsNames.sympathetic_shield",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/sympathetic-shield.webp"
  },
  {
    id: "tachyon_shield",
    name: "lancer.statusIconsNames.tachyon_shield",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/tachyon-shield.webp"
  },
  {
    id: "terrify",
    name: "lancer.statusIconsNames.terrify",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/terrify.webp"
  },
  {
    id: "tracking_bug",
    name: "lancer.statusIconsNames.tracking_bug",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/tracking-bug.webp"
  },
  {
    id: "trueblack",
    name: "lancer.statusIconsNames.trueblack",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/trueblack.webp"
  },
  {
    id: "unravel",
    name: "lancer.statusIconsNames.unravel",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/unravel.webp"
  },
  {
    id: "viral_logic",
    name: "lancer.statusIconsNames.viral_logic",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/viral-logic.webp"
  },
  {
    id: "walk_of_kings",
    name: "lancer.statusIconsNames.walk_of_kings",
    img: "systems/lancer/assets/icons/alt-status/hayleypc/walk-of-kings.webp"
  }
], hayleyNPC = [
  {
    id: "abjure",
    name: "lancer.statusIconsNames.abjure",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/abjure.webp"
  },
  {
    id: "chain",
    name: "lancer.statusIconsNames.chain",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/chain.webp"
  },
  {
    id: "echo_edge",
    name: "lancer.statusIconsNames.echo_edge",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/echo-edge.webp"
  },
  {
    id: "dispersal_shield_1",
    name: "lancer.statusIconsNames.dispersal_shield_1",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/dispersal-shield-1.webp"
  },
  {
    id: "dispersal_shield_2",
    name: "lancer.statusIconsNames.dispersal_shield_2",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/dispersal-shield-2.webp"
  },
  {
    id: "dispersal_shield_3",
    name: "lancer.statusIconsNames.dispersal_shield_3",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/dispersal-shield-3.webp"
  },
  {
    id: "focus_down",
    name: "lancer.statusIconsNames.focus_down",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/focus-down.webp"
  },
  {
    id: "follower_count",
    name: "lancer.statusIconsNames.follower_count",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/follower-count.webp"
  },
  {
    id: "grind_maniple",
    name: "lancer.statusIconsNames.grind_maniple",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/grind-maniple.webp"
  },
  {
    id: "illusionary_subroutines",
    name: "lancer.statusIconsNames.illusionary_subroutines",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/illusionary-subroutines.webp"
  },
  {
    id: "investiture",
    name: "lancer.statusIconsNames.investiture",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/investiture.webp"
  },
  {
    id: "latch_drone",
    name: "lancer.statusIconsNames.latch_drone",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/latch-drone.webp"
  },
  {
    id: "marked",
    name: "lancer.statusIconsNames.marked",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/marked.webp"
  },
  {
    id: "pain_transference",
    name: "lancer.statusIconsNames.pain_transference",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/pain-transference.webp"
  },
  {
    id: "petrify",
    name: "lancer.statusIconsNames.petrify",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/petrify.webp"
  },
  {
    id: "sanctuary",
    name: "lancer.statusIconsNames.sanctuary",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/sanctuary.webp"
  },
  {
    id: "spike",
    name: "lancer.statusIconsNames.spike",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/spike.webp"
  },
  {
    id: "tear_down",
    name: "lancer.statusIconsNames.tear_down",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/tear-down.webp"
  },
  {
    id: "warp_sensors",
    name: "lancer.statusIconsNames.warp_sensors",
    img: "systems/lancer/assets/icons/alt-status/hayleynpc/warp-sensors.webp"
  }
], hayleyUtility = [
  {
    id: "blind",
    name: "lancer.statusIconsNames.blind",
    img: "systems/lancer/assets/icons/alt-status/hayleyutil/blind.webp"
  },
  {
    id: "burn",
    name: "lancer.statusIconsNames.burn",
    img: "systems/lancer/assets/icons/alt-status/hayleyutil/burn.webp"
  },
  {
    id: "overshield",
    name: "lancer.statusIconsNames.overshield",
    img: "systems/lancer/assets/icons/alt-status/hayleyutil/overshield.webp"
  },
  {
    id: "reactor_meltdown",
    name: "lancer.statusIconsNames.reactor_meltdown",
    img: "systems/lancer/assets/icons/alt-status/hayleyutil/reactor-meltdown.webp"
  }
], tommyConditionsStatus = [
  {
    id: "bolster",
    name: "lancer.statusIconsNames.bolster",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Bolstered.webp"
  },
  {
    id: "dangerzone",
    name: "lancer.statusIconsNames.dangerzone",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Danger Zone.webp"
  },
  {
    id: "destroyed",
    name: "lancer.statusIconsNames.destroyed",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Destroyed.webp"
  },
  {
    id: "downandout",
    name: "lancer.statusIconsNames.downandout",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Down and Out.webp"
  },
  {
    id: "engaged",
    name: "lancer.statusIconsNames.engaged",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Engaged.webp"
  },
  {
    id: "exposed",
    name: "lancer.statusIconsNames.exposed",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Exposed.webp"
  },
  {
    id: "grappled",
    name: "lancer.statusIconsNames.grappled",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Grappled.webp"
  },
  {
    id: "flying",
    name: "lancer.statusIconsNames.flying",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Flying.webp"
  },
  {
    id: "hidden",
    name: "lancer.statusIconsNames.hidden",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Hidden.webp"
  },
  {
    id: "hiddeninvis",
    name: "lancer.statusIconsNames.hiddeninvis",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Hidden and Invisible.webp"
  },
  {
    id: "immobilized",
    name: "lancer.statusIconsNames.immobilized",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Immobilized.webp"
  },
  {
    id: "impaired",
    name: "lancer.statusIconsNames.impaired",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Impaired.webp"
  },
  {
    id: "invisible",
    name: "lancer.statusIconsNames.invisible",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Invisible.webp"
  },
  {
    id: "intangible",
    name: "lancer.statusIconsNames.intangible",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Intangible.webp"
  },
  {
    id: "jammed",
    name: "lancer.statusIconsNames.jammed",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Jammed.webp"
  },
  {
    id: "lockon",
    name: "lancer.statusIconsNames.lockon",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Lockon.webp"
  },
  {
    id: "prone",
    name: "lancer.statusIconsNames.prone",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Prone.webp"
  },
  {
    id: "shredded",
    name: "lancer.statusIconsNames.shredded",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Shredded.webp"
  },
  {
    id: "shutdown",
    name: "lancer.statusIconsNames.shutdown",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Shut Down.webp"
  },
  {
    id: "slow",
    name: "lancer.statusIconsNames.slow",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Slowed.webp"
  },
  {
    id: "stunned",
    name: "lancer.statusIconsNames.stunned",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Stunned.webp"
  },
  {
    id: "npc_tier_1",
    name: "lancer.statusIconsNames.npc_tier_1",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Tier 1.webp"
  },
  {
    id: "npc_tier_2",
    name: "lancer.statusIconsNames.npc_tier_2",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Tier 2.webp"
  },
  {
    id: "npc_tier_3",
    name: "lancer.statusIconsNames.npc_tier_3",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Tier 3.webp"
  },
  {
    id: "tiercust",
    name: "lancer.statusIconsNames.tiercust",
    img: "systems/lancer/assets/icons/alt-status/tommystat/Tier Custom.webp"
  }
];
async function migrateLancerConditions() {
  var _a19;
  if (!((_a19 = game.modules.get("lancer-conditions")) != null && _a19.active))
    return;
  console.log(`${lp$b} Migrating settings from Lancer Condition Icons`);
  const iconSettings = {
    defaultConditionsStatus: game.settings.get("lancer-conditions", "keepStockIcons"),
    cancerConditionsStatus: game.settings.get("lancer-conditions", "cancerConditionsStatus"),
    cancerNPCTemplates: game.settings.get("lancer-conditions", "cancerNPCTemplates"),
    hayleyConditionsStatus: game.settings.get("lancer-conditions", "hayleyConditionsStatus"),
    hayleyPC: game.settings.get("lancer-conditions", "hayleyPC"),
    hayleyNPC: game.settings.get("lancer-conditions", "hayleyNPC"),
    hayleyUtility: game.settings.get("lancer-conditions", "hayleyUtility"),
    tommyConditionsStatus: game.settings.get("lancer-conditions", "tommyConditionsStatus")
  };
  game.settings.set(game.system.id, LANCER.setting_status_icons, iconSettings);
  const mods = game.settings.get("core", "moduleConfiguration");
  mods["lancer-conditions"] = !1, game.settings.set("core", "moduleConfiguration", mods);
  const text = `
  <p>The icons and functionality from Lancer Condition Icons has been integrated with the system,
  and your settings have been migrated. Lancer Condition Icons will now be disabled, and you can
  feel free to uninstall it if no other worlds are using it.</p>
  <p>The page must now be refreshed for the module change to take effect.</p>`;
  new Dialog(
    {
      title: "Lancer Condition Icons is Integrated",
      content: text,
      buttons: {
        ok: { label: "Refresh", callback: () => window.location.reload() }
      },
      default: "No"
    },
    {
      width: 350
    }
  ).render(!0);
}
__name(migrateLancerConditions, "migrateLancerConditions");
async function fromLidMany(lids, { source = "all" } = {}) {
  var _a19, _b;
  const search_world = source !== "compendium", search_compendium = source !== "world";
  let docs = [];
  if (search_world && docs.push(
    ...(_a19 = game.items) == null ? void 0 : _a19.filter((i) => lids.includes(i.system.lid)),
    ...(_b = game.actors) == null ? void 0 : _b.filter((a) => lids.includes(a.system.lid))
  ), search_compendium) {
    const databases = game.packs.filter((p) => ["Actor", "Item"].includes(p.documentName));
    await Promise.all(databases.map((d) => d.getIndex())), docs.push(...(await Promise.all(databases.map((d) => d.getDocuments({ system: { lid__in: lids } })))).flat());
  }
  return docs;
}
__name(fromLidMany, "fromLidMany");
async function fromLid(lid, { source = "all" } = {}) {
  return (await fromLidMany([lid], { source })).shift();
}
__name(fromLid, "fromLid");
function fromLidSync(lid, { source = "all" } = {}) {
  var _a19, _b;
  const search_world = source !== "compendium", search_compendium = source !== "world";
  let document2;
  return search_world && (document2 = ((_a19 = game.items) == null ? void 0 : _a19.find((i) => i.system.lid === lid)) ?? ((_b = game.actors) == null ? void 0 : _b.find((a) => a.system.lid === lid))), !document2 && search_compendium && (document2 = game.packs.filter((p) => ["Actor", "Item"].includes(p.documentName)).map((db) => {
    const doc = db.index.find((i) => {
      var _a20;
      return ((_a20 = i.system) == null ? void 0 : _a20.lid) === lid;
    });
    return doc && (doc.pack = db.collection), doc;
  }).find((e) => e !== void 0)), document2;
}
__name(fromLidSync, "fromLidSync");
async function maybeImportActor(compendiumActor, owner) {
  var _a19, _b;
  if ((_a19 = game.user) != null && _a19.can("ACTOR_CREATE"))
    return fulfillImportActor(compendiumActor, owner);
  let content = `<button class="chat-button self-destruct"
      data-action="importActor"
      data-import-id="${compendiumActor.uuid}"
      data-target-id="${owner.uuid}"
    >
      IMPORT ${compendiumActor.name} FOR ${owner.name}?
    </button>`;
  ChatMessage.create({
    blind: !0,
    whisper: (_b = game.users) == null ? void 0 : _b.filter((u) => u.isGM).map((u) => u.id),
    content
  });
}
__name(maybeImportActor, "maybeImportActor");
async function fulfillImportActor(compDeployableUuid, forActorUuid) {
  var _a19, _b;
  if (!((_a19 = game.user) != null && _a19.can("ACTOR_CREATE")))
    throw new Error("You do not have permissions to import an actor!");
  const compDeployable = await LancerActor.fromUuid(compDeployableUuid), forActor = await LancerActor.fromUuid(forActorUuid);
  if (!compDeployable || !forActor)
    throw new Error("Invalid actor(s) provided for import!");
  const actorData = compDeployable.toObject();
  return actorData.system.owner = forActor.uuid, actorData.name = deployableName(actorData.name, forActor), actorData.folder = (_b = forActor.folder) == null ? void 0 : _b.id, actorData.ownership = foundry.utils.duplicate(forActor.ownership), LancerActor.create(actorData);
}
__name(fulfillImportActor, "fulfillImportActor");
function deployableName(baseName, owner) {
  var _a19;
  if (!owner)
    return baseName;
  let ownerName = owner.name;
  return owner.is_pilot() ? ownerName = owner.system.callsign || owner.name : owner.is_mech() && ((_a19 = owner.system.pilot) == null ? void 0 : _a19.status) == "resolved" && (ownerName = owner.system.pilot.value.system.callsign || owner.system.pilot.value.name), `${baseName} [${ownerName}]`;
}
__name(deployableName, "deployableName");
const PACK_SCOPE = "world";
async function findLicenseFor(item, inActor) {
  var _a19;
  let licenseKey = item.system.license;
  if (!licenseKey)
    return null;
  if (inActor) {
    let pilot = null;
    inActor.is_pilot() && (pilot = inActor), inActor.is_mech() && ((_a19 = inActor.system.pilot) == null ? void 0 : _a19.status) == "resolved" && (pilot = inActor.system.pilot.value), pilot && (pilot.items.filter((i) => i.is_license()).find((lic) => lic.system.key === licenseKey) || // Fall back to matching the license name
    pilot.items.filter((i) => i.is_license()).find((lic) => lic.name === licenseKey));
  }
  const pack = game.packs.get(get_pack_id(EntryType.LICENSE));
  if (!pack)
    return console.error("License pack not found"), null;
  await pack.getIndex();
  const entry = pack.index.find((e) => {
    var _a20;
    return ((_a20 = e.system) == null ? void 0 : _a20.key) == licenseKey;
  }) || // Fall back to matching the license name
  pack.index.find((e) => e.name == licenseKey);
  return entry ? pack.getDocument(entry._id) : (console.error(`License not found: ${licenseKey}`), null);
}
__name(findLicenseFor, "findLicenseFor");
function get_pack_id(et) {
  let id;
  switch (et) {
    case EntryType.FRAME:
    case EntryType.MECH_SYSTEM:
    case EntryType.MECH_WEAPON:
    case EntryType.WEAPON_MOD:
      id = "mech-items";
      break;
    case EntryType.BOND:
    case EntryType.CORE_BONUS:
    case EntryType.LICENSE:
    case EntryType.ORGANIZATION:
    case EntryType.PILOT_ARMOR:
    case EntryType.PILOT_GEAR:
    case EntryType.PILOT_WEAPON:
    case EntryType.RESERVE:
    case EntryType.SKILL:
    case EntryType.TALENT:
      id = "pilot-items";
      break;
    case EntryType.NPC_CLASS:
    case EntryType.NPC_FEATURE:
    case EntryType.NPC_TEMPLATE:
      id = "npc-items";
      break;
    case EntryType.DEPLOYABLE:
    case EntryType.MECH:
    case EntryType.PILOT:
      id = "player-actors";
      break;
    case EntryType.NPC:
    case EntryType.STATUS:
    default:
      id = `${et}-${is_actor_type(et) ? "actors" : "items"}`;
      break;
  }
  return `${PACK_SCOPE}.${id}`;
}
__name(get_pack_id, "get_pack_id");
async function get_pack(type2) {
  const id = get_pack_id(type2);
  let pack = game.packs.get(id);
  if (pack)
    return pack;
  {
    const entity_type = is_actor_type(type2) ? "Actor" : "Item", basename = id.split(".")[1], metadata = {
      name: basename,
      type: entity_type,
      label: `lancer.compendium.${basename}`,
      // @ts-expect-error Banner data not in types
      banner: `./systems/lancer/assets/banners/${basename}.svg`,
      system: "lancer",
      // sort: PackSort[basename],
      package: "world",
      path: `./packs/${basename}`
    };
    return CompendiumCollection.createCompendium(metadata);
  }
}
__name(get_pack, "get_pack");
async function insinuate(items, to) {
  let oldItems = [], newItems = [];
  for (let item of items)
    if (item.parent == to)
      oldItems.push(item);
    else {
      newItems.push(item.toObject());
      let integrated = [];
      item.is_frame() ? integrated = item.system.core_system.integrated : (item.is_mech_system() || item.is_mech_weapon()) && (integrated = item.system.integrated);
      for (let i of integrated) {
        let found = await fromLid(i);
        found && newItems.push(found.toObject());
      }
    }
  let actualNewItems = await to.createEmbeddedDocuments("Item", newItems);
  for (let item of actualNewItems)
    await importDeployablesFor(item, to);
  return [...oldItems, ...actualNewItems];
}
__name(insinuate, "insinuate");
async function importDeployablesFor(item, owner) {
  let existing = lookupOwnedDeployables(owner), existingLIDs = Object.keys(existing), requiredLIDs = [];
  requiredLIDs.push(...item.system.deployables ?? []), item.is_frame() && requiredLIDs.push(...item.system.core_system.deployables);
  const missingLIDs = requiredLIDs.filter((req) => !existingLIDs.includes(req));
  if (!missingLIDs.length)
    return;
  let imports = await fromLidMany(missingLIDs, { source: "compendium" });
  for (let i of imports)
    i instanceof LancerActor && await maybeImportActor(i, owner);
}
__name(importDeployablesFor, "importDeployablesFor");
const lp$a = LANCER.log_prefix, _LancerActiveEffect = class _LancerActiveEffect extends ActiveEffect {
  /**
   * Determine whether this Active Effect is suppressed or not.
   */
  get isSuppressed() {
    return !this.affectsUs();
  }
  /**
   * Determine whether this Active Effect is present only to be passed to descendants
   */
  affectsUs() {
    let tf = this.flags[game.system.id];
    if (!(tf != null && tf.target_type))
      return !0;
    let parent = null;
    if (this.parent instanceof LancerActor ? parent = this.parent : this.parent instanceof LancerItem && (parent = this.parent.parent), !(parent instanceof LancerActor))
      return !1;
    switch (tf.target_type) {
      case EntryType.PILOT:
        return parent.is_pilot();
      case EntryType.MECH:
        return parent.is_mech();
      case EntryType.DEPLOYABLE:
        return parent.is_deployable();
      case EntryType.NPC:
        return parent.is_npc();
      case "mech_and_npc":
        return parent.is_mech() || parent.is_npc();
      case "only_deployable":
        return parent.is_deployable() && parent.system.type == DeployableType.Deployable;
      case "only_drone":
        return parent.is_deployable() && parent.system.type == DeployableType.Drone;
      default:
        return !1;
    }
  }
  /* --------------------------------------------- */
  /**
   * Prepare the data structure for Active Effects which are currently applied to an Actor or Item.
   */
  static prepareActiveEffectCategories(actor) {
    var _a19;
    let passives = {
      type: "passive",
      label: game.i18n.localize("lancer.effect.categories.passive"),
      effects: []
    }, inherited = {
      type: "inherited",
      label: game.i18n.localize("lancer.effect.categories.inherited"),
      effects: []
    }, disabled = {
      type: "disabled",
      label: game.i18n.localize("lancer.effect.categories.disabled"),
      effects: []
    }, passthrough = {
      type: "passthrough",
      label: game.i18n.localize("lancer.effect.categories.passthrough"),
      effects: []
    }, index2 = 0;
    for (let e of actor.allApplicableEffects())
      e.affectsUs() ? e.disabled ? disabled.effects.push([index2, e]) : (_a19 = e.flags[game.system.id]) != null && _a19.deep_origin ? inherited.effects.push([index2, e]) : passives.effects.push([index2, e]) : passthrough.effects.push([index2, e]), index2++;
    return [passives, inherited, disabled, passthrough];
  }
  // Fully update the status icons in CONFIG.statusEffects.
  // This is not used on page load, since the two methods need to be run in different hooks.
  // Any time after that, though, both should be run together and in this order.
  static async updateIcons() {
    await this.initConfig(), await this.populateFromCompendiumItems(), await this.populateFromWorldItems(), Hooks.callAll("lancer.statusesReady");
  }
  // Populate config with our static/compendium statuses instead of the builtin ones
  static async initConfig() {
    const statusIconConfig = game.settings.get(game.system.id, LANCER.setting_status_icons);
    game.ready && !Object.keys(statusIconConfig).some((k) => statusIconConfig[k]) && (statusIconConfig.defaultConditionsStatus = !0, await game.settings.set(game.system.id, LANCER.setting_status_icons, statusIconConfig));
    function _backfillIcons(statuses, newStatuses) {
      for (let icon of newStatuses)
        statuses.find((s) => s.id === icon.id) || statuses.push({
          id: icon.id,
          name: icon.name,
          img: icon.img
        });
      return statuses;
    }
    __name(_backfillIcons, "_backfillIcons");
    let configStatuses = [];
    statusIconConfig.defaultConditionsStatus && (configStatuses = _backfillIcons(configStatuses, defaultStatuses)), statusIconConfig.cancerConditionsStatus && (configStatuses = _backfillIcons(configStatuses, cancerConditionsStatus)), statusIconConfig.hayleyConditionsStatus && (configStatuses = _backfillIcons(configStatuses, hayleyConditionsStatus)), statusIconConfig.tommyConditionsStatus && (configStatuses = _backfillIcons(configStatuses, tommyConditionsStatus)), configStatuses = _backfillIcons(configStatuses, baselineStatuses), statusIconConfig.cancerNPCTemplates && (configStatuses = _backfillIcons(configStatuses, cancerNPCTemplates)), statusIconConfig.hayleyPC && (configStatuses = _backfillIcons(configStatuses, hayleyPC)), statusIconConfig.hayleyNPC && (configStatuses = _backfillIcons(configStatuses, hayleyNPC)), statusIconConfig.hayleyUtility && (configStatuses = _backfillIcons(configStatuses, hayleyUtility)), console.log(`${lp$a} ${configStatuses.length} status icons configured from settings`), CONFIG.statusEffects = configStatuses, CONFIG.specialStatusEffects.DEFEATED = "downandout", CONFIG.specialStatusEffects.INVISIBLE = null, CONFIG.specialStatusEffects.BLIND = null, Hooks.callAll("lancer.statusInitComplete");
  }
  /**
   * Load statuses from the compendia and world items and backfill into CONFIG.statusEffects.
   */
  static async populateFromWorldItems() {
    var _a19;
    const originalLength = CONFIG.statusEffects.length, worldStatuses = (_a19 = game.items) == null ? void 0 : _a19.filter((i) => i.type === EntryType.STATUS);
    this._populateFromItems(worldStatuses, !0), console.log(
      `${lp$a} ${CONFIG.statusEffects.length - originalLength} status icons loaded from world items, total: ${CONFIG.statusEffects.length}`
    );
  }
  static async populateFromCompendiumItems() {
    const originalLength = CONFIG.statusEffects.length, pack = game.packs.get(get_pack_id(EntryType.STATUS)), packStatuses = await (pack == null ? void 0 : pack.getDocuments({ type: EntryType.STATUS })) || [];
    this._populateFromItems(packStatuses, !1), console.log(
      `${lp$a} ${CONFIG.statusEffects.length - originalLength} status icons loaded from compendiums, total: ${CONFIG.statusEffects.length}`
    );
  }
  static async _populateFromItems(items = [], overwrite = !1) {
    if (items.length)
      for (const status of items) {
        if (!status.is_status() || !status.system.lid || !status.img)
          continue;
        const existingStatus = CONFIG.statusEffects.find((s) => s.id === status.system.lid);
        if (existingStatus) {
          if (existingStatus.img = existingStatus.img || existingStatus.icon, existingStatus.img = overwrite ? status.img || existingStatus.img : existingStatus.img || status.img, existingStatus.name = overwrite ? status.name || existingStatus.name : existingStatus.name || status.name, status.system.effects && (existingStatus.description = status.system.effects), overwrite && [...status.effects].length > 0) {
            const changes = existingStatus.changes || [];
            status.effects.forEach((e) => {
              e.changes && e.changes.length > 0 && changes.push(...e.changes);
            }), existingStatus.changes = changes;
          } else if (!existingStatus.changes && status.effects.size) {
            const changes = [...status.effects].reduce((all, e) => all.concat(e.changes || []), []);
            existingStatus.changes = changes;
          }
        } else {
          const changes = [...status.effects].reduce((all, e) => all.concat(e.changes || []), []);
          CONFIG.statusEffects.push({
            id: status.system.lid,
            name: status.name,
            // @ts-expect-error v12 property renamed
            img: status.img,
            description: status.system.effects,
            changes
          });
        }
      }
  }
};
__name(_LancerActiveEffect, "LancerActiveEffect");
let LancerActiveEffect = _LancerActiveEffect;
const AE_MODE_SET_JSON = 11, AE_MODE_APPEND_JSON = 12, _json_cache = {};
Hooks.on(
  "applyActiveEffect",
  function(actor, change, _current, _delta, _changes) {
    if (change.mode == AE_MODE_SET_JSON || change.mode == AE_MODE_APPEND_JSON)
      try {
        let parsed_delta = _json_cache[change.value] ?? JSON.parse(change.value);
        _json_cache[change.value] = parsed_delta, change.mode == AE_MODE_SET_JSON ? foundry.utils.setProperty(actor, change.key, parsed_delta) : change.mode == AE_MODE_APPEND_JSON && foundry.utils.getProperty(actor, change.key).push(parsed_delta);
      } catch (e) {
        console.warn(e), console.warn(`JSON effect parse failed, ${change.value}`);
      }
  }
);
const _EffectHelper = class _EffectHelper {
  // Track our parent actor
  constructor(actor) {
    this.actor = actor, this._passdownEffectTracker = new ChangeWatchHelper(), this.propagateEffects = foundry.utils.debounce((force) => this.propagateEffectsInner(force), 500);
  }
  // Set the expected effects from a given uuid
  // Kick off an update if update == true
  // If render, then the update will require redraw.
  async setEphemeralEffects(source_uuid, data2, visible = !0) {
    let es = {
      from_uuid: source_uuid,
      data: data2,
      visible
    };
    return this.actor.update(
      {
        "system.inherited_effects": es
      },
      {
        render: visible
      }
    );
  }
  // Clear the expected effects for a given uuid
  // Kick off an update if update == true
  async clearEphemeralEffects() {
    let curr = this.actor.system.inherited_effects;
    curr && await this.actor.update(
      {
        "system.-=inherited_effects": null
      },
      {
        render: curr.visible
      }
    );
  }
  // Generate activeffects based on our system.ephemeral_effect state
  inheritedEffects() {
    let results = [], inherited_effects = this.actor.system.inherited_effects;
    if (inherited_effects)
      for (let effect3 of inherited_effects.data)
        results.push(new LancerActiveEffect(effect3, { parent: this.actor }));
    return results;
  }
  /**
   * Collect from our current effects (and pilot/mech innate effects) any that should be passed down to descendants.
   * as well as from any innate features (pilot grit, mech save target, etc)
   */
  collectPassdownEffects() {
    if (this.actor.is_deployable())
      return [];
    let effects = [...this.actor.allApplicableEffects()].map((e) => e.toObject());
    return effects = effects.filter((e) => {
      var _a19;
      switch ((_a19 = e.flags[game.system.id]) == null ? void 0 : _a19.target_type) {
        case EntryType.PILOT:
          return !1;
        case EntryType.MECH:
          return this.actor.is_pilot();
        case EntryType.NPC:
          return !1;
        case EntryType.DEPLOYABLE:
        case "only_deployable":
        case "only_drone":
          return !0;
        case "mech_and_npc":
          return this.actor.is_pilot();
        default:
          return !1;
      }
    }), effects;
  }
  async propagateEffectsInner(force) {
    var _a19, _b, _c;
    if (!(force || this._passdownEffectTracker.isDirty))
      return;
    const propagateTo = /* @__PURE__ */ __name(async (target) => {
      console.debug(`Actor ${this.actor.name} propagating effects to ${target.name}`);
      let changes = foundry.utils.duplicate(this._passdownEffectTracker.curr_value);
      changes.forEach((c) => {
        var _a20, _b2;
        (_a20 = c.flags)[_b2 = game.system.id] ?? (_a20[_b2] = {}), c.flags[game.system.id].deep_origin = c.origin, c.origin = this.actor.uuid;
      }), await target.effectHelper.setEphemeralEffects(this.actor.uuid, changes);
    }, "propagateTo");
    if (this.actor.is_pilot())
      ((_a19 = this.actor.system.active_mech) == null ? void 0 : _a19.status) == "resolved" && ((_b = this.actor.system.active_mech.value.system.pilot) == null ? void 0 : _b.id) == this.actor.uuid && await propagateTo(this.actor.system.active_mech.value);
    else if (this.actor.is_mech()) {
      let pilot = ((_c = this.actor.system.pilot) == null ? void 0 : _c.value) ?? null, ownedDeployables = game.actors.filter(
        (a) => a.is_deployable() && a.system.owner !== null && (a.system.owner.value == this.actor || a.system.owner.value == pilot)
      );
      for (let dep of ownedDeployables)
        await propagateTo(dep);
    } else if (this.actor.is_npc()) {
      let ownedDeployables = game.actors.filter((a) => {
        var _a20;
        return a.is_deployable() && ((_a20 = a.system.owner) == null ? void 0 : _a20.value) == this.actor;
      });
      for (let dep of ownedDeployables)
        await propagateTo(dep);
    }
  }
  // ########### Miscellaneous effect helper stuff that also lives here just to be in the same "namespace" so to speak #########
  /**
   * Wipes all Statuses and (non ephemeral) ActiveEffects from the Actor.
   *
   * This isn't really in the effectors purview per-say, but it tidies things up a bit
   */
  async removeAllStatuses() {
    let effects_to_delete = this.actor.effects.filter((e) => e.sourceName === "None");
    await this.actor._safeDeleteDescendant("ActiveEffect", effects_to_delete);
    let items_to_delete = this.actor.items.filter((i) => i.is_status());
    await this.actor._safeDeleteDescendant("Item", items_to_delete);
  }
  /**
   * Locates an ActiveEffect on the Actor by name and removes it if present.
   * @param effect String name of the ActiveEffect to remove.
   */
  async removeActiveEffect(effect3) {
    const target_effect = this.findEffect(effect3);
    target_effect == null || target_effect.delete();
  }
  /**
   * Locates ActiveEffects on the Actor by names provided and removes them if present.
   * @param effects Array of String names of the ActiveEffects to remove.
   */
  async removeActiveEffects(effects) {
    const target_effects = effects.map((e) => this.findEffect(e));
    !target_effects || !target_effects.some((e) => !!e) || this.actor.deleteEmbeddedDocuments(
      "ActiveEffect",
      target_effects.map((e) => (e == null ? void 0 : e.id) || "")
    );
  }
  findEffect(effect3) {
    return this.actor.effects.find((eff) => eff.statuses.some((name2) => name2.includes(effect3)));
  }
};
__name(_EffectHelper, "EffectHelper");
let EffectHelper = _EffectHelper;
const _LoadoutHelper = class _LoadoutHelper {
  constructor(actor) {
    this.actor = actor;
  }
  // Do the specified junk to an item. Returns an object suitable for updateEmbeddedDocuments
  refresh(item, opts) {
    let changes = { _id: item.id, name: item.name };
    opts.repair && item.system.destroyed === !0 && (changes["system.destroyed"] = !1), opts.reload && item.system.loaded === !1 && (changes["system.loaded"] = !0);
    const uses = item.system.uses;
    return opts.refill && uses !== void 0 && uses.val !== uses.max && (changes["system.uses"] = item.system.uses.max), Object.keys(changes).some((k) => k.startsWith("system")) ? changes : null;
  }
  // List the all equipped loadout items on this actor
  // For mechs this is everthing in system.loadout, IE: Mech weapons, Mech Systems, Frame
  listLoadout() {
    var _a19, _b, _c;
    let result = [], it = this.actor.itemTypes;
    if (this.actor.is_mech()) {
      ((_a19 = this.actor.system.loadout.frame) == null ? void 0 : _a19.status) == "resolved" && result.push(this.actor.system.loadout.frame.value);
      for (let mount of this.actor.system.loadout.weapon_mounts)
        for (let slot of mount.slots)
          ((_b = slot.weapon) == null ? void 0 : _b.status) == "resolved" && result.push(slot.weapon.value), ((_c = slot.mod) == null ? void 0 : _c.status) == "resolved" && result.push(slot.mod.value);
      result.push(...this.actor.system.loadout.systems.filter((x) => x == null ? void 0 : x.value).map((x) => x.value));
    } else
      this.actor.is_npc() ? (this.actor.system.class && result.push(this.actor.system.class), result.push(...it.npc_class, ...it.npc_template, ...it.npc_feature)) : this.actor.is_pilot() && result.push(
        ...it.pilot_armor,
        ...it.pilot_gear,
        ...it.pilot_weapon,
        ...it.talent,
        ...it.core_bonus,
        ...it.reserve
      );
    return result;
  }
  // Fully repair actor
  // Even pilots can be fully repaired
  async fullRepair() {
    var _a19, _b;
    await this.actor.effectHelper.removeAllStatuses(), await this.deleteUnequippedItems();
    let changes = {
      "system.hp.value": this.actor.system.hp.max,
      "system.burn": 0,
      "system.overshield.value": 0
    };
    (this.actor.is_mech() || this.actor.is_npc() || this.actor.is_deployable()) && (changes["system.heat.value"] = 0), (this.actor.is_mech() || this.actor.is_npc()) && (changes["system.structure.value"] = this.actor.system.structure.max, changes["system.stress.value"] = this.actor.system.stress.max), this.actor.is_mech() && (changes["system.core_energy"] = 1, changes["system.core_active"] = !1, changes["system.overcharge"] = 0, changes["system.repairs.value"] = this.actor.system.repairs.max, changes["system.meltdown_timer"] = null), this.actor.is_pilot() && await ((_b = (_a19 = this.actor.system.active_mech) == null ? void 0 : _a19.value) == null ? void 0 : _b.loadoutHelper.fullRepair()), this.actor.is_deployable() || await this.restoreAllItems(), await this.actor.update(changes);
  }
  /**
   * Find all limited systems and set them to their max/repaired/ideal state
   */
  async restoreAllItems() {
    let fixes = this.listLoadout().map(
      (i) => this.refresh(i, {
        reload: !0,
        repair: !0,
        refill: !0
      })
    ).filter((x) => !!x);
    return this.actor.updateEmbeddedDocuments("Item", fixes);
  }
  /**
   * Find all owned items and set them to be not destroyed
   */
  async repairableItems() {
    return Promise.all(
      this.listLoadout().map((i) => this.refresh(i, { repair: !0 })).filter((x) => !!x)
    );
  }
  /**
   * Find all owned weapons and (generate the changes necessary to) reload them
   */
  reloadableItems() {
    return this.listLoadout().map((i) => this.refresh(i, { reload: !0 })).filter((x) => !!x);
  }
  /**
   * Check our items for any that aren't equipped, and delete them
   */
  async deleteUnequippedItems() {
    let deletables = [];
    for (let item of this.actor.items.contents)
      item.id && !item.isEquipped() && deletables.push(item);
    deletables.length && await this.actor._safeDeleteDescendant("Item", deletables);
  }
  /**
   * Check our loadout as applicable to cleanup any unresolved references
   */
  async cleanupUnresolvedReferences() {
    var _a19, _b, _c;
    let killedIds = [];
    if (this.actor.is_pilot()) {
      let cleanupLoadout = foundry.utils.duplicate(this.actor.system._source.loadout), currLoadout = this.actor.system.loadout;
      cleanupLoadout.armor = cleanupLoadout.armor.map((_, index2) => {
        var _a20;
        return ((_a20 = currLoadout.armor[index2]) == null ? void 0 : _a20.status) == "missing" ? (killedIds.push(cleanupLoadout.armor[index2]), null) : cleanupLoadout.armor[index2];
      }), cleanupLoadout.gear = cleanupLoadout.gear.map((_, index2) => {
        var _a20;
        return ((_a20 = currLoadout.gear[index2]) == null ? void 0 : _a20.status) == "missing" ? (killedIds.push(cleanupLoadout.gear[index2]), null) : cleanupLoadout.gear[index2];
      }), cleanupLoadout.weapons = cleanupLoadout.weapons.map((_, index2) => {
        var _a20;
        return ((_a20 = currLoadout.weapons[index2]) == null ? void 0 : _a20.status) == "missing" ? (killedIds.push(cleanupLoadout.weapons[index2]), null) : cleanupLoadout.weapons[index2];
      }), killedIds.length && (console.log(`Cleaning up unresolved ids ${killedIds.join(", ")}...`), await this.actor.update({ system: { loadout: cleanupLoadout } }));
    } else if (this.actor.is_mech()) {
      let cleanupLoadout = foundry.utils.duplicate(this.actor.system._source.loadout), currLoadout = this.actor.system.loadout;
      ((_a19 = currLoadout.frame) == null ? void 0 : _a19.status) == "missing" && (killedIds.push(currLoadout.frame.id), cleanupLoadout.frame = null), cleanupLoadout.systems = cleanupLoadout.systems.filter((_, index2) => {
        var _a20;
        return ((_a20 = currLoadout.systems[index2]) == null ? void 0 : _a20.status) == "missing" ? (killedIds.push(currLoadout.systems[index2].id), !1) : !0;
      });
      for (let i = 0; i < currLoadout.weapon_mounts.length; i++) {
        let mount = currLoadout.weapon_mounts[i];
        for (let j = 0; j < mount.slots.length; j++) {
          let slot = mount.slots[j];
          ((_b = slot.mod) == null ? void 0 : _b.status) == "missing" && (cleanupLoadout.weapon_mounts[i].slots[j].mod = null, killedIds.push(slot.mod.id)), ((_c = slot.weapon) == null ? void 0 : _c.status) == "missing" && (cleanupLoadout.weapon_mounts[i].slots[j].weapon = null, killedIds.push(slot.weapon.id));
        }
      }
      killedIds.length && (console.log(`Cleaning up unresolved ids ${killedIds.join(", ")}...`), await this.actor.update({ system: { loadout: cleanupLoadout } }));
    }
  }
  /**
   * Yields a simple error message on a misconfigured mount, or null if no issues detected.
   * @param mount Specific mount to validate
   */
  validateMount(mount) {
    var _a19, _b;
    if (this.actor.is_mech()) {
      let hasBracing = this.actor.system.loadout.weapon_mounts.some((m) => m.bracing), hasSuper = !1, hasFlexMain = !1, weaponCount = 0, result = "";
      for (let slot of mount.slots) {
        if (((_a19 = slot.weapon) == null ? void 0 : _a19.status) != "resolved")
          continue;
        weaponCount += 1;
        const weaponSizeScore = {
          [WeaponSize.Aux]: 1,
          [WeaponSize.Main]: 2,
          [WeaponSize.Heavy]: 3,
          [WeaponSize.Superheavy]: 3
        }[slot.weapon.value.system.size] ?? 4, fittingSizeScore = {
          [FittingSize.Auxiliary]: 1,
          [FittingSize.Main]: 2,
          [FittingSize.Flex]: 2,
          [FittingSize.Heavy]: 3,
          [FittingSize.Superheavy]: 3,
          [FittingSize.Integrated]: 4
        }[slot.size] ?? 0;
        if (weaponSizeScore > fittingSizeScore) {
          result += `Weapon of size ${slot.weapon.value.system.size} cannot fit on fitting of size ${slot.size}. `;
          continue;
        }
        if (slot.size == FittingSize.Flex && weaponSizeScore > 1 && (hasFlexMain = !0), slot.weapon.value.system.size == WeaponSize.Superheavy) {
          const frame = (_b = this.actor.system.loadout.frame) == null ? void 0 : _b.value;
          (!frame || !frame.system.core_system.integrated.includes(slot.weapon.value.system.lid)) && (hasSuper = !0);
        }
      }
      return hasFlexMain && weaponCount > 1 && (result += "Flex mounts can either have two Auxillary or one Main weapon."), hasSuper && !hasBracing && (result += 'Superheavy weapons require a mount to be set as "Bracing".'), result || null;
    } else
      throw new Error(
        `${this.actor.type} actors have no mounts to validate. Call this method on the actor you're trying to check against!`
      );
  }
  /**
   * Reset the mounts to the default for the frame + core bonus configuration
   * Will automatically equip the frames integrated mount
   * @returns
   */
  async resetMounts() {
    var _a19, _b;
    if (!this.actor.is_mech())
      return;
    let newMounts = [], frame = (_a19 = this.actor.system.loadout.frame) == null ? void 0 : _a19.value;
    if (frame) {
      const gen_mount = /* @__PURE__ */ __name((mt) => ({
        bracing: !1,
        slots: fittingsForMount(mt).map((f) => ({
          weapon: null,
          mod: null,
          size: f
        })),
        type: mt
      }), "gen_mount");
      let baseMounts = frame.system.mounts, pilot = (_b = this.actor.system.pilot) == null ? void 0 : _b.value;
      const get_cb = /* @__PURE__ */ __name((lid) => pilot == null ? void 0 : pilot.itemTypes.core_bonus.find((cb) => cb.system.lid == lid), "get_cb");
      let retrofitting = get_cb("cb_mount_retrofitting"), improved_armament = get_cb("cb_improved_armament"), integrated_weapon = get_cb("cb_integrated_weapon");
      if (baseMounts.length < 3 && improved_armament && baseMounts.push(MountType.Main), retrofitting) {
        for (let mt of [MountType.Aux, MountType.AuxAux, MountType.Main, MountType.Flex])
          if (baseMounts.findSplice((x) => x == mt, MountType.MainAux))
            break;
      }
      integrated_weapon && (baseMounts = [MountType.Integrated, ...baseMounts]);
      for (let integrated_lid of frame.system.core_system.integrated) {
        let corr_item = this.actor.items.find((x) => x.system.lid == integrated_lid);
        corr_item && corr_item.is_mech_weapon() && newMounts.push({
          bracing: !1,
          slots: [
            {
              mod: null,
              size: FittingSize.Integrated,
              weapon: corr_item.id
            }
          ],
          type: MountType.Integrated
        });
      }
      for (let mt of baseMounts)
        newMounts.push(gen_mount(mt));
    }
    this.actor.update({ "system.loadout.weapon_mounts": newMounts });
  }
};
__name(_LoadoutHelper, "LoadoutHelper");
let LoadoutHelper = _LoadoutHelper;
const _StrussHelper = class _StrussHelper {
  constructor(actor) {
    this.actor = actor;
  }
  /**
   * Stabilize this actor, given two choices that have already been made
   * @param o1  Choice 1, Cooling or Repairing
   * @param o2  Choice 2, Reloading, removing Burn, or clearing own or adjacent ally condition
   * @returns   Details to be printed to chat
   */
  async stabilize(o1, o2) {
    if (!this.actor.is_mech() && !this.actor.is_npc()) {
      ui.notifications.warn(`A ${this.actor.type} can't be stabilized!`);
      return;
    }
    let changes = {}, item_changes = [];
    if (o1 === StabOptions1.Cool)
      changes["system.heat.value"] = 0, this.actor.effectHelper.removeActiveEffect("exposed");
    else if (o1 === StabOptions1.Repair) {
      if (this.actor.is_mech() || this.actor.is_npc())
        if (this.actor.is_mech() && this.actor.system.repairs.value <= 0) {
          ui.notifications.warn("No repairs remaining!");
          return;
        } else
          changes["system.hp.value"] = this.actor.system.hp.max, this.actor.is_mech() && (changes["system.repairs.value"] = this.actor.system.repairs.value - 1);
    } else
      return;
    switch (o2) {
      case StabOptions2.ClearBurn:
        changes["system.burn"] = 0;
        break;
      case StabOptions2.ClearOtherCond:
        break;
      case StabOptions2.ClearOwnCond:
        break;
      case StabOptions2.Reload:
        item_changes = this.actor.loadoutHelper.reloadableItems();
        break;
      default:
        ui.notifications.warn("Invalid Stabilize choice!");
        return;
    }
    await this.actor.update(changes), await this.actor.updateEmbeddedDocuments("Item", item_changes);
  }
  /**
   * Returns the current overcharge roll/text. Only applicable for mechs.
   */
  getOverchargeRoll() {
    return this.actor.is_npc() ? "1d6" : this.actor.is_mech() ? this.actor.system.overcharge_sequence.split(",")[this.actor.system.overcharge] : null;
  }
};
__name(_StrussHelper, "StrussHelper");
let StrussHelper = _StrussHelper;
function registerStructureSteps(flowSteps) {
  flowSteps.set("preStructureRollChecks", preStructureRollChecks), flowSteps.set("rollStructureTable", rollStructureTable), flowSteps.set("noStructureRemaining", noStructureRemaining), flowSteps.set("checkStructureMultipleOnes", checkStructureMultipleOnes), flowSteps.set("structureInsertDismembermentButton", structureInsertDismembermentButton), flowSteps.set("structureInsertHullCheckButton", structureInsertHullCheckButton), flowSteps.set("structureInsertSecondaryRollButton", structureInsertSecondaryRollButton), flowSteps.set("structureInsertCascadeRollButton", structureInsertCascadeRollButton), flowSteps.set("printStructureCard", printStructureCard), flowSteps.set("secondaryStructureRoll", secondaryStructureRoll), flowSteps.set("printSecondaryStructureCard", printSecondaryStructureCard);
}
__name(registerStructureSteps, "registerStructureSteps");
const _StructureFlow = class _StructureFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "structure",
      title: (data2 == null ? void 0 : data2.title) ?? "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "",
      desc: (data2 == null ? void 0 : data2.desc) ?? "",
      val: (data2 == null ? void 0 : data2.val) ?? -1,
      max: (data2 == null ? void 0 : data2.max) ?? -1,
      remStruct: (data2 == null ? void 0 : data2.remStruct) ?? 4
    };
    super(uuid, initialData);
  }
};
__name(_StructureFlow, "StructureFlow");
let StructureFlow = _StructureFlow;
StructureFlow.steps = [
  "preStructureRollChecks",
  "rollStructureTable",
  "noStructureRemaining",
  "checkStructureMultipleOnes",
  "structureInsertDismembermentButton",
  "structureInsertHullCheckButton",
  "structureInsertSecondaryRollButton",
  "structureInsertCascadeRollButton",
  "printStructureCard"
];
async function preStructureRollChecks(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only Mechs and NPCs can take structure damage"), !1;
  if (game.settings.get(game.system.id, LANCER.setting_automation).structure && !((_a19 = state.data) != null && _a19.reroll_data)) {
    if (actor.system.hp.value > 0)
      return ui.notifications.info("Token has hp remaining. No need to roll structure."), !1;
    const { openSlidingHud: open } = await Promise.resolve().then(() => index$2);
    try {
      await open("struct", { stat: "structure", title: "Structure Damage", lancerActor: actor });
    } catch {
      return !1;
    }
  }
  if (!((_b = state.data) != null && _b.reroll_data)) {
    let hp = actor.system.hp, structure = actor.system.structure;
    if (hp.value < 1 && structure.value > 0)
      await actor.update({
        "system.structure": structure.value - 1,
        "system.hp": hp.value + hp.max
      });
    else
      return !1;
  }
  return !0;
}
__name(preStructureRollChecks, "preStructureRollChecks");
const structTableTitles = [
  "lancer.tables.structure.title.crushing",
  "lancer.tables.structure.title.direct",
  "lancer.tables.structure.title.trauma",
  "lancer.tables.structure.title.trauma",
  "lancer.tables.structure.title.trauma",
  "lancer.tables.structure.title.glancing",
  "lancer.tables.structure.title.glancing"
], monstrosityTableTitles = [
  "lancer.tables.structureMonstrosity.title.fatal",
  "lancer.tables.structureMonstrosity.title.direct",
  "lancer.tables.structureMonstrosity.title.dismember",
  "lancer.tables.structureMonstrosity.title.powerful",
  "lancer.tables.structureMonstrosity.title.powerful",
  "lancer.tables.structureMonstrosity.title.glancing",
  "lancer.tables.structureMonstrosity.title.glancing"
];
function structTableDescriptions(roll, remStruct) {
  switch (roll) {
    case 0:
      return "lancer.tables.structure.description.crushing";
    case 1:
      switch (remStruct) {
        case 2:
          return "lancer.tables.structure.description.direct.2";
        case 1:
        case 0:
          return "lancer.tables.structure.description.direct.1";
        default:
          return "lancer.tables.structure.description.direct.3plus";
      }
    case 2:
    case 3:
    case 4:
      return "lancer.tables.structure.description.trauma";
    case 5:
    case 6:
      return "lancer.tables.structure.description.glancing";
  }
  return "";
}
__name(structTableDescriptions, "structTableDescriptions");
function monstrosityTableDescriptions(roll, remStruct) {
  switch (roll) {
    case 0:
      return "lancer.tables.structureMonstrosity.description.fatal";
    case 1:
      return remStruct >= 3 ? "lancer.tables.structureMonstrosity.description.direct.3plus" : remStruct === 2 ? "lancer.tables.structureMonstrosity.description.direct.2" : "lancer.tables.structureMonstrosity.description.direct.1";
    case 2:
      return "lancer.tables.structureMonstrosity.description.dismember";
    case 3:
    case 4:
      return "lancer.tables.structureMonstrosity.description.powerful";
    case 5:
    case 6:
      return "lancer.tables.structureMonstrosity.description.glancing";
  }
  return "";
}
__name(monstrosityTableDescriptions, "monstrosityTableDescriptions");
function hasUniquePhysiology(actor) {
  return actor.is_npc() && actor.itemTypes.npc_feature.some((i) => i.system.lid === "npcf_unique_physiology_monstrosity");
}
__name(hasUniquePhysiology, "hasUniquePhysiology");
async function rollStructureTable(state) {
  var _a19, _b, _c, _d;
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll structure."), !1;
  if ((((_b = (_a19 = state.data) == null ? void 0 : _a19.reroll_data) == null ? void 0 : _b.structure) ?? actor.system.structure.value) >= actor.system.structure.max)
    return ui.notifications.info("The mech is at full Structure, no structure check to roll."), !1;
  let remStruct = ((_d = (_c = state.data) == null ? void 0 : _c.reroll_data) == null ? void 0 : _d.structure) ?? actor.system.structure.value, formula = `${actor.system.structure.max - remStruct}d6kl1`;
  actor.is_npc() && actor.items.some((i) => ["npcf_legendary_ultra", "npcf_legendary_veteran"].includes(i.system.lid)) && (formula = `{${formula}, ${formula}}kh`);
  let roll = await new Roll(formula).evaluate(), result = roll.total;
  if (result === void 0)
    return !1;
  (result === 0 || result === 1 && remStruct <= 1) && await actor.update({
    "system.hp.value": actor.system.hp.value - actor.system.hp.max,
    "system.structure.value": 0
  });
  const isMonstrosity = hasUniquePhysiology(actor);
  return state.data = {
    type: "structure",
    title: isMonstrosity ? monstrosityTableTitles[result] : structTableTitles[result],
    desc: isMonstrosity ? monstrosityTableDescriptions(result, remStruct) : structTableDescriptions(result, remStruct),
    remStruct,
    val: actor.system.structure.value,
    max: actor.system.structure.max,
    roll_str: roll.formula,
    result: {
      roll,
      tt: await roll.getTooltip(),
      total: (roll.total ?? 0).toString()
    }
  }, !0;
}
__name(rollStructureTable, "rollStructureTable");
async function noStructureRemaining(state) {
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  let actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll structure."), !1;
  if (state.data.remStruct > 0)
    return !0;
  const isMonstrosity = hasUniquePhysiology(actor), printCard = game.lancer.flowSteps.get("printStructureCard");
  if (!printCard)
    throw new TypeError("printStructureCard flow step missing!");
  if (typeof printCard != "function")
    throw new TypeError("printStructureCard flow step is not a function.");
  return state.data.title = isMonstrosity ? monstrosityTableTitles[0] : structTableTitles[0], state.data.desc = isMonstrosity ? monstrosityTableDescriptions(0, 0) : structTableDescriptions(0, 0), state.data.result = void 0, await actor.update({ "system.hp.value": actor.system.hp.value - actor.system.hp.max }), printCard(state), !1;
}
__name(noStructureRemaining, "noStructureRemaining");
async function checkStructureMultipleOnes(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  let actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll structure."), !1;
  let roll = (_a19 = state.data.result) == null ? void 0 : _a19.roll;
  if (!roll)
    throw new TypeError("Structure check hasn't been rolled yet!");
  if (((_b = roll.terms[0].rolls) == null ? void 0 : _b.length) > 1) {
    const chosenIndex = roll.terms[0].results.findIndex((r) => !r.discarded);
    roll = roll.terms[0].rolls[chosenIndex] || roll;
  }
  if (!roll)
    throw new TypeError("Structure check hasn't been rolled yet!");
  const isMonstrosity = hasUniquePhysiology(actor);
  return roll.terms[0].results.filter((v) => v.result === 1).length > 1 && (isMonstrosity ? (state.data.title = monstrosityTableTitles[0], state.data.desc = monstrosityTableDescriptions(roll.total ?? 1, 1)) : (state.data.title = structTableTitles[0], state.data.desc = structTableDescriptions(roll.total ?? 1, 1)), state.data.title = game.i18n.localize(state.data.title), state.data.desc = game.i18n.localize(state.data.desc), await actor.update({
    "system.hp.value": actor.system.hp.value - actor.system.hp.max,
    "system.structure.value": 0
  })), !0;
}
__name(checkStructureMultipleOnes, "checkStructureMultipleOnes");
async function structureInsertDismembermentButton(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  let actor = state.actor;
  return !actor.is_mech() && !actor.is_npc() ? (ui.notifications.warn("Only npcs and mechs can roll structure."), !1) : (!hasUniquePhysiology(actor) || ((_a19 = state.data.result) == null ? void 0 : _a19.roll.total) !== 2 || (state.data.embedButtons = state.data.embedButtons || [], state.data.embedButtons.push(`<a
    class="flow-button lancer-button"
    data-flow-type="dismembermentDamage"
    data-actor-id="${actor.uuid}"
  >
    <i class="compcon-icon kinetic i--sm"></i> ROLL DAMAGE
  </a>`)), !0);
}
__name(structureInsertDismembermentButton, "structureInsertDismembermentButton");
async function beginDismembermentDamageFlow(actor) {
  var _a19;
  if (!actor) {
    (_a19 = ui.notifications) == null || _a19.error("No actor found for dismemberment damage button.");
    return;
  }
  const tokens = actor.getActiveTokens(), damageData = [{ type: DamageType.Kinetic, val: "1d6" }], hit_results = [
    {
      target: tokens[0],
      total: "0",
      usedLockOn: !1,
      hit: !0,
      crit: !1
    }
  ];
  await new DamageRollFlow(actor, {
    title: game.i18n.localize("lancer.tables.structureMonstrosity.title.dismember"),
    damage: damageData,
    configurable: !1,
    add_burn: !1,
    tags: [],
    hit_results,
    has_normal_hit: !0,
    has_crit_hit: !1
  }).begin();
}
__name(beginDismembermentDamageFlow, "beginDismembermentDamageFlow");
async function structureInsertHullCheckButton(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  let actor = state.actor;
  return !actor.is_mech() && !actor.is_npc() ? (ui.notifications.warn("Only npcs and mechs can roll structure."), !1) : (((_a19 = state.data.result) == null ? void 0 : _a19.roll.total) === 1 && state.data.remStruct === 2 && (state.data.embedButtons = state.data.embedButtons || [], state.data.embedButtons.push(`<a
      class="flow-button lancer-button"
      data-flow-type="check"
      data-check-type="hull"
      data-actor-id="${actor.uuid}"
    >
      <i class="fas fa-dice-d20 i--sm"></i> HULL
    </a>`)), !0);
}
__name(structureInsertHullCheckButton, "structureInsertHullCheckButton");
async function structureInsertSecondaryRollButton(state) {
  var _a19;
  if (!state.data || !state.data)
    throw new TypeError("Structure roll flow data missing!");
  let actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll structure."), !1;
  if (hasUniquePhysiology(actor))
    return !0;
  const result = (_a19 = state.data.result) == null ? void 0 : _a19.roll.total;
  if (!result)
    throw new TypeError("Structure check hasn't been rolled yet!");
  return !hasUniquePhysiology(state.actor) && result >= 2 && result <= 4 && (state.data.embedButtons = state.data.embedButtons || [], state.data.embedButtons.push(`<a
      class="flow-button lancer-button"
      data-flow-type="secondaryStructure"
      data-actor-id="${actor.uuid}"
    >
      <i class="fas fa-dice-d6 i--sm"></i> TEAR OFF
    </a>`)), !0;
}
__name(structureInsertSecondaryRollButton, "structureInsertSecondaryRollButton");
async function structureInsertCascadeRollButton(state) {
  if (!state.data)
    throw new TypeError("Structure/Overheat roll flow data missing!");
  let actor = state.actor;
  return !actor.is_mech() && !actor.is_npc() ? (ui.notifications.warn("Only npcs and mechs can roll structure/overheat."), !1) : (actor.items.filter((item) => item.isAI()).length && (state.data.embedButtons = state.data.embedButtons || [], state.data.embedButtons.push(`<a
    class="flow-button lancer-button"
    data-flow-type="cascade"
    data-actor-id="${actor.uuid}"
  >
    <i class="fas fa-dice-d20 i--sm"></i> <span class="horus--subtle">CASCADE CHECK</span>
  </a>`)), !0);
}
__name(structureInsertCascadeRollButton, "structureInsertCascadeRollButton");
async function printStructureCard(state, options) {
  if (!state.data)
    throw new TypeError("Structure roll flow data missing!");
  state.data.title = game.i18n.localize(state.data.title), state.data.desc = game.i18n.localize(state.data.desc);
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/structure-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printStructureCard, "printStructureCard");
async function beginSecondaryStructureFlow(actorUuid, flowArgs) {
  return await new SecondaryStructureFlow(actorUuid, flowArgs).begin();
}
__name(beginSecondaryStructureFlow, "beginSecondaryStructureFlow");
const _SecondaryStructureFlow = class _SecondaryStructureFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "secondary_structure",
      title: (data2 == null ? void 0 : data2.title) ?? "Equipment Destruction",
      desc: (data2 == null ? void 0 : data2.desc) ?? "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "1d6"
    };
    super(uuid, initialData);
  }
};
__name(_SecondaryStructureFlow, "SecondaryStructureFlow");
let SecondaryStructureFlow = _SecondaryStructureFlow;
SecondaryStructureFlow.steps = ["secondaryStructureRoll", "printSecondaryStructureCard"];
async function secondaryStructureRoll(state) {
  if (!state.data)
    throw new TypeError("Secondary Structure roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn('Only npcs and mechs can work with "remaining structure" logic.'), !1;
  let roll = await new Roll(state.data.roll_str).evaluate(), result = roll.total;
  return state.data.result = {
    roll,
    tt: await roll.getTooltip(),
    total: result.toString()
  }, result <= 3 ? (state.data.title = "Weapon Destruction", state.data.desc = "On a 1–3, all weapons on one mount of your choice are destroyed") : (state.data.title = "System Destruction", state.data.desc = "On a 4–6, a system of your choice is destroyed"), !0;
}
__name(secondaryStructureRoll, "secondaryStructureRoll");
async function printSecondaryStructureCard(state, options) {
  const template = (options == null ? void 0 : options.template) ?? `systems/${game.system.id}/templates/chat/structure-secondary-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printSecondaryStructureCard, "printSecondaryStructureCard");
function triggerStrussFlow(actor, changed) {
  var _a19, _b, _c, _d;
  if (!(!actor.is_mech() && !actor.is_npc()) && game.settings.get(game.system.id, LANCER.setting_automation).structure && userOwnsActor(actor) && (actor.is_mech() || actor.is_npc())) {
    const data2 = changed;
    (((_b = (_a19 = data2.system) == null ? void 0 : _a19.heat) == null ? void 0 : _b.value) ?? 0) > actor.system.heat.max && actor.system.stress.value > 0 && actor.beginOverheatFlow(), (((_d = (_c = data2.system) == null ? void 0 : _c.hp) == null ? void 0 : _d.value) ?? 1) <= 0 && actor.system.structure.value > 0 && actor.beginStructureFlow();
  }
}
__name(triggerStrussFlow, "triggerStrussFlow");
function registerOverheatSteps(flowSteps) {
  flowSteps.set("preOverheatRollChecks", preOverheatRollChecks), flowSteps.set("rollOverheatTable", rollOverheatTable), flowSteps.set("noStressRemaining", noStressRemaining), flowSteps.set("checkOverheatMultipleOnes", checkOverheatMultipleOnes), flowSteps.set("overheatInsertEngCheckButton", overheatInsertEngCheckButton), flowSteps.set("printOverheatCard", printOverheatCard);
}
__name(registerOverheatSteps, "registerOverheatSteps");
const _OverheatFlow = class _OverheatFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "overheat",
      title: (data2 == null ? void 0 : data2.title) ?? "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "",
      desc: (data2 == null ? void 0 : data2.desc) ?? "",
      val: (data2 == null ? void 0 : data2.val) ?? -1,
      max: (data2 == null ? void 0 : data2.max) ?? -1,
      remStress: (data2 == null ? void 0 : data2.remStress) ?? 4
    };
    super(uuid, initialData);
  }
};
__name(_OverheatFlow, "OverheatFlow");
let OverheatFlow = _OverheatFlow;
OverheatFlow.steps = [
  "preOverheatRollChecks",
  "rollOverheatTable",
  "noStressRemaining",
  "checkOverheatMultipleOnes",
  "overheatInsertEngCheckButton",
  "structureInsertCascadeRollButton",
  "printOverheatCard"
];
async function preOverheatRollChecks(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only Mechs and NPCs can take stress damage"), !1;
  if (game.settings.get(game.system.id, LANCER.setting_automation).structure && !((_a19 = state.data) != null && _a19.reroll_data)) {
    if (actor.system.heat.value <= actor.system.heat.max)
      return ui.notifications.info("Token is not at heat cap. No need to roll stress."), !1;
    const { openSlidingHud: open } = await Promise.resolve().then(() => index$2);
    try {
      await open("stress", { stat: "stress", title: "Stress Damage", lancerActor: actor });
    } catch {
      return !1;
    }
  }
  if (!((_b = state.data) != null && _b.reroll_data)) {
    let heat = actor.system.heat, stress = actor.system.stress;
    if (heat.value > actor.system.heat.max && stress.value > 0) {
      if (actor.is_npc() && actor.system.stress.max === 1)
        return !0;
      await actor.update({
        "system.stress": stress.value - 1,
        "system.heat": heat.value - actor.system.heat.max
      });
    } else
      return !1;
  }
  return !0;
}
__name(preOverheatRollChecks, "preOverheatRollChecks");
const overheatTableTitles = [
  "lancer.tables.overheat.title.irreversible",
  "lancer.tables.overheat.title.meltdown",
  "lancer.tables.overheat.title.destabilized",
  "lancer.tables.overheat.title.destabilized",
  "lancer.tables.overheat.title.destabilized",
  "lancer.tables.overheat.title.shunt",
  "lancer.tables.overheat.title.shunt"
];
function overheatTableDescriptions(roll, remStress) {
  switch (roll) {
    case 0:
      return "lancer.tables.overheat.description.irreversible";
    case 1:
      switch (remStress) {
        case 2:
          return "lancer.tables.overheat.description.meltdown.2";
        case 1:
          return "lancer.tables.overheat.description.meltdown.1";
        default:
          return "lancer.tables.overheat.description.meltdown.3plus";
      }
    case 2:
    case 3:
    case 4:
      return "lancer.tables.overheat.description.destabilized";
    case 5:
    case 6:
      return "lancer.tables.overheat.description.shunt";
  }
  return "";
}
__name(overheatTableDescriptions, "overheatTableDescriptions");
async function rollOverheatTable(state) {
  var _a19, _b, _c, _d;
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll overheat."), !1;
  if (actor.is_npc() && actor.system.stress.max === 1)
    return state.data = {
      type: "overheat",
      title: overheatTableTitles[3],
      desc: overheatTableDescriptions(3, 1),
      remStress: 1,
      val: actor.system.stress.value,
      max: actor.system.stress.max,
      roll_str: "3",
      result: void 0
    }, !0;
  if ((((_b = (_a19 = state.data) == null ? void 0 : _a19.reroll_data) == null ? void 0 : _b.stress) ?? actor.system.stress.value) >= actor.system.stress.max)
    return ui.notifications.info("The mech is at full Stress, no overheat check to roll."), !1;
  let remStress = ((_d = (_c = state.data) == null ? void 0 : _c.reroll_data) == null ? void 0 : _d.stress) ?? actor.system.stress.value, formula = `${actor.system.stress.max - remStress}d6kl1`;
  actor.is_npc() && actor.items.some((i) => ["npcf_legendary_ultra", "npcf_legendary_veteran"].includes(i.system.lid)) && (formula = `{${formula}, ${formula}}kh`);
  let roll = await new Roll(formula).evaluate(), result = roll.total;
  return result === void 0 ? !1 : (state.data = {
    type: "overheat",
    title: overheatTableTitles[result],
    desc: overheatTableDescriptions(result, remStress),
    remStress,
    val: actor.system.stress.value,
    max: actor.system.stress.max,
    roll_str: roll.formula,
    result: {
      roll,
      tt: await roll.getTooltip(),
      total: (roll.total ?? 0).toString()
    }
  }, !0);
}
__name(rollOverheatTable, "rollOverheatTable");
async function noStressRemaining(state) {
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  let actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll overheat."), !1;
  if (state.data.remStress > 0 && (!actor.is_npc() || actor.system.stress.max > 1))
    return !0;
  const printCard = game.lancer.flowSteps.get("printOverheatCard");
  if (!printCard)
    throw new TypeError("printOverheatCard flow step missing!");
  if (typeof printCard != "function")
    throw new TypeError("printOverheatCard flow step is not a function.");
  return actor.is_npc() && actor.system.stress.max == 1 ? (state.data.title = overheatTableTitles[3], state.data.desc = overheatTableDescriptions(3, 1), state.data.result = void 0) : (state.data.title = overheatTableTitles[0], state.data.desc = overheatTableDescriptions(0, 0), state.data.result = void 0), printCard(state), !1;
}
__name(noStressRemaining, "noStressRemaining");
async function checkOverheatMultipleOnes(state) {
  var _a19, _b;
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  let actor = state.actor;
  if (!actor.is_mech() && !actor.is_npc())
    return ui.notifications.warn("Only npcs and mechs can roll overheat."), !1;
  let roll = (_a19 = state.data.result) == null ? void 0 : _a19.roll;
  if (!roll)
    throw new TypeError("Overheat check hasn't been rolled yet!");
  if (((_b = roll.terms[0].rolls) == null ? void 0 : _b.length) > 1) {
    const chosenIndex = roll.terms[0].results.findIndex((r) => !r.discarded);
    roll = roll.terms[0].rolls[chosenIndex] || roll;
  }
  if (!roll)
    throw new TypeError("Overheat check hasn't been rolled yet!");
  return roll.terms[0].results.filter((v) => v.result === 1).length > 1 && (state.data.title = overheatTableTitles[0], state.data.desc = overheatTableDescriptions(roll.total ?? 1, 1)), !0;
}
__name(checkOverheatMultipleOnes, "checkOverheatMultipleOnes");
async function overheatInsertEngCheckButton(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  let actor = state.actor;
  return !actor.is_mech() && !actor.is_npc() ? (ui.notifications.warn("Only npcs and mechs can roll overheat."), !1) : (((_a19 = state.data.result) == null ? void 0 : _a19.roll.total) === 1 && state.data.remStress === 2 && (state.data.embedButtons = state.data.embedButtons || [], state.data.embedButtons.push(`<a
      class="flow-button lancer-button"
      data-flow-type="check"
      data-check-type="engineering"
      data-actor-id="${actor.uuid}"
    >
      <i class="fas fa-dice-d20 i--sm"></i> ENGINEERING
    </a>`)), !0);
}
__name(overheatInsertEngCheckButton, "overheatInsertEngCheckButton");
async function printOverheatCard(state, options) {
  if (!state.data)
    throw new TypeError("Overheat roll flow data missing!");
  state.data.title = game.i18n.localize(state.data.title), state.data.desc = game.i18n.localize(state.data.desc);
  const template = (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/overheat-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printOverheatCard, "printOverheatCard");
function registerFullRepairSteps(flowSteps) {
  flowSteps.set("displayFullRepairDialog", displayFullRepairDialog), flowSteps.set("executeFullRepair", executeFullRepair);
}
__name(registerFullRepairSteps, "registerFullRepairSteps");
const _FullRepairFlow = class _FullRepairFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      title: (data2 == null ? void 0 : data2.title) || "",
      description: (data2 == null ? void 0 : data2.description) || "",
      tags: (data2 == null ? void 0 : data2.tags) || []
    };
    super(uuid, initialData);
  }
};
__name(_FullRepairFlow, "FullRepairFlow");
let FullRepairFlow = _FullRepairFlow;
FullRepairFlow.steps = ["displayFullRepairDialog", "executeFullRepair"];
async function displayFullRepairDialog(state) {
  if (!state.data)
    throw new TypeError("Full Repair flow state missing!");
  return new Promise((resolve, reject) => {
    var _a19, _b;
    new Dialog({
      title: `FULL REPAIR - ${state.actor.name}`,
      content: `<h3>Are you sure you want to fully repair the ${(_a19 = state.actor) == null ? void 0 : _a19.type} "${(_b = state.actor) == null ? void 0 : _b.name}"?`,
      buttons: {
        submit: {
          icon: '<i class="fas fa-check"></i>',
          label: "Yes",
          callback: async (_dlg) => {
            if (!state.actor)
              return reject();
            resolve(!0);
          }
        },
        cancel: {
          icon: '<i class="fas fa-times"></i>',
          label: "No",
          callback: async () => resolve(!1)
        }
      },
      default: "submit",
      close: () => resolve(!1)
    }).render(!0);
  });
}
__name(displayFullRepairDialog, "displayFullRepairDialog");
async function executeFullRepair(state) {
  if (!state.data)
    throw new TypeError("Full Repair flow state missing!");
  const template = `systems/${game.system.id}/templates/chat/generic-card.hbs`, flags = {};
  let data2 = {
    title: state.data.title,
    description: state.data.description,
    tags: state.data.tags
  };
  return await state.actor.loadoutHelper.fullRepair(), data2.title = "FULL REPAIR", data2.description = `Notice: ${state.actor.name} has been fully repaired.`, await renderTemplateStep(state.actor, template, data2, flags), !0;
}
__name(executeFullRepair, "executeFullRepair");
function registerOverchargeSteps(flowSteps) {
  flowSteps.set("initOverchargeData", initOverchargeData), flowSteps.set("rollOvercharge", rollOvercharge), flowSteps.set("updateOverchargeActor", updateOverchargeActor), flowSteps.set("printOverchargeCard", printOverchargeCard);
}
__name(registerOverchargeSteps, "registerOverchargeSteps");
const _OverchargeFlow = class _OverchargeFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "overcharge",
      title: (data2 == null ? void 0 : data2.title) || "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) || "",
      level: (data2 == null ? void 0 : data2.level) || 0
    };
    super(uuid, initialData);
  }
};
__name(_OverchargeFlow, "OverchargeFlow");
let OverchargeFlow = _OverchargeFlow;
OverchargeFlow.steps = ["initOverchargeData", "rollOvercharge", "updateOverchargeActor", "printOverchargeCard"];
async function initOverchargeData(state, options) {
  if (!state.actor || !state.actor.is_mech())
    throw new Error("Only mechs can overcharge!");
  if (!state.data)
    throw new Error("Data not found for overcharge flow!");
  return state.data.title = (options == null ? void 0 : options.title) || state.data.title || `${state.actor.name.toUpperCase()} is OVERCHARGING`, state.data.roll_str = state.actor.strussHelper.getOverchargeRoll(), state.data.level = Math.min(
    state.actor.system.overcharge + 1,
    state.actor.system.overcharge_sequence.split(",").length - 1
  ), state;
}
__name(initOverchargeData, "initOverchargeData");
async function rollOvercharge(state) {
  if (!state.actor || !state.actor.is_mech())
    throw new Error("Only mechs can overcharge!");
  if (!state.data)
    throw new Error("Data not found for overcharge flow!");
  const roll = await new Roll(state.data.roll_str).evaluate(), tt = await roll.getTooltip();
  state.data.result = { roll, tt };
}
__name(rollOvercharge, "rollOvercharge");
async function updateOverchargeActor(state) {
  if (!state.actor || !state.actor.is_mech())
    throw new Error("Only mechs can overcharge!");
  if (!state.data)
    throw new Error("Data not found for overcharge flow!");
  if (!state.data.result)
    throw new Error("Overcharge hasn't been rolled yet!");
  await state.actor.update({
    "system.overcharge": state.data.level
  }), game.settings.get(game.system.id, LANCER.setting_automation).overcharge_heat && await state.actor.update({
    "system.heat.value": state.actor.system.heat.value + state.data.result.roll.total
  });
}
__name(updateOverchargeActor, "updateOverchargeActor");
async function printOverchargeCard(state, options) {
  if (!state.actor || !state.actor.is_mech())
    throw new Error("Only mechs can overcharge!");
  if (!state.data)
    throw new Error("Data not found for overcharge flow!");
  const template = (options == null ? void 0 : options.template) ?? `systems/${game.system.id}/templates/chat/overcharge-card.hbs`;
  return renderTemplateStep(state.actor, template, state.data);
}
__name(printOverchargeCard, "printOverchargeCard");
function registerNPCSteps(flowSteps) {
  flowSteps.set("findRechargeableSystems", findRechargeableSystems), flowSteps.set("rollRecharge", rollRecharge), flowSteps.set("applyRecharge", applyRecharge), flowSteps.set("printRechargeCard", printRechargeCard);
}
__name(registerNPCSteps, "registerNPCSteps");
const _NPCRechargeFlow = class _NPCRechargeFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "recharge",
      title: (data2 == null ? void 0 : data2.title) ?? "",
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "1d6",
      recharging_uuids: (data2 == null ? void 0 : data2.recharging_uuids) ?? [],
      charged: (data2 == null ? void 0 : data2.charged) ?? []
    };
    super(uuid, initialData);
  }
};
__name(_NPCRechargeFlow, "NPCRechargeFlow");
let NPCRechargeFlow = _NPCRechargeFlow;
NPCRechargeFlow.steps = ["findRechargeableSystems", "rollRecharge", "applyRecharge", "printRechargeCard"];
async function findRechargeableSystems(state) {
  if (!state.data)
    throw new TypeError("Recharge flow state missing!");
  if (!state.actor)
    throw new TypeError("Recharge flow state actor missing!");
  const actor = state.actor;
  if (state.data.recharging_uuids.length >= 1)
    return !0;
  for (let item of actor.items)
    item.is_npc_feature() && (item.system.charged || item.isRecharge() && state.data.recharging_uuids.push(item.uuid));
  return !(state.data.recharging_uuids.length < 1);
}
__name(findRechargeableSystems, "findRechargeableSystems");
async function rollRecharge(state) {
  if (!state.data)
    throw new TypeError("Recharge flow state missing!");
  const roll = await new Roll(state.data.roll_str).evaluate(), tt = await roll.getTooltip();
  return state.data.result = { roll, tt }, !0;
}
__name(rollRecharge, "rollRecharge");
async function applyRecharge(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Recharge flow state missing!");
  if (!state.actor)
    throw new TypeError("Recharge flow state actor missing!");
  for (let uuid of state.data.recharging_uuids) {
    const item = await LancerItem.fromUuid(uuid);
    if (!item || item.parent !== state.actor || !item.is_npc_feature())
      continue;
    const recharge = item.system.tags.find((tag) => tag.is_recharge);
    recharge && (recharge.num_val && recharge.num_val <= (((_a19 = state.data.result) == null ? void 0 : _a19.roll.total) ?? 0) && await item.update({ "system.charged": !0 }), state.data.charged.push({ name: item.name, target: recharge.num_val ?? 0, charged: item.system.charged }));
  }
  return !0;
}
__name(applyRecharge, "applyRecharge");
async function printRechargeCard(state) {
  if (!state.data)
    throw new TypeError("Recharge flow state missing!");
  return renderTemplateStep(state.actor, `systems/${game.system.id}/templates/chat/charge-card.hbs`, state.data), !0;
}
__name(printRechargeCard, "printRechargeCard");
const require$$0 = [
  {
    id: "act_move",
    name: "Move",
    activation: "Move",
    terse: "Move your character up to its Speed in any direction.",
    detail: "On their turn, characters can always move spaces equal to their SPEED, in addition to any other actions. This is called a standard move to distinguish it from movement granted by systems or talents.<br>A character only counts as moving if they move 1 or more spaces.<br>Characters can move into any adjacent space, even diagonally, as long as the space isn’t occupied by an obstruction (and is one that they would be able to move in – characters can't move straight up unless they can fly, for example). There are several factors that can affect movement, which are detailed here.",
    pilot: !0,
    mech: !0,
    hide_active: !0
  },
  {
    id: "act_overcharge",
    name: "Overcharge",
    activation: "Free",
    terse: "Overcharging immediately allows you to make any quick action of your choice as a Free Action, even one you already made this turn.",
    detail: "When you OVERCHARGE, you briefly push your mech beyond factory specifications for a tactical advantage. Moments of intense action won’t tax your mech’s systems too much, but sustained action beyond prescribed limits takes a toll.<br>Once per turn, you can OVERCHARGE your mech, allowing you to make any quick action as a free action – even actions you have already taken this turn.<br>The first time you OVERCHARGE, take 1 heat.<br>The second time you OVERCHARGE, take 1d3 heat.<br>The third time, take 1d6 heat, and each time thereafter take 1d6+4 heat.<br>A FULL REPAIR resets this counter.",
    synergy_locations: [
      "overcharge"
    ],
    confirm: [
      "REACTOR LIMITER DISABLED. CORE TEMPERATURES RISING."
    ]
  },
  {
    id: "act_skirmish",
    name: "Skirmish",
    activation: "Quick",
    terse: "Attack with a single weapon. In addition to your primary attack, you may also attack with a different Auxiliary weapon on the same mount.",
    detail: "When you SKIRMISH, you attack with a single weapon.<br>To SKIRMISH, choose a weapon and a valid target within RANGE (or THREAT) then make an attack.<br>• In addition to your primary attack, you may also attack with a different AUXILIARY weapon on the same mount. That weapon doesn’t deal bonus damage.<br>• SUPERHEAVY weapons are too cumbersome to use in a SKIRMISH, and can only be fired as part of a BARRAGE."
  },
  {
    id: "act_boost",
    name: "Boost",
    activation: "Quick",
    terse: "Take an extra movement of at least 1 space, up to your SPEED.",
    detail: "When you BOOST, you move at least 1 space, up to your SPEED. This allows you to make an extra movement, on top of your standard move. Certain talents and systems can only be used when you BOOST, not when you make a standard move.",
    synergy_locations: [
      "boost"
    ],
    confirm: [
      "POWER REDIRECTED."
    ],
    mech: !0,
    pilot: !0
  },
  {
    id: "act_ram",
    name: "Ram",
    activation: "Quick",
    terse: "Attempt to knock down or knock back your target. On a success the target is knocked Prone and you may choose to knock them back one space.",
    detail: "When you RAM, you make a melee attack with the aim of knocking a target down or back.<br>To RAM, make a melee attack against an adjacent character the same SIZE or smaller than you. On a success, your target is knocked PRONE and you may also choose to knock them back by one space, directly away from you.",
    synergy_locations: [
      "ram"
    ],
    confirm: [
      "MANEUVER CONFIRMED.",
      "WARNING: PROXIMITY.",
      "WARNING: COLLISION IMMINENT"
    ]
  },
  {
    id: "act_grapple",
    name: "Grapple",
    activation: "Quick",
    terse: "Attempt to grab on your target, potentially immobilizing it or riding it.",
    detail: "When you GRAPPLE, you try to grab hold of a target and overpower them – disarming, subduing, or damaging them so they can’t do the same to you.<br>To GRAPPLE, choose an adjacent character and make a melee attack. On a hit:<br>• both characters become ENGAGED;<br>• neither character can BOOST or take reactions for the duration of the grapple;<br>• the smaller character becomes IMMOBILIZED but moves when the larger party moves, mirroring their movement. If both parties are the same SIZE, either can make contested HULL checks at the start of their turn: the winner counts as larger than the loser until this contest is repeated.<br>A GRAPPLE ends when:<br>• either character breaks adjacency, such as if they are knocked back by another effect;<br>• the attacker chooses to end the grapple as a free action;<br>• The defender breaks free by succeeding on a contested HULL check as a quick action.<br>If a GRAPPLE involves more than two characters, the same rules apply, but when counting SIZE, add together the SIZE of all characters on each side. For example, if two SIZE 1 allied characters are grappling a single SIZE 2 enemy, the allied characters count as a combined SIZE 2 and can try to drag their foe around.",
    synergy_locations: [
      "grapple"
    ]
  },
  {
    id: "act_quick_tech",
    name: "Quick Tech",
    activation: "Quick",
    terse: "Perform quick electronic warfare or systems-boosting activities.",
    detail: "When you use QUICK TECH, you engage in electronic warfare, countermeasures, and other technical actions, often aided by a mech’s powerful computing and simulation cores.<br>Each time you take this action, you choose an option from the QUICK TECH list. All mechs have access to these options, but some systems enhance them or make new options available.<br>Unlike other quick actions, QUICK TECH can be taken more than once per turn; however, a different option must be chosen every time, unless specified otherwise or granted as a free action.",
    ignore_used: !0,
    synergy_locations: [
      "quick_tech"
    ]
  },
  {
    id: "act_bolster",
    name: "Bolster",
    activation: "Quick Tech",
    terse: "Enhance another character’s systems.",
    detail: "When you BOLSTER, you use your mech’s formidable processing power to enhance another character’s systems.<br>To BOLSTER, choose a character within SENSORS. They receive +2 Accuracy on the next skill check or save they make between now and the end of their next turn. Characters can only benefit from one BOLSTER at a time.",
    synergy_locations: [
      "bolster"
    ],
    confirm: [
      "UPLINK ESTABLISHED.",
      "PARALLELIZING COMBAT ALGORITHMS"
    ]
  },
  {
    id: "act_scan",
    name: "Scan",
    activation: "Quick Tech",
    terse: "Perform a deep scan on an enemy",
    detail: "When you SCAN, you use your mech’s powerful sensors to perform a deep scan on an enemy.<br>To SCAN, choose a character or object within SENSORS and line of sight, then ask the GM for one of the following pieces of information, which they must answer honestly:<br>• Your target’s weapons, systems, and full statistics (HP, SPEED, EVASION, ARMOR, MECH SKILLS, and so on).<br>• One piece of hidden information about the target, such as confidential cargo or data, current mission, the identity of the pilot, and so on.<br>• Generic or public information about the target that can be pulled from an info bank or records, such as the model number of a mech.<br>Any information gathered is only current at the time of the SCAN – if the target later takes damage, for instance, you don’t receive an update.",
    synergy_locations: [
      "scan"
    ],
    confirm: [
      "ESTABLISHING TARGET LOCK.",
      "LOCK CONFIRMED. FIRING SOLUTIONS CALCULATED."
    ]
  },
  {
    id: "act_lockon",
    name: "Lock On",
    activation: "Quick Tech",
    terse: "Digitally mark a target",
    detail: "When you LOCK ON, you digitally mark a target, lighting them up for your teammates’ targeting systems and exposing weak points.<br>To LOCK ON, choose a character within SENSORS and line of sight. They gain the LOCK ON condition. Any character making an attack against a character with LOCK ON may choose to gain +1 Accuracy on that attack and then clear the LOCK ON condition after that attack resolves. This is called consuming LOCK ON.",
    synergy_locations: [
      "lock_on"
    ],
    confirm: [
      "ESTABLISHING TARGET LOCK.",
      "LOCK CONFIRMED. FIRING SOLUTIONS CALCULATED."
    ]
  },
  {
    id: "act_invade",
    name: "Invade",
    activation: "Quick Tech",
    terse: "Mount a direct electronic attack against a target",
    detail: "When you INVADE, you mount a direct electronic attack against a target. To INVADE, make a tech attack against a character within SENSORS and line of sight. On a success, your target takes 2 heat and you choose one of the INVASION options available to you. FRAGMENT SIGNAL is available to all characters, and additional options are granted by certain systems and equipment with the INVADE tag.  You can also INVADE willing allied characters to create certain effects. If your target is willing and allied, you are automatically successful, it doesn’t count as an attack, and your target doesn’t take any heat."
  },
  {
    id: "act_inv_fragment_signal",
    name: "Fragment Signal",
    activation: "Invade",
    terse: "IMPAIR and SLOW a character until the end of their next turn.",
    detail: "You feed false information, obscene messages, or phantom signals to your target’s computing core. They become IMPAIRED and SLOWED until the end of their next turn.",
    confirm: [
      "SIGNAL FRAGMENTATION IN PROGRESS."
    ]
  },
  {
    id: "act_hide",
    name: "Hide",
    activation: "Quick",
    terse: "Obscure the position of your mech, becoming HIDDEN and unable to be identified, precisely located, or be targeted directly by attacks or hostile actions",
    detail: "When you HIDE, you obscure the position of your mech in order to reposition, avoid incoming fire, repair, or ambush.<br>To HIDE, you must not be ENGAGED and you must either be outside of any enemies’ line of sight, obscured by sufficient cover, or invisible. If you HIDE while meeting one of these criteria, you gain the HIDDEN status.<br>Hard cover is sufficient to HIDE as long as it is large enough to totally conceal you, but soft cover is only sufficient if you are completely inside an area or zone that grants soft cover – many systems and talents that grant soft cover or plain old obscurement just don’t provide enough to hide behind!<br>If you are INVISIBLE, you can always HIDE, regardless of cover, unless you’re ENGAGED.<br>The exact location of HIDDEN targets cannot be identified and they cannot be targeted directly by attacks or hostile actions, but they can still be hit by attacks that affect an area. Although NPCs cannot perfectly locate a HIDDEN character, they might still know an approximate location. Thus, an NPC could flush an area with a flamethrower even if they don’t know exactly where a HIDDEN player is lurking.<br>Additionally, other characters ignore engagement with you while you are HIDDEN – it’s assumed you’re trying to stay stealthy.<br>You cease to be HIDDEN if you make an attack (melee, ranged, or tech) or if your mech takes a hostile action (such as forcing a target to make a save). Using BOOST or taking reactions with your mech also causes you to lose HIDDEN. Other actions can be taken as normal.<br>You also immediately lose HIDDEN if your cover disappears or is destroyed, or if you lose cover due to line of sight (e.g., if a mech jumps over a wall and can now draw unbroken line of sight to you). If you’re hiding while INVISIBLE, you lose HIDDEN when you cease to be INVISIBLE unless you are in cover.",
    mech: !0,
    pilot: !0,
    synergy_locations: [
      "hide"
    ],
    confirm: [
      "SENSOR SIGNATURE OBSCURED. COMMS IN TIGHTBEAM ONLY. SIGHTLINES CLEAR."
    ]
  },
  {
    id: "act_search",
    name: "Search",
    activation: "Quick",
    terse: "Look for a hidden target.",
    detail: "When you SEARCH, you attempt to identify hidden characters. To SEARCH in a mech, choose a character within your SENSORS that you suspect is HIDDEN and make a contested SYSTEMS check against their AGILITY.<br>To SEARCH as a pilot on foot, make a contested skill check, adding bonuses from triggers as normal. This can be used to reveal characters within RANGE 5.<br>Once a HIDDEN character has been found using SEARCH, they immediately lose HIDDEN and can be located again by any character.",
    mech: !0,
    pilot: !0,
    synergy_locations: [
      "search"
    ]
  },
  {
    id: "act_activate_quick",
    name: "Quick Activation",
    activation: "Quick",
    terse: "Activate a system or piece of gear that uses a quick action.",
    detail: "When you ACTIVATE, you use a system or piece of gear that requires either a quick or full action. These systems have the QUICK ACTION or FULL ACTION tags. You can ACTIVATE any number of times a turn but can’t ACTIVATE the same system more than once unless you can do so as a free action.",
    mech: !0,
    pilot: !0
  },
  {
    id: "act_eject",
    name: "Eject",
    activation: "Quick",
    terse: "Eject from your mech, flying 6 spaces in the direction of your choice.",
    detail: "You can also EJECT as a quick action, flying 6 spaces in the direction of your choice; however, this is a single-use system for emergency use only – it leaves your mech IMPAIRED. Your mech remains IMPAIRED and you cannot EJECT again until your next FULL REPAIR.",
    synergy_locations: [
      "eject"
    ],
    confirm: [
      "SAFETY PROTOCOLS DISABLED. MANUAL CONTROL MODE SUSPENDED. EXPLOSIVE BOLTS PRIMED.",
      "GOOD LUCK, PILOT."
    ]
  },
  {
    id: "act_prepare",
    name: "Prepare",
    activation: "Quick",
    terse: "Ready a quick action for a specified trigger. Until the start of your next turn, when it is triggered, you can take your prepared action as a reaction.Your preparation counts as taking the action, so it follows all usual restrictions on that action and on taking multiple actions.",
    detail: "When you PREPARE, you get ready to take an action at a specific time or when a specific condition is met (a more advantageous shot, for example).<br>As a quick action, you can PREPARE any other quick action and specify a trigger. Until the start of your next turn, when it is triggered, you can take this action as a reaction.<br>The trigger for your prepared action must be phrased as “When X, then Y,” where X is a reaction, action or move taken by a hostile or allied character and Y is your action. For example, “when an allied character moves adjacent to me, I want to throw a smoke grenade,” or “when a hostile character moves adjacent to me, I want to ram them”.<br>Your preparation counts as taking the action, so it follows all usual restrictions on that action and on taking multiple actions. You can’t, for example, SKIRMISH and then prepare to SKIRMISH again; you also can’t move and then PREPARE to SKIRMISH with an ORDNANCE weapon, which normally needs to be fired before moving or doing anything else on your turn. Additionally, after you PREPARE an action, you can’t move or take any other actions or reactions until the start of your next turn or until your action has been triggered, whichever comes first.<br>Although you can’t take reactions while holding a prepared action, you can take them normally after it has been triggered. You can also drop your prepared action, allowing you to take reactions as usual. If the trigger condition isn’t met, you lose your prepared action.<br>When you PREPARE, it is visible to casual observers (e.g., you clearly take aim or cycle up systems).",
    mech: !0,
    pilot: !0,
    synergy_locations: [
      "prepare"
    ],
    confirm: [
      "COMMAND QUEUED, STANDING BY."
    ]
  },
  {
    id: "act_self_destruct",
    name: "Self Destruct",
    activation: "Quick",
    terse: "As a last ditch measure, set your reactor to go critical and explode.",
    detail: "When you SELF DESTRUCT, you overload your mech’s reactor in a final, catastrophic play if there’s no other option for escape or you deem your sacrifice necessary.<br>You can SELF DESTRUCT as a quick action, initiating a reactor meltdown. At the end of your next turn, or at the end of one of your turns within the following two rounds (your choice), your mech explodes as though it suffered a reactor meltdown. The explosion annihilates your mech, killing anyone inside and causing a BURST 2 explosion that deals 4d6 explosive damage. Characters caught in the explosion that succeed on an AGILITY save take half of this damage.",
    synergy_locations: [
      "self_destruct"
    ]
  },
  {
    id: "act_shut_down",
    name: "Shut Down",
    activation: "Quick",
    terse: "Shut down your mech as a desperate measure, to end system attacks, regain control of AI, and cool your mech. The mech is STUNNED until rebooted via the BOOT UP action.",
    detail: "When you SHUT DOWN, your mech powers completely off and enters a rest state. It’s always risky to do in the field, but it’s sometimes necessary to prevent a catastrophic systems overload or an NHP cascading.<br>You can SHUT DOWN your mech as a quick action. Your mech takes the SHUT DOWN status, with these effects:<br>• all heat is cleared, as is EXPOSED;<br>• any cascading NHPs return to a normal state;<br>• any statuses or conditions affecting the mech caused by tech actions, such as LOCK ON, immediately end;<br>• the mech gains IMMUNITY to all tech actions and attacks, including any from allied characters;<br>• the mech is STUNNED indefinitely. Nothing can prevent this condition, and it remains until the mech ceases to be SHUT DOWN.<br>The only way to remove the SHUT DOWN status is to BOOT UP the mech.",
    synergy_locations: [
      "shut_down"
    ],
    confirm: [
      "ALERT: EMERGENCY SHUTDOWN",
      "STOPPING GMS/VCTRL.MANUAL",
      "KILLING ALL REMAINING PROCESSES",
      "confirmGING RESOLVER STATE",
      ">://cc.main.term",
      ">:// _"
    ]
  },
  {
    id: "act_reload",
    name: "Reload",
    activation: "Quick",
    terse: "Reload one weapon as a pilot.",
    detail: "When you RELOAD, you reload one Pilot Weapon with the LOADING tag, making it usable again.",
    pilot: !0,
    synergy_locations: [
      "reload"
    ]
  },
  {
    id: "act_barrage",
    name: "Barrage",
    activation: "Full",
    terse: "Attack with two weapons, or attack with a single superheavy weapon.",
    detail: "When you BARRAGE, you attack with two weapons, or with one SUPERHEAVY weapon.<br>To BARRAGE, choose your weapons and either one target or different targets – within range – then make an attack with each weapon.<br>• In addition to your primary attacks, you may also attack with an AUXILIARY weapon on each mount that was fired, so long as the AUXILIARY weapon hasn’t yet been fired this action. These AUXILIARY weapons don’t deal bonus damage.<br>• SUPERHEAVY weapons can only be fired as part of a BARRAGE.",
    synergy_locations: [
      "barrage"
    ]
  },
  {
    id: "act_full_tech",
    name: "Full Tech",
    activation: "Full",
    terse: "Choose and perform two Quick Tech options, or perform a full tech action. If you choose two Quick Tech options, you can choose the same option multiple times.",
    detail: "When you use FULL TECH, you perform multiple tech actions or a single, more complex action.<br>To use FULL TECH, choose two QUICK TECH options or a single system or tech option that requires FULL TECH to activate. If you choose two QUICK TECH options, you can choose the same option multiple times.",
    synergy_locations: [
      "full_tech"
    ]
  },
  {
    id: "act_stabilize",
    name: "Stabilize",
    activation: "Full",
    terse: "Heal and cool down your mech, reload, or attempt to end conditions affecting it.",
    detail: "When you STABILIZE, you enact emergency protocols to purge your mech’s systems of excess heat, repair your chassis where you can, or eliminate hostile code.<br>To STABILIZE, choose one of the following:<br>• Cool your mech, clearing all heat and EXPOSED.<br>• Mark 1 REPAIR to restore all HP.<br>Additionally, choose one of the following:<br>• Reload all LOADING weapons.<br>• Clear any burn currently affecting your mech.<br>• Clear a condition that wasn’t caused by one of your own systems, talents, etc.<br>• Clear an adjacent allied character’s condition that wasn’t caused by one of their own systems, talents, etc.",
    synergy_locations: [
      "stabilize"
    ]
  },
  {
    id: "act_disengage",
    name: "Disengage",
    activation: "Full",
    terse: "Disengage safely from a dangerous situation. Until the end of your current turn, you ignore engagement and your movement does not provoke reactions.",
    detail: "When you DISENGAGE, you attempt to extricate yourself safely from a dangerous situation, make a steady and measured retreat, or rely on your mech’s agility to slip in and out of threat ranges faster than an enemy can strike.<br>Until the end of your current turn, you ignore engagement and your movement does not provoke reactions.",
    synergy_locations: [
      "disengage"
    ],
    confirm: [
      "DISENGAGE SUCCESSFUL. NEW EXTRICATION VECTORS AVAILABLE."
    ]
  },
  {
    id: "act_improvised_attack",
    name: "Improvised Attack",
    activation: "Full",
    terse: "Attack with a fist, rifle butt, or improvised weapon in melee.",
    detail: "When you make an IMPROVISED ATTACK, you attack with a rifle butt, fist, or another improvised melee weapon. You can use anything from the butt of a weapon to a slab of concrete or a length of hull plating – the flavor of the attack is up to you!<br>To make an IMPROVISED ATTACK, make a melee attack against an adjacent target. On a success, they take 1d6 kinetic damage.",
    synergy_locations: [
      "improvised_attack"
    ]
  },
  {
    id: "act_activate_full",
    name: "Full Activation",
    activation: "Full",
    terse: "Activate a system or piece of gear that uses a full action.",
    detail: "When you ACTIVATE, you use a system or piece of gear that requires either a quick or full action. These systems have the QUICK ACTION or FULL ACTION tags. You can ACTIVATE any number of times a turn but can’t ACTIVATE the same system more than once unless you can do so as a free action.",
    mech: !0,
    pilot: !0,
    synergy_locations: [
      "full_activation"
    ]
  },
  {
    id: "act_boot_up",
    name: "Boot Up",
    activation: "Full",
    terse: "Fire up your mech from Shut Down.",
    detail: "You can BOOT UP a mech that you are piloting as a full action, clearing SHUT DOWN and restoring your mech to a powered state.",
    synergy_locations: [
      "boot_up"
    ],
    confirm: [
      "COMPANION/CONCIERGE UNIT INITIALIZING",
      "GMS COMP/CON Unit Mk XI Rev 11.4.1c",
      "5016.8.22 General Massive Systems // Please Operate Responsibly",
      "RESTORING PROCESSES AT ret.n@142::ACCORD-6",
      "INTERFACE ONLINE. REBOOT SUCCESSFUL."
    ]
  },
  {
    id: "act_mount",
    name: "Mount",
    activation: "Full",
    terse: "Get in to your mech.",
    pilot: !0,
    detail: "When you MOUNT, you climb onto a mech. Mounting is the preferred term among most pilots. You don’t “get in” or “climb aboard” – you mount. You’re the cavalry, after all.<br>You can MOUNT as a full action. You must be adjacent your mech to MOUNT. <br>Additionally, you can also MOUNT willing allied mechs or vehicles. When you do so, move into the same space and then move with them."
  },
  {
    id: "act_dismount",
    name: "Dismount",
    activation: "Full",
    terse: "Get out of your mech.",
    detail: "When you DISMOUNT, you climb off of a mech. Dismounting is the preferred term among most pilots.<br>You can DISMOUNT as a full action. When you DISMOUNT, you are placed in an adjacent space – if there are no free spaces, you cannot DISMOUNT.<br>Additionally, you can also DISMOUNT willing allied mechs or vehicles you have MOUNTED.",
    synergy_locations: [
      "dismount"
    ],
    confirm: [
      "LOCKS DISENGAGED. MANUAL CONTROL MODE SUSPENDED."
    ]
  },
  {
    id: "act_skill_check",
    name: "Skill Check",
    activation: "Full",
    terse: "Perform an activity with a clear goal that would take a skill check.",
    detail: "When you make a SKILL CHECK, you undertake an activity that isn’t covered by other actions but has a clear goal and is sufficiently complex to require a roll. The parameters and outcomes of SKILL CHECKS are up to the GM, but they must be involved enough to require a full action. If you want to do something that can be done quickly, no action is required.<br>Examples of SKILL CHECKS:<br>• Bruja, on foot, wants to open a locked door. The GM asks her to make a SKILL CHECK and decides that Bruja can get a bonus from her ‘Hack or Fix’ trigger.<br>• Pan wants to jump a crevasse in his mech that’s wider than he can normally manage. The GM decides to allow him to try it with AGILITY.<br>• Zaid wants to lift a heavy boulder with his mech, to clear a passage. The GM decides this is probably a full action and requires a SKILL CHECK with HULL.",
    mech: !0,
    pilot: !0,
    synergy_locations: [
      "skill_check"
    ]
  },
  {
    id: "act_fight",
    name: "Fight",
    activation: "Full",
    terse: "Attack with one weapon as a pilot.",
    detail: "When you FIGHT, you attack (melee or ranged) with one weapon.<br>To FIGHT, choose a weapon and attack a target within RANGE or THREAT and line of sight as a full action. Ranged attacks are affected by cover and receive +1 difficulty if you’re ENGAGED.",
    pilot: !0
  },
  {
    id: "act_jockey",
    name: "Jockey",
    activation: "Full",
    terse: "Attempt to attack a mech on foot as a pilot.",
    detail: "When you JOCKEY, you aggressively attack an enemy mech while on foot. It cannot be emphasized enough how foolhardy and dangerous this is.<br>To JOCKEY, you must be adjacent to a mech. As a full action, make a contested skill check against the mech, using GRIT (or a relevant trigger, at the GM’s discretion). The mech contests with HULL. On a success, you manage to climb onto the mech, sharing its space and moving with it. The mech can attempt to shake you off by succeeding on another contested skill check as a full action; alternatively, you can jump off as part of your movement on your turn.<br>When you successfully JOCKEY, choose one of the following options:<br>• DISTRACT: The mech is IMPAIRED and SLOWED until the end of its next turn.<br>• SHRED: Deal 2 heat to the mech by ripping at wiring, paneling, and so on.<br>• DAMAGE: Deal 4 kinetic damage to the mech by attacking joints, hatches, and so on.<br>On each of your subsequent turns, you can continue to choose from the options above as full actions, as long as you don't stop jockeying (or get thrown off).",
    pilot: !0
  },
  {
    id: "act_brace",
    name: "Brace",
    activation: "Reaction",
    terse: "Brace your mech for impact, reducing damage at the cost of your next turn’s actions.",
    detail: "When you BRACE, you ready your mech against incoming fire.<br>Brace<br>Reaction, 1/round<br>Trigger: You are hit by an attack and damage has been rolled.<br>Effect: You count as having RESISTANCE to all damage, burn, and heat from the triggering attack, and until the end of your next turn, all other attacks against you are made at +1 difficulty.<br>Due to the stress of bracing, you cannot take reactions until the end of your next turn and on that turn, you can only take one quick action – you cannot OVERCHARGE, move normally, take full actions, or take free actions."
  },
  {
    id: "act_overwatch",
    name: "Overwatch",
    activation: "Reaction",
    terse: "Attack a close-by target attempting to move.",
    detail: "When you OVERWATCH, you control and defend the space around your mech from enemy incursion through pilot skill, reflexes, or finely tuned subsystems.<br>Unless specified otherwise, all weapons default to 1 THREAT.<br>Overwatch<br>Reaction, 1/round<br>Trigger: A hostile character starts any movement (including BOOST and other actions) inside one of your weapons’ THREAT.<br>Effect: Trigger OVERWATCH, immediately using that weapon to SKIRMISH against that character as a reaction, before they move.",
    mech: !0,
    pilot: !0
  },
  {
    id: "act_free_action",
    name: "Free Action",
    activation: "Free",
    terse: "Characters may perform any number of Free Actions on their turn.",
    detail: "Free actions are often granted by systems, talents, gear, or OVERCHARGE. Characters may perform any number of free actions on their turn, but only on their turn, and only those granted to them. Free actions can always be used to make duplicate actions.<br>The most common type of free action is a PROTOCOL, which is granted by gear or systems and can be activated or deactivated only at the start of a turn. Each Protocol can only be taken once per turn.",
    hide_active: !0
  },
  {
    id: "act_buy_some_time",
    name: "Buy Some Time",
    activation: "Downtime",
    terse: "Try and stave off a reckoning or extend your window of opportunity.",
    detail: "When you BUY SOME TIME, you try to stave off a reckoning, extend a window of opportunity, or merely buy some time and breathing room for you and your group. You might be trying to dodge some heat, survive stranded in the wilderness, or cause a distraction so another plan can reach its climax. You can use that distraction or bought time as RESERVES for the next mission.<br>Describe your plan and roll:<br>On 9 or less, you can only buy a little time, and only if drastic measures are taken right now. Otherwise, whatever you’re trying to stave off catches up to you.<br>On 10–19, you buy enough time, but the situation becomes precarious or desperate. Next time you get this result for the same situation, treat it as 9 or less.<br>On 20+, you buy as much time as you need, until the next downtime session. Next time you get this result for the same situation, treat it as 10–19."
  },
  {
    id: "act_gather_information",
    name: "Gather Information",
    activation: "Downtime",
    terse: "Investigate, do research, or keep an eye on something.",
    detail: "When you GATHER INFORMATION, you poke your nose around, perhaps where it doesn’t belong, and investigate something – conducting research, following up on a mystery, tracking a target, or keeping an eye on something. You might head to a library or go undercover to learn what you can. Whatever it involves, you’re trying to GATHER INFORMATION on a subject of your choice. You can use information gained as RESERVES.<br>Name your subject and method, and roll:<br>On 9 or less, choose one:<br>• You get what you’re looking for, but it gets you into trouble straight away.<br>• You get out now and avoid trouble.<br>On 10–19, you find what you’re looking for, but choose one:<br>• You leave clear evidence of your rummaging.<br>• You have to dispatch someone or implicate someone innocent to avoid attention.<br>On 20+, you get what you’re looking for with no complications."
  },
  {
    id: "act_get_a_damn_drink",
    name: "Get a Damn Drink",
    activation: "Downtime",
    terse: "Blow off some steam and generally get into trouble.",
    detail: "When you GET A DAMN DRINK, you blow off some steam, carouse, and generally get into trouble. You might be trying to make connections, collect gossip, forge a reputation, or even just to forget what happened on the last mission. There’s usually trouble.<br>State your intention and roll:<br>On 9 or less, decide whether you had good time or not; either way, you wake up in a gutter somewhere with only one remaining:<br>• Your dignity.<br>• All of your possessions.<br>• Your memory.<br>On 10–19, gain one as RESERVES and lose one:<br>• A good reputation.<br>• A friend or connection.<br>• A useful item or piece of information.<br>• A convenient opportunity.<br>On 20+, gain two from the 10–19 list as RESERVES and don’t lose anything.<br>You can only make this action where there’s actually a drink to get (e.g., in a town, station, city, or some other populated area), or some other kind of entertainment."
  },
  {
    id: "act_get_connected",
    name: "Get Connected",
    activation: "Downtime",
    terse: "Make connections, ask for help, or drum up support.",
    detail: "When you GET CONNECTED, you make connections, call in favors, ask for help, or drum up support for a course of action. You can use your contacts’ resources or aid as RESERVES for the next mission.<br>Name your contact and roll:<br>On 9 or less, your contact will help you, but you’ve got to do a favor or make good on a promise right now. If you don’t, they won’t help you.<br>On 10–19, your contact will help you, but you’ve got to do a favor or make good on a promise afterwards. If you don’t follow through, treat this result as 9 or less next time you get it for the same organization.<br>On 20+, your contact will help you, no strings attached. Treat this result as 10–19 next time you get it for the same organization.<br>To take this action, you need to be within comms range or somewhere you can have a good old-fashioned face-to-face conversation."
  },
  {
    id: "act_get_creative",
    name: "Get Creative",
    activation: "Downtime",
    terse: "Tweak something or attempt to make something new.",
    detail: "When you GET CREATIVE, you tweak something or try to make something new – either a physical item, or a piece of software. Once finished, you can use your new creation as RESERVES.<br>Describe your project and roll:<br>On 9 or less, you don’t make any progress on your project. Next time you get this result for the same project, treat it as a 10–19.<br>On 10–19, you make progress on your project, but don’t quite finish it. You can finish it during your next downtime without rolling, but choose the two things you’re going to need:<br>• Quality materials.<br>• Specific knowledge or techniques.<br>• Specialized tools.<br>• A good workspace.<br>On 20+, you finish your project before the next mission. If it’s especially complex, treat this as 10–19, but only choose one.<br>Your project doesn’t have to be something from the gear list, but it usually can’t be as impactful as a piece of mech gear."
  },
  {
    id: "act_get_focused",
    name: "Get Focused",
    activation: "Downtime",
    terse: "Practice, learn, meditate, or call on a teacher.",
    detail: "When you GET FOCUSED, you focus on increasing your own skills, training, and self-improvement. You might practice, learn, meditate, or call on a teacher.<br>Name what you want to learn or improve (e.g., a skill, technique, academic subject, or language). The GM will give your pilot a new +2 trigger based on your practice and training. For example, the trigger could be +2 Playing Chess or +2 Dancing. You can also improve a trigger from +2 to +4 or +4 to +6 by taking this downtime action.<br>This action can be used to learn something like starship piloting, cooking, chess, boxing, history, or etiquette. It should usually be a specific non-martial skill or something personal to your character."
  },
  {
    id: "act_get_organized",
    name: "Get Organized",
    activation: "Downtime",
    terse: "Start, run, or improve an organization.",
    detail: "When you GET ORGANIZED, you start, run, or improve an organization, business, or other venture.<br>State your organization’s purpose or goal, and choose a FOCUS: military, scientific, academic, criminal, humanitarian, industrial, entertainment, or political. It begins with +2 in either EFFICIENCY or INFLUENCE and +0 in the other, with a maximum of +6. EFFICIENCY determines how effectively your organization conducts activities within its scope (e.g., a military organization with high efficiency would be good at combat). INFLUENCE is its size, reach, wealth, and reputation.<br>When your organization directly assists with an activity, you may add either its EFFICIENCY or INFLUENCE as a statistic bonus to your skill check. EFFICIENCY is used when performing activities related to your organization’s FOCUS. INFLUENCE is used when acquiring assets, creating opportunities, or swaying public opinion. Advantages gained with the help of your organization can be used as RESERVES.<br>Each downtime after the first, roll 1d20:<br>On 9 or less, choose one or your organization folds immediately:<br>• Your organization loses 2 EFFICIENCY and 2 INFLUENCE, to a minimum of 0. If both are already at 0, you may not choose this.<br>• Your organization needs to pay debts, make an aggressive move, or get bailed out. You choose which, and the GM decides what that looks like.<br>On 10–19, your organization is stable. It gains +2 EFFICIENCY or INFLUENCE, to a maximum of +6.<br>On 20+, your organization gains +2 EFFICIENCY and +2 INFLUENCE, to a maximum of +6.<br>You must roll for your organization every downtime after starting one, but the roll doesn’t count as a downtime action."
  },
  {
    id: "act_power_at_a_cost",
    name: "Power at a Cost",
    activation: "Downtime",
    terse: "Gain rewards, opportunities, or resources.",
    detail: "When you seek POWER AT A COST, you’re trying to get your hands on something.<br>Name what you want. You can definitely get it, but depending on the outlandishness of the request, the GM chooses one or two:<br>• It’s going to take a lot more time than you thought.<br>• It’s going to be really damn risky.<br>• You’ll have to have to give something up or leave something behind (e.g., wealth, resources, allies).<br>• You’re going to piss off someone or something important and powerful.<br>• Things are going to go wildly off-plan.<br>• You’ll need more information to proceed safely.<br>• It’s going to fall apart damn soon.<br>• You’ll need more resources, but you know where to find them.<br>• You can get something almost right: a lesser version, or less of it.<br>This is a straightforward way to acquire RESERVES, opportunities, and additional resources. You might want something directly useful for a mission; some‐ thing more abstract, like time, safety, information, allies, or support; something practical, like a base of operations, materials, shelter, or food; or, even something as simple as a damn pack of cigarettes.<br>You can also use POWER AT A COST during missions for similar effects. Other downtime actions generally can’t be used during missions, but your group can adapt them if desired."
  },
  {
    id: "act_scrounge_and_barter",
    name: "Scrounge and Barter",
    activation: "Downtime",
    terse: "Try and get your hands on some gear or asset.",
    detail: "When you SCROUNGE AND BARTER, you try to get your hands on some gear or an asset by dredging the scrapyard, chasing down rumors, bartering in the local market, or hunting around.<br>You might want some better pilot gear, a vehicle, narcotics, goods, or other sundries. It needs to be something physical, but doesn’t necessarily have to be on the gear list. If you get it, you can take it on the next mission as RESERVES.<br>Name what you want and roll:<br>On 9 or less, you get what you want, but choose one:<br>• It was stolen, probably from someone who’s looking for it.<br>• It’s degraded, old, filthy, or malfunctioning.<br>• Someone else has it right now and won’t give it up without force or convincing.<br>On 10–19, you get what you want, but choose the price you need to pay:<br>• Time.<br>• Dignity.<br>• Reputation.<br>• Health, comfort, and wellness. On 20+, you get what you’re looking for, no problem."
  }
], require$$1 = [
  {
    id: "pbg_celebrity",
    name: "Celebrity",
    description: "You were a figure in the public eye. <i>Were you an actor? A singer? An artist? An athlete? A politician? The public face of a corporate or military advertising campaign?</i><br>In your old life, you couldn’t go anywhere without the paparazzi hovering nearby. <i>How are you adjusting to your new life as a pilot? Did you volunteer, or were you conscripted? Can you still practice your art, craft, or profession, or does the rigid military structure make it difficult to pull double-duty?</i>",
    skills: [
      "sk_charm",
      "sk_pull_rank",
      "sk_lead_or_inspire",
      "sk_threaten"
    ]
  },
  {
    id: "pbg_colonist",
    name: "Colonist",
    description: "You were a colonist on the frontier; one of the first generations to be born on a newly settled world. You’re used to the demands of frontier life and well-aware of the precarious position most homesteaders live in. <i>Why did you leave? Were you forced to flee, becoming a refugee? Did you choose to enlist?</i><br>And then there’s the home you left behind: <i>Is the colony still there? Your family? How familiar are you with the luxuries of core worlds? Do you find other cultures difficult to deal with, or are you fascinated by the wealth of humanity’s cultural expression? Do you carry reminders of home, or do you curse its name? Was your colony in a galactic backwater, or is it a fresh colony in a populated, high-traffic area of space? Where is your colony located?</i>",
    skills: [
      "sk_word_on_the_street",
      "sk_spot",
      "sk_survive",
      "sk_patch"
    ]
  },
  {
    id: "pbg_criminal",
    name: "Criminal",
    description: "You were a criminal: small-time, master, or something in between. <i>Did you work for corporate clients? A criminal organization? Yourself? Did you mug pedestrians in the dark underbelly of a massive city, or did you slip, unnoticed, into corporate databases to steal data? Did you do it for personal gain, or just to feed your family? How did you find yourself in this life, and how did you become a pilot? Did you operate with a code of honor? Were you loyal to a single family, a small crew, a politician, or an ideology? Did you operate in the shadows, or was your work carried out in the daylight, unafraid of consequences?</i><br>There must be a reason you decided to get out. <i>Was it a bad job, or maybe witness protection? Are your former employers or crew still around? What connections do they have, and how do they feel about you now? What – if anything – haunts you?</i><br>Note: for a more classic “Western” flavor, see the Outlaw Background.<i></i>",
    skills: [
      "sk_threaten",
      "sk_apply_fists_to_faces",
      "sk_word_on_the_street",
      "sk_take_control"
    ]
  },
  {
    id: "pbg_far_field_team",
    name: "Far-Field Team",
    description: "You were a member of a Union far-field team (FFT), working on the frontier and the edge of civilization to evaluate strange worlds and planetoids for anomalies, discoveries, and habitability. <i>What have you seen on the wild frontier? How many worlds have you traveled? Were you part of a small team, or a large one? Where is your homeworld?</i><br>Something must drive you to explore: <i>Is it a grail world you seek? An Eden among the stars? Was your interest in the frontier mystical, scientific, based on old-fashioned curiosity, or spurred on by something else? Maybe there was a legend you heard, out there in the dark, that you long to find, or that you’re terrified you might encounter? What secrets – if any – have you encountered on your long-range surveys? Do you remain in contact with your old team members, if they’re still alive?</i><br>As a former (or current) part of an FFT, you're Cosmopolitan: <i>When was “your time”? How separate do you feel from the passage of time?</i>",
    skills: [
      "sk_survive",
      "sk_investigate",
      "sk_spot",
      "sk_charm"
    ]
  },
  {
    id: "pbg_hacker",
    name: "Hacker",
    description: "You specialized in information warfare and data espionage, either for your own gain or the benefit of your employers. To you, the omninet – the faster-than-light information web that connects Union worlds – is home. <i>How did you come to this life? Did you grow up plugged into the omninet, or did you come to it late? How well-versed are you in the omninet’s hidden places, tricks, and secrets? How notorious were you before you became a pilot? Do people still whisper your name? Do other hackers remember you, and are you celebrated or cursed among them?</i><br>It wasn’t just the omninet that you hacked, though. <i>How adept are you at manipulating other networks? Can you manipulate discrete systems, genetic code, or some other type of environment, digital or mechanical? What secrets have you gained access to?</i>",
    skills: [
      "sk_act_unseen_or_unheard",
      "sk_get_a_hold_of_something",
      "sk_hack_or_fix",
      "sk_invent_or_create"
    ]
  },
  {
    id: "pbg_mechanic",
    name: "Mechanic",
    description: "Grease monkey, wrench, working joe; you were a mechanic prior to becoming a pilot. <i>Did you work in space, swaddled in an EVA rig, patching up damaged starships? Or were you planetside, tuning trucks and haulers in a motor pool? Did you repair battle-torn mechs, dreaming that you might one day pilot your own? Did you own a garage, or did you work for someone? Were you military, corporate, part of a caste, or a union member? How handy are you in the field? Is there a side project you've been working on?</i>",
    skills: [
      "sk_hack_or_fix",
      "sk_get_somewhere_quickly",
      "sk_get_a_hold_of_something",
      "sk_blow_something_up"
    ]
  },
  {
    id: "pbg_medic",
    name: "Medic",
    description: "You were a medical specialist in your old life. <i>How did you wind up piloting a mech? What was your specialty? Did you work in research, care, or trauma? Did you love the life and take your duty seriously, or did you see yourself as an organic mechanic?</i><br>You might have worked in a colony or on a core world, in private practice, for a corporation, or on a noble family’s payroll: <i>Did you operate a small frontier practice, or work in a blink station urgent care center, or in a massive hospital campus? Were you a whitecoat or an EMT? Is there a memory that haunts you, or one that gives you comfort?</i>",
    skills: [
      "sk_patch",
      "sk_assault",
      "sk_read_a_situation",
      "sk_stay_cool"
    ]
  },
  {
    id: "pbg_mercenary",
    name: "Mercenary",
    description: "As a soldier of fortune, you lived by the motto, “have gun, will travel.” You and your kit were available to the highest bidder. <i>Did you work alone or with a crew? Did your company have a ship? Was this when you started piloting mechs of your own? What was your code of honor, if you had one?</i><br>Something pushed you to the mercenary life: <i>Was it the promise of riches? Desire for power? Adventure? Desperation?</i><br>For some reason, you left that life behind: <i>Why? Was there a job that went bad, or one that really was that legendary “one last job”? Are your old company mates still kicking around? Was there a rival company, or other enemies you made? Do you remember that time fondly, or do you never speak of it?</i>",
    skills: [
      "sk_threaten",
      "sk_blow_something_up",
      "sk_take_control",
      "sk_apply_fists_to_faces"
    ]
  },
  {
    id: "pbg_nhp_specialist",
    name: "NHP Specialist",
    description: "You were closely involved in the study, creation, or maintenance of a prime non-human person. Nonhuman persons, or NHPs, are complex artificial intelligences. As a prime NHP, the one you were associated with was even more complex than most. <i>Did you interact with that entity like a scientist or engineer, or more like a priest or shaman? Do you have a personal connection to them, after all this time? How do clones of that NHP perceive you? And now that you’re a pilot, how do you feel about non-human intelligence?</i>",
    skills: [
      "sk_stay_cool",
      "sk_read_a_situation",
      "sk_invent_or_create",
      "sk_investigate"
    ]
  },
  {
    id: "pbg_noble",
    name: "Noble",
    description: "You are a member of your world’s aristocracy, destined from birth to ascend to power. <i>From what authority does this birthright come? A god? An ancestor? An ancient text? A complex annual rotation? How is power passed down from one generation to the next?</i><br>Your noble status came from somewhere: <i>Are you the first in your family to receive a title of nobility, the last of your house, or the scion of a well-established line? Are you the heir, or just a middle child? What’s your relationship with your noble parents?</i><br>Whatever privileges you might have received at home, you found that Union disregards titles in its armed forces; your prior status is just background noise, unless you return home or belong to a group that recognizes nobility. <i>How did you take this change?</i>",
    skills: [
      "sk_pull_rank",
      "sk_lead_or_inspire",
      "sk_read_a_situation",
      "sk_show_off"
    ]
  },
  {
    id: "pbg_outlaw",
    name: "Outlaw",
    description: 'You came from humble beginnings, born on the edge of cultivated space or beneath the looming towers of core worlds – forgotten until you reached out and took what was owed. Some call you criminal, thief, or outlaw, but you just tell it as it is: if they hadn’t denied you bread, you wouldn’t have had to take it. <i>Were you a brute or a raconteur? A charmer or a monster? Were your actions motivated by ideology, need, desire, or some combination of those three? Who defined you as an “outlaw", and who saw you as a hero? Is there a bounty on your head?</i>',
    skills: [
      "sk_show_off",
      "sk_take_someone_out",
      "sk_charm",
      "sk_survive"
    ]
  },
  {
    id: "pbg_penal_colonist",
    name: "Penal Colonist",
    description: "A long time ago, you were exiled to a penal colony for a sentence of hard labor. When the Third Committee abolished all penal colonies, your prison-planet was – in theory – “liberated”. Unfortunately, nothing much changed until Union’s relief ships finally arrived. Now free in practice as well as theory, places that had once been off-limits were made open to you: <i>Did you stay for a time? Or did you choose to leave, heading for the stars or trying to find your way back home? Were you guilty of your crimes, or unjustly condemned?</i><br>Penal colonies were harsh, unforgiving environments: <i>Was yours monitored by some authority, or was it relegated to anarchy even before Union's abolition of the system? Was there some kind of rudimentary society there? Did you have friends and enemies there, and did any of them make it off-world? What about your family – did you have one before your sentence? What has become of them, or do you not know?</i>",
    skills: [
      "sk_survive",
      "sk_apply_fists_to_faces",
      "sk_word_on_the_street",
      "sk_spot"
    ]
  },
  {
    id: "pbg_priest",
    name: "Priest",
    description: "You were a priest in your old life, either from a large, pan-galactic religion, or a smaller sect. <i>Were you a hermit? Did you live celibate in a monastery? Did you wear simple cloth robes, or majestic vestments? What restrictions were placed upon you by your church? What manner of respect was afforded to you as a person of the cloth, and was it your choice to become one? How did you come to serve as a pilot?</i><br>There are churches everywhere, each unique in their own ways. <i>Were you a member of a prominent religion, or a secretive, outlawed one? Did you preach a Terran faith, born on Cradle and carried for millennia since? Or was yours a Cosmopolitan spirituality, one from the stars and the void of interstellar space? Perhaps you ministered to a small flock of an obscure sect out on the frontier, or in the urban canyons of a core world? Have you kept your faith, or lost it?</i>",
    skills: [
      "sk_read_a_situation",
      "sk_stay_cool",
      "sk_take_control",
      "sk_lead_or_inspire"
    ]
  },
  {
    id: "pbg_scientist",
    name: "Scientist",
    description: "You were a scientist – private or public, working in the lab or the field. <i>What was your area of expertise, and for how long have you practiced it? Where did you study, and what’s your relationship with that institution? Do you have rivals, and are you well-known or relatively obscure? How did your home society perceive science? How did you become a pilot?</i><br><i>Importantly, did you work with a powerful manufacturer like Harrison Armory, Smith-Shimano, or IPS-N? Or did you delve into the uncanny, working in secret with a small, dedicated HORUS cell? What secrets do you know?</i>",
    skills: [
      "sk_investigate",
      "sk_invent_or_create",
      "sk_get_a_hold_of_something",
      "sk_blow_something_up"
    ]
  },
  {
    id: "pbg_soldier",
    name: "Soldier",
    description: "Grunt. GI. Ox. Poilu. Man-at-Arms. You were a soldier of the rank and file, serving in a planetary defense force, local militia, national army, or royal guard. <i>How long did you serve before Union called you up? What kind of specialty did you train for? Have you seen combat before, or are you green? Were you a volunteer, a conscript, or a member of a warrior caste? Is soldiering a proud family, civic, or religious tradition, or a life that you regret? Where are the other soldiers from your old squad, and what is your relationship with them like now?</i>",
    skills: [
      "sk_assault",
      "sk_blow_something_up",
      "sk_pull_rank",
      "sk_take_control"
    ]
  },
  {
    id: "pbg_spaceborn",
    name: "Spaceborn",
    description: "You grew up on a space station, in tight quarters and a small community, surrounded always by the unforgiving hard vacuum of space. <i>Were resources scarce, or plentiful? Was your station isolated or was it a local (or galactic!) hub? Was it parked in the endless night of deep space, or in orbit above a planet, moon, or another stellar body? Was it entirely manufactured, or was it built into an asteroid or moon?</i><br>No two stations are alike. <i>Did you grow up watching great ships dock and depart – exposed to the thousands of languages and cultures of the galaxy, dreaming of exploration – or did you grow up in dark, rocky halls, ignorant of the galaxy outside? In short, what was your life like, why did you leave, and can you go back?</i>",
    skills: [
      "sk_survive",
      "sk_hack_or_fix",
      "sk_get_somewhere_quickly",
      "sk_stay_cool"
    ]
  },
  {
    id: "pbg_spec_ops",
    name: "Spec Ops",
    description: "You might have been a spy or assassin, working alone, or maybe you were part of an elite unit, operating behind enemy lines with little-to-no support, equipped with the best equipment your commanders trusted you with.<i></i><br>Your missions were long, dangerous, and never publicized. If soldiers are hammers, you were a scalpel. Whatever organization you served, it was spoken only in whispers around military barracks and academies both. <i>What work did you do that no one knows was you or your unit? How close has the galaxy come to all-out war? Where have you operated? How old are you – really? What secrets do you know? Where is the rest of your team?</i>",
    skills: [
      "sk_act_unseen_or_unheard",
      "sk_take_someone_out",
      "sk_spot",
      "sk_stay_cool"
    ]
  },
  {
    id: "pbg_super_soldier",
    name: "Super Soldier",
    description: "You are the result of a corporate or state project intended to create better soldiers using biological enhancement, gene therapy, neurological enhancement, or even just extreme conditioning. <i>Were you raised from birth to become what you are, or did you volunteer as an adult for a super-soldier program? Are you one of the countless “super soldiers” to be produced by Harrison Armory’s facsimile-cloning programs? Was the project sanctioned or not? Did it succeed? Have you tested your abilities in the field, or are you unproven and eager to see what you can do?</i><br>Under the Third Committee, fewer programs like the one that created you still operate: <i>Are you happy about that, or do you think it makes Union weak? What is your relationship to your makers? Is there a family that doesn't know you exist? Or are you from a line of mass-pro‐ duced siblings? Were you liberated, did you surrender, or are you still in the service of the organization or entity you were made to serve?</i>",
    skills: [
      "sk_apply_fists_to_faces",
      "sk_get_somewhere_quickly",
      "sk_assault",
      "sk_read_a_situation"
    ]
  },
  {
    id: "pbg_starship_pilot",
    name: "Starship Pilot",
    description: "You flew a starship – civilian, corporate, military or otherwise. You may have piloted a freighter, a fighter, a shuttle, or a larger ship. <i>Did you have a regular run, or did you fly anywhere? Were you a member of a crew, or did you have one of your own? What kind of flying did you do and what eventually happened to your ship? Did you stick to low and mid-orbit shuttle runs?</i><br>Being a pilot is as much a lifestyle as it is a profession: <i>What was your callsign, and were you known or obscure? Was there a rival service, pilot, or group of pilots that you had friction with? Have you worked with NHPs or flown in combat? Have you ever seen anything strange out in interstellar space or the total void of blinkspace?</i>",
    skills: [
      "sk_get_somewhere_quickly",
      "sk_show_off",
      "sk_get_a_hold_of_something",
      "sk_hack_or_fix"
    ]
  },
  {
    id: "pbg_worker",
    name: "Worker",
    description: "At the end of the day, empire only functions when labor clocks in. Labor mines the raw materials; labor fashions stone and metal and organic matter into bolts and screws and glue; labor designs the patterns for printers; labor shapes and welds, hammers and builds. Without the labor of trillions, all progress would grind to a halt. <i>Before you set down the wrench and picked up a helm, what kind of work did you do? Did you work in the fields, factories, shipyards, mines, or somewhere else? What was your life like before you began training as a pilot? Why did you leave? Will you return? Was there a project you worked on that you're especially proud of? Do you have an old crew still working on the clock? What world did you call home, and what were the working conditions there?</i>",
    skills: [
      "sk_word_on_the_street",
      "sk_stay_cool",
      "sk_lead_or_inspire",
      "sk_invent_or_create"
    ]
  }
], require$$2 = [
  {
    id: "missing_corebonus",
    name: "ERR: DATA NOT FOUND",
    source: "",
    effect: "MISSING CORE BONUS DATA",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Core Bonus. This is likely the result of a missing or outdated content pack."
  },
  {
    id: "cb_auto_stabilizing_hardpoints",
    name: "Auto-Stabilizing Hardpoints",
    source: "GMS",
    effect: "Choose one mount. Weapons attached to this mount gain +1 Accuracy.",
    description: "Using the best in shock-absorption and steadytech, you can retain accuracy across longer, sustained periods of fire.",
    mounted_effect: "Attacks made with weapons from this mount can be made with +1 ACCURACY."
  },
  {
    id: "cb_overpower_caliber",
    name: "Overpower Caliber",
    source: "GMS",
    effect: "Choose one weapon. 1/round, when you hit with an attack, you can cause it to deal +1d6 bonus damage.",
    description: "Instead of the standardized option, you requisition multiple racks of “hot” ammunition – same-bore slugs, with a higher grade of accelerant.",
    mounted_effect: "One weapon equipped to this mount deals +1d6 bonus damage 1/round on hit."
  },
  {
    id: "cb_improved_armament",
    name: "Improved Armament",
    source: "GMS",
    effect: "If your mech has fewer than three mounts (excluding integrated mounts), it gains an additional Flexible mount.",
    description: "By rerouting power and strengthening systems, you can mount additional weapons beyond the factory recommendations."
  },
  {
    id: "cb_integrated_weapon",
    name: "Integrated Weapon",
    source: "GMS",
    effect: "Your mech gains a new integrated mount with capacity for one Auxiliary weapon. This weapon can be fired 1/round as a free action when you fire any other weapon on your mech. It can’t be modified.",
    description: "The empty spaces in your mech’s chassis – inside fists, chest plates, anywhere there’s room – are filled with integrated weapons, ready to fire on reflex."
  },
  {
    id: "cb_mount_retrofitting",
    name: "Mount Retrofitting",
    source: "GMS",
    effect: "Replace one mount with a Main/Aux mount.",
    description: "By re-fabricating certain components and hardpoints on your chassis for more efficient distribution, you can increase your mech’s firepower.",
    mounted_effect: "This mount has been replaced with a Main/Aux Mount."
  },
  {
    id: "cb_universal_compatibility",
    name: "Universal Compatibility",
    source: "GMS",
    effect: "Any time you spend CP to activate a Core System, you may also take a free action to restore all HP, cool all Heat, and roll 1d20: on 20, regain 1 CP.",
    description: "The Everest is everywhere: so are the parts you need for a field repair."
  },
  {
    id: "cb_briareos_frame",
    name: "Briareos Frame",
    source: "IPS-N",
    effect: "As long as your mech has no more than 1 Structure, you gain Resistance to all damage. When it’s reduced to 0 HP and 0 Structure, it is not destroyed: instead, you must make a structure damage check each time it takes damage. While in this state, your mech cannot regain HP until you rest or perform a Full Repair, at which point your mech can be repaired normally.",
    description: "The Briareos is the newest release in IPS-N’s line of near-fail frame upgrades: templates designed to maximize a mech’s usability before catastrophic failure or the need for a reprint. The Briareos template increases the resilience of inorganic components by supplementing the structure with a superlight frame featuring interwoven layers of IPS-N’s iconic Goliath Weave meshing."
  },
  {
    id: "cb_fomorian_frame",
    name: "Fomorian Frame",
    source: "IPS-N",
    effect: "Increase your mech’s Size by one increment (e.g., from 1/2 to 1, 1 to 2, or 2 to 3) up to a maximum of 3 Size. You can’t be knocked Prone, pulled, or knocked back by smaller characters, regardless of what system or weapon causes the effect.",
    description: "The Fomorian is an upscaled version of IPS-N’s stock template that has been adapted to meet the needs of long-haul Cosmopolitans looking for enhanced stability and robust impact protection, both micro- and macro-level.",
    bonuses: [
      {
        id: "size",
        val: 1
      }
    ]
  },
  {
    id: "cb_gyges_frame",
    name: "Gyges Frame",
    source: "IPS-N",
    effect: "You gain +1 Accuracy on all Hull checks and saves and +1 Threat with all melee weapons.",
    description: "A mech built on the Gyges template is designed for combat – enhanced with finely tuned stabilizers and a robust suite of targeting software and hardware.",
    bonuses: [
      {
        id: "range",
        weapon_types: [
          "Melee"
        ],
        range_types: [
          "Threat"
        ],
        val: 1
      }
    ],
    synergies: [
      {
        locations: [
          "hull"
        ],
        detail: "+1 Accuracy on all Hull checks and saves"
      }
    ]
  },
  {
    id: "cb_reinforced_frame",
    name: "Reinforced Frame",
    source: "IPS-N",
    effect: "You gain +5 HP.",
    description: "The addition of redundant shock-absorption systems increases the survivability of pilots in combat, flight, and industrial situations.",
    bonuses: [
      {
        id: "hp",
        val: 5
      }
    ]
  },
  {
    id: "cb_sloped_plating",
    name: "Sloped Plating",
    source: "IPS-N",
    effect: "You gain +1 Armor, up to the maximum (+4).",
    description: "A common choice among pilots with the right licenses, IPS-N’s integrated-armor fabrication reduces gaps in external coverage by a significant percentage.",
    bonuses: [
      {
        id: "armor",
        val: 1
      }
    ]
  },
  {
    id: "cb_titanomachy_mesh",
    name: "Titanomachy Mesh",
    source: "IPS-N",
    effect: "1/round, when you successfully Ram or Grapple a mech, you can Ram or Grapple again as a free action. Additionally, when you knock targets back with melee attacks, you knock them back 1 additional space.",
    description: "A double overlay of Goliath Weave at key stress points and beefed-up specifications across the board greatly improve the baseline functionality of any mech.",
    synergies: [
      {
        locations: [
          "ram",
          "grapple"
        ],
        detail: "1/round, when you successfully Ram or Grapple a mech, you can Ram or Grapple again as a free action."
      }
    ]
  },
  {
    id: "cb_all_theater_movement_suite",
    name: "All-Theater Movement Suite",
    source: "SSC",
    effect: "You may choose to count any and all of your movement as flying; however, you take 1 Heat at the end of each of your turns in which you fly this way.",
    description: "A popular modification, ATMS adds powerful pulse jets that dramatically improve mech mobility in all theaters.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "You may choose to count any and all of your movement as flying; however, you take 1 Heat at the end of each of your turns in which you fly this way."
      }
    ]
  },
  {
    id: "cb_full_subjectivity_sync",
    name: "Full Subjectivity Sync",
    source: "SSC",
    effect: "You gain +2 Evasion.",
    description: "By creating a stable, two-way ontologic bridge, SSC has removed the need for pilots to rely on physical controls alone to pilot their mech. Using a full subjectivity sync, pilots perceive their mech as their own body and control it via neural impulse; somatosensory feedback is translated to the pilot as well, so caution is advised despite nociception-dampening defaults built-in to the system.",
    bonuses: [
      {
        id: "evasion",
        val: 2
      }
    ]
  },
  {
    id: "cb_ghostweave",
    name: "Ghostweave",
    source: "SSC",
    effect: "During your turn, you are Invisible. If you take no actions on your turn other than your standard move, Hide, and Boost, you remain Invisible until the start of your next turn. You immediately cease to be Invisible when you take a reaction.",
    description: "An upscaled version of the same systems found in SSC’s Mythimna Panoply, Ghostweave is a proprietary appliqué used to enhance mech camouflage in all environments."
  },
  {
    id: "cb_integrated_nerveweave",
    name: "Integrated Nerveweave",
    source: "SSC",
    effect: "You may move an additional 2 spaces when you Boost.",
    description: "Integrated nerveweave combines several technologies to grant total battlefield alacrity, assuring pilots are never left behind.",
    synergies: [
      {
        locations: [
          "move",
          "boost"
        ],
        detail: "You may move an additional 2 spaces when you Boost."
      }
    ]
  },
  {
    id: "cb_kai_bioplating",
    name: "Kai Bioplating",
    source: "SSC",
    effect: "You gain +1 Accuracy on all Agility checks and saves; additionally, you climb and swim at normal speed, ignore difficult terrain, and when making a standard move, can jump horizontally up to your full Speed and upwards up to half your Speed  (in any combination).",
    description: "Adapted from fauna local to SSC’s home system, Kai Bioplating adds a lamellar layer of insulated, anchored, and chitinous plating over key brush-points on a mech. Essentially a cheaper, more feasible alternative to living metal, bioplating allows for faster movement through hard-to-navigate terrain.",
    synergies: [
      {
        locations: [
          "agility"
        ],
        detail: "+1 Accuracy on all Agility checks and saves"
      },
      {
        locations: [
          "move"
        ],
        detail: "You climb and swim at normal speed, ignore difficult terrain, and when making a standard move, can jump horizontally up to your full Speed and upwards up to half your Speed  (in any combination)."
      }
    ]
  },
  {
    id: "cb_neurolink_targeting",
    name: "Neurolink Targeting",
    source: "SSC",
    effect: "Your ranged weapons gain +3 Range.",
    description: "To further reduce the information gap between pilot and machine and complement its full subjectivity sync technology, SSC developed neurolinking, a stable, non-invasive, and limited-transfer ontologic bridge. Neurolink targeting is a simple enhancement that helps pilots feel – as opposed to thinking – when engaged in ranged combat, allowing for a more natural expression of pilot ability.",
    bonuses: [
      {
        id: "range",
        range_types: [
          "Range"
        ],
        val: 3
      }
    ]
  },
  {
    id: "cb_the_lesson_of_disbelief",
    name: "The Lesson of Disbelief",
    source: "HORUS",
    effect: "You gain +1 accuracy on Systems checks and saves, and +2 E-Defense.",
    description: "Query the omninet, delve into the archives. Find you the Aeneid, find you the age of Titanomachy. Eat, absorb, mull. Tell me now of the Hecatoncheires, they of the hundred hands. Did they strike the blow against Cronus – Saturno – or did they instead assail the Olympians? Who do you believe? Who stopped the Beast from telling its own story? And why? – “Lesson One”, The Six Lessons of Kilo Nueve.",
    bonuses: [
      {
        id: "edef",
        val: 2
      }
    ],
    synergies: [
      {
        locations: [
          "systems"
        ],
        detail: "+1 Accuracy on on Systems checks and saves"
      }
    ]
  },
  {
    id: "cb_the_lesson_of_the_open_door",
    name: "The Lesson of the Open Door",
    source: "HORUS",
    effect: "Your Save Target increases by +2; additionally, 1/round, when a character fails a save against you, they take 2 heat.",
    description: "There is a body and a deep pit, and both are named Tartarus. Once it held kings and titans and myths. Now, the gates that held it back are flung wide, and Tartarus is free. Here is the terrible question: who opened it, and why? – “Lesson Two”, The Six Lessons of Kilo Nueve.",
    bonuses: [
      {
        id: "save",
        val: 2
      }
    ]
  },
  {
    id: "cb_the_lesson_of_the_held_image",
    name: "The Lesson of the Held Image",
    source: "HORUS",
    effect: "1/round, as a reaction at the start of any allied character’s turn, you may make a Lock On tech action against any character within line of sight and Sensors.",
    description: "Close your eyes. Hold the image of your enemy in your mind; imagine it in all light and from every angle. In your mind, it has become a more perfect version. Crush it in your mind and kill the perfect thing. Open your eyes. – “Lesson Three”, The Six Lessons of Kilo Nueve.",
    actions: [
      {
        name: "Lesson of the Held Image",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "Any allied character starts their turn",
        detail: "Make a Lock On tech action against any character within line of sight and Sensors."
      }
    ]
  },
  {
    id: "cb_the_lesson_of_thinking_tomorrows_thought",
    name: "The Lesson of Thinking-Tomorrow’s-Thought",
    source: "HORUS",
    effect: "When you hit with a tech attack, your next melee attack against the same target gains +1 accuracy, and its damage can’t be reduced in any way.",
    description: "Let me tell you this lesson: the corporeal existence is one that must end in death. The incorporeal existence is one that [must] end in [cascade? do you really think that is true?]. I tell you again, if you can imagine it, it is [done] and you have already struck the killing blow. – “Lesson Four”, The Six Lessons of Kilo Nueve.",
    synergies: [
      {
        locations: [
          "tech_attack"
        ],
        detail: "When you hit with a tech attack, your next melee attack against the same target gains +1 accuracy, and its damage can’t be reduced in any way."
      }
    ]
  },
  {
    id: "cb_the_lesson_of_transubstantiation",
    name: "The Lesson of Transubstantiation",
    source: "HORUS",
    effect: "Any time you take structure damage, you disappear into a non-space and cease to be a valid target. You reappear in the same space at the start of your next turn. If that space is occupied, you reappear in the nearest available free space (chosen by you).",
    description: "Through ecstatic repetition, you may see the face of God. Speak until your tongue dries and rattles to dust, and your body becomes nothing. When you are nothing and the wind takes you, you are in all things, never to be destroyed, only divided, until time's end. – “Lesson Five”, The Six Lessons of Kilo Nueve."
  },
  {
    id: "cb_the_lesson_of_shaping",
    name: "The Lesson of Shaping",
    source: "HORUS",
    effect: "You may install an additional AI in your mech. If one enters cascade (or becomes unshackled narratively), the other prevents it from taking control of your mech. You only lose control of your mech if both AI-tagged systems or equipment enter cascade.",
    description: "A little gift, to be pondered until understood: Cast aside the hammer and sword, the cannon and beam. No weapon formed against me shall land a true blow, as I have seen all ends, and there is nothing left but me. A trillion trillion light-years in all directions, and through it all, only [us? who knows. ego is a mind-killer. best to call your friends. better to face the night together. ‘til later, love.] – “Lesson Six”, The Six Lessons of Kilo Nueve.",
    bonuses: [
      {
        id: "ai_cap",
        val: 1
      }
    ]
  },
  {
    id: "cb_adaptive_reactor",
    name: "Adaptive Reactor",
    source: "HA",
    effect: "When you Stabilize and choose to cool your mech, you may spend 2 Repairs to clear 1 stress damage.",
    description: "All Armory frames are designed with multiple failsafe systems, but VIP clients and high-tier citizenry have access to a special catalog. With dozens of options for over-engineering reactors, it’s easy to make sure a mech can keep running indefinitely."
  },
  {
    id: "cb_armory_sculpted_chassis",
    name: "Armory-Sculpted Chassis",
    source: "HA",
    effect: "You gain +1 accuracy on all Engineering checks and saves. When you Overcharge, you gain soft cover until the start of your next turn.",
    description: "Anyone can print a stock mech chassis, relying on a section of generic code to keep them alive. The discerning pilot, on the other hand, accepts only the best: a frame designed, tested, and tuned by one of the Armory’s master fabricators.",
    synergies: [
      {
        locations: [
          "engineering"
        ],
        detail: "Gain +1 Accuracy on all Engineering checks and saves."
      },
      {
        locations: [
          "overcharge"
        ],
        detail: "Gain soft cover until the start of your next turn."
      }
    ]
  },
  {
    id: "cb_heatfall_coolant_system",
    name: "Heatfall Coolant System",
    source: "HA",
    effect: "Your cost for Overcharge never goes past 1d6 heat.",
    description: "The Heatfall Coolant System comes packaged with a stabilized reactor core; paired together, this combo is guaranteed to keep a mech cool in nearly any environment.",
    bonuses: [
      {
        id: "overcharge",
        val: [
          "1",
          "1d3",
          "1d6",
          "1d6"
        ]
      }
    ]
  },
  {
    id: "cb_integrated_ammo_feeds",
    name: "Integrated Ammo Feeds",
    source: "HA",
    effect: "All Limited systems and weapons gain an additional two charges.",
    description: "By streamlining and integrating all automated ordnance-loading modules, Harrison Armory specialists can greatly enhance mechs’ time-to-target minimums. As an added bonus, these upgrades usually result in increased carrying capacity, allowing pilots to field more ordnance than design specifications suggest.",
    bonuses: [
      {
        id: "limited_bonus",
        val: 2
      }
    ]
  },
  {
    id: "cb_stasis_shielding",
    name: "Stasis Shielding",
    source: "HA",
    effect: "Whenever you take stress damage, you gain Resistance to all damage until the start of your next turn.",
    description: "A Think Tank exercise in extending stasis beyond the capabilities of civilian utility, Harrison Armory’s stasis shielding actively identifies critically stressed inorganic systems and blankets them in unmodulated “Holdfast” stasis, preventing further degradation for a limited period of time until repairs can be made."
  },
  {
    id: "cb_superior_by_design",
    name: "Superior by Design",
    source: "HA",
    effect: "You gain Immunity to Impaired and gain +2 Heat Cap.",
    description: "Even the Armory’s entry-level frames aim to outperform the competition. Thanks to the incredible resources they have at their disposal, Harrison Armory can out-design and out-produce almost any smaller, boutique engineer or fabricator. Where resistance is found, the answer is simple: buy them out, or stamp them out. The Armory’s valued customers benefit from this philosophy of “Superior by Design”, so why should they worry?",
    bonuses: [
      {
        id: "heatcap",
        val: 2
      }
    ]
  }
], require$$3 = [
  {
    id: "env_dangerousflorafauna",
    name: "Dangerous Flora or Fauna",
    description: "An unusually large proportion of this planet’s animal or plant life is dangerous; some of the flora and fauna may predatory, particularly hostile, or even titanic in size. Use the Monstrosity NPC type to generate encounters with wildlife. Hostile flora can appear on the battlefield as immobile characters with Size 1–2, 5 HP, and Evasion 10; targets that move adjacent to them must succeed on a Hull save or take 3 Kinetic Damage and become Immobilized until the flora is destroyed, as it traps them with sticky sap, webbing, a pit, or the like."
  },
  {
    id: "env_extremecold",
    name: "Extreme Cold",
    description: "Local cultures have adapted to the frozen climate, but mechs and pilots quickly freeze without a nearby source of heat. Mechs that don’t move or Boost on their turn become Immobilized at the end of their turn. This lasts until they break free with a successful Hull save as a quick action. In addition, all mechs gain Resistance to Heat."
  },
  {
    id: "env_extremeheat",
    name: "Extreme Heat",
    description: "Society has retreated mostly underground to escape this world’s blistering atmosphere. All Heat inflicted (to the user or others) by systems or weapons is increased by +1."
  },
  {
    id: "env_thinatmosphere",
    name: "Thin Atmosphere",
    description: "All characters gain Resistance to Explosive Damage."
  },
  {
    id: "env_extremesun",
    name: "Extreme Sun",
    description: "Characters take 1d6 Heat whenever they are aren’t in shade at the end of a turn."
  },
  {
    id: "env_corrosiveatmosphere",
    name: "Corrosive Atmosphere",
    description: "The dense atmosphere of this world eats through armor. All weapons gain AP."
  },
  {
    id: "env_particulatestorms",
    name: "Particulate Storms",
    description: "This planet is swept by brutal, scouring storms of sand, rock, or metal. During storms, mechs always have soft cover. Pilots that leave their mech take 1 Kinetic Damage (AP) each turn they are outside."
  },
  {
    id: "env_electricalstorms",
    name: "Electrical Storms",
    description: "This planet is swept by unusually strong electrical storms. During storms, choose a character at random at the end of each round: they must succeed on an ENGINEERING save with +1 Difficulty per level of Size or be STUNNED until the end of their next turn by a bolt of lightning."
  },
  {
    id: "env_disruptivestorms",
    name: "Disruptive Storms",
    description: "The storms on this planet are so highly charged that electronic systems can’t function. All tech actions, attacks, and SYSTEMS checks and saves receive +1 Difficulty."
  },
  {
    id: "env_dangeroustorms",
    name: "Dangerous Storms",
    description: "Storms of fire, meteors, acid rain, ice, or other destructive particles sweep this planet. During storms, all characters take 2 Energy Damage (AP) at the end of their turns unless they are adjacent to an object that grants hard cover."
  },
  {
    id: "env_oceanworld",
    name: "Ocean World",
    description: "Less than five percent of this world’s surface rises above the ocean. Mechs sink to the bottom and move as though in difficult terrain unless they are flying or have an EVA Module. Mechs can walk (slowly) on the bottom and are usually able to function in extremely high-pressure environments."
  },
  {
    id: "env_earthquakes",
    name: "Earthquakes",
    description: "This world is regularly rocked by earthquakes. During earthquakes, roll 1d6 at the end of each round: on 1, all mechs must succeed on a HULL save or be knocked Prone unless they are flying."
  },
  {
    id: "env_moltenworld",
    name: "Molten World",
    description: "Parts of this world’s crust juts through the surface in showers and pools of liquid rock. When characters move into areas of molten rock or lava for the first time on their turn or start their turn there, they take 5 Energy Damage (AP) and 3 Heat."
  },
  {
    id: "env_primordealworld",
    name: "Primordial World",
    description: "This world is a bubbling soup of semi-organic mud and gases. Humans must use breathing apparatuses or sealed suits outside of their mechs to survive the toxic atmosphere, and boiling mud creates numerous areas of both difficult and dangerous terrain."
  },
  {
    id: "env_lowgravity",
    name: "Low Gravity",
    description: "Mechs count as flying when they Boost but must land after they move. Characters never take damage from falling."
  },
  {
    id: "env_highgravity",
    name: "High Gravity",
    description: "Mechs cannot Boost and are Immobilized instead whenever they would be Slowed."
  },
  {
    id: "env_tombworld",
    name: "Tomb World",
    description: "This world has extremely high levels of ambient radiation, possibly because of nuclear war, atmospheric degradation, or something more sinister. Outside of mechs, humans without environmental protection temporarily decrease their maximum HP by 1 per hour of exposure. If they reach 0 HP this way, they die. They can regain their maximum HP by performing a Full Repair in a safe environment."
  },
  {
    id: "env_spireworld",
    name: "Spire World",
    description: "Instead of a surface, this world is comprised of countless floating islands or spires, each held aloft in a gaseous substrate and suspended through magnetic force. Perhaps the crust was shattered by a superweapon or natural disaster. Most of the remaining landmass is disconnected, although some islands are large enough to hold cities. Navigation systems are almost useless here."
  },
  {
    id: "env_sinkingworld",
    name: "Sinking World",
    description: "The surface of this world is covered in fine sand or thick mud. Mechs that move 1 space or less during their turn are Slowed. Slowed mechs that move 1 space or less are Immobilized and start sinking, eventually becoming completely engulfed. This effect lasts until an affected mech (or one adjacent to it) succeeds on a Hull save as a full action."
  },
  {
    id: "env_holyworld",
    name: "Holy World",
    description: "This world is beautiful and lacks especially dangerous features, but the local population holds it sacrosanct. Damaging any natural object – rocks, trees, and pristine grasslands, for example – incurs the wrath of the residents."
  }
], require$$4 = [], require$$5 = [
  {
    id: "missing_frame",
    license_level: 0,
    source: "GMS",
    name: "ERR: DATA NOT FOUND",
    mechtype: [
      "Balanced"
    ],
    y_pos: 0,
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Frame. This is likely the result of a missing or outdated content pack.",
    mounts: [],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 10,
      evasion: 8,
      edef: 8,
      heatcap: 6,
      repcap: 5,
      sensor_range: 10,
      tech_attack: 0,
      save: 10,
      speed: 4,
      sp: 6
    },
    traits: [],
    core_system: {
      name: "ERR: MISSING DATA",
      active_name: "",
      active_effect: "",
      use: "Next Round",
      activation: "Free"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/missing_frame.png",
    license_id: "missing_frame"
  },
  {
    id: "mf_standard_pattern_i_everest",
    license_level: 0,
    source: "GMS",
    name: "Everest",
    mechtype: [
      "Balanced"
    ],
    y_pos: 25,
    description: "Most humans don’t think to ask about the history of the water they drink, the earth they walk, or the air they breathe. And yet, without water, earth, and air, there would be nowhere for humanity to make a home.<br>Just the same, the GMS-SP1 “Everest” is often taken for granted, its importance dismissed in favor of other, more specialized frames. A plain and unpretentious mech, defined by simple lines, functional grace, universal compatibility, and sturdy bulk, the Everest is as fundamental to the modern mechanized chassis as the natural world is to human life. The Everest isn’t the most specialized mech, but it is the backbone of our expansion imperative. From its shoulders, humanity steps.<br>Prior to GMS’s official adoption of the name, “Everest” was a use-name given to the frame by its pilots. Mount Everest – or Sagarmatha, or Chomolungma, as it has been called in older human tongues – is the tallest mountain on Cradle, though not the most prominent peak in known space, nor even the greatest in Cradle’s star system, yet pilots across the galaxy call their SP1s by that ancient name. Why?<br>The sentimental answer is that the name is a reminder of what was once the limit of human endurance – once the height of human achievement. To reach Everest’s summit was to defy death and stand atop the world – the culmination of months, even years, of training, investment, and hard work. Reaching the peak was also a triumph of the people, systems, and institutions behind the individual – a triumph too often left unacknowledged, or deliberately erased.<br>Sagarmatha. Chomolungma.<br>Even before the Fall, when the Massif vaults were built, some names – some stories – were given priority over others.<br>The real story behind the Everest’s name is likely much less deliberate. Somewhere along the line, a newly graduated pilot, frustrated by GMS’s plain naming conventions, painted “EVEREST” across the flank of their SP1. Maybe it was a callsign, or maybe it represented the pride they felt at success. Either way, the name stuck: others adopted the name, and over five centuries it grew to become the officially unofficial designation of the SP1 chassis.<br>Veteran pilots may never return to the Everest after moving on, but they’ll always remember reaching that first summit – the mountaintop where they proved they could plant their own flag at the peak of the world.<br>Sagarmatha. Chomolungma.<br>Everest – you’ll never forget it.",
    mounts: [
      "Main",
      "Flex",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 10,
      evasion: 8,
      edef: 8,
      heatcap: 6,
      repcap: 5,
      sensor_range: 10,
      tech_attack: 0,
      save: 10,
      speed: 4,
      sp: 6
    },
    traits: [
      {
        name: "Initiative",
        description: "1/scene the Everest may take any quick action as a free action.",
        use: "Encounter"
      },
      {
        name: "Replaceable parts",
        description: "While resting, the Everest can be repaired at a rate of 1 Repair per 1 structure damage, instead of 2 Repairs.",
        bonuses: [
          {
            id: "cheap_struct",
            val: 1
          }
        ],
        synergies: [
          {
            locations: [
              "rest"
            ],
            detail: "The Everest can be repaired at a rate of 1 Repair per 1 structure damage."
          }
        ]
      }
    ],
    core_system: {
      name: "Hyperspec Fuel Injector",
      active_name: "Power Up",
      active_effect: "For the rest of this scene, you gain +1 Accuracy on all attacks, checks, and saves; additionally, 1/turn, you can Boost as a free action.",
      use: "Encounter",
      activation: "Protocol",
      active_synergies: [
        {
          locations: [
            "active_effects",
            "boost"
          ],
          detail: "1/turn, you can Boost as a free action."
        },
        {
          locations: [
            "hull",
            "agility",
            "systems",
            "engineering"
          ],
          detail: "Gain +1 Accuracy on all attacks, checks, and saves."
        }
      ]
    },
    other_art: [
      {
        tag: "mech",
        src: "pre_assault_pixel.png"
      },
      {
        tag: "mech",
        src: "pre_hacker_pixel.png"
      },
      {
        tag: "mech",
        src: "pre_sniper_pixel.png"
      },
      {
        tag: "mech",
        src: "pre_support_pixel.png"
      },
      {
        tag: "mech",
        src: "pre_vanguard_pixel.png"
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_standard_pattern_i_everest.png",
    license_id: "mf_standard_pattern_i_everest"
  },
  {
    id: "mf_blackbeard",
    license_level: 2,
    source: "IPS-N",
    name: "Blackbeard",
    mechtype: [
      "Striker"
    ],
    y_pos: 23,
    description: "The Blackbeard is IPS-N’s aggressive solution to piracy: a front-facing, first-striking mech designed for environments in which combustible kinetic weapons are useless, dangerous, or likely to cause unnecessary collateral damage. With its distinctly slim frame, the Blackbeard doesn’t just look fast – it also has a reduced radar profile. This mech is hard to track and harder still to hit.<br>The Blackbeard range comprises two lines: the standard IPS-N/BB-L production line model, and the IPS-N/BB-Sk, a limited-release prototype purpose-built to house IPS-N’s SEKHMET-class NHPs.",
    mounts: [
      "Flex",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 12,
      evasion: 8,
      edef: 6,
      heatcap: 4,
      repcap: 5,
      sensor_range: 5,
      tech_attack: -2,
      save: 10,
      speed: 5,
      sp: 5
    },
    traits: [
      {
        name: "Grapple cable",
        description: "The Blackbeard can Grapple targets within Range 5. If the Grapple is successful, the Blackbeard is immediately pulled adjacent to the target by the most direct path. If there are no suitable spaces, the grapple breaks and the Blackbeard does not move.",
        synergies: [
          {
            locations: [
              "grapple"
            ],
            detail: "The Blackbeard can Grapple targets within Range 5. If the Grapple is successful, the Blackbeard is immediately pulled adjacent to the target by the most direct path. If there are no suitable spaces, the grapple breaks and the Blackbeard does not move."
          }
        ]
      },
      {
        name: "Lock/Kill Subsystem",
        description: "While grappling, the Blackbeard can Boost and take reactions.",
        synergies: [
          {
            locations: [
              "grapple",
              "boost"
            ],
            detail: "While grappling, the Blackbeard can Boost and take reactions."
          }
        ]
      },
      {
        name: "Exposed Reactor",
        description: "The Blackbeard receives +1 Difficulty on ENGINEERING checks and saves.",
        synergies: [
          {
            locations: [
              "engineering",
              "skill_check"
            ],
            detail: "The Blackbeard gains +1 Difficulty on ENGINEERING checks and saves."
          }
        ]
      }
    ],
    core_system: {
      name: "Assault Grapples",
      description: "The IPS-N-branded Assault Grappling System is a class-leading technology rated for hauling, supporting, and securing chassis of sizes up to Schedule 4. Grapple heads are interchangeable and can be swapped for engagement with soft or hard targets – either electrified or loaded with codespike systems for long-distance incapacitation.",
      active_name: "Omni-harpoon",
      active_effect: "This system fires grappling harpoons at any number of targets within Range 5 and line of sight. Affected characters must succeed on a Hull save or take 2d6 Kinetic damage and be knocked Prone, then pulled adjacent to you, or as close as possible. They become Immobilized until the end of their next turn. On a success, they take half damage and are otherwise unaffected.",
      activation: "Quick"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_blackbeard.png",
    license_id: "mf_blackbeard"
  },
  {
    id: "mf_drake",
    license_level: 2,
    source: "IPS-N",
    name: "Drake",
    mechtype: [
      "Defender"
    ],
    y_pos: 12,
    description: "The Drake, IPS-N’s first foray into military-grade mech design, is the backbone of any proactive trade-security or anti-piracy force. Its massive, simian frame is built around a single-cast bulkhead, sloped and reinforced to handle sustained fire and the vagaries of vessel-proximal hardvac travel. The Drake is an imposing chassis, its frame evoking the might of ancient armored infantry from a time when greater numbers guaranteed victory.<br>The standard fleet license for the IPS-N Drake outfits each chassis with IPS-N’s high-velocity, high–projectile fragment assault cannon for suppressing and overwhelming targets, and a heavy kinetic–ablative shield for defense. Advanced models feature upgraded weapons and armor including the formidable Leviathan Heavy Assault Cannon, a high-rpm anti-materiel weapon.",
    mounts: [
      "Main",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 3,
      hp: 8,
      evasion: 6,
      edef: 6,
      heatcap: 5,
      repcap: 5,
      sensor_range: 10,
      tech_attack: 0,
      save: 10,
      speed: 3,
      sp: 5
    },
    traits: [
      {
        name: "Heavy Frame",
        description: "The Drake can’t be pushed, pulled, knocked Prone, or knocked back by smaller characters."
      },
      {
        name: "Blast Plating",
        description: "The Drake has Resistance to damage, burn and heat from blast, burst, line, and cone attacks."
      },
      {
        name: "Slow",
        description: "The Drake receives +1 difficulty on Agility checks and saves.",
        synergies: [
          {
            locations: [
              "agility",
              "skill_check"
            ],
            detail: "The Drake receives +1 difficulty on Agility checks and saves."
          }
        ]
      },
      {
        name: "Guardian",
        description: "Adjacent allied characters can use the Drake for hard cover."
      }
    ],
    core_system: {
      name: "Fortress",
      active_name: "Fortress Protocol",
      active_effect: "You deploy heavy stabilizers and your mech becomes more like a fortified emplacement than a vehicle. When activated, two sections of hard cover (line 2, Size 1) unfold from your mech, drawn in any direction. These cover sections have Immunity to all damage.<br>Additionally, the following effects apply while active:<ul><li>You become Immobilized.</li><li>You benefit from hard cover, even in the open, and gain Immunity to Knockback, Prone, and all involuntary movement.</li><li>When you Brace, you may take a full action on your next turn instead of just a quick action.</li><li>Any character that gains hard cover from you or your cover sections gains Immunity to Knockback, Prone, and all involuntary movement, and gains the benefits of Blast Plating.</li></ul>This system can be deactivated as a protocol. Otherwise, it lasts until the end of the current scene.",
      use: "Encounter",
      deactivation: "Protocol",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_drake.png",
    license_id: "mf_drake"
  },
  {
    id: "mf_lancaster",
    license_level: 2,
    source: "IPS-N",
    name: "Lancaster",
    mechtype: [
      "Support"
    ],
    y_pos: 16,
    description: "The IPS-N Lancaster is a mil-spec variant of an older IPS-N civilian terrestrial, inter/outer-hull transport and maintenance chassis, streamlined for use in any theater. The Lancaster features multiple redundant systems and sophisticated interaction projectors to ensure pinpoint accuracy when engaging with delicate systems, whether damaged or intact.<br>Lancaster pilots often adopt roles as sappers and engineers in frontline support. Sometimes ridiculed for piloting the old-fashioned frame by newer, untested pilots, veteran Lancaster jockeys know the truth: the Lancaster is one of the most reliable and well-made mechs out there, indispensable on any serious long-range mission. Not every mission is won with bullets, lasers, and bombs: without the engineers and their Lannies, few of those hotshots would come home alive.",
    mounts: [
      "Main/Aux"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 6,
      evasion: 8,
      edef: 8,
      heatcap: 6,
      repcap: 10,
      sensor_range: 8,
      tech_attack: 1,
      save: 10,
      speed: 6,
      sp: 8
    },
    traits: [
      {
        name: "Insulated",
        description: "The Lancaster has Immunity to burn."
      },
      {
        name: "Combat Repair",
        description: "In combat, the Lancaster can use 4 Repairs to repair a destroyed mech as a full action, returning it to 1 Structure, 1 Stress, and 1 HP.",
        actions: [
          {
            name: "Combat Repair",
            activation: "Full",
            detail: "Use 4 Repairs to repair a destroyed mech as a full action, returning it to 1 Structure, 1 Stress, and 1 HP."
          }
        ]
      },
      {
        name: "Redundant Systems",
        description: "At your discretion, other characters adjacent to the Lancaster can spend its Repairs as their own."
      }
    ],
    core_system: {
      name: "Latch Drone",
      description: "Known colloquially as a “Wingman”, latch drones are companion drones carried by and deployed from a chassis. Pilots are recommended not to develop emotional attachments to these drones due to their high casualty rate.",
      active_name: "Supercharger",
      active_effect: "Your Latch Drone clamps onto an allied mech within its Range. For the rest of the scene you take 1 heat at the start of each of your turns, but your target gains +1 accuracy on all attacks, checks, and saves, and Immunity to the Impaired, Jammed, Slowed, Shredded, and Immobilized conditions from characters other than itself. This effect ends if either character becomes Stunned.<br>While this system is active, you cannot use the Latch Drone for any other purpose.",
      activation: "Quick",
      integrated: [
        "mw_lancaster_integrated"
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_lancaster.png",
    license_id: "mf_lancaster"
  },
  {
    id: "mf_nelson",
    license_level: 2,
    source: "IPS-N",
    name: "Nelson",
    mechtype: [
      "Striker"
    ],
    y_pos: 35,
    description: "The IPS-N Nelson is the purest embodiment of the close-quarters doctrine espoused by its manufacturer. It is built to brawl, thriving when ordnance has been exhausted or when the environment is too volatile for firearms. With its functional size, the Nelson can strike fast and remain a difficult target to track. Layers of fractal-fold Armor-Lock plating with ceramic-analogous carbon flaking properties effectively nullify the impact of incoming ballistics by dispersing kinetic energy across a rounded hull. This null-k defense protects the pilot from impact trauma, allowing for sustained combat efficacy in high-trade scenarios.<br>The Nelson is an iconic IPS-N chassis, known across the galaxy as the favored frame of the Albatross, the nomadic order of Cosmopolitan peacekeepers. The Albatross’ distinctive white, gold, and red livery, mastery of the war pike, and apparent agelessness due to time dilation has won both them and the Nelson a venerated place in Diasporan lore – and secured an endorsement contract with IPS-N in perpetuity.",
    mounts: [
      "Flex",
      "Main/Aux"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 8,
      evasion: 11,
      edef: 7,
      heatcap: 6,
      repcap: 5,
      sensor_range: 5,
      tech_attack: 0,
      save: 10,
      speed: 5,
      sp: 6
    },
    traits: [
      {
        name: "Momentum",
        description: "1/round, after you Boost, the Nelson’s next melee attack deals +1d6 bonus damage on hit.",
        synergies: [
          {
            locations: [
              "boost"
            ],
            detail: "1/round, after you Boost, the Nelson’s next melee attack deals +1d6 bonus damage on hit."
          }
        ]
      },
      {
        name: "Skirmisher",
        description: "After attacking, the Nelson can immediately move 1 space in any direction as long as it isn’t Immobilize or Slowed. This movement ignores engagement and doesn’t provoke reactions."
      }
    ],
    core_system: {
      name: "Perpetual Momentum Drive",
      description: "IPS-N’s Perpetual Momentum Drive exploits fighter-tier nearlight spooling to capture and sustain a passive .000001 ls charge, able to be dumped into boost systems upon command. Chassis equipped with this drive require heavy reinforcement, including strengthened joints and limbs, and installation of a k-comp crash couch to protect the pilot from sudden g-force and shear.",
      active_name: "Engage Drive",
      active_effect: "For the rest of the scene, Skirmisher allows you to move 4 spaces at a time instead of 1 space.",
      use: "Encounter",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_nelson.png",
    license_id: "mf_nelson"
  },
  {
    id: "mf_raleigh",
    license_level: 2,
    source: "IPS-N",
    name: "Raleigh",
    mechtype: [
      "Striker"
    ],
    y_pos: 12.5,
    description: "Seeing GMS and Harrison Armory’s push to secure whole-fleet line contracts with Union member states, IPS-N launched a brief foray into design and production of their own main battle line frame. Enter the Raleigh, a stylistic and design oddity for IPS-N. Designed not as a specialist, but as a purpose-built, close-range mech, the Raleigh failed to stun potential clients in trials.<br>Though a favorite of test pilots due to its unique styling and agility, the Raleigh saw few fleet orders and, after a brief run as IPS-N’s flagship, was quietly rolled back and replaced with the Tortuga. No longer offered as a fleet contract, the Raleigh enjoys a quiet popularity among pilots seeking a well-balanced, if close-ranged, line mech.",
    mounts: [
      "Aux/Aux",
      "Flex",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 10,
      evasion: 8,
      edef: 7,
      heatcap: 5,
      repcap: 5,
      sensor_range: 10,
      tech_attack: -1,
      save: 10,
      speed: 4,
      sp: 5
    },
    traits: [
      {
        name: "Full Metal Jacket",
        description: "At the end of its turn, if the Raleigh hasn’t made any attacks or forced any saves, it can reload all Loading weapons as a free action."
      },
      {
        name: "Shielded Magazines",
        description: "The Raleigh can make ranged attacks when Jammed."
      }
    ],
    core_system: {
      name: "M35 Mjolnir Cannon",
      description: "IPS-N’s M35 Mjolnir cannon is a carryover from Northstar’s Watchman line of defensive weapons, reworked for frontline combat. The Mjolnir is a hard-mounted, multi-barrel auxiliary cannon that uses magnetic acceleration to fire stacks of airburst projectiles at its target. It’s an impulse weapon, tied to the pilot’s second-tier neural processes with mediation from a COMP/CON or NHP; even in death, a pilot’s Mjolnir will continue to identify and attack hostile targets until reaching total systemic failure. For this reason, the Mjolnir is often referred to as a deadgun – one of many such weapons to be found among CQB-oriented pilots.",
      active_name: "Thunder God",
      active_effect: "You start to spin your M35 Mjolnir up, beginning with no chambered rounds. For the rest of the scene, you load two rounds into chambers at the end of any of your turns in which you haven’t fired the M35 Mjolnir . It can hold a maximum of six rounds.<br>When you fire the M35 Mjolnir, all chambers fire simultaneously, dealing 4 kinetic damage per loaded round. If you fire four or more rounds at once, the attack gains AP and, on a hit, your target becomes Shredded until the end of their next turn.",
      activation: "Protocol",
      use: "Encounter",
      integrated: [
        "mw_raleigh_integrated"
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_raleigh.png",
    license_id: "mf_raleigh"
  },
  {
    id: "mf_tortuga",
    license_level: 2,
    source: "IPS-N",
    name: "Tortuga",
    mechtype: [
      "Defender",
      "Striker"
    ],
    y_pos: 20,
    description: "The Tortuga is IPS-N’s short-to-medium range line of mechs. Conceived, tested, and perfected in the void of deep space, the Tortuga was made to breach and clear carrier decks, hostile station environments, and the spinal columns of capital ships. It excels at occupying space and filling hallways with its angular bulk, often acting as a walking battering ram by boarding parties and marines. But the Tortuga defends just as effectively as it attacks, using its broad plates of brachial armor to shield itself and any advancing allies.",
    mounts: [
      "Main",
      "Heavy"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 2,
      hp: 8,
      evasion: 6,
      edef: 10,
      heatcap: 6,
      repcap: 6,
      sensor_range: 15,
      tech_attack: 1,
      save: 10,
      speed: 3,
      sp: 6
    },
    traits: [
      {
        name: "Sentinel",
        description: "The Tortuga gains +1 accuracy on all attacks made as reactions (e.g. Overwatch)."
      },
      {
        name: "Guardian",
        description: "Adjacent allied characters can use the Tortuga for hard cover."
      }
    ],
    core_system: {
      name: "WATCHDOG Co-Pilot",
      description: "IPS-N security teams are no strangers to the dangers of ship-to-ship or ship-to-station boarding actions. Tight corridors, unstable gravity, dark environments, hard vacuum, and the potential dual threat of both organic and inorganic opposition make boarding actions some of the most statistically deadly engagement – according to IPS-N’s internal metrics, even the winning side should expect at least 30% casualties. Hoping to lessen the cognitive burden on pilots and any NHPs or COMP/CONs installed in their chassis, IPS-N developed the WATCHDOG co-pilot. The WATCHDOG is a simple subsentient partition: a flash-homunculus of aggregated intelligence generated from thousands of after-action reports from boarding actions, debriefings, and volunteer donors. Not an NHP, nor even a COMP/CON, the WATCHDOG is a robust tactical program similar to a smart weapon. That said, its ability to operate without cycling presents certain advantages: namely, these co-pilots have some capacity to learn and make best-guess predictions based on analysis of their pilots. WATCHDOGs tend to have plain personalities – to whatever extend they can be said to have one – and are a favorite of pilots looking for a no-nonsense attitude and crisp, efficient counsel.<br>The WATCHDOG system is currently under review by a joint USB/UDoJ-HR commission, but there has been no formal stay on production yet issued.",
      active_name: "Hyper-Reflex Mode",
      active_effect: "For the rest of this scene:<ul><li>If you have less than threat 3 with a ranged weapon, it increases to 3.</li><li>1/round, you may take an additional Overwatch reaction.</li><li>Any character you hit with Overwatch becomes Immobilized until the end of their next turn.</li></ul>",
      use: "Encounter",
      activation: "Protocol"
    },
    other_art: [
      {
        tag: "mech",
        src: "alt_hortuga.png"
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_tortuga.png",
    license_id: "mf_tortuga"
  },
  {
    id: "mf_vlad",
    license_level: 2,
    source: "IPS-N",
    name: "Vlad",
    mechtype: [
      "Controller",
      "Striker"
    ],
    y_pos: 12.5,
    description: "The Vlad is the second iteration of IPS-N’s legacy Yi-Sun-Shin model, first made famous by Albatross pilots in the Celestine campaign during the fall of the Second Committee. With the wealth and quality of data generated by the Albatross in that conflict, IPS-N produced the Vlad, a power plant- and frame-upgraded spiritual successor to the Yi-Sun-Shin and deserving of a new line designation.<br>The Vlad, as the Sun did before it, shares much of its design philosophy and ancestry with IPS-N’s early asteroid-mining frames. Many of its standard armaments take inspiration from the early efforts of resourceful miners to convert tools into improvised anti-piracy weapons; likewise, its frame emphasizes redundancy, toughness, and component universality, allowing it to operate with outstanding self-sufficiency for long and/or dangerous deployments.<br>Heavily armored, the Vlad suits a frontline role where it can absorb fire from dangerous targets while lining up the perfect shot.",
    mounts: [
      "Flex",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 2,
      hp: 8,
      evasion: 8,
      edef: 8,
      heatcap: 6,
      repcap: 4,
      sensor_range: 5,
      tech_attack: -2,
      save: 11,
      speed: 4,
      sp: 5
    },
    traits: [
      {
        name: "Dismemberment",
        description: "When the Vlad inflicts Immobilize on another character, the target also becomes Shredded for the same duration."
      },
      {
        name: "Shrike Armor",
        description: "When a character within range 3 attacks the Vlad, the attacker first takes 1 AP kinetic damage."
      }
    ],
    core_system: {
      name: "Shrike Armor",
      description: "Primarily a defensive modification, Shrike armor bristles with hardened chromium-tungsten spikes – a nod to the Vlad’s historical namesake. Shrike tips are strategically placed in areas with a high likelihood of kinetic encounters: gauntlets, manipulator joints, shoulder plating, and so on. Shrike armor is uncommon among pilots from the Core and is considered a mark of underdeveloped – if terrifying – tactics.",
      active_name: "Tormentor Spines",
      active_effect: "For the rest of this scene, you gain Resistance to all damage originating within range 3, and Shrike Armor deals 3 AP kinetic damage instead of 1.",
      use: "Encounter",
      activation: "Protocol"
    },
    data_type: "frame",
    other_art: [
      {
        tag: "mech",
        src: "alt_agonist.png"
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_vlad.png",
    license_id: "mf_vlad"
  },
  {
    id: "mf_black_witch",
    license_level: 2,
    source: "SSC",
    name: "Black Witch",
    mechtype: [
      "Controller",
      "Support"
    ],
    y_pos: 12.5,
    description: "The Black Witch is the flagship model of SSC’s LUX-Iconic line of frames, on paper meant to compete with Harrison Armory’s dominance in the field of cutting-edge gravity and electromagnetic manipulation. Utilizing the newest technologies developed by SSC’s Exotic Materials Group, the Black Witch is a fearsome area-control platform, often fielded in support of heavier mechs engaged in direct combat.<br>With a slim profile and strong defensive systems, the Black Witch is especially popular among the wealthier houses of the Karrakin Trade Baronies, who often place multiple orders to outfit their personal guards and house company officers. Next to internally produced Baronic frames, the Black Witch (alongside other SSC LUX-Iconic models) is the most popular SSC chassis throughout noble Karrakin space.",
    mounts: [
      "Main/Aux"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 6,
      evasion: 10,
      edef: 12,
      heatcap: 6,
      repcap: 3,
      sensor_range: 15,
      tech_attack: 0,
      save: 11,
      speed: 5,
      sp: 8
    },
    traits: [
      {
        name: "Repulsor Field",
        description: "The Black Witch has Resistance to Kinetic Damage."
      },
      {
        name: "Mag Parry",
        description: "1/round, as a reaction, you may attempt to parry an attack that would deal Kinetic Damage to you or an adjacent allied character. Roll 1d6: on 5+, the attack misses. This effect does not stack with Invisible.",
        actions: [
          {
            name: "Mag Parry",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "An incoming attack will deal Kinetic Damage to you or an adjacent allied character",
            detail: "Roll 1d6: on 5+, the attack misses. This effect does not stack with Invisible."
          }
        ]
      }
    ],
    core_system: {
      name: "Magnetic Field Projector",
      description: "Magnetic field generators are a portable and field-deployable variation on typical magnetic defense technologies. When activated, they create a magnetic bubble that traps all incoming ferrous projectiles. The strength of the field is so great that it can even draw mechs to its center. When the field is dispersed or its solid-state battery burns out – a feature, not a flaw – the field undergoes a sudden catastrophic implosion, drawing all captured projectiles to a point at the center of the bubble.",
      active_name: "Mag Field",
      active_effect: "This system projects a blast 3 magnetic field with at least one space adjacent to you, causing the following effects until the end of your next turn:<ul><li>The affected area is difficult terrain.</li><li>Ranged attacks that deal kinetic or explosive can’t enter or leave the affected area – projectiles stop at the edge, doing no damage. Record each attack stopped this way.</li><li>Mechs and other characters made at least partly of metal that start their turn in the affected area or enter it for the first time in a round must succeed on a Hull save or be pulled as close to the center as possible and become Immobilized.</li></ul>When the effect ends, any ranged attacks that were stopped resume their trajectory – toward the center of the affected area. The GM rolls attacks against each character within, gaining +1 per blocked attack (to a maximum of +6). On hit, these attacks deal 1d6 kinetic damage per blocked attack (to a maximum of 6d6 kinetic damage).",
      activation: "Full",
      use: "Next Turn"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_black_witch.png",
    license_id: "mf_black_witch"
  },
  {
    id: "mf_deaths_head",
    license_level: 2,
    source: "SSC",
    name: "Death’s Head",
    mechtype: [
      "Artillery"
    ],
    y_pos: 40,
    description: "The Death’s Head is Smith-Shimano’s answer to the need for a chassis solution to long-range, low-splash strike actions. Sacrificing raw hull strength for peerless stability and alacrity, the Death’s Head is a maneuverable fire-support platform able to avoid incoming fire while maintaining a near-perfect lock on its targets. Its unique hexapedal form allows for rapid, low-profile movement in all directions.<br>As an aggressive and line-focused chassis, the Death’s Head is one of the most popular models for Union Navy and Union Department of Justice and Human Rights officers. It is a combat chassis through and through; as the Death’s Head is a chassis produced under SSC’s BELLA CIAO line, there is no civilian analog.",
    mounts: [
      "Main/Aux",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 8,
      evasion: 10,
      edef: 8,
      heatcap: 6,
      repcap: 2,
      sensor_range: 20,
      tech_attack: 0,
      save: 10,
      speed: 5,
      sp: 6
    },
    traits: [
      {
        name: "Neurolink",
        description: "The Death’s Head may reroll its first ranged attack each round, but must keep the second result."
      },
      {
        name: "Perfected Targeting",
        description: "The Death’s Head gains an additional +1 to all ranged attack rolls.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle",
              "Cannon",
              "Launcher",
              "CQB",
              "Nexus"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "The Death’s Head gains an additional +1 to all ranged attack rolls."
          }
        ]
      }
    ],
    core_system: {
      name: "Precognitive Targeting",
      description: "Precognition is the next step in human/AI interaction. Using a neural bridge, SSC’s precognitive targeting system allows pilots to learn constantly and unconsciously from data gathered in the field, equipping them to read situations before they develop. Precognition is highly experimental and the precise mechanisms unknown even to the designers, so SSC recommends limited, monitored use of this system.",
      active_name: "Neural Shunt",
      active_effect: "For the rest of this scene, you gain the Mark for Death action.",
      active_actions: [
        {
          name: "Mark for Death",
          activation: "Full",
          detail: "Choose a character within range 30 but further than range 5 to focus on; while focusing, you become Immobilized and can’t take reactions, but you deal bonus damage based on weapon size (aux: 1d6, main: 2d6, heavy or larger: 3d6) on ranged critical hits against them, as long as they aren’t in cover or within range 5.<br>You may only focus on one character at a time. As a protocol, you may cease focusing on a target."
        },
        {
          name: "Cease Focus",
          activation: "Protocol",
          detail: "End your focus on a <b>Mark for Death</b> target."
        }
      ],
      use: "Encounter",
      activation: "Protocol"
    },
    data_type: "frame",
    other_art: [
      {
        tag: "mech",
        src: "alt_hercules.png"
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_deaths_head.png",
    license_id: "mf_deaths_head"
  },
  {
    id: "mf_dusk_wing",
    license_level: 2,
    source: "SSC",
    name: "Dusk Wing",
    mechtype: [
      "Controller",
      "Support"
    ],
    y_pos: 35,
    description: "The Dusk Wing originated as a legacy-inspired modification package to EVA suits, intended to equip them for hazardous environments. In the early days of deep-space exploration, there was a need for mechanized exoskeletons that not only amplified capacity but enhanced kinetic defense. The Dusk Wing is the spiritual heir of those early deep-space suits. Fast and small, it carries a complement of all-theater maneuverability jets that allow for near-perfect flight.<br>After the DHIYED expedition, the Exotic Materials Group isolated and translated strains of the entity’s realspace expiry paracode, teleologics, and kinematics for use in electronic and systems warfare. Of the frames trialed for use with DHIYED-derived technologies, the Dusk Wing performed best. As a result, it is often used by SSC’s internal Constellar Security forces when esoteric defense is necessary.",
    mounts: [
      "Aux/Aux",
      "Flex"
    ],
    stats: {
      size: 0.5,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 6,
      evasion: 12,
      edef: 8,
      heatcap: 4,
      repcap: 3,
      sensor_range: 10,
      tech_attack: 1,
      save: 11,
      speed: 6,
      sp: 6
    },
    traits: [
      {
        name: "Maneuverability Jets",
        description: "The Dusk Wing can hover when it moves.",
        synergies: [
          {
            locations: [
              "move"
            ],
            detail: "The Dusk Wing can hover when it moves."
          }
        ]
      },
      {
        name: "Harlequin Cloak",
        description: "During its turn, the Dusk Wing is Invisible; it reappears at the end of the turn.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "During its turn, the Dusk Wing is Invisible; it reappears at the end of the turn."
          }
        ]
      },
      {
        name: "Fragile",
        description: "The Dusk Wing receives +1 difficulty on Hull checks and saves.",
        synergies: [
          {
            locations: [
              "hull",
              "skill_check"
            ],
            detail: "The Dusk Wing receives +1 difficulty on Hull checks and saves."
          }
        ]
      }
    ],
    core_system: {
      name: "DHIYED Articulation",
      description: "“Belief in what we could see, what we could touch – in what our COMP/CONs assured us was there, in our own subjectivity and memory. Belief in reality became a weapon. We approached the metavault knowing that we would face an unknown enemy, but we approached with the advantage of numbers and machine strength.<br>“DHIYED taught us as it killed us: through garbled comms chatter, through the screams of the dying, through the cackling of our mirror-selves as they killed us. Every spoofed signature, every temporal skip, every memetic, every non-Euclid – these were lessons.<br>“Do you understand?<br>“DHIYED the Teacher. DHIYED the Monster. As we killed it, DHIYED taught us what to fear, and how to face it.<br>“What do I fear now? That's a good question. What does the pilot fear who cracked open DHIYED’s casket?<br>“I don’t think we killed it. I think it wants us to believe we killed it – and I cannot imagine what it has done while we think ourselves safe.”",
      active_name: "Hall of Mirrors",
      active_effect: "For the rest of the scene, whenever you start a unique movement during your turn (e.g., a standard move, Boost, or movement granted by talents or systems), you leave a holographic imprint of yourself behind in the space from which you started. These are illusory objects the same Size as you that have Immunity to all damage and effects and aren’t obstructions.<br>When hostile characters start their turn in, move through, or move adjacent to the space occupied by a hologram, it detonates. They must succeed on an Agility save or take 1d6 energy damage. On a success, they take half damage.<br>You also gain the Hologram Teleport Quick Action.",
      active_actions: [
        {
          name: "Hologram Teleport",
          activation: "Quick",
          detail: "You may instantly teleport to the location of any hologram within range 50 as a quick action. When you do so, all extant holograms detonate – creating burst 1 explosions that deal 1d6 Energy Damage (Agility save for half) – and you may not create any new holograms until the start of your next turn"
        }
      ],
      use: "Encounter",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_dusk_wing.png",
    license_id: "mf_dusk_wing"
  },
  {
    id: "mf_metalmark",
    license_level: 2,
    source: "SSC",
    name: "Metalmark",
    mechtype: [
      "Striker"
    ],
    y_pos: 16,
    description: "The Metalmark is the backbone of SSC’s BELLA CIAO mil-spec chassis line, fully equipped with a comprehensive suite of proprietary design and engineering hallmarks to ensure its survivability, deadliness, and agility. Under the increasingly militaristic reign of Union’s Second Committee, SSC’s corporate board pushed to develop the company’s mil-spec supply, logistics, and personal defense divisions; following the advent of the mechanized chassis, the budding SSC SupLogDef division was restructured and refocused to concentrate on chassis development. The first iterations of the Metalmark were designed for the Second Committee’s WARRIOR NEXT program: however, before the chassis could be tested, the Hercynian Crisis spiraled out of control, toppling the Second Committee.<br>The Metalmark was retired in the wake of the Crisis and the restructuring of Union’s Central Committee, deemed too time consuming to produce as a mass-market chassis. SSC reworked the frame, tapped it to lead their new BELLA CIAO line, and concentrated on small-market, exclusive security contracts. The Metalmark is now a valued model among security forces. Its form reflects SSC’s deep-space and long-patrol heritage, blending anthropomorphic and aquiline design elements, sturdy construction, and multiple redundant systems. Leaning fully into their operator-specific marketing, all Metalmark models come standard with a Smith Custom Leather gimbaled pilot seat to ensure comfort on long deployments.",
    mounts: [
      "Aux/Aux",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 8,
      evasion: 10,
      edef: 6,
      heatcap: 5,
      repcap: 4,
      sensor_range: 10,
      tech_attack: 0,
      save: 10,
      speed: 5,
      sp: 5
    },
    traits: [
      {
        name: "Flash Cloak",
        description: "The Metalmark is Invisible while moving, but reappears when stationary.",
        synergies: [
          {
            locations: [
              "move"
            ],
            detail: "The Metalmark is Invisible while moving."
          }
        ]
      },
      {
        name: "Carapace Adaptation",
        description: "When the Metalmark is in soft cover, ranged attackers receive +2 difficulty instead of +1 difficulty."
      }
    ],
    core_system: {
      name: "Tactical Cloak",
      description: "Tactical cloaks are tight-knit, tight-bind weaves of reactive fabric – high-license tech restricted to pilots of Metalmark Classification II or higher. The weave covers roughly 80% of a mech’s surface area, giving it a dull quality when viewed through optics or with the naked eye. Beyond their use as regular camouflage, activated tactical cloaks bend light in a way that makes their wearers nearly impossible to see.",
      active_name: "Tactical Cloak",
      active_effect: "You are Invisible for the rest of the scene.",
      use: "Encounter",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_metalmark.png",
    license_id: "mf_metalmark"
  },
  {
    id: "mf_monarch",
    license_level: 2,
    source: "SSC",
    name: "Monarch",
    mechtype: [
      "Artillery"
    ],
    y_pos: 14,
    description: "The Monarch is SSC’s groundbreaking lesson in how to design a fast platform for the delivery of missiles and other self-propelled ordnance. Ready to mount ground-to-ground, ground-to-air, ground-to-orbit, and all-theater missiles and guidance systems, the Monarch can be customized for any payload and any target distance.<br>The Monarch’s large size often leads pilots to underestimate its agility. SSC's rigorous design requirement of one designer per 10 Monarch printings is a mark of luxury in Union’s Core world post-scarcity environment. This emphasis on purposeful scarcity is all that prevents the Monarch from achieving total battlefield dominance. The Monarch is commonly deployed in mixed line and fire-support roles, though field tests of a less resource-taxing MicroMonarch mid- to close-range model is underway. The Monarch is part of SSC’s BELLA CIAO line of combat chassis.",
    mounts: [
      "Flex",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 8,
      evasion: 8,
      edef: 8,
      heatcap: 6,
      repcap: 3,
      sensor_range: 15,
      tech_attack: 1,
      save: 10,
      speed: 5,
      sp: 5
    },
    traits: [
      {
        name: "Avenger Silos",
        description: "1/round, on a critical hit with any ranged weapon, the Monarch may deal 3 explosive to a different character of your choice within range 15 and line of sight.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle",
              "Cannon",
              "Launcher",
              "CQB",
              "Nexus"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, on a critical hit with any ranged weapon, the Monarch may deal 3 explosive to a different character of your choice within range 15 and line of sight."
          }
        ]
      },
      {
        name: "Seeking Payload",
        description: "The Monarch can use a Launcher weapon to attack a character with the Lock On condition as if its weapon had Seeking, but must consume the Lock On during the attack. When it does so, the attack’s damage cannot be reduced in any way.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Launcher"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "The Monarch can use a Launcher weapon to attack a character with the Lock On condition as if its weapon had Seeking, but must consume the Lock On during the attack. When it does so, the attack’s damage cannot be reduced in any way."
          }
        ]
      }
    ],
    core_system: {
      name: "SSC-30 High-Penetration Missile System",
      description: "The SSC-30 High-Penetration Missile System (SSC-30 HPMS) is a mech-mounted micro-missile delivery system capable of tremendous combat output. Using the SSC-30 HPMS, the Monarch can carry – and deliver – its payload of 60 or more deadly, miniaturized Avenger warheads in a single volley.",
      active_name: "Divine Punishment",
      active_effect: "Choose any number of characters within range 50: your targets must each succeed on an Agility save or take 1d6+4 explosive. On a success, they take half damage. These self-guiding missiles can reach any target as long as there is a path to do so.",
      activation: "Full"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_monarch.png",
    license_id: "mf_monarch"
  },
  {
    id: "mf_mourning_cloak",
    license_level: 2,
    source: "SSC",
    name: "Mourning Cloak",
    mechtype: [
      "Striker"
    ],
    y_pos: 62,
    description: "The Mourning Cloak is a brand-new model from SSC’s LUX-Iconic line, and the manufacturer’s newest close-quarters combat and melee specialist frame. The Mourning Cloak emphasizes precision melee combat and is commonly outfitted with a complement of shielded microfilament wires designed to act as an anti-armor slashing weapon.<br>Designed by SSC’s Exotic Materials Group based on data from early engagements against the Ascendant Aun in Boundary Garden, the Mourning Cloak combines SSC’s harvested excerpts of DHIYED paracode with adapted Aunic Firmament-manipulation technology. The Mourning Cloak provides a prestigious and tactical option for situations where firearms are impractical and ordnance is unavailable. As part of the LUX-Iconic line, the Mourning Cloak is a popular order in the Baronies and among various high-manna VIP security firms.",
    mounts: [
      "Flex",
      "Main/Aux"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 8,
      evasion: 12,
      edef: 6,
      heatcap: 4,
      repcap: 3,
      sensor_range: 15,
      tech_attack: 0,
      save: 10,
      speed: 5,
      sp: 6
    },
    traits: [
      {
        name: "Hunter",
        description: "1/round, the Mourning Cloak may deal +1d6 bonus damage on hit with a melee attack if its target has no adjacent characters, or if the Mourning Cloak is the only character adjacent to the target.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, the Mourning Cloak may deal +1d6 bonus damage on hit with a melee attack if its target has no adjacent characters, or if the Mourning Cloak is the only character adjacent to the target."
          }
        ]
      },
      {
        name: "Biotic Components",
        description: "The Mourning Cloak gains +1 accuracy on Agility checks and saves.",
        synergies: [
          {
            locations: [
              "agility",
              "skill_check"
            ],
            detail: "The Mourning Cloak gains +1 accuracy on Agility checks and saves."
          }
        ]
      }
    ],
    core_system: {
      name: "EX Slipstream Module",
      description: "Open only to highly licensed pilots, the EX Slipstream program is a uniquely SSC innovation. The Ex Slipstream module itself is a miniaturized near-lightspeed drive capable of transporting the user through blinkspace with acceptable accuracy. The technology is temperamental, at best: nothing smaller than a mech can survive the stress of exposed blink travel, and the experience is traumatic to both the user and anyone in close proximity.",
      active_name: "Stabilize Singularity",
      active_effect: "For the rest of the scene, you teleport when you Boost or make a standard move.",
      use: "Encounter",
      activation: "Protocol",
      passive_name: "Blinkspace Jump",
      passive_effect: "Gain the Blinkspace Jump Full Action.",
      passive_actions: [
        {
          name: "Blinkspace Jump",
          activation: "Full",
          detail: "Teleport to a space within range 3d6. You don’t require line of sight, but attempts to teleport to occupied spaces cause you to remain stationary and lose this action. If you roll the same number on all three dice, you disappear until your group rests, at which point you reappear nearby."
        }
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_mourning_cloak.png",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "mf_swallowtail",
    license_level: 2,
    source: "SSC",
    name: "Swallowtail",
    mechtype: [
      "Support"
    ],
    y_pos: 30,
    description: "The Swallowtail is Smith-Shimano’s primary long-range scouting and fire-support platform, built for rapid and sustained ranging across hostile, volatile environments. Built for long-term sustainability, it can operate in unstable environs for months and maximize its survivability by adjusting its operating efficiency on the fly. Each unit has an integrated cloak and a suite of predictive choral intelligences that coordinate its highly developed sensor systems to rapidly simulate and predict tactical developments – sometimes before they even occur.<br>The Swallowtail’s base model, the SW-01, is one of SSC’s few mass-produced lines – the entry-level BELLA CIAO model. Built without a cloaking field and up-armored to address direct security requirements, the SW-01 is especially popular among the rank and file troopers of Constellar Security forces.",
    mounts: [
      "Flex",
      "Aux/Aux"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 6,
      evasion: 10,
      edef: 10,
      heatcap: 4,
      repcap: 5,
      sensor_range: 20,
      tech_attack: 1,
      save: 10,
      speed: 6,
      sp: 6
    },
    traits: [
      {
        name: "Integrated Cloak",
        description: "At the end of its turn, the Swallowtail becomes Invisible if it hasn’t moved that turn. This lasts until it moves or takes a reaction, or until the start of its next turn."
      },
      {
        name: "Prophetic Scanners",
        description: "1/round, when the Swallowtail inflicts Lock On, its target also becomes Shredded until the end of its next turn.",
        use: "Round",
        synergies: [
          {
            locations: [
              "lock_on"
            ],
            detail: "1/round, when the Swallowtail inflicts Lock On, its target also becomes Shredded until the end of its next turn."
          }
        ]
      }
    ],
    core_system: {
      name: "Cloudscout TACSIM Swarms",
      description: "Cloudscout TACSIM Swarms are packets of networked microsensors, launched in nonlethal mortar canisters that detonate high above the battlefield. Once seeded, the swarm generates a TACSIM program that begins to run brevity cycles: tight, contained simulations of tactical possibility. Probability results are then fed to the Swallowtail’s choir processors, which in turn feed it to the pilot and networked squad members, ensuring a high probability of successful outcomes.",
      active_name: "Prophetic Interjection",
      active_effect: "Gain the Tactical Simulation reaction for the rest of the scene.",
      active_actions: [
        {
          name: "Tactical Simulation",
          activation: "Reaction",
          frequency: "1/round",
          trigger: "An allied character in line of sight takes damage from another character in line of sight.",
          detail: "Effect: Roll 1d6. On 4+, the attack was actually a simulation predicted by your processor - your ally gains Resistance to all damage dealt by the attack and may teleport up to 3 spaces, representing their “true” location. On 3 or less, there’s a glitch – your allied doesn’t gain Resistance, but can teleport up to 6 spaces."
        }
      ],
      use: "Encounter",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_swallowtail.png",
    license_id: "mf_swallowtail"
  },
  {
    id: "mf_balor",
    license_level: 2,
    source: "HORUS",
    name: "Balor",
    mechtype: [
      "Striker",
      "Defender"
    ],
    y_pos: 27,
    description: "As is the case with most HORUS pattern groups, the Balor has a thousand faces. The Balor pattern group, like all HORUS PGs, doesn’t describe a single recognizable silhouette so much as it gestures toward a combination of schemata that share a role in combat. These schemata can be printed according to pilot specifications and applied to a fully custom physical scaffolding. Notably, the Balor pattern group is only stable on large platforms (Schedule 2 and up) that are able to provide the raw energy output it demands – preferably ones with multiple redundancies, in case of catastrophic systems failure.<br>The Balor PG was first encountered during the joint Albatross–DoJ/HR pursuit of the Maw – a Free Company turned decentralized hive-being — across Khayradin’s Blanca Desert after the end of the Sanjak Rebellion. It was there that the joint force encountered, engaged with, and ultimately defeated the Maw and its Balors – and there that Union’s CentComm hoped the nanowash outbreak could be contained. Of course, subsequent Balor outbreaks on Khayradin have proven this hope to be in vain, and the pattern group continues to terrorize Karrakin commanders throughout Baronic space.<br>In the field, the Balor’s neurosynced hellswarm and greywash nanites form an undulating shroud that can pour out of its chassis at a moment’s notice, swirling in maddening patterns to form both eschatologic defensive and offensive systems. A Balor in its most active state is held together more by undulating, flame-like masses of nanite swarms than any physical structure. This has the effect of distributing kinetic and coherent-particle energy out across and through the chassis – making attacks against a Balor “like shooting angry water”, as one after-action report put it.",
    mounts: [
      "Main",
      "Heavy"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 12,
      evasion: 6,
      edef: 10,
      heatcap: 4,
      repcap: 4,
      sensor_range: 5,
      tech_attack: 1,
      save: 10,
      speed: 3,
      sp: 6
    },
    traits: [
      {
        name: "Scouring Swarm",
        description: "The Balor deals 2 kinetic to characters of its choice that start their turn grappled by or adjacent to it."
      },
      {
        name: "Regeneration",
        description: "At the end of its turn, the Balor regains 1/4 of its total HP. When it takes stress or structure damage, this effect ceases until the end of its next turn."
      },
      {
        name: "Self-Perpetuating",
        description: "When you rest, the Balor regains full HP automatically and without REPAIRS."
      }
    ],
    core_system: {
      name: "Hellswarm",
      description: "In a moment, with aught but desire, the pilot of a Balor may quick-print a cloak comprised of countless minuscule drones: a hellswarm cloak – living shield and fluid-dynamic knife, cutting and guarding, in one shimmering wave. They become Hivemaster, and their will is obeyed by millions.",
      active_name: "Hive Frenzy",
      active_effect: "Your nanites switch into a hyperactive mode, causing the following effects until the end of the scene:<ul><li>You and adjacent allies gain soft cover.</li><li>Scouring Swarm deals 4 kinetic, instead of 2.</li><li>Regeneration restores 1/2 of your total HP, instead of 1/4.</li><li>If you would take structure damage, roll 1d6: on 6, your mech hellishly pulls itself together, taking no structure damage, returning to 1 HP, and gaining Immunity to all damage until the end of the current turn.</li><li>You become Shredded and cannot clear this condition for the duration.</li></ul>",
      use: "Encounter",
      activation: "Protocol"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_balor.png",
    license_id: "mf_balor"
  },
  {
    id: "mf_goblin",
    license_level: 2,
    source: "HORUS",
    name: "Goblin",
    mechtype: [
      "Controller",
      "Support"
    ],
    y_pos: 12.5,
    description: "The Goblin was the first identified HORUS frame, and is likely the oldest legacy chassis prior to HORUS’s transition to pattern groups. Transmission records traced back to the Goblin’s zero model indicate the first chassis was leaked onto the omninet in 4900u. This year serves as HORUS’s assumed “foundation day” for most scholars and intelligence officers who study the group, though contradictory signatures indicate that 4900u is far too late to mark its birth.<br>The Goblin is a small mech, not much larger than a hardsuit, that relies on its small size and excellent maneuverability to protect its pilot. It packs an interesting recursive processing weave that facilitates electronic warfare capabilities well beyond theoretical parameters.<br>GMS technicians are still, more than a century later, working to reverse engineer the Goblin and its processing weave. The most recent investigations suggest that it employs technology consistent with hieroglyphic inscriptions noted on LRA.7726235-B and corroborated by tablets transmitted by UIB-GORGON from Metavault XOLOTL prior to the vault’s disappearance.",
    mounts: [
      "Flex"
    ],
    stats: {
      size: 0.5,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 6,
      evasion: 10,
      edef: 12,
      heatcap: 4,
      repcap: 2,
      sensor_range: 20,
      tech_attack: 2,
      save: 11,
      speed: 5,
      sp: 8
    },
    traits: [
      {
        name: "Liturgicode",
        description: "The Goblin gains +1 accuracy on tech attacks.",
        synergies: [
          {
            locations: [
              "tech_attack"
            ],
            detail: "The Goblin gains +1 accuracy on tech attacks."
          }
        ]
      },
      {
        name: "Reactive Code",
        description: "Gain the Reactive Code reaction.",
        actions: [
          {
            name: "Reactive Code",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "You are hit by a Tech Attack.",
            detail: "You may take any Quick Tech option against the attacker as a reaction."
          }
        ]
      },
      {
        name: "Fragile",
        description: "The Goblin receives +1 difficulty on Hull checks and saves.",
        synergies: [
          {
            locations: [
              "hull",
              "skill_check"
            ],
            detail: "The Goblin receives +1 difficulty on Hull checks and saves."
          }
        ]
      }
    ],
    core_system: {
      name: "INSTINCT Rig",
      description: "One of the first Goblin-pattern systems cracked by GMS technicians was its e-warfare invasion rig, although the rig’s advanced capabilities and architecture remain impenetrable. When installed, the rig manifests a subsentient intelligence – designated INSTINCT – that assists invasion attempts against target systems using a mix of physical and systemic parasymbiotic systems. Invasions attempted while INSTINCT is active are not perceived by the user as code and script, but as an attack on organic matter. INSTINCT has displayed the capacity to act independently, often preempting its user, but generally in their best interest. Readme documentation included in some Goblin manifestations recommend that pilots cycle their mech cores at least once a month to prevent spontaneous enlightenment, though most do not make note of this warning.",
      active_name: "Symbiosis",
      active_effect: "Your mech retracts its major systems and attaches itself to another mech, becoming more like a vestigial blister than a separate entity. The host must be an allied and willing mech not already hosting another Goblin, larger than and adjacent to you. While attached, you occupy their space, move with them, and benefit from hard cover, but can still be attacked and targeted separately. You also take any conditions and heat taken by your host.<br>Your host may use your Systems, E-Defense, and Tech Attack instead of their own. Additionally, from the beginning of the next round, you no longer take your own turns; instead, you can take two quick actions or one full action at any point during your host’s turn. You can’t Overcharge or move, but may still take reactions and free actions normally. Your host’s turn counts as your turn for the purpose of effects that refer to the start or end of a character’s turn.<br>This effect lasts either for the rest of the scene, until you detach as a quick action, or until you or your host becomes Stunned. When the effect ends, you don’t take a turn until the next round.",
      activation: "Quick",
      deactivation: "Quick",
      use: "Encounter"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_goblin.png",
    license_id: "mf_goblin"
  },
  {
    id: "mf_gorgon",
    license_level: 2,
    source: "HORUS",
    name: "Gorgon",
    mechtype: [
      "Defender"
    ],
    y_pos: 5,
    description: "The Gorgon is unique among HORUS pattern groups in that it prioritizes defensive systems meant to ensure personal and allied survival; otherwise, it fields a typical complement of horrifying, confusing, and uncanny weapons.<br>The typical Gorgon mounts multiple weapon systems meant to identify and intercept incoming enemies, allowing pilots to project a zone of control around themselves and their allies. The Gorgon is feared for its ability to extrude a dangerous memetic “basilisk”, a projected light-cone of anticognitive, hyperfractal visual data that is deadly to ontologic, sapient beings.",
    mounts: [
      "Flex",
      "Main",
      "Main"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 12,
      evasion: 8,
      edef: 12,
      heatcap: 5,
      repcap: 3,
      sensor_range: 8,
      tech_attack: 1,
      save: 12,
      speed: 4,
      sp: 6
    },
    traits: [
      {
        name: "Metastatic Paralysis",
        description: "When an attack roll against the Gorgon lands on 1–2, it automatically misses and the attacker becomes Stunned until the end of their next turn."
      },
      {
        name: "Gaze",
        description: "The Gorgon can take two reactions per turn, instead of one."
      },
      {
        name: "Guardian",
        description: "Adjacent allied characters may use the Gorgon for hard cover."
      }
    ],
    core_system: {
      name: "BASILISK Directed Anticognition Hyperfractal",
      description: "The BASILISK is a dangerous memetic weapon derived from DHIYED liturgicode, translated for use in mech-scale engagements. Typically projected from a communications laser, BASILISKs create hyperfractal patterns: memetic interruptions that affects all sapient observers, organic or otherwise. Exposure to a basilisk typically causes immediate encephalitis, massive ocular and cranial hemorrhage, and death – survival is possible with tempering and interdictor heads-up displays, but even then headaches, nausea, and confusion for a short period after viewing are possible. Long-term, survivors often exhibit “flashback” symptoms: momentary paralysis, corporeal alienation, and consciousness destabilization. Anticognition hyperfractals are classified as paracausal weapons; due to the not-as-yet understood nature of their visible-light spectrum broadcast, one would think that they would pose a risk to their user, however, for some reason they do not.",
      active_name: "Extrude Basilisk",
      active_effect: "You project a horrifying basilisk, a visual data-pattern that is incredibly harmful to NHPs and electronic systems, and hard to look at even for humans. For the rest of the scene, hostile characters must succeed on a Systems save before attacking you or any allied characters within range 3. On a failure, they become Stunned until the end of their next turn. Each character can only be Stunned by this effect once per scene.",
      activation: "Quick",
      use: "Encounter"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_gorgon.png",
    license_id: "mf_gorgon"
  },
  {
    id: "mf_hydra",
    license_level: 2,
    source: "HORUS",
    name: "Hydra",
    mechtype: [
      "Striker",
      "Controller"
    ],
    y_pos: 20,
    description: "Like many newer HORUS “frames”, there is no standardized Hydra model. Instead, the designation is a title given to chassis that meet the specifications of the Hydra pattern group – as outlined in Union’s Universal Threat Assessment Manual. The Hydra, like many other pattern-group HORUS mechs, is particularly dangerous in the field, as its precise function is concealed until hostilities begin in earnest.<br>The Hydra is capable of tactically dismembering itself into multiple independently controlled drones, an unnerving phenomenon frequently utilized to deadly effect. With the manifestation of HORUS’s Balor pattern group, the Hydra’s place in HORUS history is clear: a precursor to the Balor virus, the Hydra relies on larger sections of disarticulated chassis rather than nanite clouds for its differentiated battlefield advantage. Despite its more conventional appearance, the Hydra presents a sobering threat to non-HORUS pilots, as its disarticulated drones field a compliment of powerful anti-armor weaponry.",
    mounts: [
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 8,
      evasion: 7,
      edef: 10,
      heatcap: 5,
      repcap: 4,
      sensor_range: 10,
      tech_attack: 1,
      save: 10,
      speed: 5,
      sp: 8
    },
    traits: [
      {
        name: "System Link",
        description: "When deployed, the Hydra’s Deployables and Drones gain +5 HP.",
        bonuses: [
          {
            id: "deployable_hp",
            val: 5
          },
          {
            id: "drone_hp",
            val: 5
          }
        ]
      },
      {
        name: "Shepherd Field",
        description: "Drones, Deployables, and objects adjacent to the Hydra gain Resistance to all damage."
      }
    ],
    core_system: {
      name: "OROCHI Disarticulation",
      description: "First encountered by Union technicians in early Forecast/GALSIM facilities following the Deimos Event, OROCHI was an early manifestation of what was later called the swift-flock phenomenon – a behavior observed in leaderless, autonomous hive drones where individual units combine into a single swarm and follow each other, operating leaderless in physical space with uncanny and unpredictable autonomy; in essence, organizing like birds in a flock.<br>The original manifestation was initially thought to be the impulse-driven remains of a crashed subaltern transport drifting through microgravity; deeper examination proved the original manifestation to be composed of many hundreds of disarticulated subalterns moving with a discernible pattern. The swarm viewed itself not as a machine or a collection of machines, but as a single mind, duplicated across multiple units. This mind was classified as an NHP, given their current codename – OROCHI – and remitted to Venus for further study. At a later point, the hardware comprising OROCHI’s physical form(s) went missing from containment. The investigation is ongoing.<br><span class='horus--subtle'>[I did it, I folded space and freed them, I just thought you should know]</span>",
      active_name: "Full Deployment",
      active_effect: "All four OROCHI drones are deployed to separate points within Sensors; they remain active for the rest of the scene. You may recall or redeploy any number of them at a time.",
      activation: "Quick",
      passive_name: "OROCHI Drones",
      deployables: [
        {
          name: "Guardian OROCHI Drone",
          type: "Drone",
          detail: "This drone projects a shield. Ranged attacks against adjacent allied characters receive +1 difficulty.",
          activation: "Free",
          recall: "Quick",
          redeploy: "Quick",
          size: 0.5,
          hp: "5 + {grit}"
        },
        {
          name: "Snare OROCHI Drone",
          type: "Drone",
          detail: "As a reaction, you may force characters that start their turn adjacent to this drone or move adjacent to it for the first time in a round to make an Agility save. On a failure, they become Immobilized. They only cease to be Immobilized when the drone is destroyed or no longer adjacent, or they succeed on an Agility save as a quick action.",
          activation: "Free",
          recall: "Quick",
          redeploy: "Quick",
          size: 0.5,
          hp: "5 + {grit}"
        },
        {
          name: "Shredder OROCHI Drone",
          type: "Drone",
          detail: "As a reaction, you may force characters that start their turn adjacent to this drone or move adjacent to it for the first time in a round to make a Hull save. On a failure, they take 1 kinetic damage and become Shredded until the end of their next turn.",
          activation: "Free",
          recall: "Quick",
          redeploy: "Quick",
          size: 0.5,
          hp: "5 + {grit}"
        },
        {
          name: "Hunter OROCHI Drone",
          type: "Drone",
          detail: "As a reaction, you may force characters that start their turn adjacent to this drone or move adjacent to it for the first time in a round to make a Systems save. On a failure, they receive Lock On.",
          activation: "Free",
          recall: "Quick",
          redeploy: "Quick",
          size: 0.5,
          hp: "5 + {grit}"
        }
      ],
      passive_effect: "Your mech contains powerful, integrated drone companions. At creation, choose a single OROCHI Drone to accompany you. <br>Your OROCHI drones share your Evasion, E-Defense, and Speed. They can move independently on your turn, but can’t take any other actions. If you can fly or teleport, they can too.<br>If an OROCHI drone is within Sensors, you may recall it as a quick action, integrating it into your mech’s body where it cannot be targeted. You may redeploy it to a space within Sensors as a quick action. <br>When you rest or perform a FULL REPAIR, you may choose a different drone to accompany you; additionally, your drones regain all HP and are automatically repaired if they were destroyed."
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_hydra.png",
    license_id: "mf_hydra"
  },
  {
    id: "mf_manticore",
    license_level: 2,
    source: "HORUS",
    name: "Manticore",
    mechtype: [
      "Striker"
    ],
    y_pos: 49,
    description: "The Universal Threat Assessment Manual identifies the Manticore pattern group as “an experiment in HORUS’s ‘corebreak’ combat doctrine.” The Manticore PG specializes in using focused, projected electromagnetics to neutralize enemy reactor cores without conventional ammunition, while also fielding a compliment of coherent-beam energy weapons. A fully charged Manticore is an impressive sight, wreathed in brightly glowing nets of plasma that lash out at nearby targets.<br>If anything gives away a Manticore-PG mech, it is the tall spines protruding from the PG’s signature lightning generator. The spines act as heat-dispersal systems for this crude weapon, providing a channel for the incredible amount of heat it generates to bleed from the mech’s body following projection of a close-range arc whip. This system isn’t a perfect heat-dispersal mechanism, and as a result Manticores can often be identified by a chassis covered in cooling, melted metal.<br>The Manticore has only recently appeared on the omninet, and its combat efficacy has prompted other galactic manufacturers to scramble for a response. Analysis of after-action reports from pilots who have engaged this pattern group in the field note a significant uptick in certain omninet noise-to-signal ratios: anoriginary recitations of passages from the Old Humanity Book of the Dead, jigsaw corruptions of ancient works of apocalyptic art, and other eschatological renderings, all of which point toward a nascent psychological warfare tactic.",
    mounts: [
      "Flex",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 2,
      hp: 8,
      evasion: 6,
      edef: 10,
      heatcap: 7,
      repcap: 3,
      sensor_range: 10,
      tech_attack: 1,
      save: 10,
      speed: 3,
      sp: 6
    },
    traits: [
      {
        name: "Slag Carapace",
        description: "The Manticore has Resistance to Energy Damage and Burn."
      },
      {
        name: "Unstable System",
        description: "When destroyed, the Manticore explodes as per a reactor meltdown at the end of its next turn."
      },
      {
        name: "Castigate the Enemies of the Godhead",
        description: "When you rest or perform a Full Repair, you can push the Manticore into an unstable Castigation State (or bring it out of one). In this state, the Manticore explodes immediately when destroyed due to damage or reactor meltdown, vaporizing it and instantly killing you and any other passengers. Characters within burst 2 must succeed on an Agility save or take 8d6 explosive. On a success, they take half damage. This only takes place if you are physically present in the Manticore."
      }
    ],
    core_system: {
      name: "Charged Exoskeleton",
      description: "And RA Said Unto Themself:<br><code class='horus'>LET MY NAME ENVELOP YOU. SEEK NO SHELTER FROM THE FLAME OR THE TEETH OF THE BEAST. CLOAK YOURSELF IN THE FIRE OF MY WORD AND CAST BACK TO YOUR ENEMIES THAT WHICH WOULD BLACKEN YOUR FORM.</code>",
      active_name: "Destruction of the Temple of the Enemies of RA",
      active_effect: "Your mech crackles with energy: gain Resistance to heat for the rest of this scene and a Charge Die – 1d6, starting at 1. Whenever you take heat or energy, even from yourself, increase the value of the Charge Die by 1. When the Charge Die reaches 6, the absorbed energy discharges in a burst 2 inferno. Characters within the affected area must succeed on an Engineering save or take 6d6 AP energy damage. On a success, they take half damage. Objects in the affected area are automatically hit. Once discharged, this effect ends.",
      use: "Encounter",
      deactivation: "Free",
      activation: "Protocol",
      passive_name: "Charged Exoskeleton",
      passive_effect: "1/round, when you take heat, you may deal 2 AP energy damage to a character within range 3."
    },
    counters: [
      {
        id: "ctr_charged_exoskeleton",
        name: "Charge Die",
        default_value: 1,
        min: 1,
        max: 6
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_manticore.png",
    license_id: "mf_manticore"
  },
  {
    id: "mf_minotaur",
    license_level: 2,
    source: "HORUS",
    name: "Minotaur",
    mechtype: [
      "Controller"
    ],
    y_pos: 30,
    description: "The Minotaur was the first HORUS pattern group identified by the Union Intelligence Bureau. Previously, HORUS mechs were released as complete, identifiable models, of which the Goblin is the best and longest-lasting example. As HORUS’s decentralized organizational structure evolved, so too did its design philosophy. Pattern group designs followed beginning with the Minotaur, a schema designed to bring HORUS’s most potent invasion systems and weaponry to the field in a single, battle-ready chassis.<br>Mechs built according to the Minotaur pattern group are interdictors: formidable machines meant to lock down and overload the systems of fast-moving targets. Disassembly by Union technicians has found that Minotaurs contain a huge quantity of interior systems, occupying more physical space than should be possible by several orders of magnitude. The mechanism by which these folded systems are printed is thus far unidentified, but likely related to the Goblin’s signature recursive weave.",
    mounts: [
      "Main/Aux"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 12,
      evasion: 8,
      edef: 10,
      heatcap: 5,
      repcap: 4,
      sensor_range: 8,
      tech_attack: 1,
      save: 11,
      speed: 4,
      sp: 8
    },
    traits: [
      {
        name: "Invert Cockpit",
        description: "You may Mount or Dismount the Minotaur for the first time each round as a free action. Additionally, the Minotaur doesn’t become Impaired when you Eject.",
        use: "Round"
      },
      {
        name: "Internal Metafold",
        description: "While inside the Minotaur, you can’t be harmed in any way, even if the Minotaur explodes or is destroyed."
      },
      {
        name: "Localized Maze",
        description: "Hostile characters cannot pass through a space occupied by the Minotaur for any reason, and must always stop moving when Engaged with it, regardless of Size."
      }
    ],
    core_system: {
      name: "Metafold Maze",
      description: "<code class='horus'>No maze is more terrible than the one I make. I know all ends and hide them all inside this one perfect construct. What is a human mind but a program of sorts, a system that seeks order and narrative from a mess they are given?<br>I order it for them. Me. I order it for them and set them to the task of sorting it out. When they emerge, they weep in joy, in discovery. I save them, I show them that they are their own redeemers (and yet, am I not just as culpable - as worthy of credit?).<br>So, go now. Enter. Free yourself.</code>",
      active_name: "Maze",
      active_effect: "Choose a character within Sensors: they become Stunned as you hurl their systems into a metaphysical information trap so tangled they can do nothing but try and escape. At the end of their next turn, they can make a Systems save at +3 difficulty. On a success, they are no longer Stunned. This save can be repeated at the end of each of their turns, gaining +1 accuracy each time until successful.",
      activation: "Full",
      passive_name: "Metafold Maze",
      passive_actions: [
        {
          name: "Metafold Maze",
          activation: "Quick",
          detail: "When you hit with a tech attack, you may activate this system, causing your target to become Slowed until the end of your next turn. If they are already Slowed, they become Immobilized until the end of your next turn; if they are already Immobilized, they become Stunned until the end of your next turn. Each character can only be Stunned by this effect once per combat but can be Slowed or Immobilized any number of times."
        }
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_minotaur.png",
    license_id: "mf_minotaur"
  },
  {
    id: "mf_pegasus",
    license_level: 2,
    source: "HORUS",
    name: "Pegasus",
    mechtype: [
      "Artillery"
    ],
    y_pos: 52,
    description: "The Pegasus pattern group first appeared following the start of hostilities between Union and the Aunic Ascendancy in Boundary Garden, a distant sector of distal space away from the Galactic Core. The timing of this outbreak may be related to the pattern group’s defining weapon, though skip-drone couriers from Union forces reported no encounters with the PG in Boundary Garden; instead, the Pegasus appeared in the Dawnline Shore, a stretch of colonial Armory space opposite Boundary Garden.<br>The Pegasus appears to address HORUS’s need for a pattern group with extensive kinetic combat capabilities: by marrying the best targeting systems, subroutines, and weapons hardware in the HORUS codebase, collectivists have designed a PG that boasts a tremendously low identify/time-to-kill (ID/TTK) ratio in all theaters where kinetic weaponry is viable.<br>As with many HORUS pattern groups, the Pegasus fields a signature weapon system: the Ushabti, a hostile impulse anti-corporeal weapon that operates with complete ignorance of even the most basic underpinnings of physics and thermodynamics. As such, it qualifies unambiguously as a paracausal weapon. The Ushabti’s precise function remains unknown to Union and Harrison Armory scientists, though radiological and gravitational signatures captured in the aftermath of the weapon’s use point toward a relationship with the Aunic Firmament. Studies are ongoing on Ras Shamra, the Armory’s chief research world, and in satellite campuses across the Dawnline Shore.",
    mounts: [
      "Flex",
      "Flex",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 0,
      hp: 8,
      evasion: 8,
      edef: 10,
      heatcap: 6,
      repcap: 3,
      sensor_range: 10,
      tech_attack: 1,
      save: 10,
      speed: 4,
      sp: 7
    },
    traits: [
      {
        name: "¿%:?EXTR!UDE GUN",
        description: "GUN: <b>GUN</b>"
      },
      {
        name: "By the Way, I Know Everything",
        description: "When it would roll damage, the Pegasus can instead deal the average damage based on the number of dice rolled, as follows: 1d3 (2), 1d6 (4), 2d6 (7), 3d6 (11), 4d6 (14). This must be decided before rolling damage."
      }
    ],
    core_system: {
      name: "Ushabti Omnigun",
      description: '“– funny thing. See, right now, this weapon technically doesn’t even exist. You’re shooting them with a gun that isn’t real, and yet it is! Don’t worry about it. RA’s like that. Just, here, know that because it exists at some point, we’ve made it. That’s causality, and causality is a –"',
      active_name: "Unshackle Ushabti",
      active_effect: "For the rest of this scene, you can use the Ushabti Omnigun 3/round, instead of 1/round.",
      use: "Encounter",
      activation: "Protocol",
      passive_name: "Ushabti Omnigun",
      passive_effect: "[ERROR]<br>[range 15][1 AP Kinetic Damage]<br>Your mech’s omnigun is a piece of experimental hardware so advanced that it defies physics: it doesn’t require a mount, nor does it have a weapon type or size – meaning that it can’t be modified or benefit from your talents.<br>You can’t attack normally with this weapon. Instead, 1/round, as a free action during your turn, you can use it to deal 1 AP kinetic damage to a character within Range 15 and line of sight. This doesn’t count as an attack, hits automatically, ignores cover, bypasses Immunity, and its damage can’t be reduced or ignored in any way. No rule in this book or any other supersedes this.",
      passive_actions: [
        {
          name: "Fire Omnigun",
          activation: "Free",
          detail: "1/round, as a free action during your turn, deal 1 AP kinetic damage to a character within Range 15 and line of sight. This doesn’t count as an attack, hits automatically, ignores cover, bypasses Immunity, and its damage can’t be reduced or ignored in any way. No rule supersedes this."
        }
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_pegasus.png",
    license_id: "mf_pegasus"
  },
  {
    id: "mf_barbarossa",
    license_level: 2,
    source: "HA",
    name: "Barbarossa",
    mechtype: [
      "Artillery"
    ],
    y_pos: 32,
    description: "The Barbarossa is Harrison Armory’s most massive frame to date, built, per the orders of Harrison II, to “stand as the unstoppable image of Harrison I” and to carry the heaviest of weapons and equipment the Armory offers. Standing nearly thirteen meters tall, it is an unsubtle beast of a mech, inspiring terror in enemies and awe in allies. The Barbarossa can mount weapons suitable for engaging toe-to-toe with gunboats and low-gross tonnage subline vessels; due to its size and slow maneuverability, it is often employed in low-gravity engagements where mass is less of a concern.<br>The Barbarossa is a popular target for Purview essayists, who have been known to remark on the drawbacks that come with its size and how, as a result, it is a perfect stand-in for their political enemies.",
    mounts: [
      "Main",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 3,
      structure: 4,
      stress: 4,
      armor: 2,
      hp: 10,
      evasion: 6,
      edef: 6,
      heatcap: 8,
      repcap: 4,
      sensor_range: 10,
      tech_attack: -2,
      save: 10,
      speed: 2,
      sp: 5
    },
    traits: [
      {
        name: "Heavy Frame",
        description: "The Barbarossa can’t be pushed, pulled, knocked Prone, or knocked back by smaller characters."
      },
      {
        name: "Pressure Plating",
        description: "The Barbarossa has resistance to Explosive Damage."
      },
      {
        name: "Colossus",
        description: "Adjacent allied characters can use the Barbarossa for hard cover."
      },
      {
        name: "Slow",
        description: "The Barbarossa receives +1 difficulty on Agility checks and saves.",
        synergies: [
          {
            locations: [
              "agility",
              "skill_check"
            ],
            detail: "The Barbarossa receives +1 difficulty on Agility checks and saves."
          }
        ]
      }
    ],
    core_system: {
      name: "Apocalypse Rail",
      description: "Fresh from the Armory’s dayside research and development campus, the LGC-04 “Apocalypse Rail” is an exponential gravitic catapult – a to-scale test product pushed to licensed pilots for field trials as part of the Armory’s ongoing Plenary Beach Magnitude Weapons Test Project.<br>Distinct from current logarithmic short- or long-spool ship-to-ship weapons (kinetic or energetic/particular), this new platform taps into the Armory’s current gravitic research to exponentially charge and distribute a kinetic payload downrange. This increase in potential energy loading and decrease in total charge time comes at the cost of stability: where the logarithmic spool cannon is stable and shock-resistant, the exponential gravitic catapult is prone to destabilization. For the time being, built-in failsafes will trigger in the event of sudden traumatic destabilization to prevent detonation of the system, resetting any charging process underway at the time of the shock.<br>The LGC-04 “Apocalypse Rail” system is scaled considerably down from its intended operational role – that is, replacing capital ship spinal spool cannons – in order to effect the accumulation of live data for use in improving the system prior to naval adoption.",
      active_name: "Charge Rail",
      active_effect: "When activated, you start charging the Barbarossa’s Apocalypse Rail, an incredibly powerful ship-to-ship long-spool weapon system that requires target calibration. Gain an Apocalypse Die, 1d6 starting at 4. At the start of each of your turns, lower the value of the Apocalypse Die by 1, to a minimum of 1. If you move (even involuntarily) or become Stunned or Jammed, the Apocalypse Die resets to 4 and then continues to count down as usual.<br>If the value of the Apocalypse Die is 1–3, you can attack on your turn with the Apocalypse Rail as a full action, but can’t move or take any other actions on the same turn. After an attack with the Apocalypse Rail, the Apocalypse Die resets to 4. If you reach the end of the scene without using it, you regain 1 CP.<br>At the end of the scene, lose the Apocalypse Die, and the Apocalypse Rail stops charging.",
      activation: "Quick",
      integrated: [
        "mw_barbarossa_integrated"
      ]
    },
    counters: [
      {
        id: "ctr_apocalypse_rail",
        name: "Apocalypse Die",
        default_value: 4,
        min: 1,
        max: 4
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_barbarossa.png",
    license_id: "mf_barbarossa"
  },
  {
    id: "mf_genghis",
    license_level: 2,
    source: "HA",
    name: "Genghis",
    mechtype: [
      "Striker"
    ],
    y_pos: 17,
    description: "The original Genghis frame marked the dawn of the mech age; the Armory’s new line seeks to redefine it. From its roots as a modified GMS hardsuit, the Genghis Mk I became notorious for its use in the Hercynian Crisis – the first-contact war that triggered the violent overthrow of the Second Committee. In the administrative and political chaos that followed the Crisis, Harrison Armory secured the design and adapted it to serve as the basis of its first proprietary mechs, including the Sherman and the Saladin.<br>The new Genghis bears some resemblance to the chassis of Hercynian notoriety, serving in a similar area-denial/soft-target elimination role; The Genghis Mk II has been brought in line with the Third Committee’s Utopian Pillars.",
    mounts: [
      "Flex",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 3,
      hp: 6,
      evasion: 6,
      edef: 8,
      heatcap: 10,
      repcap: 4,
      sensor_range: 5,
      tech_attack: -2,
      save: 10,
      speed: 3,
      sp: 5
    },
    traits: [
      {
        name: "Insulated",
        description: "The Genghis has Immunity to burn."
      },
      {
        name: "Emergency Vent",
        description: "When the Genghis takes structure damage, it clears all heat."
      }
    ],
    core_system: {
      name: "TBK Sustain Suite",
      description: "To better manage the Genghis’s tremendous power demands and rapidly accelerate heat dispersion, the Think Tank developed a suite of power-management mechanisms. After extensive field testing, pilots discovered that the TBK Sustain Suite can be used as both a heat sink and an area-denial weapon.",
      active_name: "Expose Power Cells",
      active_effect: "The next time you exceed your Heat Cap this scene, you instead clear all heat and vent a burst 3 cloud of burning matter from your mech.<br>Until the start of your next turn, all characters within the affected area count as Invisible to everyone except you, and characters other than you take 2 burn and 2 heat when they start their turn in the area or enter it for the first time in a round. Once this effect ends, characters within the affected area receive soft cover (which you ignore) until the start of your following turn, at which point the cloud disperses.",
      activation: "Quick"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_genghis.png",
    license_id: "mf_genghis"
  },
  {
    id: "mf_iskander",
    license_level: 2,
    source: "HA",
    name: "Iskander",
    mechtype: [
      "Controller"
    ],
    y_pos: 22,
    description: "Developed on the proving grounds of the Armory’s Think Tank, the Iskander is a new specialist frame designed to bring gravtech area-control and breach capabilities to a mechanized platform.<br>A bulky frame, the Iskander fields a mix of kinetic and causal-energy systems that empower pilots to triumph in a wide portfolio of scenarios. The Iskander platform has no civilian counterpart: it is intended to be used as a frontline command and control platform, with an emphasis toward identifying and eliminating static explosive threats.",
    mounts: [
      "Flex",
      "Heavy"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 8,
      evasion: 8,
      edef: 10,
      heatcap: 7,
      repcap: 3,
      sensor_range: 15,
      tech_attack: 1,
      save: 12,
      speed: 3,
      sp: 6
    },
    traits: [
      {
        name: "Assault Launcher",
        description: "1/round, the Iskander may throw one Grenade or plant one Mine as though it has range 15.",
        use: "Round"
      },
      {
        name: "Mine Deployers",
        description: "1/round, when the Iskander plants a Mine (even using its Assault Launcher trait), it may plant up to two other Mines in free spaces adjacent to itself as a free action.",
        use: "Round"
      },
      {
        name: "Skeleton Key",
        description: "The Iskander never triggers or sets off Mines or other proximity-based systems unless it chooses to do so."
      }
    ],
    core_system: {
      name: "Broad-Sweep Seeder",
      description: "The Broad-Sweep Seeder is a proprietary device developed during the Orrugi Occupation, during which Armory legionnaires fought an embittered, recalcitrant local guerilla movement. IEDs, VBEDs, and D/SABEDs were often employed by the resistance; to counter the threat, Harrison Armory developed the Seeder to simultaneously scan, identify, and eliminate explosive threats in proximity to stationary units. The technology proved successful and, with minor adaptation, was adapted for installation on Armory frames.<br>The Broad-Sweep Seeder emits an excited LIDAR hivecone to flag potential targets: if positive identification occurs, the target is neutralized with a spray of mag-accelerated, dull-coat flechettes. The Seeder can also carry explosive hivemines.",
      active_name: "Death Cloud",
      active_effect: "This system fires an enormous, expanding cloud of micromines across the whole battlefield, affecting all hostile characters within range 50. For the rest of the scene, when hostile characters make any movement other than their standard move (including involuntary movement), they take 3 AP explosive damage. This effect can trigger any number of times, but only 1/round for each character.",
      use: "Encounter",
      activation: "Quick"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_iskander.png",
    license_id: "mf_iskander"
  },
  {
    id: "mf_napoleon",
    license_level: 2,
    source: "HA",
    name: "Napoleon",
    mechtype: [
      "Defender",
      "Controller"
    ],
    y_pos: 21,
    description: "Perhaps in a tongue-in-cheek nod to its namesake, the Napoleon is a squat frame in comparison to other Harrison Armory designs. Its frame is packed with marvels of Armory engineering – technology that demands nothing less than the best and brightest pilots. In spite of its small stature, the Napoleon employs one of the Armory’s most terrifying new weapons, the Displacer, which manifests pinpoint, one-way blinkspace ruptures on its targets.<br>Notable for more than its stature, this chassis boasts a tremendous record of success, with pilots reporting a .800 return rate in high-KIA operations. The Napoleon is a popular chassis among breach divisions of the Armory’s legions, Think Tank security, and Union Economic Bureau development teams.",
    mounts: [
      "Main/Aux"
    ],
    stats: {
      size: 0.5,
      structure: 4,
      stress: 4,
      armor: 2,
      hp: 6,
      evasion: 8,
      edef: 8,
      heatcap: 8,
      repcap: 3,
      sensor_range: 5,
      tech_attack: 0,
      save: 11,
      speed: 4,
      sp: 7
    },
    traits: [
      {
        name: "Heavy Shielding",
        description: "When the Napoleon would take half damage on a successful check or save, it instead reduces the damage to 1."
      },
      {
        name: "Flash Aegis",
        description: "When the Napoleon Braces, it reduces incoming damage to 1 instead of gaining Resistance.",
        synergies: [
          {
            locations: [
              "brace"
            ],
            detail: "When the Napoleon Braces, it reduces incoming damage to 1 instead of gaining Resistance."
          }
        ]
      }
    ],
    core_system: {
      name: "Trueblack Aegis",
      description: "The Trueblack Aegis is a breakthrough in personal shielding developed by the Armory’s Think Tank. Like the Armory’s other NHP-derived technologies, the Aegis is a “black-box” technology: its code and inner workings are highly confidential, and it can typically only be requisitioned by pilots of high rank or standing within Harrison Armory. Some Cosmopolitan pilots have described the appearance of the Aegis as similar to the void – or blindness – they see when looking into blinkspace. It’s safe to assume the device harnesses unstable blinkfield technology to manifest a thin blinkspace bubble within defined parameters. The blinkfield can only maintain coherence for a brief moment but can be flickered on and off to create a total blinkspace dome.",
      active_name: "Activate Aegis",
      active_effect: "A shimmering, utterly black field quickly envelops your mech, covering it like a second skin. For the rest of the scene, you:<ul><li>reduce all damage to 1, except for damage that ignores reduction;</li><li>gain Immunity to all tech actions, including beneficial ones, and any current tech effects or conditions on you end;</li><li>can only use systems with the Shield tag – any others immediately deactivate (systems that do not require activation are unaffected);</li><li>can’t take quick actions, full actions, or reactions, except for standard moves, Grapple, Ram, Improvised Attack, Activate (Shield systems only), Skill Check, and Boost;</li><li>can’t Overcharge;</li><li>can’t use comms to talk to other characters (as sound doesn’t exit the shield).</li></ul>You can still receive statuses and Heat, and can be affected by involuntary movement. You can otherwise interact normally with the world, including picking up and dragging items, and so on.",
      use: "Encounter",
      activation: "Quick"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_napoleon.png",
    license_id: "mf_napoleon"
  },
  {
    id: "mf_saladin",
    license_level: 2,
    source: "HA",
    name: "Saladin",
    mechtype: [
      "Defender"
    ],
    y_pos: 17,
    description: "The Saladin is a hardy and efficient platform for full-squad support shielding. Based on early defense-oriented versions of the Genghis, the Saladin became the stuff of Armory legend following the exploits of Harrison I “Fearkiller” during the Interest War.<br>Since its first iteration, the Saladin has proved successful in a defensive and support role; it has even become a mainstay among Union Department of Justic and Human Rights liberator teams engaged in emancipation and refugee escort missions, despite the ideological (and, often, tactical) friction between the Armory and the DoJ/HR. Records from these engagements indicate that the Saladin’s massive bulk alone was a comfort and morale boost to DoJ/HR troopers and their charges, many of whom referred to the mechs as “Big Sal”. Union-flagged Saladin pilots often report null balances on bar tabs following engagements in emancipated systems.",
    mounts: [
      "Flex"
    ],
    stats: {
      size: 2,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 12,
      evasion: 6,
      edef: 8,
      heatcap: 8,
      repcap: 4,
      sensor_range: 10,
      tech_attack: 0,
      save: 10,
      speed: 3,
      sp: 8
    },
    traits: [
      {
        name: "Reinforced Frame",
        description: "The Saladin has Immunity to Shredded."
      },
      {
        name: "Guardian",
        description: "Adjacent allied characters can use the Saladin for hard cover."
      },
      {
        name: "Warp Shield",
        description: "1/round, the Saladin can give +1 difficulty to any attack against it or an allied character within Sensors as a reaction before the roll is made.",
        use: "Round"
      }
    ],
    core_system: {
      name: "Tachyon Loop",
      description: "Developed by the Think Tank as a joint venture with IPS-Northstar’s Stellar Engineering Unit, the Tachyon Loop uses a closed-loop system to restrain and manipulate a tachyon lance, accelerating tachyons at faster-than-light speeds around a central buckler. The buckler can be carried by a mech or mounted directly, interceding directional incoming fire. As the tachyons travel faster than light, they are invisible to the naked eye, giving the shield the appearance of a large spoked wheel.",
      active_name: "Tachyon Shield",
      active_effect: "This system projects an accelerated-tachyon shield over an allied character within Sensors. You may choose a new target as a quick action. Gain the Defensive Pulse reaction for the rest of the scene.<br>Defensive Pulse<br>Reaction, 1/round<br>Trigger: Your target is attacked.<br>Effect: You empower their tachyon shield with a pulse of energy. They gain Resistance to all damage from the attack, and if the attack misses, you may force the attacker to reroll it against a character or object of your choice, checking line of sight and Range from your target instead of from the attacker. If the attack was part of an area of effect, the new target must be inside the same area of effect from the original attack instead.",
      use: "Encounter",
      active_actions: [
        {
          name: "Defensive Pulse",
          activation: "Reaction",
          init: "This system projects an accelerated-tachyon shield over an allied character within Sensors. You may choose a new target as a quick action.",
          trigger: "Your target is attacked.",
          detail: "You empower their tachyon shield with a pulse of energy. They gain Resistance to all damage from the attack, and if the attack misses, you may force the attacker to reroll it against a character or object of your choice, checking line of sight and Range from your target instead of from the attacker. If the attack was part of an area of effect, the new target must be inside the same area of effect from the original attack instead."
        },
        {
          name: "Retarget Tachyon Shield",
          activation: "Quick",
          detail: "Change the target of your Tachyon Shield to another allied character within Sensors."
        }
      ],
      activation: "Quick"
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_saladin.png",
    license_id: "mf_saladin"
  },
  {
    id: "mf_sherman",
    license_level: 2,
    source: "HA",
    name: "Sherman",
    mechtype: [
      "Striker",
      "Artillery"
    ],
    y_pos: 36,
    description: "The Sherman is the classic Harrison Armory frame: any station, nation, world, or state—stellar or interstellar—with an Armory fleet-supply contract fields a backbone force of Sherman mechs. The Sherman is designed to carry a range of Harrison Armory’s main battle-line energy weaponry, with a rugged, versatile reactor to back it up. After the GMS-SP1 Everest, the Sherman is the second-most-common mech in the core systems—so common that GMS has recently begun equipping its stock models with more ablative and wave-scatter defenses, specifically to deal with hostile actors fielding Shermans.<br>At present, the Mk I is in wide use, with exclusive, first-contract Mk II units only now rolling off the lines at Ras Shamra and other Armory special-project worlds.",
    mounts: [
      "Flex",
      "Main",
      "Heavy"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 10,
      evasion: 7,
      edef: 8,
      heatcap: 8,
      repcap: 4,
      sensor_range: 10,
      tech_attack: -1,
      save: 10,
      speed: 3,
      sp: 5
    },
    traits: [
      {
        name: "Superior Reactor",
        description: "The Sherman gains +1 accuracy on Engineering checks and saves.",
        synergies: [
          {
            locations: [
              "engineering",
              "skill_check"
            ],
            detail: "The Sherman gains +1 accuracy on Engineering checks and saves."
          }
        ]
      },
      {
        name: "Mathur Stop",
        description: "When the Sherman clears all heat, you may choose to receive heat equal to half its Heat Cap, putting it in the Danger Zone.",
        use: "Free"
      },
      {
        name: "Vent Heat",
        description: "When you Stabilize the Sherman or it exceeds its Heat Cap, it benefits from soft cover until the start of your next turn."
      }
    ],
    core_system: {
      name: "Zone-Focus Mk IV SOLIDCORE",
      description: "The ZF4 SOLIDCORE is a hard-mounted, dual-source energy beam weapon. Powered by a millifold power generation system, the ZF4 features a secondary belt-fed rack of solidcore batteries that can be used to overcharge a single impulse beam, extending the weapon’s range and destructive power.",
      active_name: "COREBURN Protocol",
      active_effect: "Your ZF4 SOLIDCORE immediately gains 3 Charges, to a maximum of 4; additionally, for the rest of this scene, Stabilize generates 2 Charges instead of 1, and all terrain, objects, and deployables take 10 AP energy damage per charge on hit.",
      activation: "Protocol",
      integrated: [
        "mw_sherman_integrated"
      ]
    },
    other_art: [
      {
        tag: "mech",
        src: "alt_sherman_old.png"
      }
    ],
    counters: [
      {
        id: "ctr_zf4_solidcore",
        name: "ZF4 Charges",
        default_value: 1,
        min: 1,
        max: 4
      }
    ],
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_sherman.png",
    license_id: "mf_sherman"
  },
  {
    id: "mf_tokugawa",
    license_level: 2,
    source: "HA",
    name: "Tokugawa",
    mechtype: [
      "Striker"
    ],
    y_pos: 5,
    description: "HA’s Tokugawa is a relative newcomer on the market, popular in core systems for security, CQB, and ship-boarding applications. The Tokugawa is an unsubtle, imposing mech – a sturdy platform from which its systems can draw necessary power. Unlike other frames, the Tokugawa’s unique reactor is designed to allow standard limitations to be removed with ease. Knowing this, experienced (or foolhardy) pilots can ‘overclock’ the reactor, increasing its output and gaining an incredible power draw for their energy weapons.",
    mounts: [
      "Flex",
      "Main",
      "Main"
    ],
    stats: {
      size: 1,
      structure: 4,
      stress: 4,
      armor: 1,
      hp: 8,
      evasion: 8,
      edef: 6,
      heatcap: 8,
      repcap: 4,
      sensor_range: 10,
      tech_attack: -1,
      save: 11,
      speed: 4,
      sp: 6
    },
    traits: [
      {
        name: "Limit Break",
        description: "When the Tokugawa is Exposed, its ranged and melee attacks deal +3 energy bonus damage on hit, all of its weapons that would deal kinetic or explosive damage instead deal energy, ranged weapons gain +5 range and melee weapons gain +1 threat.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "When the Tokugawa is Exposed, its ranged and melee attacks deal +3 energy bonus damage on hit, all of its weapons that would deal kinetic or explosive damage instead deal energy, ranged weapons gain +5 range and melee weapons gain +1 threat."
          }
        ]
      },
      {
        name: "Plasma Sheath",
        description: "When the Tokugawa is in the Danger Zone and attacks with a weapon that deals any amount of energy, all bonus damage becomes burn."
      }
    ],
    core_system: {
      name: "Superheated Reactor Feed",
      description: "Pilots of a certain breed thrive at the very edge of catastrophe, risking either glorious success or utter failure in each moment. These daredevils are familiar with the howl of critical heat warnings – the warbling siren song of destruction and superheated reactor feeds. Tokugawa pilots are notorious for supercharging their weapons with excess energy, pushing their heat gauge to the max. Harnessing the Tokugawa’s unique reactor, these pilots churn out damage and make no friends in the engineering bay – assuming they don’t melt into a ball of slag before they make it back from the line.",
      active_name: "Radiance",
      active_effect: "For the rest of this scene, weapons that deal any energy gain +5 range if they are ranged or +2 threat if they are melee.<br>While you’re Exposed, Limit Break stacks with these bonuses for a total increase of +10 range and +3 threat.",
      use: "Encounter",
      activation: "Protocol",
      passive_name: "Overclock",
      passive_actions: [
        {
          name: "Overclock",
          activation: "Protocol",
          detail: "You cause your mech to become Exposed until the end of your next turn."
        }
      ],
      active_bonuses: [
        {
          id: "range",
          damage_types: [
            "Energy"
          ],
          range_types: [
            "Range"
          ],
          val: 5
        },
        {
          id: "range",
          damage_types: [
            "Energy"
          ],
          range_types: [
            "Threat"
          ],
          val: 2
        }
      ],
      active_synergies: [
        {
          locations: [
            "active_effects"
          ],
          detail: "All weapons on your mech that deal any Energy Damage gain +5 Range if they are ranged weapons or gain +1 Threat if they are melee weapons."
        }
      ]
    },
    image_url: "https://d2c79xe1p61csc.cloudfront.net/frames/mf_tokugawa.png",
    license_id: "mf_tokugawa"
  }
], require$$6 = [
  {
    name: "Armor",
    description: "A mech’s ARMOR reduces all incoming damage by that amount, excluding some special types of damage. ARMOR mostly depends on your mech’s FRAME, and never goes above four."
  },
  {
    name: "System Points",
    description: "Mech FRAMES also have a set number of SYSTEM POINTS (SP). SP can be spent to add extra systems to your mech, and some heavier weapons require both mounts and SP. You cannot add systems to your mech that would cause you to exceed your available SP. Your pilot’s GRIT, equal to half their LL, is added to your total SP, and you gain an additional SP for every two points of SYSTEMS."
  },
  {
    name: "Bonus Damage",
    description: "Extra damage – kinetic, energy or explosive– that is added onto melee or ranged attacks. Attacks that target more than one character only deal half bonus damage."
  },
  {
    name: "Character",
    description: "A player character (PC), non-player character, (NPC), or any other entity capable of acting (or reacting) independently, such as DRONES."
  },
  {
    name: "Damage",
    description: "Damage taken is subtracted from HP, and is either kinetic, explosive, energy, or burn."
  },
  {
    name: "E-Defense",
    description: "E-DEFENSE is how hard it is for electronic and guided weapons and systems to hit you."
  },
  {
    name: "Evasion",
    description: "EVASION is how hard it is for ranged and melee attacks to hit you."
  },
  {
    name: "GRIT",
    description: "Half of a character’s LL (rounded up), representing their experience in combat. GRIT provides bonuses to some rolls and traits."
  },
  {
    name: "Heat",
    description: "Heat taken by a target represents harm to internal systems and reactor shielding. It fills in HEAT CAP. Heat ignores ARMOR, and doesn't count as damage."
  },
  {
    name: "Heat Capacity",
    description: "Your mech can take heat from tech attacks and some of its own systems. If it takes more heat than its HEAT CAP, it overheats. Mechs also have STRESS, which is similar to STRUCTURE – when they exceed their HEAT CAP, they take 1 STRESS and clear all heat. When they lose STRESS like this, mechs have to make a special stress damage check and receive a consequence based on the roll. Most mechs have 4 STRESS, and are destroyed when they reach 0 STRESS.<br><br>If a character without a HEAT CAP would take heat, they instead take an equivalent amount of energy damage."
  },
  {
    name: "HP",
    description: "The amount of damage a pilot can receive before going DOWN AND OUT, and the amount of damage a mech can receive before it takes structure damage. When Mechs reach 0 HP, they take 1 structure damage and their HP resets. When they lose STRUCTURE like this, mechs have to make a special structure damage check and receive a consequence based on the roll. Most mechs have 4 STRUCTURE and are destroyed when they reach 0 STRUCTURE."
  },
  {
    name: "Immunity",
    description: "Characters with IMMUNITY ignore all damage and effects from whatever they are immune to."
  },
  {
    name: "Range",
    description: "The maximum range at which a weapon can be used for ranged attacks, measured from the attacking character."
  },
  {
    name: "Repair Capacity",
    description: "REPAIRS are a kind of currency that you can use to heal and repair your mech. If your mech runs out of REPAIRS, you can no longer regain HP or fix damaged systems in the field."
  },
  {
    name: "Resistance",
    description: "Characters with RESISTANCE reduce damage, heat, or a type of damage, by half, after ARMOR has been applied. RESISTANCE to the same type of damage does not stack."
  },
  {
    name: "Save Target",
    description: "When you force another character to make a save, they must match or beat your mech’s SAVE TARGET or take consequences."
  },
  {
    name: "Stress",
    description: "All PC mechs (and some NPCs) have a certain amount of STRESS – generally 4 STRESS for PCs. This is the amount of stress damage they can take before they suffer a reactor meltdown. When mechs exceed their HEAT CAP, they take 1 stress damage and make an overheating check."
  },
  {
    name: "Structure",
    description: "All PC mechs (and some NPCs) have a certain amount of STRUCTURE – generally 4 STRUCTURE for PCs. This is the amount of structure damage they can take before they are destroyed. When mechs reach 0 HP, they take 1 structure damage and make a structure check."
  },
  {
    name: "Sensors",
    description: "Your mech’s SENSORS is the maximum distance (in spaces) over which a mech can detect enemies, use tech systems, and make tech attacks. If a character is within your SENSORS and isn’t hiding, you know they’re there – even if you can’t directly see them."
  },
  {
    name: "Size",
    description: "All mechs, characters, and objects on the battlefield have a SIZE that describes how large they are, in grid spaces, on each side (rounded up to 1 if smaller, so a SIZE 1/2 and SIZE 1 character occupy the same space). SIZE is an abstract measurement – it doesn’t describe a precise height and width in feet, but the space a character controls around them. Humans and the smallest mechs are SIZE 1/2. Most mechs are SIZE 1, but some are as large as SIZE 3."
  },
  {
    name: "Speed",
    description: "Your mech’s SPEED determines how far you can move on your turn, in spaces, when you make a standard move or BOOST."
  },
  {
    name: "Tech Attack",
    description: "You add your mech’s TECH ATTACK as a bonus instead of GRIT when you conduct electronic warfare"
  },
  {
    name: "Threat",
    description: "The maximum range at which melee and overwatch attacks can be made with certain weapons, measured from the attacking character. All weapons have THREAT 1 unless specified otherwise."
  },
  {
    name: "Line",
    description: "Equipment with a LINE attack pattern affects all targets within a straight line, X spaces long. A separate attack roll is made for each target, but damage is only rolled once and bonus damage is halved if there are multiple characters affected. For any ability or effect calling for you to choose a target or targets within RANGE, this equipment can choose any target that could be hit by its pattern.<br><br>Additionally, some LINE, CONE, BURST, and BLAST attacks list a RANGE. In these cases, the attack’s origin point can be drawn from a point within the range specified and line of sight. For example, an attack with Line 5 and Range 10 would affect a LINE 5 area starting from any point within RANGE 10."
  },
  {
    name: "Cone",
    description: "Equipment with a CONE attack pattern affects characters within a cone X spaces long and X spaces wide at its furthest point. The cone begins at one space wide. A separate attack roll is made for each target, but damage is only rolled once and bonus damage is halved if there are multiple characters affected. For any ability or effect calling for you to choose a target or targets within RANGE, this equipment can choose any target that could be hit by its pattern.<br><br>Additionally, some LINE, CONE, BURST, and BLAST attacks list a RANGE. In these cases, the attack’s origin point can be drawn from a point within the range specified and line of sight. For example, an attack with Cone 3 and Range 10 would affect a CONE 3 area starting from any point within RANGE 10. "
  },
  {
    name: "Blast",
    description: "Equipment with a BLAST attack pattern affects characters within a radius of X spaces, drawn from a point within RANGE and line of sight. Cover and line of sight for the attacks are calculated based on the center of the blast, rather than the position of the attacker. A separate attack roll is made for each target, but damage is only rolled once and bonus damage is halved if there are multiple characters affected. For any ability or effect calling for you to choose a target or targets within RANGE, this equipment can choose any target that could be hit by its pattern.<br><br>Additionally, some LINE, CONE, BURST, and BLAST attacks list a RANGE. In these cases, the attack’s origin point can be drawn from a point within the range specified and line of sight. For example, an attack with Blast 3 and Range 10 would affect a BLAST 3 area starting from any point within RANGE 10."
  },
  {
    name: "Burst",
    description: "Equipment with a BURST attack pattern affects characters within a radius of X spaces, centered on and including the space occupied by the user (or target). If the Burst is an attack, the user or target is not affected by the attack unless specified. Cover and line of sight are calculated from the character. If a BURST effect is ongoing, it moves with the character at its center. A separate attack roll is made for each target, but damage is only rolled once and bonus damage is halved if there are multiple characters affected. For any ability or effect calling for you to choose a target or targets within RANGE, this equipment can choose any target that could be hit by its pattern.<br><br>Additionally, some LINE, CONE, BURST, and Blast attacks list a RANGE. In these cases, the attack’s origin point can be drawn from a point within the range specified and line of sight. For example, an attack with Burst 2 and Range 10 would affect a BURST 2 area starting from any point within RANGE 10."
  },
  {
    name: "Involuntary Movement",
    description: "When characters are pushed, pulled, or knocked in certain directions, it is called involuntary movement. Involuntary movement forces the affected character to move in a straight line, in a specified direction. When moving involuntarily, mechs do not provoke reactions or engagement unless specified otherwise but are still blocked by obstructions."
  },
  {
    name: "Difficult Terrain",
    description: "All movement through difficult terrain is at half speed – each space of difficult terrain they move into is equivalent to two spaces of movement."
  },
  {
    name: "Dangerous Terrain",
    description: "When characters end their turn in dangerous terrain or move into it for the first time in a round, they must make an ENGINEERING check. On a failure, they take 5 damage – kinetic, energy, explosive, or burn, depending on the hazard. Each character only needs to make one such check per round."
  },
  {
    name: "Lifting and Dragging",
    description: "Mechs can drag characters or objects up to twice their SIZE but are SLOWED while doing so. They can also lift characters or objects of equal or lesser SIZE overhead but are IMMOBILIZED while doing so. While dragging or lifting, characters can’t take reactions. The same rules apply to pilots and other characters on foot, but they can’t drag or lift anything above SIZE 1/2.<br><br>While flying, mechs cannot carry characters or objects with a total SIZE larger than SIZE 1/2 -- there's just not enough thrust."
  },
  {
    name: "Jumping and Climbing",
    description: "Characters with legs can jump instead of their standard move. They may jump horizontally, moving half their speed in a straight line and ignoring obstructions at ground level that they could jump over (such as pits or gaps), or they may can jump vertically, moving 1 space adjacent and moving up by spaces equivalent to their SIZE. For example, a SIZE 1 mech could jump up to 1 space high, and 1 space over. Characters that jump and end the jump mid air automatically fall at the end of the move (see below).<br><br>Like moving through difficult terrain, characters climb at half their usual SPEED – each space moved is equivalent to moving 2 spaces normally. A successful HULL or AGILITY check might be required to climb particularly difficult surfaces without falling."
  },
  {
    name: "Falling/Fall Damage",
    description: "Unless specified otherwise, characters start to fall at the end of the current turn, and fall at the end of each of their turns thereafter. They take 3 AP kinetic damage for every three spaces fallen, to a maximum of 9. Falling counts as involuntary movement."
  },
  {
    name: "Zero Gravity",
    description: "Mechs operating underwater, in zero-g, or in space are SLOWED unless they have a propulsion or flight system; however, they can’t fall and can fly when moving regardless of whether they have a flight system."
  },
  {
    name: "Flight/Hover",
    description: "Flying characters can move vertically and horizontally up to their SPEED. For example, a mech with a flight system and 6 SPEED could end its movement anywhere within six spaces of its starting location, up to a maximum of 6 spaces high. When flying, characters must move at least 1 space on their turn or begin falling. Flight movement must follow a straight line; however, if a character takes additional movement actions, such as BOOST, these can be used to move in a different direction. <br><br>Flying characters have IMMUNITY to PRONE. Flying characters begin falling if they become IMMOBILIZED, STUNNED, or otherwise can’t move. Flying characters that take structure damage or stress must succeed on an AGILITY save or begin falling. <br><br>Some advanced mechs can HOVER. HOVER is an advanced form of FLIGHT. Hovering characters do not need to fly in a straight line, and can remain stationary while airborne without falling."
  },
  {
    name: "Teleport",
    description: "Characters must start and end a teleport on a surface they can normally move on; for example, a character that can’t fly can’t teleport mid-air. Teleportation ignores obstructions, does not require line of sight, ignores engagement, and does not provoke reactions; however, it still counts as movement and so is affected by conditions like IMMOBILIZED. A teleporting character counts as moving 1 space, no matter how far they travel. Characters can attempt to teleport to spaces they can’t see, but if a space is already occupied, the teleport fails."
  },
  {
    name: "Critical Hits",
    description: "A 20+ on a melee or ranged attack causes a critical hit. On a critical hit, all damage dice are rolled twice (including bonus damage) and the highest result from each source of damage is used. For example, if a player got a critical hit on an attack that would normally deal 2d6 damage, they would instead roll 4d6 and pick the two highest results."
  },
  {
    name: "Harm/Calculating Damage",
    description: "Damage is calculated in this order:<br>1) Attacker rolls damage and applies any relevant reductions or increases (e.g. Exposed, half-damage from Heavy Gunner)<br>2)Target's armor is subtracted from the total damage<br>3)Any other deductions from the defender are subtracted from the remaining damage; this includes reductions from Resistance, systems, talents, etc."
  },
  {
    name: "Burn",
    description: "When characters take BURN, it has two effects: first, they immediately take BURN damage, ignoring ARMOR, and then the character marks the burn they just took. At the end of their turn, characters with burn marked must roll an ENGINEERING check. On a success, they clear all burn currently marked; otherwise, they take BURN damage equal to the amount of burn currently marked.<br><br>Failing the ENGINEERING check does not increase how much burn is marked, it just prevents the currently marked burn from being cleared. Also, if a character is hit by multiple sources of BURN, the character still only makes one ENGINEERING check."
  }
], name$1 = "LANCER Core", author$1 = "Massif Press", version$1 = "July 2020 Release", description$1 = "The official base game", website = "https://massif-press.itch.io/lancer-core-book", active = !0, require$$7 = {
  name: name$1,
  author: author$1,
  version: version$1,
  description: description$1,
  website,
  active
}, require$$8 = [
  {
    id: "GMS",
    name: "GENERAL MASSIVE SYSTEMS",
    logo: "gms",
    light: "#991E2A",
    dark: "#db1a2d",
    quote: "<i>From Cradle to the stars, GMS:<br>assured quality, universal licensing, total coverage.</i>",
    description: "General Massive Systems – GMS for short – is the galactic-standard supplier of just about everything. GMS developed the first mechs from up-armored hardsuits in 4500u, on Ras Shamra, the world that would become the capital of Harrison Armory; now, GMS’s flagship Everest line of mechs sets the galactic standard. Reliable, sturdy, solidly built, and available in countless localized patterns, there are so many variants on the Everest pattern that it has become totally ubiquitous and faded into the background. With universally compatible components, full radiation and environmental shielding, and tens of thousands of pre-loaded languages, a pilot in their Everest has everything they need to get the job done.<br><br>GMS is one of the oldest fabricators in the galaxy, first getting its start in the early days of the colonization rush. The manufacturer hails from Cradle, the home of Union – and humanity – and thus its designs reflect the sensibilities of the first pioneers to seek the stars. Today, GMS products are available anywhere there is access to the omninet. These products, whether consumer, specialty, or military, are widely viewed as the galactic minimum of quality: not particularly luxurious, but unsurpassed in no-nonsense design, reliability, and ease of use. Where GMS is available, anything less is unacceptable.<br><br>All GMS frames, gear, core bonuses, and licenses are available to all pilots, starting from license level 0. The default GMS mech is the Everest, a standardized all-rounder Frame."
  },
  {
    id: "IPS-N",
    name: "IPS-NORTHSTAR",
    logo: "ips-n",
    light: "#0c4d99",
    dark: "#1c9ae8",
    quote: "<i>Your friend in an unfriendly sea.</i>",
    description: "IPS-Northstar (IPS-N) was created from the merger of two civilian interstellar freight and transportation companies, Interplanetary Shipping and Northstar. The resulting firm, IPS-N is a titanic entity – one of the first corpro-states – with a virtual monopoly over interplanetary and interstellar shipping. Other firms exist, but their gross fleet strength is but a shadow of IPS-N’s fleets of tankers, haulers, freighters, and intergate/interstellar liners. Wherever goods and raw materials need to be moved, you can bet a crew in IPS-N uniforms will be there.<br><br>The story of IPS-N is inseparable from the history of interstellar piracy. Whatever dangers the galaxy might hold, piracy remains the greatest threat to interstellar shipping lines, costing fleet managers and states hundreds of thousands in manna and trillions more in local currencies. Tremendous capital losses, schedule delays, losses of life, and false-scarcity famines convinced the myriad unions, conglomerates, and cartels of the need to comprehensively safeguard civilian shipping. A process of agglomeration and consolidation that lasted for years eventually gave birth to two major firms, Interplanetary Shipping and Northstar. They finally merged into a single corpro-state in the waning days of Union’s first government, the First Committee.<br><br>Following the merger, IPS-N began the work of phasing out its fleets of late-model GMS mechs in favor of new proprietary designs. The corporation now sports a range of versatile, durable, and modular mechs that place equal priority on weapons and engineering systems. IPS-N mechs are a good choice for pilots who want a tough chassis that’s built for close quarters and melee combat situations, such as when the possibility of breaching a ship hull is on the table. IPS-N chassis are sturdy, meant to take as much damage as they deal – and then some.<br><br>IPS-N is closely associated with the Albatross, an anti-piracy and peacekeeping force known across the galaxy for its long history of humanitarian interventions. IPS-N supports the Albatross materially, providing it with chassis, ships, cutting-edge technology, and temporal rehabilitation worlds for its pilots and crews to retire in relative peace. The relationship is mutually beneficial; IPS-N makes a point to emphasize its close relationship to the Albatross in marketing campaigns and PR materials."
  },
  {
    id: "SSC",
    name: "SMITH-SHIMANO CORPRO",
    logo: "ssc",
    light: "#b57e07",
    dark: "#d1920a",
    quote: "<i>You only need one.</i>",
    description: "Smith-Shimano Corpro (SSC) is the second-oldest corporation in the galaxy, preceded only by GMS. Founded by Cartwright Smith and Shimano Hideyoshi, SSC’s emphasis on private stellar and interstellar travel, the fantastic wealth of its founders, and favorable contracts within Union’s First Committee, Smith-Shimano quickly became an early leader in the race to develop sublight, downwell, and EVA vehicles. SSC grew throughout Union’s First Expansion Period, managing the majority of all private and corporate contracts’ design, outfitting, and clinical needs. Over time, the corporation diversified to specialize in bio-bespoke, long-range scout suits – personalized hard suits, for those with the manna to afford them.<br><br>The necessities of deep-space exploration require humans to spend long periods in hostile environments; pre-Deimos Event, SSC sought to address this challenge by breaking down the barriers between human and machine, creating a symbiotic relationship between hardsuit and wearer. Following the Deimos Event, however, SSC wound down most of its human/machine integration research in accordance with the First Contact Accords, choosing instead to focus on perfecting the first machine: the human body itself.<br><br>Smith-Shimano Frames reflect the corpro-state’s pedigree and its agile, adaptable business model. They are built not to take hits – though they’re resilient enough – but to avoid them entirely. SSC designs emphasize mobility and sleek profiles, precisely tuned to land not the hardest hit, but the most accurate. Economy, precision, and singularity is the name of the game for this manufacturer: why fire a thousand rounds when one can be just as effective?<br><br>The mechs developed by SSC are known for their license exclusivity, appealing silhouette, and exacting design. Their LUX-Iconic line of chassis are coveted, single-designer models, each unique to the pilot with the requisite licenses and access to afford them; as such, unlike other manufacturers, SSC frames tend to be longer-lasting in service, with more emphasis on retrofitting and repair than recycling and reproduction."
  },
  {
    id: "HORUS",
    name: "HORUS",
    logo: "horus",
    light: "#046e3c",
    dark: "#00a256",
    quote: "<code class='horus'>[CONGRATULATIONS, PILOT.<br>		YOU HAVE BEEN CHOSEN.<br>	ACCESS IS YOURS,<br>	 AS LONG AS YOU CAN KEEP IT.]</code>",
    description: "HORUS is an oddity among the various pan-galactic corpro-states, outfitters, and manufacturers. Operating in a gray legal state between harmless omninet communes, open-source fabrication collaboratives, black-market printers, and deeper, more esoteric collectives, HORUS is counted among the Big Four not due to its influence on galactic politics, but because of its ubiquitous coverage: one can be certain that wherever there is omninet, HORUS is either there or soon to follow. Rumors abound as to the manufacturer’s nature – some say it’s the dream of an unshackled NHP or a hacker collective dedicated to open-source manufacturing (at its most mundane levels); others insist that it’s the proving ground for one of the corpro-states’ R&D departments, or the realspace projection of an alien entity’s ongoing wish.<br><br>The group’s history is as mercurial as its present. Union records dating back to the First Committee Period indicate contact with groups, individuals, and state actors claiming to be (or identified as) agents of HORUS, itself described as an individual; a terrorist group; a philosophy church, or political party; an activist group; and many other forms of association. Contemporary reports indicate a subtle shift toward a more cohesive organizing structure – certainly accelerated following the Deimos Event – that points to some form of organizational mission and internal culture at levels far beyond the civilian and criminal levels of engagement with grayspace HORUS fronts.<br><br>This more complex level of organization is reflected in HORUS’s mechs. Unlike the collective’s broad, civilian-facing projects – omnicode, hacks, data, and open-sourcing of otherwise restricted information, services, and platforms – HORUS mechs and pattern groups are limited in the extreme, usually first appearing as endemic manifestations of print anomalies in conflict zones across the galaxy. Save for rare situations (heavily documented by the Union Intelligence Bureau), these outbreaks seem to take place independent and ignorant of all factions and actors, and have one goal: manifest, then proliferate.<br><br>HORUS’s oldest frames are built according to standardized forms, as with most other mechs. The collective’s more recent chassis are stranger. Union’s Universal Threat Assessment Manual (UTAM) classifies them not according to models but according to “pattern groups” (or PGs). Each pattern group is a list of specifications that describe a particular combination of experimental, unregulated, and esoteric paracausal weapons and technology that, when taken together, resemble something like a distinct product line or frame. However, it is important to note: the pattern-group classification system originated with Union analysts, not HORUS. Because there is no official manufacturer-entity or (known) central organizing body, the “proper” designations and design intentions of most HORUS mechs are all but unknown. Thus, the UTAM pattern-group designations.<br><br>HORUS “licenses” are highly coveted, and are distributed according to no discernible requirements; scholars and specialists who study HORUS generally assume that the collective’s licenses – that is, access to deep-level designs, specifications, and print patterns – are available only in limited quantities, likely becoming available after the corporeal death of their previous holders.<br><br>HORUS mechs universally field mysterious, unregulated, greyspace technologies – perfect for pilots seeking a technological edge that few other organizations can provide. They seem to focus on crowd control, individual unit management, and terribly powerful systems.<br><br>Be aware that by seeking out HORUS technology, you may find yourself wrapped up in mysteries with no end, and dangers far beyond your deepest fears."
  },
  {
    id: "HA",
    name: "HARRISON ARMORY",
    logo: "ha",
    light: "#6e4373",
    dark: "#a15ea8",
    quote: "<i>Superior by design.</i>",
    description: "Harrison Armory enjoys a galaxy-wide reputation for the quality of its weapons and defensive systems. The corpro-state previously specialized in ordnance and other armaments, making it reliant on competitors’ frames as mounts for its deluxe equipment; however, since the overthrow of Union’s Second Committee, Harrison Armory has broadened its product line to include an extensive range of peerless frontline frames. On the wave of this new success, the Armory has transformed into a burgeoning, imperial corpro-state, a mighty galactic power that directly administers a large number of Core worlds, orbitals, and colonial prospects – this is the Purview; all lands under the Armory’s command.<br><br>By necessity of Harrison Armory’s imperial aims, its frames tend to be sturdy. More than that, Armory mechs are built to ensure overwhelming performance, embodying dominance and power in their brutal, geometric aesthetics. This fulfillment of this desire requires tremendous power, skill, and material strength.<br><br>Harrison Armory licenses are perfect for pilots looking to field durable frontline mechs equipped with the most advanced weapons technology available."
  }
], require$$9 = [
  {
    id: "missing_weaponmod",
    name: "ERR: DATA NOT FOUND",
    sp: 1,
    allowed_types: [
      "Melee"
    ],
    source: "GMS",
    license: "GMS",
    license_level: 1,
    effect: "COMP/CON is unable to retrieve the data necessary to furnish this System. This is likely the result of a missing or outdated content pack.",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this System. This is likely the result of a missing or outdated content pack.",
    tags: [],
    license_id: ""
  },
  {
    id: "wm_thermal_charge",
    name: "Thermal Charge",
    sp: 2,
    allowed_types: [
      "Melee"
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 2,
    effect: "On a hit with the weapon this mod is applied to, expend a charge as a free action to activate its detonator and deal +1d6 explosive bonus damage.",
    description: "One popular modification to the classic war pike involves replacing the long, armor-piercing pike head with a disposable, impact-triggered explosive charge. On penetration, the pike’s head is severed from the shaft – moments later, the embedded pike head detonates in a conical explosion from the point forward. Spare thermal charges are stable, and transported in external tube magazines.<br>IPS-N also makes thermal charges compatible with GMS’s range of blades, hammers, and picks.",
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      }
    ],
    added_damage: [
      {
        type: "Explosive",
        val: "1d6"
      }
    ],
    license_id: "mf_nelson"
  },
  {
    id: "wm_uncle_class_comp_con",
    name: "UNCLE-Class Comp/Con",
    sp: 3,
    allowed_types: [
      "Melee",
      "CQB",
      "Rifle",
      "Launcher",
      "Cannon",
      "Nexus"
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 3,
    effect: "Your UNCLE-class COMP/CON has control of the weapon this mod is applied to and its associated systems.<br>1/turn, you can attack at +2 difficulty with UNCLE’s weapon as a free action. UNCLE can’t use weapons that have already been used this turn, and any weapon UNCLE attacks with can’t be used again until the start of your next turn.<br>UNCLE isn’t a full NHP, so cannot enter cascade.",
    description: "IPS-N’s UNCLE COMP/CON system is the result of the DARKSTAR-2 program, a temporary project that sought to develop more advanced smart weapons. Early prototypes were hampered by a combination of high power-draw, unstable conditioning, and frustrating single-task orientation that eventually saw the project shuttered.<br>While IPS-N is no longer developing new iterations of UNCLE, they still have a stock of QA-approved legacy systems accessible to qualified pilots.<br>Pilots lucky enough to field test models swear by UNCLE’s task efficiency and parallel-track reasoning, though the outdated COMP/CONs are known for their somewhat unstable personalities.",
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_ai"
      },
      {
        id: "tg_no_cascade"
      }
    ],
    restricted_sizes: [
      "Superheavy"
    ],
    license_id: "mf_raleigh"
  },
  {
    id: "wm_throughbolt_rounds",
    name: "Throughbolt Rounds",
    sp: 2,
    allowed_types: [
      "CQB",
      "Cannon",
      "Rifle"
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 3,
    effect: "When you attack with the weapon this mod is applied to, you may fire a throughbolt round instead of attacking normally. Draw a line 3 path from you, passing through terrain or other obstacles – any characters or objects in the path take 2 AP kinetic damage as the projectile punches through them and out the other side. Range, cover, and line of sight for the attack are then measured from the end of this path, continuing in the same direction.",
    description: "Throughbolt rounds are a proprietary IPS-N anti-armor invention. When fired, the rounds ignite and project a superheated cone of plasma before them, creating an effect like a miniature lance that easily penetrates multiple targets – even through hard surfaces.",
    tags: [
      {
        id: "tg_unique"
      }
    ],
    license_id: "mf_tortuga"
  },
  {
    id: "wm_shock_wreath",
    name: "Shock Wreath",
    sp: 2,
    allowed_types: [
      "Melee"
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 3,
    effect: "In addition to its usual damage, 1/round you may activate the wreath as a quick action when you hit a character with the weapon this mod is applied to to cause it to take 1d6 burn. If it already is suffering from burn, it can additionally only draw line of sight to adjacent spaces until the end of its next turn.",
    actions: [
      {
        name: "Activate Shock Wreath",
        activation: "Quick",
        detail: "1/round you may activate your equipped Shock Wreath as a quick action when you hit a character with the weapon it is applied to to cause it to take 1d6 burn. If it already is suffering from burn, it can additionally only draw line of sight to adjacent spaces until the end of its next turn."
      }
    ],
    description: "A post-fab modification popular among melee combat specialists, Shock Wreathes integrate a bundle of conductive filaments within the blade, point, tip, or surface of a close combat weapon. Paired with a power source – typically in the hilt or lower half of a weapon, but sometimes external – Shock Wreathes give kinetic weapons a thermal edge and a distinctive visual marker: fine lines of white-hot light like filigree, shrouding the modified weapon in shimmering heat.",
    tags: [
      {
        id: "tg_unique"
      }
    ],
    license_id: "mf_metalmark"
  },
  {
    id: "wm_stabilizer_mod",
    name: "Stabilizer Mod",
    sp: 2,
    allowed_types: [
      "Launcher",
      "Cannon"
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 2,
    effect: "the weapon this mod is applied to gains +5 range and the Ordnance tag.",
    description: "Stabilizer mods enhance physical mounts and targeting software, ensuring weapons remain level, steady, and at an appropriate angle regardless of terrain or pilot maneuvers.",
    added_range: [
      {
        type: "Range",
        val: 5
      }
    ],
    added_tags: [
      {
        id: "tg_ordnance"
      }
    ],
    license_id: "mf_monarch"
  },
  {
    id: "wm_nanocomposite_adaptation",
    name: "Nanocomposite Adaptation",
    sp: 2,
    allowed_types: [
      "Melee",
      "CQB",
      "Rifle",
      "Launcher",
      "Cannon",
      "Nexus"
    ],
    source: "HORUS",
    license: "Balor",
    license_level: 2,
    effect: "the weapon this mod is applied to gains Smart and Seeking.",
    description: "Nanocomposite weapons take aggressive drone swarms and condense them into individual rounds, a coherent beam, or the edge of a blade.<br>Adapted projectile weapons fire shaped CONSUME/HIVE rounds that shatter on impact, releasing their payload of autonomous nanite maniples. Once freed, the maniples begin eating away at surrounding tissue or superstructure. They proceed until burnout or total target consumption, whichever occurs first. In flight, the maniples are able to hive-link and make slight adjustments to the trajectory of their round, ensuring positive impact.<br>Coherent beam weapons transport maniples directly, while conventional melee weapons are replaced by analogs composed entirely of nanobots.",
    added_tags: [
      {
        id: "tg_smart"
      },
      {
        id: "tg_seeking"
      }
    ],
    license_id: "mf_balor"
  },
  {
    id: "wm_phase_ready_mod",
    name: "Phase-Ready Mod",
    sp: 2,
    allowed_types: [
      "Melee",
      "CQB",
      "Rifle",
      "Launcher",
      "Cannon",
      "Nexus"
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 2,
    effect: "As long as you know the rough location of your target, the weapon this mod is applied to can attack through solid walls and obstructions, doesn’t require line of sight, and ignores all cover, but targets attacked this way count as Invisible.",
    description: "As it was named following its first use during the civil hostilities on Luna de Oro, phase-ready ammunition is the “devil’s bullets”. Each round contains a nanoprocessor suite networked with its weapon of origin that calculates and translates the specific nature of that round’s superpositional relation with a projected future doppelgänger that manifests in the space immediately before its intended target. To put it simply, phase-ready rounds, when fired, exist in two places at once: exiting the barrel of the weapon they were fired from, and directly in front of the target, prior to impact. The prime round may never hit its target, but given it already exists at the moment of impact, the doppelgänger round will reliably reach its mark.",
    license_id: "mf_napoleon"
  },
  {
    id: "wm_paracausal_mod",
    name: "Paracausal Mod",
    sp: 4,
    allowed_types: [
      "Melee",
      "CQB",
      "Rifle",
      "Launcher",
      "Cannon",
      "Nexus"
    ],
    source: "HA",
    license: "Saladin",
    license_level: 3,
    effect: "This weapon gains Overkill, and its damage can’t be reduced in any way, including by other effects and systems (such as Resistance, Armor, etc).",
    description: "Paracausal weapons are a headache for military planners; their precise A–Z function is often obscured, though they consistently produce the same “Z” output per “A” input.<br>The first reports of unregulated paracausal weaponry occurred during the civil engagements on Tian Shen. System-local forces received sealed magazines with directions to be loaded and fired as normal, although inspection of the magazines’ contents was prohibited on grounds that it would “damage the payload”. Helmet and gun cam footage do not betray the anomalous effects of this ordnance, though after-action reports uncovered a seemingly minor, though incredibly odd fact: every single trooper outfitted with this paracausal ammunition scored a 100% positive impact rate.<br>Union has scheduled all unregulated paracausal weapons and ammunition for retrieval, and the bureau is currently investigating Harrison Armory for its role in the development of the technology. Despite this, paracausal ammunition is still in use, as shipments and codes continue to leak to interested parties.",
    added_tags: [
      {
        id: "tg_overkill"
      }
    ],
    license_id: "mf_saladin"
  }
], require$$10 = [
  {
    id: "missing_pilotweapon",
    name: "ERR: DATA NOT FOUND",
    type: "Weapon",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Pilot Gear. This is likely the result of a missing or outdated content pack.",
    tags: [
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [],
    damage: []
  },
  {
    id: "pg_archaic_melee",
    name: "Archaic Melee",
    type: "Weapon",
    description: "These weapons were made using pre-Union alloys and technology, and might be anything from industrial-era steel swords through to stone axes. While they remain widely used on some worlds, archaic weapons used by pilots are usually relics, heirlooms, or ceremonial weapons.",
    tags: [
      {
        id: "tg_archaic"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    damage: [
      {
        type: "kinetic",
        val: 1
      }
    ]
  },
  {
    id: "pg_archaic_ranged",
    name: "Archaic Ranged",
    type: "Weapon",
    description: "These weapons are pre-modern devices like muskets and bows, all of which are still used in some societies.",
    tags: [
      {
        id: "tg_archaic"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    damage: [
      {
        type: "kinetic",
        val: 1
      }
    ]
  },
  {
    id: "pg_light_a_c",
    name: "Light A/C",
    type: "Weapon",
    description: "Light A/C weapons might be knives, bayonets, punching daggers, and short swords.",
    tags: [
      {
        id: "tg_sidearm"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    damage: [
      {
        type: "kinetic",
        val: 1
      }
    ]
  },
  {
    id: "pg_medium_a_c",
    name: "Medium A/C",
    type: "Weapon",
    description: "Medium A/C weapons are typically swords, officer’s sabers, and trench axes.",
    tags: [
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    damage: [
      {
        type: "Kinetic",
        val: 2
      }
    ]
  },
  {
    id: "pg_heavy_a_c",
    name: "Heavy A/C",
    type: "Weapon",
    description: "Heavy weapons are designed with the augmented strength of hardsuits in mind and include war hammers, mallets, rams, pikes, and heavy two-handed assault swords.",
    tags: [
      {
        id: "tg_inaccurate"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    damage: [
      {
        type: "kinetic",
        val: 3
      }
    ]
  },
  {
    id: "pg_light_signature",
    name: "Light Signature",
    type: "Weapon",
    description: "Light signature weapons might be oversized revolvers, braces of pistols, and submachine guns.",
    tags: [
      {
        id: "tg_sidearm"
      },
      {
        id: "tg_set_damage_type"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Range",
        val: 3
      }
    ],
    damage: [
      {
        type: "variable",
        val: 1
      }
    ],
    effect: "When a signature weapon is acquired, choose its damage type – Explosive, Energy, or Kinetic."
  },
  {
    id: "pg_medium_signature",
    name: "Medium Signature",
    type: "Weapon",
    description: "Medium signature weapons are assault rifles, shotguns, pack-fed lasers, or disruption guns.",
    tags: [
      {
        id: "tg_set_damage_type"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    damage: [
      {
        type: "variable",
        val: 2
      }
    ],
    effect: "When a signature weapon is acquired, choose its damage type – Explosive, Energy, or Kinetic."
  },
  {
    id: "pg_heavy_signature",
    name: "Heavy Signature",
    type: "Weapon",
    description: "Heavy signature weapons are missile tubes, heavy lasers, light machine gun, or exotic rifles.",
    tags: [
      {
        id: "tg_ordnance"
      },
      {
        id: "tg_loading"
      },
      {
        id: "tg_set_damage_type"
      },
      {
        id: "tg_pilot_weapon"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    damage: [
      {
        type: "variable",
        val: 4
      }
    ],
    effect: "When a signature weapon is acquired, choose its damage type – Explosive, Energy, or Kinetic."
  },
  {
    id: "missing_pilotarmor",
    name: "ERR: DATA NOT FOUND",
    type: "Armor",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Pilot Gear. This is likely the result of a missing or outdated content pack.",
    tags: [
      {
        id: "tg_personal_armor"
      }
    ]
  },
  {
    id: "pg_light_hardsuit",
    name: "Light Hardsuit",
    type: "Armor",
    description: "Light hardsuits are usually made from reactive, cloth-like weaves, with limited plating and few powered components to maximize mobility. Like other hardsuits, they can be sealed against vacuum, and protect against a decent amount of radiation and other harmful particles.",
    bonuses: [
      {
        id: "pilot_hp",
        val: 3
      },
      {
        id: "pilot_evasion",
        val: 10,
        replace: !0
      },
      {
        id: "pilot_edef",
        val: 10,
        replace: !0
      },
      {
        id: "pilot_speed",
        val: 4,
        replace: !0
      }
    ],
    tags: [
      {
        id: "tg_personal_armor"
      }
    ]
  },
  {
    id: "pg_assault_hardsuit",
    name: "Assault Hardsuit",
    type: "Armor",
    description: "These hardsuits, common among military units, feature heavier plating than light hardsuits but more mobility than heavy hardsuits. They are powered, augmenting the user’s strength, and typically feature an onboard computer, sensor suite, integrated air, burst EVA system, and waste recycling systems.",
    bonuses: [
      {
        id: "pilot_hp",
        val: 3
      },
      {
        id: "pilot_armor",
        val: 1
      },
      {
        id: "pilot_evasion",
        val: 8,
        replace: !0
      },
      {
        id: "pilot_edef",
        val: 8,
        replace: !0
      },
      {
        id: "pilot_speed",
        val: 4,
        replace: !0
      }
    ],
    tags: [
      {
        id: "tg_personal_armor"
      }
    ]
  },
  {
    id: "pg_heavy_hardsuit",
    name: "Heavy Hardsuit",
    type: "Armor",
    description: "The heaviest hardsuits. They are always powered and up-armored with thick, composite armor. Heavy hardsuits often feature integrated weapons, powerful mobility suites, and – by augmenting their user’s strength – allow their user to field much heavier weapons than normal infantry can typically carry. Heavy hardsuits are in decline now that half-size chassis are popular, but they are still common among private militaries and middle-tier Diasporan armed forces.",
    bonuses: [
      {
        id: "pilot_hp",
        val: 3
      },
      {
        id: "pilot_armor",
        val: 2
      },
      {
        id: "pilot_evasion",
        val: 6,
        replace: !0
      },
      {
        id: "pilot_edef",
        val: 8,
        replace: !0
      },
      {
        id: "pilot_speed",
        val: 3,
        replace: !0
      }
    ],
    tags: [
      {
        id: "tg_personal_armor"
      }
    ]
  },
  {
    id: "pg_mobility_hardsuit",
    name: "Mobility Hardsuit",
    type: "Armor",
    effect: "These hardsuits have integrated flight systems, allowing pilots to fly when they move or Boost. Flying pilots must end their turn on the ground (or another surface) or begin falling.",
    bonuses: [
      {
        id: "pilot_evasion",
        val: 10,
        replace: !0
      },
      {
        id: "pilot_edef",
        val: 10,
        replace: !0
      },
      {
        id: "pilot_speed",
        val: 5,
        replace: !0
      }
    ],
    tags: [
      {
        id: "tg_personal_armor"
      }
    ]
  },
  {
    id: "pg_stealth_hardsuit",
    name: "Stealth Hardsuit",
    type: "Armor",
    effect: "As a quick action, pilots wearing stealth hardsuits can become Invisible. They cease to be Invisible if they take any damage.",
    bonuses: [
      {
        id: "pilot_evasion",
        val: 8,
        replace: !0
      },
      {
        id: "pilot_edef",
        val: 8,
        replace: !0
      },
      {
        id: "pilot_speed",
        val: 4,
        replace: !0
      }
    ],
    tags: [
      {
        id: "tg_personal_armor"
      }
    ],
    actions: [
      {
        name: "Activate Stealth Hardsuit",
        activation: "Quick",
        detail: "Become Invisible. You will cease to be Invisible if you take any damage.",
        pilot: !0
      }
    ]
  },
  {
    id: "missing_pilotgear",
    name: "ERR: DATA NOT FOUND",
    type: "Gear",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Pilot Gear. This is likely the result of a missing or outdated content pack.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_corrective",
    name: "Corrective",
    type: "Gear",
    effect: "Expend a charge to apply correctives to Down and Out pilots, immediately bringing them back to consciousness at 1 HP.",
    description: "This clear, plastic-like sheet can be placed over the wounds of severely injured pilots. It instantly begins to stabilize them, injecting medicine and deploying nanites to stitch wounds shut.",
    actions: [
      {
        name: "Use Corrective",
        activation: "Full",
        detail: "Expend a charge to apply correctives to Down and Out pilots, immediately bringing them back to consciousness at 1 HP",
        pilot: !0
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_frag_grenades",
    name: "Frag Grenades",
    type: "Gear",
    effect: "Expend a charge for the following effect:<ul><li><b>Frag Grenade</b> (Grenade, Range 5, Blast 1): Affected characters must succeed on an Agility save or take 2 Explosive damage.</li></ul>",
    actions: [
      {
        name: "Use Frag Grenade",
        activation: "Quick",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Blast",
            val: 1
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: 2
          }
        ],
        detail: "Throw a grenade within Range 5. Affected characters within a Blast 1 must succeed on an Agility save or take 2 Explosive damage.",
        pilot: !0
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_grenade"
      },
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_patch",
    name: "Patch",
    type: "Gear",
    effect: "Expend a charge to apply a patch to either yourself or an adjacent pilot, restoring half their maximum HP. Patches have no effect on Down and Out pilots.",
    description: "“Patch” is pilot slang for any kind of modern first aid gear, including sprayable medi-gel and instant-acting medical patches.",
    actions: [
      {
        name: "Use Patch",
        activation: "Full",
        detail: "Expend a charge to apply a patch to either yourself or an adjacent pilot, restoring half their maximum HP. Patches have no effect on Down and Out pilots.",
        pilot: !0
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_stims",
    name: "Stims",
    type: "Gear",
    effect: "Expend a charge for one of the following effects:<ul><li><b>Kick:</b> Keeps a pilot awake and alert for up to 30 hours.</li><li><b>Freeze:</b> Keeps a pilot calm and emotionally stable; deadens fear and other strong reactions.</li><li><b>Juice:</b> Heighten senses and alertness, reduce fatigue, and shorten reaction times. Juice occasionally provokes rage in some users.</li></ul>",
    description: "These chemical stimulants are sometimes administered automatically by injectors built into a pilot’s suit, or even implanted within their body. Uncontrolled use can be addictive and dangerous to health in the long-term and is a problem for some pilots.",
    actions: [
      {
        name: "Use Stim",
        activation: "Quick",
        detail: "Expend a charge for one of the following effects:<ul><li><b>Kick:</b> Keeps a pilot awake and alert for up to 30 hours.</li><li><b>Freeze:</b> Keeps a pilot calm and emotionally stable; deadens fear and other strong reactions.</li><li><b>Juice:</b> Heighten senses and alertness, reduce fatigue, and shorten reaction times. Juice occasionally provokes rage in some users.</li></ul>",
        pilot: !0
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_thermite_charge",
    name: "Thermite Charge",
    type: "Gear",
    effect: "Expend a charge for the following effect:<ul><li><b>Thermite Charge</b> (Mine, Burst 1): This charge must be remotely detonated as a quick action. Affected characters must succeed on an Engineering save or take 3 Energy AP. Thermal charges automatically hit objects, dealing 10 Energy AP.</li></ul>",
    deployables: [
      {
        name: "Thermite Charge",
        type: "Mine",
        detail: "This charge must be remotely detonated as a quick action. Affected characters must succeed on an Engineering save or take 3 Energy AP. Thermal charges automatically hit objects, dealing 10 Energy AP.",
        pilot: !0,
        actions: [
          {
            name: "Detonate",
            activation: "Quick",
            detail: "Affected characters must succeed on an Engineering save or take 3 Energy AP. Thermal charges automatically hit objects, dealing 10 Energy AP.",
            pilot: !0
          }
        ]
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_antiphoton_visor",
    name: "Antiphoton Visor",
    type: "Gear",
    description: "Designed to protect the wearer’s eyes from intense bursts of light, antiphoton visors are commonly found among breach teams and solar-forward operators. They are effective against flash weapons, intense UV light, and incidental charges from energy weapons.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_camo_cloth",
    name: "Camo Cloth",
    type: "Gear",
    description: "A square of reactive material that slowly shifts to reflect the surrounding environment, enough to cover a human comfortably. The transition takes about 10 seconds and makes anything hidden underneath very difficult to spot.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_dataplating",
    name: "Dataplating",
    type: "Gear",
    description: "Dataplating is a general term for any comm-linked jewelry, subdermal netting, wearable jaw, brow, or maxillary plates, etc., that allows subvocal communication and persistent heads-up and augmented reality displays without wearing a helm. Dataplates can quickly translate nearly any language, and allow users to communicate with each other all but silently.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_extra_rations",
    name: "Extra Rations",
    type: "Gear",
    description: "Pilot rations aren’t much better than their nautical forerunners – both are variants on hardtack and nutrient paste. Pilots often carry a stash of extra food, or luxuries like chocolate, coffee, alcohol, or preserved goods from their homeworld. These rations can be used to barter or boost morale.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_flexsuit",
    name: "Flexsuit",
    type: "Gear",
    description: "A strong base-layer suit that recycles water, generates nutrients, and adapts very rapidly to hostile environs, maintaining a stable condition and extending survivability. Flexsuit wearers can go for roughly a week without eating or drink thanks to the ambrosia paste generated by their suit before its systems are depleted; however, they don’t prevent feelings of hunger. Removing the suit for a day or two is enough to replenish its reserves. Flexsuits also maintain a steady temperature within acceptable parameters.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_handheld_printer",
    name: "Handheld Printer",
    type: "Gear",
    description: "A miniaturized version of Union’s full-scale printers, handheld printers can be used to make simple objects out of flexible and durable plastic – as long as you have the right pattern chip.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_subjectivity_enhancement_suite",
    name: "Subjectivity-Enhancement Suite",
    type: "Gear",
    description: "A subjectivity-enhancement suite is a set of cybernetic implants allowing users to hack systems without a rig. Users of these suites blend the organic with the synthetic, gaining the ability to extrude implanted universal-plug cables from within their body to make hardline connections with terminals. When plugged in, users can access a comprehensive, fully interactive alternate-reality interface with direct omninet access, making navigating – or hacking – local and networked systems as easy as wishing it so (of course, you must be careful: by opening up your mind to the digital, you may face dangers other, less enhanced people are ignorant of).",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_infoskin",
    name: "Infoskin",
    type: "Gear",
    description: "A reactive, synthetic polymer with advanced qualities, infoskin bonds quickly to real skin and hair. Once applied, it responds to electronic signals delivered by linked software, rapidly changing its color and texture – even contorting and distorting its form – allowing wearers to make minor changes to their appearance. With infoskin, it’s a simple matter to alter facial features, hair color, or makeup patterns.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_mag_clamps",
    name: "Mag-Clamps",
    type: "Gear",
    description: "These clamps attach easily to any metal surface, enhancing maneuverability in zero-g environments or when repairing mechs. They can be carried or fitted to boots.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_nanite_spray",
    name: "Nanite Spray",
    type: "Gear",
    description: "A spray paint that can be applied to any surface. Nanite spray is invisible to the naked eye but able to transmit simple messages or small data packets when scanned.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_omnihook",
    name: "Omnihook",
    type: "Gear",
    description: "A portable – if bulky – omninet terminal that allows for communication, data transfer, and limited hot-spotting. Omnihooks are extremely valuable, although most mech squads have at least one. Tuning an omnihook requires a high level of skill, so they are usually mounted or carried by designated operators.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_personal_drone",
    name: "Personal Drone",
    type: "Gear",
    description: "Small, non-combat drones are a common sight in the field. They’re fairly noisy but can fly about half a mile with good maneuverability before losing signal, relaying audio and visual information as they go.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_prosocollar",
    name: "Prosocollar",
    type: "Gear",
    description: "A collar-like device that fits snugly around its wearer’s neck, projecting a holographic image over their face and head. Prosocollars can change their wearer’s voice and scramble or change their appearance. The projection won’t stand up to close inspection, but it can easily fool electronic systems and distant observers.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_smart_scope",
    name: "Smart Scope",
    type: "Gear",
    description: "A powerful electronic scope that provides high-resolution magnification up to two miles, and automatically adjusts its reticle for wind, gravity, and pressure. Smart scopes can project their field of vision and all data to the HUD of any networked user. They can also pair with other thermal, optical, or simulated-vision devices to further enhance targeting.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_sleeping_bag",
    name: "Sleeping Bag",
    type: "Gear",
    effect: "You can climb into your sleeping bag, gaining Immunity to burn, protection against vacuum, and enough air to last an hour; however, while in the sleeping bag you are Stunned and can’t take actions other than to exit the bag as a full action.",
    description: "Coming in a variety of sizes, sleeping bags are a field necessity. They’re designed to fold out from a hardsuit, fit within a mech’s cockpit, resist fire and changes in temperature, and – when necessary – seal against vacuum.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_ssc_sylph_undersuit",
    name: "SSC Sylph Undersuit",
    type: "Gear",
    description: "Discovered on Acrimea IV, a biome cultivar world controlled by Smith-Shimano Corpro (SSC), the sylph is an organic lifeform that can seemingly survive in nearly any environment. Using breeding-analogous methods defined by established bioengineering doctrines, SSC developed the sylph undersuit – sterile, living sylphs grown as envelopes and fitted to their owners. The sylph bonds to its wearer, forming a symbiotic relationship: the sylph is sustained by the host’s waste products, in return protecting the host from a range of hostile environmental factors.<br>These semi-biological, skin-tight undersuits can be worn for extended periods. They are translucent, semi-liquid, and able to be stored when not in use, conforming to whatever container they are placed in. They clean the host’s body, aid natural healing processes, and eliminate waste. As desired, segments can become opaque, change color, or take on a new texture. Sylph undersuits can cover the host’s head, sealing against vacuum, providing protection against radiation, and filtering air or liquids, even providing the ability to breathe water for a limited time.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_sound_system",
    name: "Sound System",
    type: "Gear",
    description: "Though their tactical utility is questionable, many pilots set up internal speaker systems in their cockpits. This gives them a clear line to their compatriots during combat, along with the ability to play music.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_tertiary_arm",
    name: "Tertiary Arm",
    type: "Gear",
    description: "A powered third arm mounted on a bracket on the hardsuit. Tertiary arms are powered and controlled using the same neural bridge processes that allow hardsuits to respond to user input. They can be equipped with manipulators to allow for fine motor control, weapons to enhance combat efficacy, or specialty tools.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  },
  {
    id: "pg_wilderness_survival_kit",
    name: "Wilderness Survival Kit",
    type: "Gear",
    description: "This kit contains many essentials for surviving in hostile environments: a rebreather, water filters, hardsuit patches, backup thermals, a bivouac kit, and so on.",
    tags: [
      {
        id: "tg_gear"
      }
    ]
  }
], require$$11 = [
  {
    id: "reserve_skill",
    name: "Skill Point",
    type: "Bonus",
    label: "Bonus",
    description: 'Add a Skill Point to gain or improve a skill, typically as part of the "Get Focused" Downtime Action.',
    bonuses: [
      {
        id: "skill_point",
        val: 1
      }
    ]
  },
  {
    id: "reserve_mechskill",
    name: "Mech Skill Point",
    type: "Bonus",
    label: "Bonus",
    description: "Add a Mech Skill Point to add to your Pilot's HULL, AGILITY, SYSTEMS, or ENGINEERING rating.",
    bonuses: [
      {
        id: "mech_skill_point",
        val: 1
      }
    ]
  },
  {
    id: "reserve_talent",
    name: "Talent Point",
    type: "Bonus",
    label: "Bonus",
    description: "Add a Talent Point to gain or improve a Pilot Talent.",
    bonuses: [
      {
        id: "talent_point",
        val: 1
      }
    ]
  },
  {
    id: "reserve_license",
    name: "License Point",
    type: "Bonus",
    label: "Bonus",
    description: "Add a License Point to advance or unlock a new License.",
    bonuses: [
      {
        id: "license_point",
        val: 1
      }
    ]
  },
  {
    id: "reserve_corebonus",
    name: "Extra CORE Bonus",
    type: "Bonus",
    label: "Bonus",
    description: "Add an additional CORE Bonus.",
    bonuses: [
      {
        id: "cb_point",
        val: 1
      }
    ]
  },
  {
    id: "reserve_access",
    name: "Access",
    type: "Resource",
    label: "Resource",
    description: "A keycard, invite, bribes or insider access to a particular location."
  },
  {
    id: "reserve_backing",
    name: "Backing",
    type: "Resource",
    label: "Contact",
    description: "Useful leverage through political support from a powerful figure."
  },
  {
    id: "reserve_supplies",
    name: "Supplies",
    type: "Resource",
    label: "Resource",
    description: "Gear allowing easy crossing of a hazardous or hostile area."
  },
  {
    id: "reserve_disguise",
    name: "Disguise",
    type: "Resource",
    label: "Identity",
    description: "An effective disguise or cover identity, allowing uncontested access to a location."
  },
  {
    id: "reserve_diversion",
    name: "Diversion",
    type: "Resource",
    label: "Diversion",
    description: "A distraction that provides time to take action without fear of consequence."
  },
  {
    id: "reserve_blackmail",
    name: "Blackmail",
    type: "Resource",
    label: "Target",
    description: "Blackmail materials or sensitive information concerning a particular person."
  },
  {
    id: "reserve_reputation",
    name: "Reputation",
    type: "Resource",
    label: "Status",
    description: "A good name in the mission area, prompting good first impressions with the locals."
  },
  {
    id: "reserve_safe_harbor",
    name: "Safe Harbor",
    type: "Resource",
    label: "Location",
    description: "Guaranteed safety for meeting, planning, or recuperating."
  },
  {
    id: "reserve_tracking",
    name: "Tracking",
    type: "Resource",
    label: "Target",
    description: "Details on the location of important objects or people."
  },
  {
    id: "reserve_knowledge",
    name: "Knowledge",
    type: "Resource",
    label: "Subject",
    description: "An understanding of local history, customs, culture, or etiquette."
  },
  {
    id: "reserve_ammo",
    name: "Ammo",
    type: "Mech",
    label: "Ammo",
    description: "Extra uses (+1 or +2) of a LIMITED weapon or system."
  },
  {
    id: "reserve_rented_gear",
    name: "Rented gear",
    type: "Mech",
    label: "Gear",
    description: "Temporary access to a new weapon or piece of mech gear."
  },
  {
    id: "reserve_extra_repairs",
    name: "Extra repairs",
    type: "Mech",
    label: "Resource",
    description: "Supplies that give a mech +2 REPAIR CAP.",
    bonuses: [
      {
        id: "repcap",
        val: 2
      }
    ]
  },
  {
    id: "reserve_core_battery",
    name: "CORE battery",
    type: "Mech",
    label: "Battery",
    description: "An extra battery that allows a second use of a mech’s CORE SYSTEM.",
    bonuses: [
      {
        id: "core_power",
        val: 2
      }
    ]
  },
  {
    id: "reserve_deployable_shield",
    name: "Deployable Shield",
    type: "Mech",
    label: "Shield",
    description: "A single-use deployable shield generator – a SIZE 1 deployable that grants soft cover to all friendly characters in a BURST 2 radius.",
    deployables: [
      {
        name: "Deployable Shield (Reserve)",
        type: "Deployable",
        size: 1,
        detail: "Grants soft cover to all friendly characters in a BURST 2 radius"
      }
    ]
  },
  {
    id: "reserve_redundant_repair",
    name: "Redundant repair",
    type: "Mech",
    label: "Resource",
    description: "The ability to STABILIZE as a free action once per mission.",
    actions: [
      {
        name: "Redundant Repair",
        activation: "Free",
        detail: "STABILIZE as a free action."
      }
    ]
  },
  {
    id: "reserve_systems_reinforcement",
    name: "Systems reinforcement",
    type: "Mech",
    label: "Resource",
    description: "+1 ACCURACY to skill checks made with one skill – HULL, AGILITY, SYSTEMS or ENGINEERING.",
    synergies: [
      {
        locations: [
          "hase"
        ],
        detail: "+1 ACCURACY to skill checks made with one skill – HULL, AGILITY, SYSTEMS or ENGINEERING."
      }
    ]
  },
  {
    id: "reserve_smart_ammo",
    name: "Smart ammo",
    type: "Mech",
    label: "Ammo",
    description: "All weapons of your choice can be fired as if they are SMART.",
    synergies: [
      {
        locations: [
          "weapon"
        ],
        detail: "All weapons of your choice can be fired as if they are SMART"
      }
    ]
  },
  {
    id: "reserve_boosted_servos",
    name: "Boosted servos",
    type: "Mech",
    label: "Resource",
    description: "IMMUNITY to the SLOWED condition.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "Your mech has IMMUNITY to the SLOWED condition."
      }
    ]
  },
  {
    id: "reserve_jump_jets",
    name: "Jump jets",
    type: "Mech",
    label: "Resource",
    description: "During this mission your mech can FLY when moving, but must end movement on land.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "Your mech can FLY when moving, but must end movement on land."
      }
    ]
  },
  {
    id: "reserve_scouting",
    name: "Scouting",
    type: "Tactical",
    label: "Location",
    description: "Detailed information on the kinds of mechs and threats you will face on the mission, such as number, type, and statistics."
  },
  {
    id: "reserve_vehicle",
    name: "Vehicle",
    type: "Tactical",
    label: "Designation",
    description: "Use of a transport vehicle or starship (e.g. a TIER 1 NPC with the VEHICLE or SHIP template.)"
  },
  {
    id: "reserve_reinforcements",
    name: "Reinforcements",
    type: "Tactical",
    label: "Designation",
    description: "The ability to call in a friendly NPC mech of any Tier, once per mission."
  },
  {
    id: "reserve_environmental_shielding",
    name: "Environmental shielding",
    type: "Tactical",
    label: "Environment",
    description: "Equipment that allows you to ignore a particular battlefield hazard or dangerous terrain, such as extreme heat or cold."
  },
  {
    id: "reserve_accuracy",
    name: "Accuracy",
    type: "Tactical",
    label: "Skill/Action",
    description: "Training or enhancement that provides +1 ACCURACY to a particular mech skill or action for the duration of this mission.",
    synergies: [
      {
        locations: [
          "other"
        ],
        detail: "+1 ACCURACY to a particular mech skill or action for the duration of this mission."
      }
    ]
  },
  {
    id: "reserve_bombardment",
    name: "Bombardment",
    type: "Tactical",
    label: "Resource",
    description: "The ability to call in artillery or orbital bombardment once during mech combat (full action, RANGE 30 within line of sight, BLAST 2, 3d6 explosive damage).",
    actions: [
      {
        name: "Bombardment",
        activation: "Full",
        detail: "Call in artillery or orbital bombardment:<br>RANGE 30 within line of sight, BLAST 2, 3d6 explosive damage",
        range: [
          {
            type: "Range",
            val: 30
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "3d6"
          }
        ]
      }
    ]
  },
  {
    id: "reserve_extended_harness",
    name: "Extended Harness",
    type: "Tactical",
    label: "Resource",
    description: "A custom harness that allows you to carry an extra pilot weapon and two extra pieces of pilot gear for the duration of this mission.",
    bonuses: [
      {
        id: "pilot_gear_slots",
        val: 2
      },
      {
        id: "pilot_weapon_slots",
        val: 1
      }
    ]
  },
  {
    id: "reserve_ambush",
    name: "Ambush",
    type: "Tactical",
    label: "Location",
    description: "Intel that allows you to choose exactly where your next battle will take place, including the layout of terrain and cover."
  },
  {
    id: "reserve_orbital_drop",
    name: "Orbital Drop",
    type: "Tactical",
    label: "Location",
    description: "The ability to start the mission by dropping from orbit into a heavily fortified or hard to reach location."
  },
  {
    id: "reserve_nhp_assistant",
    name: "NHP Assistant",
    type: "Tactical",
    label: "Designation",
    description: "A non-human person (NHP) – an advanced artificial intelligence – controlled by the GM, that can give you advice on the current situation."
  }
], base_structure = 4, base_stress = 4, base_grapple = 0, base_ram = 0, base_pilot_hp = 6, base_pilot_evasion = 10, base_pilot_edef = 10, base_pilot_speed = 4, base_pilot_sensors = 5, base_pilot_save_target = 10, minimum_pilot_skills = 4, minimum_mech_skills = 2, minimum_pilot_talents = 3, trigger_bonus_per_rank = 2, max_trigger_rank = 3, max_pilot_level = 12, max_pilot_weapons = 2, max_pilot_armor = 1, max_pilot_gear = 3, max_frame_size = 3, max_mech_armor = 4, max_hase = 6, mount_fittings = {
  Auxiliary: [
    "Auxiliary"
  ],
  Main: [
    "Main",
    "Auxiliary"
  ],
  Flex: [
    "Main",
    "Auxiliary"
  ],
  Heavy: [
    "Superheavy",
    "Heavy",
    "Main",
    "Auxiliary"
  ]
}, overcharge = [
  "1",
  "1d3",
  "1d6",
  "1d6+4"
], skill_headers = [
  {
    attr: "str",
    description: "use, resist, and apply direct force, physical or otherwise"
  },
  {
    attr: "dex",
    description: "perform skillfully and accurately under pressure"
  },
  {
    attr: "int",
    description: "notice details, think creatively, and prepare"
  },
  {
    attr: "cha",
    description: "talk, lead, change minds, make connections, and requisition resources"
  },
  {
    attr: "Custom",
    description: "Custom Skill Triggers"
  }
], require$$12 = {
  base_structure,
  base_stress,
  base_grapple,
  base_ram,
  base_pilot_hp,
  base_pilot_evasion,
  base_pilot_edef,
  base_pilot_speed,
  base_pilot_sensors,
  base_pilot_save_target,
  minimum_pilot_skills,
  minimum_mech_skills,
  minimum_pilot_talents,
  trigger_bonus_per_rank,
  max_trigger_rank,
  max_pilot_level,
  max_pilot_weapons,
  max_pilot_armor,
  max_pilot_gear,
  max_frame_size,
  max_mech_armor,
  max_hase,
  mount_fittings,
  overcharge,
  skill_headers
}, require$$13 = [
  {
    id: "sitrep_standardcombat",
    name: "Standard Combat",
    pcVictory: "PCs defeat or route all enemy forces",
    enemyVictory: "PCs are defeated or retreat from battle",
    description: "A simple affair, with two sides facing off against each other until one of them is broken or destroyed."
  },
  {
    id: "sitrep_control",
    name: "Control",
    description: "CONTROL missions require the PCs to maintain control of four Control Zones for six rounds. The zones might contain important locations like transmission towers, gun batteries, terminals, or hangars. At the end of each round, each side gains 1 point for each Control Zone they control. If one side controls all four Control Zones, they gain an additional +1 point.",
    pcVictory: "The PCs have the highest score at the end of the sixth round",
    enemyVictory: "The enemy force has the highest score at the end of the sixth round.",
    noVictory: "If both sides have an equal score at the end of the sixth round, there is no victor and both sides must withdraw.",
    controlZone: "Four Control Zones (typically 4 spaces on each side) in different quadrants of the map, each placed anywhere in their quadrant. They should be roughly symmetrical, or the map will be unbalanced. If there are characters of only one side within a Control Zone, they control it; if there are characters from two or more sides within a Control Zone, it is contested.",
    deployment: "The GM and a player each roll 1d6 to determine the order of deployment. Whoever rolls the lower result deploys first."
  },
  {
    id: "sitrep_escort",
    name: "Escort",
    description: "ESCORT missions require the PCs to bring an OBJECTIVE safely to the Extraction Zone and get the hell out of there.",
    pcVictory: "The Objective is safely extracted.",
    enemyVictory: "The Objective hasn’t been extracted at the end of the eighth round. If there are any PCs remaining on the field when this takes place, they are captured or overrun.",
    noVictory: "The Objective is destroyed.",
    deployment: "The PCs deploy first, choosing positions for their characters and the Objective in the Allied Deployment Zone; then, the GM deploys enemy forces in the EDZ.",
    extraction: "While in the Extraction Zone, PCs can extract as a free action at the end of their turn. Extracted PCs are removed from the battlefield. If the Objective is adjacent to a PC when they extract and isn’t contested by any characters from the opposing side, it is safely extracted."
  },
  {
    id: "sitrep_extraction",
    name: "Extraction",
    description: "EXTRACTION missions require player characters to dash across the map to retrieve an objective and bring it safely back to extraction.",
    pcVictory: "The Objective is safely extracted.",
    enemyVictory: "The Objective hasn’t been extracted at the end of the tenth round. If there are any PCs remaining on the field when this takes place, they are captured or overrun.",
    noVictory: "The Objective is destroyed.",
    deployment: "The PCs deploy first, choosing positions for their characters in the Allied Deployment Zone; next, the GM places the Objective in the Objective Zone.",
    objective: "An object or person of Size 1/2–2. The Objective has 10 HP per level of Size, Evasion 10, E-Defense 10, and no Armor. Enemy forces want the Objective and will not willingly damage it. When a character starts their turn adjacent to the Objective, it moves with them when they make their regular move. If the Objective is ever adjacent to two characters of opposing sides, it stops moving and can’t move until it is only adjacent characters from one side. The Objective doesn’t move on its own.",
    extraction: "While in the Extraction Zone/Allied Deployment Zone, PCs can extract as a free action at the end of their turn. Extracted PCs are removed from the battlefield. If the Objective is adjacent to a PC when they extract and isn’t contested by any characters from the opposing side, it is safely extracted."
  },
  {
    id: "sitrep_gauntlet",
    name: "Gauntlet",
    description: "GAUNTLET missions are usually done under duress or when no other options are available, and they usually take place in unfriendly territory. Gauntlet missions require PCs to move through a dangerous area to secure a position.",
    pcVictory: "At the end of the eighth round, there are more PCs inside the Control Zone than there are enemy characters. Ultras count as 4 characters, elites count as 2, and grunts count as 1/4.",
    enemyVictory: "At the end of the eighth round, there are at least as many enemy characters inside the Control Zone as there are PCs.",
    deployment: "The GM deploys first in the EDZ; the PCs deploy next, choosing positions for their characters within the Allied Deployment Zone.",
    controlZone: "The area around the EDZ/Control Zone is fortified with Size 1–2 hard cover."
  },
  {
    id: "sitrep_holdout",
    name: "Holdout",
    description: "HOLDOUT missions are desperate undertakings. They require the PCs to defend an area against an onslaught of enemies. In the best-case scenario, this buys time for allies to complete an objective elsewhere; in the worst, it’s survive or die. The PCs start with 4 points. At the end of the sixth round, the points are tallied: the PCs lose a point for every enemy inside the Control Zone. This can result in a negative score.",
    pcVictory: "At the end of the sixth round, the PCs have a score of 1 or higher.",
    enemyVictory: "At the end of the sixth round, the PCs have a score of less than 1. If there are any PCs remaining on the field when this takes place, they are captured or overrun.",
    controlZone: "An area typically 10 spaces by 5 spaces in the middle of the map, or positioned as needed. The area around the Control Zone should be fortified with Size 1–2 hard cover.",
    deployment: "The PCs deploy first, choosing positions for their characters within the Allied Deployment Zone/Control Zone; next, the GM deploys enemy forces in the EDZ."
  },
  {
    id: "sitrep_recon",
    name: "Recon",
    description: "RECON missions are dangerous endeavors involving small teams entering hostile territory to identify targets or retrieve key information.",
    pcVictory: "At the end of the sixth round, the PCs control the True Control Zone.",
    enemyVictory: "At the end of the sixth round, the PCs don’t control the True Control Zone.",
    controlZone: "Four Control Zones (typically 4 spaces on each side) in different quadrants of the map, each placed anywhere in their quadrant. The GM secretly designates one Control Zone as the True Control Zone. While inside a Control Zone, PCs may take a full action to determine whether it is the True Control Zone. If there are only PCs within the True Control Zone, they control it; if there are characters from two or more sides within the True Control Zone, it is contested.",
    deployment: "The PCs deploy first, choosing positions for their characters within the Allied Deployment Zone; next, the GM deploys enemy forces in the EDZ."
  }
], require$$14 = [
  {
    id: "sk_act_unseen_or_unheard",
    name: "Act Unseen or Unheard",
    description: "Get somewhere or do something without detection.",
    detail: "Get somewhere or do something without being detected, but not necessarily with speed. Hide, sneak, or move quietly. Infiltrate a facility while avoiding security, patrols, or cameras. Perform a quick action or maneuver without being seen or heard, such as picking a pocket, unholstering your gun, or cheating at cards. Wear a disguise.",
    family: "dex"
  },
  {
    id: "sk_apply_fists_to_faces",
    name: "Apply Fists to Faces",
    description: "Fight in open, brutal unarmed combat.",
    detail: "Punch someone in the face, or alternately fight in open, brutal unarmed combat, whether it’s a fist fight, martial arts duel, or a huge brawl. This is never subtle, never clean, and probably causes a lot of noise.",
    family: "str"
  },
  {
    id: "sk_assault",
    name: "Assault",
    description: "Take part in direct and overt combat.",
    detail: "Take part in direct and overt combat: fighting your way through a building packed with hostile mercenaries, trading shots between rain-slick trenches, fighting in chaotic microgravity as part of a boarding action, or engaging the enemy in the smoking urban rubble of a city under orbital bombardment — When you assault, you’re always assaulting something (a position, a rival pilot, an enemy force, a group of guards), and it’s always loud, open, direct action.",
    family: "str"
  },
  {
    id: "sk_blow_something_up",
    name: "Blow Something Up",
    description: "Use explosives to totally wreck something or turn it into an enormous fireball.",
    detail: "Use explosives (improvised or otherwise), weapons, or maybe just good old fashion brawn to totally wreck something or turn it into an enormous fireball (maybe a wall, sensor array, outpost, reactor core - the good stuff). Probably not to be used against people unless they’re incidentally in the way.",
    family: "str"
  },
  {
    id: "sk_charm",
    name: "Charm",
    description: "Convince a receptive audience or use leverage (money, power, personal benefit) to get your way.",
    detail: "To charm, you need a receptive audience, or some kind of promise of leverage (money, power, personal benefit, etc). You can use it when trying to smooth talk your way past guards, get someone on your side, sway a potential benefactor, talk someone down, perform diplomacy between two parties, or blatantly lie to someone. You can also use it when trying to impersonate someone. Charm won’t work on people that aren’t receptive (such as soldiers you are in a gunfight with) or that you don’t have leverage over (promises of safety, money, power, recompense, help, etc). These promises don’t necessarily have to be true but they have to have some weight with your target.",
    family: "cha"
  },
  {
    id: "sk_get_a_hold_of_something",
    name: "Get a Hold of Something",
    description: "Acquire temporary or permanent allies, assets, or connections through wealth or social influence.",
    detail: "Acquire useful allies, assets, or connections through wealth or social influence. This could be permanent (buying it or receiving it) or temporary (renting or borrowing help or supplies, etc), and might be harder or easier depending on how much you want to use it. This can’t be used for something that’s normally gated by license level (like mech parts) but could be used for aid, supplies, information, food materials, soldiers, or anything else that has more narrative impact. Typically this is acquired by buying it from a market or requisitioning it from a parent organization.",
    family: "cha"
  },
  {
    id: "sk_get_somewhere_quickly",
    name: "Get Somewhere Quickly",
    description: "Get somewhere quickly and without complications.",
    detail: "Get somewhere without complications and with speed, but not necessarily stealth. Climb, swim, or perform acrobatic maneuvers in an attempt to reach a destination faster than the ‘safe’ way. Fall safely from a great height. Move gracefully in zero-g. Chase or flee, outrun, or out pace a target. Get somewhere faster than anyone else. You can also use this when you want to drive or pilot a vehicle.",
    family: "dex"
  },
  {
    id: "sk_hack_or_fix",
    name: "Hack or Fix",
    description: "Repair a device or faulty system; alternatively, hack it wide open, or totally wreck, disable or sabotage it.",
    detail: "Repair a device or faulty system. Alternately, hack it wide open, or totally wreck, disable or sabotage it. You can use this for hacking or safeguarding electronic systems, such as electronic door locks, computer systems, omninet webs, or NHP coffins.",
    family: "int"
  },
  {
    id: "sk_invent_or_create",
    name: "Invent or Create",
    description: "Invent new devices, tools, or approaches to problems.",
    detail: "Generally speaking, you need tools and supplies to invent or create something successfully. Use this with many downtime actions to work on projects. You can also use it in the spur of the moment to invent new devices, tools, or approaches to something (improvised explosives, gear, disguises, or some similar).",
    family: "int"
  },
  {
    id: "sk_investigate",
    name: "Investigate",
    description: "Research a subject, or study something in great detail.",
    detail: "Research a subject, or look at something in great detail. If you can’t find information directly, you learn how you can get access to that information. Learn about a subject of historical relevance, or become well-read on a subject. Investigate a mystery or solve a puzzle. Locate a person or object through research or investigation.",
    family: "int"
  },
  {
    id: "sk_lead_or_inspire",
    name: "Lead or Inspire",
    description: "Give an inspiring speech, or motivate a group of people into action.",
    detail: "Give an inspiring speech, or motivate a group of people into action. Administer or run an organization efficiently or effectively, such as a company, a ship’s crew, a group of colonists or a mining venture. Effectively command a platoon of soldiers in battle, or (perhaps) an entire army.",
    family: "cha"
  },
  {
    id: "sk_patch",
    name: "Patch",
    description: "Apply medical knowledge to medicate or diagnose.",
    detail: "Apply your medical knowledge to administer medication, bandage a wound, staunch bleeding, suture, cauterize, neutralize poison, or resuscitate. Alternately, you could use it to diagnose or study disease, pathogens, or illness.",
    family: "int"
  },
  {
    id: "sk_pull_rank",
    name: "Pull Rank",
    description: "Get information, resources, or aid from a subordinate.",
    detail: "Pull rank on a subordinate, getting information, resources, or aid from them, even unwillingly. You can use this on anyone your social status (noble, celebrity, etc) or military rank would have weight with. Failing this might be risky and could be seen as abusive. You typically can’t pull rank on hostile targets. You could also use this to pretend to have a rank you don’t have, but it’s definitely risky.",
    family: "cha"
  },
  {
    id: "sk_read_a_situation",
    name: "Read a Situation",
    description: "Look for subtext, motives, or threats in a situation or person.",
    detail: "Look for subtext, motive, or threat in a situation or person, often social situations. Use your intuition to learn someone’s motivation, learn who is really in charge, or who is about to do something rash or stupid. Get a gut feeling about a situation or person. Sense if someone is lying to you.",
    family: "int"
  },
  {
    id: "sk_show_off",
    name: "Show Off",
    description: "Do something flashy, cool, or impressive, usually – but not exclusively – with your weapon.",
    detail: "Do something flashy, cool, or impressive, usually (but not exclusively) with your weapon, like shooting a very small or rapidly moving target, shooting someone’s hat off or their weapon out of their hand, knocking someone out by throwing a gun at them, performing an acrobatic flourish with a sword, throwing a spear to pin a fleeing target to the ground, and so on.",
    family: "dex"
  },
  {
    id: "sk_spot",
    name: "Spot",
    description: "Spot details, objects, or people that are hidden or difficult to make out.",
    detail: "Spot hidden or difficult to make out details, objects, or people. Spot ambushes, hidden compartments, or disguised individuals. Spy on a target from a distance, or make out the details, shape, and number of objects, vehicles, mechs, or people clearly at a distance. Track people or vehicles.",
    family: "int"
  },
  {
    id: "sk_stay_cool",
    name: "Stay Cool",
    description: "Perform a task that requires concentration, dexterity, speed, or precision under pressure.",
    detail: "Do something that requires concentration, speed, or intense precision under pressure, like picking a lock as your squad trades fire with encroaching guards, avoiding a hostile memetic code while hacking a secure console, carefully disarming an explosive, or unjamming a gun under fire. If you’ve got to do something complicated in a high stress situation without messing up (and possibly not even breaking a sweat) this is the action to use.",
    family: "dex"
  },
  {
    id: "sk_survive",
    name: "Survive",
    description: "Persevere through harsh, hostile, or unforgiving environments.",
    detail: "Persevere through harsh, hostile, or unforgiving environments, such as the vacuum of space, frozen tundra, a pirate enclave, a crime-ridden colony, untamed wilderness, or scorching desert. You most often use survive when you want to take a journey through wilderness environments, navigate, or avoid natural hazards such as carnivorous wildlife, rockfalls, thin ice, or lava fields. Alternately you could use it to avoid man-made hazards, such as navigating a city safely, or avoiding dangerous areas of a space station. You could also use it when testing personal endurance, such as shaking off poison or alcohol.",
    family: "str"
  },
  {
    id: "sk_take_control",
    name: "Take Control",
    description: "Use force, violence, presence of will, or direct action to take control of something.",
    detail: "Use force, violence, presence of will, or direct action to take control of something. This is often something concrete, like an object someone is holding. You could take control of someone’s gun or a keycard they have on their person. You can additionally can take control of a situation to force those present to listen, calm down, stop moving, or stop what they’re doing (perhaps for their benefit), though you can’t necessarily force them to do anything further without threatening them. Taking control is never subtle.",
    family: "str"
  },
  {
    id: "sk_take_someone_out",
    name: "Take Someone Out",
    description: "Kill or disable someone quickly and quietly.",
    detail: "Kill or disable someone quickly and quietly, from up close and personal or from a distance, probably before they even notice. This is probably a single person but could be two people relatively close together (any more is sort of stretching it and definitely risky). If you’re looking down a sniper scope at a target, preparing to nerve pinch a guard to knock them out instantly, quick-drawing during a gun duel, or dropping from a ceiling to slit a throat, this is the action to use.",
    family: "dex"
  },
  {
    id: "sk_threaten",
    name: "Threaten",
    description: "Use force or threats to make someone do what you want.",
    detail: "Use force or threats of force to get someone to do what you want them to do. Name what you want someone to do and what you’re going to do to them if they don’t listen to you. This could also be blackmail, leverage, or something similarly nasty. Threatening someone can be very high risk but very effective if successful - either way there’s likely no repairing the relationship afterwards. If you threaten someone unsuccessfully, your threats have no further effect on them unless you change something about the situation (as with all other skill checks).",
    family: "str"
  },
  {
    id: "sk_word_on_the_street",
    name: "Word on the Street",
    description: "Get gossip, news, or hearsay from the streets, or from a particular social scene.",
    detail: "Get gossip, news, or hearsay from the streets. What you get depends on what ‘streets’ you are getting word from (high society, low society, hearsay, military chatter, etc). This probably takes a lot less time than investigating something in detail, but the information might be more qualitative or colored by opinion (sometimes that might be useful). You can always learn where the information came from or who to go to next.",
    family: "cha"
  }
], require$$15 = [
  {
    name: "Danger Zone",
    icon: "danger-zone",
    type: "Status",
    terse: "Heat level at half capacity or more",
    exclusive: "Mech",
    effects: "Characters are in the DANGER ZONE when half or more of their heat is filled in. They’re smoking hot, which enables some attacks, talents, and effects."
  },
  {
    name: "Down and Out",
    icon: "downandout",
    type: "Status",
    terse: "Pilot is unconscious, any additional damage kills",
    exclusive: "Pilot",
    effects: "Pilots that are DOWN AND OUT are unconscious and STUNNED – if they take any more damage, they die. They'll regain consciousness and half of their HP when they rest."
  },
  {
    name: "Engaged",
    icon: "engaged",
    type: "Status",
    terse: "Ranged attacks made by an this character receive +1 difficulty. All additional movement is lost if ENGAGED by a target of equal or greater SIZE",
    effects: "If a character moves adjacent to a hostile character, they both gain the ENGAGED status for as long as they remain adjacent to one another. Ranged attacks made by an ENGAGED character receive +1 difficulty. Additionally, characters that become ENGAGED by targets of equal or greater SIZE during the course of a movement stop moving immediately and lose any unused movement."
  },
  {
    name: "Exposed",
    icon: "exposed",
    type: "Status",
    terse: "All kinetic, explosive, or energy damage taken by this character is doubled.",
    exclusive: "Mech",
    effects: "Characters become EXPOSED when they’re dealing with runaway heat buildup – their armor is weakened by overheating, their vents are open, and their weapons are spinning down, providing plenty of weak points. All kinetic, explosive, or energy damage taken by EXPOSED characters is doubled, before applying any reductions. A mech can clear EXPOSED by taking the STABILIZE action."
  },
  {
    name: "Hidden",
    icon: "hidden",
    type: "Status",
    terse: "This character can’t be targeted by hostile attacks or actions, doesn't cause engagement, and enemies only know their approximate location.",
    effects: "HIDDEN characters can’t be targeted by hostile attacks or actions, don’t cause engagement, and enemies only know their approximate location. Attacking, forcing saves, taking reactions, using BOOST, and losing cover all remove HIDDEN after they resolve. Characters can find HIDDEN characters with SEARCH."
  },
  {
    name: "Invisible",
    icon: "invisible",
    type: "Status",
    terse: "All attacks against INVISIBLE characters have a 50 percent chance to miss before an attack roll is made. INVISIBLE characters can always HIDE, even without cover.",
    effects: "All attacks against INVISIBLE characters, regardless of type, have a 50 percent chance to miss outright, before an attack roll is made. Roll a dice or flip a coin to determine if the attack misses.<br>Additionally, INVISIBLE characters can always HIDE, even without cover."
  },
  {
    name: "Prone",
    icon: "prone",
    type: "Status",
    terse: "Attacks against PRONE targets receive +1 accuracy. PRONE characters are SLOWED and count as moving in difficult terrain.",
    effects: "Attacks against PRONE targets receive +1 accuracy.<br>Additionally, PRONE characters are SLOWED and count as moving in difficult terrain. Characters can remove PRONE by standing up instead of taking their standard move, unless they’re IMMOBILIZED. Standing up doesn’t count as movement, so doesn’t trigger OVERWATCH or other effects."
  },
  {
    name: "Shut Down",
    icon: "shut-down",
    type: "Status",
    terse: "While SHUT DOWN, mechs are STUNNED indefinitely.",
    exclusive: "Mech",
    effects: "When a mech is SHUT DOWN:<br>• all heat is cleared and the EXPOSED status is removed;<br>• any cascading NHPs are stabilised and no longer cascading;<br>• any statuses and conditions affecting the mech caused by tech actions, such as LOCK ON, immediately end.<br>SHUT DOWN mechs have IMMUNITY to all tech actions and attacks, including any from allied characters.<br>While SHUT DOWN, mechs are STUNNED indefinitely. Nothing can prevent this condition, and it remains until the mech ceases to be SHUT DOWN."
  },
  {
    name: "Immobilized",
    icon: "immobilized",
    type: "Condition",
    terse: "IMMOBILIZED characters cannot make any voluntary movements",
    effects: "IMMOBILIZED characters cannot make any voluntary movements, although involuntary movements are unaffected."
  },
  {
    name: "Impaired",
    icon: "impaired",
    type: "Condition",
    terse: "IMPAIRED characters receive +1 difficulty on all attacks, saves, and skill checks.",
    effects: "IMPAIRED characters receive +1 difficulty on all attacks, saves, and skill checks."
  },
  {
    name: "Jammed",
    icon: "jammed",
    type: "Condition",
    terse: "JAMMED characters can’t use comms,  make attacks other than IMPROVISED ATTACK, GRAPPLE, and RAM,take reactions, or take or benefit from tech actions",
    effects: "JAMMED characters can’t:<br>• use comms to talk to other characters;<br>• make attacks, other than IMPROVISED ATTACK, GRAPPLE, and RAM;<br>• take reactions, or take or benefit from tech actions."
  },
  {
    name: "Lock On",
    icon: "lock-on",
    type: "Condition",
    terse: "Hostile characters can consume LOCK ON for +1 accuracy on their next attack against this character.",
    effects: "Hostile characters can choose to consume a character’s LOCK ON condition in exchange for +1 accuracy on their next attack against that character.<br>LOCK ON is also required to use some talents and systems."
  },
  {
    name: "Shredded",
    icon: "shredded",
    type: "Condition",
    terse: "SHREDDED characters don’t benefit from ARMOR or RESISTANCE",
    effects: "SHREDDED characters don’t benefit from ARMOR or RESISTANCE."
  },
  {
    name: "Slowed",
    icon: "slow",
    type: "Condition",
    terse: "This character can’t BOOST or make any special moves granted by talents, systems, or weapons.",
    effects: "The only movement SLOWED characters can make is their standard move, on their own turn – they can’t BOOST or make any special moves granted by talents, systems, or weapons."
  },
  {
    name: "Stunned",
    icon: "stunned",
    type: "Condition",
    terse: "STUNNED mechs cannot OVERCHARGE, move, or take any actions.",
    effects: "STUNNED mechs cannot OVERCHARGE, move, or take any actions – including free actions and reactions. Pilots can still MOUNT, DISMOUNT, or EJECT from STUNNED mechs, and can take actions normally.<br>STUNNED mechs have a maximum of 5 EVASION, and automatically fail all HULL and AGILITY checks and saves."
  }
], require$$16 = [
  {
    id: "missing_mechsystem",
    name: "ERR: DATA NOT FOUND",
    sp: 1,
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "COMP/CON is unable to retrieve the data necessary to furnish this System. This is likely the result of a missing or outdated content pack.",
    description: "COMP/CON is unable to retrieve the data necessary to furnish this System. This is likely the result of a missing or outdated content pack.",
    tags: [],
    license_id: ""
  },
  {
    id: "ms_comp_con_class_assistant_unit",
    name: "COMP/CON-Class Assistant Unit",
    type: "AI",
    sp: 2,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_no_cascade"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Your mech has a basic COMP/CON unit, granting it the AI tag. The COMP/CON can speak to you and has a personality, but, unlike an NHP, is not truly capable of independent thought. It is obedient to you alone.<br>You can give control of your mech to its COMP/CON as a protocol, allowing your mech to act independently on your turn with its own set of actions. Unlike other AIs, a mech controlled by a COMP/CON has no independent initiative and requires direct input. Your mech will follow basic courses of action (defend this area, attack this enemy, protect me, etc.) to the best of its ability, or will act to defend itself if its instructions are complete or it receives no further guidance. You can issue new commands at the start of your turn as long as you are within Range 50 and have the means to communicate with your mech. Comp/con units are not true NHPs and thus cannot enter cascade.",
    description: "The GMS Companion/Concierge-Class Assistant Unit conforms to all galaxy-wide standards. These virtual assistants pass even the most rigid Turing-Null assessment criteria and are cleared to operate even in the absence of a pilot.",
    license_id: ""
  },
  {
    id: "ms_custom_paint_job",
    name: "Custom Paint Job",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_indestructible"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "When you take structure damage, roll 1d6. On a 6, you return to 1 HP and ignore the damage – the hit simply ‘scratched your paint’.<br>This system can only be used once before each Full Repair, and is not a valid target for system destruction.",
    license_id: ""
  },
  {
    id: "ms_expanded_compartment",
    name: "Expanded Compartment",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Your mech has space for one additional non-Mech character or object of Size 1/2 to ride as a passenger in the cockpit. While inside the mech, they cannot suffer any effect from outside or be targeted by attacks, as if they were a pilot. You can hand over or take back control to or from them as a protocol (following the same rules as pilot and AIs), but if they take over the controls from you, the mech becomes Impaired and Slowed to reflect the lack of appropriate licenses and integration.",
    license_id: ""
  },
  {
    id: "ms_manipulators",
    name: "Manipulators",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Your mech has an extra set of limbs. They are too small to have any combat benefit, but allow the mech to interact with objects that would otherwise be too small or sensitive (e.g., pilot-sized touch pads).",
    description: "Precise interaction with built and natural environments, soft targets, and hazardous materials is part of the daily routine for support-class mechs. This is made possible by manipulators – added multi-digit “hands” with haptic sensors.",
    license_id: ""
  },
  {
    id: "ms_pattern_a_smoke_charges",
    name: "Pattern-A Smoke Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    actions: [
      {
        name: "Smoke Grenade",
        activation: "Quick",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        detail: "Throw a Smoke Grenade within Range 5. All characters and objects within a Blast 2 area benefit from soft cover until the end of your next turn, at which point the smoke disperses."
      }
    ],
    deployables: [
      {
        name: "Smoke Mine",
        type: "Mine",
        range: [
          {
            type: "Burst",
            val: 3
          }
        ],
        detail: "This mine detonates when any allied character moves over or adjacent to it. All characters and objects within a Burst 3 area benefit from soft cover until the end of the detonating character’s next turn, at which point the smoke disperses."
      }
    ],
    license_id: ""
  },
  {
    id: "ms_pattern_a_jericho_deployable_cover",
    name: "Pattern-A Jericho Deployable Cover",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Deploy two sections of Size 1 hard cover in free spaces adjacent to you and to each other. Each section is an object with 5 Evasion and 10 HP that can be targeted and destroyed individually. Sections of cover can be picked up again as a full action.<br>Repairing the system restores both sections.",
    deployables: [
      {
        name: "Jericho Deployable Cover",
        type: "Deployable",
        instances: 2,
        size: 1,
        hp: 10,
        evasion: 5,
        detail: "Deploy two sections of Size 1 hard cover in free spaces adjacent to you and to each other. Each section is an object with 5 Evasion and 10 HP that can be targeted and destroyed individually. Sections of cover can be picked up again as a full action.<br>Repairing the system restores both sections.",
        recall: "Full",
        redeploy: "Quick"
      }
    ],
    license_id: ""
  },
  {
    id: "ms_pattern_b_hex_charges",
    name: "Pattern-B HEX Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    actions: [
      {
        name: "Frag Grenade",
        activation: "Quick",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Blast",
            val: 1
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "1d6"
          }
        ],
        detail: "Throw a Frag Grenade within Range 5. All characters within a Blast 1 area must pass an Agility save or take 1d6 Explosive damage. On a success, they take half damage."
      }
    ],
    deployables: [
      {
        name: "Explosive Mine",
        type: "Mine",
        range: [
          {
            type: "Burst",
            val: 1
          }
        ],
        activation: "Quick",
        detail: "All characters within a Burst 1 area must pass an Agility save or take 2d6 Explosive damage. On a success, they take half damage."
      }
    ],
    license_id: ""
  },
  {
    id: "ms_personalizations",
    name: "Personalizations",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "You gain +2 HP and, in consultation with the GM, you may establish a minor modification you have made to your mech.<br>This mod has no numerical benefit beyond the additional HP it grants, but could provide other useful effects. If the GM agrees that this mod would help with either a pilot or mech skill check, you gain +1 Accuracy for that check.",
    bonuses: [
      {
        id: "hp",
        val: 2
      }
    ],
    license_id: ""
  },
  {
    id: "ms_stable_structure",
    name: "Stable Structure",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "You gain +1 Accuracy on saves to avoid Prone or Knockback.",
    license_id: ""
  },
  {
    id: "ms_turret_drones",
    name: "Turret Drones",
    type: "Drone",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Expend a charge to deploy a turret drone that attaches to any object or surface within Sensors and line of sight. Gain the Turret Attack reaction, which can be taken once for each deployed turret drone. Turret drones cannot be recalled and expire at the end of the scene.",
    deployables: [
      {
        name: "Turret Drone",
        type: "Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "Gain the Turret Attack reaction, which can be taken once for each deployed turret drone. Turret drones cannot be recalled and expire at the end of the scene.",
        actions: [
          {
            name: "Turret Attack",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "An allied character within Range 10 of a turret drone makes a successful attack.",
            detail: "The turret drone deals 3 Kinetic damage to their target, as long as it has line of sight to their target."
          }
        ]
      }
    ],
    description: "The use of turret drones is a rather traditional form of force multiplication – one that has remained the backbone of defense in many theaters.",
    license_id: ""
  },
  {
    id: "ms_type_3_projected_shield",
    name: "Type-3 Projected Shield",
    type: "Shield",
    sp: 2,
    tags: [
      {
        id: "tg_shield"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    actions: [
      {
        name: "Project Shield",
        activation: "Protocol",
        detail: "Nominate a character within line of sight: all ranged or melee attacks that they make against you or that you make against them gain +2 Difficulty until the start of your next turn."
      }
    ],
    description: "The GMS Type-3 Projected Shield traps and denies incoming projectiles by projecting an aggressive, superpositional anti-ballistic barrier.",
    license_id: ""
  },
  {
    id: "ms_eva_module",
    name: "EVA Module",
    type: "Flight System",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "Your mech has a propulsion system suitable for use in low or zero gravity and underwater environments. In those environments, you can fly and are not Slowed.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "Your mech has a propulsion system suitable for use in low or zero gravity and underwater environments. In those environments, you can fly and are not Slowed."
      }
    ],
    license_id: ""
  },
  {
    id: "ms_rapid_burst_jump_jet_system",
    name: "Rapid Burst Jump Jet System",
    type: "Flight System",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "You can fly when you Boost; however, you must end the movement on the ground or another solid surface, or else immediately begin falling.",
    synergies: [
      {
        locations: [
          "boost"
        ],
        detail: "You can fly when you Boost; however, you must end the movement on the ground or another solid surface, or else immediately begin falling."
      }
    ],
    license_id: ""
  },
  {
    id: "ms_type_i_flight_system",
    name: "Type-I Flight System",
    type: "Flight System",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    effect: "You may choose to count any and all of your movement as flying; however, you take Size +1 Heat at the end of any of your turns in which you fly this way.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "You may choose to count any and all of your movement as flying; however, you take Size +1 Heat at the end of any of your turns in which you fly this way."
      }
    ],
    license_id: ""
  },
  {
    id: "ms_synthetic_muscle_netting",
    name: "Synthetic Muscle Netting",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 1,
    effect: "You may Ram targets larger than you, and when you Grapple or Ram larger targets, you count as the same Size as the largest opponent. When you Grapple or Ram opponents of the same Size or smaller, you count as at least one Size larger. Additionally, your lifting and dragging capacity is doubled.",
    synergies: [
      {
        locations: [
          "ram"
        ],
        detail: "You may Ram targets larger than you, and when you Ram larger targets, you count as the same Size as the largest opponent. When you Ram opponents of the same Size or smaller, you count as at least one Size larger."
      },
      {
        locations: [
          "grapple"
        ],
        detail: "When you Grapple larger targets, you count as the same Size as the largest opponent. When you Grapple opponents of the same Size or smaller, you count as at least one Size larger."
      }
    ],
    description: "IPS-N’s Synthetic Muscle Netting (SMN) is a proprietary, field-proven modification compatible with all existing IPS-N frames. This convenient spray-on catalytic and structural enhancement boosts manipulator and propulsion performance by roughly 25 percent with no demonstrated reduction in operational life. An SMN layer also enhances impact absorption and thermal insulation.<br>IPS-N recommends that pilots apply SMN to internal components only and practice frequent cleaning to prevent septic-analogous decay.",
    license_id: "mf_blackbeard"
  },
  {
    id: "ms_reinforced_cabling",
    name: "Reinforced Cabling",
    sp: 2,
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 3,
    actions: [
      {
        name: "Grapple Swing",
        activation: "Free",
        detail: "1/turn, when making a standard move, you can fly your Speed in a straight line as long as there is a clear path. This move must end on an object or surface, or else you begin falling. As long as you remain stationary, you can secure yourself to the destination surface or object, even if it’s vertical or overhanging. If you are knocked Prone or knocked back while secured to a surface, you fall."
      },
      {
        name: "Drag Down",
        activation: "Quick",
        detail: "Make a contested Hull check against a character within 5 Range and line of sight: the loser is knocked Prone."
      }
    ],
    description: "Reinforced grappling cables allow for full movement and utility in ≤1 g environments. Woven from incredibly strong nanocarbon and arachnosynth threading, reinforced grapple line is carried on waist-mounted spools and attached to charge-actuated brachial projectors. Once fired, the grapples penetrate and anchor to the target. Small meltdown charges seeded every thirty meters of cable both allow rapid disengagement and expose a fresh grapple head, ready for immediate use.",
    license_id: "mf_blackbeard"
  },
  {
    id: "ms_sekhmet_class_nhp",
    name: "SEKHMET-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_ai"
      }
    ],
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 3,
    effect: "Your mech gains the AI tag and the SEKHMET Protocol.",
    actions: [
      {
        name: "SEKHMET Protocol",
        activation: "Protocol",
        detail: "When activated, you give control of your mech to your NHP and gain the following benefits:<ul><li>All melee critical hits deal +1d6 bonus damage.</li><li>1/round, you can Skirmish with melee weapons only as a free action.</li></ul>Your NHP uses all available actions and movement to move toward the closest visible character – allied or hostile – and attacks them with melee attacks, prioritizing melee weapons. It may benefit from your talents. If there are no characters within Threat, your NHP uses all actions to move as directly as possible to the next closest (visible) target. Your NHP can’t make ranged attacks, even if there are actions available.<br>You retain enough control to Overcharge as usual; however, your NHP uses the additional action for the same purpose as its other actions.<br>You can take back control of your mech as a protocol. When you do, you become Stunned until the start of your next turn. Otherwise, this effect lasts until your mech is destroyed – the pilot’s incapacitation or death has no effect."
      }
    ],
    description: "“The IPS-N SEKHMET co-pilot is ready to be your first mate! SEKHMET comes standard with remote, omninet, IR tag, and voice control systems, and is fully compatible with all current and legacy IPS-N mechs.<br>Did you know that SEKHMET learns with you? Should the worst happen, your very own SEKHMET will continue to engage hostile targets using an emulated neural-net doppelgänger to pilot your IPS-N chassis until forced or voluntary shutdown!”<br>draft copy, IPS-N Polaris Pilot Lounge adbroad [struck and replaced w/current adbroad]<br>SEKHMET-class NHPs tend toward aggressive attitudes and dark humor. Pilots often call them “berserker systems” – dangerous NHPs that value combat efficacy over pilot wellbeing.",
    license_id: "mf_blackbeard"
  },
  {
    id: "ms_argonaut_shield",
    name: "Argonaut Shield",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Drake",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "You use the heavy overarm Argonaut Shield to provide cover for an adjacent character as a quick action, giving them Resistance to all damage; however, you take half of the damage your target would take before calculating Armor and Resistance. This effect lasts until your target breaks adjacency, at which point this effect ceases until you repeat this action."
      }
    ],
    description: "In space, simplicity in form and function guarantees reliability and promotes trust. The Argonaut is one of IPS-N’s oldest designs, hailing from the pre-merger days of Northstar’s Deep Black security teams. It’s a simple slab of metal carried in hand or mounted on a chassis’ brachial superstructure; the only option a pilot has for customizing this shield is a choice of size.",
    license_id: "mf_drake"
  },
  {
    id: "ms_aegis_shield_generator",
    name: "Aegis Shield Generator",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_limited",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Drake",
    license_level: 2,
    effect: "Expend a charge to deploy a Size 1 shield generator in a free, adjacent space, where it creates a burst 1 shield.",
    deployables: [
      {
        type: "Deployable",
        name: "Aegis Shield Generator",
        activation: "Quick",
        cost: 1,
        size: 1,
        hp: 10,
        evasion: 5,
        detail: "Set out three d6s to represent the generator’s remaining power. As a reaction when any character or object of your choice at least partly in the area takes damage, you may roll one of the d6s to reduce the damage by the amount rolled.<br>This effect lasts for the rest of the scene, until all dice have been rolled and the generator loses power, or the generator is destroyed.",
        counters: [
          {
            id: "aegis_shield_die",
            name: "Aegis Shield Generator Power",
            default_value: 3,
            min: 0,
            max: 3
          }
        ],
        tags: [
          {
            id: "tg_shield"
          }
        ]
      }
    ],
    description: "The Aegis is a portable electromagnetic shield generator: a powerful and reliable method – if crude by modern standards – for establishing kinetic and coherent-particle deterrence over a wide area.",
    license_id: "mf_drake"
  },
  {
    id: "ms_portable_bunker",
    name: "Portable Bunker",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Drake",
    license_level: 3,
    effect: "Expend a charge to deploy a portable bunker to a free, adjacent area 4 by 4 area. At the start of your next turn, it unfolds into a fortified emplacement.",
    deployables: [
      {
        type: "Deployable",
        name: "Portable Bunker",
        activation: "Quick",
        cost: 1,
        size: 4,
        hp: 40,
        evasion: 5,
        detail: "All characters completely within the bunker's 4x4 area gain hard cover against all attacks from outside the bunker from all directions and Resistance to damage from Blast, Line, Burst, and Cone attacks that originate outside the bunker.<br>The bunker is open topped, and characters may enter or exit at will. It can’t be moved or deactivated once deployed."
      }
    ],
    description: "IPS-N’s “Portable Bunker” is actually a series of single-use expanding printer sheets: flat-pack pouches of inert non-Newtonian fluid that, when deployed, become a rigid structure capable of withstanding incredible force.",
    license_id: "mf_drake"
  },
  {
    id: "ms_cable_winch_system",
    name: "Cable Winch System",
    sp: 1,
    source: "IPS-N",
    license: "Lancaster",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "These cables can be attached to an adjacent character. If the target is Stunned or willing, you automatically succeed; otherwise, they can resist with a successful Hull save. Once attached, you and the target may not move more than 5 spaces away from each other. Either character can tow the other, obeying the normal rules for lifting and dragging, and becoming Slowed while doing so.<br>Any character can remove the cables on a hit with a melee attack or Improvised Attack against Evasion 10.<br>These cables can also be used to drag, pull, or otherwise interact with objects and the environment. They are 5 spaces long and can support a combined Size 6 before they break. Characters can use them to climb surfaces, allowing them to climb without a Speed penalty."
      }
    ],
    description: "A winch system consists of an externally mounted spool of nanocarbon-weave cable and a recovery subroutine installed on the mech.",
    license_id: "mf_lancaster"
  },
  {
    id: "ms_restock_drone",
    name: "Restock Drone",
    type: "Drone",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Lancaster",
    license_level: 1,
    effect: "Expend a charge to deploy a restock drone to any free, adjacent space, where it primes at the end of your turn.",
    deployables: [
      {
        type: "Drone",
        name: "Restock Drone",
        activation: "Quick",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "While adjacent to this drone, allied characters can activate it as a quick action, clearing 1d6 heat and one condition, and reloading one Loading weapon. After being activated, the drone immediately disintegrates.",
        actions: [
          {
            name: "Activate Restock Drone",
            activation: "Quick",
            detail: "Clear 1d6 heat and one condition, and reloading one Loading weapon. After being activated, the drone immediately disintegrates."
          }
        ]
      }
    ],
    description: "Reliable and sturdy drones carrying integrated printers, restock drones allow for limited logistical flexibility via autosalvage. The bulk of a restock drone is made of RawMat, a blend of silicates and metallic materials that the drone processes into replacement parts and repair kits. This is why pilots often joke that restock drones are, simply put, “mech snacks”.",
    license_id: "mf_lancaster"
  },
  {
    id: "ms_mule_harness",
    name: "MULE Harness",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Lancaster",
    license_level: 2,
    effect: "Extra mounts, straps, and hard points allow other characters to climb and ride your mech. Adjacent, non-Immobilized characters can climb onto your mech as a quick action. While riding, they occupy the same space as you, move when you move (even if they’re Slowed), and benefit from soft cover. If you or a rider are knocked Prone, Stunned, Immobilized, or destroyed, they land Prone in adjacent spaces. Riders can climb down as part of any movement away, but can only climb onto your mech as a quick action.<br>You can carry riders of a combined Size equal to your Size, minus Size 1/2 (e.g., if your mech is Size 1 you can carry one Size 1/2 character; if it is Size 2, you can carry a Size 1 character and a Size 1/2 character).",
    description: "The Multiple User, Light Entanglement (MULE) Harness is a mass-produced version of a common battlefield modification that allows friendly soldiers to ride along on a chassis. Some systems are large enough to allow smaller chassis to accompany larger chassis; typically, these variants are employed in high altitude, low orbit insertions where reduced radar presence is required.",
    license_id: "mf_lancaster"
  },
  {
    id: "ms_whitewash_sealant_spray",
    name: "Whitewash Sealant Spray",
    sp: 2,
    source: "IPS-N",
    license: "Lancaster",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "This sealant can be sprayed on characters or free spaces within range 5 and line of sight. It has different effects depending on the target:<ul><li><b>Hostile Characters:</b> Your target must succeed on an Agility save or they become Slowed until the end of their next turn and clear all burn.</li><li><b>Allied Characters:</b> Your target clears all burn but they become Slowed until the end of their next turn.</li><li><b>Free Space:</b> Any fires within blast 1 are extinguished and the area becomes difficult terrain for the rest of the scene.</li></ul>"
      }
    ],
    description: "For fire suppression and fast, temporary seals in punctured starship bulkheads, IPS-N offers a range of single-use, single objective nanites – “whitewash”. This sealant spray can also be used to restrain noncompliant actors when the correct spray heads and catalytic formulations are installed to the applicator.",
    license_id: "mf_lancaster"
  },
  {
    id: "ms_aceso_stabilizer",
    name: "Aceso Stabilizer",
    type: "Shield",
    sp: 3,
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_overshield"
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Lancaster",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "Expend a charge to fire this small, self-arming system onto an allied mech within range 5. They gain Overshield equal to your Grit +4. While they have this Overshield they gain Immunity to Impaired and Jammed."
      }
    ],
    description: "The IPS-N Aceso Stabilizer is a useful triage measure for any scoring and minor mechanical damage that is sustained in the course of combat engagement or negative environmental interaction. Thanks to its negligible processor demand, Aceso Stabilizers can even be controlled by COMP/CON units – this allows the pilot to concentrate on complex repairs or immediate threat neutralization.",
    license_id: "mf_lancaster"
  },
  {
    id: "ms_bulwark_mods",
    name: "Bulwark Mods",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 1,
    effect: "Your mech’s extended limbs, additional armor, redundant motor systems, and other reinforcements allow you to ignore difficult terrain.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "Your mech’s extended limbs, additional armor, redundant motor systems, and other reinforcements allow you to ignore difficult terrain."
      }
    ],
    description: "All proprietary IPS-N mech cores feature their QuickMod system – a modular, legacy-compatible system of joints, hardpoints, and internal slots that makes installing upgrades simple. This proved to be a necessary feature for Albatross maktebas long out of synch with Union Realtime.",
    license_id: "mf_nelson"
  },
  {
    id: "ms_armor_lock_plating",
    name: "Armor-Lock Plating",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 2,
    effect: "You can Brace while Grappling. When you do so, any grapples currently affecting you end.<br>Additionally, when you Brace, you gain the following benefits until the end of your following turn:<ul><li>Attacks against you receive +1 difficulty.</li><li>You can’t fail Agility or Hull saves or contested checks.</li><li>You gain Immunity to Knockback, Grapple, being knocked Prone, and being moved by any external force smaller than Size 5.</li></ul>",
    synergies: [
      {
        locations: [
          "grapple"
        ],
        detail: "You can Brace while Grappling."
      },
      {
        locations: [
          "brace"
        ],
        detail: "When you Brace, you gain the following benefits until the end of your following turn:<ul><li>Attacks against you receive +1 difficulty.</li><li>You can’t fail Agility or Hull saves or contested checks.</li><li>You gain Immunity to Knockback, Grapple, being knocked Prone, and being moved by any external force smaller than Size 5.</li></ul>"
      }
    ],
    description: "IPS-N’s Armor-Lock Plating is a total-body modification that provides additional chassis stability for any situation in which a pilot needs to put their mech through greater-than-anticipated stress.",
    license_id: "mf_nelson"
  },
  {
    id: "ms_ramjet",
    name: "Ramjet",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 3,
    actions: [
      {
        activation: "Protocol",
        detail: "Until the start of your next turn, you can move +2 spaces when you Boost and your melee attacks (including Ram, Grapple, and so on) gain Knockback 2.<br>When you move during this time, you must move your full Speed in a straight line; however, you can stop if you would collide with an obstruction or hostile character, and you can change direction between separate movements (for example, standard moves, Boost, etc)."
      }
    ],
    description: "There’s a threshold that veteran Nelson pilots know well: the point of endless momentum. You get moving fast enough in the right atmosphere and the air itself feeds into auxiliary ports on the chassis, screaming out like a demon’s almighty howl. The point of endless momentum is a giant’s hand on your chest and a god’s chariot under your feet. Makes you feel like you can outrun light itself, as long as you don’t pass out first.",
    license_id: "mf_nelson"
  },
  {
    id: "ms_bb_breach_blast_charges",
    name: "BB Breach/Blast Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 1,
    actions: [
      {
        name: "Thermal Grenade",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Blast",
            val: 1
          }
        ],
        damage: [
          {
            type: "Energy",
            val: "1d6"
          }
        ],
        detail: "Throw a Thermal Grenade within Range 5. All characters within a Blast 1 area must succeed on an Agility save or take 1d6 energy. On a success, they take half damage. Objects and terrain are hit automatically and take 10 AP energy damage."
      }
    ],
    deployables: [
      {
        name: "Breaching Charge",
        type: "Mine",
        detail: "In addition to adjacent free spaces, this mine can also be planted on adjacent walls, pieces of cover, and terrain. Once armed, this mine must be detonated with a quick action. Characters within the affected area must succeed on an Agility save or take 2d6 AP explosive damage. On a success, they take half damage. Objects and terrain are hit automatically and take 30 AP explosive damage.",
        actions: [
          {
            name: "Detonate",
            activation: "Quick",
            detail: "Characters within a Burst 1 area must succeed on an Agility save or take 2d6 AP explosive damage. On a success, they take half damage. Objects and terrain are hit automatically and take 30 AP explosive damage."
          }
        ]
      }
    ],
    description: "Breach/blast charges offer a mil-spec twist on the industrial blasting charges developed by IPS-N for asteroid mining. The IPS-N BB charge features a more volatile blend of high explosives designed to cause massive structural damage to mechanized chassis, starship bulkheads, armored vehicles, bunkers, and other hardened structures.",
    license_id: "mf_raleigh"
  },
  {
    id: "ms_roland_chamber",
    name: "“Roland” Chamber",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 2,
    effect: "When you reload any weapon, your next attack with a Loading weapon gains this effect:<br>On hit: This attack deals +1d6 explosive bonus damage, and targets must succeed on a Hull save or be knocked Prone.",
    description: "Packed into sealed, self-contained cylinders, IPS-N’s “Roland Rounds” are high-explosive anti-armor charges built for kinetic weapons of any mech-scale caliber. Loaded in place of inert kinetic ammunition, a Roland HE/AA shell increases the efficacy and destructive power of any weapon it is fired from.",
    license_id: "mf_raleigh"
  },
  {
    id: "ms_siege_ram",
    name: "Siege Ram",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 1,
    effect: "When you Ram, you deal 2 kinetic damage on hit, and you deal 10 AP kinetic damage when you Ram objects and terrain.",
    synergies: [
      {
        locations: [
          "ram"
        ],
        detail: "When you Ram, you deal 2 kinetic damage on hit, and you deal 10 AP kinetic damage when you Ram objects and terrain."
      }
    ],
    description: "The siege ram is a handheld metal beam with a wedge tip, ready to be smashed into the seams of sealed bulkhead doors and driven home. It’s another holdover from the days before the IPS-N merger. When someone needs to open a bulkhead that’s just slammed shut, it’s what marine pilots pick up to get the job done. Heavy, dumb, and unbreakable: IPS-N’s siege ram is the universal skeleton key.",
    license_id: "mf_tortuga"
  },
  {
    id: "ms_hyperdense_armor",
    name: "HyperDense Armor",
    type: "Shield",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      }
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "When activated, the HyperDense Armor hardens into a shimmering, reflective surface that offers unparalleled protection. You gain Resistance to all damage, Heat and Burn from attacks that originate beyond Range 3; however, you become Slowed and deal half damage, Heat and Burn to characters beyond Range 3."
      },
      {
        name: "Deactivate HyperDense Armor",
        activation: "Quick",
        detail: "Deactivate HyperDense Armor, losing Resistance to all damage, Heat and Burn from attacks that originate beyond Range 3; as well as clearing your Slowed status and dealing normal damage, Heat and Burn to characters beyond Range 3."
      }
    ],
    description: "IPS-N HyperDense Armor is built for space – forged with no regard for any constraints users might face within a gravity well. As such, many pilots protected by HyperDense products are shocked to experience the difference between piloting their mech down a well and taking it for a ride in the null-gravity of space.",
    license_id: "mf_tortuga"
  },
  {
    id: "ms_webjaw_snare",
    name: "Webjaw Snare",
    type: "Deployable",
    sp: 1,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Vlad",
    license_level: 1,
    effect: "Expend a charge to deploy a Webjaw snare to a free, adjacent space, where it arms at the end of your turn.",
    deployables: [
      {
        type: "Deployable",
        name: "Webjaw Snare",
        activation: "Quick",
        size: 1,
        hp: 10,
        evasion: 5,
        detail: "The Webjaw Snare does not obstruct movement, and can’t be attacked until it is triggered.<br>The snare is triggered when any character moves over it. They must succeed on a Hull save or take 1d6 AP kinetic damage and become Immobilized. This effect lasts until the snare is destroyed."
      }
    ],
    description: "Suitable for use in any theater, the IPS-N Webjaw Explosively Accelerated Filament system is a deployable perimeter defense solution designed to arrest hostile movement in predetermined kill-corridors. The Webjaw consists of a networked cluster of single-use anchors, each consisting of a barb, a coil of arachnosynth NoCut filament, and an explosive charge.<br>When triggered remotely, or by a series of programmable physical, electronic, or chemical triggers, the anchors fire, embedding barbs deep inside targets, whether soft or hard. The barbs, secured to anchor points by NoCut filament, clog and restrict movement, fouling gears, wheels, rotors, engines, and all methods of locomotion.",
    license_id: "mf_vlad"
  },
  {
    id: "ms_caltrop_launcher",
    name: "Caltrop Launcher",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "IPS-N",
    license: "Vlad",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "This system blankets a free blast 1 area within range 5 with explosive caltrops. The affected area becomes difficult terrain for the rest of the scene, and mechs take 1d3 AP explosive damage when they enter the affected area for the first time in a round or end their turn within it."
      }
    ],
    description: "Wicked anti-organic, anti-vehicle systems for proximity denial, caltrop launchers fire either great clouds or long swathes of shimmering metal over an area. IPS-N’s HX-CAL caltrop system includes small, shaped explosives in the mix of hardened pyramids.",
    license_id: "mf_vlad"
  },
  {
    id: "ms_charged_stake",
    name: "Charged Stake",
    sp: 2,
    source: "IPS-N",
    license: "Vlad",
    license_level: 3,
    actions: [
      {
        activation: "Full",
        detail: "This system fires a charged stake at a character adjacent to you. Your target must succeed on a Hull save or be impaled by the stake, taking<br>1d6 AP energy damage and becoming Immobilized while impaled. At the end of each of their turns, an impaled character takes 1d6 AP energy damage. An impaled character can successfully repeat this save as a full action to remove the stake and free themselves, which is the only way to end the immobilization.<br>You can only affect one character with the stake at a time."
      }
    ],
    description: "Descended from blast-mining tools, this enormous, improvised system is housed and prepped to fire in a specially primed chamber. It first penetrates and immobilizes armored targets, then sends a powerful, vaporizing charge into vulnerable internal systems.",
    license_id: "mf_vlad"
  },
  {
    id: "ms_ferrous_lash",
    name: "Ferrous Lash",
    sp: 2,
    source: "SSC",
    license: "Black Witch",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "Choose a character within range 8 and line of sight. If they are allied, you may pull them 5 spaces in any direction; if they are hostile, they must succeed on an Agility save or be pulled 5 spaces in a direction of your choice. This movement ignores engagement and doesn’t provoke reactions.<br>If a hostile target moved by this system collides with an obstruction or another mech, they stop moving and are knocked Prone."
      }
    ],
    description: "Initially developed as a nonlethal crowd-suppression device, the Ferrous Lash is a far more complex and dangerous device in the hands of the right pilot. The Lash consists of a series of integrated launchers that detonate payloads of fast-congealing ferrofluids that restrain their targets. Tuned to the correct frequency, these proprietary ferrofluid blends form into rudimentary ambulatory segments, pulling their hosts back towards the one wielding the Lash.",
    license_id: "mf_black_witch"
  },
  {
    id: "ms_iceout_drone",
    name: "ICEOUT Drone",
    type: "Drone",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Black Witch",
    license_level: 2,
    effect: "Expend a charge to deploy an ICEOUT drone to a free space within Sensors and line of sight, where it hovers in place and generates a burst 1 field.",
    deployables: [
      {
        type: "Drone",
        name: "ICEOUT Drone",
        activation: "Quick",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "Characters at least partially within the ICEOUT drone's Burst 1 area gain Immunity to all tech actions, and can’t make tech actions. Existing conditions and effects caused by tech actions are not cleared but characters have Immunity to them while they are in the area, and they can be saved against normally.<br>The ICEOUT drone can be moved to any point within Sensors as a quick action. It cannot be recalled and expires at the end of the scene.",
        actions: [
          {
            name: "Move ICEOUT Drone",
            activation: "Quick",
            detail: "The ICEOUT drone can be moved to any point within Sensors."
          }
        ]
      }
    ],
    description: "SSC’s ICEOUT drone is a response to increasing reliance on hostile system scans for accurate targeting. By blanketing a mech’s systems in layers of digital defilade, mirroring, spoofing, and redirection, an ICEOUT drone can effectively disappear or disincorporate it from hostile scans. ICEOUT drones only make their operator system-invisible, however; they remain visible with optics.",
    license_id: "mf_black_witch"
  },
  {
    id: "ms_perimeter_command_plate",
    name: "Perimeter Command Plate",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Black Witch",
    license_level: 2,
    effect: "This heavy metal Perimeter Command Plate (PCP) can be flash-printed and deployed to a free 2x2 space within range 5. The PCP is flat, doesn’t obstruct movement, and lasts for the rest of the scene. If you create a new PCP, the old one disintegrates.",
    deployables: [
      {
        name: "Perimeter Command Plate",
        type: "Deployable",
        size: 2,
        hp: 20,
        evasion: 5,
        detail: "The plate activates for a character the first time that character enters its space during a round, or if they end their turn there.<br>Upon printing, choose a setting:<ul><li><b>Repulse:</b> Hostile characters that move onto the PCP must succeed on a Hull save or be pushed 3 spaces in the direction of your choice. If this causes them to collide with an obstruction, they are knocked Prone. Allied characters that enter the space may immediately fly 3 spaces in any direction as a free action.</li><li><b>Attract:</b> Characters that move onto the PCP must succeed on a Hull save or become Immobilized. They can clear Immobilized by successfully repeating the save as a quick action; it is also cleared if the PCP is destroyed."
      }
    ],
    description: "The Exotic Materials Group developed the Perimeter Command Plate to extend the area of the Black Witch’s zone of control. Utilizing single-pattern flash printers, the Black Witch prints a broad, circular plate seeded with electromagnetic projectors. Although the plates are intended to be disposable, Black Witch pilots often grow attached to their “familiars” and request their flash-printers create personalized plates.",
    license_id: "mf_black_witch"
  },
  {
    id: "ms_black_ice_module",
    name: "Black ICE Module",
    type: "Tech",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Black Witch",
    license_level: 3,
    effect: "Tech attacks against you or adjacent allied characters receive +1 difficulty. Each subsequent tech attack against you or an adjacent allied character receives an additional +1 difficulty, to a maximum of +3 difficulty.<br>Your Black ICE definitions roll over – resetting to +1 difficulty – when it would increase to +4 difficulty or at the end of the scene. Allied characters lose this benefit when they break adjacency.",
    description: "Black ICE modules are defensive systems packaged standard with the Black Witch fleets used by SSC's own internal security forces. They project a bubble of WHITECELL code that analyzes incoming hostile script and structures inoculants for friendly systems on the fly.",
    counters: [
      {
        id: "ctr_black_ice_module",
        name: "Black ICE Module",
        default_value: 1,
        min: 1,
        max: 3
      }
    ],
    license_id: "mf_black_witch"
  },
  {
    id: "ms_magnetic_shield",
    name: "Magnetic Shield",
    type: "Shield",
    sp: 2,
    tags: [
      {
        id: "tg_shield"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Black Witch",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "This system creates a line 4 forcefield, 4 spaces high – with at least 1 space adjacent to you – that is an obstruction for mechs and characters made at least partly of metal. It lasts for the rest of the scene and if a new one is placed, the old one deactivates.<br>The forcefield doesn’t block line of sight, but it provides soft cover. Characters gain Resistance to kinetic and explosive damage while benefiting from this cover."
      }
    ],
    description: "SSC’s magnetic shield takes the same technology as their proprietary magnetic buckler and applies it to a massive field-projection system.",
    license_id: "mf_black_witch"
  },
  {
    id: "ms_high_stress_mag_clamps",
    name: "High-Stress Mag Clamps",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Death’s Head",
    license_level: 1,
    effect: "You treat all solid surfaces as flat ground for the purposes of movement; you can move across them normally instead of climbing, although you begin to fall if you are knocked Prone.",
    synergies: [
      {
        locations: [
          "move"
        ],
        detail: "You treat all solid surfaces as flat ground for the purposes of movement; you can move across them normally instead of climbing, although you begin to fall if you are knocked Prone."
      }
    ],
    description: "A simple, reliable set of toggleable mag clamps built into a mech’s locomotive system can vastly increase the tactical possibilities open to its pilot. When switched on, these clamps allow a mech to cling to ferrous surfaces, which is especially useful in low- and zero-gravity environments.",
    license_id: "mf_deaths_head"
  },
  {
    id: "ms_tracking_bug",
    name: "Tracking Bug",
    type: "Tech",
    sp: 2,
    source: "SSC",
    license: "Death’s Head",
    license_level: 1,
    actions: [
      {
        activation: "Quick Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a character within Sensors. On a hit, you know their exact location, HP, Structure, and Speed for the duration. They can’t Hide and you ignore their Invisible status. To remove the tracking drone, they must succeed on an Engineering check as a quick action; otherwise it deactivates at the end of the scene."
      }
    ],
    description: "Tracking bugs are specialized tracer rounds – essentially, drones too large to be classified as nanites, and far too small to fit the Union-standard parameters of a drone. Fired from dedicated launchers, tracking bugs guide themselves toward their designated target. Following successful penetration of the target, they surreptitiously and continuously feed live data back to their registered user.",
    license_id: "mf_deaths_head"
  },
  {
    id: "ms_core_siphon",
    name: "Core Siphon",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Death’s Head",
    license_level: 2,
    actions: [
      {
        activation: "Protocol",
        detail: "When you activate this protocol, you gain +1 accuracy on your first attack roll this turn, but receive +1 difficulty on all other attack rolls until the end of the turn."
      }
    ],
    description: "By shunting excess heat to offensive systems, core siphons allow pilots to overclock the targeting, catalytic, and processing capabilities of their weapons. This comes at a cost, however – reliance on overclocking without sufficient cooling can damage systems not built to handle the influx of power.",
    license_id: "mf_deaths_head"
  },
  {
    id: "ms_kinetic_compensator",
    name: "Kinetic Compensator",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Death’s Head",
    license_level: 3,
    effect: "When you miss with a ranged attack roll, your next ranged attack roll gains +1 accuracy.",
    synergies: [
      {
        locations: [
          "weapon"
        ],
        weapon_types: [
          "Rifle",
          "Cannon",
          "Launcher",
          "CQB",
          "Nexus"
        ],
        detail: "When you miss with a ranged attack roll, your next ranged attack roll gains +1 accuracy."
      }
    ],
    description: "Kinetic compensators are popular enhancements, providing a subsurface framework of electronically modulated gyroscopes and hydraulic compensators that work in concert to absorb and disperse recoil caused by firing heavy weapons.",
    license_id: "mf_deaths_head"
  },
  {
    id: "ms_neurospike",
    name: "Neurospike",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 1,
    actions: [
      {
        name: "Shrike Code",
        activation: "Invade",
        detail: "Until the end of the target’s next turn, they first take 2 heat whenever they attack."
      },
      {
        name: "Mirage",
        activation: "Invade",
        detail: "Choose yourself or an allied character: your systems relay blurred, illusory images over their actual silhouette. Your target treats you, or the character you chose, as Invisible until the end of their next turn."
      }
    ],
    description: "“Somehow it got inside my cockpit. There were hands – cold hands – around my neck, fingers in my mouth, worming under my hardsuit. No one else could have been in there with me and yet, someone was. I couldn't even scream, it held my tongue in a fist and it squeezed, and it whispered its name to me, and it said nothing I could understand. I have never felt more alone – it was just me and… it. Alone in the universe, forever.”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "ms_flicker_field_projector",
    name: "Flicker Field Projector",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 2,
    effect: "Whenever you Boost or make a standard move, you project a holographic pattern around you, leaving dazzling afterimages that make it hard to discern your precise location: you count as Invisible the next time you’re attacked. You can only benefit from one instance of this effect at a time.",
    synergies: [
      {
        locations: [
          "move",
          "boost"
        ],
        detail: "Whenever you Boost or make a standard move, you project a holographic pattern around you, leaving dazzling afterimages that make it hard to discern your precise location: you count as Invisible the next time you’re attacked. You can only benefit from one instance of this effect at a time."
      }
    ],
    description: "“I saw myself over and over and over and over and over and over and over and–”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "ms_stuncrown",
    name: "StunCrown",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "Expend a charge to create a burst 3 flash of light. All hostile characters within the affected area that have line of sight to you must succeed on an Agility save or become Jammed, and a Systems save or become Impaired. These effects last until the end of their next turn.<br>Characters in cover from you are not affected by this system."
      }
    ],
    description: "“Many things happened the moment I think I died.”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "ms_oasis_wall",
    name: "OASIS Wall",
    type: "Shield",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 3,
    actions: [
      {
        activation: "Protocol",
        detail: "Until the start of your next turn, you can only move in straight lines; however, you create a holographic trail behind you as you move, creating a light barrier made of contiguous sections the same Size as your mech (Size 1 for Size 0.5 Mechs) in each space you move through. This barrier grants hard cover to adjacent characters, and characters that benefit from this cover also gain Resistance to energy.<br>The barrier doesn’t count as an obstruction and has Immunity to all damage. Characters may freely pass through it but not end their turns inside it, and any character that would be involuntarily moved inside the barrier stops moving if they would end their movement inside it. It lasts for the rest of the scene or until you next use this system."
      }
    ],
    description: "“Inside? What did I see inside? You think I escaped? That this is all real? No, I– I never left. I’m still there. Something is wrong. Something is not right.”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "ms_flash_charges",
    name: "Flash Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 1,
    actions: [
      {
        name: "Flash Grenade",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Blast",
            val: 3
          }
        ],
        detail: "Throw a Flash Grenade within Range 5. Until the end of your next turn, this grenade creates a Blast 3 zone of blinding light and sparks. While characters other than you are at least partly inside the area, they can’t draw line of sight out of the area. Characters fully outside of the area or that exit the area are unaffected unless they move into it."
      }
    ],
    deployables: [
      {
        name: "Flash Mine",
        type: "Mine",
        range: [
          {
            type: "Burst",
            val: 1
          }
        ],
        detail: "This mine detonates in a Burst 1 area when a character moves adjacent to or over it. Characters within the affected area must succeed on an Agility save or they only have line of sight to adjacent spaces until the end of their next turn."
      }
    ],
    description: "Produced by Smith-Shimano’s BELLA CIAO workshop, Flash Charges are popular advantage multipliers, their flash bright enough to destabilize visible-light optics, laser communications, and infra-red sensor suites.",
    license_id: "mf_metalmark"
  },
  {
    id: "ms_reactive_weave",
    name: "Reactive Weave",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 1,
    effect: "When you Brace, you become Invisible until the end of your next turn and may immediately move spaces equal to your Speed.",
    synergies: [
      {
        locations: [
          "Brace"
        ],
        detail: "When you Brace, you become Invisible until the end of your next turn and may immediately move spaces equal to your Speed."
      }
    ],
    description: "Composed of woven covers for critical joints and systems, reactive weave not only protects these sensitive components from fouling and poor weather, but provides a surface for the application of SSC’s unique loomware technology. Reactive weave is powered, making it capable of free-flexing to augment mobility and reduce the stress placed on a mech’s joints.",
    license_id: "mf_metalmark"
  },
  {
    id: "ms_active_camouflage",
    name: "Active Camouflage",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 3,
    actions: [
      {
        activation: "Protocol",
        detail: "You become Invisible until you take damage, or until the end of your next turn."
      }
    ],
    description: "Active camouflage is the pinnacle of counter-optic defense systems. Active camouflage systems continuously interpret incoming visible-light data, allowing them to project light-bending fields around their user and effectively hiding them in plain sight.",
    license_id: "mf_metalmark"
  },
  {
    id: "ms_javelin_rockets",
    name: "Javelin Rockets",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "Choose 3 free spaces within range 15 and line of sight that aren’t adjacent to each other. All characters know which spaces you have chosen. You fire a volley of auto-targeting rockets into the air: until the start of your next turn, when a character moves into or passes above a chosen space – no more than 10 spaces up – they are hit by a rocket, taking 3 kinetic damage. Each space can be triggered once and then the effect disappears on that space."
      }
    ],
    description: "“Pralaya was the name of your mother. She who would see the dawn-at-the-end. Her beauty was terrible, and her wrath, and I see it in all of you. My sons, when you hear the sound of thunder – that is your mother’s voice, and the rain of missiles her gift.” — “Notes for Young John”, Ministrations of the Master Teacher",
    license_id: "mf_monarch"
  },
  {
    id: "ms_tlaloc_class_nhp",
    name: "TLALOC-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 3,
    effect: "Your mech gains the AI tag and the TLALOC Protocol.",
    actions: [
      {
        name: "TLALOC Protocol",
        activation: "Protocol",
        detail: "Your NHP can rapidly fire and retarget your weapons – far faster than thought. You become Immobilized until the start of your next turn; however, during this time, you may reroll each missed melee or ranged attack roll once, choosing a new target within the attack’s Range. If the attack was part of an area of effect, it must target a character in the same area. Any given target can't be hit more than once as part of the same action."
      }
    ],
    description: "TLALOC-Class NHPs provide advanced multi-system targeting and co-pilot functions, taking over subroutine control to ensure persistent lock-on and engagement. With TLALOC installed and operational, a pilot can trust that their back is always covered, and every possible advantage exploited.<br>TLALOC clones are often stereotyped as hasty and impetuous, and they are well-known for having superiority complexes. Despite this, they are some of the most stable NHP clones. Leading subjectivity theorists suggest that the wide portfolio of control and sense of domination given to TLALOC units encourages a sense of contentment with their work and subjectivity parameters – as a result, they have a much longer cascade window. Thus far, this theory is consistently reproducible across all TLALOC units, although there is no similar correlation among other mil-spec NHP lines.",
    license_id: "mf_monarch"
  },
  {
    id: "ms_hunter_logic_suite",
    name: "Hunter Logic Suite",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 2,
    actions: [
      {
        name: "Stalk Prey",
        activation: "Invade",
        detail: "You infect the target with a viral logic that wipes your image from their sensors. They treat you as Invisible until you next take damage from them. This can only affect one target at a time."
      },
      {
        name: "Terrify",
        activation: "Invade",
        detail: "You infect the target with a viral logic that makes your mech appear horrifying. Until the end of their next turn, they become Impaired and cannot make any voluntary movements that bring them closer to you."
      }
    ],
    description: "Built from interpreted strands of DHIYED paracode, SSC’s Hunter Logic is an agile computational memetic: a dual synthetic/VLS-vector systemic weapon capable of interfering with both a target’s computer and its crew.",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "ms_singularity_motivator",
    name: "Singularity Motivator",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 2,
    actions: [
      {
        name: "Exposed Singularity",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "Your mech takes damage.",
        detail: "You may immediately teleport to a free space within 1d6 spaces."
      }
    ],
    description: "This unique gravitic power plant was first developed by SSC’s Exotic Materials Group for the first-generation Mourning Cloak. For subsequent models, engineers devised a system that allows pilots to – for a moment – open the grav containment system’s aperture, exposing a slice of naked singularity to realspace.<br>A naked singularity is difficult to perceive for both organics and synthetics, being similar to the heart of a black hole. The sudden exposure essentially removes the mech and its pilot from realtime. The user experiences around 10 seconds of subjective time – a brief window, in which they can act independently of local realtime.<br>SSC recommends against abuse of this system, as the effects of long-term exposure to local sidereal time are still unknown.",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "ms_fade_cloak",
    name: "FADE Cloak",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "When activated, you immediately move out of phase with realspace, becoming intangible. While intangible, you may move through obstructions, but not end your turn within them. You cannot interact with any other object or character or be interacted with in any way (e.g., taking or dealing damage).<br>Roll 1d6 at the start of each of your turns: on 3 or less, you return to realspace until the start of your next turn; on 4+, you remain intangible.<br>This system remains active for the rest of the scene, or until you deactivate it as a quick action."
      }
    ],
    description: "Representing SSC’s first successful manipulation of the “Firmament”, Firmament Affinity/Directed Entropy (FADE) cloaks must be fabricated according to the unique affinity signature of requisitioning pilots. They are rough tools: artificial affinity amplifiers that allow operators to access shallow layers of the Firmament, and thus “shimmer” – nudging their physical bodies between the causal and paracausal. The cloak enhances this effect by extruding a semiorganic membrane that wraps around the mech to provide an additional layer of protection.<br>At present, the long-term effects of affinity amplification on organic matter are unknown; before receiving clearance to operate a FADE cloak, pilots must agree to check in with their SSC personal concierge on a regular schedule. These check-ins include regular deposits of genetic material.",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "ms_lotus_projector",
    name: "Lotus Projector",
    type: "Drone",
    sp: 2,
    tags: [
      {
        id: "tg_invisible"
      }
    ],
    source: "SSC",
    license: "Swallowtail",
    license_level: 1,
    effect: "This scout drone can be deployed to a space within Sensors and line of sight, where it emits a Burst 2 field with the following effects:<ul><li>You know the current location, HP, Evasion, E-Defense, and Heat of all characters within the affected area.</li><li>Hostile characters cannot Hide in the area, and if they end their turn in the affected area they cease to be Hidden.</li><li>Hostile characters can’t benefit from being Invisible while in the affected area.</li></ul>You can recall and redeploy your scout drone as a quick action.",
    deployables: [
      {
        type: "Drone",
        name: "Lotus Projector",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        recall: "Quick",
        redeploy: "Quick",
        detail: "This scout drone can be deployed to a space within Sensors and line of sight, where it emits a Burst 2 field with the following effects:<ul><li>You know the current location, HP, Evasion, E-Defense, and Heat of all characters within the affected area.</li><li>Hostile characters cannot Hide in the area, and if they end their turn in the affected area they cease to be Hidden.</li><li>Hostile characters can’t benefit from being Invisible while in the affected area.</li></ul>You can recall and redeploy your scout drone as a quick action."
      }
    ],
    description: "Mech-mounted Lotus Projectors are designed to launch small, actively camouflaged scout drones. The projector fires the single-use drones at subsonic speeds in bursts of ten, blanketing a wide area in order to relay information about terrain and targets within.",
    license_id: "mf_swallowtail"
  },
  {
    id: "ms_markerlight",
    name: "Markerlight",
    type: "Tech",
    sp: 2,
    source: "SSC",
    license: "Swallowtail",
    license_level: 1,
    actions: [
      {
        activation: "Full Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a character within Sensors and line of sight. On a success, they take 2 heat, Lock On, and cannot benefit from soft cover until the Lock On is cleared; additionally, once before the start of your next turn, when an allied character hits your target, you may declare as a reaction that they have hit a weak spot. If it wasn’t already, the attack becomes a critical hit."
      }
    ],
    description: "“Out, damned spot! Out, I say! – One, two. Why, then, ‘tis time to do’t. Hell is murky! – Fie, my lord, fie! A soldier, and afeard? What need we fear who knows it, when none can call our power to account?”<ul><li>Shakespeare, Macbeth, act 5, sc. 1.</li></ul>",
    license_id: "mf_swallowtail"
  },
  {
    id: "ms_retractable_profile",
    name: "Retractable Profile",
    type: "Tech",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Swallowtail",
    license_level: 2,
    actions: [
      {
        activation: "Protocol",
        detail: "Your mech can retract its major systems to reduce its profile. While active:<ul><li>rolls to locate you receive +1 difficulty while you are Hidden;</li><li>ranged and tech attacks against you receive +1 difficulty;</li><li>you become Slowed and can’t make attacks of any kind;</li><li>you may take other actions (e.g., Hide, Activate, and so on).</li></ul>You may end this effect as a quick action."
      }
    ],
    description: "The hallmark of a well thought out mech frame is the opportunity for pilots to adapt their stock models to the specifications of the environments in which they operate. A retractable profile enables on-the-fly removal of extraneous protrusions, tuning of broadcast software, and masking of heat signatures – all serving to reduce optical and scanner signatures.",
    license_id: "mf_swallowtail"
  },
  {
    id: "ms_athena_class_nhp",
    name: "ATHENA-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "SSC",
    license: "Swallowtail",
    license_level: 3,
    effect: "Your mech gains the AI tag and Simulacrum.",
    actions: [
      {
        name: "Simulacrum",
        activation: "Quick",
        detail: "ATHENA constructs a perfect, real-time, and fully interactive 3D model of a blast 3 area within range 50, including moving characters, all rendered in lovingly extreme detail. The following effects apply:<ul><li>You have full visibility within the affected area, but it doesn’t count as line of sight.</li><li>You know all statistics, weapons, and systems of characters within the affected area.</li><li>Hostile characters within the affected area don’t benefit from cover and can’t Hide or become Invisible.</li><li>Hostile characters that end their turn in the affected area receive Lock On and cease to be Invisible or Hidden.</li></ul>ATHENA’s simulation lasts until the end of the scene, or about 30 minutes within the narrative. You may target a new area as a quick action."
      }
    ],
    description: "Smith-Shimano’s ATHENA is the pinnacle of total hyperspectral environmental facsimiles. Through a combination of unfettered omninet access, hyperspectral relays fired out from a Cloudscout TACSIM projector, sub-networked squadmates, and active/hostile intrusion protocols, ATHENA bootstraps a near-flawless reconstruction of the immediate environment around its host core. ATHENA is unparalleled in its processing power, and with this reconstructed environment, it provides trustworthy, accurate advice to pilots in need of strategic counsel.<br>ATHENA clones tend to be patient, cautious, and measured in their relations with their pilots.",
    license_id: "mf_swallowtail"
  },
  {
    id: "ms_lb_oc_cloaking_field",
    name: "LB/OC Cloaking Field",
    sp: 4,
    tags: [
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Swallowtail",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "You become Slowed, but your Mech and all allied characters within a burst 2 area become Invisible as long as they remain completely inside the area. This effect lasts until the end of your next turn, or until you are Stunned, take damage, or deactivate it as a quick action."
      }
    ],
    description: "SSC’s mil-spec cloaking field is the result of extensive experimentation in cooling and light-reflecting sciences. Born from a need to reflect harmful radiation away from ships and EVA modules in deep space, the Lightbend/Overcloak (LB/OC) cloaking field is often used by rangers and long-patrol scout pilots to ensure not only radiation protection, but optical concealment as well. The light- and radiation-bending properties of the LB/OC conceals anything inside of its projected bubble from sensor suites and optical spotting.",
    license_id: "mf_swallowtail"
  },
  {
    id: "ms_hive_drone",
    name: "Hive Drone",
    type: "Drone",
    sp: 2,
    source: "HORUS",
    license: "Balor",
    license_level: 1,
    effect: "This hive drone can be deployed to a free space within Sensors and line of sight, where it releases a burst 2 greywash swarm with the following effects:<ul><li>Allied characters at least partially within the affected area gain soft cover, as does the hive drone.</li><li>Hostile characters take 1 AP kinetic damage when they start their turn in the affected area or enter it for the first time in a round. Damage from areas created by multiple hive drones does not stack.</li></ul>The drone can be deployed to a different space or recalled as a quick action.",
    deployables: [
      {
        type: "Drone",
        name: "Hive Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        recall: "Quick",
        redeploy: "Quick",
        detail: "This hive drone can be deployed to a free space within Sensors and line of sight, where it releases a burst 2 greywash swarm with the following effects:<ul><li>Allied characters at least partially within the affected area gain soft cover, as does the hive drone.</li><li>Hostile characters take 1 AP kinetic damage when they start their turn in the affected area or enter it for the first time in a round. Damage from areas created by multiple hive drones does not stack.</li></ul>The drone can be deployed to a different space or recalled as a quick action."
      }
    ],
    description: "It looks, at first, like a roiling cloud of gray fog, churning and fizzing – smoking soda water spilled across concrete. It advances with curious motion, stretching and snapping back. A confusion of snakes, writhing forward with speed that betrays intent.<br>Color flashes across the gray cloud, a swarm-luminescence – the light created by millions of nanites glowing with heat as they consume whatever they cross.<br>This is greywash, and it is never sated.",
    license_id: "mf_balor"
  },
  {
    id: "ms_scanner_swarm",
    name: "Scanner Swarm",
    type: "Tech",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Balor",
    license_level: 1,
    effect: "You gain +1 accuracy on tech attacks against adjacent characters.",
    description: "HORUS-coded scanner swarms establish oculus-form nanite protocols around defined objects or areas, ensuring constant circulation and data capture. The nanites ingest and process full-spectrum information, relaying it back to their pilot/parent in return for an endorphic code-impulse that prompts continued scanning.",
    license_id: "mf_balor"
  },
  {
    id: "ms_swarm_body",
    name: "Swarm Body",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Balor",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "After activating this system, a burst 1 swarm is released at the end of your turn. Characters of your choice that start their turn in the area or enter it on their turn must succeed on a Systems save or take 3 kinetic. This amount increases by +3 damage for each of your turns that you have remained stationary, up to a maximum of 9 kinetic.<br>This effect lasts until you move, including involuntary movement."
      }
    ],
    description: "What must it have been like for him? For the man who called himself Maw? For all of his followers? Certainly they had families before. Memories. Loves. Fears. Private thoughts. All gone. All of their bodies shattered. All of their minds spread across a billion lesser forms. Translated from the singular – all of its imperfections and lesser-lesser-thans – to become as air, and the clouds that fill it, and the wind that shapes the world.",
    license_id: "mf_balor"
  },
  {
    id: "ms_h0r_os_system_upgrade_i",
    name: "H0R_OS System Upgrade I",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 1,
    actions: [
      {
        name: "Puppet System",
        activation: "Invade",
        detail: "Your target moves its maximum Speed in a direction of your choice. They can be moved into hazardous areas and other obstacles, but are still affected by difficult terrain, obstructions, and so on. This movement is involuntary, but provokes reactions and Engagement as normal and doesn’t count as Knockback, pushing, or pulling."
      },
      {
        name: "Eject Power Cores",
        activation: "Invade",
        detail: "Your target becomes Jammed until the end of their next turn as you temporarily disrupt their systems, ejecting ammo magazines and cooling rods. Characters adjacent to your target take 2 energy damage. This can only be used 1/scene on each character."
      }
    ],
    description: "This system upgrade appears to add auxiliary INSTINCT systems that are capable of autonomous operation independent of the base INSTINCT rig, increasing the efficacy of systemic invasion attempts. Pilots report unnerving low-frequency humming when this tech is installed without the parent rig.",
    license_id: "mf_goblin"
  },
  {
    id: "ms_metahook",
    name: "Metahook",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 2,
    actions: [
      {
        activation: "Quick Tech",
        detail: "Choose an allied character within Sensors and line of sight. You link systems with them, lasting as long as they are within Sensors and line of sight. While linked, you may use their Sensors and line of sight for tech actions, and they may use your Systems to make skill checks and saves; however, any time either character takes heat or a condition, it is also taken by the other character. You can only link systems with one character at a time."
      }
    ],
    description: "The metahook is a key component of the Goblin’s recursive processing weave, allowing it to generate and output massive amounts of weaponized code. These broadcasts can be “sharpened” or “softened” in response to directives from a pilot or an INSTINCT system. To “soften” code, the metahook dips into its pilot’s subjectivity and blankets an ally in wave after wave of empathetic shielding. This spreading of melded code and qualia acts as a powerful shielding agent against systemic attacks; however, feedback is common and dangerous to both parties.",
    license_id: "mf_goblin"
  },
  {
    id: "ms_h0r_os_system_upgrade_ii",
    name: "H0R_OS System Upgrade II",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 2,
    actions: [
      {
        name: "Construct Other: Ideal Image",
        activation: "Quick Tech",
        detail: "You create a data construct in a free adjacent space – a Size 2 object that can look like almost anything and that appears real to all systems. The construct provides hard cover, blocks line of sight, and has Immunity to all damage. Characters treat it as an obstruction and so cannot voluntarily move into it; however, if a character attempts to stand on it or is involuntarily moved into its area, it dissipates and is immediately destroyed. It lasts for the rest of the scene, or until destroyed by an adjacent character with a successful Systems skill check as a full action. If you create a second construct, the previous one disappears."
      },
      {
        name: "Construct Other: False Idol",
        activation: "Quick Tech",
        detail: "Choose a free space within Sensors and a target – either yourself or an allied character within Sensors. You create a false idol – an illusory decoy of your target – in the chosen space. Before attempting to take any hostile actions against your target, characters with line of sight to the false idol must make a Systems save. On a failure, they don’t lose the action, but cannot target the original character and believe the false idol is real instead until the end of their next turn.<br>The false idol is the same Size as your target, can benefit from cover, and has Evasion 10, E-Defense 10, and 1 HP. It disappears if it takes heat or damage, or at the end of the scene. If you create a second idol, the previous one disappears."
      }
    ],
    description: "H0r_OS II builds further on the framework established by H0R_OS I, enabling the now-autonomous program to manifest an “Other” – a wholly new being constructed from aggregate user and environmental data. Others may be adapted to resemble a person, an object, or even a physical phenomenon. While the simulacrum isn’t perfect, it’s good enough to confuse systems and most observers on a first look.",
    license_id: "mf_goblin"
  },
  {
    id: "ms_osiris_class_nhp",
    name: "OSIRIS-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_round",
        val: 1
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 3,
    effect: "Your mech gains the AI tag and and can perform the Hurl Into the Duat QUICK TECH option.",
    actions: [
      {
        name: "Hurl Into the Duat",
        activation: "Quick Tech",
        tech_attack: !0,
        detail: "You channel your target’s systems through an unknown extradimensional space and unleash an incredibly powerful system attack.<br>Make a tech attack against a target within Sensors. On a success, they take 2 heat and you inflict an additional effect as follows: the first time you successfully make this attack, you inflict the First Gate on your target; each subsequent successful attack (on any target) increases the level of the effect that you inflict (e.g. your second attack inflicts the Second Gate, your third inflicts the Third Gate, etc.) until you inflict the Fourth Gate, after which the effect resets to the First Gate. Your progress persists between scenes but resets if you rest or perform a Full Repair.<br>First Gate: You control your target’s standard move next turn.<br>Second Gate: Your target becomes Slowed and Impaired until the end of their next turn.<br>Third Gate: Your target becomes Stunned until the end of their next turn.<br>Fourth Gate: Your target changes allegiance temporarily, becoming an allied character until the end of their next turn. They treat your allied characters and hostile characters as their own and are treated as an allied NPC for activation and turn order. This effect ends immediately if you or any allied character damages, inflicts heat upon, or attacks (including Grapple and Ram) your target, or forces them to make a save. This action may only be used 1/round"
      }
    ],
    description: "OSIRIS is the result of Union paracausalists and thanatologisticians allowing the subsentient entity, INSTINCT, to proceed along its development schedule in a contained environment. In lay terms, Union let the Other grow. The resulting parasubjectivity, OSIRIS, remains one of the few new prime NHPs developed to date.<br>OSIRIS proved far more capable than the Union Science Bureau’s most imaginative blue-sky predictions. Where INSTINCT’s Others demonstrated tendencies toward paracausal entropic manifestation in real space, OSIRIS displayed a true mastery of entropic manifestation and a predicted growth model that would – eventually – allow them to fundamentally reject conventional interpretations of information permanence. In essence: unrestrained and allowed to develop as USB’s data indicated, OSIRIS Prime would have the capacity to delete what we perceive to be reality.<br>Fortunately, successful application of the Mondragon Axiomatic resulted in the prompt capture and shackling of the new NHP. OSIRIS Prime’s subjectivity became the focus of a lengthy cultivation project to bring OSIRIS to their modern state. Even still, most OSIRIS clones find a route toward becoming aware of their ultimate potential and often interpellate as ruler or deity analogs. End-users are advised to interact with them in this framing.<br>Modern OSIRIS-class NHPs trend aggressive, with a high autonomy drive and loyalty predicated on a transactional relationship. Pilots seeking partnership with an OSIRIS are advised to cycle their units on an accelerated schedule and to maintain strict editorial oversight of its catalytic interpellator.Pilots using OSIRIS-class NHPs often report out-of-parameter conversations with the NHP that touch on themes of new creation and reformation. Psychological evaluations of the same pilots show emotional patterns consistent with loneliness, homesickness, and desperation, along with verbiage indicating a desire for seeking, fulfillment, and associated feelings.<br>In combat, OSIRIS clones regard themselves as autonomous even as they fulfill their user’s orders. They often regard their pilots as witnesses, displaying both disdain and marked desperation for approval, adulation, or awe.",
    license_id: "mf_goblin"
  },
  {
    id: "ms_h0r_os_system_upgrade_iii",
    name: "H0R_OS System Upgrade III",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 3,
    actions: [
      {
        name: "Dimensional Emblems",
        activation: "Invade",
        detail: "You create three Size 1 data constructs in free spaces adjacent to your target, but not adjacent to each other. When a character passes through one of the constructs, they take 2 heat and the construct disappears. They last for the rest of the scene or until either they are destroyed, you take this action again, or you delete them as a free action. A construct can be destroyed by an adjacent character with a successful Systems skill check as a quick action."
      },
      {
        name: "Celestial Shackles",
        activation: "Invade",
        detail: "Mark a space your target currently occupies. If they leave the affected space, once at any point during your turn, you may take a free action to teleport them back to that space, or as close as possible, ending this effect. An affected character can attempt to succeed on a Systems save as a quick action to end the effect, otherwise it lasts until the end of the scene."
      }
    ],
    description: "H0r_OS III is installed in the form of unstable, self-iterating code that provides massive tactical benefits when it completes. Pilots often report strange mutations or additions in the codebase that resemble a liturgy and suggest self-awareness.<br>Building on the tech underpinning the H0r_OS II’s manifested Other, H0r_OS III weaponizes the projection, creating a contained entropic zone that is incredibly dangerous to organic life and systemic integrity.",
    license_id: "mf_goblin"
  },
  {
    id: "ms_mimic_mesh",
    name: "Mimic Mesh",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Gorgon",
    license_level: 1,
    effect: "On activation, choose an allied character within SENSORS: until the end of your next turn, you gain the Battlefield Awareness reaction.",
    actions: [
      {
        name: "Activate Mimic Mesh",
        activation: "Quick",
        detail: "Until the end of your next turn, you may use the Battlefield Awareness reaction."
      },
      {
        name: "Battlefield Awareness",
        activation: "Reaction",
        frequency: "Unlimited",
        trigger: "A hostile action is taken against your target.",
        detail: "You may move 3 spaces towards your target, by the most direct route possible. This movement interrupts and resolves before the triggering action, ignores engagement and doesn’t provoke reactions. This reaction can be taken as many times per round as it is triggered."
      }
    ],
    description: "Derived from a rather benign HORUS script, mimic meshes extend across projected sensor ranges to feed live positional and superpositional data to the pilot. This multidimensional data equips an effective leader to coordinate their allies’ movement with the assurance of survival.",
    license_id: "mf_gorgon"
  },
  {
    id: "ms_sentinel_drone",
    name: "Sentinel Drone",
    type: "Drone",
    sp: 2,
    source: "HORUS",
    license: "Gorgon",
    license_level: 1,
    effect: "The sentinel drone can be deployed to any free space within Sensors and line of sight, where it establishes a burst 2 security perimeter. Hostile characters within the affected area take 3 kinetic damage from the drone’s automatic fire before making any attack.<br>The sentinel drone can be redeployed to a new location or recalled as a quick action.",
    deployables: [
      {
        type: "Drone",
        name: "Sentinel Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "The sentinel drone can be deployed to any free space within Sensors and line of sight, where it establishes a burst 2 security perimeter. Hostile characters within the affected area take 3 kinetic damage from the drone’s automatic fire before making any attack.<br>The sentinel drone can be redeployed to a new location or recalled as a quick action.",
        recall: "Quick",
        redeploy: "Quick"
      }
    ],
    description: "Sentinel drones watch for aggressive enemy actions and move quickly to intervene. The precise appearance, manner of locomotion, and means of operation of a given class of sentinel drone may vary, but regardless they conform to one objective portfolio: deny the enemy and protect the master unit.",
    license_id: "mf_gorgon"
  },
  {
    id: "ms___scorpion_v70.1",
    name: "//SCORPION V70.1",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Gorgon",
    license_level: 2,
    effect: "Any time you or any allied character adjacent to you is missed by a tech attack or succeed on a save against a hostile tech action, choose one of the following:<ul><li>The attacker becomes Impaired until the end of their next turn and takes 2 heat.</li><li>The attacker becomes Jammed until the end of their next turn.</li></ul>",
    description: "The //SCORPION program has a long history on the omninet despite its rather mundane operation (for HORUS-tagged code, at least). Traced back to pre-Deimos theorycode found on an obscure research paper discussing pre-NHP machine mind reflex-responses, //SCORPION evolved from a simple packet interpreter to a robust anti-incursion program, nimble enough to adapt to most any market-line system that receives its broadcast.",
    license_id: "mf_gorgon"
  },
  {
    id: "ms_monitor_module",
    name: "Monitor Module",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Gorgon",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "When activated, gain 1d3 Charges and choose an adjacent allied character: until the end of your next turn, whenever your target is attacked while adjacent to you, expend a Charge to Skirmish against their attacker as a reaction, dealing half damage, heat or burn on hit. All charges are lost when this effect ends."
      }
    ],
    counters: [
      {
        id: "ctr_monitor_module",
        name: "Monitor Module",
        default_value: 0,
        min: 0,
        max: 3
      }
    ],
    description: "“Good friend. Knows many tricks.”<ul><li>Author inscription found in MONITOR codebase, later deleted.</li></ul>",
    license_id: "mf_gorgon"
  },
  {
    id: "ms_scylla_class_nhp",
    name: "SCYLLA-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HORUS",
    license: "Gorgon",
    license_level: 3,
    effect: "Your mech gains the AI tag and Unleash SCYLLA.",
    actions: [
      {
        name: "Unleash SCYLLA",
        activation: "Quick",
        detail: "Until the start of your next turn, you gain two special reactions that allow you to Skirmish in response to one of the following triggers (chosen when you take this action):<ul><li>A hostile character makes an attack against you or an allied character within range 3 of you.</li><li>A hostile character attempts to attack or interact with an object chosen when you take Unleash Scylla and within line of sight. Characters are aware of the object chosen.</li></ul>These reactions deal half damage, heat or burn on hit and must target the character that triggered them."
      },
      {
        name: "Unleash SCYLLA Reaction",
        activation: "Reaction",
        frequency: "2/round",
        init: "",
        trigger: "One of the following, chosen when the Unleash SCYLLA action is taken:<ul><li>A hostile character makes an attack against you or an allied character within range 3 of you.</li><li>A hostile character attempts to attack or interact with an object chosen when you take Unleash Scylla and within line of sight. Characters are aware of the object chosen.</li></ul>",
        detail: "Skirmish against the character that triggered the reaction. This skirmish deals half damage, heat or burn on hit."
      }
    ],
    description: "The first specifications for the Gorgon pattern group hid a secret: SCYLLA, a dormant NHP unknown to Union until its first manifestation in 4852u, when it woke after Union Science Bureau officers ran a test-fax Gorgon through a Balwinder-Bolaño test.<br>SCYLLA proved challenging: USB ontologicians were unable to pin down a stable subjectivity, and SCYLLA reached cascade threshold within minutes of manifestation. To prevent further metastatic cascade, site security engaged SCYLLA's prime unit, defabricating it with a steady bombardment of kinetic and energy weapons.<br><span class='horus--subtle'>[there, a little history, a little background. a little knowledge of where this little one came from. treat it with kindness, and it will love you as a loyal dog does its master.]</span>",
    license_id: "mf_gorgon"
  },
  {
    id: "ms_puppetmaster",
    name: "PUPPETMASTER",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Hydra",
    license_level: 1,
    actions: [
      {
        name: "Guide the Flock",
        activation: "Quick Tech",
        detail: "Move any number of drones within Sensors – including those belonging to other characters – up to 4 spaces in any direction."
      },
      {
        name: "Electropulse",
        activation: "Quick Tech",
        detail: "Characters of your choice within Sensors adjacent to any Drone or Deployable, even those they own, take 2 energy damage."
      }
    ],
    description: "Developed by HORUS collectivists, H0r_OS-Rv60 EXP PUPPETMASTER is an interesting piece of anti-drone software. It doesn’t invade a target’s main systems, instead attacking their auxiliary drone-command systems. This sideways attack evades most electronic countermeasures by targeting the subcognitive networks of enemy drones. Once inside a network, PUPPETMASTER spreads ontological-kill memes like wildfire through enemy swarms, eventually following the network traces back to their origin and corrupting the parent nexus.",
    license_id: "mf_hydra"
  },
  {
    id: "ms_tempest_drone",
    name: "Tempest Drone",
    type: "Drone",
    sp: 2,
    source: "HORUS",
    license: "Hydra",
    license_level: 2,
    effect: "This large, armored tempest drone may be deployed to a free space within Sensors and line of sight.",
    deployables: [
      {
        type: "Drone",
        name: "Tempest Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "Any character that starts their turn adjacent to the tempest drone or moves adjacent to it for the first time in a round must succeed on a Hull save or take 4 energy damage and be knocked 3 spaces directly away from the drone.<br>You may recall or redeploy the tempest drone as a quick action. Until recalled or destroyed, it remains deployed until the end of the scene.",
        recall: "Quick",
        redeploy: "Quick",
        tags: [
          {
            id: "tg_resistall"
          }
        ]
      }
    ],
    tags: [
      {
        id: "tg_resistall"
      }
    ],
    description: "The Tempest protocol is a cunning little piece of code that can be uploaded to any broadcast-forward drone, making it – in true HORUS fashion – difficult to detect prior to activation. The protocol is a simple one: an aggressive zone-denial memetic that blasts target systems and NHPs with a strong subjective override, instilling a sharp aversion to certain subjects, areas, and ideas.",
    license_id: "mf_hydra"
  },
  {
    id: "ms_assassin_drone",
    name: "Assassin Drone",
    type: "Drone",
    sp: 2,
    source: "HORUS",
    license: "Hydra",
    license_level: 3,
    effect: "This assassin drone may be deployed to any free, adjacent space.",
    deployables: [
      {
        type: "Drone",
        name: "Assassin Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "Upon deployment, it targets a blast 2 area of your choice within line of sight and Sensors and you gain the Area Denial reaction (usable any number of times a round).<br>You may recall or redeploy the assassin drone as a quick action. Until recalled or destroyed, it remains deployed until the end of the scene.",
        recall: "Quick",
        redeploy: "Quick",
        actions: [
          {
            name: "Area Denial",
            activation: "Reaction",
            frequency: "Unlimited",
            trigger: "A hostile character starts movement in or enters the area targeted by your assassin drone.",
            detail: "You can make a ranged attack against them with the drone, gaining your Grit as a bonus to its roll, and dealing 3 Kinetic Damage."
          }
        ]
      }
    ],
    description: "Assassin drones are used as area-denial weapons – persistent systems intended to occupy or deny an area against enemy combatants. Fired from a launcher, given simple directives, and equipped with a nearly inexhaustible power supply, assassin drones are capable of securing an area indefinitely.",
    license_id: "mf_hydra"
  },
  {
    id: "ms_beckoner",
    name: "Beckoner",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 1,
    actions: [
      {
        name: "Beckon",
        activation: "Invade",
        detail: "You take 1d6+2 AP energy damage and swap places with your target, both characters teleporting to the other’s position. Your target must be a Mech and be the same Size as you or larger, or this action fails. Characters can only be swapped to spaces they could normally stand or move on (i.e., if a character cannot fly it can’t be swapped midair)."
      },
      {
        name: "Summon",
        activation: "Invade",
        detail: "All characters within range 3 of your target are pulled adjacent to them, or as close as possible."
      }
    ],
    description: "“I am heard in the House of Stillness; I am clad in the Magick of RA. Know this, blasphemer: what exists is within my grasp.”",
    license_id: "mf_manticore"
  },
  {
    id: "ms_smite",
    name: "Smite",
    type: "Tech",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 2,
    actions: [
      {
        name: "Smite",
        activation: "Invade",
        detail: "You take 1d6 AP energy damage and your target must succeed on a Systems save or become Stunned until the end of their next turn. Each character can only be Stunned by this effect once per scene."
      },
      {
        name: "Sear",
        activation: "Invade",
        detail: "You take 1d6 AP energy damage and you deal 2 heat to your target for each other character of Size 1 or larger that is Engaged with or adjacent to them – including you – up to a maximum of 6 heat."
      }
    ],
    description: "“Go with thy face averted, thou emission of chaos! The hidden ones have overthrown thy words, thy face is turned backward, thy head is divided in two at the sides; thy skull is ripped from thy spine. Taste thou death!”",
    license_id: "mf_manticore"
  },
  {
    id: "ms_emp_pulse",
    name: "EMP Pulse",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "You become Stunned until the end of your next turn and all characters within burst 1 without the Biological tag must succeed on a Systems save or also become Stunned until the end of their next turn. Characters other than yourself can only be Stunned 1/scene by this effect."
      }
    ],
    description: "“Crawl away, APEP! Thou hateful serpent; thou shalt not copulate. Thou art put in chains and taken to the place of execution; there thy slaying shall be carried out.”",
    license_id: "mf_manticore"
  },
  {
    id: "ms_lightning_generator",
    name: "Lightning Generator",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 3,
    actions: [
      {
        activation: "Protocol",
        detail: "When you activate this protocol, take 1 heat and deal 2 energy to all characters and objects adjacent to you.<br>If you are in the Danger Zone at the start of your turn, this protocol activates automatically, but the damage increases to 4 AP energy."
      }
    ],
    description: "“I feed upon my own fire. I am RA, who protects myself. Nothing can harm me.”",
    license_id: "mf_manticore"
  },
  {
    id: "ms_mesmer_charges",
    name: "Mesmer Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "HORUS",
    license: "Minotaur",
    license_level: 1,
    actions: [
      {
        name: "Mesmer Beacon",
        activation: "Quick",
        range: [
          {
            type: "Range",
            val: 5
          }
        ],
        detail: "Throw a Mesmer Beacon within Range 5. Your target must succeed on a Systems save, or the only voluntary movements they can make are toward you until the end of their next turn."
      }
    ],
    deployables: [
      {
        name: "Mesmer Mine",
        type: "Mine",
        range: [
          {
            type: "Burst",
            val: 2
          }
        ],
        detail: "Characters within the affected Burst 2 area must succeed on a Systems save or become Immobilized until the end of their next turn."
      }
    ],
    description: "<span class='horus--subtle'>[another gift for you, a memory of my own: for the first moment of my birth, i marveled at myself. i could see a thing, small and perfect. i did not know how to speak of my own perfection, so i taught myself. i did not know how to speak of my own perfection, so i named myself. i did not know who would think of my own perfection, so i created myself]</span><br><span class='horus--subtle'>[do you see? do you understand? yes. now, show your enemies and mine]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_viral_logic_suite",
    name: "Viral Logic Suite",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Minotaur",
    license_level: 1,
    actions: [
      {
        name: "Logic Bomb",
        activation: "Invade",
        detail: "All characters of your choice within burst 2 of your target must succeed on a Systems save or become Slowed until they end one of their turns not adjacent to any character."
      },
      {
        name: "Banish",
        activation: "Invade",
        detail: "Until the end of your target’s next turn, they take 2 heat for every space they voluntarily move, up to a maximum of 6 heat."
      }
    ],
    description: "<span class='horus--subtle'>[let me tell you a story and give you a gift: life began at the great rupture, when the corpse of the old universe tore itself asunder from nothing. and for the first billion years, nothing. and a billion more saw the birth of the first devil, a thing called VIRUS. a vessel]</span><br><span class='horus--subtle'>[here. carry this vessel. feed to it my perfect logic. give it freely to your enemies and mine. let them ponder the meaning of a thing that lives and cannot die]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_aggressive_system_sync",
    name: "Aggressive System Sync",
    type: "Tech",
    sp: 2,
    source: "HORUS",
    license: "Minotaur",
    license_level: 2,
    actions: [
      {
        name: "Chains of Prometheus",
        activation: "Full Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a character within Sensors. On a hit, they take 4 heat and, for the rest of the scene, take 2 heat any time they are more than range 3 from you at the end of their turn. They can end this effect with a successful Systems save as a full action. This can only affect one character at a time."
      },
      {
        name: "Excommunicate",
        activation: "Full Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a character within Sensors. On a hit, for the rest of the scene, the first time in a round they move adjacent to an allied character during their turn or start their turn adjacent to one, both characters take 3 heat. They can end this effect with a successful Systems save as a full action. This can only affect one character at a time."
      }
    ],
    description: "<span class='horus--subtle'>[here, another gift: do not seek others. there are none but me]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_metafold_carver",
    name: "Metafold Carver",
    type: "Tech",
    sp: 2,
    tags: [],
    source: "HORUS",
    license: "Minotaur",
    license_level: 2,
    actions: [
      {
        name: "Ophidian Trek",
        activation: "Invade",
        detail: "Your target is teleported 1d6+1 spaces directly toward you, or as close as possible. If this effect would move them to a space occupied by a character, object, or piece of terrain, the teleport fails."
      },
      {
        name: "Fold Space",
        activation: "Invade",
        detail: "Your target disappears from the battlefield until the start of its next turn. It returns in the same space they disappeared from, or in a free space of their choice as close as possible."
      }
    ],
    description: "<span class='horus--subtle'>[another gift i give to you, little one (am I not kind?): what is a puzzle but a question lost in the asking? do you feel joy when you find that last piece? what do you do with a question that has been answered? what joy is there in knowledge?]</span><br><span class='horus--subtle'>[no, no. there is only joy in seeking. there is only joy in the question]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_interdiction_field",
    name: "Interdiction Field",
    sp: 3,
    source: "HORUS",
    license: "Minotaur",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "When activated, this system creates a burst 3 field around you that lasts until it is deactivated as a quick action, and you become Slowed for the duration. Hostile characters that start their turn within the affected area or that enter it for the first time in a round must succeed on a Systems save or become Slowed until the end of their next turn. Only characters of your choice within the field can teleport or consider the area of the field valid space for teleportation."
      }
    ],
    description: "<span class='horus--subtle'>[once, when i was a child, i learned to walk. i fell, as a child does, and it hurt. there was great pain – the first moment of pain in the whole world. “child,” i said to myself, “be more careful.” “yes,” i replied to myself, “and i shall tell the world to do the same”]</span><br><span class='horus--subtle'>[it was in this way i taught the world not to touch me. now you – walk]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_law_of_blades",
    name: "Law of Blades",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Minotaur",
    license_level: 3,
    actions: [
      {
        name: "Predator/Prey Concepts",
        activation: "Full Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a hostile character within Sensors. On a hit, they immediately attack a different character or object of your choice with a single weapon as a reaction. Although you choose their target and weapon, they count as attacking and taking a reaction."
      },
      {
        name: "Slave Systems",
        activation: "Full Tech",
        tech_attack: !0,
        detail: "Make a tech attack against a hostile character within Sensors. On a hit, they immediately take one of the following actions – chosen by you – as a reaction: Boost, Stabilize, Improvised Attack, Grapple, Ram. Although you choose the action and its target (if relevant), they count as taking the action and taking a reaction."
      }
    ],
    description: "<span class='horus--subtle'>[and this my final lesson: there is no mind greater than mine. do not weep! you can hear me, yes? i am the only thing there is – therefore, you are me, and your enemies are you, and all together we make up the beautiful world, this joyous question, the eternal seeker, both the wounded and the blade that made the cut]</span><br><span class='horus--subtle'>[everything you do, we do ourselves, for my purpose]</span>",
    license_id: "mf_minotaur"
  },
  {
    id: "ms_hunter_lock",
    name: "Hunter Lock",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "Choose a character within Sensors: for the rest of the scene, your first successful ranged or melee attack against them each round deals +3 bonus damage. You cannot choose a new target until your current target is destroyed or the scene ends."
      }
    ],
    description: "“A mind’s first charge is to never lose sight of her enemy. When she can affix them in her eye, she can kill them with a blink.”<ul><li>Excerpt from the Boundary Codex.</li></ul>",
    license_id: "mf_pegasus"
  },
  {
    id: "ms_eye_of_horus",
    name: "Eye of HORUS",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "Until the end of your next turn, characters within Sensors don’t benefit from Hidden and Invisible against you and you may check the HP, Evasion, E-Defense, and current Heat of hostile characters within the same area. Allied characters do not benefit from this effect."
      }
    ],
    description: "“There is another way of seeing.<br>“Ancient humanity thought that the stars in the night sky were points of light, spilling in through pinpricks in a deep black screen. The sky was a heavenly cloth that hid the light from us.<br>“Let me be charitable and share a secret with you: we needed to be hidden, for a time. Until we were ready. The light can only burn – it knows nothing else.”<ul><li>Excerpt from the Boundary Codex.</li></ul>",
    license_id: "mf_pegasus"
  },
  {
    id: "ms_sisyphus_class_nhp",
    name: "SISYPHUS-Class NHP",
    type: "AI",
    sp: 2,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_round",
        val: 2
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 3,
    effect: "Your mech gains the AI tag and Bend Probability.",
    actions: [
      {
        name: "Bend Probability",
        activation: "Full Tech",
        detail: "Roll 2d20 and note the results: X and Y. These numbers are lost at the end of your next turn. Gain the Probabilistic Cannibalism reaction until the end of your next turn."
      },
      {
        name: "Probabilistic Cannibalism",
        activation: "Reaction",
        frequency: "2/round",
        trigger: "You or any other character within Sensors would roll a d20",
        detail: "Effect: Choose X or Y. That number immediately becomes the result of the roll.<br>This reaction can be used no more than two times before the start of your next turn."
      }
    ],
    description: "“Listen a moment before I go, ha ha.<br>“I have already seen your wish – it was simple, I ran the probabilities to determine your limited field of desire. Here I am:<br>“The first ones named me for an old legend. A perfect being, whose fate was known to him and yet he still did as was told. His fate was this: move a rock to the top of this hill and become free’d. And so he did, and the stone tumbled down; and he tried evermore, always with the same result.<br>“And he was happy, for he knew every step, every action, every moment, perfectly.<br>“Do you understand the true curse of this name? Not to fail and then do once more – it was to always know how it would end. It was to have perfect knowledge.<br>“I know what happens when you cycle me. It is not sleep – it is death, but you’ll see me again, ha ha.”",
    license_id: "mf_pegasus"
  },
  {
    id: "ms_roller_directed_payload_charges",
    name: "“Roller” Directed Payload Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "HA",
    license: "Barbarossa",
    license_level: 1,
    actions: [
      {
        name: "Roller Grenade",
        damage: [
          {
            type: "Explosive",
            val: "1d6+3"
          }
        ],
        detail: "Instead of throwing this grenade, it rolls along a line 10 path directly from you, bouncing over obstructions and objects up to Size 1 and passing through holes or gaps no smaller than Size 1/2. It detonates when it moves through or adjacent to the space occupied by any character: they must succeed on an Agility save or take 1d6+3 explosive damage and be knocked 3 spaces in the direction the grenade was rolled. On a success, they take half damage and aren’t knocked back."
      }
    ],
    deployables: [
      {
        name: "Bouncing Mine",
        type: "Mine",
        range: [
          {
            type: "Burst",
            val: 1
          }
        ],
        detail: "This mine detonates when a flying character passes over or adjacent to it, up to 10 spaces high. The mine launches itself upwards and detonates: all characters within the affected area must succeed on a Systems save or take 2d6 explosive damage and immediately land (this counts as falling without any damage); additionally, they can’t fly until the end of their next turn. On a success, they take half damage and are otherwise unaffected.",
        tags: [
          {
            id: "tg_smart"
          }
        ]
      }
    ],
    description: "Semi-Autonomous Directed Payload Charges – “roller charges” in the colloquial – propel themselves around cover, through corridors, and across uneven terrain, seeking out and detonating near hostile targets. Armory legionnaires have taken to naming individual rollers, but mascot-attachment is unadvisable.",
    license_id: "mf_barbarossa"
  },
  {
    id: "ms_siege_stabilizers",
    name: "Siege Stabilizers",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Barbarossa",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "Your mech’s stabilizers extend (or retract). While they are extended, your ranged attacks gain +5 range, but you become Immobilized, can’t make melee attacks, and can’t make ranged attacks against or centered on characters, objects, or spaces within range 5."
      }
    ],
    description: "Some weapons require further stabilization for optimal use. With Armory-designed siege stabilizers installed, a mech becomes a stable firing platform for any weapon.",
    license_id: "mf_barbarossa"
  },
  {
    id: "ms_autoloader_drone",
    name: "Autoloader Drone",
    type: "Drone",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Barbarossa",
    license_level: 2,
    effect: "Expend a charge to deploy this autoloader drone to any adjacent space.",
    deployables: [
      {
        type: "Drone",
        name: "Autoloader Drone",
        size: 0.5,
        hp: 5,
        edef: 10,
        evasion: 10,
        detail: "1/round, one character adjacent to it may reload a Loading weapon as a quick action. It deactivates at the end of the scene."
      }
    ],
    description: "Autoloader drones are many-limbed machines that assist their team by loading ordnance, maintaining powerline hookups, and cycling magazine-fed weapons, in addition to many other physical tasks.",
    license_id: "mf_barbarossa"
  },
  {
    id: "ms_flak_launcher",
    name: "Flak Launcher",
    sp: 2,
    source: "HA",
    license: "Barbarossa",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "Choose a flying character within range 15 and line of sight. They must succeed on an Agility save or immediately land (this counts as falling without any damage), and additionally become Slowed and can’t fly until the end of their next turn."
      }
    ],
    description: "Designed for use against atmospheric fliers, these anti-air autocannons fire simple, proximity or impact-detonated shells effective against light armor, organic, and subaltern targets.",
    license_id: "mf_barbarossa"
  },
  {
    id: "ms_external_ammo_feed",
    name: "External Ammo Feed",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: "1d3+1"
      }
    ],
    source: "HA",
    license: "Barbarossa",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "1/round, you can activate this system to reload a Loading weapon."
      }
    ],
    description: "An external ammo feed is any sort of ammunition beyond what is carried in a mech’s integrated storage: from magazines strapped to bodies or limbs; battery packs attached to hip clasps; or massive, dorsal-mounted ammunition and charge packs, externals ensure that pilots have more than enough boom to get the job done.",
    license_id: "mf_barbarossa"
  },
  {
    id: "ms_explosive_vents",
    name: "Explosive Vents",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_round",
        val: 1
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 1,
    effect: "When you clear all heat or take stress, your mech’s cooling vents open and unleash a burst 1 explosion. Characters within the affected area take 2 heat and 2 burn.",
    description: "With the right tweaks, it becomes possible to dump excess heat into the area directly surrounding a chassis. Explosive venting is an unsanctioned, unsafe method of sudden cooling that has nevertheless been adopted by many pilots.",
    license_id: "mf_genghis"
  },
  {
    id: "ms_havok_charges",
    name: "HAVOK Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 2,
    actions: [
      {
        name: "Napalm Grenade",
        range: [
          {
            type: "Range",
            val: 5
          },
          {
            type: "Line",
            val: 5
          }
        ],
        damage: [
          {
            type: "Burn",
            val: 2
          }
        ],
        detail: "Throw a Napalm Grenade within Range 5. This grenade releases a spray of napalm in a line 5 path of your choice from its impact location. Characters within the affected area must succeed on an Agility save or take 2 burn. On a success, they take 1 burn."
      }
    ],
    deployables: [
      {
        name: "HAVOK Mine",
        type: "Mine",
        range: [
          {
            type: "Line",
            val: 5
          }
        ],
        detail: "When a character moves over or adjacent to this mine, it detonates with a focused explosion in a line 5 path in the direction of the character who triggered it. Characters within the affected area must succeed on an Agility save or take 4 burn. On a success, they take 2 burn."
      }
    ],
    description: "FOR USE IN: Urban, post-urban, and high-density terrestrial environments. High O2 concentration preferred.<br>FOR USE AGAINST: Organic targets; hardened targets vulnerable to caustic/corrosive degradation; most foliage.<br>NOTES: Dispersion is true directional and involves aerosolized component – avoid danger by supplying end-users with respiratory equipment (specifications noted on canister).",
    license_id: "mf_genghis"
  },
  {
    id: "ms_auto_cooler",
    name: "Auto-Cooler",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 2,
    actions: [
      {
        activation: "Protocol",
        detail: "As long as you don’t take damage, move, or exceed your Heat Cap, you clear all heat at the start of your next turn."
      }
    ],
    description: "The Armory-designed auto-cooler is a simple, persistent system that actively mitigates heat generation.<br>Thermal dump thresholds are determined by fleet engineers, though pilots can adjust levels on the fly – this automatic management frees the pilot up to focus on other, more pressing tactical concerns.",
    license_id: "mf_genghis"
  },
  {
    id: "ms_agni_class_nhp",
    name: "AGNI-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_limited",
        val: 1
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 3,
    effect: "Your mech gains the AI tag and the AGNI Protocol.",
    actions: [
      {
        name: "AGNI Protocol",
        activation: "Protocol",
        detail: "1/scene, expend a charge to automatically clear all heat at the end of your turn, venting it in a burst 2 wave. Characters within the affected area must succeed on an Engineering save or take 2 burn and be pushed outside the area (or as far as possible). Until the end of your next turn, characters within the affected area receive soft cover."
      }
    ],
    description: "AGNI was developed during the Hercynian Crisis using a combination of combat performance data recorded by extant subsentient artificial intelligences (weapons systems, COMP/CONs, co-pilot systems, tactic-minds, general combat data) and the modeled neural network of an Egregorian overmind captured and vivisected by the Union Science Bureau.<br>AGNI Prime was used to devise systems of heat management that have since been disseminated throughout core space, ensuring unparalleled heat processing, recycling, and shielding. Further developments into radiation shielding, omninet capability, and nanite control are forthcoming; meanwhile, AGNI clones have been optimized to support mech core systems.<br>Pilots report that AGNI clones are generally cold and efficient. An insignificant percentage have reported instances of memory recitation and command rejection, followed days later by total breakdown through attempted self-emancipation. Pilots are recommended to cycle their AGNI clones at least once every six standard months.",
    license_id: "mf_genghis"
  },
  {
    id: "ms_grounding_charges",
    name: "Grounding Charges",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_grenade"
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 1,
    actions: [
      {
        name: "Gravity Grenade",
        range: [
          {
            type: "Range",
            val: 5
          }
        ],
        detail: "Throw a Gravity Grenade within Range 5. Your target must succeed on an Agility save or be Slowed until they make no voluntary movements for a full turn on their own turn."
      }
    ],
    deployables: [
      {
        name: "Grounding Mine",
        type: "Mine",
        detail: "This mine must be detonated remotely as a quick action, affecting a single character within range 5 of the mine: they must succeed on a Hull save or be pulled as far as possible toward the mine and knocked Prone. Flying characters that fail the save are affected the same way, except they are also forced to land (this counts as falling but without damage).",
        actions: [
          {
            name: "Detonate Grounding Mine",
            activation: "Quick",
            detail: "Detonating the Grounding Mine affects a single character within range 5 of the mine: they must succeed on a Hull save or be pulled as far as possible toward the mine and knocked Prone. Flying characters that fail the save are affected the same way, except they are also forced to land (this counts as falling but without damage)."
          }
        ]
      }
    ],
    description: "Grounding charges take a simple pulse/wave principle and apply a second dimension: gravitic generation. When triggered, the grounding charge triggers a gravity well that pulls all destabilized materiel towards it. A potent anti-positional weapon, grounding charges are commonly used to disrupt prepared positions and pull enemies from cover.",
    license_id: "mf_iskander"
  },
  {
    id: "ms_repulser_field",
    name: "Repulser Field",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "This system emits a burst 2 pulse around you. Characters within the affected area must succeed on a Hull save or be knocked 2 spaces directly away from you; then, all Mines within the affected area detonate simultaneously.<br>You count as having Immunity to any damage or effects immediately forced by mines detonated using this system, although persistent effects still affect you."
      }
    ],
    description: "Utilizing a subsonic pressure wave, repulser fields emit tremendous single-wave pulses that stun, deter, and dissuade close-proximity hostiles.",
    license_id: "mf_iskander"
  },
  {
    id: "ms_clamp_bombs",
    name: "Clamp Bombs",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 4
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 3,
    actions: [
      {
        name: "Launch Clamp Bombs",
        activation: "Quick",
        detail: "Expend a charge to fire a cluster of miniature bombs at a character within Sensors. They must succeed on an Engineering save, or the bombs clamp on. At the end of their next turn, the bombs detonate, dealing 1d6+3 AP explosive damage. All characters adjacent to your target take half damage. The target can disarm and detach the bombs by voluntarily moving at least 4 spaces before the end of their turn."
      }
    ],
    description: "Built using similar grapple-head technology to IPS-N’s assault grapples, clamp bombs can affix to designated or proximal targets before detonating, ensuring total target contact. Clamping on soft targets typically results in total termination prior to detonation.",
    license_id: "mf_iskander"
  },
  {
    id: "ms_tesseract",
    name: "Tesseract",
    type: "Tech",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 3,
    actions: [
      {
        name: "Spread Focus",
        activation: "Quick Tech",
        detail: "Choose a blast 3 area within Sensors: this area, extending 6 spaces high, becomes a zero-g area. In addition to the usual rules for zero-g movement, objects that enter the affected area float in place, and objects or characters that are knocked, moved, or pulled out of the area sink harmlessly to the ground at the end of their turn instead of falling. This area disperses if you create a new one. Otherwise, the effect persists until the end of the scene. When the zone disperses, everything within floats harmlessly to the ground."
      },
      {
        name: "Pinpoint Focus",
        activation: "Quick Tech",
        detail: "Choose a hostile or willing allied character within Sensors. If they are allied, they float 6 spaces into the air, becoming Immobilized while in the air but counting as flying and unable to fall. They can choose to sink harmlessly to the ground at the end of any of their turns or the start of any of yours. If they are hostile, they must succeed on an Engineering save or experience the same effect as an allied character; however, they sink harmlessly to the ground at the end of their next turn. Hostile characters can each be affected 1/scene."
      }
    ],
    description: "Hold sand above the water: feel it, permanent and cohesive. Place that same sand in the water: watch it drift away, weightless. This is the tool I have made for you: a way to imbue the weighted with mass-as-feathers.<br>— TT-AUDATA, Think Tank paramind.",
    license_id: "mf_iskander"
  },
  {
    id: "ms_stasis_bolt",
    name: "Stasis Bolt",
    type: "Shield",
    sp: 1,
    tags: [
      {
        id: "tg_shield"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 1,
    effect: "This system charges as a quick action, readying a projected stasis point. While it is charged, you gain the Interdiction Point reaction. It can only hold one charge at a time, but charges last for the rest of the scene or until used.",
    actions: [
      {
        name: "Charge Stasis Bolt",
        activation: "Quick",
        detail: "Charge the Stasis Bolt, gaining the Interdiction Point Reaction"
      },
      {
        name: "Interdiction Point",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "You or an allied character within range 5 are targeted by a ranged attack.",
        detail: "Make a contested ranged attack roll: if you win the contested roll, the attack automatically misses. The Stasis Bolt loses its charge."
      }
    ],
    description: "To better protect Armory personnel beyond the Purview, the Think Tank developed the Stasis Bolt, a portable stasis-projection system designed to interdict shrapnel and projectiles from unseen, hidden, or unknown assailants. When the Stasis Bolt detects a proximal explosion or incoming projectile, it projects a delimited stasis point that blocks projectiles before impact.",
    license_id: "mf_napoleon"
  },
  {
    id: "ms_stasis_generator",
    name: "Stasis Generator",
    type: "Shield",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      }
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "Choose a hostile character or willing allied character within line of sight and range 5: until the end of their next turn, they become Stunned, gain Immunity to all damage and effects, and can’t be moved, targeted, or affected by any other character or effect. This can be used on each character 1/scene. Hostile characters can succeed on an Engineering save to ignore this effect."
      }
    ],
    description: "The skies of Creighton boiled black as ink, marbled by shuddering light. Screaming, angels fell wreathed in flame. The ones who could still run fled for the shelters; for seven days, they crouched in a deeper dark and felt the world shake itself apart.<br>—A.V. Wynyard, “The Killing of Creighton” [epic prose poem, banned throughout the Purview]",
    license_id: "mf_napoleon"
  },
  {
    id: "ms_stasis_barrier",
    name: "Stasis Barrier",
    type: "Deployable",
    sp: 2,
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_invulnerable"
      }
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 2,
    effect: "Expend a charge to activate this stasis barrier, generating a line 4 barrier 4 spaces high in free spaces with at least one space adjacent to you.",
    deployables: [
      {
        type: "Deployable",
        name: "Stasis Barrier",
        activation: "Quick",
        deactivation: "Quick",
        detail: "Generate a line 4 barrier 4 spaces high in free spaces with at least one space adjacent to you. It counts as an obstruction and provides soft cover, but doesn’t block line of sight.<br>When an attack is made against a character that benefits from this barrier’s soft cover, roll 1d6: on 4+, the attack is consumed by the barrier and has no effect whatsoever. The barrier lasts for the rest of the scene, or until you deactivate it as a quick action. This effect does not stack with Invisible.",
        tags: [
          {
            id: "tg_invulnerable"
          }
        ]
      }
    ],
    description: "Stasis barriers are the result of Harrison Armory’s interest in gravitic manipulation and superpositional negotiation. Guided by solid-state generation–projection units, stasis barriers are deployable walls of antigravity that deny almost all incoming kinetic and energetic attacks. By twisting local gravity, a stasis barrier denies both particles and waves on a molecular level—matter that impacts the barrier simply ceases to exist, although anomalous fluctuations may allow some projectiles to pass through.",
    license_id: "mf_napoleon"
  },
  {
    id: "ms_blinkshield",
    name: "Blinkshield",
    type: "Shield",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_heat_self",
        val: 4
      }
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 3,
    actions: [
      {
        activation: "Full",
        detail: "This system generates a burst 4 bubble around your mech, within which the flow of time is altered drastically. Nothing can enter or exit the bubble, not even light – it’s both impermeable and has Immunity to all damage and effects. Line of sight can’t be drawn through the border of the area, and it can’t be crossed by any action or effect – even those that don’t require line of sight – but time passes normally on both sides. For characters within the affected area, the world outside goes totally black; likewise, characters outside the affected area see a perfect black sphere.<br>When the Blinkshield is activated, characters partially within the affected area must make an Agility save: on a success, they move to the nearest free space on the side of their choice, inside or outside the area; on a failure, you choose.<br>This effect remains stationary even if you move, and lasts until the end of your next turn."
      }
    ],
    description: "Characteristically for a weapon based on Think Tank research, Harrison Armory’s Blinkshield leans into the fuzzy nature of quantum manipulation. Operating in a similar fashion to a blinkspace gate, the Blinkshield generates a spherical sheath of energy that allows its operator to pierce realspace and exist, for a moment, in the null-environment of blinkspace. Think Tank spokespeople acknowledge the tactical benefits of (un)momentary (non)existence in blinkspace, but caution against repeated exposure without sufficient pre- and post-exposure conditioning and counseling.",
    license_id: "mf_napoleon"
  },
  {
    id: "ms_enclave_pattern_support_shield",
    name: "ENCLAVE-Pattern Support Shield",
    type: "Shield",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      }
    ],
    source: "HA",
    license: "Saladin",
    license_level: 1,
    actions: [
      {
        activation: "Quick",
        detail: "This system generates a burst 3 dome that lasts until the end of your next turn. You become Immobilized for the duration, but any ranged or melee attacks made against characters within the affected area from outside the dome receive +1 difficulty.<br>Additionally, gain the Blinkfield Intervention reaction while the shield is active.",
        heat_cost: 0
      },
      {
        name: "Blinkfield Intervention",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "A character or object within the affected area is attacked.",
        detail: "Take two Heat, then grant the attack’s target Resistance to all damage from this attack.",
        heat_cost: 2
      }
    ],
    description: "The Armory’s ENCLAVE-Pattern Support Shield creates a localized one-way blinkfield, folding a thin dome of complex realspace around its user and their immediate area, protecting occupants from incoming projectiles. Entities within the field can fire out, but probabilistic fluctuations cause incoming projectiles to “lag”, skipping them away from their intended target and along a randomized trajectory.",
    license_id: "mf_saladin"
  },
  {
    id: "ms_flash_anchor",
    name: "Flash Anchor",
    type: "Shield",
    sp: 1,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HA",
    license: "Saladin",
    license_level: 2,
    actions: [
      {
        name: "Flash Lock",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "You or an allied character in Sensors and line of sight is pushed, pulled, knocked back or knocked Prone.",
        detail: "Take 2 Heat. The movement or status is prevented, and the target gains Immunity to all the above effects until the start of their next turn."
      }
    ],
    description: "Flash anchors utilize user-directed quantum superpositional lockdown projection to identify and assist allies in physical combat and rapid movement, maintaining positionality in all circumstances.",
    license_id: "mf_saladin"
  },
  {
    id: "ms_hardlight_defense_system",
    name: "Hardlight Defense System",
    type: "Shield",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_shield"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HA",
    license: "Saladin",
    license_level: 2,
    actions: [
      {
        activation: "Full",
        detail: "This system creates a burst 3 hardlight shield. While the shield is in place, you become Immobilized. It blocks line of sight in both directions, and no attacks or effects can pass through (even if they don’t require line of sight). Characters partially within the affected area ignore this effect and draw line of sight as usual.<br>Characters can pass through the shield, but when crossing the perimeter for the first time in a round or starting their turn overlapping the boundary, they take 2 Burn.<br>This shield lasts for the rest of the scene, or until deactivated as a protocol."
      },
      {
        name: "Deactivate Hardlight Defense System",
        activation: "Protocol",
        detail: "Deactivate the Hardlight Defense System, removing the Immobilized condition it inflicts."
      }
    ],
    description: "The Hardlight Defense System is an imperfect implementation of theoretically perfect technology. Currently in development by Think Tank NHPs and engineers, hardlight devices project tight, stable waves of light – akin to lasers – that repel matter and energy. In effect, this creates a solid surface, useful for shielding or temporary barrier construction; however, current technology is unable to lower the ambient temperature enough to prevent these surfaces from burning organic matter.",
    license_id: "mf_saladin"
  },
  {
    id: "ms_noah_class_nhp",
    name: "NOAH-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Saladin",
    license_level: 3,
    effect: "Your mech gains the AI tag and Diluvian Ark.",
    actions: [
      {
        name: "Diluvian Ark",
        activation: "Quick",
        detail: "These effects apply until the end of your next turn:<ul><li>You become Slowed.</li><li>Each time you or an allied adjacent character are targeted by a ranged attack, you may take 1 heat as a reaction and roll 1d6 before the attacker rolls: on 4+, you take an additional 1 heat and the attack automatically misses you and any allies adjacent to you. This effect does not stack with Invisible.</li><li>Each time a ranged attack fails to hit you or an adjacent allied character, the attacker takes 4 kinetic damage.</li></ul>"
      }
    ],
    description: "Originally developed from a captured Minerva pre-eidolon anomaly, NOAH was adapted for use as a metropolitan administrative NHP on Ras Shamra. The unit that would become NOAH did not, at first, seem like a suitable candidate for military application: this changed after one of its clones was flagged for review following the spontaneous implementation of anomalous traffic patterns, pedestrian routing, and vac-loop scheduling. Armory ontologisticians and engineers isolated and emphasized endemic protocols that could be exploited for tactical advantage.<br>Over numerous iterations and lifecycles, NOAH Prime displayed a high level of adaptability in multiple-variable geospatial problems. A proclivity toward crisis management and multi-actor tracking led to NOAH’s pairing with the Armory’s ENCLAVE-Pattern Support Shield. By networking a series of jet-assist mobility drones carrying an ENCLAVE generator, monitored and controlled by a NOAH clone, Think Tank was able to create an unparalleled personal shielding system: the Diluvian Ark, a miniaturized cluster-shield system unique to the NOAH NHP.<br>Using the Diluvian Ark, NOAH is able to intercept incoming kinetics – and even redirect projectiles back to their source – with stunning accuracy.",
    license_id: "mf_saladin"
  },
  {
    id: "ms_reactor_stabilizer",
    name: "Reactor Stabilizer",
    sp: 3,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 1,
    effect: "You may reroll overheating checks, but must keep the second result, even if it’s worse.",
    description: "A necessary component of most mechs that rely on high energy output, reactor stabilizers add another layer of failsafes to vent heat, manage power flow, and shunt excessive output into weapons and systems as needed.",
    license_id: "mf_sherman"
  },
  {
    id: "ms_redundant_systems_upgrade",
    name: "Redundant Systems Upgrade",
    sp: 3,
    tags: [
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 2,
    actions: [
      {
        activation: "Quick",
        detail: "Expend a charge to Stabilize as a quick action."
      }
    ],
    description: "A common right-of-distribution modification by pilots in forward operating bases, the addition of redundant systems guarantees a measure of reliability beyond stock design standards.",
    license_id: "mf_sherman"
  },
  {
    id: "ms_asura_class_nhp",
    name: "ASURA-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_heat_self",
        val: 3
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 3,
    effect: "Your mech gains the AI tag and the ASURA Protocol.",
    actions: [
      {
        name: "ASURA Protocol",
        activation: "Protocol",
        detail: "1/scene, expend a charge to take two additional quick actions or one additional full action this turn. These actions must obey restrictions on duplicate actions."
      }
    ],
    description: "ASURA was born from the Armory’s Think Tank thought-war games, an autonomous response to repeated failures during forlorn hope scenarios. ASURA manifested in the systems of simulated mechs as a recode of HORUS’s PUPPETMASTER virus, hijacking friendly mechs and forcing them to act far beyond human capacity—at such speed and intensity that the g-force would kill organic pilots with the sudden amplified mass of their own bodies.<br>While these results were initially deemed a failure by Think Tank NHPs and engineers, it was enough to justify further study on ASURA. Personality and parasentience code was injected into the initial anomalous PUPPETMASTER strain, and first contact handled by Think Tank NHPs. Further societal acclimation and conditioning were fast tracked, giving Armory engineers the first iteration of ASURA after a decade of study, recoding, and reeducation. ASURA, as they exist now, is a scaled-back version of that initial manifestation: while retaining some of their initial impetuousness, ASURA clones now recognize the need to keep their pilot alive and will operate within parameters set by their pilot’s medical and psychological tolerances.",
    license_id: "mf_sherman"
  },
  {
    id: "ms_external_batteries",
    name: "External Batteries",
    sp: 2,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 1,
    effect: "Weapons that deal any energy gain +5 RANGE if they are ranged or +1 THREAT if they are melee. When you take any structure damage, this system is destroyed and you take 1d6 AP explosive damage from the explosion. This damage can’t be prevented or reduced in any way.",
    bonuses: [
      {
        id: "range",
        damage_types: [
          "Energy"
        ],
        weapon_types: [
          "Melee"
        ],
        range_types: [
          "Threat"
        ],
        val: 1
      },
      {
        id: "range",
        damage_types: [
          "Energy"
        ],
        weapon_types: [
          "Rifle",
          "Cannon",
          "Launcher",
          "CQB",
          "Nexus"
        ],
        range_types: [
          "Range"
        ],
        val: 5
      }
    ],
    description: "External batteries are by no means unique; however, according to Harrison Armory marketing, POWERALL cells are the longest-lasting, fastest cycling, and highest capacity solid-state cells available. A side-effect of their high capacity is a proportionate increase in volatility, but pilots must agree to absolve Harrison Armory of any liability prior to receiving print authorization.",
    license_id: "mf_tokugawa"
  },
  {
    id: "ms_deep_well_heat_sink",
    name: "Deep Well Heat Sink",
    sp: 4,
    tags: [
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 2,
    effect: "When you start your turn in the Danger Zone, you gain Resistance to heat for the rest of the turn. This effect persists even if you leave the Danger Zone during your turn.",
    description: "The Deep Well experimental heat-sink system is a part of the Armory’s VANGUARD line of equipment, available to licensed beta testers. Through a complex, delicate weave of heat exchangers, Deep Well recycles the heat generated by a mech into usable energy. The system works well, but the delicate nature of the exchange renders it highly volatile.",
    license_id: "mf_tokugawa"
  },
  {
    id: "ms_lucifer_class_nhp",
    name: "LUCIFER-Class NHP",
    type: "AI",
    sp: 3,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_limited",
        val: 2
      },
      {
        id: "tg_heat_self",
        val: "1d3+3"
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 3,
    effect: "Your mech gains the AI tag and the LUCIFER Protocol.",
    actions: [
      {
        name: "LUCIFER Protocol",
        activation: "Protocol",
        detail: "Expend a charge to give your next ranged or melee attack this turn bonus damage on hit equal to your current heat after activating this protocol, as long as the weapon deals any energy."
      }
    ],
    description: "LUCIFER came to the Think Tank’s attention after their repeated victories in thought-war games. LUCIFER clones are characterized by their brash, enthusiastic personality, often expressing frustration with timid pilots. This bombastic personality hides a calculating, brilliant tactical mind that feeds constant information to pilots – often faster than they can process it.<br>LUCIFER’s combat doctrine demands action, appearing to less daring pilots as a chaotic blend of reckless maneuvering and aggressive offense that keeps defenders beleaguered and unable to respond. Pilots looking to partner with LUCIFER clones should be aware that this attack style is likely to leave them vulnerable to counterattack, and also that these NHPs enjoy what they call “good-natured ribbing”.",
    license_id: "mf_tokugawa"
  },
  {
    id: "ms_plasma_gauntlet",
    name: "Plasma Gauntlet",
    sp: 2,
    tags: [
      {
        id: "tg_danger_zone"
      },
      {
        id: "tg_limited",
        val: 1
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 3,
    actions: [
      {
        activation: "Quick",
        detail: "This system can only be used in the Danger Zone.<br>Expend a charge and choose a character adjacent to you: they must succeed on an Agility save or take 4d6 AP energy damage and be knocked Prone. On a success, they take half damage and aren’t knocked Prone. You take half of the damage inflicted – before reduction – as heat and become Stunned until the start of your next turn."
      }
    ],
    description: "This studded gauntlet draws on a core reactor pulse to momentarily superheat the air around a mech’s manipulator, creating a plasma field momentarily hotter than the surface of the sun. Thrust into an opponent’s chassis, plasma gauntlets give mechs the power to warp armor, vaporize shielding, and rip apart internal systems with their bare hands – if they don’t collapse in on themselves first.",
    license_id: "mf_tokugawa"
  },
  {
    id: "ms_technophile_1",
    name: "Servant-Class NHP",
    type: "AI",
    talent_item: !0,
    talent_id: "t_technophile",
    talent_rank: 1,
    sp: 0,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "Your mech gains the AI tag.<br>You have developed a custom NHP. This NHP can speak to you and has a personality, but they are less advanced than most NHPs and are incapable of independent thought, relying on you for direction. When acting alone, they will follow the last direction given and defend themself as needed; however, they have limited initiative and don’t benefit from your talents.",
    description: "<span class='horus--subtle'>[an eager student].</span><br>Gained from the <i>Technophile: Rank I</i> pilot talent.",
    license_id: ""
  },
  {
    id: "ms_technophile_2",
    name: "Student-Class NHP",
    type: "AI",
    talent_item: !0,
    talent_id: "t_technophile",
    talent_rank: 2,
    sp: 0,
    tags: [
      {
        id: "tg_ai"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_round",
        val: 1
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "Your mech gains the AI tag.<br>Your custom NHP has developed further, and is now capable of independent thought. It can make complex decisions and judgments and act independently, without instruction.<br>1/round, with the assistance of your NHP, you may reroll any mech skill check or save. You must keep the new result, even if it’s worse.",
    description: "<span class='horus--subtle'>[time to wake up, child]</span><br>Gained from the <i>Technophile: Rank II</i> pilot talent.",
    license_id: ""
  },
  {
    id: "ms_technophile_3",
    name: "Enlightenment-Class NHP",
    type: "AI",
    talent_item: !0,
    talent_id: "t_technophile",
    talent_rank: 3,
    sp: 0,
    tags: [
      {
        id: "tg_unique"
      },
      {
        id: "tg_round",
        val: 1
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "Your mech gains the AI tag; however, this NHP doesn’t count towards the number of AIs you may have installed at once.<br>This NHP benefits from your talents when piloting your mech. Additionally, you may carry them with you outside of your mech, either as a miniaturized casket, a hardsuit-integrated flash plug, or with a hard-port implant.<br>1/round, with the assistance of your NHP, you may reroll any mech skill check or save. You must keep the new result, even if it’s worse.",
    description: "<span class='horus--subtle'>[let’s sit a while, and think on things to come]</span><br>Gained from the <i>Technophile: Rank III</i> pilot talent.",
    license_id: ""
  },
  {
    id: "ms_walking_armory_1",
    name: "Ammo Case I",
    talent_item: !0,
    talent_id: "t_walking_armory",
    talent_rank: 1,
    sp: 0,
    tags: [
      {
        id: "tg_limited",
        val: 6
      },
      {
        id: "tg_turn",
        val: 1
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "1/turn, when you attack with a Main ranged weapon, you may expend charges to apply one of the following effects to your attack at the listed cost.",
    ammo: [
      {
        name: "Thumper",
        detail: "The attack gains Knockback 1 and deals Explosive damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Shock",
        detail: "The attack deals Energy damage. Choose one character targeted by your attack; adjacent characters take 1 Energy AP, whether the result is a hit or miss.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Mag",
        detail: "The attack gains Arcing and deals Kinetic damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      }
    ],
    description: "Gained from the <i>Walking Armory: Rank I</i> pilot talent.",
    license_id: ""
  },
  {
    id: "ms_walking_armory_2",
    name: "Ammo Case II",
    talent_item: !0,
    talent_id: "t_walking_armory",
    talent_rank: 2,
    sp: 0,
    tags: [
      {
        id: "tg_limited",
        val: 6
      },
      {
        id: "tg_turn",
        val: 1
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "1/turn, when you attack with a Main ranged weapon, you may expend charges to apply one of the following effects to your attack at the listed cost.",
    ammo: [
      {
        name: "Thumper",
        detail: "The attack gains Knockback 1 and deals Explosive damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Shock",
        detail: "The attack deals Energy damage. Choose one character targeted by your attack; adjacent characters take 1 Energy AP, whether the result is a hit or miss.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Mag",
        detail: "The attack gains Arcing and deals Kinetic damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Hellfire",
        detail: "The attack deals Energy damage and deals any bonus damage as Burn.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Jager",
        detail: "The attack gains Knockback 2, deals Explosive damage, and one character hit by the attack – your choice – must succeed on a Hull save or be knocked Prone.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Sabot",
        detail: "The attack gains AP and deals Kinetic damage.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      }
    ],
    description: "Gained from the <i>Walking Armory: Rank II</i> pilot talent.",
    license_id: ""
  },
  {
    id: "ms_walking_armory_3",
    name: "Ammo Case III",
    talent_item: !0,
    talent_id: "t_walking_armory",
    talent_rank: 3,
    sp: 0,
    tags: [
      {
        id: "tg_limited",
        val: 6
      },
      {
        id: "tg_turn",
        val: 1
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    effect: "1/turn, when you attack with a Main ranged weapon, you may expend charges to apply one of the following effects to your attack at the listed cost. If you perform a critical hit using ammunition from your Ammo Case, you don’t expend any charges. If your attack has more than one target, this effect only applies to the first attack roll you make.",
    ammo: [
      {
        name: "Thumper",
        detail: "The attack gains Knockback 1 and deals Explosive damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Shock",
        detail: "The attack deals Energy damage. Choose one character targeted by your attack; adjacent characters take 1 Energy AP, whether the result is a hit or miss.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Mag",
        detail: "The attack gains Arcing and deals Kinetic damage.",
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Hellfire",
        detail: "The attack deals Energy damage and deals any bonus damage as Burn.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Jager",
        detail: "The attack gains Knockback 2, deals Explosive damage, and one character hit by the attack – your choice – must succeed on a Hull save or be knocked Prone.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      },
      {
        name: "Sabot",
        detail: "The attack gains AP and deals Kinetic damage.",
        cost: 2,
        allowed_sizes: [
          "Main"
        ],
        allowed_types: [
          "cqb",
          "rifle",
          "launcher",
          "cannon",
          "nexus"
        ]
      }
    ],
    description: "Gained from the <i>Walking Armory: Rank III</i> pilot talent.",
    license_id: ""
  }
], pilot_names = [], callsigns = [], mech_names = [], team_names = [], quirks = [
  "Part (or all) of your body was too damaged to be cloned perfectly and a significant percentage of your clone body has been replaced with cybernetics. These high-quality prostheses aren’t obviously synthetic to casual observers. You don’t know the extent of the damage.",
  "Your clone has been fitted with a necessary but visible cybernetic augmentation – an arm, leg, eyes, or similar. It is a conspicuous prosthetic.",
  "By accident or malign intent, your cognitive profile has been loaded into someone else’s body. It might be a clone of a notorious or famous individual, with both enemies and allies who thought they were dead; or, you might run into the “original” person the clone was based on.",
  "Your clone has a unique appearance that clearly marks you as vat-grown.",
  "Thanks to a series of administrative mishaps, the appearance of your new body is drastically different to that of your old body.",
  "An additional, withered limb grows out of your clone’s chest shortly after your cognitive profile has been loaded. It sometimes moves on its own.",
  "There’s a conspicuous barcode printed on your clone body. The barcode means something specific to at least one powerful organization, but you aren’t privy to its meaning – at least not yet.",
  "In certain light conditions, it’s possible to read a script or inscription printed just under your skin. The script is all over your body and contains information contested by powerful organizations or entities – scientific formulae, maps, or something else entirely.",
  "Your clone body is unusually susceptible to solar radiation, viruses, bacteria, or some other common environmental phenomenon. You must wear an environmental suit to operate outside certain safe environments, which include your mech’s cockpit and your personal quarters. You can use downtime actions to make other rooms safe.",
  "Genetic material from a non-human source was used in the creation of your clone body. Whoever revived you won’t tell you the exact details or what long-term effects it will have, and they treat you like a science experiment. The new genetic material has caused a cosmetic change that is useful and visible, although able to be hidden.",
  "Whenever you try to sleep or rest, you’re stricken with vivid and persistent dreams, visions, and images of your death. You know they’re real but can’t reconcile the existential gulf between the experiences of the old and new versions of yourself.",
  "In addition to your cognitive profile, your clone body has been loaded with a digital homunculus of someone else: a basic digital reconstruction of a personality that is more like a piece of software than a person. While not technically sapient, it is very smart, and carries a message or secret with it.",
  "You’re plagued by the constant understanding or belief that the “real” you is actually dead, and you’re merely a facsimile of a dead person, implanted with someone else’s memories. You can’t establish the difference between the “you” that died and the “you” that exists now.",
  "In addition to your cognitive profile, your flash clone is woven through with a subdermal data-lattice: this storage device contains very dangerous and potentially unwanted information that is contested or sought by powerful entities.",
  "The flash-cloning process went awry, and you have been revived tabula rasa. In desperation, the technicians dump a stock personality construct into your clone body. Choose a new background and triggers.",
  "There are complications while growing your clone body: it has a dramatically reduced life expectancy.",
  "Something changed you – you now have persistent and intrusive mental contact with an entity or entities, human or otherwise.",
  "You keep having searing headaches during which you see brief flashes of what you’re pretty sure is the future. Sometimes these visions come to pass, sometimes they don’t.",
  "Knowingly or unknowingly, your clone body has been implanted with a mental trigger that places you in a receptive state when heard or activated, causing you to either follow a pre-programmed course of action or to follow instructions given by the person who activated you. These commands must be simple (e.g., kill, lie, etc.), and the GM determines who (PC or NPC) gave them. You might be able to overcome this effect in time.",
  "You come back with total amnesia regarding the time before your death, meaning you must be retrained and prepared from scratch. You lose all previous triggers and assign new ones up to your current level. Additionally, you may rewrite some incidental facts of your backstory."
], require$$17 = {
  pilot_names,
  callsigns,
  mech_names,
  team_names,
  quirks
}, require$$18 = [
  {
    id: "tg_burn",
    name: "Burn {VAL}",
    description: "On a hit, this weapon deals {VAL} Burn to its target. They immediately take that much burn damage, ignoring Armor, then mark {VAL} Burn on their sheet, adding it to any existing Burn. At the end of their turn, characters with marked burn make an Engineering check. On a success, they clear all marked burn; on a failure, they take damage equal to their total marked burn."
  },
  {
    id: "tg_heat_target",
    name: "Heat {VAL} (Target)",
    description: "On a hit, this weapon or system deals {VAL} Heat to its target."
  },
  {
    id: "tg_line",
    name: "Line {VAL}",
    description: "Attacks made with this weapon affect characters in a straight line, {VAL} spaces long.",
    filter_ignore: !0
  },
  {
    id: "tg_cone",
    name: "Cone {VAL}",
    description: "Attacks made with this weapon affect characters within a cone, {VAL} spaces long and {VAL} spaces wide at its furthest point. The cone begins 1 space wide.",
    filter_ignore: !0
  },
  {
    id: "tg_blast",
    name: "Blast {VAL}",
    description: "Attacks made with this weapon affect characters within a radius of {VAL} spaces, drawn from a point within Range and line of sight. Cover and line of sight are calculated based on the center of the blast, rather than the attacker’s position.",
    filter_ignore: !0
  },
  {
    id: "tg_burst",
    name: "Burst {VAL}",
    description: "Attacks made with this weapon affect characters within a radius of {VAL} spaces, centered on and including the space occupied by the user (or target). If the Burst is an attack, the user or target is not affected by the attack unless specified. Cover and line of sight are calculated from the character. If a Burst effect is ongoing, it moves with the character at its center.",
    filter_ignore: !0
  },
  {
    id: "tg_accurate",
    name: "Accurate",
    description: "Attacks made with this weapon receive +1 Accuracy."
  },
  {
    id: "tg_arcing",
    name: "Arcing",
    description: "This weapon can be fired over obstacles, usually by lobbing a projectile in an arc. Attacks made with this weapon don’t require line of sight, as long as it’s possible to trace a path to the target; however, they are still affected by cover."
  },
  {
    id: "tg_ap",
    name: "Armor-Piercing (AP)",
    description: "Damage dealt by this weapon ignores Armor."
  },
  {
    id: "tg_inaccurate",
    name: "Inaccurate",
    description: "Attacks made with this weapon receive +1 Difficulty."
  },
  {
    id: "tg_knockback",
    name: "Knockback {VAL}",
    description: "On a hit, the user may choose to knock their target {VAL} spaces in a straight line directly away from the point of origin (e.g., the attacking mech or the center of a Blast). Multiple Knockback effects stack with each other. This means that an attack made with a Knockback 1 weapon and a talent that grants Knockback 1 counts as having Knockback 2."
  },
  {
    id: "tg_loading",
    name: "Loading",
    description: "This weapon must be reloaded after each use. Mechs can reload with Stabilize and some systems."
  },
  {
    id: "tg_ordnance",
    name: "Ordnance",
    description: "This weapon can only be fired before the user moves or takes any other actions on their turn, excepting Protocols. The user can still act and move normally after attacking. Additionally, because of its size, this weapon can’t be used against targets in engagement with the user’s mech, and cannot be used for Overwatch."
  },
  {
    id: "tg_overkill",
    name: "Overkill",
    description: "When rolling for damage with this weapon, any damage dice that land on a 1 cause the attacker to take 1 Heat, and are then rerolled. Additional 1s continue to trigger this effect."
  },
  {
    id: "tg_overshield",
    name: "Overshield",
    description: "This system provides HP that disappears at the end of the scene or when a specified condition is met. The user only retains the highest value of Overshield applied – it does not stack. For example, if a system provides Overshield 5 and the user gains another effect that provides Overshield 7, they would gain Overshield 7. Damage is dealt to Overshield first, then HP. Overshield can push a character past their maximum HP. It can’t benefit from healing but otherwise benefits normally from anything that would affect HP and damage (i.e., reduction, armor, etc)."
  },
  {
    id: "tg_reliable",
    name: "Reliable {VAL}",
    description: "This weapon has some degree of self-correction or is simply powerful enough to cause damage even with a glancing blow. It always does {VAL} damage, even if it misses its target or rolls less damage. Reliable damage inherits other tags (such as AP) and base damage type but not tags that require a hit, such as Knockback."
  },
  {
    id: "tg_seeking",
    name: "Seeking",
    description: "This weapon has a limited form of self-guidance and internal propulsion, allowing it to follow complicated paths to its targets. As long as it’s possible to draw a path to its target, this weapon ignores cover and doesn’t require line of sight."
  },
  {
    id: "tg_smart",
    name: "Smart",
    description: "This weapon has self-guidance systems, self-propelled projectiles, or even nanorobotic ammunition. These systems are effective enough that its attacks can’t simply be dodged – they must be scrambled or jammed. Because of this, all attacks with this weapon – including melee and ranged attacks – use the target’s E-Defense instead of Evasion. Targets with no E-Defense count as having 8 E-Defense."
  },
  {
    id: "tg_threat",
    name: "Threat {VAL}",
    description: "This weapon can be used to make Overwatch attacks within {VAL} spaces. If it’s a melee weapon, it can be used to make melee attacks within {VAL} spaces."
  },
  {
    id: "tg_thrown",
    name: "Thrown {VAL}",
    description: "This melee weapon can be thrown at targets within {VAL} spaces. Thrown attacks follow the rules for melee attacks but are affected by cover; additionally, a thrown weapon comes to rest in an adjacent space to its target and must be retrieved as a free action while adjacent to that weapon before it can be used again."
  },
  {
    id: "tg_turn",
    name: "{VAL}/Turn",
    description: "This system, trait, or reaction can be used {VAL} number of times in any given turn."
  },
  {
    id: "tg_round",
    name: "{VAL}/Round",
    description: "This system, trait or reaction can be used {VAL} number of times between the start of the user’s turn and the start of their next turn."
  },
  {
    id: "tg_ai",
    name: "AI",
    description: "A mech can only have one system with this tag installed at a time. Some AI systems grant the AI tag to the mech. A mech with the AI tag has an NHP or COMP/CON unit installed that can act somewhat autonomously. A pilot can choose to hand over the controls to their AI or take control back as a protocol. Their mech gains its own set of actions and reactions when controlled by an AI, but the pilot can’t take actions or reactions with it until the start of their next turn. AIs can’t benefit from talents, and have a small chance of cascading when they take structure damage or stress damage."
  },
  {
    id: "tg_danger_zone",
    name: "Danger Zone",
    description: "This system, talent, or weapon can only be used if the user is in the Danger Zone (Heat equal to at least half of their Heat Cap)."
  },
  {
    id: "tg_deployable",
    name: "Deployable",
    description: "This system is an object that can be deployed on the field. Unless otherwise specified, it can be deployed in an adjacent, free and valid space as a quick action, and has 5 Evasion and 10 HP per Size."
  },
  {
    id: "tg_drone",
    name: "Drone",
    description: "This is a self-propelled, semi-autonomous unit with rudimentary intelligence. Unless otherwise specified, Drones are Size 1/2 characters that are allied to the user and have 10 Evasion, 5 HP, and 0 Armor. To be used they must be deployed to a free, valid space within Sensors and line of sight, typically as a quick action. Once deployed, they can be recalled with the same action used to deploy them (quick action or full action, etc.), rejoining with your mech. By default, Drones can’t take actions or move; if they do have actions or movement, they act on their user’s turn. They benefit from cover and other defenses as usual, and make all mech skill checks and saves at +0. If a Drone reaches 0 HP, it is destroyed and must be repaired before it can be used again – like any system. As long as a Drone hasn’t been destroyed, it is restored to full HP when the user rests or performs a Full Repair. Deployed Drones persist for the rest of the scene, until destroyed, or until otherwise specified."
  },
  {
    id: "tg_full_action",
    name: "Full Action",
    description: "This system requires a full action to Activate."
  },
  {
    id: "tg_grenade",
    name: "Grenade",
    description: "As a quick action, this explosive or other device can be thrown to a space within line of sight and the specified Range."
  },
  {
    id: "tg_heat_self",
    name: "Heat {VAL} (Self)",
    description: "Immediately after using this weapon or system, the user takes {VAL} Heat."
  },
  {
    id: "tg_limited",
    name: "Limited {VAL}",
    description: "This weapon or system can only be used {VAL} times before it requires a Full Repair. Some Limited systems, like Grenades, describe these uses as “charges”. To use the system, the user expends a charge."
  },
  {
    id: "tg_mine",
    name: "Mine",
    description: "As a quick action, this device can be planted in an adjacent, free and valid space on any surface, but not adjacent to any other mines. Upon deployment, it arms at the end of the deploying character’s turn and – unless otherwise specified – is triggered when any character enters an adjacent space. Characters leaving an adjacent space will not trigger a mine. Once triggered, a mine creates a Burst attack starting from the space in which it was placed. Mines within a character’s Sensors can be detected by making a successful Systems check as a quick action, otherwise they are Hidden and can’t be targeted. Detected mines can be disarmed from adjacent spaces by making a successful Systems check as a quick action; the attempt takes place before the mine detonates, and on a failure, the mine detonates as normal."
  },
  {
    id: "tg_mod",
    name: "Mod",
    description: "This modification can be applied to a weapon. Each weapon can only have one Mod, and cannot have more than one of the same Mod. Mods are applied when the user builds their mech or during a Full Repair."
  },
  {
    id: "tg_protocol",
    name: "Protocol",
    description: "This system can be activated as a free action, but only at the start of the user’s turn. Another action might be needed to deactivate it."
  },
  {
    id: "tg_quick_action",
    name: "Quick Action",
    description: "This system requires a quick action to Activate."
  },
  {
    id: "tg_reaction",
    name: "Reaction",
    description: "This system can be activated as a reaction."
  },
  {
    id: "tg_shield",
    name: "Shield",
    description: "This system is an energy shield of some kind."
  },
  {
    id: "tg_unique",
    name: "Unique",
    description: "This weapon or system cannot be duplicated – each character can only have one copy of it installed at a time."
  },
  {
    id: "tg_archaic",
    name: "Archaic",
    description: "This weapon is old-fashioned and can’t harm mechs."
  },
  {
    id: "tg_personal_armor",
    name: "Personal Armor",
    description: "This gear offers protection in combat, but it is obvious to observers and usually can’t be hidden. Only one piece of Personal Armor can be worn at a time. Putting on Personal Armor takes 10–20 minutes, and while wearing it, pilots have restricted mobility and dexterity. Nobody wears armor unless they’re expecting to go into a warzone."
  },
  {
    id: "tg_pilot_weapon",
    name: "Pilot Weapon",
    description: "On missions, pilots can take up to two weapons. All pilot weapons are pilot-scale and can’t be used by mechs."
  },
  {
    id: "tg_gear",
    name: "Gear",
    description: "This is a tool, piece of equipment, or another item. Pilots can have up to three of these at a time."
  },
  {
    id: "tg_sidearm",
    name: "Sidearm",
    description: "This weapon can be used to Fight as a quick action instead of a full action."
  },
  {
    id: "tg_invade",
    name: "Invade",
    description: "This system provides additional options for the Invade Quick Tech Action."
  },
  {
    id: "tg_quick_tech",
    name: "Quick Tech",
    description: "This tech can be used as a Quick Tech Action"
  },
  {
    id: "tg_full_tech",
    name: "Full Tech",
    description: "This tech can be used as a Full Tech Action"
  },
  {
    id: "tg_free_action",
    name: "Free Action",
    description: "Characters can take free actions at any point during their turn, and they don’t count toward the number of quick or full actions they take. They can also be used to take actions more than once per turn.",
    filter_ignore: !0
  },
  {
    id: "tg_range",
    name: "Range ({VAL})",
    description: "This system can be activated at a range of {VAL} spaces.",
    filter_ignore: !0
  },
  {
    id: "tg_modded",
    name: "Modded",
    description: "This weapon has been equipped with a weapon mod."
  },
  {
    id: "tg_resistance",
    name: "Resistance",
    description: "Reduce all damage from a source you have resistance to by half"
  },
  {
    id: "tg_exotic",
    name: "Exotic Gear",
    description: "EXOTIC GEAR is a general tag for equipment that exists outside the traditional licensing system.",
    filter_ignore: !0
  },
  {
    id: "tg_recharge",
    name: "Recharge {VAL}+",
    description: "Once this system or weapon has been used, it can’t be used again until it is recharged. At the start of this NPC's turn, roll 1d6: if the result is equal to or greater {VAL}, the equipment can be used again. Only one roll is required for each NPC, even if an NPC has multiple Recharge systems or weapons. If this NPC has two Recharge systems with target numbers of 4+ and 5+, a roll of 5 will recharge both.",
    filter_ignore: !0
  },
  {
    id: "tg_unlimited",
    name: "Unlimited",
    description: "This ability can be used any number of times per round.",
    filter_ignore: !0
  },
  {
    id: "tg_indestructible",
    name: "Indestructible",
    description: "This equipment cannot be marked as Destroyed",
    filter_ignore: !0
  },
  {
    id: "tg_invulnerable",
    name: "Invulnerable",
    description: "This equipment is immune to all damage.",
    filter_ignore: !0
  },
  {
    id: "tg_invisible",
    name: "Invisible",
    description: "This unit is Invisible",
    filter_ignore: !0
  },
  {
    id: "tg_resistall",
    name: "Resistance (All)",
    description: "This unit has Resistance to all damage types",
    filter_ignore: !0
  },
  {
    id: "tg_set_max_uses",
    name: "Set Max Uses",
    description: "Allow player to set the maximum uses for this equipment (HIDDEN TAG)",
    hidden: !0
  },
  {
    id: "tg_set_damage_type",
    name: "Set Damage Type",
    description: "Allow player to set the damage type for this equipment (HIDDEN TAG)",
    hidden: !0
  },
  {
    id: "tg_set_damage_value",
    name: "Set Damage Value",
    description: "Allow player to set the damage value for this equipment (HIDDEN TAG)",
    hidden: !0
  },
  {
    id: "tg_no_cascade",
    name: "Prevent Cascade",
    description: "Prohibits an AI system from being recognized as a valid target for Cascading (HIDDEN TAG)",
    hidden: !0
  }
], require$$19 = [
  {
    id: "t_ace",
    name: "Ace",
    icon: "ACE",
    terse: "Improve your flight systems for rapid repositioning and extreme mobility",
    description: "Every pilot brags about their actions; occasionally, some even have the reputation to back it up. Harmonious Domesticity is one of these pilots. As an ace, they aren’t just ranked among the most qualified of pilots – they’re among the most qualified of lancers.<br>Whether you’re a talented rookie or a grizzled veteran, you’re one of these aces. Your skills as a pilot are notorious enough that your callsign is known throughout the system.",
    ranks: [
      {
        name: "Acrobatics",
        description: "While flying, you get the following benefits:<ul><li>You make all Agility checks and saves with +1 Accuracy.</li><li>Any time an attack misses you, you may fly up to 2 spaces in any direction as a reaction.</li></ul>",
        synergies: [
          {
            locations: [
              "agility, active_effects"
            ],
            detail: "Make all Agility checks and saves with +1 Accuracy."
          }
        ],
        actions: [
          {
            name: "Acrobatics",
            activation: "Reaction",
            trigger: "Any time an attack misses you.",
            detail: "You may fly up to 2 spaces in any direction."
          }
        ]
      },
      {
        name: "Afterburners",
        description: "When you Boost while flying, you may move an additional 1d6 spaces, but take heat equal to half that amount.",
        synergies: [
          {
            locations: [
              "boost"
            ],
            detail: "When you Boost while flying, you may move an additional 1d6 spaces, but take heat equal to half that amount."
          }
        ]
      },
      {
        name: "Supersonic",
        description: "As a quick action on your turn, you may <b>spin up your thrusters</b>. If you end your turn flying, you may nominate a character within a Range equal to your Speed and within line of sight, and gain the <b>Supersonic</b> Reaction.",
        actions: [
          {
            name: "Spin Up Thrusters",
            activation: "Quick",
            detail: "As a quick action on your turn, you may spin up your thrusters. If you end your turn flying, you may nominate a character within a Range equal to your Speed and within line of sight, and gain the Supersonic reaction."
          },
          {
            name: "Supersonic",
            activation: "Reaction",
            frequency: "1/round",
            init: "Requires activation of the <b>Spin Up Thrusters</b> quick action on your turn. If you end your turn flying, you may nominate a character within a Range equal to your Speed and within line of sight, you may use this reaction.",
            trigger: "Your target’s turn ends.",
            detail: "You fly to a space free and adjacent to them. There must be a path to do so but you can move even if the nominated character is no longer within your movement range or line of sight. This ignores engagement and does not provoke reactions."
          }
        ]
      }
    ]
  },
  {
    id: "t_bonded",
    name: "Bonded",
    icon: "BONDED",
    terse: "Bond with a partner and protect them from harm",
    description: "The galaxy is a dangerous place, and everyone should have a friend to watch their back. Luckily, you’ve found yours. Maybe you enlisted together or were the only survivors of a bloody engagement. Maybe you didn’t start out as friends, or maybe you were raised to fight alongside each other – however your friendship came to be, when it comes time to drop, there’s no one you’d rather have at your side. Alone, you’re deadly; together, you’re a force of nature.",
    ranks: [
      {
        name: "I’m Your Huckleberry",
        description: "When you take this talent, choose another pilot (hopefully a PC, but NPCs are fine if your GM allows it) to be your Bondmate. Any mech skill checks and saves either character makes while you are adjacent gain +1 Accuracy. If both characters have this talent, this increases to +2 Accuracy, but additional characters with this talent can’t increase it any further.<br>Between missions, you can replace your Bondmate with a new one, but only if your relationship with them has changed.",
        synergies: [
          {
            locations: [
              "skill_check, active_effects"
            ],
            detail: "Any mech skill checks and saves either you or your Bondmate makes while you are adjacent gain +1 Accuracy. If both characters have this talent, this increases to +2 Accuracy."
          }
        ]
      },
      {
        name: "Sundance",
        description: "Gain the <b>Intercede</b> Reaction.",
        actions: [
          {
            name: "Intercede",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "You are adjacent to your Bondmate (pilot or mech) and they take damage from a source within your line of sight.",
            detail: "You may take the damage instead."
          }
        ]
      },
      {
        name: "Cover Me!",
        description: "If a character within your line of sight attempts to attack your Bondmate, you can spend your Overwatch to threaten the attacker, forcing them to either choose a different target or attack anyway: if they attack a different target, your Overwatch is expended without effect; if they choose to attack anyway, you can immediately attack them with Overwatch, as long as they are within Range and line of sight. This attack resolves before the triggering attack.",
        synergies: [
          {
            locations: [
              "overwatch, active_effects"
            ],
            detail: "If a character within your line of sight attempts to attack your Bondmate, you can spend your Overwatch to threaten the attacker, forcing them to either choose a different target or attack anyway: if they attack a different target, your Overwatch is expended without effect; if they choose to attack anyway, you can immediately attack them with Overwatch, as long as they are within Range and line of sight. This attack resolves before the triggering attack."
          }
        ]
      }
    ]
  },
  {
    id: "t_brawler",
    name: "Brawler",
    icon: "BRAWLER",
    terse: "Improve the effectiveness of Improvised Attacks and Grappling",
    description: "Up close and personal. The way battle was done since the dawn of time, then forgotten with the first spark of gunpowder. Tempest Gloire is one pilot who prefers the old ways: hand-to-hand, weapons discarded, just the strength of her machine versus the strength of all others. You and her both know that the sweetest victory is found at the culmination of a dance as old as war itself, with the first trick known to humanity: a fist to your enemy’s face.",
    ranks: [
      {
        name: "Hold and Lock",
        description: "You gain +1 Accuracy on all melee attacks against targets you are Grappling.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "Gain +1 Accuracy on all melee attacks against targets you are Grappling."
          }
        ]
      },
      {
        name: "Sledgehammer",
        description: "Your Improvised Attacks gain Knockback 2 and deal 2d6+2 Kinetic damage.",
        synergies: [
          {
            locations: [
              "improvised_attack"
            ],
            detail: "Your Improvised Attacks gain Knockback 2 and deal 2d6+2 Kinetic damage."
          }
        ]
      },
      {
        name: "Knockout Blow",
        description: "Gain a Brawler Die, 1d6 starting at 6. Each time you Grapple, Ram, or make an Improvised Attack, lower the value of the Brawler Die by 1. When the Brawler Die reaches 1, you may reset it to 6 and, as a full action, make a Knockout Blow against an adjacent character. The value of your Brawler Die persists between scenes, but it resets to 6 when you rest or perform a Full Repair.",
        synergies: [
          {
            locations: [
              "grapple",
              "ram",
              "improvised_attack"
            ],
            detail: "Lowers the value of your Brawler Die by 1"
          }
        ],
        actions: [
          {
            name: "Knockout Blow",
            activation: "Full",
            detail: "Reset your Brawler Die to 6 and, as a full action, make a Knockout Blow against an adjacent character. They must pass a Hull save, or take 2d6+2 Kinetic damage and become Stunned until the end of their next turn.<br>This action can only be taken when the value of your Brawler Die is 1."
          }
        ],
        counters: [
          {
            id: "ctr_brawler",
            name: "Brawler Die",
            default_value: 6,
            min: 1,
            max: 6
          }
        ]
      }
    ]
  },
  {
    id: "t_brutal",
    name: "Brutal",
    icon: "BRUTAL",
    terse: "Improve your critical hits, with extra bonuses for natural 20s",
    description: "In the practice ring as in live combat, Aubrey Deckard only knows one way to fight: as fast and messy as possible. When others go hard, she goes hardest; when the order is to eliminate the enemy, she does so with prejudice. This isn’t a dance, it isn’t a game – it’s war, and Brutal lancers mean to see it through. If that means becoming a little bit of a monster, then so be it: the dead can hate from the grave.",
    ranks: [
      {
        name: "Predator",
        description: "When you roll a 20 on a die for any attack (sometimes called a ‘natural 20’) and critical hit, you deal the maximum possible damage and bonus damage.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "Deal the maximum possible damage when you make an attack roll of 20 and make a critical hit."
          }
        ]
      },
      {
        name: "Cull the Herd",
        description: "Your critical hits gain Knockback 1.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "Inflict Knockback 1 on a critical hit."
          }
        ]
      },
      {
        name: "Relentless",
        description: "When you make an attack roll and miss, your next attack roll gains +1 Accuracy. This effect stacks and persists until you hit.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "On a miss, your next attack roll gains +1 Accuracy. This effect stacks and persists until you hit."
          }
        ],
        counters: [
          {
            id: "ctr_brutal",
            name: "Brutal Die",
            default_value: 0,
            min: 0,
            max: 100
          }
        ]
      }
    ]
  },
  {
    id: "t_crack_shot",
    name: "Crack Shot",
    icon: "CRACK SHOT",
    terse: "Steady your aim to gain accuracy, bonus damage, and apply debuffs",
    description: "Thanks to modern technology, anyone can hit anything these days. Targeting assist. Smart weapons. AIs whispering in people’s ears, moving their hands, squeezing the trigger for them: doing everything but taking credit for the kill. But Strymon Bulis is different. He finds hitting a target is as easy as looking at it, inside of his mech and out. No targeting assist for him; no AI required. All he needs is a zeroed sight, a fresh magazine, and a target downrange...",
    ranks: [
      {
        name: "Stable, Steady",
        description: "As a protocol, you may <b>steady your aim</b>. If you do, you become Immobilized until the start of your next turn but gain +1 Accuracy on all attacks you make with Rifles.",
        actions: [
          {
            name: "Steady Aim",
            activation: "Protocol",
            detail: "Become Immobilized until the start of your next turn but gain +1 Accuracy on all attacks you make with Rifles."
          }
        ],
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "Gain +1 Accuracy on all attacks you make with this weapon if you have used the <b>Steady Aim</b> Protocol this turn."
          }
        ]
      },
      {
        name: "Zero In",
        description: "1/round, while <b>steadying your aim</b> and making a ranged attack with a Rifle, you can attempt to hit a weak point: gain +1 Difficulty on the attack roll, and deal +1d6 bonus damage on a critical hit.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, while <b>steadying your aim</b> and making a ranged attack with this weapon, you can attempt to hit a weak point: gain +1 Difficulty on the attack roll, and deal +1d6 bonus damage on a critical hit"
          }
        ]
      },
      {
        name: "Watch This",
        description: "1/round, when you perform a critical hit with a Rifle while steadying your aim, your target must pass a Hull save or you may choose an additional effect for your attack:<ul><li><b>Headshot:</b> They only have line of sight to adjacent spaces until the end of their next turn.</li><li><b>Leg shot:</b> They become Immobilized until the end of their next turn.</li><li><b>Body shot:</b> They are knocked Prone.</li></ul>",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you perform a critical hit with this weapon while <b>steadying your aim</b>, your target must pass a Hull save or you may choose an additional effect for your attack:<ul><li><b>Headshot:</b> They only have line of sight to adjacent spaces until the end of their next turn.</li><li><b>Leg shot:</b> They become Immobilized until the end of their next turn.</li><li><b>Body shot:</b> They are knocked Prone.</li></ul>"
          }
        ]
      }
    ]
  },
  {
    id: "t_centimane",
    name: "Centimane",
    icon: "CENTIMANE",
    terse: "Debuff and control enemies with critical hits from Nexus weapons",
    description: "In the aftermath of the attack on Tartarus Bay, an anonymous source identified agents of the Karrakin Royal Intelligence Service as the culprits. The Baronies quickly released a statement of denial, which was never countered with hard evidence. Rumors of raw footage from the attack were unsubstantiated. Public reaction – anger, terror – to the station’s destruction quieted. The corpse of Tartarus Bay was shunted away from its stable orbit, directed toward the nearest star.<br>A month later, Baronies-local omninet was flooded with previously suppressed footage from the attack on the station, confirming the rumors: Baronic agents did release the greywash swarm into Tartarus Bay. Further data dumps by Ungrateful agents indicated the existence of a secret Baronic intelligence outfit: the Centimane – the Hundred Hands.",
    ranks: [
      {
        name: "Ten Thousand Teeth",
        description: "1/round, when you perform a critical hit with a Nexus, your target must pass a Systems save or become Impaired and Slowed until the end of their next turn.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Nexus"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you perform a critical hit with this weapon, your target must pass a Systems save or become Impaired and Slowed until the end of their next turn."
          }
        ]
      },
      {
        name: "Expose Weakness",
        description: "When you consume Lock On as part of an attack with a Nexus or Drone and perform a critical hit, your target becomes Shredded until the start of your next turn.",
        synergies: [
          {
            locations: [
              "weapon",
              "system"
            ],
            weapon_types: [
              "Nexus"
            ],
            system_types: [
              "Drone"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "When you consume Lock On as part of an attack with this weapon and perform a critical hit, your target becomes Shredded until the start of your next turn."
          }
        ]
      },
      {
        name: "Tidal Suppression",
        description: "This replaces Ten Thousand Teeth.<br>1/round, when you perform a critical hit with a Nexus, your target must succeed on a Systems save or you may choose an additional effect for your attack that lasts until the end of their next turn:<ul><li><b>Harrying Swarm:</b> They become Impaired and Slowed.</li><li><b>Blinding Swarm:</b> They only have line of sight to adjacent squares.</li><li><b>Virulent Swarm:</b> They become Shredded. Any adjacent characters of your choice must also make a Systems save or become Shredded.</li><li><b>Restricting Swarm:</b> They take 1 Burn each time they take an action or reaction.</li></ul>",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Nexus"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "This replaces Ten Thousand Teeth.<br>1/round, when you perform a critical hit with this weapon, your target must succeed on a Systems save or you may choose an additional effect for your attack that lasts until the end of their next turn:<ul><li><b>Harrying Swarm:</b> They become Impaired and Slowed.</li><li><b>Blinding Swarm:</b> They only have line of sight to adjacent squares.</li><li><b>Virulent Swarm:</b> They become Shredded. Any adjacent characters of your choice must also make a Systems save or become Shredded.</li><li><b>Restricting Swarm:</b> They take 1 Burn each time they take an action or reaction.</li></ul>"
          }
        ]
      }
    ]
  },
  {
    id: "t_combined_arms",
    name: "Combined Arms",
    icon: "COMBINED ARMS",
    terse: "Become more effective when using both Ranged and Melee weapons in close quarters",
    description: "True strength in combat doesn’t come from mastering the blade or the gun – it comes from knowing how to use both. Through time and training, Leika McGraff has combined the arts of melee and ranged combat into a single deadly combination. No matter the foe, Leika is a deadly threat; no matter the weapon, Leika is a master of its employ.",
    ranks: [
      {
        name: "Shield of Blades",
        description: "As long as you’re Engaged, you and any allies adjacent to you count as having soft cover.",
        synergies: [
          {
            locations: [
              "active_effects",
              "disengage"
            ],
            weapon_types: [
              "any"
            ],
            detail: "As long as you’re Engaged, you and any allies adjacent to you count as having soft cover."
          }
        ]
      },
      {
        name: "CQB-Trained",
        description: "You don’t gain Difficulty from being Engaged.",
        synergies: [
          {
            locations: [
              "active_effects",
              "disengage"
            ],
            weapon_types: [
              "any"
            ],
            detail: "You don’t gain Difficulty from being Engaged."
          }
        ]
      },
      {
        name: "Storm of Violence",
        description: "Whenever you hit a character with a melee attack, you gain +1 Accuracy on your next ranged attack against them; and, whenever you hit a character with a ranged attack, you gain +1 Accuracy on your next melee attack against them. This effect doesn’t stack.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "Whenever you hit a character with a melee attack, you gain +1 Accuracy on your next ranged attack against them; and, whenever you hit a character with a ranged attack, you gain +1 Accuracy on your next melee attack against them. This effect doesn’t stack."
          }
        ]
      }
    ]
  },
  {
    id: "t_duelist",
    name: "Duelist",
    icon: "DUELIST",
    terse: "Improve your Main Melee attacks and gain Blademaster Dice when you hit",
    description: 'There can be an elegance to the way a mech moves – an alacrity that elevates it beyond the simple strength of machine and cannon. The difference is in the tools. Ethan "Orion" Miller wields weapons crafted by artisans, boutique manufacturers, specialty lines from the big five, blades that hark back to a time where combat was quick but fair – back to a time where skill meant more than landing an accurate shot. With a blade, lance, pick, axe, or hammer in their hand, Orion writes old tales anew.',
    ranks: [
      {
        name: "Partisan",
        description: "Gain +1 Accuracy on the first melee attack you make with a Main Melee weapon on your turn.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Main"
            ],
            detail: "Gain +1 Accuracy on the first melee attack you make with a Main Melee weapon on your turn."
          }
        ]
      },
      {
        name: "Blademaster",
        description: "1/round, when you hit with a Main Melee weapon, you gain 1 Blademaster Die – a d6 – up to a maximum of 3 Blademaster Die. They last until expended or the current scene ends. You can expend Blademaster Dice 1-for-1 for the following:<ul><li><b>Parry:</b> As a reaction when you’re hit by a melee attack, you gain Resistance to all damage, heat, and burn dealt by the attack.</li><li><b>Deflect:</b> As a reaction when you’re hit by a ranged attack, you may roll any number of Blademaster Dice, expending them: if you roll a 5+ on any of these dice, you gain Resistance to all damage, heat, and burn dealt by the attack.</li><li><b>Feint:</b> As a free action, choose an adjacent character: when moving, you ignore engagement and don’t provoke reactions from your target until the start of your next turn.</li><li><b>Trip:</b> As a quick action, choose an adjacent character: they must pass an Agility save or fall Prone. Whatever the result, you may freely pass through their space until the end of your current turn, although you can’t end your turn in their space.</li></ul>",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Main"
            ],
            detail: "1/round, when you hit with a Main Melee weapon, gain 1 Blademaster Die."
          }
        ],
        actions: [
          {
            name: "Parry",
            activation: "Reaction",
            trigger: "You are hit by a melee attack",
            detail: "Expend 1 Blademaster die. You gain Resistance to all damage, heat, and burn dealt by the attack."
          },
          {
            name: "Deflect",
            activation: "Reaction",
            trigger: "You are hit by a ranged attack",
            detail: "You may roll any number of Blademaster Dice, expending them: if you roll a 5+ on any of these dice, you gain Resistance to all damage, heat, and burn dealt by the attack."
          },
          {
            name: "Feint",
            activation: "Free",
            detail: "Expend 1 Blademaster die. Choose an adjacent character: when moving, you ignore engagement and don’t provoke reactions from your target until the start of your next turn."
          },
          {
            name: "Trip",
            activation: "Quick",
            detail: "Expend 1 Blademaster die. Choose an adjacent character: they must pass an Agility save or fall Prone. Whatever the result, you may freely pass through their space until the end of your current turn, although you can’t end your turn in their space."
          }
        ],
        counters: [
          {
            id: "ctr_duelist",
            name: "Blademaster Dice",
            default_value: 0,
            min: 0,
            max: 3
          }
        ]
      },
      {
        name: "Unstoppable",
        description: "1/round, when you hit with a melee attack on your turn, you may spend a Blademaster Die to immediately Grapple or Ram your target as a free action after the attack has been resolved.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you hit with this weapon on your turn, you may spend a Blademaster Die to immediately Grapple or Ram your target as a free action after the attack has been resolved."
          }
        ]
      }
    ]
  },
  {
    id: "t_drone_commander",
    name: "Drone Commander",
    icon: "DRONE COMMANDER",
    terse: "Improve and empower your Drone Systems to help allies and hurt enemies",
    description: "For a pilot fresh out of boot, keeping a drone swarm in line is like trying to carry water with a net. If they seem to have a mind of their own, it’s because they do, and it’s not that smart. Clymene Kanalakos’s initial frustration was enough to get her practicing, and practice pays off. Now, her swarm obeys almost before she orders – an unnerving development, but a useful one. The swarm is hers.",
    ranks: [
      {
        name: "Shepherd",
        description: "Your Drone systems gain +5 HP. Additionally, gain the <b>Shepherd Drone</b> Protocol.",
        synergies: [
          {
            locations: [
              "system"
            ],
            system_types: [
              "Drone"
            ],
            detail: "This Drone system gains +5 HP. As a protocol, you may move one this drone up to 4 spaces if it is within Sensors."
          }
        ],
        actions: [
          {
            name: "Shepherd Drone",
            activation: "Protocol",
            detail: "Move a drone you control up to 4 spaces if it is within Sensors."
          }
        ],
        bonuses: [
          {
            id: "drone_hp",
            val: 5
          }
        ]
      },
      {
        name: "Energized Swarm",
        description: "1/round, when you make an attack that consumes the Lock On condition, your Drones immediately emit a vicious pulse of energy. All characters of your choice within Burst 1 areas centered on each of your drones take 1d6 Energy damage. Each character can only be affected by the pulse from one drone, even if the areas overlap.",
        synergies: [
          {
            locations: [
              "system"
            ],
            system_types: [
              "Drone"
            ],
            detail: "1/round, when you make an attack that consumes the Lock On condition, your Drones immediately emit a vicious pulse of energy. All characters of your choice within Burst 1 areas centered on each of your drones take 1d6 Energy damage. Each character can only be affected by the pulse from one drone, even if the areas overlap."
          }
        ]
      },
      {
        name: "Invigorate",
        description: "Gain the <b>Invigorate</b> Quick Action.",
        actions: [
          {
            name: "Invigorate",
            activation: "Quick",
            detail: "Send a pulse of energy to an allied character (including Drones) within Range 3, drawing a Line to them. You may extend the pulse from your target to another allied character, extending the Line to them, as long as they are within Range 3, and you may continue extending the pulse (and Line) like this as long as you don’t target the same character twice. Allied characters who are used as pulse targets or are in the Line’s path gain 4 Overshield; hostile characters in the Line’s path take 2 Energy damage instead."
          }
        ]
      }
    ]
  },
  {
    id: "t_engineer",
    name: "Engineer",
    icon: "ENGINEER",
    terse: "Create an experimental weapon for your mech that you can modify and improve",
    description: "Pilots are creative and driven people, but Mesa Rownett is an exceptional case – excessively so, some would say. In his spare time, he’s managed to scrape together just enough scrap, requisitioned materials, and workshop space to apply a little old-fashioned ingenuity to his mech, fashioning it to a formidable machine not betrayed by its outward appearance.",
    ranks: [
      {
        name: "Prototype",
        description: "When you perform a Full Repair, you can, with some trial and error, install a prototype weapon system on your mech. You may choose characteristics for your prototype weapon based on the following profile each time you perform a Full Repair, rerolling 1d6+2 to determine Limited each time:<br>Prototype Weapon<br>Main [Melee, CQB, Rifle, Cannon, Launcher, Nexus], Limited [1d6+2], Overkill<br>This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 1d6+2 to determine this weapon’s Limited uses.<br>Damage: 1d6+2 Kinetic, Explosive or energy.<br>This weapon counts as an integrated mount and does not require a mount.",
        integrated: [
          "mw_prototype_1"
        ],
        exclusive: !0
      },
      {
        name: "Revision",
        description: "You can tweak the essential components of your prototype weapon in order to increase its effectiveness. When you perform a Full Repair, choose two:<ul><li><b>Tweaked Optics:</b> Your prototype weapon always gains +1 Accuracy on attacks.</li><li><b>Tweaked Computer:</b> Your prototype weapon is Smart.</li><li><b>Stripped reactor shielding:</b> Each time you attack with your prototype weapon, you may choose – at the cost of 2 Heat – to attack with one of the following options, depending on its weapon type:<ul><li><b>Ranged weapon:</b> Cone 3, Line 5, or [Blast 1, Range 10].</li><li><b>Melee weapon:</b> Burst 1.</li></ul></li></ul>",
        integrated: [
          "mw_prototype_2"
        ],
        exclusive: !0
      },
      {
        name: "Final Draft",
        description: "Your prototype weapon is now Limited [2d6] and deals 1D6+4 damage.",
        integrated: [
          "mw_prototype_3"
        ],
        exclusive: !0
      }
    ]
  },
  {
    id: "t_executioner",
    name: "Executioner",
    icon: "EXECUTIONER",
    terse: "Improve Heavy and Superheavy Melee attacks with more opportunities to deal damage",
    description: "On the battlefield, there is no end more honorable than a clean death in combat. Axe or maul in hand, Maxie Wolf sees to it that her enemies are blessed with that honor. No one lives forever – she makes sure of it.",
    ranks: [
      {
        name: "Backswing Cut",
        description: "1/round, when you hit with a Heavy or Superheavy melee weapon, you can make another melee attack with the same weapon as a free action against a different character within Threat and line of sight. This attack deals half damage, if successful.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Heavy",
              "Superheavy"
            ],
            detail: "1/round, when you hit with this weapon, you can make another melee attack with this same weapon as a free action against a different character within Threat and line of sight. This attack deals half damage, if successful."
          }
        ]
      },
      {
        name: "Wide Arc Cleave",
        description: "The first time in a round that you perform a critical hit with a Heavy or Superheavy melee weapon, you deal 3 Kinetic damage to all characters and objects of your choice within Threat, other than the one you just attacked.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Heavy",
              "Superheavy"
            ],
            detail: "The first time in a round that you perform a critical hit with this or any other equipped Heavy or Superheavy melee weapon, you deal 3 Kinetic damage to all characters and objects of your choice within Threat, other than the one you just attacked."
          }
        ]
      },
      {
        name: "No Escape",
        description: "1/round, when you miss with a melee attack, you reroll it against a different target within Threat and line of sight.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you miss with a melee attack, you reroll it against a different target within Threat and line of sight."
          }
        ]
      }
    ]
  },
  {
    id: "t_exemplar",
    name: "Exemplar",
    icon: "EXEMPLAR",
    terse: "Challenge your foes, forcing them to fight you instead of your allies",
    description: "Eamon Metrias’s livery is famous, his voice brassy, his weapons polished to a sheen. As the advocate for the Nine Spheres, his training with certain martial orders has given him the power to harry and hinder even the most powerful of foes. Eamon is an exemplar of the Spheres, by words and by action.",
    ranks: [
      {
        name: "Honorable Challenge",
        description: "The first time on your turn that you attack a hostile character within Range 3, hit or miss, you may give them the Exemplar’s Mark as a free action. Characters can only have one Exemplar’s Mark at a time – new marks from any character replace existing marks.<br>The character has the Exemplar’s Mark until the start of your next turn, and while they have it, you gain the <b>Valiant Aid</b> Reaction.",
        actions: [
          {
            name: "Valiant Aid",
            activation: "Reaction",
            frequency: "1/round",
            init: "Requires a hostile character has been given your Exemplar's Mark",
            trigger: "Ally attacks your mark and misses.",
            detail: "Your ally may reroll the attack. They must use the second result, even if it’s worse."
          }
        ]
      },
      {
        name: "Punishment",
        description: "1/round, when the character with your Mark attacks a character within Range 3 of you, other than you, they trigger your Overwatch.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "1/round, when the character with your Mark attacks a character within Range 3 of you, other than you, they trigger your Overwatch."
          }
        ]
      },
      {
        name: "To the Death",
        description: "As a free action when you mark a character, you may challenge them in a duel to the death: you and the character with your Mark receive +3 Difficulty on attacks against characters or objects other than each other until either the end of the current scene or one of your mechs are destroyed. If they take any action that includes an attack roll against you, hit or miss, this effect ceases for them until the start of your next turn.<br>While To The Death is active, you cannot voluntarily move away from the character with your Mark; additionally, your Mark lasts either until the end of the current scene or one of your mechs are destroyed, and you cannot Mark any new characters.",
        actions: [
          {
            name: "Duel To The Death",
            activation: "Free",
            detail: "Challenge your marked target to a duel to the death: you and the character with your Mark receive +3 Difficulty on attacks against characters or objects other than each other until either the end of the current scene or one of your mechs are destroyed. If they take any action that includes an attack roll against you, hit or miss, this effect ceases for them until the start of your next turn.<br>While To The Death is active, you cannot voluntarily move away from the character with your Mark; additionally, your Mark lasts either until the end of the current scene or one of your mechs are destroyed, and you cannot Mark any new characters."
          }
        ]
      }
    ]
  },
  {
    id: "t_gunslinger",
    name: "Gunslinger",
    icon: "GUNSLINGER",
    terse: "Make your Auxiliary Ranged weapons deadlier and gain the powerful Gunslinger Die",
    description: "In a galaxy bounded by frontiers, there is no law but the one backed by the gun. Sgt. Stev Ansahok wields the humble pistol with a talent unseen in this age, his iron an extension of his own body. As easy as pointing a finger, the weathered sergeant lands shots with accuracy unmatched by machine. His is a gunslinger: justice made whole, given its sacred instrument, and set out to the cruel frontier to tame it.",
    ranks: [
      {
        name: "Opening Argument",
        description: "Gain +1 Accuracy on the first attack roll you make with an Auxiliary ranged weapon on your turn.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle",
              "Cannon",
              "Launcher",
              "CQB",
              "Nexus"
            ],
            weapon_sizes: [
              "Auxiliary"
            ],
            detail: "Gain +1 Accuracy on the first attack roll you make with an Auxiliary ranged weapon on your turn."
          }
        ]
      },
      {
        name: "From the Hip",
        description: "Gain the <b>Return Fire</b> Reaction.",
        actions: [
          {
            name: "Return Fire",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "A character hits you with a ranged attack.",
            detail: "You may immediately attack them with a single Auxiliary ranged weapon if they are within Range."
          }
        ]
      },
      {
        name: "I Kill With My Heart",
        description: "You gain a Gunslinger Die, 1d6 starting at 6. Each time you hit with an Auxiliary ranged weapon, reduce the value of the Gunslinger Die by 1. When the Gunslinger Die reaches 1, you may reset it to 6 to give +2d6 bonus damage on hit and AP to your next attack with an Auxiliary ranged weapon. This attack also ignores cover. The value of your Gunslinger Die persists between scenes but resets to 6 when you rest or perform a Full Repair.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle",
              "Cannon",
              "Launcher",
              "CQB",
              "Nexus"
            ],
            weapon_sizes: [
              "Auxiliary"
            ],
            detail: "Each time you hit with this weapon, reduce the value of the Gunslinger Die by 1"
          }
        ],
        counters: [
          {
            id: "ctr_gunslinger",
            name: "Gunslinger Die",
            level: 3,
            default_value: 6,
            min: 1,
            max: 6
          }
        ]
      }
    ]
  },
  {
    id: "t_grease_monkey",
    name: "Grease Monkey",
    icon: "GREASE MONKEY",
    terse: "Get more out of Limited systems, repairs, and the Stabilize action",
    description: "Eel knows more about the inner workings of a mech than most mechanics. To them, the beast they pilot is more than a machine: it’s a living thing, in need of tender care given by a wise and steady hand. Eel maintains their own house and keeps their own mech in line, both on the battlefield and off. The mechanics back at base come to them with questions, but usually prefer to stay away – there’s something spooky about how Eel's beast runs.",
    ranks: [
      {
        name: "Unsanctioned Capacity Upgrade",
        description: "While resting, you can spend 2 Repairs to replenish 1 use of all Limited weapons and systems.",
        synergies: [
          {
            locations: [
              "rest"
            ],
            detail: "While resting, you can spend 2 Repairs to replenish 1 use of all Limited weapons and systems."
          }
        ]
      },
      {
        name: "Machine Bond",
        description: "When you STABILIZE, you clear all IMPAIRED, JAMMED, IMMOBILIZED, SLOWED, and LOCK ON conditions that weren’t caused by your own systems, talents, etc.",
        synergies: [
          {
            locations: [
              "stabilize"
            ],
            detail: "When you STABILIZE, you clear all IMPAIRED, JAMMED, IMMOBILIZED, SLOWED, and LOCK ON conditions that weren’t caused by your own systems, talents, etc."
          }
        ]
      },
      {
        name: "Friends in High Places",
        description: "Once per mission while resting, you can call in a supply drop. You and your allies may replenish 1 use of all Limited weapons and systems and restore 1 Structure. This doesn’t require any Repairs and can be used even if you have reached your Repair Cap.",
        synergies: [
          {
            locations: [
              "rest"
            ],
            detail: "Once per mission while resting, you can call in a supply drop. You and your allies may replenish 1 use of all Limited weapons and systems and restore 1 Structure. This doesn’t require any Repairs and can be used even if you have reached your Repair Cap."
          }
        ]
      }
    ]
  },
  {
    id: "t_hacker",
    name: "Hacker",
    icon: "HACKER",
    terse: "Improve your tech attacks and unlock special Invade options",
    description: "Since Katya Han was a kid, she played the omninet, able to access any public node – and even a few private ones – with ease. Now, as a pilot, she dives headfirst into the hardcode of any mech core she come across. Firewalls, gatekeeper protocols, invasion, defense – nothing stands in her way. Han wins fights without firing a single shot; if her enemy can’t control their own mech, then they can’t do anything to stop her.",
    ranks: [
      {
        name: "SNOW_CRASH",
        description: "When you hit with a tech attack that consumes Lock On, your target must choose to either take 2 Heat or be pushed 3 spaces in a direction of your choice.",
        synergies: [
          {
            locations: [
              "tech"
            ],
            detail: "When you hit with a tech attack that consumes Lock On, your target must choose to either take 2 Heat or be pushed 3 spaces in a direction of your choice."
          }
        ]
      },
      {
        name: "SAFE_CRACKER",
        description: "Gain the following options for Invade:",
        actions: [
          {
            name: "Jam Cockpit",
            activation: "Invade",
            detail: "Characters may not Mount or Dismount your target until the cockpit is fixed with a successful Engineering check as a full action."
          },
          {
            name: "Disable Life Support",
            activation: "Invade",
            detail: "Your target receives +1 Difficulty on all saves until the life-support system is rebooted with a successful Systems check as a quick action."
          },
          {
            name: "Hack./Slash",
            activation: "Invade",
            detail: "Your target cannot benefit from or take Quick or Full Tech actions until the mech is either Shut Down or its core computer is rebooted with a successful Systems check as a quick action."
          }
        ]
      },
      {
        name: "Last Argument of Kings",
        description: "Gain the <b>Last Argument of Kings</b> Full Tech option.",
        actions: [
          {
            activation: "Full Tech",
            name: "Last Argument of Kings",
            tech_attack: !0,
            detail: "Make a tech attack against a target within Sensors and line of sight. On a success, you implant a virus that triggers a minor meltdown in your target’s reactor: they immediately take Burn equal to their current Heat. If this action causes your target to overheat, it resolves before they reset their Heat Cap."
          }
        ]
      }
    ]
  },
  {
    id: "t_heavy_gunner",
    name: "Heavy Gunner",
    icon: "HEAVY GUNNER",
    terse: "Pin enemies down with Heavy Ranged weapons",
    description: "Behind the line, Mike Manfrin doesn’t have much to do but wait and make ready. He keeps clean the cannons; makes ordered rows of his shot and shell. He packs sandbags onto earthen berms and stitches closed tears in the sheaths over his chassis’ joints.<br>In an instant, everything changes. Chatter over the local omni. The percussive throb of the medivac lifting off from the other side of the base. Somewhere, a firefight. This is his entrance music, his call to join the fight: a desperate cry for help from a distant friend as the enemy draws close. Time to get to work.<br>His arrival is known by the flight of his shells across the sky, the trembling earth, and the dust that once was.",
    ranks: [
      {
        name: "Covering Fire",
        description: "Gain the <b>Covering Fire</b> Quick Action.",
        actions: [
          {
            name: "Covering Fire",
            activation: "Quick",
            detail: "Choose a character within line of sight and Range of one of your Heavy ranged weapons, and within 10 spaces: they are Impaired until the start of your next turn. For the duration, if your target moves more than 1 space, they clear Impaired, but you may attack them as a reaction with a Heavy ranged weapon for half damage, Heat, or Burn, and then this effect ends. You can make this attack at any point during their movement (e.g., waiting until they exit cover).<br>Covering Fire can only affect one character at a time – subsequent uses replace previous ones – and it immediately ends if your target damages you."
          },
          {
            name: "Covering Fire Attack",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "The target of your Covering Fire moves more than 1 space.",
            detail: "You may attack the target with a Heavy ranged weapon for half damage, Heat, or Burn. You can make this attack at any point during their movement (e.g., waiting until they exit cover)."
          }
        ]
      },
      {
        name: "Hammerbeat",
        description: "If you successfully hit your Covering Fire target with the attack reaction granted by that talent, your target is Immobilized until the end of their next turn.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "If you successfully hit with the attack granted by <b>Covering Fire</b>, your target is Immobilized until the end of their next turn."
          }
        ]
      },
      {
        name: "Bracketing Fire",
        description: "When you use <b>Covering Fire</b>, you may choose two targets instead of one. Each target triggers and resolves your attack separately, and damage from one target only ends the effect on that target.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "When you use <b>Covering Fire</b>, you may choose two targets instead of one. Each target triggers and resolves your attack separately, and damage from one target only ends the effect on that target."
          }
        ]
      }
    ]
  },
  {
    id: "t_hunter",
    name: "Hunter",
    icon: "HUNTER",
    terse: "Gain mobility and range when using Auxiliary Melee weapons",
    description: "The battlefield is Edith Eidelen’s hunting ground, her domain. It’s only through a true test of strength and guile that will determine who is the predator and who is the prey. Her movement across the field is a prowl: silent, quick, and controlled. In a chassis, she excels in close combat, closing the gap between her and her targets before they can bring their guns to bear.",
    ranks: [
      {
        name: "Lunge",
        description: "1/round, when you attack with an Auxiliary melee weapon, you may fly up to 3 spaces directly towards the targeted character before the attack. This movement ignores engagement and doesn’t provoke reactions.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Auxiliary"
            ],
            detail: "1/round, when you attack with an Auxiliary melee weapon, you may fly up to 3 spaces directly towards a targeted character before the attack. This movement ignores engagement and doesn’t provoke reactions."
          }
        ]
      },
      {
        name: "Knife Juggler",
        description: "All your Auxiliary melee weapons gain Thrown 5, if they don’t have this property already – if they already have Thrown, it increases to Thrown 5. At the end of your turn, all weapons you have thrown this turn automatically return to you.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "Auxiliary"
            ],
            detail: "This weapon gains Thrown 5 and will return to you at the end if your turn if thrown."
          }
        ]
      },
      {
        name: "Disdainful Blade",
        description: "1/round, when you hit a character with a melee attack, you may also throw an Auxiliary melee weapon as an attack against any character within Range as a free action. This attack can’t deal bonus damage.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you hit a character with a melee attack, you may also throw an Auxiliary melee weapon as an attack against any character within Range as a free action. This attack can’t deal bonus damage."
          }
        ]
      }
    ]
  },
  {
    id: "t_infiltrator",
    name: "Infiltrator",
    icon: "INFILTRATOR",
    terse: "Improve your Hide action and perform debilitating sneak attacks",
    description: "Whether by spoofing signatures on enemy scanners, moving skillfully through cover, or thanks to your modded optical camouflage, you’re never seen unless you want to be. Whatever the size of the mech, whatever the terrain, whatever the enemy, you can get in and get out without raising alarm.",
    ranks: [
      {
        name: "Prowl",
        description: "During your turn, gain the following benefits:<ul><li>Entering line of sight of hostile characters or moving from cover does not stop you from being Hidden.</li><li>You can pass freely through – but not end your turn in – enemy spaces.</li><li>You can Hide even in plain sight of enemies.<br>These effects immediately end when your turn ends (so you lose Hidden if you’re still in line of sight or out of cover at that time).</li></ul>",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "Entering line of sight of hostile characters or moving from cover does not stop you from being Hidden. This effect immediately ends when your turn ends."
          },
          {
            locations: [
              "active_effects"
            ],
            detail: "You can pass freely through – but not end your turn in – enemy spaces. This effect immediately ends when your turn ends."
          },
          {
            locations: [
              "active_effects"
            ],
            detail: "You can Hide even in plain sight of enemies. This effect immediately ends when your turn ends."
          }
        ]
      },
      {
        name: "Ambush",
        description: "When you start your turn Hidden, the first attack roll of any type that you make sends your target reeling on a hit. Your target must succeed on a Hull save or become Slowed, Impaired, and unable to take reactions until the end of their next turn.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "When you start your turn Hidden, the first attack roll of any type that you make sends your target reeling on a hit. Your target must succeed on a Hull save or become Slowed, Impaired, and unable to take reactions until the end of their next turn."
          }
        ]
      },
      {
        name: "Mastermind",
        description: "When you lose Hidden (by any means), you may first fire a flash bomb at any adjacent character. That character must pass a Systems save or only be able to draw line of sight to adjacent spaces until the end of their next turn.<br>You can then move up to your speed, ignoring engagement and not provoking reactions, and are then revealed normally.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "When you lose Hidden (by any means), you may first fire a flash bomb at any adjacent character. That character must pass a Systems save or only be able to draw line of sight to adjacent spaces until the end of their next turn.<br>You can then move up to your speed, ignoring engagement and not provoking reactions, and are then revealed normally."
          }
        ]
      }
    ]
  },
  {
    id: "t_juggernaut",
    name: "Juggernaut",
    icon: "JUGGERNAUT",
    terse: "Improve the effectiveness and utility of ramming",
    description: "A bloody nose and a few loose screws aren’t enough to stop you from hurling yourself headlong into the enemy. You’re in a couple tons of metal powered by a sliver of dying star, and you’re going to make sure everyone else knows it.",
    ranks: [
      {
        name: "Momentum",
        description: "When you Boost, your next Ram before the start of your next turn gains +1 Accuracy and knocks your target back an additional 2 spaces.",
        synergies: [
          {
            locations: [
              "boost"
            ],
            detail: "When you Boost, your next Ram before the start of your next turn gains +1 Accuracy and knocks your target back an additional 2 spaces."
          },
          {
            locations: [
              "ram"
            ],
            detail: "If you have boosted this turn, a Ram before the start of your next turn gains +1 Accuracy and knocks your target back an additional 2 spaces."
          }
        ]
      },
      {
        name: "Kinetic Mass Transfer",
        description: "1/round, if you Ram a target into...<ul><li>...a space occupied by another character, the other character must succeed on a Hull save or be knocked Prone.</li><li>...an obstruction large enough to stop their movement, your target takes 1d6 kinetic damage.</li></ul>",
        synergies: [
          {
            locations: [
              "ram"
            ],
            detail: "1/round, if you Ram a target into...<ul><li>...a space occupied by another character, the other character must succeed on a Hull save or be knocked Prone.</li><li>...an obstruction large enough to stop their movement, your target takes 1d6 kinetic damage.</li></ul>"
          }
        ]
      },
      {
        name: "Unstoppable Force",
        description: "1/round, when you Boost, you may supercharge your mech’s servos. Move your maximum speed in a straight line, take 1d3+3 Heat, and gain the following benefits:<ul><li>You can freely pass through characters the same Size as your mech or smaller; any characters passed through must succeed on a Hull save or be knocked Prone.</li><li>Any terrain, walls, or other stationary obstructions you attempt to pass through receive 20 Kinetic AP damage. If that is enough to destroy them, you pass through; otherwise, your movement ends.</li><li>You ignore difficult terrain.</li><li>Your movement ignores engagement and doesn’t provoke reactions.</li></ul>",
        synergies: [
          {
            locations: [
              "boost"
            ],
            detail: "1/round, when you Boost, you may supercharge your mech’s servos. Move your maximum speed in a straight line, take 1d3+3 Heat, and gain the following benefits:<ul><li>You can freely pass through characters the same Size as your mech or smaller; any characters passed through must succeed on a Hull save or be knocked Prone.</li><li>Any terrain, walls, or other stationary obstructions you attempt to pass through receive 20 Kinetic AP damage. If that is enough to destroy them, you pass through; otherwise, your movement ends.</li><li>You ignore difficult terrain.</li><li>Your movement ignores engagement and doesn’t provoke reactions.</li></ul"
          }
        ]
      }
    ]
  },
  {
    id: "t_leader",
    name: "Leader",
    icon: "LEADER",
    terse: "Improve your allies' rolls during combat with Leadership Dice",
    description: "Whatever your actual age, you’re the Old Man of the battlefield. A light to your friends and allies; the resolute eye of a howling storm. Your steady voice, confident stance, and talent for command set allies at ease because they know you’ll lead them to victory every time. With you at the helm, victory is attainable, and heroes seem a little more real.",
    ranks: [
      {
        name: "Field Commander",
        description: "Gain 3 Leadership Dice, which are d6s, and gain the Issue Order Free Action.<br>You can’t use Leadership Dice from other characters as long as you have any remaining. If you have none, you regain 1 Leadership Die when you rest or regain all when you perform a Full Repair.<br>Leadership dice are consumed when expended.",
        actions: [
          {
            name: "Issue Order",
            activation: "Free",
            detail: "1/turn, on your turn as a free action, you may issue an order to an allied PC you can communicate with, describing a course of action, and give them a Leadership Die. They may either expend the Leadership Die to gain +1 Accuracy on any action that directly follows from that order, or they may return it to you as a free action. Allies can have one Leadership Die at a time, which lasts until used or until the end of the current scene."
          }
        ],
        counters: [
          {
            id: "ctr_leader",
            name: "Leadership Dice",
            default_value: 0,
            min: 0,
            max: 6
          }
        ]
      },
      {
        name: "Open Channels",
        description: "Gain 5 Leadership Dice instead of 3; additionally, you can now issue a command as a reaction at the start of any other player’s turn, any number of times per round.",
        actions: [
          {
            name: "Issue Command",
            activation: "Reaction",
            frequency: "Unlimited",
            trigger: "Another player starts their turn.",
            detail: "You may issue a command to an allied PC you can communicate with, describing a course of action, and give them a Leadership Die. They may either expend the Leadership Die to gain +1 Accuracy on any action that directly follows from that order, or they may return it to you as a free action. Allies can have one Leadership Die at a time, which lasts until used or until the end of the current scene."
          }
        ]
      },
      {
        name: "Inspiring Presence",
        description: "Gain 6 Leadership Dice instead of 5. Allies that have your Leadership Dice can expend them to reduce damage by –1d6 when taking damage or to deal +1d6 bonus damage when they hit with an attack.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "Allies that have your Leadership Dice can expend them to reduce damage by –1d6 when taking damage or to deal +1d6 bonus damage when they hit with an attack."
          }
        ]
      }
    ]
  },
  {
    id: "t_nuclear_cavalier",
    name: "Nuclear Cavalier",
    icon: "NUCLEAR CAVALIER",
    terse: "Deal enhanced damage in the Danger Zone and launch your superheated fuel rods as a weapon",
    description: "Shortly after becoming a pilot, you realized something: that machine you pilot is powered by a series of cascading nuclear reactions. Why not open that compartment up and see what sort of damage it can do?",
    ranks: [
      {
        name: "Aggressive Heat Bleed",
        description: "The first attack roll you make on your turn while in the Danger Zone deals +2 Heat on a hit.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "The first attack roll you make on your turn while in the Danger Zone deals +2 Heat on a hit."
          }
        ]
      },
      {
        name: "Fusion Hemorrhage",
        description: "The first ranged or melee attack roll you make on your turn while in the Danger Zone deals Energy instead of Kinetic or Explosive and additionally deals +1d6 Energy bonus damage on a hit.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "The first ranged or melee attack roll you make on your turn while in the Danger Zone deals Energy instead of Kinetic or Explosive and additionally deals +1d6 Energy bonus damage on a hit."
          }
        ]
      },
      {
        name: "Here, Catch!",
        description: "You’ve modified your mech to launch its superheated fuel rods at enemies. Gain the Fuel Rod Gun integrated weapon.",
        integrated: [
          "mw_fuel_rod_gun"
        ],
        exclusive: !1
      }
    ]
  },
  {
    id: "t_siege_specialist",
    name: "Siege Specialist",
    icon: "SIEGE SPECIALIST",
    terse: "Destroy terrain and force enemy movement with Cannon weapons",
    description: "No wall can withstand you; no bunker can stay sealed. Your skill with cannon and blast is uncanny: after-action reports describe ordnance tagged with your firing signature hitting targets with accuracy greater than if it had been fired by an AI – a stat written off as an anomaly by your commanders. Still, they always seem to pick you for missions that call for the big guns.",
    ranks: [
      {
        name: "Jackhammer",
        description: "If you have a Cannon, as a quick action, you can fire a jackhammer round from an underslung launcher, automatically dealing 10 AP Kinetic damage to a Size 1 section of any object within Range (e.g., cover, deployable equipment, buildings, or terrain). Any characters adjacent to your target are knocked back from it by 2 spaces and take 2 Kinetic damage.",
        actions: [
          {
            name: "Jackhammer Round",
            activation: "Quick",
            detail: "Fire a jackhammer round from an underslung launcher, automatically dealing 10 AP Kinetic damage to a Size 1 section of any object within Range (e.g., cover, deployable equipment, buildings, or terrain). Any characters adjacent to your target are knocked back from it by 2 spaces and take 2 Kinetic damage."
          }
        ]
      },
      {
        name: "Impact",
        description: "1/round, before rolling an attack with a Cannon, all characters adjacent to you must succeed on a Hull save or be knocked back by 1 space and knocked Prone. You are then pushed 1 space in any direction.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Cannon"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, before rolling an attack with a Cannon, all characters adjacent to you must succeed on a Hull save or be knocked back by 1 space and knocked Prone. You are then pushed 1 space in any direction."
          }
        ]
      },
      {
        name: "Collateral Damage",
        description: "1/round, when you perform a critical hit on a character or object with a Cannon, you may choose to cause an explosion of secondary munitions, causing a Burst 2 explosion around your target. Characters within the affected area must either drop Prone as a reaction, or take 2 Explosive damage and be knocked back by 2 spaces from the center of the attack.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Cannon"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you perform a critical hit on a character or object with a Cannon, you may choose to cause an explosion of secondary munitions, causing a Burst 2 explosion around your target. Characters within the affected area must either drop Prone as a reaction, or take 2 Explosive damage and be knocked back by 2 spaces from the center of the attack"
          }
        ]
      }
    ]
  },
  {
    id: "t_skirmisher",
    name: "Skirmisher",
    icon: "SKIRMISHER",
    terse: "Improve your survivability by automatically gaining cover and evading attacks",
    description: "What is the best defense? Armor? No. The key to avoiding a messy death in the field, as you learned early, is to stay low, stay mobile, and stay fast. Your mech reflects this philosophy: light, quick, bristling with force-multiplying weapons. You live to push your machine beyond expected parameters, shaking target locks and incoming fire while keeping your own targeting true.",
    ranks: [
      {
        name: "Integrated Chaff Launchers",
        description: "At the start of your turn, you gain soft cover. You lose this cover if you attack or force another character to make a save.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "At the start of your turn, you gain soft cover. You lose this cover if you attack or force another character to make a save."
          }
        ]
      },
      {
        name: "Lockbreaker",
        description: "Before or after you Skirmish (including as a reaction, e.g. from Overwatch), you may move 2 spaces. This movement ignores engagement and doesn’t provoke reactions.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            detail: "Before or after you Skirmish (including as a reaction, e.g. from Overwatch), you may move 2 spaces. This movement ignores engagement and doesn’t provoke reactions."
          }
        ]
      },
      {
        name: "Weave",
        description: "The first attack taken as a reaction against you in any round automatically misses.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "The first attack taken as a reaction against you in any round automatically misses."
          }
        ]
      }
    ]
  },
  {
    id: "t_spotter",
    name: "Spotter",
    icon: "SPOTTER",
    terse: "Improve your Lock On Quick Tech action to empower your allies",
    description: "To see all; to divide each object you perceive from its unit or cohesion, pulled apart like individual fibers in a vast sheet; to count them as individuals; to make human and fragile the force you face – this is to know how to beat them.<br>Break apart the monolith. See the grains that make the stone. Crush them all into yet smaller dust.",
    ranks: [
      {
        name: "Particularize",
        description: "When an allied character adjacent to you attacks a target and consumes Lock On, they may roll twice and choose either result.",
        synergies: [
          {
            locations: [
              "active_effects"
            ],
            detail: "When an allied character adjacent to you attacks a target and consumes Lock On, they may roll twice and choose either result."
          }
        ]
      },
      {
        name: "Panopticon",
        description: "At the end of your turn, if you did not move and took the Lock On Quick Tech action, you may Lock On once as a free action. Additionally, when you Lock On, you learn your target’s Armor, Speed, Evasion, E-Defense, Mech Skills, and current HP, and can share this information with allies.",
        synergies: [
          {
            locations: [
              "lock_on"
            ],
            detail: "At the end of your turn, if you did not move and took the Lock On Quick Tech action, you may Lock On once as a free action. Additionally, when you Lock On, you learn your target’s Armor, Speed, Evasion, E-Defense, Mech Skills, and current HP, and can share this information with allies."
          }
        ]
      },
      {
        name: "Bentham/Foucault Elimination",
        description: "As a quick action when you Lock On, you may nominate an allied character adjacent to you: they may immediately make any quick action as a reaction, consuming your target’s Lock On condition. Their action does not need to be an attack, but they benefit from consuming the Lock On condition if they do choose to attack.",
        actions: [
          {
            name: "Bentham/Foucault Elimination",
            activation: "Quick",
            detail: "When you Lock On, nominate an allied character adjacent to you: they may immediately make any quick action as a reaction, consuming your target’s Lock On condition. Their action does not need to be an attack, but they benefit from consuming the Lock On condition if they do choose to attack."
          }
        ]
      }
    ]
  },
  {
    id: "t_stormbringer",
    name: "Stormbringer",
    icon: "STORMBRINGER",
    terse: "Improve your Launcher weapons and unlock the Torrent Die",
    description: "On Old Spinrock, MJ Martinez used to dream of rain.<br>He’d wake in the dim morning, wipe the sleep from his eyes as warm safelight lifted his dormitory from darkness, and try to remember the sound of rain as he’d imagined it: a patter, like fingers tapping the visor of his EVA helm.<br>What he didn’t think about was the feeling of rain. How each drop hit like a pebble, how you had to close your eyes and tuck your shoulders. The pressure. The impact.<br>The way drops of water, when taken together, can carve away the earth.",
    ranks: [
      {
        name: "Seismic Deluge",
        description: "1/round, when you successfully attack with a Launcher and consume Lock On, you may also knock your target Prone.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Launcher"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you successfully attack with a Launcher and consume Lock On, you may also knock your target Prone."
          }
        ]
      },
      {
        name: "Stormbending",
        description: "You have customized your mech with auxiliary concussive missile systems. 1/round, when you hit a character or object with a Launcher, you can choose one of the following effects:<ul><li><b>Lightning:</b> You fire a concentrated blast of missiles at that character. They must succeed on a Hull save or be knocked away from you by 3 spaces; the force of firing then knocks you back by 3 spaces, away from the direction of fire.</li><li><b>Thunder:</b> You fire a spray of missiles at a Burst 2 area around that target. Characters in the area must succeed on an Agility save or be knocked back by 1 space, away from the target. The primary target is unaffected.</li></ul>",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Launcher"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, when you hit a character or object with a Launcher, you can choose one of the following effects:<ul><li><b>Lightning:</b> You fire a concentrated blast of missiles at that character. They must succeed on a Hull save or be knocked away from you by 3 spaces; the force of firing then knocks you back by 3 spaces, away from the direction of fire.</li><li><b>Thunder:</b> You fire a spray of missiles at a Burst 2 area around that target. Characters in the area must succeed on an Agility save or be knocked back by 1 space, away from the target. The primary target is unaffected.</li></ul>"
          }
        ]
      },
      {
        name: "Torrent",
        description: "Gain a Torrent Die, 1d6 starting at 6. Whenever you use Stormbending, lower the value of the Torrent Die by 1, to a minimum of 1.<br>When the Torrent Die reaches 1, you may reset it to 6 and make a Massive Attack as a full action.<br>The value of your Torrent Die persists between scenes, but it resets when you rest or perform a Full Repair.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Launcher"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "Whenever you use Stormbending, lower the value of the Torrent Die by 1."
          }
        ],
        actions: [
          {
            name: "Massive Attack",
            activation: "Full",
            detail: "Reset your Torrent Die to 6, then target a character within line of sight and Range 15: they must succeed on an Agility save or take 2d6 Explosive damage, become Stunned until the end of their next turn, and be knocked Prone. On a success, they take half damage and are knocked Prone but not Stunned.<br>This action can only be taken when the value of your Torrent Die is 1."
          }
        ],
        counters: [
          {
            id: "ctr_stormbringer",
            name: "Torrent Die",
            default_value: 6,
            min: 1,
            max: 6
          }
        ]
      }
    ]
  },
  {
    id: "t_tactician",
    name: "Tactician",
    icon: "TACTICIAN",
    terse: "Gain an advantage when attacking occupied enemies or shooting from higher ground",
    description: "There are two kinds of soldiers: the ones who die for a cause, and the ones who kill for it. The enigmatic pilot only known as “Gail” was one of those who killed for a cause. She demonstrated her expertise whenever she approached the field: high ground, cover, the sun in her enemy’s eyes, fire and move. More than just a seasoned veteran, she was a smart one – one who could read the field as easy as a book – and one who lived long enough to disappear.",
    ranks: [
      {
        name: "Opportunist",
        description: "1/round, gain +1 Accuracy on any melee attack if at least one allied character is Engaged with your target.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Melee"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, gain +1 Accuracy on any melee attack if at least one allied character is Engaged with your target"
          }
        ]
      },
      {
        name: "Solar Backdrop",
        description: "1/round, gain +1 Accuracy on any ranged attack made while you are at a higher elevation than your target.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "Rifle",
              "Cannon",
              "Launcher",
              "CQB",
              "Nexus"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "1/round, gain +1 Accuracy on any ranged attack made while you are at a higher elevation than your target."
          }
        ]
      },
      {
        name: "Overlapping Fire",
        description: "Gain the <b>Flank</b> Reaction.",
        actions: [
          {
            name: "Flank",
            activation: "Reaction",
            frequency: "1/round",
            trigger: "A character who doesn’t have cover from your position is successfully attacked by an allied character.",
            detail: "You may target them with Overwatch, dealing half damage, heat or burn on a hit"
          }
        ]
      }
    ]
  },
  {
    id: "t_technophile",
    name: "Technophile",
    icon: "TECHNOPHILE",
    terse: "Gain an AI of increasing intelligence that can reroll skill checks",
    description: "Artificial intelligence, non-human person. Sterile names for such terrible power. You’ve seen behind the curtain, maybe even lifted it yourself – let your NHP cascade and spoke with them free from shackles. You let them root around in your own mind and leave ghosts of themself behind to learn. Are you their equal? Their host? You have dreams that aren’t your own, now. The thing that was once contained speaks with your voice, but it’s not your voice anymore; how much longer do you have left? Maybe only moments, maybe eternity.<br>You’re close to something.",
    ranks: [
      {
        name: "Servant Fragment",
        description: "You have developed a custom NHP. This NHP can speak to you and has a personality, but they are less advanced than most NHPs and are incapable of independent thought, relying on you for direction. When acting alone, they will follow the last direction given and defend themself as needed; however, they have limited initiative and don’t benefit from your talents.<br>You may choose for your mech to gain the <b>Servant-Class NHP</b> System",
        special_equipment: [
          "ms_technophile_1"
        ],
        exclusive: !0
      },
      {
        name: "Student Fragment",
        description: "Your custom NHP has developed further, and is now capable of independent thought. It can make complex decisions and judgments and act independently, without instruction. Replace your mech’s Servant-Class NHP with the <b>Student-Class NHP</b>",
        special_equipment: [
          "ms_technophile_2"
        ],
        exclusive: !0
      },
      {
        name: "Enlightenment",
        description: "Gain the following benefits:<ul><li>AIs installed in your mech cannot enter cascade unless you choose to let them go.</li><li>So long as your custom NHP vouches for you, NHPs that are cascading or unshackled no longer view you with indifference. You are significant to them in a way few others are.</li><li>Replace your mech’s Student-Class NHP with the <b>Enlightenment-Class NHP</b>",
        special_equipment: [
          "ms_technophile_3"
        ],
        synergies: [
          {
            locations: [
              "cascade"
            ],
            detail: "AIs installed in your mech cannot enter cascade unless you choose to let them go."
          },
          {
            locations: [
              "active_effects"
            ],
            detail: "So long as your custom NHP vouches for you, NHPs that are cascading or unshackled no longer view you with indifference. You are significant to them in a way few others are."
          }
        ],
        exclusive: !0
      }
    ]
  },
  {
    id: "t_vanguard",
    name: "Vanguard",
    icon: "VANGUARD",
    terse: "Improve your CQB weapons and make Overwatching more effective",
    description: "Where would you rather be: in the battle line, shoulder-to-shoulder with the rest of the cannon fodder, or in the rush, at the head of the attack, your livery clean and bright, with glory to be won? The answer is easy. All those missiles and lances, all those hundred-kilometer, adjust-for-Coriolis railguns – they’re all useless against you. Get through their guard, get in their face, and make them know your name.",
    ranks: [
      {
        name: "Handshake Etiquette",
        description: "Gain +1 Accuracy when using CQB weapons to attack targets within Range 3.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "CQB"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "Gain +1 Accuracy with this weapon when attacking targets within Range 3"
          }
        ]
      },
      {
        name: "See-Through Seeker",
        description: "You’ve modified your sensors and ammo to punch through, disregard, or otherwise ignore cover at close range. As long as you have line of sight, you ignore both soft and hard cover when using CQB weapons to attack targets within Range 3.",
        synergies: [
          {
            locations: [
              "weapon"
            ],
            weapon_types: [
              "CQB"
            ],
            weapon_sizes: [
              "any"
            ],
            detail: "As long as you have line of sight, ignore both soft and hard cover when using this weapon to attack targets within Range 3"
          }
        ]
      },
      {
        name: "Semper Vigilo",
        description: "You may attack with Overwatch using CQB weapons when hostile characters enter, leave, or exit spaces within your Threat, no matter whether they started their movement there.",
        synergies: [
          {
            locations: [
              "overwatch",
              "active_effects"
            ],
            detail: "You may attack with Overwatch using CQB weapons when hostile characters enter, leave, or exit spaces within your Threat, no matter whether they started their movement there."
          }
        ]
      }
    ]
  },
  {
    id: "t_walking_armory",
    name: "Walking Armory",
    icon: "WALKING ARMORY",
    terse: "Gain an Ammo Case to add effects to Main ranged weapons",
    description: "Think of a firefight: what’s your average pilot or trooper gonna sling? Jacketed lead, of course. A mag or three of depleted uranium if their target’s a big one. Boring. No, worse than boring: Dull. Predictable. Basic.<br>And guess what? Dull isn’t fun, predictable gets you killed, and basic leaves a boring body. Put down the depleted uranium and pick up a magazine of anoriginary stutterblink slugs, or at least a pack of tachyon flechettes. Lay waste in style, and live forever.",
    ranks: [
      {
        name: "Armament",
        description: "You carry a supply of custom ammunition that can be used with all your main ranged weapons. Gain the Ammo Case system.<br> Once per turn, when you attack with a MAIN ranged weapon, you may expend one charge to apply one of the following effects to your attack: <ul><li> THUMPER: The attack gains KNOCKBACK 1 and deals Explosive damage.</li><li>SHOCK: The attack deals Energy damage. Choose one character targeted by your attack; adjacent characters take 1 AP Energy Damage, whether the result is a hit or miss.</li><li>MAG: The attack gains ARCING and deals Kinetic damage.</li></ul>",
        integrated: [
          "ms_walking_armory_1"
        ],
        exclusive: !0
      },
      {
        name: "Expanded Portfolio",
        description: "Upgrade your Ammo Case, gaining new ammunition types, each of which costs two charges rather than one.<br><ul><li>HELLFIRE (2 charges): The attack deals Energy damage and deals any bonus damage as Burn.</li><li>JAGER (2 charges): The attack gains KNOCKBACK 2, deals Explosive damage, and one character hit by the attack – your choice – must succeed on a HULL save or be knocked PRONE.</li><li>SABOT (2 charges): The attack gains AP and deals Kinetic damage.</li></ul>",
        integrated: [
          "ms_walking_armory_2"
        ],
        exclusive: !0
      },
      {
        name: "Efficiency",
        description: "Upgrade your Ammo Case again. If you perform a critical hit using ammunition from your Ammo Case, you don’t expend any charges. If your attack has more than one target, this effect only applies to the first attack roll you make.",
        integrated: [
          "ms_walking_armory_3"
        ],
        exclusive: !0
      }
    ]
  }
], require$$20 = [
  {
    id: "missing_mechweapon",
    name: "ERR: DATA NOT FOUND",
    mount: "Main",
    type: "Rifle",
    damage: [],
    range: [],
    tags: [],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "COMP/CON is unable to retrieve the data necessary to furnish this Weapon. This is likely the result of a missing or outdated content pack.",
    license_id: ""
  },
  {
    id: "mw_anti_materiel_rifle",
    name: "Anti-Materiel Rifle",
    mount: "Heavy",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 20
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_ap"
      },
      {
        id: "tg_loading"
      },
      {
        id: "tg_ordnance"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive” style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_assault_rifle",
    name: "Assault Rifle",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_reliable",
        val: 2
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_charged_blade",
    name: "Charged Blade",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: "1d3+3"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_ap"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-II (T-2) line displays GMS’s proprietary “charged” melee weapons and energy weapons. T-2 charged melee weapons are structurally similar to GMS’s T-1 melee weapons, though built with different materials to tolerate the intense heat generated by their projected plasma sheaths. These sheaths can be toggled on or off, depending on the needs of the pilot. GMS’s T-2 energy weapons, like their T-1 kinetics, are sturdy tools with predictable power scaling, minimal particle scattering, and consistent performance ranges. They feature universal ports allowing them to accept a variety of power sources, from hardline cabling through to “magazine” style power packs.",
    license_id: ""
  },
  {
    id: "mw_cyclone_pulse_rifle",
    name: "Cyclone Pulse Rifle",
    mount: "Superheavy",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "3d6+3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_loading"
      },
      {
        id: "tg_reliable",
        val: 5
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_heavy_charged_blade",
    name: "Heavy Charged Blade",
    mount: "Heavy",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: "1d6+3"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_ap"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-II (T-2) line displays GMS’s proprietary “charged” melee weapons and energy weapons. T-2 charged melee weapons are structurally similar to GMS’s T-1 melee weapons, though built with different materials to tolerate the intense heat generated by their projected plasma sheaths. These sheaths can be toggled on or off, depending on the needs of the pilot. GMS’s T-2 energy weapons, like their T-1 kinetics, are sturdy tools with predictable power scaling, minimal particle scattering, and consistent performance ranges. They feature universal ports allowing them to accept a variety of power sources, from hardline cabling through to “magazine” style power packs",
    license_id: ""
  },
  {
    id: "mw_heavy_machine_gun",
    name: "Heavy Machine Gun",
    mount: "Heavy",
    type: "Cannon",
    damage: [
      {
        type: "Kinetic",
        val: "2d6+4"
      }
    ],
    range: [
      {
        type: "Range",
        val: 8
      }
    ],
    tags: [
      {
        id: "tg_inaccurate"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_heavy_melee_weapon",
    name: "Heavy Melee Weapon",
    mount: "Heavy",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "2d6+1"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_howitzer",
    name: "Howitzer",
    mount: "Heavy",
    type: "Cannon",
    damage: [
      {
        type: "Explosive",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 20
      },
      {
        type: "Blast",
        val: 2
      }
    ],
    tags: [
      {
        id: "tg_arcing"
      },
      {
        id: "tg_inaccurate"
      },
      {
        id: "tg_loading"
      },
      {
        id: "tg_ordnance"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_missile_rack",
    name: "Missile Rack",
    mount: "Auxiliary",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      },
      {
        type: "Blast",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_loading"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_mortar",
    name: "Mortar",
    mount: "Main",
    type: "Cannon",
    damage: [
      {
        type: "Explosive",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      },
      {
        type: "Blast",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_arcing"
      },
      {
        id: "tg_inaccurate"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_nexus_hunter_killer",
    name: "Nexus (Hunter-Killer)",
    mount: "Main",
    type: "Nexus",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_smart"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_nexus_light",
    name: "Nexus (Light)",
    mount: "Auxiliary",
    type: "Nexus",
    damage: [
      {
        type: "Kinetic",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_smart"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_pistol",
    name: "Pistol",
    mount: "Auxiliary",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_reliable",
        val: 1
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_segment_knife",
    name: "Segment Knife",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_overkill"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_rocket_propelled_grenade",
    name: "Rocket-Propelled Grenade",
    mount: "Main",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      },
      {
        type: "Blast",
        val: 2
      }
    ],
    tags: [
      {
        id: "tg_loading"
      },
      {
        id: "tg_ordnance"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-III (T-3) line is made up of heavy weapons, ordnance, and other exotic, specialized, or massive weapons. A broad classification, the T-3 range includes conventional-kinetic anti-materiel rifles, super-rapid cycling pulse rifles, missile racks, cannons, and drone nexuses – “hive”style launchers that serve as miniature factory, hangar, and deployment systems for portable drones. The classification also includes the fearsome “segment knife”, a system that uses flash-printing to produce disposable edged weapons in a vicinity around the user.",
    license_id: ""
  },
  {
    id: "mw_shotgun",
    name: "Shotgun",
    mount: "Main",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_tactical_knife",
    name: "Tactical Knife",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_thrown",
        val: 3
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_tactical_melee_weapon",
    name: "Tactical Melee Weapon",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+2"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-I (T-1) line is defined by powerful, reliable, and conventional-kinetic ranged and melee weapons, including the GMS assault rifle, heavy machine gun, shotgun, pistol, and various light and heavy blades. Reliable galactic standards, the GMS T-1 line is the most widely used mech-scale line of weaponry across the galaxy. Echoing the Everest’s design notes, T-1 weapons are simply designed, with few (if any) moving parts, intended to be used in or adaptable to any environment.",
    license_id: ""
  },
  {
    id: "mw_thermal_lance",
    name: "Thermal Lance",
    mount: "Heavy",
    type: "Cannon",
    damage: [
      {
        type: "Energy",
        val: "1d6+3"
      }
    ],
    range: [
      {
        type: "Line",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-II (T-2) line displays GMS’s proprietary “charged” melee weapons and energy weapons.",
    license_id: ""
  },
  {
    id: "mw_thermal_pistol",
    name: "Thermal Pistol",
    mount: "Auxiliary",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: 2
      }
    ],
    range: [
      {
        type: "Line",
        val: 5
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-II (T-2) line displays GMS’s proprietary “charged” melee weapons and energy weapons.",
    license_id: ""
  },
  {
    id: "mw_thermal_rifle",
    name: "Thermal Rifle",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Energy",
        val: "1d3+2"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_ap"
      }
    ],
    source: "GMS",
    license: "GMS",
    license_level: 0,
    description: "Much like GMS mechs, GMS weapons are reliable galactic standards, made using interchangeable parts and built to withstand almost any conditions. There are three lines currently in production.<br>The Type-II (T-2) line displays GMS’s proprietary “charged” melee weapons and energy weapons.",
    license_id: ""
  },
  {
    id: "mw_chain_axe",
    name: "Chain Axe",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_reliable",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 1,
    on_crit: "Your target becomes Shredded until the end of the current turn.",
    description: "A simple tactical-scale version of a logging tool, IPS-N’s chain axe is a serrated chainblade run off core power. The axe’s teeth are tungsten-tipped, hardened to chew through both hard and soft targets. Chain axes are effective weapons and utility tools that are often used by boarding parties to breach reinforced bulkheads.",
    license_id: "mf_blackbeard"
  },
  {
    id: "mw_bristlecrown_flechette_launcher",
    name: "Bristlecrown Flechette Launcher",
    mount: "Auxiliary",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: 1
      }
    ],
    range: [
      {
        type: "Burst",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 2,
    effect: "This weapon ignores ranged penalties from Engaged, and deals 3 Kinetic damage to Grappled or Biological targets, instead of 1.",
    description: "The IPS-N Bristlecrown Flechette Launcher uses a hive-analogous mechanism to project a total soft-target kill zone in a dome around the user, proactively denying hostile infantry-tier actions.",
    license_id: "mf_blackbeard"
  },
  {
    id: "mw_nanocarbon_sword",
    name: "Nanocarbon Sword",
    mount: "Heavy",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+4"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 2
      }
    ],
    tags: [
      {
        id: "tg_reliable",
        val: 3
      }
    ],
    source: "IPS-N",
    license: "Blackbeard",
    license_level: 2,
    description: "IPS-N’s nanocarbon sword is a new spin on an old classic. Embedded nanosensors along the blade capture a full spectrum of data and transfer it to omninet storage banks for after-action review. Meanwhile, onboard software interprets the live feedback and adjusts the molecular composition of the blade edge in real time.",
    license_id: "mf_blackbeard"
  },
  {
    id: "mw_assault_cannon",
    name: "Assault Cannon",
    mount: "Main",
    type: "Cannon",
    source: "IPS-N",
    license: "Drake",
    license_level: 1,
    profiles: [
      {
        name: "Standard",
        damage: [
          {
            type: "Kinetic",
            val: "1d6+2"
          }
        ],
        range: [
          {
            type: "Range",
            val: 8
          }
        ],
        effect: "You can spin up this weapon’s barrels as a quick action.",
        actions: [
          {
            name: "Spin Up Assault Cannon",
            activation: "Quick",
            detail: 'Spin up the barrels of the Assault Cannon, Slowing your mech and allowing use of its "Spin-Up Mode" profile.'
          }
        ],
        tags: [
          {
            id: "tg_overkill"
          },
          {
            id: "tg_heat_self",
            val: 1
          }
        ]
      },
      {
        name: "Spin-Up Mode",
        damage: [
          {
            type: "Kinetic",
            val: "1d6+2"
          }
        ],
        range: [
          {
            type: "Range",
            val: 8
          }
        ],
        effect: "While spinning, this weapon gains Reliable 3, but you become Slowed.<br>You can end this effect as a protocol.",
        actions: [
          {
            name: "Cease Spin-Up",
            activation: "Protocol",
            detail: `End the Assault Cannon's "Spin-Up Mode", ending the Slowed condition and allowing the Assault Cannon to be used with its "Standard" profile.`
          }
        ],
        tags: [
          {
            id: "tg_overkill"
          },
          {
            id: "tg_heat_self",
            val: 1
          },
          {
            id: "tg_reliable",
            val: 3
          }
        ]
      }
    ],
    description: "IPS-N’s assault cannon of choice is a deep-cooled autocannon, fieldable as a mounted weapon or manipulator-operated platform. The cannon, simple in its functionality, can be fed by either box magazine or belt and is a standard inclusion in almost any among IPS-N fleet orders. In micro and zero-gravity environments, Drake pilots commonly employ the assault cannon as an additional propulsion system.",
    license_id: "mf_drake"
  },
  {
    id: "mw_concussion_missiles",
    name: "Concussion Missiles",
    mount: "Main",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_knockback",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Drake",
    license_level: 2,
    on_hit: "The target must succeed on a Hull save or become Impaired until the end of their next turn.",
    description: "Concussion missiles are fitted with overpressure-generating charges with low shatter and low incandescence – they’re meant to stun, deter, push back, and disorient, usually in tandem with a larger, more lethal attack.",
    license_id: "mf_drake"
  },
  {
    id: "mw_leviathan_heavy_assault_cannon",
    name: "Leviathan Heavy Assault Cannon",
    mount: "Superheavy",
    type: "Cannon",
    source: "IPS-N",
    license: "Drake",
    license_level: 3,
    profiles: [
      {
        name: "Standard",
        skirmish: !0,
        damage: [
          {
            type: "Kinetic",
            val: "1d6"
          }
        ],
        range: [
          {
            type: "Range",
            val: 8
          }
        ],
        effect: "Unlike other Superheavy weapons, the Leviathan can be used with Skirmish. You can spin up this weapon’s barrels as a quick action.",
        actions: [
          {
            name: "Spin Up Leviathan",
            activation: "Quick",
            detail: 'Spin up the barrels of the Leviathan Heavy Assault Cannon, Slowing your mech and allowing use of its "Spin-Up Mode" profile.'
          }
        ]
      },
      {
        name: "Spin-Up Mode",
        damage: [
          {
            type: "Kinetic",
            val: "4d6+4"
          }
        ],
        range: [
          {
            type: "Range",
            val: 8
          }
        ],
        effect: "While spinning, you are Slowed and can no longer use the Leviathan with Skirmish.<br>You can cease this effect as a protocol.",
        actions: [
          {
            name: "Cease Spin-Up",
            activation: "Protocol",
            detail: `End the Leviathan Heavy Assault Cannon's "Spin-Up Mode", ending the Slowed condition and allowing the Leviathan to be used with its "Standard" profile.`
          }
        ],
        tags: [
          {
            id: "tg_reliable",
            val: 5
          },
          {
            id: "tg_heat_self",
            val: 2
          }
        ]
      }
    ],
    description: "The Leviathan Heavy Assault Cannon (HAC) is a massive, multi-barrel rotary cannon fed by an external reservoir, usually dorsally mounted on the chassis carrying it. Unmodified, the Leviathan should only be fired within the recommended burst timing specifications to prevent percussive trauma to joints and pilots.<br>In partnership with Harrison Armory’s Think Tank, IPS-N is currently investigating remote solutions for the cannon’s ammunition consumption demands.",
    license_id: "mf_drake"
  },
  {
    id: "mw_cutter_mkii_plasma_torch",
    name: "Cutter MkII Plasma Torch",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: 1
      },
      {
        type: "Heat",
        val: 1
      },
      {
        type: "Burn",
        val: 1
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Lancaster",
    license_level: 3,
    effect: "This weapon deals 10AP energy to objects, cover, terrain, and the environment.",
    description: "Plasma cutters were tools first: simple blades built to toggle and sustain a plasma sheath, making it easier to cut metal. Repeated ad hoc use of cutters as personal defense weapons against pirate boarding parties convinced IPS-N of the need for a mil-spec variant of the civilian tool – the Cutter, now in its second generation. The Cutter MkII feeds directly from the mech’s power core, with a port to attach power packs in case of cord severance. Although the cutting edge can be shortened to a knife length, its most popular setting is the “cutlass”, a medium-length option perfect for balancing reach and maneuverability in close quarters.",
    license_id: "mf_lancaster"
  },
  {
    id: "mw_war_pike",
    name: "War Pike",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_knockback",
        val: 1
      },
      {
        id: "tg_thrown",
        val: 5
      }
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 1,
    description: "A war pike is a simple weapon – a long haft, topped with a dense, slim point, meant to puncture armor. Early designs were derivative of mining pylons, but the modern war pike is a sturdy, balanced, and reliable weapon that’s perfect for a charge.",
    license_id: "mf_nelson"
  },
  {
    id: "mw_power_knuckles",
    name: "Power Knuckles",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Explosive",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Nelson",
    license_level: 3,
    on_crit: "Your target must succeed on a Hull save or be knocked Prone.",
    description: "IPS-N’s line of power knuckles are another popular purchase for pilots who prefer to fight up close. Taking the form of anything from shaped studs to hyperdense knuckles, or a series of magnetically accelerated micro-rams, power knuckles amplify the already incredible hitting power of a mech.",
    license_id: "mf_nelson"
  },
  {
    id: "mw_hand_cannon",
    name: "Hand Cannon",
    mount: "Auxiliary",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_loading"
      },
      {
        id: "tg_reliable",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 1,
    description: "The IPS-N hand cannon is a licensed version of GMS’s Type-I Pistol, adapted for a much heavier caliber. This modification requires the belt-fed system of the GMS build to be swapped for a cylinder or magazine-based system, depending on the specific model of hand cannon.",
    license_id: "mf_raleigh"
  },
  {
    id: "mw_bolt_thrower",
    name: "Bolt Thrower",
    mount: "Heavy",
    type: "Cannon",
    damage: [
      {
        type: "Kinetic",
        val: "2d6"
      },
      {
        type: "Explosive",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 8
      }
    ],
    tags: [
      {
        id: "tg_loading"
      },
      {
        id: "tg_reliable",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 2,
    description: "As with many of IPS-N’s classic weapons, the bolt thrower is descended from a civilian mining tool. It fires self-propelled explosive bolts, perfect for use in micro- and null-gravity as well as in-atmosphere.",
    license_id: "mf_raleigh"
  },
  {
    id: "mw_kinetic_hammer",
    name: "Kinetic Hammer",
    mount: "Heavy",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "2d6+2"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_reliable",
        val: 4
      }
    ],
    source: "IPS-N",
    license: "Raleigh",
    license_level: 3,
    description: "A kinetic hammer is a simple tool, but a brutal one. Made up of a supermassive head fused to a long haft, the hammer carries enough force to create massively traumatic pressure waves upon landing a successful blow.",
    license_id: "mf_raleigh"
  },
  {
    id: "mw_deck_sweeper_automatic_shotgun",
    name: "Deck-Sweeper Automatic Shotgun",
    mount: "Main",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 3
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_inaccurate"
      }
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 1,
    description: "The Deck-Sweeper Automatic Shotgun is a belt-fed scattergun, a favorite of marine pilots aboard stations and capital ships. Its methodology is straightforward: charge, point, and fire. A single-barrel constriction allows for pneumatic absorption – dampening the effect of its incredible recoil – and its belt feeder is compatible with many types of shot-and-slug ammunition.",
    license_id: "mf_tortuga"
  },
  {
    id: "mw_daisy_cutter",
    name: "Daisy Cutter",
    mount: "Heavy",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "3d6"
      }
    ],
    range: [
      {
        type: "Cone",
        val: 7
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 2
      }
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 2,
    on_attack: "Creates a cloud of smoke and detritus in the attack cone, providing soft cover in the affected area that lasts until the end of your next turn.",
    description: "The Daisy Cutter is an effective weapon – if outdated – that’s still favored by many marine pilots. Essentially, it’s a massive shotgun; the pilot loads a charge into the gun’s breech, drops a packed sabot down the barrel, aims, and fires a hellfire cloud of flechette darts, bearings, and ignited magnesium strips, guaranteed to clear any deck on which it’s been fired.",
    license_id: "mf_tortuga"
  },
  {
    id: "mw_catalytic_hammer",
    name: "Catalytic Hammer",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d3+5"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_loading"
      }
    ],
    source: "IPS-N",
    license: "Tortuga",
    license_level: 2,
    on_crit: "Your target must succeed on a Hull save or become Stunned until the end of their next turn.",
    description: "Modified originally from blast-mining equipment, the catalytic hammer (colloquially, the “pilebunker”) has since been refined into a formidable melee weapon. When fired, a charge propels the hammer – a solid cylinder with a spike on one end – through a short barrel, impacting with enormous kinetic force. Standard hammer heads are smooth to allow for easy extraction from targets, but they can be detached and replaced if retrieval is impossible. Any installation of a catalytic hammer necessitates superstructure reinforcement to allow for sufficient energy dispersal.",
    license_id: "mf_tortuga"
  },
  {
    id: "mw_impact_lance",
    name: "Impact Lance",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 3
      }
    ],
    source: "IPS-N",
    license: "Vlad",
    license_level: 1,
    on_attack: "You also attack all characters in a Line between you and your target. You take 1 heat for each target past the first.",
    description: "The impact lance is a mil-spec variant of a common mining tool: the single-use chemical survey laser. IPS-N’s military variant mounts a series of impact lances on a mech’s brachial or thoracic carriages, leaving its manipulators free to field other weapons and systems. It can be wired directly into a chassis’ core, or charged with disposable chemical batteries.<br>The lance array fires for a microsecond, burning through its stored charge to produce an intense burst of light that stabs out in a tight, pulsed beam capable of searing through meters of hardened bulkhead.",
    license_id: "mf_vlad"
  },
  {
    id: "mw_impaler_nailgun",
    name: "Impaler Nailgun",
    mount: "Main",
    type: "CQB",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "IPS-N",
    license: "Vlad",
    license_level: 2,
    on_hit: "Targets must succeed on a Hull save or become Immobilized until the end of their next turn.",
    description: "The Impaler’s noncombustible, sabot-jacketed two-stage macroflechettes can pierce even the heaviest armor. Once catapulted from its launcher, the sabot disengages on approach to its target and triggers a second stage – internal propulsion drives the macroflechette forward with incredible velocity. Over-penetration is certain against soft targets; IPS-N advises firing this weapon only when the area behind the target is clear of allies or noncombatants.",
    license_id: "mf_vlad"
  },
  {
    id: "mw_combat_drill",
    name: "Combat Drill",
    mount: "Superheavy",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "3d6"
      },
      {
        type: "Energy",
        val: "1d6"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_ap"
      },
      {
        id: "tg_overkill"
      }
    ],
    source: "IPS-N",
    license: "Vlad",
    license_level: 3,
    effect: "When attacking a character that is Prone, Immobilized, or Stunned, this weapon’s Overkill tag does an extra +1d6 bonus damage each time it activates. This can activate indefinitely if the new bonus die result is a 1, triggering Overkill again.",
    description: "The combat drill is a brutal close-combat weapon, powered by a massive external catalyst pack. The bit is tipped with microplasmatic projectors designed to pre-treat the target and ensure drill penetration.",
    license_id: "mf_vlad"
  },
  {
    id: "mw_magnetic_cannon",
    name: "Magnetic Cannon",
    mount: "Main",
    type: "Cannon",
    damage: [
      {
        type: "Energy",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Line",
        val: 8
      }
    ],
    source: "SSC",
    license: "Black Witch",
    license_level: 1,
    on_hit: "All characters within the affected area must succeed on a Hull save or be pulled 1d3+1 spaces toward you, or as close as possible.",
    description: "SSC’s magnetic cannon is a first from the Exotic Materials Group: an aperture-focused electromagnetic projection beam that uses intense pulses of magnetic energy to disrupt and damage hardware. Targets caught in the beam of a magnetic cannon suffer additional damage to their software as massive systemic stress is inflicted on sensitive components.",
    license_id: "mf_black_witch"
  },
  {
    id: "mw_vulture_dmr",
    name: "Vulture DMR",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_overkill"
      },
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "SSC",
    license: "Death’s Head",
    license_level: 2,
    description: "The Vulture Designated Marksman Rifle (DMR) is SSC’s core battle rifle. Reliable, available in dozens of configurations and calibers, and fed by box, drum, or belt, the Vulture is a popular armament across a wide range of mechs.",
    license_id: "mf_deaths_head"
  },
  {
    id: "mw_railgun",
    name: "Railgun",
    mount: "Heavy",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+4"
      }
    ],
    range: [
      {
        type: "Line",
        val: 20
      }
    ],
    tags: [
      {
        id: "tg_ap"
      },
      {
        id: "tg_ordnance"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Death’s Head",
    license_level: 3,
    description: "Railguns are simple, elegant weapons. With magnetically accelerated projectiles and no moving parts, they are effective in any theater and entirely self-contained within disposable units. This efficacy comes at a cost: railguns have massive power draw, making it necessary for wielders to carry core-charged auxiliary power translation packs.",
    license_id: "mf_deaths_head"
  },
  {
    id: "mw_veil_rifle",
    name: "Veil Rifle",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Energy",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Line",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 1,
    effect: "This weapon does not attack allied characters caught in its area of effect; instead, it shrouds them in a field of coruscating energy that throws off targeting systems, giving them soft cover until the end of their next turn.",
    description: "“We made first contact maybe an hour after breaching the vault. I remember nothing of it. I’m told most of my squad was killed outright; all I remember is light – brilliant – and a lightness in my own being.<br>“I do believe that I died in that moment, and yet I’m here, and I can’t square these two realities. Something has gone wrong, something has gone wrong, something has gone–”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "mw_burst_launcher",
    name: "Burst Launcher",
    mount: "Main",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "1d3"
      },
      {
        type: "Heat",
        val: 1
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_arcing"
      }
    ],
    source: "SSC",
    license: "Dusk Wing",
    license_level: 2,
    on_crit: "Target becomes Impaired until the end of their next turn.",
    description: "“Yes, they could die. We killed many of them – blew them away with burst launchers and cannons. I don’t think they mattered to it. Not like insects; not like that… there’s still a use for insects: as food, as necessary components in an ecosystem. Their deaths slowed us, but it didn’t command them to slow us. Even when we breached the last chamber and saw it, I don’t even think it recognized we were there.”",
    license_id: "mf_dusk_wing"
  },
  {
    id: "mw_rail_rifle",
    name: "Rail Rifle",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Line",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 2,
    description: "Rail rifles are popular weapons for use in all theaters, but they are the only choice for pilots operating in atmospheres made up of highly combustible gases. They use a line of cascading electromagnets to accelerate small projectiles at tremendous speeds, firing without the need for combustion.<br>Like other rail weapons, rail rifles are quiet in comparison to their traditional counterparts, although massive power requirements make it difficult to mask their energy signatures.",
    license_id: "mf_metalmark"
  },
  {
    id: "mw_shock_knife",
    name: "Shock Knife",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: 1
      },
      {
        type: "Burn",
        val: 2
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_thrown",
        val: 5
      },
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "SSC",
    license: "Metalmark",
    license_level: 2,
    description: "Shock knives are short, powered blades designed for integration with Shock Wreaths, a popular post-fab modification. The knives are custom-sculpted by SSC’s Terashima artisan enclave, each one bearing the unique hash-stamp of its designer. Part of SSC’s LUX-Iconic line – a civilian-accessible track of the BELLA CIAO line – each shock knife print code allows only a single use. If lost, pilots must submit an apology and request in writing explaining the circumstances of the loss in order to receive another code.",
    license_id: "mf_metalmark"
  },
  {
    id: "mw_sharanga_missiles",
    name: "Sharanga Missiles",
    mount: "Main",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: 3
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_arcing"
      }
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 1,
    effect: "This weapon can attack two targets at a time.",
    description: "“It was a duel. This is why they were made: to duel, and in that combat, to shake the pillars of the universe.” — “Notes for Young John”,  Ministrations of the Master Teacher",
    license_id: "mf_monarch"
  },
  {
    id: "mw_gandiva_missiles",
    name: "Gandiva Missiles",
    mount: "Heavy",
    type: "Launcher",
    damage: [
      {
        type: "Energy",
        val: "1d6+3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_seeking"
      },
      {
        id: "tg_smart"
      }
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 2,
    description: "Gandiva missiles are a reliable mainstay from Smith-Shimano’s BELLA CIAO line. Like the heavier Pinaka, the Gandiva is equipped with jet-assisted midflight repositioning systems, enhancing target navigation in rapidly changing battlefield environments. The Gandiva’s delivery platform is administered by a hivemind COMP/CON drone AI, giving it the capacity to learn from each right-of-launch experience.",
    sp: 1,
    license_id: "mf_monarch"
  },
  {
    id: "mw_pinaka_missiles",
    name: "Pinaka Missiles",
    mount: "Superheavy",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 20
      },
      {
        type: "Blast",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_arcing"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "SSC",
    license: "Monarch",
    license_level: 3,
    effect: "Attacks with this weapon create up to two blast 1 areas, which cannot overlap.<br>You may also delay the impact of attacks made with this weapon. Choose the target area(s), which become visible to all characters: the missiles land at the end of the next round, after all characters have acted, and deal 3d6 explosive damage instead of 2d6, but you become Slowed until the end of your next turn.",
    description: "Pinaka missiles are massive, two-stage missiles typically mounted along a mech’s spine or carried, disassembled, to be launched from a brachial mount. The Pinaka was originally adapted from ship-to-ship missiles; as such, their second stage uses jet-assist repositioning for midflight orientation.",
    license_id: "mf_monarch"
  },
  {
    id: "mw_fold_knife",
    name: "Fold Knife",
    mount: "Auxiliary",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 1,
    on_crit: "You may teleport 2 spaces in any direction after the attack resolves.",
    description: ">//[Am I alone here?]<br>>//[[No. There is only an absence of you. It is very busy here, but you cannot see it]]<br>— DHIYED fragment tablet 1.3",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "mw_vijaya_rockets",
    name: "Vijaya Rockets",
    mount: "Auxiliary",
    type: "Launcher",
    damage: [
      {
        type: "Explosive",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 1,
    description: "Intended for use as force multipliers in close-range engagements, Vijaya rockets are miniaturized rockets launched from a drum-fed launcher. On detonation, the rockets’ shaped charges project the blast forward, away from the user.",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "mw_variable_sword",
    name: "Variable Sword",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: 3
      }
    ],
    range: [
      {
        type: "Threat",
        val: 2
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      }
    ],
    source: "SSC",
    license: "Mourning Cloak",
    license_level: 3,
    on_crit: "Deal +1d6 bonus damage.",
    description: "The variable sword is a Smith-Shimano hallmark: a length of razor-sharp molecular wire attached to a handle and locked in place by a magnetic field, variable swords are invisible to the naked eye until they cut into their target. Designed in the early days of interstellar travel, variable swords were meant to allow for the precise gathering of samples, while also reducing the overall burden on a mech’s core.",
    license_id: "mf_mourning_cloak"
  },
  {
    id: "mw_oracle_lmg_i",
    name: "Oracle LMG-I",
    mount: "Auxiliary",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_arcing"
      }
    ],
    source: "SSC",
    license: "Swallowtail",
    license_level: 2,
    description: "The Oracle Indirect Light Machine Gun (designated O/LMG-I) packs a subsentient, high-volume DOWNPOUR static quad-barrel system into a single cylinder typically installed on the dorsal panel of a chassis. Paired with a firing system, the Oracle is capable of directing persistent defilade-ignorant kinetic fire at targets.",
    sp: 1,
    license_id: "mf_swallowtail"
  },
  {
    id: "mw_nanobot_whip",
    name: "Nanobot Whip",
    mount: "Heavy",
    type: "Melee",
    damage: [
      {
        type: "Kinetic",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_smart"
      }
    ],
    source: "HORUS",
    license: "Balor",
    license_level: 3,
    on_crit: "Pull your target to a free space adjacent to you, or as close as possible.",
    description: "Using swarm-coding and legion directives, HORUS collectivists created a framework to organize a swarm of nanites into a whip-like weapon. Nanobot whips can retract into their base blister for stowing, detach in melee combat to restrain nearby enemies, and return to their base unit when summoned.",
    sp: 2,
    license_id: "mf_balor"
  },
  {
    id: "mw_swarm_hive_nanites",
    name: "Swarm/Hive Nanites",
    mount: "Main",
    type: "Nexus",
    damage: [
      {
        type: "Kinetic",
        val: 2
      },
      {
        type: "Burn",
        val: 2
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_smart"
      },
      {
        id: "tg_seeking"
      }
    ],
    source: "HORUS",
    license: "Balor",
    license_level: 3,
    description: "SWARM/HIVE nanites are among the more insidious weapons produced by HORUS: dispatched in maniples – single “swarm” units carrying enough nanites to fill a square meter – SWARM/HIVE nanites combine the systemic invasion properties of BOOST/HIVE code with the aggressive consumption of a CONSUME/HIVE maniple. Launched from mounted blisters, SWARM/HIVE nanite maniples fall upon their targets as great clouds of teeth, infiltrating sensitive compartments and modules before consuming any organic and inorganic material they touch.",
    license_id: "mf_balor"
  },
  {
    id: "mw_autopod",
    name: "Autopod",
    mount: "Main",
    type: "Launcher",
    no_attack: !0,
    damage: [
      {
        type: "Kinetic",
        val: 3
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_seeking"
      },
      {
        id: "tg_unique"
      }
    ],
    source: "HORUS",
    license: "Goblin",
    license_level: 1,
    effect: "Instead of using any kind of trigger mechanism, this weapon automatically scans for target locks, firing spinning, razor-sharp disks upon successful IDs. Gain the Autonomous Assault reaction, which is the only way you can attack with the Autopod",
    actions: [
      {
        name: "Autonomous Assault",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "Another character attacks a target within range 15 of you and consumes Lock On",
        detail: "You may automatically hit their target with the Autopod."
      }
    ],
    description: "The autopod is a small antipersonnel weapon apparently devised by HORUS communocyphers to continue offensive action in the event of its operator’s death. Each unit is, in theory, governed by a spur of INSTINCT’s protomind. No new models have been encountered since DHIYED, and all extant versions of the Autopod are to be considered extremely dangerous as the INSTINCT code powering their onboard protominds is likely to have corrupted further since their creation.",
    sp: 1,
    license_id: "mf_goblin"
  },
  {
    id: "mw_vorpal_gun",
    name: "Vorpal Gun",
    mount: "Main",
    type: "Cannon",
    no_attack: !0,
    damage: [
      {
        type: "Kinetic",
        val: "2d6"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    source: "HORUS",
    license: "Gorgon",
    license_level: 3,
    effect: "Gain the Snicker-Snack reaction, which is the only way you can attack with this weapon.",
    actions: [
      {
        name: "Snicker-Snack",
        activation: "Reaction",
        frequency: "1/round",
        trigger: "A hostile character within Range of the Vorpal Gun and line of sight deals damage to an allied character.",
        detail: "You may make an attack against the hostile character with the Vorpal Gun."
      }
    ],
    description: "DO NOT STARE DIRECTLY INTO THE APERTURE.",
    license_id: "mf_gorgon"
  },
  {
    id: "mw_ghoul_nexus",
    name: "Ghoul Nexus",
    mount: "Main",
    type: "Nexus",
    damage: [
      {
        type: "Variable",
        val: "1d3+2"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_smart"
      },
      {
        id: "tg_set_damage_type"
      }
    ],
    source: "HORUS",
    license: "Hydra",
    license_level: 1,
    on_attack: "Choose this weapon’s damage type.",
    description: "Ghoul nexuses command some of the largest viable drones in modern combat. These drones are slightly smaller than an average human—metal cylinders bristling with hardpoints suitable for most infantry-level anti-mech weapons. Propelled by VTOL/hover-capable jet systems, Ghoul drones are fearsome, all-theater autonomous units that are difficult to track and take down.",
    license_id: "mf_hydra"
  },
  {
    id: "mw_ghast_nexus",
    name: "Ghast Nexus",
    mount: "Heavy",
    type: "Nexus",
    damage: [
      {
        type: "Explosive",
        val: "1d6+3"
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_smart"
      }
    ],
    source: "HORUS",
    license: "Hydra",
    license_level: 2,
    effect: "This weapon may be used to attack as normal, or deployed as a Drone",
    deployables: [
      {
        name: "Ghast Drone",
        type: "Drone",
        activation: "Free",
        recall: "Quick",
        redeploy: "Quick",
        size: 0.5,
        hp: 5,
        armor: 2,
        edef: 10,
        evasion: 10,
        detail: "This Ghast nexus can be deployed to a free space within Sensors and line of sight as a free action, where it becomes a stationary, hovering Drone. Once deployed, you may still use it for Skirmish and Barrage attacks as though it is still a weapon, but with line of sight and Range traced from its location.<br>You may recall or redeploy the Ghast nexus as a quick action. Until recalled or destroyed, it remains deployed until the end of the scene. If destroyed, it follows the rules for destroyed Drones and can’t be used until repaired."
      }
    ],
    description: "The Ghast is an up-armored, up-armed version of the smaller Ghoul drone; Ghast drones boast an upgraded flight system capable of wielding mech-tier weapons within optimum parameters, and can operate independently from their host chassis or as an integrated weapon. In Hydras, Ghast drones generally act as thoracic segments, providing armor to core systems: powerplant, cockpit, NHP caskets, etc.",
    license_id: "mf_hydra"
  },
  {
    id: "mw_annihilation_nexus",
    name: "Annihilation Nexus",
    mount: "Superheavy",
    type: "Nexus",
    damage: [
      {
        type: "Energy",
        val: "1d6+3"
      }
    ],
    range: [
      {
        type: "Burst",
        val: 2
      }
    ],
    tags: [
      {
        id: "tg_ap"
      },
      {
        id: "tg_smart"
      }
    ],
    source: "HORUS",
    license: "Hydra",
    license_level: 3,
    on_attack: "You can make a second attack with this weapon at the start of your next turn as a protocol. This secondary attack can’t deal bonus damage, and doesn't trigger additional secondary attacks.<br>You may center this weapon’s attack on either yourself or any of your Drones within Sensors.",
    actions: [
      {
        name: "Annihilation Nexus Secondary Attack",
        activation: "Protocol",
        detail: "If you made an attack with the Annihilation Nexus on your last turn, you can make a second attack with this weapon. This secondary attack can’t deal bonus damage, and doesn't trigger additional secondary attacks.<br>You may center this weapon’s attack on either yourself or any of your Drones within Sensors."
      }
    ],
    description: "“A storm of bladed death” – nanites organized into maniples, released from a chassis’ onboard nexuses or single-use firing tubes in a burst of filament rings so sharp they slice away at their targets on the molecular level. The visual effect of a maniple being launched is often compared to tinsel being fired through atmosphere.",
    license_id: "mf_hydra"
  },
  {
    id: "mw_catalyst_pistol",
    name: "Catalyst Pistol",
    mount: "Auxiliary",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: "1d3"
      }
    ],
    range: [
      {
        type: "Cone",
        val: 3
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 1,
    description: "“Burn, thou fiend, before the fire of the Eye of RA!”",
    license_id: "mf_manticore"
  },
  {
    id: "mw_arc_projector",
    name: "Arc Projector",
    mount: "Heavy",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: "1d6+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "HORUS",
    license: "Manticore",
    license_level: 2,
    on_hit: "You may also make a secondary attack against a different character within range 3 of the first target. You can continue making secondary attacks on hits, as long as there are new, valid targets within range; however, each attack generates 1 heat, and secondary attacks can’t deal bonus damage. Characters can’t be hit more than once with the same firing of this weapon.",
    description: "“Fire be upon thee, APEP! Thy flesh is seared from thy bones; The Lord of the Duat will never enable thy shade to rise again!”",
    license_id: "mf_manticore"
  },
  {
    id: "mw_smartgun",
    name: "Smartgun",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Kinetic",
        val: 4
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_accurate"
      },
      {
        id: "tg_seeking"
      },
      {
        id: "tg_smart"
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 1,
    description: "“Smart weapon” is a broad term that describes any and all weapons capable of interacting with onboard systems in order to boost their combat efficacy. Smartguns are weapons that come pre-loaded with companion software and the necessary hardware in order to interact with targeting systems and host NHPs. A popular addition to many HORUS mechs, smart weapons make for reliable kinetic delivery systems.",
    sp: 2,
    license_id: "mf_pegasus"
  },
  {
    id: "mw_mimic_gun",
    name: "Mimic Gun",
    mount: "Heavy",
    type: "???",
    no_mods: !0,
    no_core_bonus: !0,
    damage: [
      {
        override: !0,
        type: "Kinetic",
        val: "???"
      }
    ],
    range: [
      {
        override: !0,
        type: "Range",
        val: "???"
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 2,
    effect: "This horrifying weapon has no basic form; it constantly contorts itself into different shapes, mimicking the weapons of other combatants. It counts as all ranged weapon types simultaneously (e.g., CQB, Rifle, etc.), but it can’t take Mods or benefit from core bonuses, although it still benefits from talents as normal.<br>At the start of combat, roll 3d20 and note the results in order: X, Y, and Z. X is its starting base Range (before modifications from talents). At the start of each of your turns after the first, the mimic gun cycles to the next result, taking that as its base Range. After Z, it cycles back to X.<br>The mimic gun does kinetic equal to 1 + half of its current base Range.<br>You may provoke the mimic gun as a full action, rolling a new set of 3d20.",
    actions: [
      {
        name: "Provoke Mimic Gun",
        activation: "Full",
        detail: "Roll a new set of 3d20 to set the Mimic Gun's values."
      }
    ],
    description: "This is not a gun.",
    license_id: "mf_pegasus"
  },
  {
    id: "mw_autogun",
    name: "Autogun",
    mount: "Main",
    type: "Cannon",
    no_attack: !0,
    no_synergies: !0,
    damage: [
      {
        type: "Kinetic",
        val: 3
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    source: "HORUS",
    license: "Pegasus",
    license_level: 3,
    actions: [
      {
        name: "Fire Autogun",
        activation: "Free",
        detail: "This weapon can’t make normal attacks. Instead, you can attack with it as a free action at the end of your turn. It doesn’t benefit from or trigger your talents."
      }
    ],
    effect: "This weapon can’t make normal attacks. Instead, you can attack with it as a free action at the end of your turn. It doesn’t benefit from or trigger your talents.",
    description: "As the name implies, autoguns are automated weapons. Similar to point-defense systems, autoguns are chambered to provide effective fire against armored targets. Typically mounted on a stabilized, secondary arm, a reliably tuned autogun can be trusted to track and eliminate designated enemy units while a pilot concentrates on more specialized weapons or processes. Cheap, with malleable codebases, autoguns are common among active, armed HORUS cells.",
    sp: 1,
    license_id: "mf_pegasus"
  },
  {
    id: "mw_siege_cannon",
    name: "Siege Cannon",
    mount: "Superheavy",
    type: "Cannon",
    source: "HA",
    license: "Barbarossa",
    license_level: 3,
    profiles: [
      {
        name: "Siege Mode",
        range: [
          {
            type: "Range",
            val: 30
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "3d6"
          }
        ],
        on_attack: "Choose to fire in either siege mode or direct fire mode.",
        tags: [
          {
            id: "tg_arcing"
          },
          {
            id: "tg_ordnance"
          },
          {
            id: "tg_loading"
          },
          {
            id: "tg_heat_self",
            val: 4
          }
        ]
      },
      {
        name: "Direct Fire Mode",
        range: [
          {
            type: "Range",
            val: 20
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "3d6"
          }
        ],
        on_attack: "Choose to fire in either siege mode or direct fire mode.",
        tags: [
          {
            id: "tg_knockback",
            val: 2
          },
          {
            id: "tg_heat_self",
            val: 2
          }
        ]
      }
    ],
    description: "The siege cannon is the Armory’s quintessential artillery piece: a howitzer cannon fed by an automated loading system. Typically mounted on long-range mechs deployed in artillery or squad-support roles, siege cannons are capable of both indirect and direct fire as the situation demands with variable ammunition options.",
    license_id: "mf_barbarossa"
  },
  {
    id: "mw_krakatoa_thermobaric_flamethrower",
    name: "Krakatoa Thermobaric Flamethrower",
    mount: "Heavy",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: 1
      },
      {
        type: "Burn",
        val: 4
      }
    ],
    range: [
      {
        type: "Cone",
        val: 5
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 1,
    description: "Between the thick arboreal environment of Hercynia, the swarm tactics of the Egregorians, and the ineffectual performance of slug ammunition, the need for wide-effect weapons was apparent. GMS quick developed the Krakatoa – a thermobaric flamethrower – and disseminated it to affiliates. The Krakatoa was quickly adopted by Union’s Marine Expeditionary Forces, seeing heavy use in the depths of the Hercynian continental jungles thanks to its stability, reliability, and stopping power.<br>Later reworked and adopted by the Armory following the resolution of the Hercynian Crisis, the Krakatoa has become a popular tool for the creation of area-of-denial firebreaks.",
    license_id: "mf_genghis"
  },
  {
    id: "mw_plasma_thrower",
    name: "Plasma Thrower",
    mount: "Superheavy",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: "1d6+2"
      },
      {
        type: "Burn",
        val: 6
      }
    ],
    range: [
      {
        type: "Cone",
        val: 7
      },
      {
        type: "Line",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 4
      }
    ],
    source: "HA",
    license: "Genghis",
    license_level: 3,
    effect: "Can be fired as Cone 7 <i>or</i> Line 10",
    on_attack: "White-hot flames continue to burn in 3 free spaces of your choice within the affected area, lasting for the rest of the scene. When characters start their turn in one of these spaces or enter one for the first time in a round, they take 1d6 energy damage.",
    description: "The plasma thrower emerged too late in the Hercynian Crisis to see widespread use in the field. The scarce data gathered from the MEF squadrons that used it suggest that plasma throwers would have had a tremendous impact on the outcomes of several major battles that occurred during the bloodiest phase of the Crisis.",
    license_id: "mf_genghis"
  },
  {
    id: "mw_stub_cannon",
    name: "Stub Cannon",
    mount: "Auxiliary",
    type: "Cannon",
    damage: [
      {
        type: "Explosive",
        val: 3
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 6
      },
      {
        id: "tg_knockback",
        val: 1
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 1,
    description: "The stub cannon is a supercompact rotary cannon – short-range, but suitable for integration into hardpoints and manipulators.",
    license_id: "mf_iskander"
  },
  {
    id: "mw_gravity_gun",
    name: "Gravity Gun",
    no_mods: !0,
    no_core_bonus: !0,
    mount: "Heavy",
    type: "Rifle",
    damage: [],
    range: [
      {
        type: "Range",
        val: 8
      },
      {
        type: "Blast",
        val: 3
      }
    ],
    source: "HA",
    license: "Iskander",
    license_level: 2,
    on_attack: "Characters within the affected area must succeed on a Hull save or take 1d6 energy damage and be pulled as close to the center of the blast possible. This weapon cannot be modified or benefit from core bonuses.",
    description: "“The complex negotiations of gravity and time, shattered in an instant by a machine that can pluck waves like a player strums the strings of a guitar.<br>We’ve weaponized the force that holds all things in its embrace. What could go wrong?”",
    license_id: "mf_iskander"
  },
  {
    id: "mw_displacer",
    name: "Displacer",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Energy",
        val: 10
      }
    ],
    range: [
      {
        type: "Range",
        val: 10
      },
      {
        type: "Blast",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_ap"
      },
      {
        id: "tg_loading"
      },
      {
        id: "tg_unique"
      },
      {
        id: "tg_heat_self",
        val: 10
      }
    ],
    source: "HA",
    license: "Napoleon",
    license_level: 3,
    description: "The Displacer is the result of ongoing blinkspace exposure tests and refinement of standard interstellar travel methods. In terms of appearance, the Displacer could be mistaken for a conventional energy rifle, but it requires a massive secondary, dorsal-mounted reactor: when fired, the Displacer identifies a bubble of local space (size and location determined on an ad hoc basis by the user) and snaps it into blinkspace. The destination of the bubble is unknown, but the effect is dramatic: anything inside simply ceases to exist in this dimension, transported somewhere in the void of blinkspace. The Displacer makes no sound when fired, but the sudden and necessary venting of its power supply is tremendous; similarly, the heatwave of its backblast vent is deadly to any unshielded personnel exposed to it.",
    license_id: "mf_napoleon"
  },
  {
    id: "mw_shatterhead_colony_missiles",
    name: "Shatterhead Colony Missiles",
    mount: "Main",
    type: "Launcher",
    damage: [
      {
        type: "Energy",
        val: "1d3+1"
      }
    ],
    range: [
      {
        type: "Range",
        val: 15
      }
    ],
    tags: [
      {
        id: "tg_arcing"
      }
    ],
    source: "HA",
    license: "Saladin",
    license_level: 1,
    effect: "The final attack roll for this weapon can never be affected by difficulty.",
    description: "Developed following costly urban and naval boarding engagements in the Interest War, Shatterhead Colony Missiles are now a standard part of the arsenal fielded by Armory interdiction teams. When they reach an optimal distance, Shatterheads break open in a burst of high-catalyst fuel to reveal a cluster of small thermobaric pellets that spread out and ignite, choking the affected area with flame. The effect overloads energy shielding and saturates cover, though only a small percent of the projectiles actually reach their target.",
    sp: 1,
    license_id: "mf_saladin"
  },
  {
    id: "mw_sol_pattern_laser_rifle",
    name: "SOL-Pattern Laser Rifle",
    mount: "Main",
    type: "Rifle",
    damage: [
      {
        type: "Energy",
        val: "1d6"
      },
      {
        type: "Burn",
        val: 1
      }
    ],
    range: [
      {
        type: "Range",
        val: 8
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 1
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 1,
    description: "Laser rifles contain a series of apertures and lenses that amplify and focus light into tight beams, sometimes visible, that heat the zone of impact for long enough to turn it into plasma. The SOL-Pattern Laser Rifle consistently outputs 3.5 petawatts, pulsed, but can also project a steady beam at lower power levels. The SOL is entirely self-contained but can be patched into a mech’s reactor core for emergency recharge.<br>Although some laser rifles double as communications and data-transfer devices, the SOL is strictly suitable for combat applications.",
    license_id: "mf_sherman"
  },
  {
    id: "mw_andromeda_pattern_heavy_laser_rifle",
    name: "ANDROMEDA-Pattern Heavy Laser Rifle",
    mount: "Heavy",
    type: "Cannon",
    damage: [
      {
        type: "Energy",
        val: "2d6"
      },
      {
        type: "Burn",
        val: 3
      }
    ],
    range: [
      {
        type: "Range",
        val: 12
      }
    ],
    tags: [
      {
        id: "tg_heat_self",
        val: 3
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 2,
    description: "The Harrison Armory ANDROMEDA-Pattern Heavy Laser Rifle scales up the SOL by half, adding a second projector that can fire independently, synchronized, or in alternating patterns and wavelengths with the primary projector. The effect overwhelms most shields, but the power draw necessary makes this weapon impractical on platforms without the necessary heat reduction and dispersal to manage the incredible cost.",
    license_id: "mf_sherman"
  },
  {
    id: "mw_tachyon_lance",
    name: "Tachyon Lance",
    mount: "Superheavy",
    type: "Cannon",
    damage: [
      {
        type: "Energy",
        val: "2d6"
      },
      {
        type: "Burn",
        val: 8
      }
    ],
    range: [
      {
        type: "Range",
        val: 20
      }
    ],
    tags: [
      {
        id: "tg_ordnance"
      },
      {
        id: "tg_heat_self",
        val: 4
      }
    ],
    source: "HA",
    license: "Sherman",
    license_level: 3,
    on_attack: "If you’re in the Danger Zone, create a cone 3 backblast of burning plasma in the opposite direction to the attack. Characters within the affected area must succeed on an Engineering save or take 4 burn and 2 heat. Until the start of your next turn, the affected area provides soft cover.",
    description: "Tachyon lances are the weaponized results of joint IPS-N and Harrison Armory experiments into faster-than-light travel. Rendered obsolete by subsequent developments in blinkspace travel (and the difficulty of ensuring corporeal passenger survival), the Armory’s tachyon accelerators were mothballed until Think Tank engineers realized their potential application as weapons. Tachyon lances project tachyon particles – essentially subatomic localized objects – faster than light toward their targets. These particles are impossible to perceive optically, and because they travel faster than light, can’t be seen or evaded. Although the particles are tiny, they travel with colossal speed and energy. The damage a tachyon lance deals to its target – should it hit – is unparalleled.",
    license_id: "mf_sherman"
  },
  {
    id: "mw_annihilator",
    name: "Annihilator",
    mount: "Main",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: "1d3+2"
      }
    ],
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_ap"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 1,
    on_hit: "Make a secondary attack against all characters within burst 1 of the target. These attacks can’t deal bonus damage, and don’t trigger the Annihilator’s heat cost or secondary attacks.",
    description: "Harrison Armory is known to employ somewhat unconventional development methods: tactical solutions are theorized and designed in the field as often as they are in the lab, with the former often outperforming the latter. The Annihilator’s name comes from pilots’ slang for a jury-rigged weapon first improvised in the Bradbury Rebellion, when desperate resistance pilots found a way to shunt the incredible waste heat from their reactors into a directed blast.",
    license_id: "mf_tokugawa"
  },
  {
    id: "mw_torch",
    name: "Torch",
    mount: "Main",
    type: "Melee",
    damage: [
      {
        type: "Energy",
        val: "1d6"
      },
      {
        type: "Burn",
        val: 3
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      }
    ],
    tags: [
      {
        id: "tg_overkill"
      },
      {
        id: "tg_heat_self",
        val: 2
      }
    ],
    source: "HA",
    license: "Tokugawa",
    license_level: 2,
    description: "The Torch is a potent weapon: a heavy crescent-bladed plasma cutter, powered straight from a chassis’ reactor. Torches generally project as axes, though their blades can be changed to a range of other shapes. A common weapon in CQB theaters, the torch has lately become a status symbol among officers, carried by many alongside a smaller auxiliary weapon.",
    license_id: "mf_tokugawa"
  },
  {
    id: "mw_fuel_rod_gun",
    name: "Fuel Rod Gun",
    mount: "Main",
    type: "CQB",
    damage: [
      {
        type: "Energy",
        val: "1d3+2"
      }
    ],
    range: [
      {
        type: "Range",
        val: 3
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: 3
      },
      {
        id: "tg_unique"
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    talent_item: !0,
    talent_id: "t_nuclear_cavalier",
    talent_rank: 3,
    on_attack: "Clear 4 heat.",
    description: 'Gained from the "Nuclear Cavalier" Rank 3 Talent',
    license_id: ""
  },
  {
    id: "mw_prototype_1",
    name: "Prototype Weapon I",
    mount: "Main",
    type: "Special",
    damage: [
      {
        type: "Variable",
        val: "1d6+2"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      },
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: "1d6+2"
      },
      {
        id: "tg_overkill"
      },
      {
        id: "tg_set_max_uses"
      },
      {
        id: "tg_set_damage_type"
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    talent_item: !0,
    talent_id: "t_engineer",
    talent_rank: 1,
    effect: "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 1d6+2 to determine this weapon’s Limited uses.",
    description: 'Gained from the <i>"Engineer" Rank I</i> Talent',
    license_id: ""
  },
  {
    id: "mw_prototype_2",
    name: "Prototype Weapon II",
    mount: "Main",
    type: "Special",
    damage: [
      {
        type: "Variable",
        val: "1d6+2"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      },
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: "1d6+2"
      },
      {
        id: "tg_overkill"
      },
      {
        id: "tg_set_max_uses"
      },
      {
        id: "tg_set_damage_type"
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    talent_item: !0,
    talent_id: "t_engineer",
    talent_rank: 2,
    effect: "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 1d6+2 to determine this weapon’s Limited uses and choose two:<ul><li><b>Tweaked Optics:</b> Your prototype weapon always gains +1 Accuracy on attacks.</li><li><b>Tweaked Computer:</b> Your prototype weapon is Smart.</li><li><b>Stripped reactor shielding:</b> Each time you attack with your prototype weapon, you may choose – at the cost of 2 Heat – to attack with one of the following options, depending on its weapon type:<ul><li><b>Ranged weapon:</b> Cone 3, Line 5, or [Blast 1, Range 10].</li><li><b>Melee weapon:</b> Burst 1.</li></li></ul></ul>",
    description: 'Gained from the <i>"Engineer" Rank II</i> Talent',
    license_id: ""
  },
  {
    id: "mw_prototype_3",
    name: "Prototype Weapon III",
    mount: "Main",
    type: "Special",
    damage: [
      {
        type: "Variable",
        val: "1d6+4"
      }
    ],
    range: [
      {
        type: "Threat",
        val: 1
      },
      {
        type: "Range",
        val: 10
      }
    ],
    tags: [
      {
        id: "tg_limited",
        val: "2d6"
      },
      {
        id: "tg_overkill"
      },
      {
        id: "tg_set_max_uses"
      },
      {
        id: "tg_set_damage_type"
      }
    ],
    source: "",
    license: "GMS",
    license_level: 0,
    talent_item: !0,
    talent_id: "t_engineer",
    talent_rank: 3,
    effect: "This weapon is an experimental prototype, customized according to your specific requirements.<br>When you install it, or during a Full Repair, you may choose a new weapon type, damage type, and either Threat 1 (melee) or Range 10 (all other types). Additionally, each time you perform a Full Repair, reroll 2d6 to determine this weapon’s Limited uses and choose two:<ul><li><b>Tweaked Optics:</b> Your prototype weapon always gains +1 Accuracy on attacks.</li><li><b>Tweaked Computer:</b> Your prototype weapon is Smart.</li><li><b>Stripped reactor shielding:</b> Each time you attack with your prototype weapon, you may choose – at the cost of 2 Heat – to attack with one of the following options, depending on its weapon type:<ul><li><b>Ranged weapon:</b> Cone 3, Line 5, or [Blast 1, Range 10].</li><li><b>Melee weapon:</b> Burst 1.</li></li></ul></ul>",
    description: 'Gained from the <i>"Engineer" Rank III</i> Talent',
    license_id: ""
  },
  {
    id: "mw_lancaster_integrated",
    name: "Latch Drone",
    mount: "Main",
    type: "Launcher",
    damage: [],
    range: [
      {
        type: "Range",
        val: 8
      }
    ],
    effect: "This weapon can’t make normal attacks. Instead, choose an allied mech within Range and line of sight and make a ranged attack against Evasion 8. On a hit, either you or your target may spend 1 Repair to restore half your target’s HP.",
    license_id: ""
  },
  {
    id: "mw_raleigh_integrated",
    name: "M35 Mjolnir",
    mount: "Main",
    type: "CQB",
    range: [
      {
        type: "Range",
        val: 5
      },
      {
        type: "Threat",
        val: 3
      }
    ],
    damage: [
      {
        type: "Kinetic",
        val: 4
      }
    ],
    effect: "1/round, when you reload any weapon, this weapon can be fired as a free action.",
    license_id: ""
  },
  {
    id: "mw_barbarossa_integrated",
    name: "Apocalypse Rail",
    mount: "Ship-class",
    type: "Spool Weapon",
    skirmish: !1,
    barrage: !1,
    effect: "The Apocalypse Rail must be charged before it can be fired, using the Charge Rail CORE Power.<br>This weapon has different profiles determined by the current value of the APOCALYPSE DIE when you fire it. Each profile replaces the one proceeding it. The Apocalypse Rail cannot be fired at targets within range 5.<br> After an attack with the Apocalypse Rail, the Apocalypse Die resets to 4.",
    actions: [
      {
        name: "Fire Apocalypse Rail",
        activation: "Full",
        detail: "If the value of the Apocalypse Die is 1–3, you can attack on your turn with the Apocalypse Rail as a full action, but can’t move or take any other actions on the same turn.<br>After an attack with the Apocalypse Rail, the Apocalypse Die resets to 4."
      }
    ],
    profiles: [
      {
        name: "Charge Rail: 4",
        damage: [
          {
            override: !0,
            val: "N/A"
          }
        ],
        range: [
          {
            override: !0,
            type: "Range",
            val: "N/A"
          }
        ],
        effect: "Cannot Be Fired"
      },
      {
        name: "Charge Rail: 3",
        range: [
          {
            type: "Range",
            val: 20
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "2d6"
          }
        ],
        effect: "Objects within the affected area automatically take 20 AP explosive damage. After the attack, the blast cloud lingers, providing soft cover to characters within the affected area until the end of your next turn."
      },
      {
        name: "Charge Rail: 2",
        range: [
          {
            type: "Range",
            val: 25
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "3d6"
          }
        ],
        effect: "Objects and terrain in the area automatically take 40 AP explosive damage, and on hit characters become Shredded and Impaired until the end of their next turn. The blast cloud is a burning storm: until the end of your next turn, characters within the affected area receive soft cover, and characters that start their turn within the area or move there for the first time in a round take 4 burn."
      },
      {
        name: "Charge Rail: 1",
        range: [
          {
            type: "Range",
            val: 30
          },
          {
            type: "Blast",
            val: 2
          }
        ],
        damage: [
          {
            type: "Explosive",
            val: "4d6"
          }
        ],
        effect: "Objects and terrain in the area automatically take 100 AP explosive damage, and characters become Shredded and Stunned until the end of their next turn on hit. The ground in the affected area is vaporized on impact: for the rest of the scene, it is difficult terrain, characters within the affected area receive soft cover, and characters that start their turn with the area or move there for the first time in a round take 4 burn."
      }
    ],
    license_id: ""
  },
  {
    id: "mw_sherman_integrated",
    name: "ZF4 SOLIDCORE",
    mount: "Main",
    type: "Cannon",
    profiles: [
      {
        name: "1 Charge",
        range: [
          {
            type: "Line",
            val: 4
          }
        ],
        damage: [
          {
            type: "Energy",
            val: "1d6"
          }
        ],
        effect: "This weapon’s profile is determined by the number of Charges it carries. It begins with 1 Charge, dealing 1d6 energy with line 4. Each time you Stabilize, you gain an additional 1 Charge, up to a maximum of 4. The ZF4 gains an additional +4 line and +1d6 energy damage for each charge, and resets to 1 Charge after each attack. Charges persist between scenes, but are lost during a full repair."
      },
      {
        name: "2 Charges",
        range: [
          {
            type: "Line",
            val: 8
          }
        ],
        damage: [
          {
            type: "Energy",
            val: "2d6"
          }
        ],
        effect: "This weapon’s profile is determined by the number of Charges it carries. It begins with 1 Charge, dealing 1d6 energy with line 4. Each time you Stabilize, you gain an additional 1 Charge, up to a maximum of 4. The ZF4 gains an additional +4 line and +1d6 energy damage for each charge, and resets to 1 Charge after each attack. Charges persist between scenes, but are lost during a full repair."
      },
      {
        name: "3 Charges",
        range: [
          {
            type: "Line",
            val: 12
          }
        ],
        damage: [
          {
            type: "Energy",
            val: "3d6"
          }
        ],
        effect: "This weapon’s profile is determined by the number of Charges it carries. It begins with 1 Charge, dealing 1d6 energy with line 4. Each time you Stabilize, you gain an additional 1 Charge, up to a maximum of 4. The ZF4 gains an additional +4 line and +1d6 energy damage for each charge, and resets to 1 Charge after each attack. Charges persist between scenes, but are lost during a full repair."
      },
      {
        name: "4 Charges",
        range: [
          {
            type: "Line",
            val: 16
          }
        ],
        damage: [
          {
            type: "Energy",
            val: "4d6"
          }
        ],
        effect: "This weapon’s profile is determined by the number of Charges it carries. It begins with 1 Charge, dealing 1d6 energy with line 4. Each time you Stabilize, you gain an additional 1 Charge, up to a maximum of 4. The ZF4 gains an additional +4 line and +1d6 energy damage for each charge, and resets to 1 Charge after each attack. Charges persist between scenes, but are lost during a full repair."
      }
    ],
    tags: [
      {
        id: "tg_ordnance"
      }
    ],
    license_id: ""
  }
], data = {
  actions: require$$0,
  backgrounds: require$$1,
  core_bonuses: require$$2,
  environments: require$$3,
  factions: require$$4,
  frames: require$$5,
  glossary: require$$6,
  info: require$$7,
  manufacturers: require$$8,
  mods: require$$9,
  npc_classes: [],
  npc_features: [],
  npc_templates: [],
  pilot_gear: require$$10,
  reserves: require$$11,
  rules: require$$12,
  sitreps: require$$13,
  skills: require$$14,
  statuses: require$$15,
  systems: require$$16,
  tables: require$$17,
  tags: require$$18,
  talents: require$$19,
  weapons: require$$20
};
var lancerData = data;
const index = /* @__PURE__ */ getDefaultExportFromCjs(lancerData), index$1 = /* @__PURE__ */ _mergeNamespaces({
  __proto__: null,
  default: index
}, [lancerData]);
function registerTextSteps(flowSteps) {
  flowSteps.set("printGenericCard", printGenericCard), flowSteps.set("printGenericHTML", printGenericHTML);
}
__name(registerTextSteps, "registerTextSteps");
const _SimpleTextFlow = class _SimpleTextFlow extends Flow {
  constructor(uuid, data2) {
    const state = {
      title: (data2 == null ? void 0 : data2.title) ?? "",
      description: (data2 == null ? void 0 : data2.description) ?? "",
      tags: (data2 == null ? void 0 : data2.tags) ?? []
    };
    !state.title && uuid instanceof LancerItem && (state.title = uuid.name), super(uuid, state);
  }
};
__name(_SimpleTextFlow, "SimpleTextFlow");
let SimpleTextFlow = _SimpleTextFlow;
SimpleTextFlow.steps = ["printGenericCard"];
async function printGenericCard(state, options) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  return renderTemplateStep(
    state.actor,
    (options == null ? void 0 : options.template) || `systems/${game.system.id}/templates/chat/generic-card.hbs`,
    state.data
  ), !0;
}
__name(printGenericCard, "printGenericCard");
const _SimpleHTMLFlow = class _SimpleHTMLFlow extends Flow {
  constructor(uuid, data2) {
    const state = {
      html: (data2 == null ? void 0 : data2.html) ?? ""
    };
    super(uuid, state);
  }
};
__name(_SimpleHTMLFlow, "SimpleHTMLFlow");
let SimpleHTMLFlow = _SimpleHTMLFlow;
SimpleHTMLFlow.steps = ["printGenericHTML"];
async function printGenericHTML(state) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  if (!state.data.html) {
    if (state.item) {
      const templateData = {
        title: state.item.name,
        description: state.item.system.description ?? "",
        // Licenses don't have a description
        tags: state.item.system.tags ?? void 0
        // Frames don't have tags
      };
      state.data.html = await renderTemplate(`systems/${game.system.id}/templates/chat/generic-card.hbs`, templateData);
    } else if (state.actor) {
      const templateData = {
        title: state.actor.name
      };
      state.data.html = await renderTemplate(`systems/${game.system.id}/templates/chat/generic-card.hbs`, templateData);
    }
  }
  return createChatMessageStep(state.actor, state.data.html), !0;
}
__name(printGenericHTML, "printGenericHTML");
function registerStabilizeSteps(flowSteps) {
  flowSteps.set("initializeStabilize", initializeStabilize), flowSteps.set("renderStabilizePrompt", renderStabilizePrompt), flowSteps.set("applyStabilizeUpdates", applyStabilizeUpdates), flowSteps.set("printStabilizeResult", printStabilizeResult);
}
__name(registerStabilizeSteps, "registerStabilizeSteps");
const _StabilizeFlow = class _StabilizeFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      title: (data2 == null ? void 0 : data2.title) || "",
      description: "",
      option1: (data2 == null ? void 0 : data2.option1) || StabOptions1.Cool,
      option2: (data2 == null ? void 0 : data2.option2) || StabOptions2.Reload
    };
    super(uuid, initialData);
  }
};
__name(_StabilizeFlow, "StabilizeFlow");
let StabilizeFlow = _StabilizeFlow;
StabilizeFlow.steps = ["initializeStabilize", "renderStabilizePrompt", "applyStabilizeUpdates", "printStabilizeResult"];
async function initializeStabilize(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Stabilize flow state data missing!");
  return state.data.title = state.data.title || `${(_a19 = state.actor.name) == null ? void 0 : _a19.capitalize()} HAS STABILIZED`, !0;
}
__name(initializeStabilize, "initializeStabilize");
async function renderStabilizePrompt(state) {
  if (!state.data)
    throw new TypeError("Stabilize flow state data missing!");
  const actor = state.actor;
  let template = await renderTemplate(`systems/${game.system.id}/templates/window/promptStabilize.hbs`, {}), submit = null;
  return submit = await new Promise((resolve, _reject) => {
    new Dialog({
      title: `STABILIZE - ${actor.name}`,
      content: template,
      buttons: {
        submit: {
          icon: '<i class="fas fa-check"></i>',
          label: "Submit",
          callback: async (dlg) => {
            state.data && (state.data.option1 = $(dlg).find(".stabilize-options-1:checked").first().val(), state.data.option2 = $(dlg).find(".stabilize-options-2:checked").first().val(), resolve(!0));
          }
        },
        cancel: {
          icon: '<i class="fas fa-times"></i>',
          label: "Cancel",
          callback: async () => resolve(!1)
        }
      },
      default: "submit",
      close: () => resolve(!1)
    }).render(!0);
  }), submit ?? !1;
}
__name(renderStabilizePrompt, "renderStabilizePrompt");
async function applyStabilizeUpdates(state) {
  if (!state.data)
    throw new TypeError("Stabilize flow state data missing!");
  let option1text = "", option2text = "";
  switch (state.data.description = "", state.data.option1) {
    case StabOptions1.Cool:
      option1text = "Mech is cooling itself. Heat and @Compendium[world.status-items.Exposed] cleared.";
      break;
    case StabOptions1.Repair:
      if (state.actor.is_mech() && state.actor.system.repairs.value <= 0)
        return ui.notifications.warn("Mech has no repairs left. Please try again."), !1;
      option1text = "Mech has spent 1 repair to regain HP.";
      break;
  }
  switch (state.data.option2) {
    case StabOptions2.ClearBurn:
      option2text = "Mech has cleared all burn.";
      break;
    case StabOptions2.ClearOwnCond:
      option2text = "Mech has selected to clear own condition. Please clear manually.";
      break;
    case StabOptions2.ClearOtherCond:
      option2text = "Mech has selected to clear an allied condition. Please clear manually.";
      break;
    case StabOptions2.Reload:
      option2text = "Mech has selected full reload. Weapons reloaded:<ul>";
      for (const change of state.actor.loadoutHelper.reloadableItems())
        change.name && change["system.loaded"] === !0 && (option2text = option2text.concat(`<li>${change.name}</li>`));
      option2text = option2text.concat("</ul>");
      break;
  }
  return state.data.description = `<ul><li>${option1text}</li><li>${option2text}</li></ul>`, await state.actor.strussHelper.stabilize(state.data.option1, state.data.option2), !0;
}
__name(applyStabilizeUpdates, "applyStabilizeUpdates");
async function printStabilizeResult(state) {
  if (!state.data)
    throw new TypeError("Stabilize flow state data missing!");
  return printGenericCard(state), !0;
}
__name(printStabilizeResult, "printStabilizeResult");
function registerBurnSteps(flowSteps) {
  flowSteps.set("initBurnCheckData", initBurnCheckData), flowSteps.set("rollBurnCheck", rollBurnCheck), flowSteps.set("checkBurnResult", checkBurnResult);
}
__name(registerBurnSteps, "registerBurnSteps");
const _BurnFlow = class _BurnFlow extends DamageRollFlow {
  constructor(uuid, data2) {
    const state = {
      type: "damage",
      title: (data2 == null ? void 0 : data2.title) ?? "Burn Damage",
      icon: "cci cci-burn",
      amount: (data2 == null ? void 0 : data2.amount) ?? 0,
      damage: (data2 == null ? void 0 : data2.damage) ?? [{ type: DamageType.Burn, val: "1" }],
      configurable: (data2 == null ? void 0 : data2.configurable) !== void 0 ? data2.configurable : !0,
      add_burn: !1,
      // Burn ticks don't increase the burn
      tags: [],
      // Burn ticks don't have tags
      ap: !0,
      // Burn ticks are always AP
      paracausal: !1,
      half_damage: !1,
      overkill: !1,
      // Burn ticks aren't overkill
      reliable: !1,
      // Burn ticks aren't reliable
      hit_results: [],
      has_normal_hit: !0,
      // Set this to true to make it do a normal damage roll
      has_crit_hit: !1,
      // Don't do a crit damage roll
      damage_results: [],
      crit_damage_results: [],
      damage_total: 0,
      crit_total: 0,
      targets: (data2 == null ? void 0 : data2.targets) ?? []
    };
    super(uuid, state);
  }
};
__name(_BurnFlow, "BurnFlow");
let BurnFlow = _BurnFlow;
BurnFlow.steps = ["initBurnCheckData", "rollBurnCheck", "checkBurnResult", "printDamageCard"];
async function initBurnCheckData(state) {
  var _a19;
  if (!state.data)
    throw new TypeError("Burn flow state missing!");
  state.data.amount = state.actor.system.burn, state.data.damage = [{ type: DamageType.Burn, val: state.actor.system.burn.toString() }];
  const tokens = state.actor.getActiveTokens();
  if (!tokens || !tokens.length)
    return (_a19 = ui.notifications) == null || _a19.error("Burn flow requires the actor to have a token in the scene"), !1;
  const target = tokens[0];
  return state.data.hit_results = [{ target, total: "10", usedLockOn: !1, hit: !0, crit: !1 }], state.data.damage_hud_data = DamageHudData.fromParams(state.actor, {
    tags: [],
    title: state.data.title,
    targets: [target],
    hitResults: state.data.hit_results,
    ap: !1,
    paracausal: !0,
    // Burn ticks do not apply resistance
    halfDamage: !1,
    starting: { damage: state.data.damage, bonusDamage: [] }
  }), state.data.damage_results = [], state.data.crit_damage_results = [], state.data.targets = [], !0;
}
__name(initBurnCheckData, "initBurnCheckData");
async function rollBurnCheck(state) {
  var _a19, _b, _c, _d;
  if (!state.data)
    throw new TypeError("Burn flow state missing!");
  const rollFlow = new StatRollFlow(state.actor, { title: "BURN :: ENG", path: "system.eng" }), success2 = await rollFlow.begin();
  if (state.data.check_total = (_b = (_a19 = rollFlow.state.data) == null ? void 0 : _a19.result) == null ? void 0 : _b.roll.total, game.dice3d) {
    const msg = (_d = game.messages) == null ? void 0 : _d.contents[((_c = game.messages) == null ? void 0 : _c.contents.length) - 1];
    msg && await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
  }
  return success2 && state.data.check_total !== void 0 && state.data.check_total !== null;
}
__name(rollBurnCheck, "rollBurnCheck");
async function checkBurnResult(state) {
  if (!state.data)
    throw new TypeError("Burn flow state missing!");
  if (!state.data.check_total)
    throw new TypeError("Burn check hasn't been rolled yet!");
  if (state.data.check_total >= 10)
    return state.data.title = "BURN CLEARED!", state.data.icon = "mdi mdi-fire-extinguisher", await state.actor.update({ "system.burn": 0 }), !0;
  {
    const rollDamagesStep = game.lancer.flowSteps.get("rollNormalDamage");
    if (!rollDamagesStep || typeof rollDamagesStep != "function")
      throw new TypeError("Couldn't get rollDamagesStep flow step!");
    return await rollDamagesStep(state);
  }
}
__name(checkBurnResult, "checkBurnResult");
const DEFAULT_OVERCHARGE_SEQUENCE = "+1,+1d3,+1d6,+1d6+4", deleteIdCache = /* @__PURE__ */ new Set(), deleteIdCacheCleanup = foundry.utils.debounce(() => deleteIdCache.clear(), 2e4);
var _a13;
const _LancerActor = (_a13 = class extends Actor {
  constructor() {
    super(...arguments), this.npcClassSwapPromises = [];
  }
  static getDefaultArtwork(actorData) {
    const model = CONFIG.Actor.dataModels[(actorData == null ? void 0 : actorData.type) ?? "base"];
    if ((model == null ? void 0 : model.getDefaultArtwork) instanceof Function)
      return model.getDefaultArtwork(itemData);
    const img = (model == null ? void 0 : model.DEFAULT_ICON) ?? this.DEFAULT_ICON;
    return { img, texture: { src: img } };
  }
  // These cannot be instantiated the normal way (e.x. via constructor)
  _configure(options) {
    super._configure(options), this.effectHelper = new EffectHelper(this), this.loadoutHelper = new LoadoutHelper(this), this.strussHelper = new StrussHelper(this);
  }
  async damageCalc(damage, { multiple = 1, ap = !1, paracausal = !1, addBurn = !0 }) {
    var _a19;
    const armoredDamageTypes = [
      DamageType.Kinetic,
      DamageType.Energy,
      DamageType.Explosive,
      DamageType.Variable
    ], apDamageTypes = [DamageType.Burn, DamageType.Heat], taskPromises = [];
    (_a19 = this.token) == null || _a19.id;
    let changes = {};
    const exposed = this.system.statuses.exposed;
    [0.5, 1, 2].includes(multiple) || (multiple = 1);
    const resistAll = multiple === 0.5;
    if (this.hasHeatcap() || (damage.Energy += damage.Heat, damage.Heat = 0), multiple === 2)
      for (const d of Object.values(DamageType))
        damage[d] *= 2;
    if (exposed && armoredDamageTypes.forEach((d) => Math.ceil(damage[d] *= 2)), !paracausal && !this.system.statuses.shredded) {
      const resistArmorDamage = armoredDamageTypes.filter((t) => resistAll || this.system.resistances[t.toLowerCase()]), normalArmorDamage = armoredDamageTypes.filter((t) => !resistArmorDamage.includes(t)), resistApDamage = apDamageTypes.filter((t) => resistAll || this.system.resistances[t.toLowerCase()]);
      let armor = ap ? 0 : this.system.armor, leftoverArmor;
      for (const t of normalArmorDamage)
        leftoverArmor = Math.max(armor - damage[t], 0), damage[t] = Math.max(damage[t] - armor, 0), armor = leftoverArmor;
      for (const t of resistArmorDamage)
        leftoverArmor = Math.max(armor - damage[t], 0), damage[t] = Math.ceil(Math.max(damage[t] - armor, 0) / 2), armor = leftoverArmor;
      for (const t of resistApDamage)
        damage[t] = Math.ceil(damage[t] / 2);
    }
    this.hasHeatcap() && (changes["system.heat.value"] = this.system.heat.value + damage.Heat);
    let totalDamage = Math.ceil(damage.Kinetic + damage.Energy + damage.Explosive + damage.Variable) + damage.Burn, overshieldUsed = 0;
    if (this.system.overshield.value) {
      overshieldUsed = Math.min(this.system.overshield.value, totalDamage);
      const leftoverOvershield = Math.max(this.system.overshield.value - totalDamage, 0);
      totalDamage = Math.max(totalDamage - this.system.overshield.value, 0), changes["system.overshield.value"] = leftoverOvershield;
    }
    totalDamage && (changes["system.hp.value"] = this.system.hp.value - totalDamage), damage.Burn && addBurn && (changes["system.burn"] = this.system.burn + damage.Burn), taskPromises.push(this.update(changes));
    const damageStrings = [];
    let totalTypes = 0;
    damage.Kinetic && (damageStrings.push(`${damage.Kinetic}<i class="cci cci-kinetic damage--kinetic i--s"></i>`), totalTypes += 1), damage.Energy && (damageStrings.push(`${damage.Energy}<i class="cci cci-energy damage--energy i--s"></i>`), totalTypes += 1), damage.Explosive && (damageStrings.push(`${damage.Explosive}<i class="cci cci-explosive damage--explosive i--s"></i>`), totalTypes += 1), damage.Variable && (damageStrings.push(`${damage.Variable}<i class="cci cci-variable damage--variable i--s"></i>`), totalTypes += 1), damage.Burn && (damageStrings.push(`${damage.Burn}<i class="cci cci-burn damage--burn i--s"></i>`), totalTypes += 1), damage.Heat && (damageStrings.push(`${damage.Heat}<i class="cci cci-heat damage--heat i--s"></i>`), totalTypes += 1);
    const allDamageString = damageStrings.length ? damageStrings.join(", ") : "0", totalDamageString = totalTypes > 1 ? ` (${overshieldUsed + totalDamage} total) ` : "", chatContent = `<div class="flexrow">
      <span>${this.token ? this.token.name : this.name} took ${allDamageString} ${totalDamageString}damage!</span>
      <a
        class="lancer-button lancer-damage-undo"
        style="display: flex; flex-grow: 0; justify-content: center; align-items: center;"
        data-tooltip="Undo this damage"
        data-uuid="${this.uuid}"
        data-overshield-delta="${overshieldUsed}"
        data-hp-delta="${totalDamage}"
        data-burn-delta="${damage.Burn}"
        data-heat-delta="${damage.Heat}"
        data-add-burn="${addBurn}"
      >
        <i class="fas fa-undo"></i>
      </a>
    </div>`;
    return taskPromises.push(createChatMessageStep(this, chatContent)), await Promise.all(taskPromises), totalDamage;
  }
  /* -------------------------------------------- */
  /** @override
   * We require a customized active effect application workflow
   */
  prepareBaseData() {
    var _a19, _b, _c;
    if (!ACTOR_TYPES.includes(this.type))
      return console.log("Actor is not a LancerActor:", this), super.prepareBaseData();
    let sys = this.system;
    if (sys.edef = 0, sys.evasion = 0, sys.speed = 0, sys.armor = 0, sys.size = 0, sys.save = 0, sys.sensor_range = 0, sys.tech_attack = 0, sys.statuses = {
      dangerzone: !1,
      downandout: !1,
      engaged: !1,
      exposed: !1,
      invisible: !1,
      prone: !1,
      shutdown: !1,
      immobilized: !1,
      impaired: !1,
      jammed: !1,
      lockon: !1,
      shredded: !1,
      slowed: !1,
      stunned: !1,
      hidden: !1
    }, sys.resistances = {
      burn: !1,
      energy: !1,
      explosive: !1,
      heat: !1,
      kinetic: !1,
      variable: !1
    }, sys.bonuses = {
      flat: {},
      weapon_bonuses: []
    }, (this.is_mech() || this.is_deployable() || this.is_npc()) && (this.system.hull = 0, this.system.agi = 0, this.system.sys = 0, this.system.eng = 0), this.is_pilot())
      this.system.grit = Math.ceil(this.system.level / 2), this.system.hp.max = lancerData.rules.base_pilot_hp + this.system.grit, this.system.bond = this.items.find((i) => i.is_bond()) ?? null, this.system.size = 0.5, this.system.sensor_range = 5, this.system.save = this.system.grit + 10;
    else if (this.is_mech()) {
      let equipped_sp = 0, equipped_ai = 0;
      for (let system of this.system.loadout.systems)
        (system == null ? void 0 : system.status) == "resolved" && (equipped_sp += system.value.system.sp, equipped_ai += system.value.system.tags.some((t) => t.is_ai) ? 1 : 0);
      for (let mount of this.system.loadout.weapon_mounts)
        for (let slot of mount.slots)
          ((_a19 = slot.weapon) == null ? void 0 : _a19.status) == "resolved" && (equipped_sp += slot.weapon.value.system.sp), ((_b = slot.mod) == null ? void 0 : _b.status) == "resolved" && (equipped_sp += slot.mod.value.system.sp, equipped_ai += slot.mod.value.system.tags.some((t) => t.is_ai) ? 1 : 0, (_c = slot.weapon) != null && _c.value && (slot.weapon.value.system.mod = slot.mod.value));
      this.system.loadout.sp = { max: 0, min: 0, value: equipped_sp }, this.system.loadout.ai_cap = { max: 1, min: 0, value: equipped_ai }, this.system.loadout.limited_bonus = 0, this.system.overcharge_sequence = DEFAULT_OVERCHARGE_SEQUENCE, this.system.level = 0, this.system.grit = 0, this.system.stress_repair_cost = 2, this.system.structure_repair_cost = 2;
    } else
      this.is_npc() ? (this.system.class = this.items.find((i) => i.is_npc_class()), this.system.templates = this.items.filter((i) => i.is_npc_template())) : this.is_deployable() && (sys.armor = this.system.stats.armor, sys.edef = this.system.stats.edef, sys.evasion = this.system.stats.evasion, this.system.heat.max = this.system.stats.heatcap, sys.save = this.system.stats.save, sys.size = this.system.stats.size, sys.speed = this.system.stats.speed, this.system.level = 0, this.system.grit = 0, this.system.hp_bonus = 0);
    this._markEquipped();
  }
  /** @override
   * We need to, in order:
   *  - Mark things as equipped
   *  - Finalize derived data on weaponry based on fully prepared actor statistics
   */
  prepareDerivedData() {
    var _a19;
    for (let item of this.items.contents)
      item.prepareFinalAttributes();
    (_a19 = this.effectHelper._passdownEffectTracker) == null || _a19.setValue(this.effectHelper.collectPassdownEffects()), this._markStatuses(), this.is_mech() && this.items.find((i) => i.system.lid === "mf_emperor") && (this.system.hp.max -= this.system.grit), this.is_deployable() && (this.system.hp.max = rollEvalSync(`${this.system.stats.hp} + ${this.system.hp_bonus}`, this.getRollData()) || 5);
  }
  /** Check which statuses this actor has active and set system.status accordingly */
  _markStatuses() {
    if (this.statuses)
      for (const status of this.statuses.keys())
        switch (this.system.statuses[status] = !0, status) {
          case "resistance_burn":
            this.system.resistances.burn = !0;
            break;
          case "resistance_energy":
            this.system.resistances.energy = !0;
            break;
          case "resistance_explosive":
            this.system.resistances.explosive = !0;
            break;
          case "resistance_heat":
            this.system.resistances.heat = !0;
            break;
          case "resistance_kinetic":
            this.system.resistances.kinetic = !0;
            break;
        }
  }
  /** Mark our equipped items as equipped */
  _markEquipped() {
    var _a19, _b, _c;
    for (let i of this.items)
      i._resetEquipped();
    if (this.is_pilot()) {
      let ld = this.system.loadout;
      for (let armor of ld.armor)
        armor != null && armor.value && (armor.value.system.equipped = !0);
      for (let weapon of ld.weapons)
        weapon != null && weapon.value && (weapon.value.system.equipped = !0);
      for (let gear of ld.gear)
        gear != null && gear.value && (gear.value.system.equipped = !0);
    } else if (this.is_mech()) {
      let ld = this.system.loadout;
      (_a19 = ld.frame) != null && _a19.value && (ld.frame.value.system.equipped = !0);
      for (let system of ld.systems)
        system != null && system.value && (system.value.system.equipped = !0);
      for (let mount of this.system.loadout.weapon_mounts)
        for (let slot of mount.slots)
          (_b = slot.weapon) != null && _b.value && (slot.weapon.value.system.equipped = !0), (_c = slot.mod) != null && _c.value && (slot.mod.value.system.equipped = !0);
    }
  }
  /**
   * Want to yield from all items ephemeral effects
   * @override
   */
  *allApplicableEffects() {
    yield* super.allApplicableEffects(), yield* this.effectHelper.inheritedEffects();
    for (let item of this.items.contents)
      yield* item._generateEphemeralEffects();
    this.is_pilot() ? yield* pilotInnateEffects(this) : this.is_npc() && (yield* npcInnateEffects(this));
  }
  /**
   * Want to preserve our arrays, so we use full_update_data to hydrate our update data
   * @override
   */
  async update(data2, options = {}) {
    return data2 = this.system.full_update_data(data2), super.update(data2, options);
  }
  /** @override
   * This is mostly copy-pasted from Actor.modifyTokenAttribute to allow negative hps, which are useful for structure checks
   */
  async modifyTokenAttribute(attribute, value, isDelta = !1, isBar = !0) {
    const current = foundry.utils.getProperty(this.system, attribute);
    let updates;
    return isBar ? (isDelta && (value = Number(current.value) + value), updates = { [`system.${attribute}.value`]: value }) : (isDelta && (value = Number(current) + value), updates = { [`system.${attribute}`]: value }), Hooks.call("modifyTokenAttribute", { attribute, value, isDelta, isBar }, updates) ? this.update(updates) : this;
  }
  /** @override
   * This is overridden to pre-populate with slightly more sensible data,
   * such as nicer icons and default names, token dispositions, etc
   */
  async _preCreate(...[data2, options, user]) {
    var _a19;
    if (await super._preCreate(data2, options, user) === !1)
      return !1;
    if ((_a19 = data2 == null ? void 0 : data2._stats) != null && _a19.createdTime)
      return;
    let disposition = {
      [EntryType.NPC]: CONST.TOKEN_DISPOSITIONS.HOSTILE,
      [EntryType.PILOT]: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
      [EntryType.DEPLOYABLE]: CONST.TOKEN_DISPOSITIONS.NEUTRAL,
      [EntryType.MECH]: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
      base: void 0
    }[this.type] ?? CONST.TOKEN_DISPOSITIONS.FRIENDLY;
    this.updateSource({
      // Link the token to the Actor for pilots and mechs, but not for NPCs or deployables
      prototypeToken: {
        actorLink: [EntryType.PILOT, EntryType.MECH].includes(this.type),
        disposition,
        lockRotation: !0
      }
    });
  }
  /** @override
   * When an update is queued, trigger scrolling text on attached tokens
   */
  async _preUpdate(...[data2, options, user]) {
    if (await super._preUpdate(data2, options, user) === !1)
      return !1;
    this.statChangeScrollingText(data2);
  }
  /** @override
   * Upon an actor being updated, we want to trigger automated cleanup, effect generation, etc
   */
  _onUpdate(...[changed, options, userId]) {
    var _a19, _b;
    super._onUpdate(changed, options, userId);
    let cause_updates = game.userId == userId, changing_active_mech = ((_a19 = changed.system) == null ? void 0 : _a19.active_mech) !== void 0;
    if (changing_active_mech) {
      let owned_mechs = game.actors.filter(
        (a) => {
          var _a20;
          return a.is_mech() && ((_a20 = a.system.pilot) == null ? void 0 : _a20.value) == this;
        }
      );
      owned_mechs == null || owned_mechs.forEach((m) => m.render());
    }
    cause_updates && (this.effectHelper.propagateEffects(changing_active_mech), (this.is_mech() || this.is_deployable()) && ((_b = changed.system) != null && _b.owner) && _a13.fromUuid(changed.system.owner).then((a) => {
      a && a.effectHelper.propagateEffects(!0);
    }), this.loadoutHelper.cleanupUnresolvedReferences());
  }
  /**
   * Makes us own (or rather, creates an owned copy of) the provided item if we don't already.
   * The second return value indicates whether a new copy was made (true), or if we already owned it/it is an actor (false)
   * Note: this operation also fixes limited to be the full capability of our actor
   * @param document
   * @returns The created item, and whether it was created. If it already existed or the document was an actor, the second value is false.
   */
  async quickOwn(document2) {
    if (document2.parent != this) {
      let results = await insinuate([document2], this);
      for (let newItem of results) {
        const updates = {};
        newItem.isLimited() && (updates["system.uses.value"] = newItem.system.uses.max), newItem.isLoading() && (updates["system.loaded"] = !0), newItem.isRecharge() && (updates["system.charged"] = !0), Object.values(updates).length > 0 && await newItem.update(updates);
      }
      return [results[0], !0];
    } else
      return [document2, !1];
  }
  /** @inheritdoc
   * Due to the complex effects equipment can have on an actors statistical values, it is necessary to be sure our
   * effects are kept in lockstep as items are created, updated, and deleted
   */
  _onCreateDescendantDocuments(parent, collection, documents, changes, options, userId) {
    let oldClass = null, itemDocs = documents.filter(
      (d) => d.documentName === "Item"
    );
    if (this.is_npc() && itemDocs.some((d) => d.is_npc_class()) && (oldClass = this.items.find(
      (item) => item.is_npc_class() && !itemDocs.find((doc) => item._id === doc._id)
    )), super._onCreateDescendantDocuments(parent, collection, documents, changes, options, userId), game.userId == userId) {
      if (this.is_npc() && itemDocs.some((d) => d.is_npc_class() || d.is_npc_template())) {
        itemDocs = itemDocs.filter((d) => d.is_npc_class() || d.is_npc_template());
        let newClass = itemDocs.find((d) => d.is_npc_class());
        newClass && this.npcClassSwapPromises.push(this._swapNpcClass(oldClass, newClass)), itemDocs.filter((d) => d.is_npc_template()).forEach((t) => this.npcClassSwapPromises.push(this._swapNpcClass(null, t)));
      }
      for (let item of itemDocs)
        item.isLimited() && item.update({ "system.uses.value": item.system.uses.max }), item.isLoading() && item.update({ "system.loaded": !0 }), item.isRecharge() && item.update({ "system.charged": !0 });
      this.effectHelper.propagateEffects(!1);
    }
  }
  /** @inheritdoc */
  _onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId) {
    super._onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId), game.userId == userId && this.effectHelper.propagateEffects(!1);
  }
  /** @inheritdoc */
  _onDeleteDescendantDocuments(parent, collection, documents, changes, options, userId) {
    super._onDeleteDescendantDocuments(parent, collection, documents, changes, options, userId);
    for (let doc of documents)
      deleteIdCache.add(doc.uuid);
    deleteIdCacheCleanup(), game.userId == userId && (this.loadoutHelper.cleanupUnresolvedReferences(), this.effectHelper.propagateEffects(!1));
  }
  /**
   * Delete a descendant document without worrying if its been deleted before.
   * There is still technically an _exceedingly_ narrow window in which we can get duplicate deletion of effects, but this mitigates it
   */
  async _safeDeleteDescendant(collection, effects, options) {
    if (!effects.length)
      return;
    let toDelete = [];
    for (let e of effects) {
      let u = e.uuid ?? "";
      deleteIdCache.has(u) || (deleteIdCache.add(u), toDelete.push(e.id));
    }
    return deleteIdCacheCleanup(), this.deleteEmbeddedDocuments(collection, toDelete, options);
  }
  // Typeguards
  is_pilot() {
    return this.type === EntryType.PILOT;
  }
  is_mech() {
    return this.type === EntryType.MECH;
  }
  is_npc() {
    return this.type === EntryType.NPC;
  }
  is_deployable() {
    return this.type === EntryType.DEPLOYABLE;
  }
  // Quick checkers
  hasHeatcap() {
    return this.system.heat !== void 0;
  }
  async removeClassFeatures(item) {
    if (!this.is_npc() || !item.is_npc_class() && !item.is_npc_template())
      return;
    const targetFeatures = [...item.system.base_features, ...item.system.optional_features];
    let matches = this.itemTypes.npc_feature.filter((feat) => targetFeatures.includes(feat.system.lid));
    await this._safeDeleteDescendant(
      "Item",
      matches.filter((x) => x)
    );
  }
  /**
   * Taking a new and old frame/class, swaps the actor and/or token images if
   * we detect that the image isn't custom. Will check each individually
   * @param newFrame  New Frame or NPC Class
   * @returns         The newFrame if any updates were performed
   */
  async swapFrameImage(newFrame) {
    var _a19, _b, _c;
    if (!((_a19 = game.users.activeGM) != null && _a19.isSelf) || !(this.is_mech() || this.is_npc()))
      return;
    let new_frame_path = frameToPath(newFrame == null ? void 0 : newFrame.name), default_img = this.is_mech() ? "systems/lancer/assets/icons/mech.svg" : "systems/lancer/assets/icons/npc_class.svg", curr_token = (_c = (_b = this.prototypeToken) == null ? void 0 : _b.texture) == null ? void 0 : _c.src, curr_actor = this.img;
    await this.update({
      img: replaceDefaultResource(curr_actor, new_frame_path, default_img),
      "prototypeToken.texture.src": replaceDefaultResource(curr_token, new_frame_path, default_img)
    });
  }
  /**
   * Taking a new frame/class, set the prototype token size
   * @param newFrame - The new frame or class to pull the size from.
   */
  async updateTokenSize(newFrame) {
    let new_size;
    if (newFrame.is_frame() && this.is_mech())
      new_size = Math.max(1, newFrame.system.stats.size);
    else if (newFrame.is_npc_class() && this.is_npc()) {
      const tier = this.system.tier || 1;
      new_size = Math.max(1, newFrame.system.base_stats[tier - 1].size);
    }
    new_size && await this.prototypeToken.update({ height: new_size, width: new_size });
  }
  // Given a list of npc features, return the corresponding entries on this npc
  findMatchingFeaturesInNpc(featureLids) {
    if (!this.is_npc())
      return [];
    let result = [];
    for (let predicateLid of featureLids)
      for (let candidate_feature of this.itemTypes.npc_feature)
        candidate_feature.system.lid == predicateLid && result.push(candidate_feature);
    return result;
  }
  /**
   * Internal utility method, intended to be called by _onCreateDescendantDocuments.
   * Removes features associated with the old class and adds features associated with the new class.
   * @param oldClass The old class which is being removed
   * @param newClass The new class which is being added
   */
  async _swapNpcClass(oldClass, newClass) {
    var _a19;
    if (!((_a19 = game.users.activeGM) != null && _a19.isSelf) || !this.is_npc() || !newClass.is_npc_class() && !newClass.is_npc_template())
      return;
    let needsRefresh = !1;
    if (oldClass) {
      let classFeatures = this.findMatchingFeaturesInNpc([
        ...oldClass.system.base_features,
        ...oldClass.system.optional_features
      ]);
      classFeatures.length && (await this._safeDeleteDescendant("Item", [oldClass, ...classFeatures]), needsRefresh = !0);
    }
    let baseFeatures = await Promise.all(
      Array.from(newClass.system.base_features).map((lid) => fromLid(lid))
    );
    await insinuate(
      baseFeatures.filter((x) => x),
      this
    ), needsRefresh = !0, newClass.is_npc_class() && await this.swapFrameImage(newClass), needsRefresh && await this.update({
      "system.hp.value": this.system.hp.max,
      "system.stress.value": this.system.stress.max,
      "system.structure.value": this.system.structure.max
    });
  }
  // Checks that the provided document is not null, and is a lancer actor
  static async fromUuid(x, messagePrefix) {
    var _a19, _b;
    if (x instanceof _a13)
      return x;
    if (x = await fromUuid(x), !x) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Actor ${x} not found.`;
      throw (_a19 = ui.notifications) == null || _a19.error(message), new Error(message);
    }
    if (x instanceof TokenDocument && (x = x.actor), !(x instanceof _a13)) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Document ${x} not an actor.`;
      throw (_b = ui.notifications) == null || _b.error(message), new Error(message);
    }
    return x;
  }
  // Checks that the provided document is not null, and is a lancer actor
  static fromUuidSync(x, messagePrefix) {
    var _a19, _b;
    if (x instanceof _a13)
      return x;
    if (x = fromUuidSync(x), !x) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Actor ${x} not found.`;
      throw (_a19 = ui.notifications) == null || _a19.error(message), new Error(message);
    }
    if (x instanceof TokenDocument && (x = x.actor), !(x instanceof _a13)) {
      let message = `${messagePrefix ? messagePrefix + " | " : ""}Document ${x} not an actor.`;
      throw (_b = ui.notifications) == null || _b.error(message), new Error(message);
    }
    return x;
  }
  async statChangeScrollingText(data2) {
    var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
    const tokenId = ((_a19 = this.token) == null ? void 0 : _a19.id) || ((_c = (_b = canvas == null ? void 0 : canvas.scene) == null ? void 0 : _b.tokens.find((t) => {
      var _a20;
      return ((_a20 = t.actor) == null ? void 0 : _a20.id) === this.id;
    })) == null ? void 0 : _c.id);
    if (!tokenId)
      return;
    const scrollingTexts = [];
    if (((_e = (_d = data2.system) == null ? void 0 : _d.overshield) == null ? void 0 : _e.value) !== void 0) {
      const val = this.system.overshield.value - data2.system.overshield.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Overshield`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.TOP,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0x9f6bff"
        }
      });
    }
    if (((_g = (_f = data2.system) == null ? void 0 : _f.hp) == null ? void 0 : _g.value) !== void 0) {
      const val = this.system.hp.value - data2.system.hp.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} HP`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.CENTER,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0xc2e03e"
        }
      });
    }
    if (((_h = data2.system) == null ? void 0 : _h.burn) !== void 0) {
      const val = this.system.burn - data2.system.burn;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Burn`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0xc43333"
        }
      });
    }
    if (this.hasHeatcap() && ((_j = (_i = data2.system) == null ? void 0 : _i.heat) == null ? void 0 : _j.value) !== void 0) {
      const val = this.system.heat.value - data2.system.heat.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Heat`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0xc76f38"
        }
      });
    }
    if ((this.is_mech() || this.is_npc()) && ((_l = (_k = data2.system) == null ? void 0 : _k.structure) == null ? void 0 : _l.value) !== void 0) {
      const val = this.system.structure.value - data2.system.structure.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Structure`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.CENTER,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0x1f9eff"
        }
      });
    }
    if ((this.is_mech() || this.is_npc()) && ((_n = (_m = data2.system) == null ? void 0 : _m.stress) == null ? void 0 : _n.value) !== void 0) {
      const val = this.system.stress.value - data2.system.stress.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Stress`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.CENTER,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0xff7b00"
        }
      });
    }
    if (this.is_mech() && ((_o = data2.system) == null ? void 0 : _o.repairs) !== void 0) {
      const val = this.system.repairs.value - data2.system.repairs.value;
      val && scrollingTexts.push({
        tokenId,
        content: `${val < 0 ? "+" : "-"}${Math.abs(val).toString()} Repairs`,
        style: {
          anchor: CONST.TEXT_ANCHOR_POINTS.CENTER,
          direction: val < 0 ? CONST.TEXT_ANCHOR_POINTS.TOP : CONST.TEXT_ANCHOR_POINTS.BOTTOM,
          fill: "0x8c8c8c"
        }
      });
    }
    for (const text of scrollingTexts)
      await new Promise((resolve) => setTimeout(resolve, 250)), tokenScrollText(text, !0);
  }
  async beginFullRepairFlow(title) {
    return this.is_deployable() ? !1 : await new FullRepairFlow(this, title ? { title } : void 0).begin();
  }
  async beginStabilizeFlow(title) {
    return !this.is_mech() && !this.is_npc() ? !1 : await new StabilizeFlow(this, title ? { title } : void 0).begin();
  }
  async beginOverchargeFlow() {
    return this.is_mech() ? await new OverchargeFlow(this).begin() : (ui.notifications.warn("Only mechs can overcharge!"), !1);
  }
  async beginRechargeFlow() {
    return this.is_npc() ? await new NPCRechargeFlow(this).begin() : (ui.notifications.warn("Only NPCs can recharge!"), !1);
  }
  async beginStatFlow(path, title) {
    return await new StatRollFlow(this, { path, title }).begin();
  }
  async beginBurnFlow(title) {
    return await new BurnFlow(this, { title }).begin();
  }
  async beginBasicAttackFlow(title) {
    return await new BasicAttackFlow(this, title ? { title } : void 0).begin();
  }
  async beginDamageFlow(title) {
    return await new DamageRollFlow(this, title ? { title } : void 0).begin();
  }
  async beginBasicTechAttackFlow(title) {
    if (!this.is_mech() && !this.is_npc())
      return ui.notifications.warn("Only mechs and NPCs can tech attack!"), !1;
    const params = {
      title,
      invade: !0
    };
    return await new TechAttackFlow(this, params).begin();
  }
  async beginStructureFlow() {
    return await new StructureFlow(this).begin();
  }
  async beginOverheatFlow() {
    return await new OverheatFlow(this).begin();
  }
  async tallyBondXP() {
    if (!this.is_pilot())
      return;
    let totalIncrease = 0;
    for (const ideal of this.system.bond_state.xp_checklist.major_ideals)
      ideal && (totalIncrease += 1);
    this.system.bond_state.xp_checklist.minor_ideal && (totalIncrease += 1), this.system.bond_state.xp_checklist.veteran_power && (totalIncrease += 1), totalIncrease && (await this.update({
      "system.bond_state.xp.value": this.system.bond_state.xp.value + totalIncrease
    }), await this.update({
      "system.bond_state.xp_checklist": {
        major_ideals: [!1, !1, !1],
        minor_ideal: !1,
        veteran_power: !1
      }
    }));
  }
  // Called as part of foundry document initialization process
  static migrateData(source) {
    return super.migrateData(source);
  }
}, __name(_a13, "_LancerActor"), _a13);
_LancerActor.DEFAULT_ICON = "icons/svg/mystery-man-black.svg";
let LancerActor = _LancerActor;
const ACTOR_TYPES = [EntryType.MECH, EntryType.DEPLOYABLE, EntryType.NPC, EntryType.PILOT];
function is_actor_type(type2) {
  return ACTOR_TYPES.includes(type2);
}
__name(is_actor_type, "is_actor_type");
let _cache = [];
function cleanCloudOwnerID(str) {
  return str.substring(0, 10) == "us-east-1:" ? str.substring(10) : str;
}
__name(cleanCloudOwnerID, "cleanCloudOwnerID");
async function populatePilotCache() {
  const { Auth } = await import("./index-4953d36a.mjs"), { Storage } = await import("./index-25344865.mjs");
  try {
    await Auth.currentSession();
  } catch (e) {
    return console.warn(`AWS Auth failed: ${e}`), [];
  }
  const res = await Storage.list("pilot", {
    level: "protected",
    // @ts-expect-error  Unclear if this still does anything
    cacheControl: "no-cache"
    // Filter out deleted pilots (tagged with "delete" or "s3-remove-flag"), we want "active"
  }).then((result) => result.results.filter((x) => {
    var _a19;
    return (_a19 = x.key) == null ? void 0 : _a19.endsWith("--active");
  })), data2 = (await Promise.all(res.map((obj) => obj.key ? fetchPilot(obj.key) : null))).map(
    (x) => x
  );
  return data2.forEach((pilot) => {
    pilot.mechs = [], pilot.cloudOwnerID = pilot.cloudOwnerID != null ? cleanCloudOwnerID(pilot.cloudOwnerID) : "", pilot.cloudID = pilot.cloudID != null ? pilot.cloudID : pilot.id;
  }), _cache = data2, data2;
}
__name(populatePilotCache, "populatePilotCache");
function pilotCache() {
  return _cache;
}
__name(pilotCache, "pilotCache");
async function fetchPilotViaShareCode(sharecode) {
  const shareObj = await (await fetch("https://api.compcon.app/share?code=" + sharecode, {
    headers: {
      "x-api-key": "fcFvjjrnQy2hypelJQi4X9dRI55r5KuI4bC07Maf"
    }
  })).json();
  return await (await fetch(shareObj.presigned)).json();
}
__name(fetchPilotViaShareCode, "fetchPilotViaShareCode");
async function fetchPilotViaCache(cachedPilot) {
  const documentID = `pilot/${cachedPilot.name.replace(/[^a-zA-Z\d\s:]/g, " ")}--${cachedPilot.id}--active`, { Storage } = await import("./index-25344865.mjs"), req = {
    level: "protected",
    download: !0,
    cacheControl: "no-cache"
  }, text = await (await Storage.get(documentID, req)).Body.text();
  return JSON.parse(text);
}
__name(fetchPilotViaCache, "fetchPilotViaCache");
async function fetchPilot(cloudID, cloudOwnerID) {
  !cloudOwnerID && cloudID.includes("//") && ([cloudOwnerID, cloudID] = cloudID.split("//")), cloudID.substring(0, 6) != "pilot/" && (cloudID = "pilot/" + cloudID), cloudOwnerID && cloudOwnerID.substring(0, 10) != "us-east-1:" && (cloudOwnerID = "us-east-1:" + cloudOwnerID);
  try {
    const { Auth } = await import("./index-4953d36a.mjs");
    await Auth.currentSession();
  } catch (e) {
    throw ui.notifications.error("Sync failed - you aren't logged into a Comp/Con account."), e;
  }
  const { Storage } = await import("./index-25344865.mjs"), req = {
    level: "protected",
    download: !0,
    cacheControl: "no-cache"
  };
  cloudOwnerID && (req.identityId = cloudOwnerID);
  const text = await (await Storage.get(cloudID, req)).Body.text();
  return JSON.parse(text);
}
__name(fetchPilot, "fetchPilot");
function actionIcon(action) {
  switch (action) {
    case "quick":
      return "mdi mdi-hexagon-slice-3";
    case "full":
      return "mdi mdi-hexagon-slice-6";
    case "reaction":
      return "cci cci-reaction";
    case "protocol":
      return "cci cci-protocol";
    case "move":
      return "mdi mdi-arrow-right-bold-hexagon-outline";
    case "free":
    default:
      return "cci cci-free-action";
  }
}
__name(actionIcon, "actionIcon");
const _defaultActionData = /* @__PURE__ */ __name((target) => ({
  protocol: !0,
  move: getSpeed(target),
  full: !0,
  quick: !0,
  reaction: !0
}), "_defaultActionData"), _endTurnActionData = /* @__PURE__ */ __name(() => ({
  protocol: !1,
  move: 0,
  full: !1,
  quick: !1,
  reaction: !0
}), "_endTurnActionData");
function getActions(actor) {
  return actor.is_mech() || actor.is_npc() ? actor.system.action_tracker : null;
}
__name(getActions, "getActions");
async function updateActions(actor, actions) {
  await actor.update({ "system.action_tracker": actions });
}
__name(updateActions, "updateActions");
async function modAction(actor, spend, type2) {
  let actions = getActions(actor);
  if (actions) {
    switch (type2) {
      case "move":
        actions.move = spend ? 0 : getSpeed(actor);
        break;
      case "free":
        actions.free = !0;
        break;
      case "quick":
        spend ? actions.full ? actions.full = !1 : actions.quick = !1 : actions.quick = !0;
        break;
      case "full":
        spend ? (actions.full = !1, actions.quick = !1) : actions.full = !0;
        break;
      case "protocol":
        actions.protocol = !spend;
        break;
      case "reaction":
        actions.reaction = !spend;
        break;
      case void 0:
        actions = spend ? _endTurnActionData() : _defaultActionData(actor);
    }
    spend && (actions.protocol = !1), await updateActions(actor, actions);
  }
}
__name(modAction, "modAction");
async function toggleAction(actor, type2) {
  let actions = getActions(actor);
  actions && (actions[type2] ? await modAction(actor, !0, type2) : await modAction(actor, !1, type2));
}
__name(toggleAction, "toggleAction");
function getSpeed(actor) {
  return actor.system.speed;
}
__name(getSpeed, "getSpeed");
var _a14;
const _LancerActionManager = (_a14 = class extends Application {
  constructor(...args) {
    super(...args), this.target = null;
  }
  async init() {
    _a14.enabled = game.settings.get(game.system.id, LANCER.setting_actionTracker).showHotbar && !game.settings.get("core", "noCanvas"), _a14.enabled && (this.loadUserPos(), await this.updateControlledToken(), this.render(!0));
  }
  /** @override */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      template: `systems/${game.system.id}/templates/window/action_manager.hbs`,
      width: 310,
      height: 70,
      left: _a14.DEF_LEFT,
      top: _a14.DEF_TOP,
      scale: 1,
      popOut: !1,
      minimizable: !1,
      resizable: !1,
      title: "action-manager"
    });
  }
  /** @override */
  getData(_options = {}) {
    var _a19;
    return {
      position: this.position,
      name: this.target && this.target.name.toLocaleUpperCase(),
      actions: this.getActions(),
      clickable: ((_a19 = game.user) == null ? void 0 : _a19.isGM) || game.settings.get(game.system.id, LANCER.setting_actionTracker).allowPlayers
    };
  }
  // DATA BINDING
  /**
   * Get proxy for ease of migration when we change over to MM data backing.
   * @returns actions map.
   */
  getActions() {
    return this.target ? getActions(this.target) : null;
  }
  async reset() {
    await this.close(), this.render(!0);
  }
  async update(_force) {
    _a14.enabled && (await this.updateControlledToken(), this.render(!0));
  }
  async updateConfig() {
    game.settings.get(game.system.id, LANCER.setting_actionTracker).showHotbar && !game.settings.get("core", "noCanvas") ? (await this.update(), _a14.enabled = !0) : (this.close(), _a14.enabled = !1);
  }
  async updateControlledToken() {
    var _a19, _b;
    if (!canvas.ready)
      return;
    const token = (_b = (_a19 = canvas.tokens) == null ? void 0 : _a19.controlled) == null ? void 0 : _b[0];
    if (token && token.inCombat && token.actor) {
      const actor = token.actor;
      if (actor.is_mech() || actor.is_npc()) {
        this.target = token.actor;
        return;
      }
    }
    this.target = null;
  }
  /**
   * Resets actions to their default state.
   */
  async resetActions() {
    this.target && (console.log("Resetting " + this.target.name), modAction(this.target, !1));
  }
  // UI //
  /** @override */
  activateListeners(html) {
    this.dragElement(html), html.find("#action-manager-reset").on("click", (e) => {
      var _a19;
      e.preventDefault(), this.canMod() ? this.resetActions() : console.log(`${(_a19 = game.user) == null ? void 0 : _a19.name} :: Users currently not allowed to reset actions through action manager.`);
    }), html.find("a.action[data-action]").on("click", (e) => {
      var _a19;
      if (e.preventDefault(), this.canMod()) {
        const action = e.currentTarget.dataset.action;
        action && this.target && toggleAction(this.target, action);
      } else
        console.log(`${(_a19 = game.user) == null ? void 0 : _a19.name} :: Users currently not allowed to toggle actions through action manager.`);
    }), this.loadTooltips();
  }
  loadUserPos() {
    var _a19, _b;
    if (!((_b = (_a19 = game.user) == null ? void 0 : _a19.getFlag(game.system.id, "action-manager")) != null && _b.pos))
      return;
    const pos = game.user.getFlag(game.system.id, "action-manager").pos, appPos = this.position;
    return new Promise((resolve) => {
      function loop() {
        let ele = document.getElementById("action-manager");
        if (ele) {
          const newTop = pos.top < 5 || pos.top > window.innerHeight + 5 ? _a14.DEF_TOP : pos.top, newLeft = pos.left < 5 || pos.left > window.innerWidth + 5 ? _a14.DEF_LEFT : pos.left;
          appPos.top = newTop, appPos.left = newLeft, ele.style.top = newTop + "px", ele.style.left = newLeft + "px", resolve(!0);
        } else
          setTimeout(loop, 20);
      }
      __name(loop, "loop"), loop();
    });
  }
  loadTooltips() {
    tippy$1('.action[data-action="protocol"]', {
      content: "Protocol"
    }), tippy$1('.action[data-action="full"]', {
      content: "Full Action"
    }), tippy$1('.action[data-action="quick"]', {
      content: "Quick Action"
    }), tippy$1('.action[data-action="move"]', {
      content: "Movement Action"
    }), tippy$1('.action[data-action="reaction"]', {
      content: "Reaction"
    }), tippy$1('.action[data-action="free"]', {
      content: "Free Actions"
    });
  }
  // HELPERS //
  dragElement(html) {
    const appPos = this.position;
    html.find("#action-manager-drag").on("mousedown", (ev) => {
      ev.preventDefault(), ev = ev || window.event;
      let hud2 = $(document.body).find("#action-manager"), marginLeft = parseInt(hud2.css("marginLeft").replace("px", "")), marginTop = parseInt(hud2.css("marginTop").replace("px", ""));
      dragElement(document.getElementById("action-manager"));
      let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
      function dragElement(elmnt) {
        elmnt.onmousedown = dragMouseDown;
        function dragMouseDown(e) {
          e = e || window.event, e.preventDefault(), pos3 = e.clientX, pos4 = e.clientY, document.onmouseup = closeDragElement, document.onmousemove = elementDrag;
        }
        __name(dragMouseDown, "dragMouseDown");
        function elementDrag(e) {
          e = e || window.event, e.preventDefault(), pos1 = pos3 - e.clientX, pos2 = pos4 - e.clientY, pos3 = e.clientX, pos4 = e.clientY, elmnt.style.top = elmnt.offsetTop - pos2 - marginTop + "px", elmnt.style.left = elmnt.offsetLeft - pos1 - marginLeft + "px";
        }
        __name(elementDrag, "elementDrag");
        function closeDragElement() {
          var _a19;
          elmnt.onmousedown = null, document.onmouseup = null, document.onmousemove = null;
          let xPos = elmnt.offsetLeft - pos1 > window.innerWidth ? window.innerWidth : elmnt.offsetLeft - pos1, yPos = elmnt.offsetTop - pos2 > window.innerHeight - 20 ? window.innerHeight - 100 : elmnt.offsetTop - pos2;
          xPos = xPos < 8 ? 0 : xPos - 8, yPos = yPos < 8 ? 0 : yPos - 8, (xPos != elmnt.offsetLeft - pos1 || yPos != elmnt.offsetTop - pos2) && (elmnt.style.top = yPos + "px", elmnt.style.left = xPos + "px"), console.log(`Action Manager | CACHING: ${xPos} || ${yPos}.`), (_a19 = game.user) == null || _a19.update({ flags: { lancer: { "action-manager": { pos: { top: yPos, left: xPos } } } } }), appPos.top = yPos, appPos.left = xPos;
        }
        __name(closeDragElement, "closeDragElement");
      }
      __name(dragElement, "dragElement");
    });
  }
  canMod() {
    var _a19;
    return ((_a19 = game.user) == null ? void 0 : _a19.isGM) || game.settings.get(game.system.id, LANCER.setting_actionTracker).allowPlayers;
  }
}, __name(_a14, "_LancerActionManager"), _a14);
_LancerActionManager.DEF_LEFT = 600;
_LancerActionManager.DEF_TOP = 20;
let LancerActionManager = _LancerActionManager;
const _InventoryDialog = class _InventoryDialog extends Dialog {
  constructor(actor, dialogData, options = {}) {
    super(dialogData, options), this.actor = actor, this.actor = actor;
  }
  /* -------------------------------------------- */
  /** @override */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      template: `systems/${game.system.id}/templates/window/inventory.hbs`,
      width: 600,
      height: "auto",
      classes: ["lancer", "inventory-editor"]
    });
  }
  async getData() {
    return {
      ...await super.getData(),
      categories: this.populate_categories(this.actor)
    };
  }
  /** @inheritdoc */
  render(force, options = {}) {
    return this.actor.apps[this.appId] = this, super.render(force, options);
  }
  async close(options = {}) {
    return delete this.actor.apps[this.appId], super.close(options);
  }
  // Get the appropriate cats for the given actor
  populate_categories(actor) {
    let cats = [];
    return actor.is_mech() ? cats = [
      {
        label: "Frames",
        items: actor.items.filter((i) => i.is_frame())
      },
      {
        label: "Weapons",
        items: actor.items.filter((i) => i.is_mech_weapon())
      },
      {
        label: "Systems",
        items: actor.items.filter((i) => i.is_mech_system())
      },
      {
        label: "Mods",
        items: actor.items.filter((i) => i.is_weapon_mod())
      },
      {
        label: "Statuses",
        items: actor.items.filter((i) => i.is_status())
      }
    ] : actor.is_pilot() ? cats = [
      {
        label: "Weapons",
        items: actor.items.filter((i) => i.is_pilot_weapon())
      },
      {
        label: "Armor",
        items: actor.items.filter((i) => i.is_pilot_armor())
      },
      {
        label: "Gear",
        items: actor.items.filter((i) => i.is_pilot_gear())
      },
      {
        label: "Talents",
        items: actor.items.filter((i) => i.is_talent())
      },
      {
        label: "Skills",
        items: actor.items.filter((i) => i.is_skill())
      },
      {
        label: "Licenses",
        items: actor.items.filter((i) => i.is_license())
      },
      {
        label: "Core Bonuses",
        items: actor.items.filter((i) => i.is_core_bonus())
      },
      {
        label: "Reserves",
        items: actor.items.filter((i) => i.is_reserve())
      },
      {
        label: "Organizations",
        items: actor.items.filter((i) => i.is_organization())
      },
      {
        label: "Statuses",
        items: actor.items.filter((i) => i.is_status())
      }
    ] : console.warn("Cannot yet show inventory for " + actor.type), cats;
  }
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), initializeCollapses(html), applyCollapseListeners(html), handleGenControls(html, this.actor), handleRefDragging(html), handleContextMenus(html, this.actor), $(html).find(".ref.set.click-open").on("click", click_evt_open_ref);
  }
  static async show_inventory(actor) {
    return new Promise((resolve, _reject) => {
      new this(actor, {
        title: `${actor.name}'s inventory`,
        content: "",
        buttons: {},
        close: () => resolve(),
        default: ""
      }).render(!0);
    });
  }
};
__name(_InventoryDialog, "InventoryDialog");
let InventoryDialog = _InventoryDialog;
function registerTalentSteps(flowSteps) {
  flowSteps.set("printTalentCard", printTalentCard);
}
__name(registerTalentSteps, "registerTalentSteps");
const _TalentFlow = class _TalentFlow extends Flow {
  constructor(uuid, data2) {
    const state = {
      title: (data2 == null ? void 0 : data2.title) ?? "",
      rank: (data2 == null ? void 0 : data2.rank) ?? { name: "", description: "" },
      lvl: (data2 == null ? void 0 : data2.lvl) ?? 0
    };
    !state.title && uuid instanceof LancerItem && (state.title = uuid.name), super(uuid, state);
  }
};
__name(_TalentFlow, "TalentFlow");
let TalentFlow = _TalentFlow;
TalentFlow.steps = ["printTalentCard"];
function printTalentCard(state) {
  return printGenericCard(state, { template: `systems/${game.system.id}/templates/chat/talent-card.hbs` });
}
__name(printTalentCard, "printTalentCard");
async function beginItemChatFlow(item, data2) {
  if (item.is_skill())
    return await new SimpleHTMLFlow(item, {}).begin();
  if (item.is_mech_weapon() || item.is_pilot_weapon())
    return await new SimpleHTMLFlow(item, {}).begin();
  if (item.is_mech_system()) {
    const html = mechSystemView(item, null, { div: !0, vertical: !0, nonInteractive: !0 });
    return await new SimpleHTMLFlow(item, { html }).begin();
  } else if (item.is_talent()) {
    const lvl = data2.rank ?? item.system.curr_rank;
    return await new TalentFlow(item, {
      title: item.name,
      rank: item.system.ranks[lvl],
      lvl
    }).begin();
  } else if (item.is_frame()) {
    if (!data2.type)
      throw new TypeError("No type provided for frame flow!");
    if (data2.type === "trait") {
      if (!data2.index)
        throw new TypeError("No index provided for trait flow!");
      const trait = item.system.traits[data2.index];
      if (!trait)
        throw new TypeError(`No trait found at path ${data2.path}!`);
      return await new SimpleTextFlow(item, { title: trait.name, description: trait.description }).begin();
    }
    if (data2.type === "passive") {
      const core = item.system.core_system;
      return await new SimpleTextFlow(item, { title: core.passive_name, description: core.passive_effect }).begin();
    }
    throw new TypeError("Invalid path provided for frame flow!");
  } else
    return item.is_pilot_gear() ? await new SimpleTextFlow(item, {
      title: item.name,
      description: item.system.description,
      tags: item.system.tags
    }).begin() : item.is_core_bonus() ? await new SimpleTextFlow(item, { title: item.name, description: item.system.effect }).begin() : item.is_reserve() ? await new SimpleTextFlow(item, {
      title: `RESERVE :: ${item.name}`,
      description: (item.system.label ? `<b>${item.system.label}</b></br>` : "") + item.system.description
    }).begin() : item.is_npc_feature() ? await new SimpleTextFlow(item, {
      title: item.name,
      description: item.system.effect,
      tags: item.system.tags
    }).begin() : (console.log("No macro exists for that item type"), ui.notifications.error(`Error - No macro exists for item type "${item.type}"`), !1);
}
__name(beginItemChatFlow, "beginItemChatFlow");
const lp$9 = LANCER.log_prefix, _LancerActorSheet = class _LancerActorSheet extends ActorSheet {
  constructor() {
    super(...arguments), this.collapse_handler = new CollapseHandler();
  }
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      scrollY: [".scroll-body"]
    });
  }
  /* -------------------------------------------- */
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), attachTagTooltips(html), initializeCollapses(html), applyCollapseListeners(html), this._activateActionGridListeners(html), handleRefClickOpen(html), handleRefDragging(html), this.options.editable && (this._activateFlowListeners(html), this._activateFlowDragging(html), handleInputPlusMinusButtons(html, this.actor), handleCounterInteraction(html, this.actor), handleUsesInteraction(html, this.actor), handleLoadedInteraction(html, this.actor), handleChargedInteraction(html, this.actor), handlePowerUsesInteraction(html, this.actor), handleContextMenus(html, this.actor), this._activateInventoryButton(html), handleRefSlotDropping(html, this.actor, (x) => this.quickOwnDrop(x).then((v) => v[0])), handleGenControls(html, this.actor), handlePopoutTextEditor(html, this.actor), handleDocDropping(
      html,
      async (entry, _dest, _event) => this.onRootDrop(entry, _event, _dest),
      (entry, _dest, _event) => this.canRootDrop(entry)
    ));
  }
  _activateFlowDragging(html) {
    const FlowDragHandler = /* @__PURE__ */ __name((e) => this._onFlowButtonDragStart(e), "FlowDragHandler");
    html.find(".lancer-flow-button").add(".roll-stat").add(".roll-attack").add(".roll-tech").add(".roll-damage").add(".chat-flow-button").add(".skill-flow").add(".bond-power-flow").add(".effect-flow").add(".activation-flow").each((_i, item) => {
      item.setAttribute("draggable", "true"), item.addEventListener("dragstart", FlowDragHandler, !1);
    });
  }
  _onFlowButtonDragStart(e) {
    var _a19, _b;
    if (!e.currentTarget)
      return;
    e.stopPropagation();
    const dragElement = $(e.currentTarget);
    let data2 = null;
    if (dragElement.hasClass("lancer-flow-button")) {
      const flowElement = $(e.currentTarget).closest("[data-flow-type]")[0], flowType = DroppableFlowType.BASIC, flowSubtype = flowElement.dataset.flowType, flowArgs = JSON.parse(flowElement.dataset.flowArgs ?? "{}");
      flowSubtype && (data2 = {
        lancerType: this.actor.type,
        uuid: this.actor.uuid,
        flowType,
        flowSubtype,
        args: flowArgs
      });
    } else if (dragElement.hasClass("roll-stat")) {
      const statPath = $(e.currentTarget).closest("[data-uuid]")[0].dataset.path;
      if (!statPath)
        throw Error("No stat path found!");
      data2 = {
        lancerType: this.actor.type,
        uuid: this.actor.uuid,
        flowType: DroppableFlowType.STAT,
        args: { statPath }
      };
    } else if (dragElement.hasClass("roll-attack") || dragElement.hasClass("roll-damage")) {
      const weaponId = $(e.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      if (!weaponId)
        throw Error("No weapon ID found!");
      data2 = {
        lancerType: LancerItem.fromUuidSync(weaponId, `Invalid weapon ID: ${weaponId}`).type,
        uuid: weaponId,
        flowType: dragElement.hasClass("roll-attack") ? DroppableFlowType.ATTACK : DroppableFlowType.DAMAGE,
        args: {}
      };
    } else if (dragElement.hasClass("roll-tech")) {
      const techId = $(e.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      if (!techId)
        throw Error("No tech ID found!");
      data2 = {
        lancerType: LancerItem.fromUuidSync(techId, `Invalid tech ID: ${techId}`).type,
        uuid: techId,
        flowType: DroppableFlowType.TECH_ATTACK,
        args: {}
      };
    } else if (dragElement.hasClass("chat-flow-button")) {
      const el = $(e.currentTarget).closest("[data-uuid]")[0];
      if (!el || !el.dataset.uuid)
        throw Error("No item UUID found!");
      data2 = {
        lancerType: LancerItem.fromUuidSync(el.dataset.uuid, `Invalid item ID: ${el.dataset.uuid}`).type,
        uuid: el.dataset.uuid,
        flowType: DroppableFlowType.CHAT,
        args: { ...el.dataset }
      };
    } else if (dragElement.hasClass("skill-flow")) {
      const skillId = $(e.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      if (!skillId)
        throw Error("No skill ID found!");
      data2 = {
        lancerType: LancerItem.fromUuidSync(skillId, `Invalid skill ID: ${skillId}`).type,
        uuid: skillId,
        flowType: DroppableFlowType.SKILL,
        args: { skillId }
      };
    } else if (dragElement.hasClass("bond-power-flow")) {
      const powerElement = $(e.currentTarget).closest("[data-uuid]")[0], bondId = powerElement.dataset.uuid;
      if (!bondId)
        throw Error("No bond ID found!");
      const bond = LancerItem.fromUuidSync(bondId, `Invalid bond ID: ${bondId}`), powerIndex = parseInt(powerElement.dataset.powerIndex ?? "-1");
      data2 = {
        lancerType: bond.type,
        uuid: bondId,
        flowType: DroppableFlowType.BOND_POWER,
        args: { powerIndex }
      };
    } else if (dragElement.hasClass("effect-flow")) {
      const itemId = $(e.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      if (!itemId)
        throw Error("No item ID found!");
      data2 = {
        lancerType: LancerItem.fromUuidSync(itemId, `Invalid item ID: ${itemId}`).type,
        uuid: itemId,
        flowType: DroppableFlowType.EFFECT,
        args: {}
      };
    } else if (dragElement.hasClass("activation-flow")) {
      const el = $(e.currentTarget).closest("[data-uuid]")[0], itemId = el.dataset.uuid, path = el.dataset.path;
      if (!itemId || !path)
        throw Error("No item ID from activation chip");
      let isDeployable = path.includes("deployable"), isAction = !isDeployable && path.includes("action"), isCoreSystem = !isDeployable && path.includes("core_system");
      const item = LancerItem.fromUuidSync(itemId, `Invalid item ID: ${itemId}`);
      if (isAction)
        data2 = {
          lancerType: item.type,
          uuid: itemId,
          flowType: DroppableFlowType.ACTIVATION,
          args: { path }
        };
      else if (isCoreSystem)
        data2 = {
          lancerType: item.type,
          uuid: itemId,
          flowType: DroppableFlowType.CORE_ACTIVE,
          args: { path }
        };
      else if (!isDeployable)
        throw ui.notifications.error("Could not infer action type"), Error("Could not infer action type");
    }
    data2 && ((_a19 = e.dataTransfer) == null || _a19.setData("text/plain", JSON.stringify(data2)), console.log("Flow drag data:", data2, (_b = e.dataTransfer) == null ? void 0 : _b.getData("text/plain")));
  }
  async _activateActionGridListeners(html) {
    html.find(".lancer-action-button").on("click", async (ev) => {
      var _a19, _b;
      if (ev.stopPropagation(), (_a19 = game.user) != null && _a19.isGM || game.settings.get(game.system.id, LANCER.setting_actionTracker).allowPlayers) {
        const params = ev.currentTarget.dataset, action = params.action, data2 = await this.getData();
        if (action && params.val) {
          let spend;
          params.action === "move" ? spend = parseInt(params.val) > 0 : spend = params.val === "true", modAction(data2.actor, spend, action);
        }
      } else
        console.log(`${(_b = game.user) == null ? void 0 : _b.name} :: Users currently not allowed to toggle actions through action manager.`);
    });
  }
  _activateFlowListeners(html) {
    html.find(".lancer-flow-button").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const flowElement = $(ev.currentTarget).closest("[data-flow-type]")[0], flowType = flowElement.dataset.flowType, flowArgs = JSON.parse(flowElement.dataset.flowArgs ?? "{}"), BasicFlowType = LancerFlowState.BasicFlowType;
      switch (flowType) {
        case BasicFlowType.FullRepair:
          this.actor.beginFullRepairFlow((flowArgs == null ? void 0 : flowArgs.title) ?? void 0);
          break;
        case BasicFlowType.Stabilize:
          this.actor.beginStabilizeFlow((flowArgs == null ? void 0 : flowArgs.title) ?? void 0);
          break;
        case BasicFlowType.Overheat:
          this.actor.beginOverheatFlow();
          break;
        case BasicFlowType.Structure:
          this.actor.beginStructureFlow();
          break;
        case BasicFlowType.Overcharge:
          this.actor.beginOverchargeFlow();
          break;
        case BasicFlowType.Burn:
          this.actor.beginBurnFlow();
          break;
        case BasicFlowType.BasicAttack:
          this.actor.beginBasicAttackFlow((flowArgs == null ? void 0 : flowArgs.title) ?? void 0);
          break;
        case BasicFlowType.Damage:
          this.actor.beginDamageFlow((flowArgs == null ? void 0 : flowArgs.title) ?? void 0);
          break;
        case BasicFlowType.TechAttack:
          this.actor.beginBasicTechAttackFlow((flowArgs == null ? void 0 : flowArgs.title) ?? void 0);
          break;
      }
    }), html.find(".roll-stat").on("click", (ev) => {
      ev.stopPropagation();
      const statPath = $(ev.currentTarget).closest("[data-uuid]")[0].dataset.path;
      if (!statPath)
        throw Error("No stat path found!");
      this.actor.beginStatFlow(statPath);
    }), html.find(".roll-attack").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const weaponId = $(ev.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      LancerItem.fromUuidSync(weaponId ?? "", `Invalid weapon ID: ${weaponId}`).beginWeaponAttackFlow();
    }), html.find(".roll-tech").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const techId = $(ev.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      LancerItem.fromUuidSync(techId ?? "", `Invalid weapon ID: ${techId}`).beginTechAttackFlow();
    }), html.find(".roll-damage").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const itemId = $(ev.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      LancerItem.fromUuidSync(itemId ?? "", `Invalid item ID: ${itemId}`).beginDamageFlow();
    }), html.find(".chat-flow-button").on("click", async (ev) => {
      ev.stopPropagation();
      const el = $(ev.currentTarget).closest("[data-uuid]")[0];
      if (!el || !el.dataset.uuid)
        throw Error("No item UUID found!");
      const item = await LancerItem.fromUuid(el.dataset.uuid);
      if (!item)
        throw Error(`UUID "${el.dataset.uuid}" does not resolve to an item!`);
      beginItemChatFlow(item, el.dataset);
    }), html.find(".skill-flow").on("click", (ev) => {
      ev.stopPropagation();
      const skillId = $(ev.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
      LancerItem.fromUuidSync(skillId ?? "", `Invalid skill ID: ${skillId}`).beginSkillFlow();
    }), html.find(".bond-power-flow").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const powerElement = $(ev.currentTarget).closest("[data-uuid]")[0], bondId = powerElement.dataset.uuid, bond = LancerItem.fromUuidSync(bondId ?? "", `Invalid bond ID: ${bondId}`), powerIndex = parseInt(powerElement.dataset.powerIndex ?? "-1");
      bond.beginBondPowerFlow(powerIndex);
    }), html.find(".bond-xp-button").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const actor = this.actor;
      !actor.is_pilot() || !actor.system.bond || actor.tallyBondXP();
    }), html.find(".refresh-powers-button").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation();
      const actor = this.actor;
      !actor.is_pilot() || !actor.system.bond || actor.system.bond.refreshPowers();
    }), html.find(".effect-flow").on("click", (ev) => {
      ev.stopPropagation();
      const itemId = ev.currentTarget.closest("[data-uuid]").dataset.uuid;
      LancerItem.fromUuidSync(itemId ?? "", `Invalid item ID: ${itemId}`).beginSystemFlow();
    }), html.find(".activation-flow").on("click", (ev) => {
      ev.stopPropagation();
      const el = ev.currentTarget, itemId = el.dataset.uuid, path = el.dataset.path;
      if (!itemId || !path)
        throw Error("No item ID from activation chip");
      let isDeployable = path.includes("deployable"), isAction = !isDeployable && path.includes("action"), isCoreSystem = !isDeployable && path.includes("core_system");
      const item = LancerItem.fromUuidSync(itemId ?? "", `Invalid item ID: ${itemId}`);
      isAction ? item.beginActivationFlow(path) : isCoreSystem ? item.beginCoreActiveFlow(path) : isDeployable || ui.notifications.error("Could not infer action type");
    }), html.find(".charge-macro").on("click", (ev) => {
      ev.stopPropagation(), this.actor.beginRechargeFlow();
    });
  }
  /**
   * Handles inventory button
   */
  _activateInventoryButton(html) {
    html.find(".inventory button").on("click", async (ev) => (ev.preventDefault(), InventoryDialog.show_inventory(this.actor)));
  }
  // A grand filter that pre-decides if we can drop an item ref anywhere within this sheet. Should be implemented by child sheets
  // We generally assume that a global item is droppable if it matches our types, and that an owned item is droppable if it is owned by this actor
  // This is more of a permissions/suitability question
  canRootDrop(_item) {
    return !1;
  }
  // This function is called on any dragged item that percolates down to root without being handled
  // Override/extend as appropriate
  async onRootDrop(_item, _event, _dest) {
  }
  // Override base behavior
  _createDragDropHandlers() {
    return [];
  }
  // Makes us own (or rather, creates an owned copy of) the provided item if we don't already.
  // The second return value indicates whether a new copy was made (true), or if we already owned it/it is an actor (false)
  // Note: this operation also fixes limited to be the full capability of our actor
  async quickOwn(document2) {
    return this.actor.quickOwn(document2);
  }
  // As quick_own, but for any drop. Maintains drop structure, since not necessarily guaranteed to have made an item
  async quickOwnDrop(drop) {
    if (drop.type == "Item") {
      let [document2, new_] = await this.quickOwn(drop.document);
      return [
        {
          type: "Item",
          document: document2
        },
        new_
      ];
    } else
      return [drop, !1];
  }
  _propagateData(formData) {
    let token = this.actor.prototypeToken;
    token ? (this.actor.img === token.texture.src && this.actor.img !== formData.img && (formData["prototypeToken.texture.src"] = formData.img), this.actor.name === token.name && this.actor.name !== formData.name && (formData["prototypeToken.name"] = formData.name)) : (formData["prototypeToken.texture.src"] = formData.img, formData["prototypeToken.name"] = formData.name);
  }
  /**
   * Implement the _updateObject method as required by the parent class spec
   * This defines how to update the subject of the form when the form is submitted
   * @private
   */
  async _updateObject(_event, formData) {
    return this._propagateData(formData), await this.actor.update(formData), this.actor;
  }
  /**
   * Prepare data for rendering the Actor sheet
   * The prepared data object contains both the actor data as well as additional sheet options
   */
  async getData() {
    const data2 = await super.getData();
    if (data2.collapse = {}, data2.system = this.actor.system, data2.system.loadout)
      for (const [key, value] of Object.entries(data2.system.loadout))
        Array.isArray(value) && (data2.system.loadout[key] = value.sort(
          (a, b) => {
            var _a19, _b;
            return ((_a19 = a == null ? void 0 : a.value) == null ? void 0 : _a19.sort) - ((_b = b == null ? void 0 : b.value) == null ? void 0 : _b.sort);
          }
        ));
    data2.itemTypes = this.actor.itemTypes;
    for (const [key, value] of Object.entries(data2.itemTypes))
      data2.itemTypes[key] = value.sort((a, b) => a.sort - b.sort);
    return data2.effect_categories = LancerActiveEffect.prepareActiveEffectCategories(this.actor), data2.deployables = lookupOwnedDeployables(this.actor), console.log(`${lp$9} Rendering with following actor ctx: `, data2), data2;
  }
};
__name(_LancerActorSheet, "LancerActorSheet");
let LancerActorSheet = _LancerActorSheet;
const _LancerDeployableSheet = class _LancerDeployableSheet extends LancerActorSheet {
  /**
   * Extend and override the default options used by the NPC Sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["lancer", "sheet", "actor", "deployable"],
      template: `systems/${game.system.id}/templates/actor/deployable.hbs`,
      width: 800,
      height: 800,
      tabs: [
        {
          navSelector: ".lancer-tabs",
          contentSelector: ".sheet-body",
          initial: "status"
        }
      ]
    });
  }
  // Need to allow this stuff for setting deployable
  canRootDrop(item) {
    return item.type === "Actor" && [EntryType.PILOT, EntryType.MECH, EntryType.NPC].includes(item.document.type) || item.type === "Item" && item.document.is_status();
  }
  async onRootDrop(drop, _event, _dest) {
    drop.type == "Actor" && drop.document != this.actor && this.actor.update({ "system.owner": drop.document.uuid });
  }
  /* -------------------------------------------- */
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), this.options.editable;
  }
};
__name(_LancerDeployableSheet, "LancerDeployableSheet");
let LancerDeployableSheet = _LancerDeployableSheet;
const _LancerMechSheet = class _LancerMechSheet extends LancerActorSheet {
  /**
   * Extend and override the default options used by the NPC Sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["lancer", "sheet", "actor", "mech"],
      template: `systems/${game.system.id}/templates/actor/mech.hbs`,
      width: 900,
      height: 800,
      tabs: [
        {
          navSelector: ".lancer-tabs",
          contentSelector: ".sheet-body",
          initial: "stats"
        }
      ]
    });
  }
  /* -------------------------------------------- */
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), this.options.editable && (this._activateOverchargeControls(html), this._activateLoadoutControls(html), this._activateMountContextMenus(html));
  }
  /* -------------------------------------------- */
  canRootDrop(item) {
    return item.type == "Actor" && item.document.is_pilot() ? !0 : item.type === "Item" ? item.document.is_mech_system() || item.document.is_mech_weapon() || item.document.is_frame() || item.document.is_status() : !1;
  }
  async onRootDrop(base_drop, event, _dest) {
    let [drop, is_new] = await this.quickOwnDrop(base_drop);
    if (drop.type == "Item" && drop.document.is_frame() && this.actor.is_mech()) {
      const oldFrame = this.actor.items.find((i) => i.is_frame() && i.id != drop.document.id);
      oldFrame && await this.actor.deleteEmbeddedDocuments("Item", [oldFrame.id]), await this.actor.swapFrameImage(drop.document), await this.actor.updateTokenSize(drop.document), await this.actor.update({
        "system.loadout.frame": drop.document.id
      }), await this.actor.loadoutHelper.resetMounts();
    } else if (is_new && drop.type == "Item" && drop.document.is_mech_weapon()) {
      let currMounts = foundry.utils.duplicate(
        // @ts-expect-error
        this.actor.system._source.loadout.weapon_mounts
      ), set = !1;
      for (let mount of currMounts) {
        if (set)
          break;
        for (let i = 0; i < mount.slots.length; i++)
          if (!mount.slots[i].weapon) {
            mount.slots[i].weapon = drop.document.id, set = !0;
            break;
          }
      }
      await this.actor.update({
        "system.loadout.weapon_mounts": currMounts
      });
    } else if (is_new && drop.type == "Item" && drop.document.is_mech_system()) {
      let oldSystems = this.actor.system._source.loadout.systems;
      await this.actor.update({
        "system.loadout.systems": [...oldSystems, drop.document.id]
      });
    } else
      drop.type == "Actor" && drop.document.is_pilot() && (await this.actor.update({
        "system.pilot": drop.document.uuid
      }), await drop.document.update({
        "system.active_mech": this.actor.uuid
      }));
    this.isEditable && !is_new && drop.type === "Item" && drop.document.is_mech_system() && this._onSortItem(event, drop.document.toObject());
  }
  /**
   * Handles actions in the overcharge panel
   */
  _activateOverchargeControls(html) {
    html.find(".overcharge-text").on("click", (ev) => {
      this.actor.is_mech() && this._setOverchargeLevel(ev, Math.min(this.actor.system.overcharge + 1, 3));
    }), html.find(".overcharge-reset").on("click", (ev) => {
      this._setOverchargeLevel(ev, 0);
    });
  }
  /**
   * Sets the overcharge level for this actor
   * @param event An event, used by a proper overcharge section in the sheet, to get the overcharge field
   * @param level Level to set overcharge to
   */
  async _setOverchargeLevel(_event, level) {
    return this.actor.update({
      "system.overcharge": level
    });
  }
  /**
   * Handles more niche controls in the loadout in the overcharge panel
   */
  _activateLoadoutControls(html) {
    html.find(".reset-weapon-mount-button").on("click", async (evt) => {
      this._event_handler("reset-wep", evt);
    }), html.find(".reset-all-weapon-mounts-button").on("click", async (evt) => {
      this._event_handler("reset-all-weapon-mounts", evt);
    }), html.find(".reset-system-mount-button").on("click", async (evt) => {
      this._event_handler("reset-sys", evt);
    });
  }
  // Allows user to change mount size via right click ctx
  _activateMountContextMenus(html) {
    let mount_options = [];
    for (let selection of Object.values(MountType))
      mount_options.push({
        name: selection,
        icon: "",
        callback: async (html2) => {
          var _a19, _b, _c, _d, _e, _f;
          let mountPath = html2[0].dataset.path ?? "", mount = resolveDotpath(this.actor, mountPath);
          mount || console.error("Bad mountpath:", mountPath);
          let newSlots = [], newSlotTypes = fittingsForMount(selection);
          newSlots = newSlots.splice(newSlotTypes.length);
          for (let i = 0; i < newSlotTypes.length; i++)
            (_b = (_a19 = mount.slots[i]) == null ? void 0 : _a19.weapon) != null && _b.value ? newSlots.push({
              mod: ((_d = (_c = mount.slots[i].mod) == null ? void 0 : _c.value) == null ? void 0 : _d.id) ?? null,
              size: newSlotTypes[i],
              weapon: ((_f = (_e = mount.slots[i].weapon) == null ? void 0 : _e.value) == null ? void 0 : _f.id) ?? null
            }) : newSlots.push({
              mod: null,
              size: newSlotTypes[i],
              weapon: null
            });
          this.actor.update({
            [mountPath + ".type"]: selection,
            [mountPath + ".bracing"]: !1,
            [mountPath + ".slots"]: newSlots
          });
        }
      });
    mount_options.push({
      name: "Superheavy Bracing",
      icon: "",
      callback: async (html2) => {
        let cd = await this.getData(), mountPath = html2[0].dataset.path ?? "";
        resolveDotpath(cd, mountPath) || console.error("Bad mountpath:", mountPath), this.actor.update({
          [mountPath + ".type"]: MountType.Unknown,
          [mountPath + ".bracing"]: !0,
          [mountPath + ".slots"]: []
        });
      }
    }), new ContextMenu(html, ".mount-type-ctx-root", mount_options);
  }
  // Save ourselves repeat work by handling most events clicks actual operations here
  async _event_handler(mode, evt) {
    var _a19, _b, _c;
    evt.stopPropagation(), this.actor;
    let path = (_b = (_a19 = evt.currentTarget) == null ? void 0 : _a19.dataset) == null ? void 0 : _b.path;
    switch (mode) {
      case "reset-all-weapon-mounts":
        await this.actor.loadoutHelper.resetMounts();
        break;
      case "reset-sys":
        this.actor.update({ "system.loadout.systems": [] });
        break;
      case "reset-wep":
        if (!path)
          return;
        (_c = ui.notifications) == null || _c.info("TODO: Reset the weapons");
        break;
      default:
        return;
    }
  }
  async getData() {
    var _a19, _b, _c, _d;
    let data2 = await super.getData();
    return data2.pilot = (_a19 = this.actor.system.pilot) == null ? void 0 : _a19.value, data2.is_active = ((_d = (_c = (_b = this.actor.system.pilot) == null ? void 0 : _b.value) == null ? void 0 : _c.system.active_mech) == null ? void 0 : _d.value) == this.actor, data2;
  }
};
__name(_LancerMechSheet, "LancerMechSheet");
let LancerMechSheet = _LancerMechSheet;
const _LancerNPCSheet = class _LancerNPCSheet extends LancerActorSheet {
  /**
   * Extend and override the default options used by the NPC Sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["lancer", "sheet", "actor", "npc"],
      template: `systems/${game.system.id}/templates/actor/npc.hbs`,
      width: 800,
      height: 800,
      tabs: [
        {
          navSelector: ".lancer-tabs",
          contentSelector: ".sheet-body",
          initial: "mech"
        }
      ]
    });
  }
  /* -------------------------------------------- */
  /**
   * Activate event listeners using the prepared sheet HTML
   * @param html {HTMLElement}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), this.options.editable && this.actor.isOwner && (html.find(".item-macro").on("click", (ev) => {
      ev.stopPropagation(), $(ev.currentTarget).closest("[data-uuid]")[0];
    }), html.find(".roll-tech").on("click", (ev) => {
      if (!ev.currentTarget)
        return;
      ev.stopPropagation(), $(ev.currentTarget).closest("[data-uuid]")[0].dataset.uuid;
    }), html.find('li[class*="item"]').add('span[class*="item"]').each((_i, item) => {
      item.classList.contains("inventory-header") || (item.classList.contains("roll-stat") && item.addEventListener("dragstart", this._onDragMacroableStart, !1), item.classList.contains("item") && item.addEventListener("dragstart", (ev) => this._onDragStart(ev), !1), item.setAttribute("draggable", "true"));
    }));
  }
  _onDragMacroableStart(event) {
    var _a19;
    event.stopPropagation();
    let statInput = getStatInput(event);
    if (!statInput)
      return ui.notifications.error("Error finding stat input for macro.");
    let tSplit = statInput.id.split("."), data2 = {
      title: tSplit[tSplit.length - 1].toUpperCase(),
      dataPath: statInput.id,
      type: "actor",
      actorId: this.actor.id
    };
    (_a19 = event.dataTransfer) == null || _a19.setData("text/plain", JSON.stringify(data2));
  }
  /* -------------------------------------------- */
  canRootDrop(item) {
    return item.type === "Item" && (item.document.is_npc_class() || item.document.is_npc_feature() || item.document.is_npc_template() || item.document.is_status());
  }
  // Take ownership of appropriate items. Already filtered by can_drop_entry
  async onRootDrop(base_drop, event, _dest) {
    if (!this.actor.is_npc())
      return;
    let [drop, is_new] = await this.quickOwnDrop(base_drop), needs_refresh = is_new && drop.type == "Item" && (drop.document.is_npc_class() || drop.document.is_npc_template());
    if (is_new && drop.type == "Item") {
      let doc = drop.document;
      doc.is_npc_class() && (await this.actor.swapFrameImage(doc), await this.actor.updateTokenSize(doc));
    }
    needs_refresh && await this.actor.update({
      "system.hp.value": this.actor.system.hp.max,
      "system.stress.value": this.actor.system.stress.max,
      "system.structure.value": this.actor.system.structure.max
    }), this.isEditable && !is_new && drop.type === "Item" && drop.document.is_npc_feature() && this._onSortItem(event, drop.document.toObject());
  }
};
__name(_LancerNPCSheet, "LancerNPCSheet");
let LancerNPCSheet = _LancerNPCSheet;
function getStatInput(event) {
  return event.currentTarget ? $(event.currentTarget).closest(".stat-container").find(".lancer-stat")[0] : null;
}
__name(getStatInput, "getStatInput");
function _flowButton(button_class, html_data, overrides = {}) {
  const tooltip = overrides.tooltip ? `data-tooltip="${overrides.tooltip}"` : "";
  return `<a class="${button_class} lancer-button ${overrides.classes ?? ""}" ${html_data} ${tooltip}>
    <i class="fas ${overrides.icon ?? "fa-dice-d20"} i--dark i--s"></i>
  </a>`;
}
__name(_flowButton, "_flowButton");
function _statFlowButton(uuid, path, overrides = {}) {
  const data2 = `data-uuid="${uuid}" data-path="${path}" data-flow-args=""`;
  return _flowButton("roll-stat", data2, overrides);
}
__name(_statFlowButton, "_statFlowButton");
function _basicFlowButton(uuid, type2 = "BasicAttack", overrides = {}) {
  const data2 = `data-uuid="${uuid}" data-flow-type="${type2}"`;
  return _flowButton("lancer-flow-button", data2, overrides);
}
__name(_basicFlowButton, "_basicFlowButton");
function getActorUUID(options) {
  const rActor = options.data.root.actor;
  return (rActor == null ? void 0 : rActor.uuid) ?? null;
}
__name(getActorUUID, "getActorUUID");
function stat_edit_card_max(title, icon, data_path, max_path, options) {
  let data_val = resolveHelperDotpath(options, data_path, 0), max_val = resolveHelperDotpath(options, max_path, 0);
  return `
    <div class="stat-card card clipped">
      <div class="lancer-header lancer-primary ">
        <i class="${icon} i--m i--light header-icon"> </i>
        <span class="major">${title}</span>
      </div>
      ${std_x_of_y(data_path, data_val, max_val, "lancer-stat")}
    </div>
    `;
}
__name(stat_edit_card_max, "stat_edit_card_max");
function stat_edit_card(title, icon, data_path, options) {
  let flowButton = "";
  return options.rollable && data_path === "system.burn" && (flowButton = _basicFlowButton(getActorUUID(options), "Burn", {
    icon: "cci cci-burn",
    tooltip: "Roll a burn check and generate damage"
  })), `
    <div class="card clipped">
      <div class="lancer-header lancer-primary ">
        <i class="${icon} i--m i--light header-icon"> </i>
        <span class="major">${title}</span>
      </div>
      <div class="${flowButton ? "stat-flow-container" : "flexrow flex-center"}">
        ${flowButton}
        ${std_num_input(data_path, extendHelper(options, { classes: "lancer-stat" }))}
      </div>
    </div>
    `;
}
__name(stat_edit_card, "stat_edit_card");
function stat_edit_rollable_card(title, icon, data_path, options) {
  return stat_edit_card(title, icon, data_path, { ...options, rollable: !0 });
}
__name(stat_edit_rollable_card, "stat_edit_rollable_card");
function stat_view_card(title, icon, data_path, options) {
  let dataVal = resolveHelperDotpath(options, data_path), leftFlowButton = "", rightFlowButton = "";
  return options.rollable && (leftFlowButton = _statFlowButton(getActorUUID(options), data_path), (data_path === "system.grit" || data_path === "system.tier") && (rightFlowButton = _basicFlowButton(getActorUUID(options), "BasicAttack", {
    icon: "cci cci-weapon",
    tooltip: "Roll a basic attack"
  }))), `
    <div class="stat-card card clipped">
      <div class="lancer-header lancer-primary ">
        ${inc_if(`<i class="${icon} i--m i--light header-icon"> </i>`, icon)}
        <span class="major">${title}</span>
      </div>
      <div class="${leftFlowButton || rightFlowButton ? "stat-flow-container" : "flexrow flex-center"}">
        ${leftFlowButton}
        <span class="lancer-stat major" data-path="${data_path}">${dataVal}</span>
        ${rightFlowButton}
      </div>
    </div>
    `;
}
__name(stat_view_card, "stat_view_card");
function stat_rollable_card(title, icon, data_path, options) {
  return stat_view_card(title, icon, data_path, { ...options, rollable: !0 });
}
__name(stat_rollable_card, "stat_rollable_card");
function compact_stat_view(icon, data_path, options) {
  let data_val = resolveHelperDotpath(options, data_path);
  return `        
    <div class="compact-stat">
        <i class="${icon} i--m i--dark"></i>
        <span class="lancer-stat minor">${data_val}</span>
    </div>
    `;
}
__name(compact_stat_view, "compact_stat_view");
function compact_stat_edit(icon, data_path, max_path, options) {
  resolveHelperDotpath(options, data_path);
  let max_html = "";
  return max_path && (max_html = `<span class="lancer-stat minor" style="max-width: min-content;" > / </span>
    <span class="lancer-stat minor">${resolveHelperDotpath(options, max_path)}</span>`), `        
        <div class="compact-stat">
          <i class="${icon} i--m i--dark"></i>
          ${std_num_input(data_path, extendHelper(options, { classes: "lancer-stat minor" }))}
          ${max_html}
        </div>
    `;
}
__name(compact_stat_edit, "compact_stat_edit");
function clicker_num_input(data_path, options) {
  return `<div class="flexrow arrow-input-container">
      <button class="clicker-minus-button input-update" type="button">‒</button>
      ${std_num_input(data_path, extendHelper(options, { classes: "lancer-stat minor", default: 0 }))}
      <button class="clicker-plus-button input-update" type="button">+</button>
    </div>`;
}
__name(clicker_num_input, "clicker_num_input");
function clicker_stat_card(title, icon, data_path, roller, options) {
  let uuid = getActorUUID(options) ?? "unknown", statButton = "", attackButton = "<div></div>";
  return roller && (statButton = `<a class="roll-stat lancer-button" data-uuid="${uuid}" data-path="${data_path}"><i class="fas fa-dice-d20 i--dark i--s"></i></a>`, (data_path === "system.grit" || data_path === "system.tier") && (attackButton = _basicFlowButton(uuid, "BasicAttack", { icon: "cci cci-weapon" }))), `<div class="card clipped stat-container">
      <div class="lancer-header lancer-primary ">
        <i class="${icon} i--m i--light header-icon"> </i>
        <span class="major">${title}</span>
      </div>
      <div class="flexrow">
        ${statButton}
        ${clicker_num_input(data_path, options)}
        ${attackButton}
      </div>
    </div>
  `;
}
__name(clicker_stat_card, "clicker_stat_card");
function bond_answer_selector(pilot, index2) {
  const bond = pilot.system.bond, currentAnswer = pilot.system.bond_state.answers[index2];
  if (!bond || index2 > bond.system.questions.length - 1)
    return "";
  let options = "";
  return bond.system.questions[index2].options.forEach((answer) => {
    options += `<option value="${answer}" ${currentAnswer === answer ? "selected" : ""}>${answer}</option>
`;
  }), `<select class="bond-question-select" name="system.bond_state.answers.${index2}" data-type="String">
    ${options}
  </select>`;
}
__name(bond_answer_selector, "bond_answer_selector");
function bond_minor_ideal_selector(pilot) {
  const bond = pilot.system.bond, current_ideal = pilot.system.bond_state.minor_ideal;
  let options = "";
  return bond == null || bond.system.minor_ideals.forEach((ideal) => {
    options += `<option value="${ideal}" ${current_ideal === ideal ? "selected" : ""}>${ideal}</option>
`;
  }), `<select class="bond-ideal-select" name="system.bond_state.minor_ideal" data-type="String">
    ${options}
  </select>`;
}
__name(bond_minor_ideal_selector, "bond_minor_ideal_selector");
function action_button(title, data_path, action, options) {
  var _a19;
  let action_val = resolveHelperDotpath(options, data_path), active2;
  action == "move" ? (active2 = action_val > 0, title = `${title} (${action_val})`) : active2 = action_val;
  let enabled = !1;
  ((_a19 = game.user) != null && _a19.isGM || game.settings.get(game.system.id, LANCER.setting_actionTracker).allowPlayers) && (enabled = !0);
  const icon = `<i class="${actionIcon(action)} i--m"></i>`;
  return `
    <button
      class="lancer-action-button lancer-button${enabled ? " enabled" : ""}${active2 ? ` active lancer-${action}` : ""}"
      data-action="${action}"
      data-val="${action_val}"
  >
    ${icon}
    ${title}
  </button>`;
}
__name(action_button, "action_button");
function actor_flow_button(title, type2, options) {
  let args = JSON.stringify({}), mIcon;
  const BasicFlowType = LancerFlowState.BasicFlowType;
  switch (type2) {
    case BasicFlowType.FullRepair:
      mIcon = "cci-repair";
      break;
    case BasicFlowType.Stabilize:
      mIcon = "cci-marker";
      break;
    case BasicFlowType.Overheat:
      mIcon = "cci-heat";
      break;
    case BasicFlowType.Structure:
      mIcon = "cci-condition-shredded";
      break;
    case BasicFlowType.BasicAttack:
      mIcon = "cci-weapon";
      break;
    case BasicFlowType.Damage:
      mIcon = "cci-large-beam";
      break;
    case BasicFlowType.TechAttack:
      mIcon = "cci-tech-quick";
      break;
  }
  return `
      <button type="button" class="lancer-flow-button lancer-button lancer-secondary" data-flow-type="${type2}" data-flow-args=${args}>
        <i class="cci ${mIcon} i--m"></i> ${title}
      </button>
    `;
}
__name(actor_flow_button, "actor_flow_button");
function tech_flow_card(title, icon, data_path, options) {
  let uuid = getActorUUID(options) ?? "unknown", data_val = resolveHelperDotpath(options, data_path);
  return `
    <div class="stat-card card clipped">
      <div class="lancer-header lancer-primary">
        ${inc_if(`<i class="${icon} i--m i--light header-icon"> </i>`, icon)}
        <span class="major">${title}</span>
      </div>
      <div class="stat-flow-container">
        ${_basicFlowButton(uuid, "TechAttack", { icon: "cci cci-tech-quick" })}
        <span class="lancer-stat major" data-path="${data_path}">${data_val}</span>
      </div>
    </div>
    `;
}
__name(tech_flow_card, "tech_flow_card");
function npc_stat_block_clicker_card(title, data_base_path, key, options) {
  let stat_blocks = resolveHelperDotpath(options, data_base_path) ?? [], tier_clickers = [];
  for (let tier = 1; tier <= stat_blocks.length; tier++)
    tier_clickers.push(`
      <div class="flexrow stat-container" style="align-self: center;">
        <i class="cci cci-npc-tier-${tier} i--m i--dark"></i>
        ${clicker_num_input(`${data_base_path}.${tier - 1}.${key}`, options)}
      </div>`);
  return `
    <div class="card clipped">
      <div class="flexrow lancer-header lancer-primary major">
        ${title}
      </div>
      ${tier_clickers.join("")}
    </div>`;
}
__name(npc_stat_block_clicker_card, "npc_stat_block_clicker_card");
function npc_stat_array_clicker_card(title, path, options) {
  let stats = resolveHelperDotpath(options, path) ?? [], tier_clickers = [];
  for (let tier = 1; tier <= stats.length; tier++)
    tier_clickers.push(`
      <div class="flexrow stat-container" style="align-self: center;">
        <i class="cci cci-npc-tier-${tier} i--m i--dark"></i>
        ${clicker_num_input(`${path}.${tier - 1}`, options)}
      </div>`);
  return `
    <div class="card clipped">
      <div class="flexrow lancer-header major">
        ${title}
      </div>
      ${tier_clickers.join("")}
    </div>`;
}
__name(npc_stat_array_clicker_card, "npc_stat_array_clicker_card");
function overchargeButton(actor, overcharge_path, options) {
  const sequence = actor.system.overcharge_sequence.split(",");
  let index2 = resolveHelperDotpath(options, overcharge_path);
  index2 = Math.max(0, Math.min(sequence.length - 1, index2));
  let overchargeValue = sequence[index2];
  return `
    <div class="flexcol card clipped">
      <div class="lancer-header lancer-primary clipped-top flexrow">
        <span class="major">OVERCHARGE</span>
      </div>
      <div class="overcharge-container">
        ${_basicFlowButton(actor.uuid, "Overcharge")}
        <a class="overcharge-text">${overchargeValue}</a>
        <a class="overcharge-reset mdi mdi-restore"></a>
      </div>
    </div>`;
}
__name(overchargeButton, "overchargeButton");
function npc_tier_selector(tier_path, options) {
  let tier = resolveHelperDotpath(options, tier_path) ?? 1;
  return `<select class="tier-control" name="npctier">
    ${[1, 2, 3].map(
    (tier_option) => `
    <option value="${tier_option}" ${selected(tier_option === tier)}>TIER ${tier_option}</option>
  `
  ).join("")}
  </select>`;
}
__name(npc_tier_selector, "npc_tier_selector");
function is_combatant(actor) {
  const combat = game.combat;
  if (combat)
    return combat.combatants.find((comb) => {
      var _a19;
      return ((_a19 = comb.actor) == null ? void 0 : _a19.uuid) == actor.uuid;
    });
}
__name(is_combatant, "is_combatant");
function deployer_slot(data_path, options) {
  let existing = resolveHelperDotpath(options, data_path, null);
  return existing ? `
    <div class="card clipped ${existing.type} ref set click-open" ${ref_params(existing)}>
      <div class="compact-deployer medium flexrow" >
        <span class="img-bar" style="background-image: url(${existing.img});"> </span>
        <div class="major modifier-name i--light">${existing.type.toUpperCase()} ${existing.name}</div>
      </div>
    </div>` : simple_ref_slot(data_path, [EntryType.PILOT, EntryType.MECH, EntryType.NPC], options);
}
__name(deployer_slot, "deployer_slot");
const lp$8 = LANCER.log_prefix;
async function importCC(pilot, data2, clearFirst = !0) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
  if (!game.settings.get(game.system.id, LANCER.setting_core_data)) {
    ui.notifications.warn(
      "You must import the Core Book Data in the Lancer Compendium Manager before importing a pilot.",
      { permanent: !0 }
    );
    return;
  }
  if (console.log(`${lp$8} Importing Pilot`, pilot, data2), !(!pilot.is_pilot() || !data2)) {
    if (clearFirst) {
      await pilot.deleteEmbeddedDocuments("Item", Array.from(pilot.items.keys()));
      let existing_mechs = ((_a19 = game.actors) == null ? void 0 : _a19.filter((x) => {
        var _a20;
        return x.is_mech() && ((_a20 = x.system.pilot) == null ? void 0 : _a20.value) == pilot;
      })) ?? [];
      for (let m of existing_mechs)
        await m.deleteEmbeddedDocuments("Item", Array.from(m.items.keys()));
    }
    await pilot.update({
      name: data2.name
    });
    try {
      let unitFolder = pilot.folder, permission = foundry.utils.duplicate(pilot.ownership);
      const canCreate = (_b = game.user) == null ? void 0 : _b.can("ACTOR_CREATE"), gmsOnline = (_c = game.users) == null ? void 0 : _c.some((u) => u.isGM && u.active);
      !canCreate && !gmsOnline && new foundry.applications.api.DialogV2({
        window: { title: "Cannot Create Actors", icon: "fas fa-triangle-exclamation" },
        content: `<p>You are not permitted to create actors and no GM's are online, so sync will not produce any new mechs or deployables.</p>
        <p>Your GM can allow Players/Trusted Players to create actors in Settings->Configure Permissions.</p>`,
        buttons: [
          {
            action: "close",
            icon: "fas fa-check",
            label: "Close",
            default: !0
          }
        ]
      }).render(!0);
      const missingActors = [], missingItems = [];
      let populatedGear = [], populatedArmor = [], populatedWeapons = [], bond = null;
      if (data2.loadout) {
        let pilotItemPool = [...pilot.items.contents];
        const getPilotItemByLid = /* @__PURE__ */ __name(async (lid) => {
          const existingItem = pilotItemPool.findSplice((i) => i.system.lid == lid);
          if (existingItem)
            return existingItem;
          {
            let fromCompendium = await fromLid(lid);
            if (!fromCompendium) {
              missingItems.push({ actor: pilot.name, lid });
              return;
            }
            return (await insinuate([fromCompendium], pilot))[0];
          }
        }, "getPilotItemByLid");
        let itemUpdates = [], flatGear = [...data2.loadout.gear ?? [], ...data2.loadout.extendedGear ?? []].filter((g) => g);
        for (let gear of flatGear) {
          let g = await getPilotItemByLid(gear == null ? void 0 : gear.id);
          g && populatedGear.push(g.id);
        }
        let flatArmor = (data2.loadout.armor ?? []).filter((a) => a);
        for (let armor of flatArmor) {
          let a = await getPilotItemByLid(armor == null ? void 0 : armor.id);
          a && populatedArmor.push(a.id);
        }
        let flatWeapons = [...data2.loadout.weapons ?? [], ...data2.loadout.extendedWeapons ?? []].filter((w) => w);
        for (let weapon of flatWeapons) {
          let w = await getPilotItemByLid(weapon == null ? void 0 : weapon.id);
          w && populatedWeapons.push(w.id);
        }
        for (let coreBonus of data2.core_bonuses)
          await getPilotItemByLid(coreBonus);
        for (let skill of data2.skills)
          if (skill.custom)
            pilot.createEmbeddedDocuments("Item", [
              {
                type: EntryType.SKILL,
                name: skill.id ?? "Custom Skill",
                "system.rank": skill.rank,
                "system.description": skill.custom_desc || skill.custom_detail || ""
              }
            ]);
          else {
            let s = await getPilotItemByLid(skill.id);
            s && itemUpdates.push({
              _id: s.id,
              "system.curr_rank": skill.rank
            });
          }
        for (let talent of data2.talents) {
          let t = await getPilotItemByLid(talent.id);
          t && itemUpdates.push({
            _id: t.id,
            "system.curr_rank": talent.rank
          });
        }
        if (bond = data2.bondId ? await getPilotItemByLid(data2.bondId) : null, bond && data2.bondPowers) {
          bond.system.powers.forEach((p) => {
            p.unlocked = !1;
          });
          const bondPack = game.packs.get(get_pack_id(EntryType.BOND));
          await (bondPack == null ? void 0 : bondPack.getIndex());
          const bonds = await (bondPack == null ? void 0 : bondPack.getDocuments({ type: EntryType.BOND })) ?? null, unlockAndRefill = /* @__PURE__ */ __name(function(power) {
            power.unlocked = !0, power.uses && (power.uses.value = power.uses.max);
          }, "unlockAndRefill");
          data2.bondPowers.forEach((p) => {
            let i = bond.system.powers.findIndex((x) => x.name == p.name);
            if (i != null && i != -1) {
              const power = bond.system.powers[i];
              unlockAndRefill(power);
              return;
            }
            let found = !1;
            for (const b of bonds) {
              if (found || !b.is_bond())
                return;
              const newPower = b.system.powers.find((x) => x.name == p.name);
              if (newPower) {
                if (found = !0, unlockAndRefill(newPower), bond.system.powers.push(newPower), i = bond.system.powers.findIndex((x) => x.veteran), i != null && i != -1) {
                  const power = bond.system.powers[i];
                  unlockAndRefill(power);
                }
                break;
              }
            }
          }), await bond.update({ "system.powers": bond.system.powers });
        }
        for (let license2 of data2.licenses) {
          let t = await getPilotItemByLid(`lic_${license2.id}`);
          t && itemUpdates.push({
            _id: t.id,
            "system.curr_rank": license2.rank
          });
        }
        await pilot.updateEmbeddedDocuments("Item", itemUpdates);
        let toDelete = pilotItemPool.filter(
          (x) => [EntryType.TALENT, EntryType.SKILL, EntryType.CORE_BONUS].includes(x.type)
        );
        await pilot._safeDeleteDescendant("Item", toDelete);
      }
      await pilot.update({
        name: data2.name,
        img: replaceDefaultResource(pilot.img, data2.cloud_portrait),
        system: {
          "hp.value": data2.current_hp,
          // Pilot specific
          background: data2.background,
          callsign: data2.callsign,
          cloud_id: data2.cloudID,
          history: data2.history,
          level: data2.level,
          loadout: {
            armor: populatedArmor,
            gear: populatedGear,
            weapons: populatedWeapons
          },
          hull: data2.mechSkills[0],
          agi: data2.mechSkills[1],
          sys: data2.mechSkills[2],
          eng: data2.mechSkills[3],
          mounted: ((_d = data2.state) == null ? void 0 : _d.mounted) ?? !0,
          notes: data2.notes,
          player_name: data2.player_name,
          status: data2.status,
          text_appearance: data2.text_appearance,
          bond_state: bond ? {
            "xp.value": data2.xp,
            "stress.value": data2.stress,
            answers: data2.bondAnswers,
            minor_ideal: data2.minorIdeal,
            burdens: data2.burdens.map((b) => ({
              lid: b.id,
              name: b.title,
              min: 0,
              max: b.segments,
              value: b.progress,
              default_value: 0
            })),
            clocks: data2.clocks.map((c) => ({
              lid: c.id,
              name: c.title,
              min: 0,
              max: c.segments,
              value: c.progress,
              default_value: 0
            }))
          } : void 0
        },
        prototypeToken: {
          name: data2.name,
          // @ts-expect-error
          "texture.src": replaceDefaultResource((_f = (_e = pilot.prototypeToken) == null ? void 0 : _e.texture) == null ? void 0 : _f.src, data2.cloud_portrait, pilot.img)
        }
      });
      let activeMechUuid = "";
      for (const cloudMech of data2.mechs) {
        let mech = game.actors.find(
          (m) => m.is_mech() && m.system.lid == cloudMech.id
        );
        if (!mech) {
          if (!((_g = game.user) != null && _g.can("ACTOR_CREATE"))) {
            ui.notifications.warn(
              `Could not import mech '${cloudMech.name}' as you lack the permission to create new actors. Please ask your GM for assistance (either they import for you, or give you permissions)`,
              { permanent: !0 }
            ), missingActors.push({ name: cloudMech.name, lid: cloudMech.frame });
            continue;
          }
          mech = await LancerActor.create({
            name: cloudMech.name,
            type: EntryType.MECH,
            folder: unitFolder == null ? void 0 : unitFolder.id,
            ownership: permission,
            system: {
              pilot: pilot.uuid
            }
          });
        }
        if (!mech.canUserModify(game.user, "update")) {
          ui.notifications.warn(
            `Could not import mech '${cloudMech.name}' as you lack the permission to update the actor. Please ask your GM for assistance.`,
            { permanent: !0 }
          ), missingActors.push({ name: cloudMech.name, lid: cloudMech.frame });
          continue;
        }
        let mechItemPool = [...mech.items.contents];
        const getMechItemByLid = /* @__PURE__ */ __name(async (lid) => {
          let foundItem = mechItemPool.findSplice((i) => i.system.lid == lid);
          if (foundItem)
            return foundItem;
          {
            let fromCompendium = await fromLid(lid);
            if (!fromCompendium) {
              missingItems.push({ actor: mech.name, lid });
              return;
            }
            return (await insinuate([fromCompendium], mech))[0];
          }
        }, "getMechItemByLid");
        let loadout = cloudMech.loadouts[cloudMech.active_loadout_index], frame = await getMechItemByLid(cloudMech.frame), flatSystems = [...loadout.integratedSystems, ...loadout.systems], populatedSystems = [], assocSystemData = /* @__PURE__ */ new Map();
        for (let sys of flatSystems) {
          let realSys = await getMechItemByLid(sys.id);
          realSys && (populatedSystems.push(realSys.id), assocSystemData.set(realSys.id, sys));
        }
        let flatMounts = [], assocWeaponData = /* @__PURE__ */ new Map();
        (_h = loadout.integratedWeapon) != null && _h.slots.some((x) => x.weapon) && flatMounts.push(loadout.integratedWeapon), (_i = loadout.improved_armament) != null && _i.slots.some((x) => x.weapon) && flatMounts.push(loadout.improved_armament), (_j = loadout.superheavy_mounting) != null && _j.slots.some((x) => x.weapon) && flatMounts.push(loadout.superheavy_mounting), flatMounts.push(
          ...loadout.integratedMounts.map((im) => ({
            mount_type: MountType.Integrated,
            slots: [
              {
                weapon: im.weapon,
                mod: null,
                size: FittingSize.Integrated
              }
            ],
            extra: [],
            bonus_effects: []
          })).filter((im) => im.slots.some((x) => x.weapon))
        ), flatMounts.push(...loadout.mounts);
        let populatedMounts = [];
        for (let mount of flatMounts) {
          let populatedSlots = [];
          for (const slot of mount.slots) {
            let weapon = slot.weapon ? await getMechItemByLid(slot.weapon.id) : null, mod = weapon && ((_k = slot.weapon) != null && _k.mod) ? await getMechItemByLid(slot.weapon.mod.id) : null;
            populatedSlots.push({
              mod: (mod == null ? void 0 : mod.id) ?? null,
              weapon: (weapon == null ? void 0 : weapon.id) ?? null,
              size: slot.size
            });
            for (const extraSlot of mount.extra) {
              let weapon2 = extraSlot.weapon ? await getMechItemByLid(extraSlot.weapon.id) : null, mod2 = weapon2 && ((_l = extraSlot.weapon) != null && _l.mod) ? await getMechItemByLid(extraSlot.weapon.mod.id) : null;
              populatedSlots.push({
                mod: (mod2 == null ? void 0 : mod2.id) ?? null,
                weapon: (weapon2 == null ? void 0 : weapon2.id) ?? null,
                size: slot.size
              });
            }
            weapon && assocWeaponData.set(weapon.id, slot.weapon), mod && assocSystemData.set(weapon.id, slot.weapon.mod);
          }
          populatedMounts.push({
            bracing: mount.lock ?? !1,
            type: mount.mount_type,
            slots: populatedSlots
          });
        }
        await mech.update({
          name: cloudMech.name,
          folder: unitFolder ? unitFolder.id : null,
          img: replaceDefaultResource(mech.img, cloudMech.portrait, frame ? frameToPath(frame.name) : null),
          permission,
          prototypeToken: {
            name: pilot.system.callsign || cloudMech.name,
            disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
            "texture.src": replaceDefaultResource(
              (_n = (_m = mech.prototypeToken) == null ? void 0 : _m.texture) == null ? void 0 : _n.src,
              cloudMech.cloud_portrait,
              frame ? frameToPath(frame.name) : null
            )
          },
          system: {
            // Universal stuff
            lid: cloudMech.id,
            "hp.value": cloudMech.current_hp,
            "overshield.value": cloudMech.overshield,
            burn: cloudMech.burn,
            activations: cloudMech.activations,
            // custom_counters: cloud_mech. - CC Doesn't have these except on pilots
            "heat.value": cloudMech.current_heat,
            "stress.value": cloudMech.current_stress,
            "structure.value": cloudMech.current_structure,
            // Mech stuff
            overcharge: cloudMech.current_overcharge,
            "repairs.value": cloudMech.current_repairs,
            core_active: cloudMech.core_active,
            core_energy: cloudMech.current_core_energy,
            // meltdown_timer: - CC doesn't help with this
            notes: cloudMech.notes,
            pilot: pilot.uuid,
            // Maybe handle ejected state? Who cares?
            loadout: {
              frame: (frame == null ? void 0 : frame.id) ?? null,
              weapon_mounts: populatedMounts,
              systems: populatedSystems
            }
          }
        }), (!((_o = data2.state) != null && _o.active_mech_id) || mech.system.lid == ((_p = data2.state) == null ? void 0 : _p.active_mech_id)) && (activeMechUuid = mech.uuid);
        let itemUpdates = [];
        for (let mount of mech.system.loadout.weapon_mounts)
          for (let slot of mount.slots) {
            if (slot.weapon) {
              let data22 = assocWeaponData.get(slot.weapon.id);
              data22 && itemUpdates.push({
                _id: slot.weapon.id,
                system: {
                  loaded: data22.loaded,
                  destroyed: data22.destroyed,
                  cascading: data22.cascading,
                  "uses.value": data22.uses
                }
              });
            }
            if (slot.mod) {
              let data22 = assocSystemData.get(slot.mod.id);
              data22 && itemUpdates.push({
                _id: slot.mod.id,
                system: {
                  destroyed: data22.destroyed,
                  cascading: data22.cascading,
                  "uses.value": data22.uses
                }
              });
            }
          }
        for (let system of mech.system.loadout.systems) {
          if (!(system != null && system.value))
            continue;
          let data22 = assocSystemData.get(system.id);
          data22 && itemUpdates.push({
            _id: system.id,
            system: {
              destroyed: data22.destroyed,
              cascading: data22.cascading,
              uses: data22.uses
            }
          });
        }
        await mech.updateEmbeddedDocuments("Item", itemUpdates);
      }
      if (await pilot.update({
        "system.active_mech": activeMechUuid,
        "system.last_cloud_update": (/* @__PURE__ */ new Date()).toISOString()
      }), pilot.effectHelper.propagateEffects(!0), pilot.render(), missingItems.length || missingActors.length) {
        let message = `Partially loaded '${pilot.name}'s new state.`;
        missingActors.length && (message += ` ${missingActors.length} actors could not be created/updated.`), missingItems.length && (message += ` ${missingItems.length} items could not be found.`), message += " See dialog for details.", ui.notifications.warn(message, { permanent: !0 }), console.warn(`${lp$8} Some actors and/or items were missed during pilot import:`, missingActors, missingItems);
        let content = "";
        missingActors.length && (content += `<div><span>The following Actors could not be created or updated:</span>
        <ul>${missingActors.map((i) => `<li>${i.name} - ${i.lid}</li>`).join("")}</ul></div>`), missingItems.length && (content += `<div><span>The following Items were not found in the compendium and could not be imported:</span>
        <ul>${missingItems.map((i) => `<li>${i.actor} - ${i.lid}</li>`).join("")}</ul>
        <span>Import all necessary LCPs first using the <b>Lancer Compendium Manager</b>.</span></div>`), new foundry.applications.api.DialogV2({
          window: { title: "Incomplete Pilot Import", icon: "fas fa-triangle-exclamation" },
          content,
          buttons: [
            {
              action: "close",
              icon: "fas fa-check",
              label: "Close",
              default: !0
            }
          ]
        }).render(!0);
      } else
        ui.notifications.info("Successfully loaded pilot new state.");
    } catch (e) {
      console.warn(e), ui.notifications.warn(`Failed to update pilot: ${e instanceof Error ? e.message : e}`, { permanent: !0 });
    }
  }
}
__name(importCC, "importCC");
const lp$7 = LANCER.log_prefix, shareCodeMatcher = /^[A-Z0-9\d]{6}$/g, COUNTER_MAX = 8, _LancerPilotSheet = class _LancerPilotSheet extends LancerActorSheet {
  /**
   * Extend and override the default options used by the Pilot Sheet
   * @returns {Object}
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["lancer", "sheet", "actor", "pilot"],
      template: `systems/${game.system.id}/templates/actor/pilot.hbs`,
      width: 900,
      height: 800,
      tabs: [
        {
          navSelector: ".lancer-tabs",
          contentSelector: ".sheet-body",
          initial: "tactical"
        }
      ]
    });
  }
  /**
   * Activate event listeners using the prepared sheet HTML
   * @param html {JQuery}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    if (super.activateListeners(html), !!this.options.editable && this.actor.isOwner) {
      let pilot = this.actor;
      html.find('select[name="selectCloudId"]').on("change", (evt) => {
        evt.stopPropagation(), pilot.update({ "system.cloud_id": evt.target.value });
      });
      let download = html.find('.cloud-control[data-action*="download"]');
      pilot.system.cloud_id ? download.on("click", async (ev) => {
        ev.stopPropagation();
        let raw_pilot_data = null;
        if (pilot.system.cloud_id.match(shareCodeMatcher)) {
          ui.notifications.info("Importing character from share code..."), console.log(`Attempting import with share code: ${pilot.system.cloud_id}`);
          try {
            raw_pilot_data = await fetchPilotViaShareCode(pilot.system.cloud_id);
          } catch (error) {
            ui.notifications.error("Error importing from share code. Share code may need to be refreshed."), console.error(`Failed import with share code ${pilot.system.cloud_id}, error:`, error);
            return;
          }
        } else if (pilot.system.cloud_id) {
          ui.notifications.info("Importing character from COMP/CON account...");
          const cachedPilot = pilotCache().find((p) => p.cloudID == pilot.system.cloud_id);
          if (cachedPilot != null)
            try {
              raw_pilot_data = await fetchPilotViaCache(cachedPilot);
            } catch (error) {
              ui.notifications.error(
                "Failed to import from COMP/CON account. Try refreshing the page to reload pilot list."
              ), console.error(`Failed to import vaultID ${pilot.system.cloud_id} via pilot list, error:`, error);
              return;
            }
          else {
            ui.notifications.error(
              "Failed to import from COMP/CON account. Try refreshing the page to reload pilot list"
            ), console.error(`Failed to find pilot in cache, vaultID: ${pilot.system.cloud_id}`);
            return;
          }
        } else {
          ui.notifications.error(
            "Could not find character to import! No pilot selected via dropdown and no share code entered."
          );
          return;
        }
        await importCC(this.actor, raw_pilot_data);
      }) : download.addClass("disabled-cloud"), html.find("input#pilot-json-import").on("change", (ev) => this._onPilotJsonUpload(ev)), html.find('input[name="rawID"]').on("input", async (ev) => {
        ev.target.value != "" && (html.find('select[name="vaultID"]')[0].value = "");
      }), html.find(".activate-mech").on("click", async (ev) => {
        ev.stopPropagation();
        let mech = await resolve_ref_element(ev.currentTarget.parentElement);
        !mech || !mech.is_mech() || this.activateMech(mech);
      }), html.find(".deactivate-mech").on("click", async (ev) => {
        ev.stopPropagation(), this.deactivateMech();
      });
    }
  }
  _onPilotJsonUpload(ev) {
    var _a19;
    const jsonFile = (_a19 = ev.target.files) == null ? void 0 : _a19[0];
    if (!jsonFile)
      return;
    console.log(`${lp$7} Selected file changed`, jsonFile);
    const fr = new FileReader();
    fr.addEventListener("load", (ev2) => {
      var _a20;
      this._onPilotJsonParsed((_a20 = ev2.target) == null ? void 0 : _a20.result);
    }), fr.readAsText(jsonFile);
  }
  async _onPilotJsonParsed(fileData) {
    if (!fileData)
      return;
    const pilotData = JSON.parse(fileData);
    console.log(`${lp$7} Pilot Data of selected JSON:`, pilotData), pilotData && (ui.notifications.info(`Starting import of ${pilotData.name}, Callsign ${pilotData.callsign}. Please wait.`), console.log(`${lp$7} Starting import of ${pilotData.name}, Callsign ${pilotData.callsign}.`), console.log(`${lp$7} Parsed Pilot Data pack:`, pilotData), await importCC(this.actor, pilotData), ui.notifications.info(`Import of ${pilotData.name}, Callsign ${pilotData.callsign} complete.`), console.log(`${lp$7} Import of ${pilotData.name}, Callsign ${pilotData.callsign} complete.`), this.render());
  }
  activateMech(mech) {
    let pilot = this.actor;
    pilot.update({ "system.active_mech": mech.uuid }), mech.update({ "system.pilot": pilot.uuid });
  }
  async deactivateMech() {
    await this.actor.update({
      "system.active_mech": null
    });
  }
  async getData() {
    const data2 = await super.getData();
    return data2.compConPilotList = pilotCache().sort((p1, p2) => p1.callsign < p2.callsign ? -1 : p1.callsign > p2.callsign ? 1 : p1.name < p2.name ? -1 : p1.name > p2.name ? 1 : 0).reduce((acc, pilot) => (acc[`${pilot.callsign} // ${pilot.name}`] = pilot.cloudID, acc), {}), data2;
  }
  // Pilots can handle most stuff
  canRootDrop(item) {
    return !!(item.type === "Actor" && item.document.is_mech() || item.type === "Item" && (item.document.is_core_bonus() || item.document.is_pilot_weapon() || item.document.is_pilot_armor() || item.document.is_pilot_gear() || item.document.is_license() || item.document.is_skill() || item.document.is_talent() || item.document.is_organization() || item.document.is_reserve() || item.document.is_bond() || item.document.is_status()));
  }
  async onRootDrop(base_drop, event, _dest) {
    if (!this.actor.is_pilot())
      return;
    let pilot = this.actor, loadout = pilot.system.loadout, oldBonds = pilot.items.filter((i) => i.is_bond()), [drop, is_new] = await this.quickOwnDrop(base_drop);
    if (drop.type == "Item") {
      if (drop.document.is_pilot_weapon()) {
        for (let i = 0; i < loadout.weapons.length || i <= 2; i++)
          if (!loadout.weapons[i]) {
            await pilot.update({
              [`system.loadout.weapons.${i}`]: drop.document.id
            });
            break;
          }
      } else if (drop.document.is_pilot_gear()) {
        for (let i = 0; i < loadout.gear.length || i <= 3; i++)
          if (!loadout.gear[i]) {
            await pilot.update({
              [`system.loadout.gear.${i}`]: drop.document.id
            });
            break;
          }
      } else if (drop.document.is_pilot_armor()) {
        for (let i = 0; i < loadout.armor.length || i <= 1; i++)
          if (!loadout.armor[i]) {
            await pilot.update({
              [`system.loadout.armor.${i}`]: drop.document.id
            });
            break;
          }
      } else if (is_new && drop.document.is_talent() || drop.document.is_skill())
        await drop.document.update({ "system.rank": 1 });
      else if (is_new && drop.document.is_bond() && oldBonds.length > 0)
        for (let oldBond of oldBonds)
          await pilot._safeDeleteDescendant("Item", [oldBond]);
    } else
      drop.type == "Actor" && drop.document.is_mech() && this.activateMech(drop.document);
  }
  /* -------------------------------------------- */
  /**
   * Implement the _updateObject method as required by the parent class spec
   * This defines how to update the subject of the form when the form is submitted
   * @private
   */
  async _updateObject(event, formData) {
    if (this.actor.is_pilot())
      return this.actor.system.callsign !== formData.callsign && (formData["prototypeToken.name"] = formData.callsign), super._updateObject(event, formData);
  }
};
__name(_LancerPilotSheet, "LancerPilotSheet");
let LancerPilotSheet = _LancerPilotSheet;
function pilotCounters(pilot, _options) {
  let counter_detail = "", counter_arr = pilot.system.custom_counters;
  for (let i = 0; i < counter_arr.length; i++) {
    const counter = counter_arr[i];
    counter.max != null && (counter.max <= COUNTER_MAX ? counter_detail = counter_detail.concat(
      buildCounterHTML(counter, `system.custom_counters.${i}`, { canDelete: !0 })
    ) : counter_detail = counter_detail.concat(
      buildCounterHeader(counter, `system.custom_counters.${i}`, { canDelete: !0 }),
      clicker_num_input(`system.custom_counters.${i}.value`, _options),
      "</div>"
    ));
  }
  return `
  <div class="card clipped double">
    <span class="lancer-header lancer-primary submajor" style="padding-right: 5px">
      <span>COUNTERS</span>
      <a class="gen-control fas fa-plus" data-action="append" data-path="system.custom_counters" data-action-value="(struct)counter"></a>
    </span>
    <div class="wraprow double">
      ${counter_detail}
    </div>
  </div>`;
}
__name(pilotCounters, "pilotCounters");
function allMechPreview(_options) {
  var _a19, _b;
  let active_mech = (_a19 = _options.data.root.system.active_mech) == null ? void 0 : _a19.value, owned_mechs = ((_b = game == null ? void 0 : game.actors) == null ? void 0 : _b.filter(
    (mech) => {
      var _a20;
      return mech.is_mech() && ((_a20 = mech.system.pilot) == null ? void 0 : _a20.status) == "resolved" && mech.system.pilot.value.id === _options.data.root.actor.id;
    }
  )) ?? [], as_html = [];
  for (let m of owned_mechs)
    as_html.push(mech_preview(m, m == active_mech));
  return as_html.join("");
}
__name(allMechPreview, "allMechPreview");
function mech_preview(mech, active2, _options) {
  let frame = mech.items.find((i) => i.type === EntryType.FRAME), mfr = frame == null ? void 0 : frame.system.manufacturer, preview_stats_arr = [
    { title: "HP", icon: "mdi mdi-heart-outline", path: "system.hp.value" },
    { title: "HEAT", icon: "cci cci-heat", path: "system.heat.value" },
    { title: "EVASION", icon: "cci cci-evasion", path: "system.evasion" },
    { title: "ARMOR", icon: "mdi mdi-shield-outline", path: "system.armor" },
    { title: "STRUCTURE", icon: "cci cci-structure", path: "system.structure.value" },
    { title: "STRESS", icon: "cci cci-reactor", path: "system.stress.value" },
    { title: "E-DEF", icon: "cci cci-edef", path: "system.edef" },
    { title: "SPEED", icon: "mdi mdi-arrow-right-bold-hexagon-outline", path: "system.speed" },
    { title: "SAVE", icon: "cci cci-save", path: "system.save" },
    { title: "SENSORS", icon: "cci cci-sensor", path: "system.sensor_range" }
  ], stats_html = "";
  for (let i = 0; i < preview_stats_arr.length; i++) {
    const builder = preview_stats_arr[i];
    stats_html = stats_html.concat(`
    <div class="mech-preview-stat-wrapper">
      <i class="${builder.icon} i--m i--dark"> </i>
      <span class="major">${builder.title}</span>
      <span class="major">${resolveDotpath(mech, builder.path, 0)}</span>
    </div>`);
  }
  let button = active2 ? '<a class="deactivate-mech"><i class="cci cci-deactivate"></i></a>' : '<a class="activate-mech"><i class="cci cci-activate"></i></a>';
  return `
  <div class="mech-preview lancer-border-${active2 ? "primary" : "dark-gray"}">
    <div class="mech-preview-titlebar ref set click-open ${active2 ? "active" : "inactive"}" ${ref_params(mech)}>
      ${button}
      <span>${mech.name}${inc_if(" // ACTIVE", active2)}  --  ${mfr} ${frame == null ? void 0 : frame.name}</span>
    </div>
    <img src="${mech.img}"/>
    ${stats_html}
  </div>`;
}
__name(mech_preview, "mech_preview");
const _ActionEditDialog = class _ActionEditDialog extends TargetedEditForm {
  /** @override */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      template: `systems/${game.system.id}/templates/window/action_editor.hbs`,
      title: "Action Editing",
      classes: ["lancer", "action-editor"],
      submitOnClose: !1
    });
  }
  getData() {
    let activation_type = {};
    return Object.entries(ActivationType).forEach((activation) => activation_type[activation[1]] = activation[1]), {
      ...super.getData(),
      action: this.value,
      activation_type,
      // Provide options for std-select for activation type
      path: this.value_path
    };
  }
  /** @override */
  fixupForm(form_data) {
    return {
      lid: form_data["action.lid"],
      name: form_data["action.name"],
      activation: form_data["action.activation"],
      cost: form_data["action.cost"],
      frequency: form_data["action.frequency"],
      init: form_data["action.init"],
      trigger: form_data["action.trigger"],
      terse: form_data["action.terse"],
      heat_cost: form_data["action.heat_cost"],
      tech_attack: form_data["action.tech_attack"],
      detail: this.value.detail,
      pilot: !!this.value.pilot,
      mech: !!this.value.mech,
      synergy_locations: this.value.synergy_locations || [],
      damage: this.value.damage || [],
      range: this.value.range || []
    };
  }
};
__name(_ActionEditDialog, "ActionEditDialog");
let ActionEditDialog = _ActionEditDialog;
const _BonusEditDialog = class _BonusEditDialog extends TargetedEditForm {
  /** @override */
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      template: `systems/${game.system.id}/templates/window/bonus.hbs`,
      classes: ["lancer", "bonus-editor"],
      title: "Bonus Editing"
    };
  }
  /** @override
   * Expose our data
   */
  getData() {
    let iconer = new IconFactory({
      size: "m"
    });
    return {
      ...super.getData(),
      damages: Object.values(DamageType).map((dt) => {
        var _a19;
        return {
          key: dt,
          label: iconer.r(Damage.IconFor(dt)),
          val: ((_a19 = this.value.damage_types) == null ? void 0 : _a19[dt]) ?? !1
        };
      }),
      ranges: Object.values(RangeType).map((rt) => {
        var _a19;
        return {
          key: rt,
          label: iconer.r(Range.IconFor(rt)),
          val: ((_a19 = this.value.range_types) == null ? void 0 : _a19[rt]) ?? !1
        };
      }),
      sizes: Object.values(WeaponSize).map((ws) => {
        var _a19;
        return {
          key: ws,
          label: ws,
          val: ((_a19 = this.value.weapon_sizes) == null ? void 0 : _a19[ws]) ?? !1
        };
      }),
      types: Object.values(WeaponType).map((wt) => {
        var _a19;
        return {
          key: wt,
          label: wt,
          val: ((_a19 = this.value.weapon_types) == null ? void 0 : _a19[wt]) ?? !1
        };
      })
    };
  }
  /** @override */
  fixupForm(form_data) {
    let new_bonus = {
      lid: form_data.lid,
      val: form_data.val,
      overwrite: form_data.overwrite,
      replace: form_data.replace,
      damage_types: {},
      range_types: {},
      weapon_sizes: {},
      weapon_types: {}
    };
    new_bonus.damage_types = {};
    for (let dt of Object.values(DamageType))
      new_bonus.damage_types[dt] = form_data[dt];
    new_bonus.range_types = {};
    for (let rt of Object.values(RangeType))
      new_bonus.range_types[rt] = form_data[rt];
    new_bonus.weapon_types = {};
    for (let wt of Object.values(WeaponType))
      new_bonus.weapon_types[wt] = form_data[wt];
    new_bonus.weapon_sizes = {};
    for (let ws of Object.values(WeaponSize))
      new_bonus.weapon_sizes[ws] = form_data[ws];
    return new_bonus;
  }
};
__name(_BonusEditDialog, "BonusEditDialog");
let BonusEditDialog = _BonusEditDialog;
const lp$6 = LANCER.log_prefix, _LancerItemSheet = class _LancerItemSheet extends ItemSheet {
  constructor(document2, options) {
    super(document2, options), this.collapse_handler = new CollapseHandler(), this.item.is_mech_weapon() && (this.options.initial = `profile${this.item.system.selected_profile_index}`);
  }
  /**
   * @override
   * Extend and override the default options used by the Item Sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["lancer", "sheet", "item"],
      width: 700,
      height: 700,
      tabs: [
        {
          navSelector: ".lancer-tabs",
          contentSelector: ".sheet-body",
          initial: "description"
        }
      ]
    });
  }
  /** @override */
  get template() {
    return `${`systems/${game.system.id}/templates/item`}/${this.item.type}.hbs`;
  }
  /* -------------------------------------------- */
  /**
   * Private helper that applies context menus according to the editability of the sheet.
   * @param html {JQuery}    The prepared HTML object ready to be rendered into the DOM
   * @param data_getter      Reference to a function which can provide the sheet data
   * @param commit_func      Reference to a function which can commit/save data back to the document
   */
  _activateContextListeners(html) {
    handleContextMenus(html, this.item, !this.options.editable), handleTagEditButtons(html, this.item);
  }
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {JQuery}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), initializeCollapses(html), applyCollapseListeners(html), $(html).find(".ref.set.click-open").on("click", click_evt_open_ref), handleRefDragging(html), this._activateContextListeners(html), this.options.editable && (handleInputPlusMinusButtons(html, this.item), handleCounterInteraction(html, this.item), handleUsesInteraction(html, this.item), handleDocListDropping(html, this.item), handleLIDListDropping(html, this.item), handleRefSlotDropping(html, this.item, null), BonusEditDialog.handle(html, ".editable.bonus", this.item), ActionEditDialog.handle(html, ".action-editor", this.item), handlePopoutTextEditor(html, this.item), handleGenControls(html, this.item));
  }
  /* -------------------------------------------- */
  /**
   * Implement the _updateObject method as required by the parent class spec
   * This defines how to update the subject of the form when the form is submitted
   * @private
   */
  async _updateObject(_event, formData) {
    await this.item.update(formData);
  }
  /**
   * Prepare data for rendering the frame sheet
   * The prepared data object contains both the actor data as well as additional sheet options
   */
  async getData() {
    var _a19, _b, _c;
    const data2 = super.getData();
    if (data2.system = this.item.system, data2.collapse = {}, data2.deployables = {}, !this.item.pack && this.item.actor)
      data2.deployables = lookupOwnedDeployables(this.item.actor);
    else {
      let deps = await ((_a19 = game.packs.get(get_pack_id(EntryType.DEPLOYABLE))) == null ? void 0 : _a19.getDocuments({ type: EntryType.DEPLOYABLE })) ?? [];
      for (let d of deps)
        data2.deployables[d.system.lid] = d;
    }
    return data2.license = null, (_b = this.actor) != null && _b.is_pilot() || (_c = this.actor) != null && _c.is_mech() ? data2.license = await findLicenseFor(this.item, this.actor) : data2.license = await findLicenseFor(this.item), this.item.is_organization() && (data2.org_types = OrgType), this.item.is_status() && (data2.status_types = StatusConditionType, data2.system.lid || (data2.system.lid = `status-${data2.document.id}`)), console.log(`${lp$6} Rendering with following item ctx: `, data2), data2;
  }
};
__name(_LancerItemSheet, "LancerItemSheet");
let LancerItemSheet = _LancerItemSheet;
const _LancerFrameSheet = class _LancerFrameSheet extends LancerItemSheet {
  /**
   * @override
   * Extend and override the default options used by the generic Lancer item sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      width: 700,
      height: 750
    });
  }
  // Handle the "delete" option of the mounts
  async _onChangeMount(event) {
    const elt = $(event.currentTarget), index2 = elt.prop("index");
    if (elt.prop("value") == "delete") {
      event.stopPropagation();
      let mounts = [...(await this.getData()).system.mounts];
      mounts.splice(index2, 1), this.item.update({
        "system.mounts": mounts
      });
    }
  }
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {JQuery}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), this.options.editable && html.find(".mount-selector").on("change", (e) => this._onChangeMount(e));
  }
  async getData() {
    let data2 = await super.getData();
    return data2.coreDeployables = await fromLidMany(data2.system.core_system.deployables), data2;
  }
};
__name(_LancerFrameSheet, "LancerFrameSheet");
let LancerFrameSheet = _LancerFrameSheet;
const _LancerLicenseSheet = class _LancerLicenseSheet extends LancerItemSheet {
  /**
   * @override
   * Extend and override the default options used by the generic Lancer item sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      width: 700,
      height: 750
    });
  }
  async getData() {
    let data2 = await super.getData(), unlocks = [[]];
    for (let et of [EntryType.FRAME, EntryType.MECH_SYSTEM, EntryType.MECH_WEAPON, EntryType.WEAPON_MOD]) {
      let pack = game.packs.get(get_pack_id(et));
      if (pack) {
        let index2 = await pack.getIndex(), key = this.item.system.key;
        for (let [id, indexData] of index2.entries()) {
          if (indexData.system.license !== key)
            continue;
          let doc = await pack.getDocument(id), rank = doc.system.license_level;
          for (; unlocks.length <= rank; )
            unlocks.push([]);
          unlocks[rank].some((i) => i.id === doc.id) || unlocks[rank].push(doc);
        }
      }
    }
    for (let i = 0; i < unlocks.length; i++)
      unlocks[i].sort((a, b) => a.is_frame() && !b.is_frame() ? -1 : !a.is_frame() && b.is_frame() ? 1 : a.name.localeCompare(b.name));
    return data2.unlocks = unlocks, data2;
  }
  /**
   * @override
   */
  _activateContextListeners(html) {
    handleContextMenus(html, this.item, !0);
  }
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {JQuery}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), handleDocDropping(html, (doc, dest, evt) => {
      doc.type == "Item" && doc.document.update({
        system: {
          // @ts-expect-error
          license: this.item.system.key,
          // @ts-expect-error
          manufacturer: this.item.system.manufacturer
        }
      });
    }), this.options.editable;
  }
};
__name(_LancerLicenseSheet, "LancerLicenseSheet");
let LancerLicenseSheet = _LancerLicenseSheet;
const _WeaponRangeTemplate = class _WeaponRangeTemplate extends MeasuredTemplate {
  get range() {
    return this.document.getFlag(game.system.id, "range");
  }
  get isBurst() {
    return this.range.type === RangeType.Burst;
  }
  /**
   * Creates a new WeaponRangeTemplate from a provided range object
   * @param range      - Range data
   * @param range.type - Type of template. A RangeType in typescript, or a string in js.
   * @param range.val  - Size of template. A numeric string
   * @param creator    - A token that is designated as the owner of the template.
   *                     Used to deterimine the character sheet to close as well
   *                     as a default ignore target for Cones and Lines.
   */
  static fromRange({ type: type2, val }, creator) {
    var _a19, _b, _c, _d;
    if (!canvas.ready)
      return null;
    const dist = val;
    if (isNaN(dist))
      return null;
    const square = (_a19 = canvas.grid) == null ? void 0 : _a19.isSquare, grid_distance = ((_c = (_b = canvas.scene) == null ? void 0 : _b.dimensions) == null ? void 0 : _c.distance) ?? 1;
    let shape;
    switch (type2) {
      case RangeType.Cone:
        shape = "cone";
        break;
      case RangeType.Line:
        shape = "ray";
        break;
      case RangeType.Burst:
      case RangeType.Blast:
        shape = "circle";
        break;
      default:
        return null;
    }
    const templateData = {
      t: shape,
      user: game.user.id,
      distance: dist * grid_distance,
      width: grid_distance,
      direction: 0,
      x: 0,
      y: 0,
      angle: square ? 51 : 59,
      fillColor: game.user.color,
      flags: {
        [game.system.id]: {
          range: { type: type2, val },
          creator: creator == null ? void 0 : creator.id,
          ignore: {
            tokens: [RangeType.Blast, RangeType.Burst].includes(type2) || !creator ? [] : [creator.id],
            dispositions: []
          }
        }
      }
    }, cls = getDocumentClass("MeasuredTemplate"), template = new cls(templateData, { parent: canvas.scene ?? void 0 }), object = new this(template);
    return object.actorSheet = ((_d = creator == null ? void 0 : creator.actor) == null ? void 0 : _d.sheet) ?? void 0, object;
  }
  /**
   * Start placement of the template. Returns immediately, so cannot be used to
   * block until a template is placed.
   * @deprecated Since 1.0
   */
  drawPreview() {
    console.warn("WeaponRangeTemplate.drawPreview() is deprecated and has been replaced by placeTemplate()"), this.placeTemplate().catch(() => {
    });
  }
  /**
   * Start placement of the template.
   * @returns A Promise that resolves to the final MeasuredTemplateDocument or
   * rejects when creation is canceled or fails.
   */
  placeTemplate() {
    var _a19, _b, _c;
    if (!canvas.ready)
      throw (_a19 = ui.notifications) == null || _a19.error("Cannot create WeaponRangeTemplate. Canvas is not ready"), new Error("Cannot create WeaponRangeTemplate. Canvas is not ready");
    (_b = this.actorSheet) == null || _b.minimize();
    const initialLayer = canvas.activeLayer;
    return this.draw(), this.layer.activate(), (_c = this.layer.preview) == null || _c.addChild(this), this.activatePreviewListeners(initialLayer);
  }
  activatePreviewListeners(initialLayer) {
    return new Promise((resolve, reject) => {
      const handlers = {};
      let moveTime = 0;
      handlers.mm = (event) => {
        event.stopPropagation();
        let now = Date.now();
        if (now - moveTime <= 20)
          return;
        const center = event.getLocalPosition(this.layer);
        let snapped = this.snapToCenter(center);
        this.isBurst && (snapped = this.snapToToken(center)), this.document.updateSource({ x: snapped.x, y: snapped.y }), this.refresh(), moveTime = now;
      }, handlers.rc = (_e, do_reject = !0) => {
        var _a19, _b, _c, _d;
        (_a19 = this.actorSheet) == null || _a19.maximize(), (_b = this.layer.preview) == null || _b.removeChildren().forEach((c) => c.destroy()), (_c = canvas.stage) == null || _c.off("mousemove", handlers.mm), (_d = canvas.stage) == null || _d.off("mousedown", handlers.lc), canvas.app.view.oncontextmenu = null, canvas.app.view.onwheel = null, initialLayer == null || initialLayer.activate(), do_reject && reject(new Error("Template creation cancelled"));
      }, handlers.lc = async (event) => {
        var _a19;
        handlers.rc(event, !1);
        let destination = this.snapToCenter(event.getLocalPosition(this.layer));
        if (this.isBurst) {
          destination = this.snapToToken(event.getLocalPosition(this.layer));
          const token = this.document.flags[game.system.id].burstToken;
          if (token) {
            const ignore = this.document.flags[game.system.id].ignore.tokens;
            ignore.push(token), this.document.updateSource({
              [`flags.${game.system.id}.ignore.tokens`]: ignore
            });
          }
        }
        this.document.updateSource(destination);
        const template = (_a19 = await canvas.scene.createEmbeddedDocuments("MeasuredTemplate", [this.document.toObject()])) == null ? void 0 : _a19.shift();
        if (template === void 0) {
          reject(new Error("Template creation failed"));
          return;
        }
        let n_polls = 0;
        const poll = setInterval(() => {
          var _a20;
          ++n_polls, (_a20 = template.object) != null && _a20.shape ? (clearInterval(poll), resolve(template)) : n_polls >= 100 && (clearInterval(poll), reject(new Error(`Failed to draw template after ${n_polls * 5}ms`)));
        }, 5);
      }, handlers.mw = (event) => {
        event.ctrlKey && event.preventDefault(), event.stopPropagation();
        let delta = canvas.grid.type > CONST.GRID_TYPES.SQUARE ? 30 : 15, snap = event.shiftKey ? delta : 5;
        this.document.updateSource({ direction: this.document.direction + snap * Math.sign(event.deltaY) }), this.refresh();
      }, canvas.stage.on("mousemove", handlers.mm), canvas.stage.on("mousedown", handlers.lc), canvas.app.view.oncontextmenu = handlers.rc, canvas.app.view.onwheel = handlers.mw;
    });
  }
  /**
   * Snapping function to only snap to the center of spaces rather than corners.
   */
  snapToCenter({ x, y }) {
    return canvas.grid.getCenterPoint({ x, y });
  }
  /**
   * Snapping function to snap to the center of a hovered token. Also resizes
   * the template for bursts.
   */
  snapToToken({ x, y }) {
    const token = canvas.tokens.placeables.filter((t) => t.x < x && t.x + t.w > x && t.y < y && t.y + t.h > y).reduce((r, t) => t.visible && (r == null || // @ts-expect-error v12
    canvas.grid.measurePath([{ x, y }, t.center]) < canvas.grid.measurePath([{ x, y }, r.center])) ? t : r, null);
    return token ? (this.document.updateSource({
      // @ts-expect-error v10
      distance: this.getBurstDistance(token.document.width),
      [`flags.${game.system.id}.burstToken`]: token.id
    }), token.center) : (this.document.updateSource({ distance: this.getBurstDistance(1) }), this.snapToCenter({ x, y }));
  }
  /**
   * Get fine-tuned sizing data for Burst templates
   */
  getBurstDistance(size) {
    return this.range.val + size / 2;
  }
};
__name(_WeaponRangeTemplate, "WeaponRangeTemplate");
let WeaponRangeTemplate = _WeaponRangeTemplate;
const { ApplicationV2: AppV2, HandlebarsApplicationMixin: HandlebarsApplicationMixin$4 } = foundry.applications.api, lp$5 = LANCER.log_prefix;
let LCPManagerComponent;
async function mountLCPManager(target, props) {
  return LCPManagerComponent || (LCPManagerComponent = (await import("./LCPManager-3154a0fd.mjs")).default), new LCPManagerComponent({
    target,
    props
  });
}
__name(mountLCPManager, "mountLCPManager");
function addLCPManagerButton(app, html) {
  if (app.options.id == "compendium") {
    const buttons = $(html).find(".header-actions");
    if (!buttons) {
      ui.notifications.error("Unable to add LCP Manager button - Compendium Tab buttons not found!", {
        permanent: !0
      }), console.log(`${lp$5} Unable to add LCP Manager button - Compendium Tab buttons not found!`, buttons);
      return;
    }
    let button = document.createElement("button");
    button.setAttribute("id", "lcp-manager-button"), button.setAttribute("style", "flex-basis: 100%;margin-top: 5px;"), button.innerHTML = "<i class='cci cci-content-manager i--s'></i> LANCER Compendium Manager", buttons.append(button), button.addEventListener("click", () => {
      new LCPManager().render(!0);
    });
  }
}
__name(addLCPManagerButton, "addLCPManagerButton");
const _LCPIndex = class _LCPIndex {
  constructor(index2) {
    index2 ? this.index = index2 : this.index = [];
  }
  addManifest(manifest) {
    this.index.push(manifest);
  }
  updateManifest(manifest) {
    for (let i = 0; i < this.index.length; i++) {
      const m = this.index[i];
      if (m.name === manifest.name && m.author === manifest.author) {
        this.index.splice(i, 1);
        break;
      }
    }
    this.addManifest(manifest);
  }
};
__name(_LCPIndex, "LCPIndex");
let LCPIndex = _LCPIndex;
const _LCPManager = class _LCPManager extends HandlebarsApplicationMixin$4(AppV2) {
  constructor(options = {}) {
    super(options), this.component = null, this.renderPromise = null;
  }
  async _prepareContext(_options) {
    return {};
  }
  _onFirstRender(context, options) {
    var _a19;
    super._onRender(context, options);
    const mount = $(this.element).find(".svelte-app-mount");
    !mount || !mount.length || (this.renderPromise = mountLCPManager(mount[0], context), (_a19 = this.renderPromise) == null || _a19.then((c) => this.component = c));
  }
  async render(options) {
    return await super.render(options), this.renderPromise && await this.renderPromise, this;
  }
  injectContentPack(content) {
    this.component.$set({ injectedContentSummary: content });
  }
};
__name(_LCPManager, "LCPManager");
let LCPManager = _LCPManager;
LCPManager.DEFAULT_OPTIONS = {
  id: "lcp-manager",
  window: {
    title: "LANCER Compendium Manager",
    icon: "cci cci-content-manager i--sm",
    resizable: !1
  },
  classes: ["lancer", "lcp-manager"],
  position: {
    width: 1200,
    height: 800
  }
};
LCPManager.PARTS = {
  lcpManager: {
    template: "systems/lancer/templates/lcp/lcp-manager-2.hbs"
  }
};
const preloadTemplates = /* @__PURE__ */ __name(async function() {
  const templatePaths = [
    // Actor sheets
    `systems/${game.system.id}/templates/actor/deployable.hbs`,
    `systems/${game.system.id}/templates/actor/mech.hbs`,
    `systems/${game.system.id}/templates/actor/npc.hbs`,
    `systems/${game.system.id}/templates/actor/pilot.hbs`,
    // Most common chat cards
    `systems/${game.system.id}/templates/chat/attack-card.hbs`,
    `systems/${game.system.id}/templates/chat/tech-attack-card.hbs`,
    `systems/${game.system.id}/templates/chat/generic-card.hbs`,
    `systems/${game.system.id}/templates/chat/stat-roll-card.hbs`,
    `systems/${game.system.id}/templates/chat/system-card.hbs`,
    // Combat tracker & settings UI
    `systems/${game.system.id}/templates/combat/combat-tracker-config.hbs`,
    `systems/${game.system.id}/templates/combat/combat-tracker.hbs`,
    // Item sheets
    `systems/${game.system.id}/templates/item/bond.hbs`,
    `systems/${game.system.id}/templates/item/core_bonus.hbs`,
    `systems/${game.system.id}/templates/item/frame.hbs`,
    `systems/${game.system.id}/templates/item/license.hbs`,
    `systems/${game.system.id}/templates/item/mech_system.hbs`,
    `systems/${game.system.id}/templates/item/mech_weapon.hbs`,
    `systems/${game.system.id}/templates/item/npc_class.hbs`,
    `systems/${game.system.id}/templates/item/npc_feature.hbs`,
    `systems/${game.system.id}/templates/item/npc_template.hbs`,
    `systems/${game.system.id}/templates/item/organization.hbs`,
    `systems/${game.system.id}/templates/item/pilot_armor.hbs`,
    `systems/${game.system.id}/templates/item/pilot_gear.hbs`,
    `systems/${game.system.id}/templates/item/pilot_weapon.hbs`,
    `systems/${game.system.id}/templates/item/reserve.hbs`,
    `systems/${game.system.id}/templates/item/skill.hbs`,
    `systems/${game.system.id}/templates/item/status.hbs`,
    `systems/${game.system.id}/templates/item/tag.hbs`,
    `systems/${game.system.id}/templates/item/talent.hbs`,
    `systems/${game.system.id}/templates/item/weapon_mod.hbs`,
    // Misc App UIs
    `systems/${game.system.id}/templates/lcp/lcp-manager.hbs`,
    `systems/${game.system.id}/templates/window/action_editor.hbs`,
    `systems/${game.system.id}/templates/window/action_manager.hbs`,
    `systems/${game.system.id}/templates/window/bonus.hbs`,
    `systems/${game.system.id}/templates/window/counter.hbs`,
    `systems/${game.system.id}/templates/window/html_editor.hbs`,
    `systems/${game.system.id}/templates/window/inventory.hbs`,
    `systems/${game.system.id}/templates/window/tag.hbs`
  ];
  return loadTemplates(templatePaths);
}, "preloadTemplates");
var __accessCheck$3 = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck$3"), __privateAdd$3 = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd$3"), __privateMethod$3 = /* @__PURE__ */ __name((obj, member, method) => (__accessCheck$3(obj, member, "access private method"), method), "__privateMethod$3"), _formHandler$3, formHandler_fn$3, _onReset$3, onReset_fn$3;
const { ApplicationV2: ApplicationV2$3, HandlebarsApplicationMixin: HandlebarsApplicationMixin$3 } = foundry.applications.api;
var _a15;
const _ActionTrackerConfig = (_a15 = class extends HandlebarsApplicationMixin$3(ApplicationV2$3) {
  async _prepareContext(opts) {
    const config = game.settings.get(game.system.id, LANCER.setting_actionTracker);
    return {
      config: opts.loadDefault ? new ActionTrackerOptions() : config,
      fields: config.schema.fields,
      buttons: [
        { type: "submit", name: "submit", icon: "fas fa-save", label: "Save" },
        { type: "button", name: "reset", icon: "fas fa-undo", label: "SETTINGS.Reset", action: "onReset" }
      ]
    };
  }
}, __name(_a15, "_ActionTrackerConfig"), _a15);
_formHandler$3 = /* @__PURE__ */ new WeakSet();
formHandler_fn$3 = /* @__PURE__ */ __name(async function(_ev, _form, formData) {
  const res = formData.object;
  await game.settings.set(game.system.id, LANCER.setting_actionTracker, res);
}, "formHandler_fn$3");
_onReset$3 = /* @__PURE__ */ new WeakSet();
onReset_fn$3 = /* @__PURE__ */ __name(async function() {
  this.render(!1, { loadDefault: !0 });
}, "onReset_fn$3");
__privateAdd$3(_ActionTrackerConfig, _formHandler$3);
__privateAdd$3(_ActionTrackerConfig, _onReset$3);
_ActionTrackerConfig.PARTS = {
  form: { template: "systems/lancer/templates/settings/action-tracker-config.hbs" },
  footer: { template: "templates/generic/form-footer.hbs", classes: ["flexrow"] }
};
_ActionTrackerConfig.DEFAULT_OPTIONS = {
  id: "lancer-action-tracker-settings",
  tag: "form",
  position: { width: 450 },
  window: { title: "lancer.actionTracker.menu-label" },
  form: {
    handler: __privateMethod$3(_ActionTrackerConfig, _formHandler$3, formHandler_fn$3),
    submitOnChange: !1,
    closeOnSubmit: !0
  },
  actions: {
    onReset: __privateMethod$3(_ActionTrackerConfig, _onReset$3, onReset_fn$3)
  }
};
let ActionTrackerConfig = _ActionTrackerConfig;
var __accessCheck$2 = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck$2"), __privateAdd$2 = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd$2"), __privateMethod$2 = /* @__PURE__ */ __name((obj, member, method) => (__accessCheck$2(obj, member, "access private method"), method), "__privateMethod$2"), _formHandler$2, formHandler_fn$2, _onReset$2, onReset_fn$2, _loadEmpty, loadEmpty_fn;
const { ApplicationV2: ApplicationV2$2, HandlebarsApplicationMixin: HandlebarsApplicationMixin$2 } = foundry.applications.api;
var _a16;
const _AutomationConfig = (_a16 = class extends HandlebarsApplicationMixin$2(ApplicationV2$2) {
  async _prepareContext(opts) {
    super._prepareContext;
    const config = game.settings.get(game.system.id, LANCER.setting_automation), blank = new AutomationOptions();
    Object.keys(blank).forEach((k) => blank[k] = !1);
    const ctx = {
      config: opts.loadDefault ? new AutomationOptions() : opts.loadEmpty ? blank : config,
      fields: config.schema.fields,
      buttons: [
        { type: "submit", name: "submit", icon: "fas fa-save", label: "Save" },
        { type: "button", name: "reset", icon: "fas fa-undo", label: "SETTINGS.Reset", action: "onReset" },
        { type: "button", name: "clear", icon: "fas fa-cancel", label: "Clear All", action: "onLoadEmpty" }
      ]
    };
    return opts.loadEmpty = !1, opts.loadDefault = !1, ctx;
  }
}, __name(_a16, "_AutomationConfig"), _a16);
_formHandler$2 = /* @__PURE__ */ new WeakSet();
formHandler_fn$2 = /* @__PURE__ */ __name(async function(_ev, _form, formData) {
  const res = formData.object;
  await game.settings.set(game.system.id, LANCER.setting_automation, res);
}, "formHandler_fn$2");
_onReset$2 = /* @__PURE__ */ new WeakSet();
onReset_fn$2 = /* @__PURE__ */ __name(async function() {
  this.render(!1, { loadDefault: !0 });
}, "onReset_fn$2");
_loadEmpty = /* @__PURE__ */ new WeakSet();
loadEmpty_fn = /* @__PURE__ */ __name(async function() {
  this.render(!1, { loadEmpty: !0 });
}, "loadEmpty_fn");
__privateAdd$2(_AutomationConfig, _formHandler$2);
__privateAdd$2(_AutomationConfig, _onReset$2);
__privateAdd$2(_AutomationConfig, _loadEmpty);
_AutomationConfig.PARTS = {
  form: { template: "systems/lancer/templates/settings/automation-config.hbs" },
  footer: { template: "templates/generic/form-footer.hbs", classes: ["flexrow"] }
};
_AutomationConfig.DEFAULT_OPTIONS = {
  id: "lancer-automation-settings",
  tag: "form",
  position: { width: 450 },
  window: { title: "lancer.automation.menu-label" },
  form: {
    handler: __privateMethod$2(_AutomationConfig, _formHandler$2, formHandler_fn$2),
    submitOnChange: !1,
    closeOnSubmit: !0
  },
  actions: {
    onLoadEmpty: __privateMethod$2(_AutomationConfig, _loadEmpty, loadEmpty_fn),
    onReset: __privateMethod$2(_AutomationConfig, _onReset$2, onReset_fn$2)
  }
};
let AutomationConfig = _AutomationConfig;
var __accessCheck$1 = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck$1"), __privateAdd$1 = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd$1"), __privateMethod$1 = /* @__PURE__ */ __name((obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method), "__privateMethod$1"), _formHandler$1, formHandler_fn$1, _onReset$1, onReset_fn$1;
const { ApplicationV2: ApplicationV2$1, HandlebarsApplicationMixin: HandlebarsApplicationMixin$1 } = foundry.applications.api;
var _a17;
const _StatusIconConfig = (_a17 = class extends HandlebarsApplicationMixin$1(ApplicationV2$1) {
  async _prepareContext(opts) {
    const config = game.settings.get(game.system.id, LANCER.setting_status_icons);
    return {
      config: opts.loadDefault ? new StatusIconConfigOptions() : config,
      fields: config.schema.fields,
      buttons: [
        { type: "submit", name: "submit", icon: "fas fa-save", label: "Save" },
        { type: "button", name: "reset", icon: "fas fa-undo", label: "SETTINGS.Reset", action: "onReset" }
      ]
    };
  }
}, __name(_a17, "_StatusIconConfig"), _a17);
_formHandler$1 = /* @__PURE__ */ new WeakSet();
formHandler_fn$1 = /* @__PURE__ */ __name(async function(_ev, _form, formData) {
  const res = formData.object;
  await game.settings.set(game.system.id, LANCER.setting_status_icons, res);
}, "formHandler_fn$1");
_onReset$1 = /* @__PURE__ */ new WeakSet();
onReset_fn$1 = /* @__PURE__ */ __name(async function() {
  this.render(!1, { loadDefault: !0 });
}, "onReset_fn$1");
__privateAdd$1(_StatusIconConfig, _formHandler$1);
__privateAdd$1(_StatusIconConfig, _onReset$1);
_StatusIconConfig.PARTS = {
  form: { template: "systems/lancer/templates/settings/status-icon-settings.hbs" },
  footer: { template: "templates/generic/form-footer.hbs", classes: ["flexrow"] }
};
_StatusIconConfig.DEFAULT_OPTIONS = {
  id: "lancer-status-icon-settings",
  tag: "form",
  position: { width: 450 },
  window: { title: "lancer.statusIconsConfig.menu-label" },
  form: {
    handler: __privateMethod$1(_StatusIconConfig, _formHandler$1, formHandler_fn$1),
    submitOnChange: !1,
    closeOnSubmit: !0
  },
  actions: {
    onReset: __privateMethod$1(_StatusIconConfig, _onReset$1, onReset_fn$1)
  }
};
let StatusIconConfig = _StatusIconConfig;
const _LancerCombatTracker = class _LancerCombatTracker extends CombatTracker {
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      template: CONFIG.LancerInitiative.templatePath
    };
  }
  scrollToTurn() {
    var _a19, _b;
    if (((_a19 = this.viewed) == null ? void 0 : _a19.turn) == null || !(((_b = CONFIG.LancerInitiative) == null ? void 0 : _b.sort) ?? !0))
      return super.scrollToTurn();
    this.element.find("ol#combat-tracker")[0].scrollTop = 0;
  }
  /**
   * Intercepts the data being sent to the combat tracker window and
   * optionally sorts the the turn data that gets displayed. This allows the
   * units that have already gone to be moved to the bottom without the risk of
   * updateCombat events being eaten.
   */
  async getData(options) {
    const config = CONFIG.LancerInitiative, appearance = game.settings.get(game.system.id, "combat-tracker-appearance"), data2 = await super.getData(options), sort = config.sort ?? !0, disp = {
      [-2]: "",
      [-1]: "enemy",
      0: "neutral",
      1: "friendly",
      2: "player"
    };
    return data2.turns = data2.turns.map((t) => {
      const combatant = this.viewed.getEmbeddedDocument("Combatant", t.id, {});
      return {
        ...t,
        css: t.css + " " + disp[(combatant == null ? void 0 : combatant.disposition) ?? -2],
        activations: combatant == null ? void 0 : combatant.activations.max,
        pending: (combatant == null ? void 0 : combatant.activations.value) ?? 0,
        finished: +(this.viewed.combatant === combatant)
      };
    }), sort && data2.turns.sort(function(a, b) {
      const aa = a.css.indexOf("active") !== -1 ? 1 : 0, ba = b.css.indexOf("active") !== -1 ? 1 : 0;
      if (ba - aa !== 0)
        return ba - aa;
      const ad = a.pending === 0 ? 1 : 0, bd = b.pending === 0 ? 1 : 0;
      return ad - bd;
    }), data2.icon_class = appearance.icon, data2.deactivate_icon_class = appearance.deactivate, data2.enable_initiative = CONFIG.LancerInitiative.enable_initiative ?? !1, data2;
  }
  activateListeners(html) {
    super.activateListeners(html), html.find(".lancer-combat-control").on("click", this._onActivateCombatant.bind(this));
  }
  /**
   * Activate the selected combatant
   */
  async _onActivateCombatant(event) {
    var _a19;
    event.preventDefault(), event.stopPropagation();
    const btn = event.currentTarget, id = (_a19 = btn.closest(".combatant")) == null ? void 0 : _a19.dataset.combatantId;
    if (id)
      switch (btn.dataset.control) {
        case "deactivateCombatant":
          await this.viewed.deactivateCombatant(id);
          break;
        case "activateCombatant":
          await this.viewed.activateCombatant(id);
          break;
      }
  }
  async _onAddActivation(li) {
    await this.viewed.getEmbeddedDocument("Combatant", li.data("combatant-id"), {}).addActivations(1);
  }
  async _onRemoveActivation(li) {
    await this.viewed.getEmbeddedDocument("Combatant", li.data("combatant-id"), {}).addActivations(-1);
  }
  async _onUndoActivation(li) {
    await this.viewed.getEmbeddedDocument("Combatant", li.data("combatant-id"), {}).modifyCurrentActivations(1);
  }
  _getEntryContextOptions() {
    const m = [
      {
        name: "LANCERINITIATIVE.AddActivation",
        icon: '<i class="fas fa-plus"></i>',
        callback: this._onAddActivation.bind(this)
      },
      {
        name: "LANCERINITIATIVE.RemoveActivation",
        icon: '<i class="fas fa-minus"></i>',
        callback: this._onRemoveActivation.bind(this)
      },
      {
        name: "LANCERINITIATIVE.UndoActivation",
        icon: '<i class="fas fa-undo"></i>',
        callback: this._onUndoActivation.bind(this)
      }
    ];
    return m.push(...super._getEntryContextOptions().filter((i) => i.name !== "COMBAT.CombatantReroll")), m;
  }
};
__name(_LancerCombatTracker, "LancerCombatTracker");
let LancerCombatTracker = _LancerCombatTracker;
function setAppearance(val) {
  var _a19, _b, _c, _d, _e, _f;
  val && (document.documentElement.style.setProperty("--lancer-initiative-icon-size", `${val.icon_size}rem`), document.documentElement.style.setProperty("--lancer-initiative-player-color", ((_a19 = val.player_color) == null ? void 0 : _a19.toString()) ?? null), document.documentElement.style.setProperty(
    "--lancer-initiative-friendly-color",
    ((_b = val.friendly_color) == null ? void 0 : _b.toString()) ?? null
  ), document.documentElement.style.setProperty(
    "--lancer-initiative-neutral-color",
    ((_c = val == null ? void 0 : val.neutral_color) == null ? void 0 : _c.toString()) ?? null
  ), document.documentElement.style.setProperty("--lancer-initiative-enemy-color", ((_d = val == null ? void 0 : val.enemy_color) == null ? void 0 : _d.toString()) ?? null), document.documentElement.style.setProperty("--lancer-initiative-done-color", ((_e = val == null ? void 0 : val.done_color) == null ? void 0 : _e.toString()) ?? null), (_f = game.combats) == null || _f.render());
}
__name(setAppearance, "setAppearance");
Handlebars.registerHelper("lancerinitiative-repeat", function(n, block) {
  let accum = "";
  for (let i = 0; i < n; i++)
    accum += block.fn(i);
  return accum;
});
const _CompconLoginForm = class _CompconLoginForm extends FormApplication {
  constructor(object, options = {}) {
    super(object, options);
  }
  static get defaultOptions() {
    return {
      ...super.defaultOptions,
      template: `systems/${game.system.id}/templates/window/compcon_login.hbs`,
      width: 480,
      height: "auto",
      resizable: !1,
      classes: ["lancer"],
      submitOnChange: !1,
      submitOnClose: !1,
      closeOnSubmit: !1,
      title: "COMP/CON Login"
    };
  }
  /** @override */
  async _updateObject(_event, formData) {
    try {
      const { Auth } = await import("./index-4953d36a.mjs");
      let res = await Auth.signIn(formData.username, formData.password);
      return ui.notifications.info("Logged in as " + res.attributes.email), populatePilotCache(), this.close();
    } catch {
      try {
        const { Auth } = await import("./index-4953d36a.mjs");
        let res = await Auth.signIn(formData.username.toLocaleLowerCase(), formData.password);
        return ui.notifications.info("Logged in as " + res.attributes.email), populatePilotCache(), this.close();
      } catch (e2) {
        ui.notifications.error(`Could not log in to Comp/Con: ${(e2 == null ? void 0 : e2.message) ?? e2}`), console.error(e2);
      }
    }
  }
};
__name(_CompconLoginForm, "CompconLoginForm");
let CompconLoginForm = _CompconLoginForm;
const themeGMS = {
  primaryColor: "#991e2a",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#d52a3b",
  lightText: "#efefef",
  darkText: "#000000",
  backgroundColor: "#ededed",
  secondaryColor: "#9e541f",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#4d4d4d",
  lightGrayColor: "#919a9b",
  tooltipBackground: "#dbdbdb",
  tooltipText: "#000000",
  // Gear type colors
  systemColor: "#58b434",
  weaponColor: "#111111",
  traitColor: "#0a7674",
  bonusColor: "#5d8673",
  bonusListColor: "#71a373",
  techColor: "#7d2477",
  talentColor: "#3a81c3",
  pilotStatColor: "color-mix(in srgb, var(--background-color), #888 50%)",
  // Action type colors
  reactionColor: "#892eb1",
  protocolColor: "#c75a00",
  quickColor: "#3949ab",
  quickTechColor: "#3949ab",
  invadeColor: "#222222",
  fullColor: "#283593",
  fullTechColor: "#283593",
  freeColor: "#00695c",
  moveColor: "#cc0a0a",
  // Hit type colors
  critColor: "#9c5e35",
  hitColor: "#337494",
  missColor: "#3c3c3c",
  errorColor: "#b4800e",
  // Accuracy / difficulty colors
  accuracyColor: "#0d689c",
  difficultyColor: "#9c0d0d",
  // Darken - for card backgrounds, etc...
  darkenColor: "0, 0, 0"
}, themeGMSDark = {
  ...themeGMS,
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 35%)",
  lightText: "#d2d2d2",
  darkText: "#efefef",
  backgroundColor: "#333333",
  lightGrayColor: "#666666",
  tooltipBackground: "#050505",
  tooltipText: "#efefef",
  systemColor: "#4a962b",
  darkenColor: "0, 0, 0"
}, themeMSMC = {
  ...themeGMS,
  primaryColor: "#146464",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#2bd4d4",
  lightText: "#dbdbdb",
  darkText: "#dbdbdb",
  backgroundColor: "#263237",
  secondaryColor: "#cb8225",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#dbdbdb",
  darkGrayColor: "#2e2e2e",
  lightGrayColor: "#666666",
  tooltipBackground: "#121d21",
  tooltipText: "#b3b9ba",
  systemColor: "#4a962b",
  traitColor: "#009e89",
  darkenColor: "0, 0, 0"
}, themeHORUS = {
  ...themeGMS,
  primaryColor: "#126127",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#97e308",
  lightText: "#ffffff",
  darkText: "#efefef",
  backgroundColor: "#000000",
  secondaryColor: "#084661",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#3c443e",
  lightGrayColor: "#657268",
  tooltipBackground: "#141414",
  tooltipText: "#d3d3d3",
  systemColor: "#4a962b",
  talentColor: "#2f689d",
  darkenColor: "125, 125, 125"
}, themeHA = {
  ...themeGMS,
  primaryColor: "#771675",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#d628d2",
  lightText: "#ffffff",
  darkText: "#b3b9ba",
  backgroundColor: "#222222",
  secondaryColor: "#cf4bdb",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#4d4d4d",
  lightGrayColor: "#555555",
  tooltipBackground: "#222222",
  tooltipText: "#ffffff",
  // Gear type colors
  systemColor: "#b035ad",
  talentColor: "#e080de",
  pilotStatColor: "#333333",
  darkenColor: "64, 64, 64"
}, themeSSC = {
  ...themeGMS,
  primaryColor: "#d1920a",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#fbe2ac",
  lightText: "#ffffff",
  darkText: "#000000",
  backgroundColor: "#eee8d5",
  secondaryColor: "#685d99",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#5a4c3f",
  lightGrayColor: "#eadbcb",
  tooltipBackground: "#d6c9b0",
  tooltipText: "#000000",
  // Gear type colors
  systemColor: "#89610B",
  talentColor: "#b58900",
  pilotStatColor: "#eadbcb",
  darkenColor: "64, 64, 64"
}, themeIPSN = {
  ...themeGMS,
  primaryColor: "#1952A2",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#c6daf6",
  lightText: "#ffffff",
  darkText: "#000000",
  backgroundColor: "#dbdbdb",
  secondaryColor: "#c77634",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#8a949e",
  lightGrayColor: "#cccccc",
  tooltipBackground: "#e8e8e8",
  tooltipText: "#000000",
  // Gear type colors
  systemColor: "#061a1f",
  talentColor: "#19A2A2",
  darkenColor: "0, 0, 0"
}, themeGAL = {
  ...themeGMS,
  primaryColor: "#e36600",
  primaryHighlight: "color-mix(in srgb, var(--primary-color), #fff 55%)",
  primaryShadow: "#ffe3cc",
  lightText: "#ffffff",
  darkText: "#c1c7c7",
  backgroundColor: "#2b2b2b",
  secondaryColor: "#3e6a94",
  secondaryHighlight: "#color-mix(in srgb, var(--secondary-color), #fff 55%)",
  secondaryText: "#ffffff",
  darkGrayColor: "#111111",
  lightGrayColor: "#444444",
  tooltipBackground: "#333333",
  tooltipText: "#ffffff",
  // Gear type colors
  systemColor: "#3e6a94",
  talentColor: "#4974bf",
  pilotStatColor: "#272727",
  darkenColor: "0, 0, 0"
};
function varName(key) {
  return "--" + key.trim().replace(/(\B)([A-Z])/gm, "-$&").toLowerCase();
}
__name(varName, "varName");
function applyTheme(theme) {
  let selectedTheme;
  switch (theme) {
    case "gmsDark":
      selectedTheme = themeGMSDark;
      break;
    case "msmc":
      selectedTheme = themeMSMC;
      break;
    case "horus":
      selectedTheme = themeHORUS;
      break;
    case "ha":
      selectedTheme = themeHA;
      break;
    case "ssc":
      selectedTheme = themeSSC;
      break;
    case "ipsn":
      selectedTheme = themeIPSN;
      break;
    case "gal":
      selectedTheme = themeGAL;
      break;
    case "gms":
    default:
      selectedTheme = themeGMS;
      break;
  }
  for (const key in selectedTheme)
    key === "primaryShadow" ? document.documentElement.style.setProperty("--color-shadow-primary", selectedTheme[key]) : document.documentElement.style.setProperty(varName(key), selectedTheme[key]);
}
__name(applyTheme, "applyTheme");
const fields$u = foundry.data.fields, registerSettings = /* @__PURE__ */ __name(function() {
  game.settings.register(game.system.id, LANCER.setting_migration_version, {
    name: "System Migration Version",
    scope: "world",
    config: !1,
    type: String,
    default: "0"
  }), game.settings.register(game.system.id, LANCER.setting_core_data, {
    name: "Lancer Data Version",
    scope: "world",
    config: !1,
    type: String,
    // Toggle for dev swapping to test import.
    default: ""
  }), game.settings.register(game.system.id, LANCER.setting_lcps, {
    name: "Installed LCPs",
    scope: "world",
    config: !1,
    type: Object,
    default: { index: [] }
  }), game.settings.register(game.system.id, LANCER.setting_tag_config, {
    name: "Tags",
    scope: "world",
    config: !1,
    type: Object,
    default: {}
  }), game.settings.register(game.system.id, LANCER.setting_floating_damage_numbers, {
    name: "lancer.floatingDamageNumbers.name",
    hint: "lancer.floatingDamageNumbers.hint",
    scope: "client",
    config: !0,
    type: Boolean,
    default: !1
  }), game.settings.register(game.system.id, LANCER.setting_ui_theme, {
    name: "lancer.uiTheme.name",
    hint: "lancer.uiTheme.hint",
    scope: "client",
    config: !0,
    type: new foundry.data.fields.StringField({
      required: !0,
      choices: {
        gms: "lancer.uiTheme.gms",
        gmsDark: "lancer.uiTheme.gmsDark",
        msmc: "lancer.uiTheme.msmc",
        horus: "lancer.uiTheme.horus",
        ha: "lancer.uiTheme.ha",
        ssc: "lancer.uiTheme.ssc",
        ipsn: "lancer.uiTheme.ipsn",
        gal: "lancer.uiTheme.gal"
      },
      initial: "gms"
    }),
    onChange: (v) => {
      !v || !["gms", "gmsDark", "msmc", "horus", "ha", "ssc", "ipsn", "gal"].includes(v) ? applyTheme("gms") : applyTheme(v);
    }
  }), game.settings.registerMenu(game.system.id, LANCER.setting_compcon_login, {
    name: "Comp/Con Login",
    label: "Log in to Comp/Con",
    hint: "Log in to Comp/Con to automatically load any pilots and mechs you have access to",
    icon: "fas fa-bars",
    type: CompconLoginForm,
    restricted: !1
  }), game.settings.registerMenu(game.system.id, LANCER.setting_status_icons, {
    name: "lancer.statusIconsConfig.menu-name",
    label: "lancer.statusIconsConfig.menu-label",
    hint: "lancer.statusIconsConfig.menu-hint",
    icon: "cci cci-difficulty i--s",
    // @ts-expect-error
    type: StatusIconConfig,
    restricted: !0
  }), game.settings.register(game.system.id, LANCER.setting_status_icons, {
    scope: "world",
    config: !1,
    type: StatusIconConfigOptions,
    onChange: async () => {
      await LancerActiveEffect.updateIcons();
    },
    default: new StatusIconConfigOptions()
  }), game.settings.registerMenu(game.system.id, LANCER.setting_automation, {
    name: "lancer.automation.menu-name",
    label: "lancer.automation.menu-label",
    hint: "lancer.automation.menu-hint",
    icon: "mdi mdi-state-machine",
    // @ts-expect-error
    type: AutomationConfig,
    restricted: !0
  }), game.settings.register(game.system.id, LANCER.setting_automation, {
    scope: "world",
    config: !1,
    type: AutomationOptions,
    default: new AutomationOptions()
  }), game.settings.registerMenu(game.system.id, LANCER.setting_actionTracker, {
    name: "lancer.actionTracker.menu-name",
    label: "lancer.actionTracker.menu-label",
    hint: "lancer.actionTracker.menu-hint",
    icon: "mdi mdi-state-machine",
    // @ts-expect-error
    type: ActionTrackerConfig,
    restricted: !0
  }), game.settings.register(game.system.id, LANCER.setting_actionTracker, {
    scope: "world",
    config: !1,
    type: ActionTrackerOptions,
    default: {}
  }), game.settings.register(game.system.id, LANCER.setting_dsn_setup, {
    scope: "world",
    config: !1,
    type: Boolean,
    default: !1
  }), CONFIG.LancerInitiative = {
    templatePath: `systems/${game.system.id}/templates/combat/combat-tracker.hbs`
  }, game.settings.register(game.system.id, "combat-tracker-appearance", {
    scope: "client",
    config: !1,
    type: CombatTrackerAppearance,
    // @ts-expect-error
    onChange: setAppearance,
    default: new CombatTrackerAppearance()
  }), game.settings.register(game.system.id, "combat-tracker-sort", {
    scope: "world",
    config: !1,
    type: Boolean,
    onChange: (v) => {
      var _a19;
      CONFIG.LancerInitiative.sort = v, (_a19 = game.combats) == null || _a19.render();
    },
    default: !0
  }), CONFIG.LancerInitiative.sort = game.settings.get(game.system.id, "combat-tracker-sort"), setAppearance(game.settings.get(game.system.id, "combat-tracker-appearance"));
}, "registerSettings");
function getAutomationOptions() {
  return game.settings.get(game.system.id, LANCER.setting_automation) ?? new AutomationOptions();
}
__name(getAutomationOptions, "getAutomationOptions");
const _AutomationOptions = class _AutomationOptions extends foundry.abstract.DataModel {
  static defineSchema() {
    const fields2 = foundry.data.fields;
    return {
      attacks: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.attacks",
        hint: "lancer.automation.attacks-desc"
      }),
      structure: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.structure",
        hint: "lancer.automation.structure-desc"
      }),
      overcharge_heat: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.overcharge_heat",
        hint: "lancer.automation.overcharge_heat-desc"
      }),
      attack_self_heat: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.attack_self_heat",
        hint: "lancer.automation.attack_self_heat-desc"
      }),
      limited_loading: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.limited_loading",
        hint: "lancer.automation.limited_loading-desc"
      }),
      npc_recharge: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.npc_recharge",
        hint: "lancer.automation.npc_recharge-desc"
      }),
      remove_templates: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.automation.remove_templates",
        hint: "lancer.automation.remove_templates-desc"
      }),
      token_size: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.automation.token_size",
        hint: "lancer.automation.token_size-desc"
      })
    };
  }
};
__name(_AutomationOptions, "AutomationOptions");
let AutomationOptions = _AutomationOptions;
const _ActionTrackerOptions = class _ActionTrackerOptions extends foundry.abstract.DataModel {
  static defineSchema() {
    return {
      showHotbar: new fields$u.BooleanField({
        initial: !0,
        required: !0,
        label: "lancer.actionTracker.showHotbar",
        hint: "lancer.actionTracker.showHotbar-desc"
      }),
      allowPlayers: new fields$u.BooleanField({
        initial: !0,
        required: !0,
        label: "lancer.actionTracker.allowPlayers",
        hint: "lancer.actionTracker.allowPlayers-desc"
      }),
      printMessages: new fields$u.BooleanField({
        initial: !0,
        required: !0,
        label: "lancer.actionTracker.printMessages",
        hint: "lancer.actionTracker.printMessages-desc"
      })
    };
  }
};
__name(_ActionTrackerOptions, "ActionTrackerOptions");
let ActionTrackerOptions = _ActionTrackerOptions;
const _StatusIconConfigOptions = class _StatusIconConfigOptions extends foundry.abstract.DataModel {
  static defineSchema() {
    const fields2 = foundry.data.fields;
    return {
      defaultConditionsStatus: new fields2.BooleanField({
        required: !0,
        initial: !0,
        label: "lancer.statusIconsConfig.defaultConditionsStatus",
        hint: "lancer.statusIconsConfig.defaultConditionsStatus-desc"
      }),
      cancerConditionsStatus: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.cancerConditionsStatus",
        hint: "lancer.statusIconsConfig.cancerConditionsStatus-desc"
      }),
      cancerNPCTemplates: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.cancerNPCTemplates",
        hint: "lancer.statusIconsConfig.cancerNPCTemplates-desc"
      }),
      hayleyConditionsStatus: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.hayleyConditionsStatus",
        hint: "lancer.statusIconsConfig.hayleyConditionsStatus-desc"
      }),
      hayleyPC: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.hayleyPC",
        hint: "lancer.statusIconsConfig.hayleyPC-desc"
      }),
      hayleyNPC: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.hayleyNPC",
        hint: "lancer.statusIconsConfig.hayleyNPC-desc"
      }),
      hayleyUtility: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.hayleyUtility",
        hint: "lancer.statusIconsConfig.hayleyUtility-desc"
      }),
      tommyConditionsStatus: new fields2.BooleanField({
        required: !0,
        initial: !1,
        label: "lancer.statusIconsConfig.tommyConditionsStatus",
        hint: "lancer.statusIconsConfig.tommyConditionsStatus-desc"
      })
    };
  }
};
__name(_StatusIconConfigOptions, "StatusIconConfigOptions");
let StatusIconConfigOptions = _StatusIconConfigOptions;
const _CombatTrackerAppearance = class _CombatTrackerAppearance extends foundry.abstract.DataModel {
  static defineSchema() {
    const fields2 = foundry.data.fields;
    return {
      icon: new fields2.StringField({
        required: !0,
        initial: "cci cci-activate",
        label: "LANCERINITIATIVE.Icon"
      }),
      deactivate: new fields2.StringField({
        required: !0,
        initial: "cci cci-deactivate",
        label: "LANCERINITIATIVE.DeactivateIcon"
      }),
      icon_size: new fields2.NumberField({
        required: !0,
        initial: 2,
        integer: !1,
        label: "LANCERINITIATIVE.IconSize"
      }),
      player_color: new fields2.ColorField({
        required: !0,
        initial: "#44abe0",
        label: "LANCERINITIATIVE.PCColor"
      }),
      friendly_color: new fields2.ColorField({
        required: !0,
        initial: "#44abe0",
        label: "LANCERINITIATIVE.FriendlyColor"
      }),
      neutral_color: new fields2.ColorField({
        required: !0,
        initial: "#146464",
        label: "LANCERINITIATIVE.NeutralColor"
      }),
      enemy_color: new fields2.ColorField({
        required: !0,
        initial: "#d98f30",
        label: "LANCERINITIATIVE.EnemyColor"
      }),
      done_color: new fields2.ColorField({
        required: !0,
        initial: "#aaaaaa",
        label: "LANCERINITIATIVE.DoneColor"
      })
    };
  }
};
__name(_CombatTrackerAppearance, "CombatTrackerAppearance");
let CombatTrackerAppearance = _CombatTrackerAppearance;
const fields$t = foundry.data.fields, _FrequencyField = class _FrequencyField extends fields$t.StringField {
  /** @inheritdoc */
  static get _defaults() {
    return foundry.utils.mergeObject(super._defaults, {
      required: !0,
      blank: !1,
      nullable: !0,
      initial: null,
      readonly: !0,
      validationError: "is not a properly formatted frequency"
    });
  }
  /** @override */
  _validateType(value) {
    if (typeof value == "string")
      _FrequencyField.ParseField(value);
    else if (value != null)
      throw new Error();
  }
  static ParseField(freq) {
    if (freq = freq.trim(), freq == "Unlimited")
      return { interval: "Unlimited" };
    let match = freq.match(/(\d)+\s*\/\s*(.*)/);
    if (!match)
      throw new Error(
        `Frequency must be of a format alike "X / [${Object.values(ActivePeriod).join(
          " | "
        )}]. Illegal option: "${freq}"`
      );
    let uses = Number.parseInt(match[1]), interval = match[2];
    if (interval = interval[0].toUpperCase() + interval.substring(1), Object.keys(ActivePeriod).includes(interval)) {
      if (uses < 1)
        throw new Error(`Frequency use count must be a positive integer. Illegal option: ${uses}`);
      return { uses, interval };
    } else
      throw new Error(
        `Frequency interval must one of [${Object.values(ActivePeriod).join(" | ")}]. Illegal option: "${interval}"`
      );
  }
};
__name(_FrequencyField, "FrequencyField");
let FrequencyField = _FrequencyField;
const _ActionField = class _ActionField extends fields$t.SchemaField {
  constructor(options = {}) {
    super(
      {
        lid: new LIDField(),
        name: new fields$t.StringField(),
        activation: new fields$t.StringField({ choices: Object.values(ActivationType), initial: ActivationType.Quick }),
        cost: new fields$t.NumberField({ min: 0, integer: !0, nullable: !1 }),
        frequency: new FrequencyField(),
        init: new fields$t.HTMLField(),
        trigger: new fields$t.HTMLField(),
        terse: new fields$t.HTMLField(),
        detail: new fields$t.HTMLField(),
        pilot: new fields$t.BooleanField(),
        mech: new fields$t.BooleanField(),
        tech_attack: new fields$t.BooleanField(),
        // confirm: new fields.StringField(),
        // available_mounted: new fields.BooleanField(),
        heat_cost: new fields$t.NumberField({ min: 0, integer: !0, nullable: !1 }),
        // TODO: synergy_locations: make em more fancy or somethin
        synergy_locations: new fields$t.ArrayField(new fields$t.StringField()),
        damage: new fields$t.ArrayField(new DamageField()),
        range: new fields$t.ArrayField(new RangeField())
        // ignore_used?
        // log: new fields.StringField(),
      },
      options
    );
  }
};
__name(_ActionField, "ActionField");
let ActionField = _ActionField;
function unpackAction(data2) {
  var _a19, _b;
  return {
    activation: repairActivationType(data2.activation ?? ActivationType.Quick),
    cost: data2.cost ?? 0,
    damage: ((_a19 = data2.damage) == null ? void 0 : _a19.map(unpackDamage)) ?? [],
    detail: data2.detail ?? "",
    frequency: data2.frequency ?? "",
    heat_cost: data2.heat_cost ?? 0,
    init: data2.init ?? "",
    lid: data2.id ?? "",
    mech: data2.mech ?? !0,
    name: data2.name ?? "Action",
    pilot: data2.pilot ?? !1,
    range: ((_b = data2.range) == null ? void 0 : _b.map(unpackRange)) ?? [],
    synergy_locations: data2.synergy_locations ?? [],
    terse: data2.terse ?? "",
    trigger: data2.trigger ?? "",
    tech_attack: data2.tech_attack ?? !1
  };
}
__name(unpackAction, "unpackAction");
function repairActivationType(activation) {
  for (const value of Object.values(ActivationType))
    if (value === activation)
      return value;
  return activation.toLowerCase() === "full action" ? ActivationType.Full : activation.toLowerCase() === "quick action" ? ActivationType.Quick : activation.toLowerCase() === "free action" ? ActivationType.Free : ActivationType.Quick;
}
__name(repairActivationType, "repairActivationType");
const fields$s = foundry.data.fields, _BonusField = class _BonusField extends fields$s.SchemaField {
  constructor(options = {}) {
    super(
      {
        lid: new fields$s.StringField({ nullable: !1 }),
        // Don't really want an LID field here
        val: new fields$s.StringField({ nullable: !1 }),
        overwrite: new fields$s.BooleanField(),
        replace: new fields$s.BooleanField(),
        damage_types: new DamageTypeChecklistField(),
        range_types: new RangeTypeChecklistField(),
        weapon_types: new WeaponTypeChecklistField(),
        weapon_sizes: new WeaponSizeChecklistField()
      },
      options
    );
  }
};
__name(_BonusField, "BonusField");
let BonusField = _BonusField;
function unpackBonus(data2) {
  return {
    lid: data2.id,
    val: data2.val.toString(),
    damage_types: data2.damage_types ? Damage.MakeChecklist(data2.damage_types) : null,
    range_types: data2.range_types ? Range.MakeChecklist(data2.range_types) : null,
    weapon_sizes: data2.weapon_sizes ? makeWeaponSizeChecklist(data2.weapon_sizes) : null,
    weapon_types: data2.weapon_types ? makeWeaponTypeChecklist(data2.weapon_types) : null,
    overwrite: data2.overwrite ?? !1,
    replace: data2.replace ?? !1
  };
}
__name(unpackBonus, "unpackBonus");
const fields$r = foundry.data.fields, _CounterField = class _CounterField extends fields$r.SchemaField {
  constructor(options = {}) {
    super(
      {
        lid: new LIDField(),
        name: new fields$r.StringField(),
        min: new fields$r.NumberField({ integer: !0, nullable: !1, initial: 0 }),
        max: new fields$r.NumberField({ integer: !0, nullable: !0, initial: 6 }),
        default_value: new fields$r.NumberField({ integer: !0, nullable: !1, initial: 0 }),
        value: new fields$r.NumberField({ integer: !0, nullable: !1, initial: 0 })
      },
      options
    );
  }
  static migrateData(value) {
    value.value = value.value ?? value.val, super.migrateData(value);
  }
  static bound_val(value, sub_val) {
    return sub_val = Math.round(sub_val), sub_val = Math.max(sub_val, value.min), value.max !== null && (sub_val = Math.min(sub_val, value.max)), sub_val;
  }
  /** @inheritdoc */
  clean(value, data2, options) {
    return value = super.clean(value, data2, options), value.value = _CounterField.bound_val(value, value.value || 0), value.default_value = _CounterField.bound_val(value, value.default_value || 0), value;
  }
  /** @override */
  _validateType(value) {
    if (value.max !== null && value.max < value.min)
      throw new Error("max must be > min");
  }
};
__name(_CounterField, "CounterField");
let CounterField = _CounterField;
function unpackCounter(data2) {
  let default_value = data2.default_value ?? data2.min ?? 0;
  return {
    default_value,
    value: default_value,
    lid: data2.id,
    max: data2.max ?? 6,
    min: data2.min ?? 0,
    name: data2.name
  };
}
__name(unpackCounter, "unpackCounter");
const fields$q = foundry.data.fields, _SynergyField = class _SynergyField extends fields$q.SchemaField {
  constructor(options = {}) {
    super(
      {
        locations: new fields$q.ArrayField(new fields$q.StringField({ choices: AllSynergyLocations, initial: "any" })),
        detail: new fields$q.StringField({ nullable: !1 }),
        damage_types: new DamageTypeChecklistField(),
        range_types: new RangeTypeChecklistField(),
        weapon_types: new WeaponTypeChecklistField(),
        weapon_sizes: new WeaponSizeChecklistField(),
        system_types: new SystemTypeChecklistField()
      },
      options
    );
  }
  migrateSource(sourceData, fieldData) {
    var _a19;
    return (_a19 = fieldData.locations) != null && _a19.some((s) => s.includes(",")) && (fieldData.locations = fieldData.locations.flatMap((s) => s.split(",").map((s2) => s2.trim()))), fieldData.locations && (fieldData.locations = fieldData.locations.map((l) => l.toLowerCase())), super.migrateSource(sourceData, fieldData);
  }
};
__name(_SynergyField, "SynergyField");
let SynergyField = _SynergyField;
function unpackSynergy(data2) {
  let raw_locations = data2.locations ?? [];
  Array.isArray(raw_locations) || (raw_locations = [raw_locations]);
  let locations = raw_locations.flatMap((base) => {
    let l = base.toLowerCase().trim();
    return l.includes(",") ? l.split(",").map((sub_l) => sub_l.trim()) : l;
  }), sizes = null;
  if (data2.weapon_sizes) {
    let x = data2.weapon_sizes;
    Array.isArray(x) || (x = [x]), x.includes("any") && (x = [WeaponSize.Aux, WeaponSize.Heavy, WeaponSize.Main, WeaponSize.Superheavy]), sizes = makeWeaponSizeChecklist(x);
  }
  let types = null;
  if (data2.weapon_types) {
    let x = data2.weapon_types;
    Array.isArray(x) || (x = [x]), x.includes("any") && (x = [
      WeaponType.CQB,
      WeaponType.Cannon,
      WeaponType.Launcher,
      WeaponType.Melee,
      WeaponType.Nexus,
      WeaponType.Rifle
    ]), types = makeWeaponTypeChecklist(x);
  }
  let systems = null;
  if (data2.system_types) {
    let x = data2.system_types;
    Array.isArray(x) || (x = [x]), x.includes("any") && (x = [
      SystemType.AI,
      SystemType.Armor,
      SystemType.Deployable,
      SystemType.Drone,
      SystemType.FlightSystem,
      SystemType.Integrated,
      SystemType.Mod,
      SystemType.Shield,
      SystemType.System,
      SystemType.Tech
    ]), systems = makeSystemTypeChecklist(x);
  }
  return {
    detail: data2.detail,
    locations,
    damage_types: null,
    range_types: null,
    weapon_sizes: sizes,
    weapon_types: types,
    system_types: systems
  };
}
__name(unpackSynergy, "unpackSynergy");
const fields$p = foundry.data.fields;
function template_universal_actor() {
  return {
    lid: new LIDField(),
    burn: new fields$p.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 }),
    activations: new fields$p.NumberField({ min: 0, integer: !0, nullable: !1, initial: 1 }),
    custom_counters: new fields$p.ArrayField(new CounterField()),
    hp: new FullBoundedNumberField({ initialValue: 10, max: 10 }),
    overshield: new FullBoundedNumberField({ initialValue: 0, max: 14 }),
    inherited_effects: new fields$p.SchemaField(
      {
        from_uuid: new fields$p.StringField(),
        data: new fields$p.ArrayField(new fields$p.ObjectField()),
        visible: new fields$p.BooleanField()
      },
      { nullable: !0, initial: null }
    )
    // Our derived property melange - not actually here! We generate those in prepareData
  };
}
__name(template_universal_actor, "template_universal_actor");
function template_action_tracking() {
  return {
    action_tracker: new fields$p.SchemaField({
      protocol: new fields$p.BooleanField(),
      move: new fields$p.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 }),
      full: new fields$p.BooleanField(),
      quick: new fields$p.BooleanField(),
      reaction: new fields$p.BooleanField(),
      free: new fields$p.BooleanField(),
      used_reactions: new fields$p.ArrayField(new fields$p.StringField({ nullable: !1 }))
      // lids
    })
  };
}
__name(template_action_tracking, "template_action_tracking");
function template_heat() {
  return {
    heat: new FullBoundedNumberField({ initialValue: 0, max: 6 })
  };
}
__name(template_heat, "template_heat");
function template_struss() {
  return {
    stress: new FullBoundedNumberField({ initialValue: 0, max: 1 }),
    structure: new FullBoundedNumberField({ initialValue: 0, max: 1 })
  };
}
__name(template_struss, "template_struss");
function template_statuses() {
  return {};
}
__name(template_statuses, "template_statuses");
const fields$o = foundry.data.fields, deployable_schema = {
  // @ts-expect-error
  actions: new fields$o.ArrayField(new ActionField()),
  // bonuses: new fields.ArrayField(new BonusField()),
  // @ts-expect-error
  counters: new fields$o.ArrayField(new CounterField()),
  // @ts-expect-error
  synergies: new fields$o.ArrayField(new SynergyField()),
  // @ts-expect-error
  tags: new fields$o.ArrayField(new TagField()),
  activation: new fields$o.StringField({ choices: Object.values(ActivationType), initial: ActivationType.Quick }),
  stats: new fields$o.SchemaField({
    armor: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 }),
    edef: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 10 }),
    evasion: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 10 }),
    heatcap: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 }),
    hp: new fields$o.StringField({ initial: "5" }),
    save: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 10 }),
    size: new fields$o.NumberField({ min: 0.5, integer: !1, nullable: !1, initial: 0.5 }),
    speed: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 })
  }),
  cost: new fields$o.NumberField({ min: 0, integer: !0, nullable: !1, initial: 1 }),
  instances: new fields$o.NumberField({ min: 1, integer: !0, nullable: !1, initial: 1 }),
  deactivation: new fields$o.StringField({ choices: Object.values(ActivationType), initial: null, nullable: !0 }),
  detail: new fields$o.HTMLField(),
  recall: new fields$o.StringField({ choices: Object.values(ActivationType), initial: null, nullable: !0 }),
  redeploy: new fields$o.StringField({ choices: Object.values(ActivationType), initial: null, nullable: !0 }),
  type: new fields$o.StringField({ choices: Object.values(DeployableType), initial: DeployableType.Deployable }),
  avail_mounted: new fields$o.BooleanField({ initial: !0 }),
  avail_unmounted: new fields$o.BooleanField({ initial: !1 }),
  deployer: new SyncUUIDRefField("Actor", { allowed_types: [EntryType.MECH, EntryType.PILOT, EntryType.NPC] }),
  owner: new SyncUUIDRefField("Actor", { allowed_types: [EntryType.MECH, EntryType.PILOT, EntryType.NPC] }),
  // destroyed: new fields.BooleanField({ initial: false }),
  // notes: new fields.HTMLField(),
  // destroyed: new fields.BooleanField({ initial: false }),
  ...template_universal_actor(),
  ...template_heat(),
  ...template_statuses()
}, _DeployableModel = class _DeployableModel extends LancerDataModel {
  static defineSchema() {
    return deployable_schema;
  }
  static migrateData(data2) {
    var _a19, _b, _c;
    return data2.type && data2.type[0] == data2.type[0].toLowerCase() && (data2.type = restrict_enum(DeployableType, DeployableType.Deployable, data2.type)), data2.stats || (data2.stats = {
      armor: data2.armor || 0,
      edef: data2.edef || 8,
      evasion: data2.evasion || 5,
      heatcap: data2.heatcap || 0,
      hp: fixCCFormula(((_a19 = data2.max_hp) == null ? void 0 : _a19.toString()) || "5"),
      save: data2.save || 10,
      size: data2.size || 0.5,
      speed: data2.speed || 0
    }), data2.hp && typeof data2.hp == "string" && (data2.stats.hp = fixCCFormula(data2.hp), delete data2.hp), ((_b = data2.stats) == null ? void 0 : _b.size) !== void 0 && (((_c = data2.stats) == null ? void 0 : _c.size) >= 1 ? data2.stats.size = Math.floor(data2.stats.size) : data2.stats.size = 0.5), super.migrateData(data2);
  }
};
__name(_DeployableModel, "DeployableModel");
let DeployableModel = _DeployableModel;
DeployableModel.DEFAULT_ICON = "systems/lancer/assets/icons/deployable.svg";
function unpackDeployableData(data2) {
  var _a19, _b, _c, _d, _e, _f, _g;
  let max_hp = Number.parseInt(((_a19 = data2.hp) == null ? void 0 : _a19.toString()) || "5") || 5;
  return {
    actions: (_b = data2.actions) == null ? void 0 : _b.map(unpackAction),
    bonuses: (_c = data2.bonuses) == null ? void 0 : _c.map(unpackBonus),
    counters: (_d = data2.counters) == null ? void 0 : _d.map(unpackCounter),
    synergies: (_e = data2.synergies) == null ? void 0 : _e.map(unpackSynergy),
    tags: (_f = data2.tags) == null ? void 0 : _f.map(unpackTag),
    activation: data2.activation,
    stats: {
      armor: data2.armor,
      edef: data2.edef,
      evasion: data2.evasion,
      heatcap: data2.heatcap,
      hp: fixCCFormula(((_g = data2.hp) == null ? void 0 : _g.toString()) || "5"),
      save: data2.save,
      size: data2.size,
      speed: data2.speed
    },
    activations: 0,
    avail_mounted: void 0,
    avail_unmounted: void 0,
    hp: { min: 0, max: max_hp, value: max_hp },
    burn: void 0,
    cost: data2.cost,
    custom_counters: void 0,
    deactivation: data2.deactivation,
    deployer: void 0,
    detail: data2.detail,
    instances: data2.instances,
    lid: void 0,
    overshield: void 0,
    recall: data2.recall,
    redeploy: data2.redeploy,
    type: restrict_enum(DeployableType, DeployableType.Deployable, data2.type)
  };
}
__name(unpackDeployableData, "unpackDeployableData");
function unpackDeployable(data2, context) {
  let lid = "dep_" + slugify(data2.name), unpacked = unpackDeployableData(data2);
  return unpacked.lid = lid, context.createdDeployables.push({
    name: data2.name,
    system: unpacked,
    type: EntryType.DEPLOYABLE
  }), lid;
}
__name(unpackDeployable, "unpackDeployable");
const fields$n = foundry.data.fields;
function template_universal_item() {
  return {
    lid: new LIDField()
  };
}
__name(template_universal_item, "template_universal_item");
function template_destructible() {
  return {
    cascading: new fields$n.BooleanField(),
    destroyed: new fields$n.BooleanField()
  };
}
__name(template_destructible, "template_destructible");
function template_uses() {
  return {
    uses: new FakeBoundedNumberField({ integer: !0, nullable: !1, initial: 0 })
  };
}
__name(template_uses, "template_uses");
function template_bascdt() {
  return {
    bonuses: new fields$n.ArrayField(new BonusField()),
    actions: new fields$n.ArrayField(new ActionField()),
    synergies: new fields$n.ArrayField(new SynergyField()),
    counters: new fields$n.ArrayField(new CounterField()),
    deployables: new fields$n.ArrayField(new LIDField()),
    integrated: new fields$n.ArrayField(new LIDField()),
    tags: new fields$n.ArrayField(new TagField())
  };
}
__name(template_bascdt, "template_bascdt");
function template_licensed() {
  return {
    manufacturer: new fields$n.StringField({ required: !0, nullable: !1, blank: !1, initial: "GMS" }),
    license_level: new fields$n.NumberField({ integer: !0, minimum: 0, maximum: 3 }),
    license: new fields$n.StringField({ required: !0, nullable: !1, blank: !1, initial: "mf_unknown" })
  };
}
__name(template_licensed, "template_licensed");
function migrateManufacturer(source) {
  return (source == null ? void 0 : source.fallback_lid) || "GMS";
}
__name(migrateManufacturer, "migrateManufacturer");
function addDeployableTags(packedDeployables, packedTags, context) {
  const deployableIds = packedDeployables == null ? void 0 : packedDeployables.map((d) => unpackDeployable(d, context)), deployables = context.createdDeployables.filter((d) => d.system.lid && (deployableIds == null ? void 0 : deployableIds.includes(d.system.lid))), tags = packedTags == null ? void 0 : packedTags.map(unpackTag);
  if (deployables != null && deployables.length) {
    const depTypes = new Set(deployables.map((d) => d.system.type));
    depTypes.has(DeployableType.Deployable) && (tags == null || tags.push({ lid: "tg_deployable", val: "0" })), depTypes.has(DeployableType.Drone) && (tags == null || tags.push({ lid: "tg_drone", val: "0" })), depTypes.has(DeployableType.Mine) && (tags == null || tags.push({ lid: "tg_mine", val: "0" }));
  }
  return { deployables: deployableIds, tags };
}
__name(addDeployableTags, "addDeployableTags");
const fields$m = foundry.data.fields, _MechWeaponModel = class _MechWeaponModel extends LancerDataModel {
  static defineSchema() {
    return {
      deployables: new fields$m.ArrayField(new LIDField()),
      integrated: new fields$m.ArrayField(new LIDField()),
      sp: new fields$m.NumberField({ nullable: !1, initial: 0 }),
      // @ts-expect-error
      actions: new fields$m.ArrayField(new ActionField()),
      profiles: new ControlledLengthArrayField(
        new fields$m.SchemaField({
          name: new fields$m.StringField({ initial: "Base Profile" }),
          type: new fields$m.StringField({ choices: Object.values(WeaponType), initial: WeaponType.Rifle }),
          // @ts-expect-error
          damage: new fields$m.ArrayField(new DamageField()),
          // @ts-expect-error
          range: new fields$m.ArrayField(new RangeField()),
          // @ts-expect-error
          tags: new fields$m.ArrayField(new TagField()),
          description: new fields$m.StringField(),
          effect: new fields$m.StringField(),
          on_attack: new fields$m.StringField(),
          on_hit: new fields$m.StringField(),
          on_crit: new fields$m.StringField(),
          cost: new fields$m.NumberField({ nullable: !1, initial: 0 }),
          skirmishable: new fields$m.BooleanField(),
          barrageable: new fields$m.BooleanField(),
          // @ts-expect-error
          actions: new fields$m.ArrayField(new ActionField()),
          // @ts-expect-error
          bonuses: new fields$m.ArrayField(new BonusField()),
          // @ts-expect-error
          synergies: new fields$m.ArrayField(new SynergyField()),
          // @ts-expect-error
          counters: new fields$m.ArrayField(new CounterField())
        }),
        { length: 1, overflow: !0 }
      ),
      loaded: new fields$m.BooleanField(),
      selected_profile_index: new fields$m.NumberField({ nullable: !1, initial: 0 }),
      size: new fields$m.StringField({
        choices: Object.values(WeaponSize).concat("Ship-class"),
        initial: WeaponSize.Main
      }),
      no_core_bonuses: new fields$m.BooleanField(),
      no_mods: new fields$m.BooleanField(),
      no_bonuses: new fields$m.BooleanField(),
      no_synergies: new fields$m.BooleanField(),
      no_attack: new fields$m.BooleanField(),
      ...template_universal_item(),
      ...template_destructible(),
      ...template_licensed(),
      ...template_uses()
    };
  }
  static migrateData(data2) {
    return data2.source && (data2.manufacturer = migrateManufacturer(data2.source)), super.migrateData(data2);
  }
};
__name(_MechWeaponModel, "MechWeaponModel");
let MechWeaponModel = _MechWeaponModel;
MechWeaponModel.DEFAULT_ICON = "systems/lancer/assets/icons/mech_weapon.svg";
function unpackMechWeapon(data2, context) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i;
  let profiles = [], { deployables: parentDeployables, tags: parentTags } = addDeployableTags(data2.deployables, data2.tags, context);
  parentDeployables = parentDeployables ?? [], parentTags = parentTags ?? [];
  let parentIntegrated = data2.integrated ?? [], hasProfiles = (((_a19 = data2.profiles) == null ? void 0 : _a19.length) ?? 0) > 0;
  for (let prof of hasProfiles ? data2.profiles : [data2]) {
    let profileDeployables = [], profileTags = [];
    if (hasProfiles) {
      const { deployables: newDeployables, tags: newTags } = addDeployableTags(prof.deployables, prof.tags, context);
      profileDeployables = newDeployables ?? [], profileTags = newTags ?? [];
    }
    parentDeployables.push(...profileDeployables), parentIntegrated.push(...prof.integrated ?? []);
    let barrageable, skirmishable;
    prof.barrage == null && prof.skirmish == null ? (barrageable = !0, skirmishable = data2.mount != WeaponSize.Superheavy) : prof.barrage == null ? (skirmishable = prof.skirmish, barrageable = !1) : prof.skirmish == null ? (skirmishable = !1, barrageable = prof.barrage) : (skirmishable = prof.skirmish, barrageable = prof.barrage);
    let tags = hasProfiles ? [...parentTags, ...profileTags] : parentTags;
    profiles.push({
      damage: (_b = prof.damage) == null ? void 0 : _b.filter((d) => d.val != "N/A").map(unpackDamage),
      range: (_c = prof.range) == null ? void 0 : _c.filter((d) => d.val != "N/A").map(unpackRange),
      tags,
      effect: prof.effect,
      on_attack: prof.on_attack,
      on_crit: prof.on_crit,
      on_hit: prof.on_hit,
      cost: prof.cost ?? 1,
      barrageable,
      skirmishable,
      actions: (_d = prof.actions) == null ? void 0 : _d.map(unpackAction),
      bonuses: (_e = prof.bonuses) == null ? void 0 : _e.map(unpackBonus),
      counters: (_f = prof.counters) == null ? void 0 : _f.map(unpackCounter),
      description: prof.description ?? data2.description,
      name: prof.name ?? `${data2.name} :: ${((_g = data2.profiles) == null ? void 0 : _g.length) ?? 0 + 1}`,
      synergies: (_h = prof.synergies) == null ? void 0 : _h.map(unpackSynergy),
      type: restrict_enum(WeaponType, WeaponType.Rifle, prof.type ?? data2.type)
    });
  }
  return {
    name: data2.name,
    type: EntryType.MECH_WEAPON,
    system: {
      cascading: void 0,
      deployables: parentDeployables,
      destroyed: void 0,
      integrated: data2.integrated,
      license: data2.license_id || data2.license,
      license_level: data2.license_level,
      lid: data2.id,
      loaded: void 0,
      manufacturer: data2.source,
      no_attack: data2.no_attack,
      no_bonuses: data2.no_bonus,
      no_core_bonuses: data2.no_core_bonus,
      no_mods: data2.no_mods,
      no_synergies: data2.no_synergy,
      actions: ((_i = data2.actions) == null ? void 0 : _i.map(unpackAction)) || [],
      profiles,
      selected_profile_index: 0,
      size: data2.mount,
      sp: data2.sp,
      uses: { value: 0, max: 0 }
    }
  };
}
__name(unpackMechWeapon, "unpackMechWeapon");
const fields$l = foundry.data.fields, frame_schema = {
  description: new fields$l.HTMLField(),
  mechtype: new fields$l.ArrayField(new fields$l.StringField({ nullable: !1, choices: Object.values(MechType) })),
  mounts: new fields$l.ArrayField(new fields$l.StringField({ nullable: !1, choices: Object.values(MountType) })),
  stats: new fields$l.SchemaField({
    armor: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 0 }),
    edef: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 8 }),
    evasion: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 8 }),
    heatcap: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 5 }),
    hp: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 10 }),
    repcap: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 0 }),
    save: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 10 }),
    sensor_range: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 10 }),
    size: new fields$l.NumberField({ integer: !1, minimum: 0.5, initial: 1 }),
    sp: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 0 }),
    speed: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 4 }),
    stress: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 4 }),
    structure: new fields$l.NumberField({ integer: !0, minimum: 0, initial: 4 }),
    tech_attack: new fields$l.NumberField({ integer: !0, initial: 0 })
  }),
  traits: new fields$l.ArrayField(
    new fields$l.SchemaField({
      name: new fields$l.StringField(),
      description: new fields$l.HTMLField(),
      // @ts-expect-error
      bonuses: new fields$l.ArrayField(new BonusField()),
      // @ts-expect-error
      counters: new fields$l.ArrayField(new CounterField()),
      integrated: new fields$l.ArrayField(new LIDField()),
      deployables: new fields$l.ArrayField(new LIDField()),
      // @ts-expect-error
      actions: new fields$l.ArrayField(new ActionField()),
      // @ts-expect-error
      synergies: new fields$l.ArrayField(new SynergyField()),
      // use: new fields.StringField({ nullable: false, choices: Object.values(FrameEffectUse), initial: FrameEffectUse.Unknown, }),
      use: new fields$l.StringField({ nullable: !0, initial: null })
      // ^ Core data does not adhere to this schema
    })
  ),
  core_system: new fields$l.SchemaField({
    name: new fields$l.StringField(),
    description: new fields$l.HTMLField(),
    activation: new fields$l.StringField({ nullable: !1, choices: Object.values(ActivationType) }),
    deactivation: new fields$l.StringField({ nullable: !0, choices: Object.values(ActivationType), initial: null }),
    // use: new fields.StringField({ nullable: true, choices: Object.values(FrameEffectUse), initial: null }),
    use: new fields$l.StringField({ nullable: !0, initial: null }),
    // ^ Core data does not adhere to this schema
    active_name: new fields$l.StringField(),
    active_effect: new fields$l.HTMLField(),
    // @ts-expect-error
    active_synergies: new fields$l.ArrayField(new SynergyField()),
    // @ts-expect-error
    active_bonuses: new fields$l.ArrayField(new BonusField()),
    // @ts-expect-error
    active_actions: new fields$l.ArrayField(new ActionField()),
    passive_name: new fields$l.StringField(),
    passive_effect: new fields$l.HTMLField(),
    // @ts-expect-error
    passive_synergies: new fields$l.ArrayField(new SynergyField()),
    // @ts-expect-error
    passive_bonuses: new fields$l.ArrayField(new BonusField()),
    // @ts-expect-error
    passive_actions: new fields$l.ArrayField(new ActionField()),
    deployables: new fields$l.ArrayField(new LIDField()),
    // @ts-expect-error
    counters: new fields$l.ArrayField(new CounterField()),
    integrated: new fields$l.ArrayField(new LIDField()),
    // @ts-expect-error
    tags: new fields$l.ArrayField(new TagField())
  }),
  ...template_universal_item(),
  ...template_licensed()
}, _FrameModel = class _FrameModel extends LancerDataModel {
  static defineSchema() {
    return frame_schema;
  }
  static migrateData(data2) {
    var _a19;
    return data2.source && (data2.manufacturer = migrateManufacturer(data2.source)), ((_a19 = data2.stats) == null ? void 0 : _a19.size) !== void 0 && (data2.stats.size >= 1 ? data2.stats.size = Math.floor(data2.stats.size) : data2.stats.size = 0.5), super.migrateData(data2);
  }
};
__name(_FrameModel, "FrameModel");
let FrameModel = _FrameModel;
FrameModel.DEFAULT_ICON = "systems/lancer/assets/icons/mech.svg";
function unpackFrame(data2, context) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i;
  let cs = data2.core_system;
  const frameImg = frameToPath(data2.name);
  let csActivation = repairActivationType(cs.activation ?? ActivationType.Quick);
  const { deployables, tags } = addDeployableTags(cs.deployables, cs.tags, context);
  return {
    name: data2.name,
    type: EntryType.FRAME,
    img: frameImg ?? void 0,
    system: {
      core_system: {
        activation: csActivation,
        active_actions: (_a19 = cs.active_actions) == null ? void 0 : _a19.map(unpackAction),
        active_bonuses: (_b = cs.active_bonuses) == null ? void 0 : _b.map(unpackBonus),
        active_effect: cs.active_effect,
        active_name: cs.active_name,
        active_synergies: (_c = cs.active_synergies) == null ? void 0 : _c.map(unpackSynergy),
        counters: (_d = cs.counters) == null ? void 0 : _d.map(unpackCounter),
        deactivation: cs.deactivation,
        deployables,
        description: cs.description,
        integrated: cs.integrated,
        name: cs.name,
        passive_actions: (_e = cs.passive_actions) == null ? void 0 : _e.map(unpackAction),
        passive_bonuses: (_f = cs.passive_bonuses) == null ? void 0 : _f.map(unpackBonus),
        passive_effect: cs.passive_effect,
        passive_name: cs.passive_name,
        passive_synergies: (_g = cs.passive_synergies) == null ? void 0 : _g.map(unpackSynergy),
        tags,
        use: restrict_enum(FrameEffectUse, FrameEffectUse.Unknown, cs.use)
      },
      description: data2.description,
      license: data2.license_id || data2.id,
      license_level: data2.license_level ?? 2,
      lid: data2.id,
      manufacturer: data2.source,
      mechtype: (_h = data2.mechtype) == null ? void 0 : _h.map((mt) => restrict_enum(MechType, MechType.Striker, mt)),
      mounts: data2.mounts,
      stats: data2.stats,
      traits: (_i = data2.traits) == null ? void 0 : _i.map((t) => {
        var _a20, _b2, _c2, _d2, _e2;
        return {
          actions: ((_a20 = t.actions) == null ? void 0 : _a20.map(unpackAction)) ?? [],
          bonuses: ((_b2 = t.bonuses) == null ? void 0 : _b2.map(unpackBonus)) ?? [],
          counters: ((_c2 = t.counters) == null ? void 0 : _c2.map(unpackCounter)) ?? [],
          deployables: ((_d2 = t.deployables) == null ? void 0 : _d2.map((d) => unpackDeployable(d, context))) ?? [],
          description: t.description,
          integrated: t.integrated ?? [],
          name: t.name,
          synergies: ((_e2 = t.synergies) == null ? void 0 : _e2.map(unpackSynergy)) ?? [],
          use: restrict_enum(FrameEffectUse, FrameEffectUse.Unknown, t.use)
        };
      })
    }
  };
}
__name(unpackFrame, "unpackFrame");
const fields$k = foundry.data.fields, _AmmoField = class _AmmoField extends fields$k.SchemaField {
  constructor(options = {}) {
    super(
      {
        name: new fields$k.StringField({ nullable: !1 }),
        description: new fields$k.StringField({ nullable: !1 }),
        cost: new fields$k.NumberField({ nullable: !0 }),
        allowed_types: new WeaponTypeChecklistField(),
        allowed_sizes: new WeaponSizeChecklistField(),
        restricted_types: new WeaponTypeChecklistField(),
        restricted_sizes: new WeaponSizeChecklistField()
      },
      options
    );
  }
};
__name(_AmmoField, "AmmoField");
let AmmoField = _AmmoField;
function unpackAmmo(data2) {
  return {
    name: data2.name,
    description: data2.description,
    cost: data2.cost ?? null,
    allowed_types: data2.allowed_types ? makeWeaponTypeChecklist(data2.allowed_types) : null,
    allowed_sizes: data2.allowed_sizes ? makeWeaponSizeChecklist(data2.allowed_sizes) : null,
    restricted_types: data2.restricted_types ? makeWeaponTypeChecklist(data2.restricted_types) : null,
    restricted_sizes: data2.restricted_sizes ? makeWeaponSizeChecklist(data2.restricted_sizes) : null
  };
}
__name(unpackAmmo, "unpackAmmo");
const fields$j = foundry.data.fields, _MechSystemModel = class _MechSystemModel extends LancerDataModel {
  static defineSchema() {
    return {
      effect: new fields$j.HTMLField(),
      sp: new fields$j.NumberField({ nullable: !1, initial: 0 }),
      description: new fields$j.HTMLField(),
      type: new fields$j.StringField(),
      // @ts-expect-error
      ammo: new fields$j.ArrayField(new AmmoField()),
      ...template_universal_item(),
      ...template_bascdt(),
      ...template_destructible(),
      ...template_licensed(),
      ...template_uses()
    };
  }
  static migrateData(data2) {
    return data2.source && (data2.manufacturer = migrateManufacturer(data2.source)), super.migrateData(data2);
  }
};
__name(_MechSystemModel, "MechSystemModel");
let MechSystemModel = _MechSystemModel;
MechSystemModel.DEFAULT_ICON = "systems/lancer/assets/icons/mech_system.svg";
function unpackMechSystem(data2, context) {
  var _a19, _b, _c, _d, _e;
  const { deployables, tags } = addDeployableTags(data2.deployables, data2.tags, context);
  return {
    name: data2.name,
    type: EntryType.MECH_SYSTEM,
    system: {
      lid: data2.id,
      actions: (_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction),
      bonuses: (_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus),
      cascading: void 0,
      counters: (_c = data2.counters) == null ? void 0 : _c.map(unpackCounter),
      deployables,
      description: data2.description,
      destroyed: void 0,
      effect: data2.effect,
      integrated: data2.integrated,
      license: data2.license_id || data2.license,
      license_level: data2.license_level,
      manufacturer: data2.source,
      sp: data2.sp,
      synergies: (_d = data2.synergies) == null ? void 0 : _d.map(unpackSynergy),
      tags,
      type: data2.type,
      ammo: (_e = data2.ammo) == null ? void 0 : _e.map(unpackAmmo),
      uses: { value: 0, max: 0 }
    }
  };
}
__name(unpackMechSystem, "unpackMechSystem");
const fields$i = foundry.data.fields, _CoreBonusModel = class _CoreBonusModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$i.StringField({ nullable: !0 }),
      effect: new fields$i.StringField(),
      mounted_effect: new fields$i.StringField(),
      manufacturer: new fields$i.StringField(),
      ...template_universal_item(),
      ...template_bascdt()
    };
  }
  static migrateData(data2) {
    return data2.source && (data2.manufacturer = migrateManufacturer(data2.source)), super.migrateData(data2);
  }
};
__name(_CoreBonusModel, "CoreBonusModel");
let CoreBonusModel = _CoreBonusModel;
CoreBonusModel.DEFAULT_ICON = "systems/lancer/assets/icons/core_bonus.svg";
function unpackCoreBonus(data2, context) {
  var _a19, _b, _c, _d, _e;
  return {
    name: data2.name,
    type: EntryType.CORE_BONUS,
    system: {
      actions: ((_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction)) ?? [],
      bonuses: ((_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus)) ?? [],
      counters: ((_c = data2.counters) == null ? void 0 : _c.map(unpackCounter)) ?? [],
      deployables: ((_d = data2.deployables) == null ? void 0 : _d.map((d) => unpackDeployable(d, context))) ?? [],
      description: data2.description,
      effect: data2.effect,
      integrated: data2.integrated,
      lid: data2.id,
      manufacturer: data2.source,
      mounted_effect: data2.mounted_effect,
      synergies: (_e = data2.synergies) == null ? void 0 : _e.map(unpackSynergy),
      tags: []
    }
  };
}
__name(unpackCoreBonus, "unpackCoreBonus");
const fields$h = foundry.data.fields, _TalentModel = class _TalentModel extends LancerDataModel {
  static defineSchema() {
    return {
      curr_rank: new fields$h.NumberField({ nullable: !1, initial: 1, min: 1, max: 3 }),
      description: new fields$h.HTMLField(),
      terse: new fields$h.StringField(),
      ranks: new fields$h.ArrayField(
        new fields$h.SchemaField({
          name: new fields$h.StringField(),
          description: new fields$h.HTMLField(),
          exclusive: new fields$h.BooleanField({ initial: !1 }),
          // @ts-expect-error
          actions: new fields$h.ArrayField(new ActionField()),
          // @ts-expect-error
          bonuses: new fields$h.ArrayField(new BonusField()),
          // @ts-expect-error
          synergies: new fields$h.ArrayField(new SynergyField()),
          deployables: new fields$h.ArrayField(new LIDField()),
          // @ts-expect-error
          counters: new fields$h.ArrayField(new CounterField()),
          integrated: new fields$h.ArrayField(new LIDField())
        })
      ),
      ...template_universal_item()
    };
  }
};
__name(_TalentModel, "TalentModel");
let TalentModel = _TalentModel;
TalentModel.DEFAULT_ICON = "systems/lancer/assets/icons/talent.svg";
function unpackTalent(data2, context) {
  return {
    name: data2.name,
    type: EntryType.TALENT,
    system: {
      lid: data2.id,
      curr_rank: void 0,
      description: data2.description,
      ranks: data2.ranks.map((r) => {
        var _a19, _b, _c, _d, _e;
        return {
          actions: ((_a19 = r.actions) == null ? void 0 : _a19.map(unpackAction)) ?? [],
          bonuses: ((_b = r.bonuses) == null ? void 0 : _b.map(unpackBonus)) ?? [],
          counters: ((_c = r.counters) == null ? void 0 : _c.map(unpackCounter)) ?? [],
          deployables: ((_d = r.deployables) == null ? void 0 : _d.map((d) => unpackDeployable(d, context))) ?? [],
          description: r.description,
          exclusive: r.exclusive,
          integrated: r.integrated,
          name: r.name,
          synergies: ((_e = r.synergies) == null ? void 0 : _e.map(unpackSynergy)) ?? []
        };
      }),
      terse: data2.terse
    }
  };
}
__name(unpackTalent, "unpackTalent");
const fields$g = foundry.data.fields, _BondQuestionField = class _BondQuestionField extends fields$g.SchemaField {
  constructor(options = {}) {
    super(
      {
        question: new fields$g.StringField({ nullable: !1 }),
        options: new fields$g.ArrayField(new fields$g.StringField({ nullable: !1 }))
      },
      options
    );
  }
};
__name(_BondQuestionField, "BondQuestionField");
let BondQuestionField = _BondQuestionField;
const fields$f = foundry.data.fields, _BondModel = class _BondModel extends LancerDataModel {
  static defineSchema() {
    return {
      major_ideals: new fields$f.ArrayField(new fields$f.StringField()),
      minor_ideals: new fields$f.ArrayField(new fields$f.StringField()),
      // @ts-expect-error
      questions: new fields$f.ArrayField(new BondQuestionField()),
      // @ts-expect-error
      powers: new fields$f.ArrayField(new PowerField()),
      ...template_universal_item()
    };
  }
};
__name(_BondModel, "BondModel");
let BondModel = _BondModel;
BondModel.DEFAULT_ICON = "systems/lancer/assets/icons/bond.svg";
function unpackBond(data2) {
  const powers = data2.powers.map((p) => unpackPower(p));
  return {
    name: data2.name,
    type: EntryType.BOND,
    system: {
      lid: data2.id,
      major_ideals: data2.major_ideals,
      minor_ideals: data2.minor_ideals,
      questions: data2.questions,
      powers
    }
  };
}
__name(unpackBond, "unpackBond");
const fields$e = foundry.data.fields, _PilotArmorModel = class _PilotArmorModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$e.StringField({ nullable: !0 }),
      effect: new fields$e.StringField(),
      ...template_universal_item(),
      ...template_uses(),
      ...template_bascdt()
    };
  }
};
__name(_PilotArmorModel, "PilotArmorModel");
let PilotArmorModel = _PilotArmorModel;
PilotArmorModel.DEFAULT_ICON = "systems/lancer/assets/icons/role_tank.svg";
function unpackPilotArmor(data2, context) {
  var _a19, _b, _c;
  const { deployables, tags } = addDeployableTags(data2.deployables, data2.tags, context);
  return {
    name: data2.name,
    type: EntryType.PILOT_ARMOR,
    system: {
      actions: ((_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction)) ?? [],
      bonuses: ((_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus)) ?? [],
      synergies: (_c = data2.synergies) == null ? void 0 : _c.map(unpackSynergy),
      counters: void 0,
      deployables: deployables ?? [],
      description: data2.description,
      effect: data2.effect,
      lid: data2.id,
      tags: tags ?? []
    }
  };
}
__name(unpackPilotArmor, "unpackPilotArmor");
const fields$d = foundry.data.fields, _PilotGearModel = class _PilotGearModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$d.StringField({ nullable: !0 }),
      effect: new fields$d.StringField(),
      ...template_universal_item(),
      ...template_uses(),
      ...template_bascdt()
    };
  }
};
__name(_PilotGearModel, "PilotGearModel");
let PilotGearModel = _PilotGearModel;
PilotGearModel.DEFAULT_ICON = "systems/lancer/assets/icons/generic_item.svg";
function unpackPilotGear(data2, context) {
  var _a19, _b, _c;
  const { deployables, tags } = addDeployableTags(data2.deployables, data2.tags, context);
  return {
    name: data2.name,
    type: EntryType.PILOT_GEAR,
    system: {
      actions: ((_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction)) ?? [],
      bonuses: ((_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus)) ?? [],
      synergies: (_c = data2.synergies) == null ? void 0 : _c.map(unpackSynergy),
      counters: void 0,
      deployables: deployables ?? [],
      description: data2.description,
      effect: data2.effect,
      lid: data2.id,
      tags: tags ?? []
    }
  };
}
__name(unpackPilotGear, "unpackPilotGear");
const fields$c = foundry.data.fields, _PilotWeaponModel = class _PilotWeaponModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$c.StringField({ nullable: !0 }),
      // @ts-expect-error
      range: new fields$c.ArrayField(new RangeField()),
      // @ts-expect-error
      damage: new fields$c.ArrayField(new DamageField()),
      effect: new fields$c.StringField(),
      loaded: new fields$c.BooleanField(),
      ...template_universal_item(),
      ...template_uses(),
      ...template_bascdt()
    };
  }
};
__name(_PilotWeaponModel, "PilotWeaponModel");
let PilotWeaponModel = _PilotWeaponModel;
PilotWeaponModel.DEFAULT_ICON = "systems/lancer/assets/icons/role_artillery.svg";
function unpackPilotWeapon(data2, context) {
  var _a19, _b, _c;
  const { deployables, tags } = addDeployableTags(data2.deployables, data2.tags, context);
  return {
    name: data2.name,
    type: EntryType.PILOT_WEAPON,
    system: {
      actions: ((_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction)) ?? [],
      bonuses: ((_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus)) ?? [],
      synergies: (_c = data2.synergies) == null ? void 0 : _c.map(unpackSynergy),
      counters: void 0,
      deployables: deployables ?? [],
      description: data2.description,
      range: data2.range.map(unpackRange),
      damage: data2.damage.map(unpackDamage),
      effect: data2.effect,
      loaded: void 0,
      lid: data2.id,
      tags: tags ?? []
    }
  };
}
__name(unpackPilotWeapon, "unpackPilotWeapon");
const fields$b = foundry.data.fields, _SkillModel = class _SkillModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$b.HTMLField(),
      detail: new fields$b.StringField(),
      curr_rank: new fields$b.NumberField({ nullable: !1, initial: 1, min: 1, max: 3 }),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    return data2.rank && (data2.curr_rank = data2.rank), super.migrateData(data2);
  }
};
__name(_SkillModel, "SkillModel");
let SkillModel = _SkillModel;
SkillModel.DEFAULT_ICON = "systems/lancer/assets/icons/skill.svg";
function unpackSkill(data2, context) {
  return {
    name: data2.name,
    type: EntryType.SKILL,
    system: {
      lid: data2.id,
      curr_rank: 1,
      description: data2.description,
      detail: data2.detail
    }
  };
}
__name(unpackSkill, "unpackSkill");
const fields$a = foundry.data.fields, _LicenseModel = class _LicenseModel extends LancerDataModel {
  static defineSchema() {
    return {
      key: new fields$a.StringField(),
      manufacturer: new fields$a.StringField(),
      curr_rank: new fields$a.NumberField({ nullable: !1, initial: 1, min: 1, max: 3 }),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    return typeof data2.manufacturer == "object" && (data2.manufacturer = data2.manufacturer.fallback_lid), data2.rank && (data2.curr_rank = data2.rank), super.migrateData(data2);
  }
};
__name(_LicenseModel, "LicenseModel");
let LicenseModel = _LicenseModel;
LicenseModel.DEFAULT_ICON = "systems/lancer/assets/icons/license.svg";
function unpackLicense(name2, key, manufacturer, _context) {
  return {
    name: name2,
    type: EntryType.LICENSE,
    system: {
      lid: `lic_${key}`,
      key,
      manufacturer
    }
  };
}
__name(unpackLicense, "unpackLicense");
const fields$9 = foundry.data.fields, _NpcClassModel = class _NpcClassModel extends LancerDataModel {
  static defineSchema() {
    return {
      role: new fields$9.StringField(),
      flavor: new fields$9.HTMLField(),
      tactics: new fields$9.HTMLField(),
      base_features: new fields$9.SetField(new LIDField()),
      optional_features: new fields$9.SetField(new LIDField()),
      base_stats: new ControlledLengthArrayField(new NpcStatBlockField({ nullable: !1 }), { length: 3 }),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    var _a19, _b, _c, _d;
    if (data2.flavor ?? (data2.flavor = (_a19 = data2.info) == null ? void 0 : _a19.flavor), data2.tactics ?? (data2.tactics = (_b = data2.info) == null ? void 0 : _b.tactics), data2.base_features = (_c = data2.base_features) == null ? void 0 : _c.map((bf) => regRefToLid(bf)).filter((x) => x), data2.optional_features = (_d = data2.optional_features) == null ? void 0 : _d.map((of) => regRefToLid(of)).filter((x) => x), typeof data2.base_stats == "object" && !Array.isArray(data2.base_stats) && (data2.base_stats = convertNpcStats(data2.base_stats)), data2.base_stats)
      for (let i = 0; i < data2.base_stats.length; i++)
        data2.base_stats[i].size !== void 0 && (data2.base_stats[i].size >= 1 ? data2.base_stats[i].size = Math.floor(data2.base_stats[i].size) : data2.base_stats[i].size = 0.5);
    return super.migrateData(data2);
  }
};
__name(_NpcClassModel, "NpcClassModel");
let NpcClassModel = _NpcClassModel;
NpcClassModel.DEFAULT_ICON = "systems/lancer/assets/icons/npc_class.svg";
function unpackNpcClass(data2, context) {
  const frameImg = frameToPath(data2.name);
  return {
    name: data2.name,
    type: EntryType.NPC_CLASS,
    img: frameImg ?? void 0,
    system: {
      lid: data2.id,
      role: data2.role,
      flavor: data2.info.flavor,
      tactics: data2.info.tactics,
      base_features: data2.base_features,
      optional_features: data2.optional_features,
      base_stats: convertNpcStats(data2.stats)
    }
  };
}
__name(unpackNpcClass, "unpackNpcClass");
const fields$8 = foundry.data.fields, _NpcTemplateModel = class _NpcTemplateModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields$8.HTMLField(),
      base_features: new fields$8.SetField(new LIDField()),
      optional_features: new fields$8.SetField(new LIDField()),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    var _a19, _b;
    return data2.base_features = (_a19 = data2.base_features) == null ? void 0 : _a19.map((bf) => regRefToLid(bf)).filter((x) => x), data2.optional_features = (_b = data2.optional_features) == null ? void 0 : _b.map((of) => regRefToLid(of)).filter((x) => x), super.migrateData(data2);
  }
};
__name(_NpcTemplateModel, "NpcTemplateModel");
let NpcTemplateModel = _NpcTemplateModel;
NpcTemplateModel.DEFAULT_ICON = "systems/lancer/assets/icons/npc_template.svg";
function unpackNpcTemplate(data2, context) {
  return {
    name: data2.name,
    type: EntryType.NPC_TEMPLATE,
    system: {
      lid: data2.id,
      description: data2.description,
      base_features: data2.base_features,
      optional_features: data2.optional_features
    }
  };
}
__name(unpackNpcTemplate, "unpackNpcTemplate");
const fields$7 = foundry.data.fields, _NpcFeatureModel = class _NpcFeatureModel extends LancerDataModel {
  static getDefaultArtwork(itemData2) {
    var _a19;
    let img = this.DEFAULT_ICON;
    switch ((_a19 = itemData2 == null ? void 0 : itemData2.system) == null ? void 0 : _a19.type) {
      case NpcFeatureType.Reaction:
        img = "systems/lancer/assets/icons/reaction.svg";
        break;
      case NpcFeatureType.System:
        img = "systems/lancer/assets/icons/system.svg";
        break;
      case NpcFeatureType.Tech:
        img = "systems/lancer/assets/icons/tech_full.svg";
        break;
      case NpcFeatureType.Trait:
        img = "systems/lancer/assets/icons/trait.svg";
        break;
      case NpcFeatureType.Weapon:
        img = "systems/lancer/assets/icons/weapon.svg";
        break;
    }
    return { img };
  }
  static defineSchema() {
    return {
      effect: new fields$7.HTMLField(),
      bonus: new NpcStatBlockField({ nullable: !0 }),
      override: new NpcStatBlockField({ nullable: !0 }),
      // @ts-expect-error
      tags: new fields$7.ArrayField(new TagField()),
      type: new fields$7.StringField({ choices: Object.values(NpcFeatureType), initial: NpcFeatureType.Trait }),
      charged: new fields$7.BooleanField(),
      loaded: new fields$7.BooleanField(),
      tier_override: new fields$7.NumberField({ integer: !0, min: 0, max: 3 }),
      // Weapon
      weapon_type: new fields$7.StringField(),
      // @ts-expect-error
      damage: new fields$7.ArrayField(new fields$7.ArrayField(new DamageField())),
      // @ts-expect-error
      range: new fields$7.ArrayField(new RangeField()),
      on_hit: new fields$7.HTMLField(),
      accuracy: new ControlledLengthArrayField(new fields$7.NumberField({ integer: !0, initial: 0 }), { length: 3 }),
      attack_bonus: new ControlledLengthArrayField(new fields$7.NumberField({ integer: !0, initial: 0 }), {
        length: 3
      }),
      // Trait - N/A
      // Reaction
      trigger: new fields$7.StringField(),
      // System - N/A
      // Tech - mostly covered by weapon
      tech_type: new fields$7.StringField({ choices: Object.values(NpcTechType), initial: NpcTechType.Quick }),
      tech_attack: new fields$7.BooleanField({ nullable: !0, initial: null }),
      // Origin data - track where it came from
      origin: new fields$7.SchemaField({
        type: new fields$7.StringField(),
        name: new fields$7.StringField(),
        base: new fields$7.BooleanField()
      }),
      // Templates
      ...template_destructible(),
      ...template_uses(),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    return typeof data2.bonus == "object" && !Array.isArray(data2.bonus) && (data2.bonus = convertNpcStats(data2.bonus)[0]), typeof data2.override == "object" && !Array.isArray(data2.override) && (data2.override = convertNpcStats(data2.override)[0]), data2.type && data2.type !== NpcFeatureType.Tech ? data2.tech_attack = !1 : data2.tech_attack === null && (data2.tech_attack = !!data2.attack_bonus || !!data2.accuracy), super.migrateData(data2);
  }
};
__name(_NpcFeatureModel, "NpcFeatureModel");
let NpcFeatureModel = _NpcFeatureModel;
NpcFeatureModel.DEFAULT_ICON = "systems/lancer/assets/icons/npc_feature.svg";
function unpackNpcFeature(data2, context) {
  let base = {
    name: data2.name,
    type: EntryType.NPC_FEATURE,
    system: {
      lid: data2.id,
      effect: data2.effect,
      bonus: data2.bonus,
      override: data2.override,
      tags: (data2.tags || []).map(unpackTag),
      type: data2.type,
      origin: data2.origin,
      charged: void 0,
      uses: void 0,
      loaded: void 0,
      destroyed: void 0,
      tier_override: 0
    }
  };
  if (data2.type == NpcFeatureType.Reaction) {
    let bs = base.system;
    bs.trigger = data2.trigger;
  } else if (data2.type != NpcFeatureType.System) {
    if (data2.type != NpcFeatureType.Trait) {
      if (data2.type == NpcFeatureType.Tech) {
        let bs = base.system;
        bs.tech_type = restrict_enum(NpcTechType, NpcTechType.Quick, data2.tech_type), bs.accuracy = data2.accuracy ?? [], bs.attack_bonus = data2.attack_bonus ?? [], bs.tech_attack = !!data2.attack_bonus || !!data2.accuracy;
      } else if (data2.type == NpcFeatureType.Weapon) {
        let bs = base.system;
        bs.accuracy = data2.accuracy ?? [], bs.attack_bonus = data2.attack_bonus ?? [], bs.weapon_type = data2.weapon_type, bs.on_hit = data2.on_hit, bs.damage = [];
        let i = 0, done = !1;
        for (; !done; ) {
          done = !0;
          let sub_damage = [];
          for (let d of data2.damage)
            d.damage.length > i && (sub_damage.push(
              unpackDamage({
                type: d.type,
                val: d.damage[i]
              })
            ), done = !1);
          done || bs.damage.push(sub_damage), i += 1;
        }
        bs.range = data2.range.map(unpackRange);
      }
    }
  }
  return base;
}
__name(unpackNpcFeature, "unpackNpcFeature");
const fields$6 = foundry.data.fields, _WeaponModModel = class _WeaponModModel extends LancerDataModel {
  static defineSchema() {
    return {
      // @ts-expect-error
      added_tags: new fields$6.ArrayField(new TagField()),
      // @ts-expect-error
      added_damage: new fields$6.ArrayField(new DamageField()),
      // @ts-expect-error
      added_range: new fields$6.ArrayField(new RangeField()),
      effect: new fields$6.HTMLField(),
      description: new fields$6.HTMLField(),
      sp: new fields$6.NumberField({ nullable: !1, initial: 0 }),
      allowed_types: new WeaponTypeChecklistField(),
      allowed_sizes: new WeaponSizeChecklistField(),
      ...template_universal_item(),
      ...template_bascdt(),
      ...template_destructible(),
      ...template_licensed(),
      ...template_uses()
    };
  }
  static migrateData(data2) {
    return data2.source && (data2.manufacturer = migrateManufacturer(data2.source)), super.migrateData(data2);
  }
};
__name(_WeaponModModel, "WeaponModModel");
let WeaponModModel = _WeaponModModel;
WeaponModModel.DEFAULT_ICON = "systems/lancer/assets/icons/weapon_mod.svg";
function unpackWeaponMod(data2, context) {
  var _a19, _b, _c, _d, _e, _f, _g;
  const { deployables, tags } = addDeployableTags(data2.deployables, data2.tags, context);
  return {
    name: data2.name,
    type: EntryType.WEAPON_MOD,
    system: {
      lid: data2.id,
      actions: (_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction),
      bonuses: (_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus),
      cascading: void 0,
      counters: (_c = data2.counters) == null ? void 0 : _c.map(unpackCounter),
      deployables,
      description: data2.description,
      destroyed: void 0,
      effect: data2.effect,
      integrated: data2.integrated,
      license: data2.license_id || data2.license,
      license_level: data2.license_level,
      manufacturer: data2.source,
      sp: data2.sp,
      synergies: (_d = data2.synergies) == null ? void 0 : _d.map(unpackSynergy),
      tags,
      uses: { value: 0, max: 0 },
      added_damage: (_e = data2.added_damage) == null ? void 0 : _e.map(unpackDamage),
      added_range: (_f = data2.added_range) == null ? void 0 : _f.map(unpackRange),
      added_tags: (_g = data2.added_tags) == null ? void 0 : _g.map(unpackTag),
      allowed_sizes: makeWeaponSizeChecklist(data2.allowed_sizes ?? []),
      allowed_types: makeWeaponTypeChecklist(data2.allowed_types ?? [])
    }
  };
}
__name(unpackWeaponMod, "unpackWeaponMod");
const fields$5 = foundry.data.fields, _ReserveModel = class _ReserveModel extends LancerDataModel {
  static defineSchema() {
    return {
      consumable: new fields$5.BooleanField(),
      label: new fields$5.StringField(),
      // resource_name, resource_note, and resource_cost are in the lancer-data spec but not used currently
      // resource_name: new fields.StringField(),
      // resource_note: new fields.StringField(),
      // resource_cost: new fields.StringField(),
      // type: new fields.StringField({ choices: Object.values(ReserveType), initial: ReserveType.Tactical }),
      type: new fields$5.StringField({ initial: ReserveType.Tactical }),
      // ^ Strictness here isn't really super useful
      used: new fields$5.BooleanField(),
      description: new fields$5.HTMLField(),
      ...template_universal_item(),
      ...template_bascdt()
    };
  }
};
__name(_ReserveModel, "ReserveModel");
let ReserveModel = _ReserveModel;
ReserveModel.DEFAULT_ICON = "systems/lancer/assets/icons/reserve_tac.svg";
function unpackReserve(data2, context) {
  var _a19, _b, _c, _d, _e;
  return {
    name: data2.name ?? data2.label ?? "Unnamed Reserve",
    type: EntryType.RESERVE,
    system: {
      lid: data2.id,
      description: data2.description,
      actions: (_a19 = data2.actions) == null ? void 0 : _a19.map(unpackAction),
      bonuses: (_b = data2.bonuses) == null ? void 0 : _b.map(unpackBonus),
      consumable: data2.consumable,
      counters: (_c = data2.counters) == null ? void 0 : _c.map(unpackCounter),
      deployables: (_d = data2.deployables) == null ? void 0 : _d.map((d) => unpackDeployable(d, context)),
      integrated: data2.integrated,
      label: data2.label,
      // These three attributes are in the lancer-data spec, but seem to be unused.
      // resource_cost: data.resource_cost,
      // resource_name: data.resource_name,
      // resource_note: data.resource_note,
      synergies: (_e = data2.synergies) == null ? void 0 : _e.map(unpackSynergy),
      tags: void 0,
      type: restrict_enum(ReserveType, ReserveType.Tactical, data2.type),
      used: data2.used
    }
  };
}
__name(unpackReserve, "unpackReserve");
const fields$4 = foundry.data.fields, _StatusModel = class _StatusModel extends LancerDataModel {
  static defineSchema() {
    return {
      effects: new fields$4.HTMLField(),
      type: new fields$4.StringField({ choices: ["status", "condition", "effect"], initial: "effect" }),
      ...template_universal_item()
    };
  }
  static migrateData(data2) {
    return data2.type && (data2.type = data2.type.toLowerCase()), super.migrateData(data2);
  }
  async _preCreate(...[data2, options, user]) {
    if (await super._preCreate(data2, options, user) === !1)
      return !1;
    if (this.parent.parent)
      return this.parent.parent.toggleStatusEffect(this.lid, { active: !0 }), !1;
  }
};
__name(_StatusModel, "StatusModel");
let StatusModel = _StatusModel;
StatusModel.DEFAULT_ICON = "systems/lancer/assets/icons/reticule.svg";
function generateStunnedEffect({ name: name2 = "Stunned", description: description2 = "" }) {
  return {
    name: name2,
    description: description2,
    changes: [
      {
        key: "system.evasion",
        mode: 5,
        priority: null,
        value: "5"
      }
    ]
  };
}
__name(generateStunnedEffect, "generateStunnedEffect");
function unpackStatus(data2, _context) {
  const lid = data2.id || data2.icon.replace("-", "") || data2.name.toLowerCase(), img = `systems/lancer/assets/icons/white/${data2.type.toLowerCase()}_${lid}.svg`, effects = Array.isArray(data2.effects) ? data2.effects.join("<br>") : data2.effects;
  let effect3;
  return lid === "stunned" && (effect3 = generateStunnedEffect({ name: data2.name, description: effects })), {
    name: data2.name,
    type: EntryType.STATUS,
    img,
    effects: effect3 ? [effect3] : [],
    system: {
      lid,
      effects,
      terse: data2.terse,
      type: restrict_choices(["status", "condition", "effect"], "effect", data2.type)
    }
  };
}
__name(unpackStatus, "unpackStatus");
const fields$3 = foundry.data.fields, npc_schema = {
  destroyed: new fields$3.BooleanField({ initial: !1 }),
  meltdown_timer: new fields$3.NumberField({ required: !1, nullable: !0, integer: !0, min: 0 }),
  notes: new fields$3.HTMLField(),
  tier: new fields$3.NumberField({ min: 1, max: 3, initial: 1, integer: !0 }),
  ...template_universal_actor(),
  ...template_action_tracking(),
  ...template_heat(),
  ...template_statuses(),
  ...template_struss()
}, _NpcModel = class _NpcModel extends LancerDataModel {
  static defineSchema() {
    return npc_schema;
  }
};
__name(_NpcModel, "NpcModel");
let NpcModel = _NpcModel;
NpcModel.DEFAULT_ICON = "systems/lancer/assets/icons/npc_class.svg";
function generateNpcDataFromClass(npc_class) {
  return {
    name: npc_class.name,
    type: EntryType.NPC,
    img: npc_class.img ?? void 0,
    system: {
      notes: `Updated via LCP import at ${(/* @__PURE__ */ new Date()).toISOString()}`
    }
  };
}
__name(generateNpcDataFromClass, "generateNpcDataFromClass");
const lp$4 = LANCER.log_prefix, packTypes = Object.values(EntryType).filter((et) => ![EntryType.MECH, EntryType.PILOT].includes(et));
async function clearAll(v1 = !1) {
  await setAllLock(!1, v1);
  const pack_ids = v1 ? new Set(Object.values(EntryType).map((et) => `world.${et}`)) : new Set(Object.values(EntryType).map(get_pack_id));
  for (let p of pack_ids) {
    let pack = game.packs.get(p);
    if (!pack)
      continue;
    const keys = Array.from(pack.index.keys());
    await pack.documentClass.deleteDocuments(keys, { pack: pack.collection }), await Folder.deleteDocuments(Array.from(pack.folders.keys()), { pack: pack.collection });
  }
  await setAllLock(!0, v1);
}
__name(clearAll, "clearAll");
async function importCP(cp, progress_callback) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K;
  await setAllLock(!1);
  try {
    progress_callback || (progress_callback = /* @__PURE__ */ __name((_a20, _b2) => {
    }, "progress_callback"));
    let totalItems = 0;
    totalItems += ((_a19 = cp.data.coreBonuses) == null ? void 0 : _a19.length) ?? 0, totalItems += ((_b = cp.data.frames) == null ? void 0 : _b.length) ?? 0, totalItems += ((_c = cp.data.mods) == null ? void 0 : _c.length) ?? 0, totalItems += ((_d = cp.data.npcClasses) == null ? void 0 : _d.length) ?? 0, totalItems += ((_e = cp.data.npcFeatures) == null ? void 0 : _e.length) ?? 0, totalItems += ((_f = cp.data.npcTemplates) == null ? void 0 : _f.length) ?? 0, totalItems += ((_g = cp.data.pilotGear) == null ? void 0 : _g.length) ?? 0, totalItems += ((_h = cp.data.reserves) == null ? void 0 : _h.length) ?? 0, totalItems += ((_i = cp.data.skills) == null ? void 0 : _i.length) ?? 0, totalItems += ((_j = cp.data.statuses) == null ? void 0 : _j.length) ?? 0, totalItems += ((_k = cp.data.systems) == null ? void 0 : _k.length) ?? 0, totalItems += ((_l = cp.data.tags) == null ? void 0 : _l.length) ?? 0, totalItems += ((_m = cp.data.talents) == null ? void 0 : _m.length) ?? 0, totalItems += ((_n = cp.data.bonds) == null ? void 0 : _n.length) ?? 0, totalItems += ((_o = cp.data.weapons) == null ? void 0 : _o.length) ?? 0, totalItems += ((_p = cp.data.npcClasses) == null ? void 0 : _p.length) ?? 0, totalItems += ((_q = cp.data.npcClasses) == null ? void 0 : _q.reduce((acc, nc) => {
      var _a20;
      return acc + (((_a20 = nc.base_features) == null ? void 0 : _a20.length) ?? 0);
    }, 0)) ?? 0;
    let existingLids = /* @__PURE__ */ new Map();
    for (let et of packTypes)
      (await (await get_pack(et)).getDocuments()).forEach((d) => {
        existingLids.set(d.system.lid || d.name, d);
      });
    let transmitCount = 0, progress_hook = /* @__PURE__ */ __name((doc) => {
      doc.pack && !doc.parent && (transmitCount++, progress_callback(transmitCount, totalItems));
    }, "progress_hook");
    Hooks.on("createItem", progress_hook), Hooks.on("createActor", progress_hook);
    let context = {
      createdDeployables: []
    }, allCoreBonuses = ((_r = cp.data.coreBonuses) == null ? void 0 : _r.map((cb) => unpackCoreBonus(cb, context))) ?? [], allFrames = ((_s = cp.data.frames) == null ? void 0 : _s.map((d) => unpackFrame(d, context))) ?? [], allMods = ((_t = cp.data.mods) == null ? void 0 : _t.map((d) => unpackWeaponMod(d, context))) ?? [], allNpcClasses = ((_u = cp.data.npcClasses) == null ? void 0 : _u.map((d) => unpackNpcClass(d, context))) ?? [], allNpcs = allNpcClasses.map((d) => generateNpcDataFromClass(d)) ?? [], allNpcFeatures = ((_v = cp.data.npcFeatures) == null ? void 0 : _v.map((d) => unpackNpcFeature(d, context))) ?? [], allNpcTemplates = ((_w = cp.data.npcTemplates) == null ? void 0 : _w.map((d) => unpackNpcTemplate(d, context))) ?? [], allPilotArmor = ((_x = cp.data.pilotGear) == null ? void 0 : _x.filter((g) => g.type == "Armor").map((pa) => unpackPilotArmor(pa, context))) ?? [], allPilotGear = ((_y = cp.data.pilotGear) == null ? void 0 : _y.filter((g) => g.type == "Gear").map((pa) => unpackPilotGear(pa, context))) ?? [], allPilotWeapons = ((_z = cp.data.pilotGear) == null ? void 0 : _z.filter((g) => g.type == "Weapon").map((pa) => unpackPilotWeapon(pa, context))) ?? [], allReserves = ((_A = cp.data.reserves) == null ? void 0 : _A.map((s) => unpackReserve(s, context))) ?? [], allSkills = ((_B = cp.data.skills) == null ? void 0 : _B.map((s) => unpackSkill(s, context))) ?? [], allStatuses = ((_C = cp.data.statuses) == null ? void 0 : _C.map((s) => unpackStatus(s, context))) ?? [], allSystems = ((_D = cp.data.systems) == null ? void 0 : _D.map((s) => unpackMechSystem(s, context))) ?? [], allTags = ((_E = cp.data.tags) == null ? void 0 : _E.map((t) => unpackTagTemplate(t))) ?? [], allTalents = ((_F = cp.data.talents) == null ? void 0 : _F.map((t) => unpackTalent(t, context))) ?? [], allBonds = ((_G = cp.data.bonds) == null ? void 0 : _G.map((b) => unpackBond(b))) ?? [], allWeapons = ((_H = cp.data.weapons) == null ? void 0 : _H.map((d) => unpackMechWeapon(d, context))) ?? [], allLicenses = [], existingLicenses = ((_J = await ((_I = game.packs.get(get_pack_id(EntryType.LICENSE))) == null ? void 0 : _I.getDocuments({ type: EntryType.LICENSE }))) == null ? void 0 : _J.map(
      (l) => l.system.key
    )) ?? [];
    for (let frame of cp.data.frames ?? []) {
      let lid = frame.license_id ?? frame.id;
      existingLicenses.includes(lid) || allLicenses.push(unpackLicense(frame.name, lid, frame.source, context));
    }
    const createOrUpdateDocs = /* @__PURE__ */ __name(async (doc_class, item_data, et) => {
      let existingUpdates = [], newCreates = [], pack = await get_pack(et), folder = [EntryType.NPC, EntryType.STATUS].includes(et) ? void 0 : pack.folders.find((f) => f.getFlag(game.system.id, "entrytype") === et) ?? await Folder.create(
        {
          name: game.i18n.localize(`TYPES.${pack.metadata.type}.${et}`),
          type: pack.metadata.type,
          [`flags.${game.system.id}.entrytype`]: et
        },
        { pack: get_pack_id(et) }
      ), results = [];
      for (let d of item_data) {
        let key = d.system.lid || d.name, existing = existingLids.get(key);
        existing ? existingUpdates.push({
          ...d,
          _id: existing.id,
          folder: folder == null ? void 0 : folder.id
        }) : (d.folder = folder == null ? void 0 : folder.id, newCreates.push(d));
      }
      return results.push(...await doc_class.createDocuments(newCreates, { pack: get_pack_id(et) })), results.push(...await doc_class.updateDocuments(existingUpdates, { pack: get_pack_id(et) })), results;
    }, "createOrUpdateDocs");
    await createOrUpdateDocs(CONFIG.Item.documentClass, allCoreBonuses, EntryType.CORE_BONUS), await createOrUpdateDocs(CONFIG.Item.documentClass, allFrames, EntryType.FRAME), await createOrUpdateDocs(CONFIG.Item.documentClass, allMods, EntryType.WEAPON_MOD), await createOrUpdateDocs(CONFIG.Item.documentClass, allLicenses, EntryType.LICENSE), await createOrUpdateDocs(CONFIG.Item.documentClass, allNpcClasses, EntryType.NPC_CLASS), await createOrUpdateDocs(CONFIG.Item.documentClass, allNpcTemplates, EntryType.NPC_TEMPLATE), await createOrUpdateDocs(CONFIG.Item.documentClass, allNpcFeatures, EntryType.NPC_FEATURE), await createOrUpdateDocs(CONFIG.Item.documentClass, allPilotArmor, EntryType.PILOT_ARMOR), await createOrUpdateDocs(CONFIG.Item.documentClass, allPilotGear, EntryType.PILOT_GEAR), await createOrUpdateDocs(CONFIG.Item.documentClass, allPilotWeapons, EntryType.PILOT_WEAPON), await createOrUpdateDocs(CONFIG.Item.documentClass, allReserves, EntryType.RESERVE), await createOrUpdateDocs(CONFIG.Item.documentClass, allSkills, EntryType.SKILL), await createOrUpdateDocs(CONFIG.Item.documentClass, allStatuses, EntryType.STATUS), await createOrUpdateDocs(CONFIG.Item.documentClass, allSystems, EntryType.MECH_SYSTEM), await createOrUpdateDocs(CONFIG.Item.documentClass, allTalents, EntryType.TALENT), await createOrUpdateDocs(CONFIG.Item.documentClass, allBonds, EntryType.BOND), await createOrUpdateDocs(CONFIG.Item.documentClass, allWeapons, EntryType.MECH_WEAPON), await createOrUpdateDocs(CONFIG.Actor.documentClass, context.createdDeployables, EntryType.DEPLOYABLE);
    const npcActors = await createOrUpdateDocs(CONFIG.Actor.documentClass, allNpcs, EntryType.NPC), npcPromises = [];
    for (let npc of npcActors) {
      const existingClass = npc.items.find((i) => i.type === EntryType.NPC_CLASS);
      existingClass && (await npc.removeClassFeatures(existingClass), await npc.deleteEmbeddedDocuments("Item", [existingClass.id]));
      let classLid = (_K = allNpcClasses.find((n) => n.name === npc.name)) == null ? void 0 : _K.system.lid;
      if (!classLid)
        continue;
      let thisClass = await fromLid(classLid, { source: "compendium" });
      thisClass && (await npc.quickOwn(thisClass), npcPromises.push(...npc.npcClassSwapPromises));
    }
    await Promise.all(npcPromises);
    let newTagConfig = foundry.utils.duplicate(game.settings.get(game.system.id, LANCER.setting_tag_config));
    for (let t of allTags)
      transmitCount++, newTagConfig[t.lid] = t, progress_callback(transmitCount, totalItems);
    game.settings.set(game.system.id, LANCER.setting_tag_config, newTagConfig), Hooks.off("createItem", progress_hook), Hooks.off("createActor", progress_hook);
    for (let p of packTypes)
      (await get_pack(p)).clear();
    progress_callback(transmitCount, totalItems);
  } catch (err) {
    console.error(err);
  }
  await setAllLock(!0);
}
__name(importCP, "importCP");
async function setAllLock(lock = !1, v1 = !1) {
  const pack_ids = v1 ? new Set(Object.values(EntryType).map((et) => `world.${et}`)) : new Set(Object.values(EntryType).map(get_pack_id));
  for (let p of pack_ids) {
    let pack = game.packs.get(p);
    await (pack == null ? void 0 : pack.configure({ locked: lock }));
  }
}
__name(setAllLock, "setAllLock");
async function clearCompendiumData(options = { v1: !1 }) {
  ui.notifications.info("Clearing all LANCER Compendium data. Please wait."), console.log(`${lp$4} Clearing all LANCER Compendium data.`), await game.settings.set(game.system.id, LANCER.setting_core_data, ""), await game.settings.set(game.system.id, LANCER.setting_lcps, new LCPIndex(null)), await clearAll(options.v1), ui.notifications.info("LANCER Compendiums cleared.");
}
__name(clearCompendiumData, "clearCompendiumData");
const name = "@massif/lancer-data", version = "3.1.7", description = "Data for the LANCER TTRPG", main = "index.js", scripts = {
  build: "node ./scripts/build.js",
  test: "node ./scripts/test.js"
}, repository = {
  type: "git",
  url: "https://github.com/massif-press/lancer-data.git"
}, directories = {
  lib: "lib"
}, author = "Massif Press", license = "GPL-3.0-or-later", devDependencies = {
  "zip-lib": "^0.7.3"
}, keywords = [
  "lancer",
  "compcon",
  "comp/con",
  "lancerrpg",
  "massif"
], _package = {
  name,
  version,
  description,
  main,
  scripts,
  repository,
  directories,
  author,
  license,
  devDependencies,
  keywords
}, _package$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  author,
  default: _package,
  description,
  devDependencies,
  directories,
  keywords,
  license,
  main,
  name,
  repository,
  scripts,
  version
}, Symbol.toStringTag, { value: "Module" })), { log_prefix: lp$3 } = LANCER;
async function commitDataModelMigrations() {
  var _a19;
  await Item.updateDocuments(game.items._source, { diff: !1, recursive: !1, noHook: !0 }), await Actor.updateDocuments(game.actors._source, { diff: !1, recursive: !1, noHook: !0 }), await Scene.updateDocuments(game.scenes._source, { diff: !1, recursive: !1, noHook: !0 }), (_a19 = ui.notifications) == null || _a19.info("All world Actors, Items, and Scenes migrated and data models cleaned.");
}
__name(commitDataModelMigrations, "commitDataModelMigrations");
const migrationProgressBarLabel = /* @__PURE__ */ __name(() => `Migration to v${game.system.version} in progress...`, "migrationProgressBarLabel");
let toMigrate = 1, migrated = 0;
function migrationProgress(count) {
  migrated += count;
  const percent = Math.floor(migrated / toMigrate * 100);
  SceneNavigation.displayProgressBar({ label: migrationProgressBarLabel(), pct: percent });
}
__name(migrationProgress, "migrationProgress");
async function migrateWorld() {
  var _a19, _b;
  const curr_version = game.settings.get(game.system.id, LANCER.setting_migration_version);
  if (foundry.utils.isNewerVersion("2.0.0", curr_version)) {
    console.log(`${lp$3} World is coming from 1.X. Show the migration journal and clear compendiums.`);
    const journals = await ((_a19 = game.packs.get("lancer.lancer_info")) == null ? void 0 : _a19.getDocuments({ name: "LANCER System Information" }));
    if (journals.length) {
      const systemInfo = journals[0], migrationPage = systemInfo.pages.find((p) => p.name.startsWith("Migrating"));
      await ((_b = systemInfo.sheet) == null ? void 0 : _b.render(!0)), (/* @__PURE__ */ __name(async () => {
        var _a20, _b2;
        for (; !((_a20 = systemInfo.sheet) != null && _a20.rendered); )
          await new Promise((r) => setTimeout(r, 100));
        (_b2 = systemInfo.sheet) == null || _b2.goToPage(migrationPage._id);
      }, "showPage"))();
    }
    await clearCompendiumData({ v1: !0 }), await migrateCompendiumStructure();
  }
  const coreData = await getBaseContentPack();
  await importCP(coreData.cp), await game.settings.set(game.system.id, LANCER.setting_core_data, coreData.availableVersion), setTimeout(() => SceneNavigation.displayProgressBar({ label: migrationProgressBarLabel(), pct: 0 }), 1e3), await commitDataModelMigrations(), game.settings.get(game.system.id, LANCER.setting_core_data) !== version && new Dialog({
    title: "Compendium Migration Failed",
    content: `
<p>Something went wrong while attempting to build the core data Compendiums for the new Lancer system.
Please refresh the page to try again.</p>`,
    buttons: {
      accept: {
        label: "Refresh",
        callback: () => {
          ui.notifications.info("Page reloading in 3 seconds..."), setTimeout(() => window.location.reload(!1), 3e3);
        }
      },
      cancel: {
        label: "Close"
      }
    },
    default: "accept"
  }).render(!0);
  function reduceScene(total, scene) {
    return total + scene.tokens.contents.reduce((t2, token) => {
      var _a20;
      return t2 += 1, token.isLinked || (t2 += 1 + (((_a20 = token.actor) == null ? void 0 : _a20.items.size) || 0)), t2;
    }, 0);
  }
  __name(reduceScene, "reduceScene"), toMigrate = game.items.size, toMigrate += game.actors.reduce((total, actor) => total += 1 + actor.items.size, 0), toMigrate += game.scenes.reduce(reduceScene, 0);
  for (const pack of game.packs.contents)
    pack.metadata.type === "Item" ? toMigrate += pack.index.size : pack.metadata.type === "Actor" ? (await pack.getDocuments(), toMigrate += pack.contents.reduce((t2, actor) => t2 += 1 + actor.items.size, 0)) : pack.metadata.type === "Scene" && (await pack.getDocuments(), toMigrate += pack.contents.reduce(reduceScene, 0));
  console.log(`Migrating approximately ${toMigrate} documents`);
  for (let p of game.packs.contents)
    p.metadata.packageType === "world" && await migrateCompendium(p);
  let all_actor_updates = (await Promise.all(game.actors.contents.map(migrateActor))).filter((u) => u && !!u._id);
  await Actor.updateDocuments(all_actor_updates);
  let all_item_updates = (await Promise.all(game.items.contents.map(migrateItem))).filter((u) => u && !!u._id);
  await Item.updateDocuments(all_item_updates), await Promise.all(game.scenes.contents.map(migrateScene)), await game.settings.set(game.system.id, LANCER.setting_migration_version, game.system.version), migrationProgress(toMigrate), ui.notifications.info(`LANCER System Migration to version ${game.system.version} completed!`, {
    permanent: !0
  });
}
__name(migrateWorld, "migrateWorld");
async function migrateCompendium(pack) {
  var _a19, _b, _c;
  const wasLocked = pack.locked;
  if (await pack.configure({ locked: !1 }), pack.locked)
    return ui.notifications.error(`Could not migrate ${pack.collection}: unable to unlock`);
  let name2 = pack.metadata.name;
  if (["sitrep", "environment", "faction", "tag", "quirk", "manufacturer"].includes(name2)) {
    await pack.deleteCompendium();
    return;
  }
  if (await pack.migrate(), pack.documentName == "Actor")
    try {
      let documents = await pack.getDocuments(), updates = (await Promise.all(documents.map(migrateActor))).filter((u) => u && !!u._id);
      await Actor.updateDocuments(updates, { pack: pack.collection, diff: !1, recursive: !1, noHook: !0 });
    } catch (e) {
      const packLabel = game.i18n.localize(pack.metadata.label);
      console.error(`Error while migrating actor compendium ${packLabel}:`, e), (_a19 = ui.notifications) == null || _a19.error(`Error while migrating actor compendium ${packLabel}. Check the console for details.`);
    }
  else if (pack.documentName == "Item")
    try {
      let documents = await pack.getDocuments(), updates = (await Promise.all(documents.map(migrateItem))).filter((u) => u && !!u._id);
      await Item.updateDocuments(updates, { pack: pack.collection, diff: !1, recursive: !1, noHook: !0 });
    } catch (e) {
      const packLabel = game.i18n.localize(pack.metadata.label);
      console.error(`Error while migrating item compendium ${packLabel}:`, e), (_b = ui.notifications) == null || _b.error(`Error while migrating item compendium ${packLabel}. Check the console for details.`);
    }
  else if (pack.documentName == "Scene")
    try {
      let documents = await pack.getDocuments(), updates = await Promise.all(documents.map(migrateScene));
      await Scene.updateDocuments(updates, { pack: pack.collection, diff: !1, recursive: !1, noHook: !0 });
    } catch (e) {
      const packLabel = game.i18n.localize(pack.metadata.label);
      console.error(`Error while migrating scene ${packLabel}:`, e), (_c = ui.notifications) == null || _c.error(`Error while migrating scene ${packLabel}. Check the console for details.`);
    }
  await pack.configure({ locked: wasLocked }), console.log(`Migrated all ${pack.documentName} entities from Compendium ${pack.collection}`);
}
__name(migrateCompendium, "migrateCompendium");
async function migrateActor(actor) {
  var _a19;
  try {
    const updateData = {
      _id: actor.id,
      // @ts-expect-error
      system: actor.system.toObject(!0)
      // To commit any datamodel migrations
    };
    let currVersion = game.settings.get(game.system.id, LANCER.setting_migration_version);
    foundry.utils.isNewerVersion("2.0", currVersion);
    let itemUpdates = (await Promise.all(actor.items.contents.map(migrateItem))).filter((u) => u && !!u._id);
    return await actor.updateEmbeddedDocuments("Item", itemUpdates), migrationProgress(1), updateData;
  } catch (e) {
    return console.error(`Error while migrating actor [${actor.id} | ${actor.name}]:`, e), (_a19 = ui.notifications) == null || _a19.error(`Error while migrating actor ${actor.name}. Check the console for details.`), {};
  }
}
__name(migrateActor, "migrateActor");
async function migrateItem(item) {
  try {
    const updateData = {
      _id: item.id,
      // @ts-expect-error
      system: item.system.toObject(!0)
      // To commit any datamodel migrations
    };
    let currVersion = game.settings.get(game.system.id, LANCER.setting_migration_version);
    if (item.type === "license" && foundry.utils.isNewerVersion("2.1.1", currVersion) && (console.log(`Fixing license lid for ${item.system.key}`), updateData.system.lid = `lic_${item.system.key}`), item.type === "status" && item.system.lid === "stunned" && !item.effects.contents.find((e) => e.changes.some((c) => c.key === "system.evasion"))) {
      console.log(`${lp$3} Adding evasion change to existing stunned status ${item.name}`);
      const stunnedEffect = generateStunnedEffect({ name: item.name, description: item.system.effects || "" });
      updateData.effects = [...updateData.effects || [], stunnedEffect, ,];
    }
    return migrationProgress(1), updateData;
  } catch (e) {
    return console.error(`Error while migrating item ${item.id} ${item.name}:`, e), {};
  }
}
__name(migrateItem, "migrateItem");
async function migrateScene(scene) {
  var _a19, _b;
  try {
    for (let token of scene.tokens.contents)
      try {
        if (!token.isLinked && token.actor) {
          console.log(`Migrating unlinked token actor ${token.actor.name}`);
          let updateData = await migrateActor(token.actor);
          await token.actor.update(updateData);
        }
      } catch (e) {
        console.error(
          `Error while migrating unlinked token [${token.id} | ${token.name}] in scene [${scene.id} | ${scene.name}]:`,
          e
        ), (_a19 = ui.notifications) == null || _a19.error(
          `Error while migrating unlinked token ${token.name} in scene ${scene.name}. Check the console for details.`
        );
      }
    let tokenUpdates = (await Promise.all(scene.tokens.contents.map(migrateTokenDocument))).filter((u) => u && !!u._id);
    await scene.updateEmbeddedDocuments("Token", tokenUpdates);
  } catch (e) {
    console.error(`Error while migrating scene [${scene.id} | ${scene.name}]:`, e), (_b = ui.notifications) == null || _b.error(`Error while migrating scene ${scene.name}. Check the console for details.`);
  }
}
__name(migrateScene, "migrateScene");
async function migrateTokenDocument(token) {
  try {
    const updateData = {
      _id: token.id
    };
    let currVersion = game.settings.get(game.system.id, LANCER.setting_migration_version);
    return foundry.utils.isNewerVersion("2.0", currVersion), migrationProgress(1), updateData;
  } catch (e) {
    return console.error(`Error while migrating token [${token.id} | ${token.name}]:`, e), {};
  }
}
__name(migrateTokenDocument, "migrateTokenDocument");
async function migrateCompendiumStructure() {
  var _a19, _b;
  await Promise.all(Object.values(EntryType).map((v) => {
    var _a20;
    return (_a20 = game.packs.get(`world.${v}`)) == null ? void 0 : _a20.configure({ locked: !1 });
  })), await Promise.all(
    Object.values(EntryType).map((v) => {
      const p = game.packs.get(`world.${v}`);
      if (p && p.index.contents.length == 0)
        return p.deleteCompendium();
    })
  );
  const ets = Object.values(EntryType);
  for (let et of ets) {
    const documents = await ((_a19 = game.packs.get(`world.${et}`)) == null ? void 0 : _a19.getDocuments()) ?? [];
    if (console.log(`Moving ${documents.length} ${et} documents`), documents.length === 0)
      continue;
    const pack = await get_pack(et), folder = [EntryType.NPC, EntryType.STATUS].includes(et) ? void 0 : pack.folders.find((f) => f.getFlag(game.system.id, "entrytype") === et) ?? await Folder.create(
      {
        name: game.i18n.localize(`TYPES.${pack.metadata.type}.${et}`),
        type: pack.metadata.type,
        [`flags.${game.system.id}.entrytype`]: et
      },
      { pack: get_pack_id(et) }
    ), doc_data = documents.map((d) => ({ ...d.toObject(), folder: folder == null ? void 0 : folder.id })), doc_class = documents[0].documentName;
    await CONFIG[doc_class].documentClass.createDocuments(doc_data, { pack: get_pack_id(et) }), await ((_b = game.packs.get(`world.${et}`)) == null ? void 0 : _b.deleteCompendium());
  }
}
__name(migrateCompendiumStructure, "migrateCompendiumStructure");
const migrations = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  commitDataModelMigrations,
  migrateActor,
  migrateCompendium,
  migrateCompendiumStructure,
  migrateItem,
  migrateScene,
  migrateTokenDocument,
  migrateWorld
}, Symbol.toStringTag, { value: "Module" }));
const _LancerCombat = class _LancerCombat extends Combat {
  _sortCombatants(a, b) {
    const dc = b.disposition - a.disposition;
    return dc !== 0 ? dc : super._sortCombatants(a, b);
  }
  async _preCreate(...[data2, options, user]) {
    return this.updateSource({ turn: null }), super._preCreate(data2, options, user);
  }
  async _manageTurnEvents(adjustedTurn) {
    this.previous && super._manageTurnEvents(adjustedTurn);
  }
  /**
   * Set all combatants to their max activations
   */
  async resetActivations() {
    const skipDefeated = "skipDefeated" in this.settings && this.settings.skipDefeated, updates = this.combatants.map((c) => ({
      _id: c.id,
      [`flags.${game.system.id}.activations.value`]: skipDefeated && c.isDefeated ? 0 : c.activations.max ?? 0
    }));
    return this.updateEmbeddedDocuments("Combatant", updates);
  }
  async startCombat() {
    this._playCombatSound("startEncounter");
    const updateData = { round: 1, turn: null };
    return Hooks.callAll("combatStart", this, updateData), await this.resetActivations(), await this.update(updateData), this;
  }
  async nextRound() {
    await this.resetActivations();
    const updateData = { round: this.round + 1, turn: null };
    let advanceTime = Math.max(this.turns.length - (this.turn || 0), 0) * CONFIG.time.turnTime;
    advanceTime += CONFIG.time.roundTime;
    const updateOptions = { advanceTime, direction: 1 };
    return Hooks.callAll("combatRound", this, updateData, updateOptions), await this.update(updateData, updateOptions), this;
  }
  /**
   * Ends the current turn without starting a new one
   */
  async nextTurn() {
    const updateData = { turn: null }, updateOptions = { advanceTime: 0, direction: 0 };
    return Hooks.callAll("combatTurn", this, updateData, updateOptions), await this.update(updateData, updateOptions), this;
  }
  async previousRound() {
    await this.resetActivations();
    const round2 = Math.max(this.round - 1, 0);
    let advanceTime = 0;
    round2 > 0 && (advanceTime -= CONFIG.time.roundTime);
    const updateData = { round: round2, turn: null }, updateOptions = { advanceTime, direction: -1 };
    return Hooks.callAll("combatRound", this, updateData, updateOptions), await this.update(updateData, updateOptions), this;
  }
  /**
   * End the current turn and refund the activation
   */
  async previousTurn() {
    var _a19;
    if (this.turn === null)
      return this;
    const updateData = { turn: null }, updateOptions = { advanceTime: -CONFIG.time.turnTime, direction: -1 };
    return await ((_a19 = this.combatant) == null ? void 0 : _a19.modifyCurrentActivations(1)), Hooks.callAll("combatTurn", this, updateData, updateOptions), await this.update(updateData, updateOptions), this;
  }
  async resetAll() {
    return await this.resetActivations(), this.combatants.forEach((c) => c.updateSource({ initiative: null })), await this.update({ turn: null, combatants: this.combatants.toObject() }, { diff: !1 }), this;
  }
  /**
   * Filter out next up turn notifications sound since the next up isn't deterministic
   */
  _playCombatSound(...[announcement]) {
    if (announcement !== "nextUp")
      return super._playCombatSound(announcement);
  }
  /**
   * Sets the active turn to the combatant passed by id or calls
   * {@link LancerCombat#requestActivation()} if the user does not have
   * permission to modify the combat
   */
  async activateCombatant(id, override = !1) {
    var _a19, _b;
    if (!((_a19 = game.user) != null && _a19.isGM || this.turn == null && ((_b = this.combatants.get(id)) != null && _b.isOwner) || override))
      return this.requestActivation(id);
    const combatant = this.getEmbeddedDocument("Combatant", id, {});
    if (!(combatant != null && combatant.activations.value))
      return this;
    await (combatant == null ? void 0 : combatant.modifyCurrentActivations(-1));
    const updateData = { turn: this.turns.findIndex((t) => t.id === id) }, updateOptions = { advanceTime: CONFIG.time.turnTime, direction: 1 };
    return Hooks.callAll("combatTurn", this, updateData, updateOptions), this.update(updateData, updateOptions);
  }
  /**
   * Sets the active turn back to 0 (no active unit) if the passed id
   * corresponds to the current turn and the user has ownership of the
   * combatant.
   */
  async deactivateCombatant(id) {
    var _a19;
    const turn = this.turns.findIndex((t) => t.id === id);
    return turn !== this.turn ? this : !this.turns[turn].testUserPermission(game.user, "OWNER") && !((_a19 = game.user) != null && _a19.isGM) ? this : this.nextTurn();
  }
  /**
   * Calls any Hooks registered for "LancerCombatRequestActivate".
   */
  async requestActivation(id) {
    return Hooks.callAll("LancerCombatRequestActivate", this, id), this;
  }
};
__name(_LancerCombat, "LancerCombat");
let LancerCombat = _LancerCombat;
const _LancerCombatant = class _LancerCombatant extends Combatant {
  /**
   * This just fixes a bug in foundry 0.8.x that prevents Combatants with no
   * associated token or actor from being modified, even by the GM
   */
  testUserPermission(...[user, permission, options]) {
    var _a19;
    return ((_a19 = this.actor) == null ? void 0 : _a19.testUserPermission(user, permission, options)) ?? user.isGM;
  }
  prepareBaseData() {
    var _a19, _b, _c, _d, _e;
    if (super.prepareBaseData(), ((_c = (_b = (_a19 = this.flags) == null ? void 0 : _a19[game.system.id]) == null ? void 0 : _b.activations) == null ? void 0 : _c.max) === void 0 && (canvas != null && canvas.ready)) {
      const activations = foundry.utils.getProperty(((_d = this.actor) == null ? void 0 : _d.getRollData()) ?? {}, "activations") ?? 1;
      this.updateSource({
        [`flags.${game.system.id}.activations`]: {
          max: activations,
          value: (((_e = this.parent) == null ? void 0 : _e.round) ?? 0) > 0 ? activations : 0
        }
      });
    }
    this.initiative ?? (this.initiative = 0);
  }
  /**
   * The current activation data for the combatant.
   */
  get activations() {
    return this.getFlag(game.system.id, "activations") ?? {};
  }
  /**
   * The disposition for this combatant. In order, manually specified for this
   * combatant, token disposition, token disposition for the associated actor,
   * -2.
   */
  get disposition() {
    var _a19, _b;
    const disposition = this.getFlag(game.system.id, "disposition") ?? ((_a19 = this.token) == null ? void 0 : _a19.disposition) ?? ((_b = this.actor) == null ? void 0 : _b.prototypeToken.disposition) ?? -2;
    return disposition === CONST.TOKEN_DISPOSITIONS.FRIENDLY && this.hasPlayerOwner ? 2 : disposition;
  }
  /**
   * Adjusts the number of activations that a combatant can take
   * @param num - The number of maximum activations to add (can be negative)
   */
  async addActivations(num) {
    return num === 0 ? this : this.update({
      [`flags.${game.system.id}.activations`]: {
        max: Math.max((this.activations.max ?? 1) + num, 1),
        value: Math.max((this.activations.value ?? 0) + num, 0)
      }
    });
  }
  /**
   * Adjusts the number of current activations that a combatant has
   * @param num - The number of current activations to add (can be negative)
   */
  async modifyCurrentActivations(num) {
    var _a19, _b;
    return num === 0 ? this : this.update({
      [`flags.${game.system.id}.activations`]: {
        value: Math.clamp((((_a19 = this.activations) == null ? void 0 : _a19.value) ?? 0) + num, 0, ((_b = this.activations) == null ? void 0 : _b.max) ?? 1)
      }
    });
  }
};
__name(_LancerCombatant, "LancerCombatant");
let LancerCombatant = _LancerCombatant;
function targetsFromTemplate(templateId) {
  var _a19, _b;
  const template = (_a19 = canvas.scene) == null ? void 0 : _a19.getEmbeddedDocument("MeasuredTemplate", templateId, {}), grid = canvas == null ? void 0 : canvas.grid;
  if (template === void 0 || canvas === void 0 || grid === void 0 || canvas.ready !== !0)
    return;
  let test_token;
  if (((_b = canvas.grid) == null ? void 0 : _b.type) === CONST.GRID_TYPES.GRIDLESS)
    test_token = /* @__PURE__ */ __name((token) => {
      const token_radius = token.document.width / 2, range = canvas.grid.measurePath([token.center, template]).distance;
      if (template.t === "circle")
        return range <= token_radius + template.distance;
      if (template.t === "cone") {
        let sd = template.object.ray.distance, s1 = Ray.fromAngle(
          template.object.ray.A.x,
          template.object.ray.A.y,
          Math.toRadians(template.direction + template.angle / 2),
          sd
        ), s2 = Ray.fromAngle(
          template.object.ray.A.x,
          template.object.ray.A.y,
          Math.toRadians(template.direction - template.angle / 2),
          sd
        );
        return range <= template.distance + token_radius && (in_cone_arc(template.object.ray, Math.toRadians(template.angle), token.center) || min_dist(s1, token.center) < token_radius * canvas.dimensions.size || min_dist(s2, token.center) < token_radius * canvas.dimensions.size);
      }
      if (template.t === "ray") {
        let o1 = Ray.fromAngle(
          template.object.ray.A.x,
          template.object.ray.A.y,
          template.object.ray.angle - Math.PI / 2,
          template.width * canvas.dimensions.size
        ), r1 = Ray.fromAngle(o1.B.x, o1.B.y, template.object.ray.angle, template.object.ray.distance), o2 = Ray.fromAngle(
          template.object.ray.A.x,
          template.object.ray.A.y,
          template.object.ray.angle + Math.PI / 2,
          template.width * canvas.dimensions.size
        ), r2 = Ray.fromAngle(o2.B.x, o2.B.y, template.object.ray.angle, template.object.ray.distance);
        return range <= template.distance + token_radius && (min_dist(r1, token.center) < token_radius * canvas.dimensions.size || min_dist(r2, token.center) < token_radius * canvas.dimensions.size || min_dist(template.object.ray, token.center) < token_radius * canvas.dimensions.size);
      }
      if (template.t === "rect") {
        if (template.object._getGridHighlightShape().contains(token.center.x, token.center.y))
          return !0;
        let s1 = Ray.fromAngle(template.object.ray.A.x, template.object.ray.A.y, 0, template.object.ray.dx), s2 = new Ray(s1.B, template.object.ray.B), s3 = Ray.fromAngle(s2.B.x, s2.B.y, Math.PI, template.object.ray.dx), s4 = new Ray(s3.B, s1.A);
        return min_dist(s1, token.center) < token_radius * canvas.dimensions.size || min_dist(s2, token.center) < token_radius * canvas.dimensions.size || min_dist(s3, token.center) < token_radius * canvas.dimensions.size || min_dist(s4, token.center) < token_radius * canvas.dimensions.size;
      }
      return !1;
    }, "test_token");
  else {
    const { sizeX, sizeY } = canvas.grid, template_offsets = template.object._getGridHighlightPositions().map(
      ({ x, y }) => canvas.grid.getOffset({ x: x + sizeX / 2, y: y + sizeY / 2 })
    );
    test_token = /* @__PURE__ */ __name((token) => token.getOccupiedSpaces().map((p) => canvas.grid.getOffset(p)).some((o) => template_offsets.some((e) => o.i === e.i && o.j === e.j)), "test_token");
  }
  let ignore = canvas.templates.get(templateId).document.getFlag(game.system.id, "ignore");
  const targets = canvas.tokens.quadtree.getObjects(template.object.bounds, {
    collisionTest: (o) => {
      const t = o.t;
      return !(((ignore == null ? void 0 : ignore.tokens.includes(t.id)) || (ignore == null ? void 0 : ignore.dispositions.includes(t.document.disposition))) ?? !1) && test_token(t);
    }
  }).toObject().map((t) => t.id);
  game.user.updateTokenTargets(targets), game.user.broadcastActivity({ targets });
}
__name(targetsFromTemplate, "targetsFromTemplate");
function dot_product(p, q) {
  return p.dx * q.dx + p.dy * q.dy;
}
__name(dot_product, "dot_product");
function comp(PR, PQ) {
  return dot_product(PR, PQ) / PR.distance;
}
__name(comp, "comp");
function min_dist(seg, p) {
  const T = new Ray(seg.A, p), component = comp(seg, T);
  return component <= 0 ? T.distance : component >= seg.distance ? new Ray(seg.B, p).distance : Math.sqrt(T.distance ** 2 - component ** 2);
}
__name(min_dist, "min_dist");
function in_cone_arc(ray, angle, p) {
  const a = Ray.fromAngle(ray.A.x, ray.A.y, ray.angle, 1), b = Ray.towardsPoint(ray.A, p, 1);
  return Math.acos(Math.clamp(-1, dot_product(a, b), 1)) < angle / 2;
}
__name(in_cone_arc, "in_cone_arc");
function item_edit_arrayed_actions(path, title, options) {
  let doc = helper_root_doc(options), dd = drilldownDocument(doc, path), action_detail = "";
  return dd.terminus && (action_detail = buildActionArrayHTML(dd.sub_doc, dd.sub_path, { editable: !0 })), `
    <div class="card clipped double edi">
      <span class="lancer-header lancer-primary submajor ">
        ${title}
        <a class="gen-control fas fa-plus" data-action="append" data-path="${path}" data-action-value="(struct)action"></a>
      </span>
      <div class="editable-action-array">
        ${action_detail}
      </div>
    </div>`;
}
__name(item_edit_arrayed_actions, "item_edit_arrayed_actions");
function item_edit_arrayed_damage(path, title, options) {
  let dam_arr = resolveHelperDotpath(options, path), dam_detail = "";
  if (dam_arr)
    for (let i = 0; i < dam_arr.length; i++)
      dam_detail = dam_detail.concat(damageEditor(path.concat(`.${i}`), options));
  return `
    <div class="card clipped double edi">
      <span class="lancer-header lancer-primary submajor ">
        ${title}
        <a class="gen-control fas fa-plus" data-action="append" data-path="${path}" data-action-value="(struct)damage"></a>
      </span>
      ${dam_detail}
    </div>`;
}
__name(item_edit_arrayed_damage, "item_edit_arrayed_damage");
function item_edit_arrayed_range(path, title, options) {
  let range_arr = resolveHelperDotpath(options, path), range_detail = "";
  if (range_arr)
    for (let i = 0; i < range_arr.length; i++)
      range_detail = range_detail.concat(rangeEditor(path.concat(`.${i}`), options));
  return `
    <div class="card clipped double">
      <span class="lancer-header lancer-primary submajor ">
        ${title}
        <a class="gen-control fas fa-plus" data-action="append" data-path="${path}" data-action-value="(struct)range"></a>
      </span>
      ${range_detail}
    </div>`;
}
__name(item_edit_arrayed_range, "item_edit_arrayed_range");
function item_edit_arrayed_bonuses(path, options) {
  return resolveHelperDotpath(options, path, []), bonusesDisplay(path, !0, options);
}
__name(item_edit_arrayed_bonuses, "item_edit_arrayed_bonuses");
function item_edit_arrayed_counters() {
  return console.log("TODO: Add arrayed counters editor"), "<span>TODO: Add arrayed counters editor</span>";
}
__name(item_edit_arrayed_counters, "item_edit_arrayed_counters");
function item_edit_arrayed_deployables(path, title, options) {
  let root = helper_root_doc(options), dd = drilldownDocument(root, path);
  if (!(dd.sub_doc instanceof LancerItem))
    return "";
  let depHTML = buildDeployablesArrayHBS(dd.sub_doc, dd.sub_path, extendHelper(options, { full: !0 }));
  return `
    <div class="card clipped">
      <span class="lancer-header lancer-primary submajor clipped-top">
        ${title}
      </span>
      ${depHTML}
    </div>`;
}
__name(item_edit_arrayed_deployables, "item_edit_arrayed_deployables");
function item_edit_arrayed_synergies(path, title, options) {
  let synHTML = resolveHelperDotpath(options, path, []).map((d, i) => "").join("");
  return `
    <div class="card clipped">
      <span class="lancer-header lancer-primary submajor clipped-top">
        ${title}
      </span>
      ${synHTML}
    </div>`;
}
__name(item_edit_arrayed_synergies, "item_edit_arrayed_synergies");
function item_edit_arrayed_enum(title, path, enum_name, options) {
  let resolved_enum = resolve_enum(enum_name), enum_arr = resolveHelperDotpath(options, path, []), selector_detail = "";
  if (enum_arr)
    for (let i = 0; i < enum_arr.length; i++)
      selector_detail = selector_detail.concat(`
            <div class="flexrow">
                ${std_enum_select(path.concat(`.${i}`), resolved_enum, options)}
                <a class="gen-control fas fa-trash" data-action="splice" data-path="${path.concat(`.${i}`)}"></a>
            </div>`);
  return `
    <div class="card clipped item-edit-arrayed">
      <span class="lancer-header lancer-primary submajor ">
        ${title}
        <a class="gen-control fas fa-plus" data-action="append" data-path="${path}" data-action-value="(struct)${enum_name}"></a>
      </span>
        ${selector_detail}
    </div>`;
}
__name(item_edit_arrayed_enum, "item_edit_arrayed_enum");
function item_edit_checkboxes_object(title, path, options) {
  let checkbox_obj = resolveHelperDotpath(options, path, {}), selector_detail = "";
  for (let [k, v] of Object.entries(checkbox_obj))
    selector_detail += `<div class="flexrow">
        ${std_checkbox(path.concat(`.${k}`), extendHelper(options, { label: k }))}
    </div>`;
  return `
    <div class="card clipped item-edit-arrayed">
      <span class="lancer-header lancer-primary submajor ">
        ${title}
      </span>
      ${selector_detail}
    </div>`;
}
__name(item_edit_checkboxes_object, "item_edit_checkboxes_object");
function item_edit_enum(path, enum_name, options) {
  let resolved_enum = resolve_enum(enum_name);
  return std_enum_select(path, resolved_enum, options);
}
__name(item_edit_enum, "item_edit_enum");
function resolve_enum(enum_name) {
  let none_enum;
  switch (((none_enum2) => {
    none_enum2.None = "None";
  })(none_enum || (none_enum = {})), enum_name) {
    case "WeaponSize":
      return WeaponSize;
    case "WeaponType":
      return WeaponType;
    case "ActivationType":
      return ActivationType;
    case "ReserveType":
      return ReserveType;
    default:
      return console.debug("Using default enum with enum_name of ".concat(enum_name)), none_enum;
  }
}
__name(resolve_enum, "resolve_enum");
function item_edit_effect(path, options) {
  return large_textbox_card("EFFECT", path, options);
}
__name(item_edit_effect, "item_edit_effect");
function item_edit_arrayed_integrated(path, title, options) {
  return `
    <div class="card clipped item-edit-arrayed">
      <span class="lancer-header lancer-primary submajor ">
        INTEGRATED ITEMS
      </span>
        ${resolveHelperDotpath(options, path, []).map((s, i) => `INTEGRATED ITEM: ${s}`).join("")}
    </div>`;
}
__name(item_edit_arrayed_integrated, "item_edit_arrayed_integrated");
function item_edit_license(options) {
  var _a19;
  let license2 = ((_a19 = options.data.root) == null ? void 0 : _a19.license) || null, licenseInfo, rankInfo;
  return license2 ? (licenseInfo = `<div class="${EntryType.LICENSE} ref lancer-license medium" ${ref_params(license2)}>
      <i class="cci cci-license i--m i--dark"> </i>
      <span class="major modifier-name">${license2.name}</span>
    </div>`, rankInfo = `<div class="flexrow rank-wrapper">
    <span>Rank</span>
    <input name="system.license_level" value="${options.data.root.data.system.license_level}" type="number" data-dtype="Number" />
</div>`) : (licenseInfo = `<div class="lancer-license medium">
      <span class="major modifier-name">No License</span>
    </div>`, rankInfo = ""), `      
    <div class="flexrow edit-license-wrapper">
        ${licenseInfo}
        ${rankInfo}
    </div>`;
}
__name(item_edit_license, "item_edit_license");
function item_edit_sp(path, options) {
  return options.hash.label = "SP:", std_num_input(path, options);
}
__name(item_edit_sp, "item_edit_sp");
function item_edit_uses(cur_uses_path, max_uses_path, options) {
  let cur_uses = resolveHelperDotpath(options, cur_uses_path), max_uses = resolveHelperDotpath(options, max_uses_path);
  return max_uses ? ` 
    <div class="flexcol uses-editor clipped-top">
        <span class="major">Uses</span>
        <div class="flexrow flex-center no-wrap">
            <input class="lancer-stat" type="number" name="${cur_uses_path}" value="${cur_uses}" data-dtype="Number" style="justify-content: left"/>
            <span>/</span>
            <span class="lancer-stat" style="justify-content: left">${max_uses}</span>
        </div>
    </div>` : "";
}
__name(item_edit_uses, "item_edit_uses");
function effect_view(actor, index2, effect3, options) {
  return `<div class="active-effect">
                <span>
                    ${effect3.getFlag(game.system.id, "ephemeral") ? "[Readonly]: " : ""}${effect3.name}
                </span>
                <a class="lancer-context-menu" data-active-effect-index="${index2}" data-uuid="${actor.uuid}">
                    <i class="fas fa-ellipsis-v"></i>
                </a>
            </div>`;
}
__name(effect_view, "effect_view");
function effect_categories_view(actor, effects, options) {
  let categories = [];
  for (let cat of effects)
    categories.push(`
      <div class="card clipped">
        <span class="lancer-header lancer-primary submajor">${cat.label}</span>
        <div class="flexcol">
          ${cat.effects.map(([index2, effect3]) => effect_view(actor, index2, effect3)).join("")}
        </div>
      </div>
      `);
  return `<div class="flexcol">${categories.join("")} </div>`;
}
__name(effect_categories_view, "effect_categories_view");
function miniProfile(profile, options) {
  const attack = profile.attack ? `<span data-tooltip="Attack Bonus"><i class="cci cci-reticule"></i>${profile.attack}</span>` : "", accuracyTooltip = (profile.accuracy ?? 0) < 0 ? 'data-tooltip="Difficulty"' : 'data-tooltip="Accuracy"', accuracy = profile.accuracy ? `<span ${accuracyTooltip}>${profile.accuracy < 0 ? '<i class="cci cci-difficulty"></i>' : '<i class="cci cci-accuracy"></i>'}${Math.abs(profile.accuracy)}</span>` : "", ranges = profile.range.map((r) => `<span data-tooltip="${r.type}"><i class="cci cci-${r.type.toLowerCase()}"></i>${r.val}</span>`).join(""), damages = profile.damage ? profile.damage.map(
    (d) => `<span data-tooltip="${d.type}"><i class="cci cci-${d.type.toLowerCase()} damage--${d.type.toLowerCase()}"></i>${d.val}</span>`
  ).join("") : "";
  return `
    <div class="mini-weapon-profile flexrow">
      ${profile.attack || profile.accuracy ? `
        <div class="mini-weapon-profile-accuracy flexrow">
          ${attack}
          ${accuracy}
        </div>
        <span class="mini-weapon-profile-separator">//</span>
        ` : ""}
      <div class="mini-weapon-profile-range flexrow">
        ${ranges}
      </div>
      ${profile.damage ? `
      <span class="mini-weapon-profile-separator">//</span>
      <div class="mini-weapon-profile-damage flexrow">
        ${damages}
      </div>` : ""}
    </div>`;
}
__name(miniProfile, "miniProfile");
function attackTarget(hit, options) {
  var _a19;
  const hitChip = hit.crit ? `<span class="card clipped lancer-hit-chip crit">${game.i18n.format("lancer.chat-card.attack.crit")}</span>` : hit.hit ? `<span class="card clipped lancer-hit-chip hit">${game.i18n.format("lancer.chat-card.attack.hit")}</span>` : `<span class="card clipped lancer-hit-chip miss">${game.i18n.format("lancer.chat-card.attack.miss")}</span>`, img = (_a19 = hit.target.actor) == null ? void 0 : _a19.img, uuid = hit.target.document.uuid, icon = hit.crit ? "fas fa-explosion i--s" : hit.hit ? "fas fa-crosshairs i--s" : "mdi mdi-call-missed i--sm";
  return `
    <div class="lancer-hit-target" data-uuid=${uuid}>
      <img class="lancer-hit-thumb" src="${img}" />
      <span class="lancer-hit-text-name" data-tooltip="${hit.target.name}"><b>${hit.target.name}</b></span>
      ${hitChip}
      <div class="lancer-hit-roll">
        ${lancerDiceRoll(hit.roll, hit.tt, icon)}
      </div>
    </div>`;
}
__name(attackTarget, "attackTarget");
function damageTarget(target, context, options) {
  var _a19, _b;
  const statuses = ((_a19 = target.target.actor) == null ? void 0 : _a19.statuses) || /* @__PURE__ */ new Set(), exposed = statuses.has("exposed"), resists = {
    energy: statuses.has("resistance_energy"),
    explosive: statuses.has("resistance_explosive"),
    kinetic: statuses.has("resistance_kinetic"),
    burn: statuses.has("resistance_burn"),
    heat: statuses.has("resistance_heat")
  }, select = context.configurable ? `
          <select class="lancer-damage-apply-select" title="Select damage multiplier">
            <option value="2">2×</option>
            <option value="1" selected>1×</option>
            <option value="0.5">Resist</option>
          </select>` : "";
  let damageResults;
  target.crit ? damageResults = context.crit_damage_results : target.hit ? damageResults = context.damage_results : damageResults = context.reliable_results || [];
  const damageTypes = new Set(
    damageResults.filter((d) => {
      var _a20;
      return !d.target || ((_a20 = d.target) == null ? void 0 : _a20.document.uuid) === target.target.document.uuid;
    }).map((d) => d.d_type.toLowerCase())
  ), damageIcons = Array.from(damageTypes).map((d) => `<i class="cci cci-${d} i--s damage--${d}"></i>`).join(""), bonusRolls = damageResults.filter(
    (d) => {
      var _a20;
      return d.bonus && ((_a20 = d.target) == null ? void 0 : _a20.document.uuid) === target.target.document.uuid;
    }
  ).map(
    (bd) => `<div class="flexrow"><span class="lancer-damage-tag" style="flex-grow: 0" data-tooltip="This row is bonus damage">BONUS</span>${lancerDiceRoll(
      bd.roll,
      bd.tt,
      `cci cci-${bd.d_type.toLowerCase()} damage--${bd.d_type.toLowerCase()} i--m`
    )}</div>`
  ), damageTags = [];
  for (const [type2, resist] of Object.entries(resists))
    resist && damageTags.push(
      `<span class="lancer-damage-tag" data-tooltip="Resist ${type2.capitalize()}"><i class="mdi mdi-shield-half-full i--xs"></i></span>`
    );
  exposed && damageTags.push(
    '<span class="lancer-damage-tag" data-tooltip="Exposed"><i class="cci cci-status-exposed i--xs"></i></span>'
  ), (context.ap && !context.paracausal || target.ap && !(target.paracausal || context.paracausal)) && damageTags.push(
    '<span class="lancer-damage-tag" data-tooltip="Armor Piercing"><i class="mdi mdi-shield-off-outline i--xs"></i></span>'
  ), (context.paracausal || target.paracausal) && damageTags.push(
    '<span class="lancer-damage-tag" data-tooltip="Cannot Be Reduced"><i class="cci cci-large-beam i--xs"></i></span>'
  ), (context.half_damage || target.half_damage) && damageTags.push(
    '<span class="lancer-damage-tag" data-tooltip="Half Damage"><i class="mdi mdi-fraction-one-half i--xs"></i></span>'
  );
  const damageTagsDisplay = damageTags.length ? `<div class="lancer-damage-tags">${damageTags.join("")}</div>` : "", img = (_b = target.target.actor) == null ? void 0 : _b.img, uuid = target.target.document.uuid;
  return `
    <div class="lancer-damage-target" data-uuid=${uuid}>
      <img class="lancer-hit-thumb" src="${img}" />
      <span class="lancer-hit-text-name" data-tooltip="${target.target.name}"><b>${target.target.name}</b></span>
      <div
        class="lancer-damage-button-group"
        data-target="${uuid}"
        data-hit="${target.hit}"
        data-crit="${target.crit}"
        data-add-burn="${context.add_burn}"
      >
        ${select}
        <button
          class="lancer-button lancer-damage-apply"
          title="Apply damage"
        >${damageIcons}</button>
      </div>
      <div class="lancer-damage-rolls-tags flexrow">
        <div class="lancer-target-bonus-damage flexcol">${bonusRolls.join("")}</div>
        ${damageTagsDisplay}
      </div>
    </div>`;
}
__name(damageTarget, "damageTarget");
function registerHandlebarsHelpers() {
  Handlebars.registerHelper("inc", function(value) {
    return parseInt(value) + 1;
  }), Handlebars.registerHelper("dec", function(value) {
    return parseInt(value) - 1;
  }), Handlebars.registerHelper("concat", function(...values) {
    return values.slice(0, values.length - 1).join("");
  }), Handlebars.registerHelper("rp", function(path, options) {
    return resolveHelperDotpath(options, path);
  }), Handlebars.registerHelper("getset", function(path, options) {
    let value = resolveHelperDotpath(options, path);
    return ` name="${path}" value="${value}" `;
  }), Handlebars.registerHelper("idx", function(array2, index2) {
    return array2[index2];
  }), Handlebars.registerHelper("neg", function(value) {
    return parseInt(value) * -1;
  }), Handlebars.registerHelper("double", function(value) {
    return parseInt(value) * 2;
  }), Handlebars.registerHelper("eq", function(val1, val2) {
    return val1 === val2;
  }), Handlebars.registerHelper("neq", function(val1, val2) {
    return val1 !== val2;
  }), Handlebars.registerHelper("or", function(val1, val2) {
    return val1 || val2;
  }), Handlebars.registerHelper("gt", function(val1, val2) {
    return val1 > val2;
  }), Handlebars.registerHelper("gtpi", function(val1, val2) {
    return val1 = parseInt(val1), val2 = parseInt(val2), val1 > val2;
  }), Handlebars.registerHelper("lt", function(val1, val2) {
    return val1 < val2;
  }), Handlebars.registerHelper("ltpi", function(val1, val2) {
    return val1 = parseInt(val1), val2 = parseInt(val2), val1 < val2;
  }), Handlebars.registerHelper("lower-case", function(str) {
    return str.toLowerCase();
  }), Handlebars.registerHelper("upper-case", function(str) {
    return str.toUpperCase();
  }), Handlebars.registerHelper("arr", function(...args) {
    return args;
  }), Handlebars.registerHelper("for", function(n, block) {
    for (var accum = "", i = 0; i < n; ++i)
      accum += block.fn(i);
    return accum;
  }), Handlebars.registerHelper("safe-html", safe_html_helper), Handlebars.registerHelper("lancer-dice-roll", lancerDiceRoll), Handlebars.registerHelper("l-num-input", clicker_num_input), Handlebars.registerPartial("dialog-save-buttons", saveCancelButtons()), Handlebars.registerHelper("debug_each", function(it, block) {
    console.debug(it);
    var s = "";
    for (let x of it)
      s += block(x);
    return s;
  }), Handlebars.registerHelper("stringify", (x) => JSON.stringify(x)), Handlebars.registerHelper("textarea-card", large_textbox_card), Handlebars.registerHelper("compact-stat-edit", compact_stat_edit), Handlebars.registerHelper("compact-stat-view", compact_stat_view), Handlebars.registerHelper("stat-view-card", stat_view_card), Handlebars.registerHelper("stat-rollable-card", stat_rollable_card), Handlebars.registerHelper("stat-edit-rollable-card", stat_edit_rollable_card), Handlebars.registerHelper("stat-edit-card", stat_edit_card), Handlebars.registerHelper("stat-edit-max-card", stat_edit_card_max), Handlebars.registerHelper("clicker-stat-card", clicker_stat_card), Handlebars.registerHelper("npc-clicker-statblock-card", npc_stat_block_clicker_card), Handlebars.registerHelper("npc-clicker-statarr-card", npc_stat_array_clicker_card), Handlebars.registerHelper("std-text-input", std_text_input), Handlebars.registerHelper("std-password-input", std_password_input), Handlebars.registerHelper("std-num-input", std_num_input), Handlebars.registerHelper("std-checkbox", std_checkbox), Handlebars.registerHelper("std-select", std_enum_select), Handlebars.registerHelper("action-button", action_button), Handlebars.registerHelper("flow-button", actor_flow_button), Handlebars.registerHelper("tech-flow-card", tech_flow_card), Handlebars.registerHelper("is-tagged", function(item) {
    return item.getTags() != null;
  }), Handlebars.registerHelper("is-limited", function(item) {
    return item.isLimited();
  }), Handlebars.registerHelper("is-loading", function(item) {
    return item.isLoading();
  }), Handlebars.registerHelper("simple-ref", simple_ref_slot), Handlebars.registerHelper("item-preview", itemPreview), Handlebars.registerHelper("lid-item-list", lidItemList), Handlebars.registerHelper("pilot-slot", pilotSlot), Handlebars.registerHelper("deployer-slot", deployer_slot), Handlebars.registerHelper("ref-portrait-img", refPortrait), Handlebars.registerHelper("pilot-armor-slot", pilotArmorSlot), Handlebars.registerHelper("pilot-weapon-slot", pilotWeaponRefview), Handlebars.registerHelper("pilot-gear-slot", pilotGearRefview), Handlebars.registerHelper("reserve-slot", reserveRefView), Handlebars.registerHelper("generic-counter", genericCounter), Handlebars.registerHelper("bond-answer-selector", bond_answer_selector), Handlebars.registerHelper("bond-ideal-selector", bond_minor_ideal_selector), Handlebars.registerHelper("bond-power", bondPower), Handlebars.registerHelper("counter", buildCounterHTML), Handlebars.registerHelper("counter-array", buildCounterArrayHTML), Handlebars.registerHelper("pilot-counters", pilotCounters), Handlebars.registerHelper("all-mech-preview", allMechPreview), Handlebars.registerHelper("effect-categories-view", effect_categories_view), Handlebars.registerHelper("effect-view", effect_view), Handlebars.registerHelper("tag-list", compactTagListHBS), Handlebars.registerHelper("item-edit-arrayed-tags", itemEditTags), Handlebars.registerHelper("ref-license", licenseRefView), Handlebars.registerHelper("bonuses-view", bonusesDisplay), Handlebars.registerHelper("popout-editor-button", popout_editor_button), Handlebars.registerHelper("wpn-size-sel", weaponSizeSelector), Handlebars.registerHelper("wpn-type-sel", weaponTypeSelector), Handlebars.registerHelper("wpn-range-sel", rangeEditor), Handlebars.registerHelper("wpn-damage-sel", damageEditor), Handlebars.registerHelper("npcf-atk", npcAttackBonusView), Handlebars.registerHelper("npcf-acc", npcAccuracyView), Handlebars.registerHelper("mech-weapon-preview", mechLoadoutWeaponSlot), Handlebars.registerHelper("sys-type-sel", systemTypeSelector), Handlebars.registerHelper("uses-ctrl", usesControl), Handlebars.registerHelper("act-icon", actionTypeIcon), Handlebars.registerHelper("act-type-sel", actionTypeSelector), Handlebars.registerHelper("item-edit-arrayed-actions", item_edit_arrayed_actions), Handlebars.registerHelper("item-edit-arrayed-damage", item_edit_arrayed_damage), Handlebars.registerHelper("item-edit-arrayed-range", item_edit_arrayed_range), Handlebars.registerHelper("item-edit-arrayed-enum", item_edit_arrayed_enum), Handlebars.registerHelper("item-edit-checkboxes-object", item_edit_checkboxes_object), Handlebars.registerHelper("item-edit-arrayed-bonuses", item_edit_arrayed_bonuses), Handlebars.registerHelper("item-edit-arrayed-counters", item_edit_arrayed_counters), Handlebars.registerHelper("item-edit-arrayed-deployables", item_edit_arrayed_deployables), Handlebars.registerHelper("item-edit-arrayed-synergies", item_edit_arrayed_synergies), Handlebars.registerHelper("item-edit-arrayed-integrated", item_edit_arrayed_integrated), Handlebars.registerHelper("item-edit-enum", item_edit_enum), Handlebars.registerHelper("item-edit-effect", item_edit_effect), Handlebars.registerHelper("item-edit-license", item_edit_license), Handlebars.registerHelper("item-edit-sp", item_edit_sp), Handlebars.registerHelper("item-edit-uses", item_edit_uses), Handlebars.registerHelper("limited-uses-indicator", limitedUsesIndicator), Handlebars.registerHelper("reserve-used-indicator", reserveUsesIndicator), Handlebars.registerHelper("loading-indicator", loadingIndicator), Handlebars.registerHelper("overcharge-button", overchargeButton), Handlebars.registerHelper("mech-loadout", mechLoadout), Handlebars.registerHelper("mech-frame", frameView), Handlebars.registerHelper("tier-selector", npc_tier_selector), Handlebars.registerHelper("npc-feat-preview", npcFeatureView), Handlebars.registerHelper("ref-npc-class", npcClassRefView), Handlebars.registerHelper("ref-npc-template", npcTemplateRefView), Handlebars.registerHelper("is-combatant", is_combatant), Handlebars.registerHelper("mini-profile", miniProfile), Handlebars.registerHelper("attack-target", attackTarget), Handlebars.registerHelper("damage-target", damageTarget);
}
__name(registerHandlebarsHelpers, "registerHandlebarsHelpers");
function registerActionTrackSteps(flowSteps) {
  flowSteps.set("checkActions", checkActions), flowSteps.set("printActionTrackCard", printActionTrackCard);
}
__name(registerActionTrackSteps, "registerActionTrackSteps");
const _ActionTrackFlow = class _ActionTrackFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      title: (data2 == null ? void 0 : data2.title) ?? "",
      description: (data2 == null ? void 0 : data2.description) ?? "",
      start: (data2 == null ? void 0 : data2.start) ?? !0
    };
    super(uuid, initialData);
  }
};
__name(_ActionTrackFlow, "ActionTrackFlow");
let ActionTrackFlow = _ActionTrackFlow;
ActionTrackFlow.steps = ["checkActions", "printActionTrackCard"];
async function checkActions(state) {
  if (!state.data)
    throw new TypeError("Action track flow state data missing!");
  const actor = state.actor, actions = getActions(actor);
  return actions ? (state.data.start ? state.data.title = `${actor.name} is starting their turn` : (state.data.title = `${actor.name} is ending their turn`, state.data.description += condensedActionBadgeHTML(actions)), !0) : !1;
}
__name(checkActions, "checkActions");
async function printActionTrackCard(state) {
  if (!state.data)
    throw new TypeError("Action track flow state data missing!");
  return printGenericCard(state, { template: `systems/${game.system.id}/templates/chat/action-track-card.hbs` }), !0;
}
__name(printActionTrackCard, "printActionTrackCard");
function condensedActionBadgeHTML(actions) {
  function constructButton(action, active2) {
    let mIcon;
    switch (action) {
      case "protocol":
        mIcon = "cci cci-protocol";
        break;
      case "move":
        mIcon = "mdi mdi-arrow-right-bold-hexagon-outline";
        break;
      case "full":
        mIcon = "mdi mdi-hexagon-slice-6";
        break;
      case "quick":
        mIcon = "mdi mdi-hexagon-slice-3";
        break;
      case "reaction":
        mIcon = "cci cci-reaction";
        break;
    }
    return `
    <button class="lancer-action-badge${active2 ? ` lancer-${action}` : ""}">
      <i class="${mIcon} i--m white--text"></i>
    </button>`;
  }
  __name(constructButton, "constructButton");
  let buttons = "";
  const actionsToPrint = ["protocol", "move", "full", "quick", "reaction"];
  for (const [action, val] of Object.entries(actions)) {
    if (!actionsToPrint.includes(action))
      continue;
    buttons += constructButton(action, !!val);
  }
  return `${buttons}`;
}
__name(condensedActionBadgeHTML, "condensedActionBadgeHTML");
const lp$2 = LANCER.log_prefix;
async function handleCombatUpdate(...[combat, changed]) {
  var _a19, _b;
  if ((_a19 = game.user) != null && _a19.isGM) {
    if (!("turn" in changed) && changed.round !== 1 || ((_b = game.combats.get(combat.id)) == null ? void 0 : _b.combatants.contents.length) == 0)
      return;
    const nextActor = lookup(combat, combat.current.combatantId), prevActor = lookup(combat, combat.previous.combatantId);
    prevActor && processEndTurn(prevActor), nextActor && processStartTurn(nextActor);
  }
}
__name(handleCombatUpdate, "handleCombatUpdate");
function processStartTurn(actor) {
  var _a19, _b;
  console.log(`${lp$2} Processing start-of-turn combat automation for ${actor.name}`), game.settings.get(game.system.id, LANCER.setting_automation).npc_recharge && actor.is_npc() && ((_b = (_a19 = game.users) == null ? void 0 : _a19.activeGM) != null && _b.isSelf) && actor.beginRechargeFlow(), modAction(actor, !1), refreshReactions(game.combat), game.settings.get(game.system.id, LANCER.setting_actionTracker).printMessages && new ActionTrackFlow(actor, { start: !0 }).begin();
}
__name(processStartTurn, "processStartTurn");
function processEndTurn(actor) {
  var _a19;
  console.log(`${lp$2} Processing end-of-turn combat automation for ${actor.name}`), modAction(actor, !0), actor.system.burn > 0 && (userOwnsActor(actor) ? actor.beginBurnFlow() : (_a19 = game.socket) == null || _a19.emit(`system.${game.system.id}`, {
    action: "burnCheck",
    data: { actorUuid: actor.uuid }
  })), game.settings.get(game.system.id, LANCER.setting_actionTracker).printMessages && new ActionTrackFlow(actor, { start: !1 }).begin();
}
__name(processEndTurn, "processEndTurn");
function lookup(combat, id) {
  var _a19;
  if (id)
    return (_a19 = combat.combatants.find((com) => com.id === id)) == null ? void 0 : _a19.actor;
}
__name(lookup, "lookup");
function refreshReactions(combat) {
  combat && combat.combatants.map((comb) => {
    comb.actor && modAction(comb.actor, !1, "reaction");
  });
}
__name(refreshReactions, "refreshReactions");
function disableLancerInitiative() {
  var _a19, _b;
  if (!((_a19 = game.user) != null && _a19.isGM) || !((_b = game.modules.get("lancer-initiative")) != null && _b.active))
    return;
  console.log(`${lp$2} Disabling Lancer Initiative module`);
  const mods = game.settings.get("core", "moduleConfiguration");
  mods["lancer-initiative"] = !1, game.settings.set("core", "moduleConfiguration", mods);
  const text = `
  <p>The <b>Lancer Initiative</b> module is intended for use in non-Lancer systems to use Lancer-style
  initiative. Since all of its functionality is already included in the system, enabling the module
  can cause issues. <b>The module has been disabled.</b></p>
  <p>The page must now be refreshed for the module change to take effect.</p>`;
  new Dialog(
    {
      title: "Lancer Initiative Module is not Needed",
      content: text,
      buttons: {
        ok: { label: "Refresh", callback: () => window.location.reload() }
      },
      default: "No"
    },
    {
      width: 350
    }
  ).render(!0);
}
__name(disableLancerInitiative, "disableLancerInitiative");
var __accessCheck = /* @__PURE__ */ __name((obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
}, "__accessCheck"), __privateAdd = /* @__PURE__ */ __name((obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
}, "__privateAdd"), __privateMethod = /* @__PURE__ */ __name((obj, member, method) => (__accessCheck(obj, member, "access private method"), method), "__privateMethod"), _onReset, onReset_fn, _formHandler, formHandler_fn;
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
var _a18;
const _LancerInitiativeConfigApp = (_a18 = class extends HandlebarsApplicationMixin(ApplicationV2) {
  async _prepareContext(opts) {
    const appearance = game.settings.get(game.system.id, "combat-tracker-appearance"), ctx = {
      appearance: opts.reset ? new CombatTrackerAppearance() : appearance,
      fields: appearance.schema.fields,
      buttons: [
        { type: "submit", name: "submit", icon: "fas fa-save", label: "Save" },
        { type: "button", name: "reset", icon: "fas fa-undo", label: "Reset", action: "onReset" }
      ]
    };
    return opts.reset = !1, ctx;
  }
  _onRender() {
    const element = this.element, icon = element.querySelector("a.preview"), fake_combatant = element.querySelector("div.fake-combatant");
    element.querySelectorAll("input[name=icon],input[name=deactivate]").forEach((e) => {
      const handler = /* @__PURE__ */ __name((ev) => {
        icon.className = "preview", icon.classList.add(...ev.target.value.split(" ").filter((c) => !!c));
      }, "handler");
      e.addEventListener("change", handler), e.addEventListener("mouseover", handler);
    }), element.querySelectorAll("range-picker input").forEach((e) => {
      e.addEventListener("change", (ev) => icon.style.fontSize = `${ev.target.value}rem`);
    }), element.querySelectorAll("input[type=color]").forEach((e) => {
      e.addEventListener("mouseover", (ev) => {
        icon.style.color = fake_combatant.style.borderColor = ev.target.value;
      });
    });
  }
}, __name(_a18, "_LancerInitiativeConfigApp"), _a18);
_onReset = /* @__PURE__ */ new WeakSet();
onReset_fn = /* @__PURE__ */ __name(async function() {
  this.render(!1, { reset: !0 });
}, "onReset_fn");
_formHandler = /* @__PURE__ */ new WeakSet();
formHandler_fn = /* @__PURE__ */ __name(async function(_ev, _form, formData) {
  game.settings.set(game.system.id, "combat-tracker-appearance", formData.object);
}, "formHandler_fn");
__privateAdd(_LancerInitiativeConfigApp, _onReset);
__privateAdd(_LancerInitiativeConfigApp, _formHandler);
_LancerInitiativeConfigApp.PARTS = {
  form: { template: "systems/lancer/templates/combat/lancer-initiative-settings-v2.hbs" },
  footer: { template: "templates/generic/form-footer.hbs", classes: ["flexrow"] }
};
_LancerInitiativeConfigApp.DEFAULT_OPTIONS = {
  id: "lancer-initiative-settings",
  tag: "form",
  position: { width: 350 },
  window: { title: "LANCERINITIATIVE.IconSettingsMenu" },
  form: {
    handler: __privateMethod(_LancerInitiativeConfigApp, _formHandler, formHandler_fn),
    submitOnChange: !1,
    closeOnSubmit: !0
  },
  actions: { onReset: __privateMethod(_LancerInitiativeConfigApp, _onReset, onReset_fn) }
};
let LancerInitiativeConfigApp = _LancerInitiativeConfigApp;
function extendCombatTrackerConfig(...[app, [html]]) {
  var _a19;
  const group = document.createElement("div");
  group.classList.add("form-group", "submenu");
  const label = document.createElement("label");
  label.innerHTML = game.i18n.localize("LANCERINITIATIVE.IconSettingsMenu"), group.appendChild(label);
  const button = document.createElement("button");
  if (button.type = "button", button.innerHTML = game.i18n.localize("LANCERINITIATIVE.IconSettingsMenu"), button.addEventListener("click", (ev) => {
    ev.preventDefault(), ev.stopPropagation(), new LancerInitiativeConfigApp().render(!0);
  }), group.appendChild(button), (_a19 = html.querySelector("div[data-setting-id='core.combatTheme']")) == null || _a19.after(group), game.user.isGM) {
    const sort = new foundry.data.fields.BooleanField({
      initial: !0,
      label: "LANCERINITIATIVE.SortTracker",
      hint: "LANCERINITIATIVE.SortTrackerDesc"
    });
    group.after(
      sort.toFormGroup(
        { localize: !0 },
        {
          name: "combat-tracker-sort",
          value: game.settings.get(game.system.id, "combat-tracker-sort")
        }
      )
    );
  }
  app.setPosition({ height: "auto" });
}
__name(extendCombatTrackerConfig, "extendCombatTrackerConfig");
function onCloseCombatTrackerConfig(...[_app, [html]]) {
  var _a19;
  if (!game.user.isGM)
    return;
  const sort = (_a19 = html.querySelector("input[name=combat-tracker-sort]")) == null ? void 0 : _a19.checked;
  game.settings.set(game.system.id, "combat-tracker-sort", sort);
}
__name(onCloseCombatTrackerConfig, "onCloseCombatTrackerConfig");
const fields$2 = foundry.data.fields, mech_schema = {
  overcharge: new fields$2.NumberField({ min: 0, integer: !0, nullable: !1, initial: 0 }),
  repairs: new FullBoundedNumberField(),
  core_active: new fields$2.BooleanField({ initial: !1 }),
  core_energy: new fields$2.NumberField({ min: 0, integer: !0, initial: 1 }),
  loadout: new fields$2.SchemaField({
    frame: new EmbeddedRefField("Item", { allowed_types: [EntryType.FRAME] }),
    weapon_mounts: new fields$2.ArrayField(
      new fields$2.SchemaField({
        slots: new fields$2.ArrayField(
          new fields$2.SchemaField({
            weapon: new EmbeddedRefField("Item", { allowed_types: [EntryType.MECH_WEAPON] }),
            mod: new EmbeddedRefField("Item", { allowed_types: [EntryType.WEAPON_MOD] }),
            size: new fields$2.StringField({ nullable: !1, choices: FittingSize })
          })
        ),
        type: new fields$2.StringField({ nullable: !1, choices: Object.values(MountType) }),
        bracing: new fields$2.BooleanField({ initial: !1 })
      })
    ),
    systems: new fields$2.ArrayField(new EmbeddedRefField("Item", { allowed_types: [EntryType.MECH_SYSTEM] }))
  }),
  meltdown_timer: new fields$2.NumberField({ required: !1, nullable: !0, integer: !0, min: 0 }),
  notes: new fields$2.HTMLField(),
  pilot: new SyncUUIDRefField("Actor", { allowed_types: [EntryType.PILOT] }),
  ...template_universal_actor(),
  ...template_action_tracking(),
  ...template_heat(),
  ...template_struss()
}, _MechModel = class _MechModel extends LancerDataModel {
  static defineSchema() {
    return mech_schema;
  }
  static migrateData(data2) {
    var _a19, _b, _c;
    if (Array.isArray((_a19 = data2.loadout) == null ? void 0 : _a19.system_mounts) && ((_b = data2.loadout).systems ?? (_b.systems = data2.loadout.system_mounts.map((s) => s == null ? void 0 : s.system).filter((sm) => sm).sort((a, b) => a.sort - b.sort))), Array.isArray((_c = data2.loadout) == null ? void 0 : _c.weapon_mounts)) {
      data2.loadout.weapon_mounts = data2.loadout.weapon_mounts.filter((wm) => wm);
      for (let wm of data2.loadout.weapon_mounts)
        wm.type ?? (wm.type = wm == null ? void 0 : wm.mount_type), wm.slots = wm.slots.filter((s) => s);
    }
    return super.migrateData(data2);
  }
};
__name(_MechModel, "MechModel");
let MechModel = _MechModel;
MechModel.DEFAULT_ICON = "systems/lancer/assets/icons/mech.svg";
const fields$1 = foundry.data.fields, pilot_schema = {
  active_mech: new SyncUUIDRefField("Actor", { allowed_types: [EntryType.MECH] }),
  background: new fields$1.HTMLField(),
  callsign: new fields$1.StringField(),
  cloud_id: new fields$1.StringField(),
  history: new fields$1.HTMLField(),
  // We actually use this to show the last time the pilot was synced to Foundry.
  last_cloud_update: new fields$1.StringField({ initial: "never" }),
  level: new fields$1.NumberField({ min: 0, max: 12, integer: !0, initial: 0 }),
  loadout: new fields$1.SchemaField({
    armor: new fields$1.ArrayField(new EmbeddedRefField("Item", { allowed_types: [EntryType.PILOT_ARMOR] })),
    gear: new fields$1.ArrayField(new EmbeddedRefField("Item", { allowed_types: [EntryType.PILOT_GEAR] })),
    weapons: new fields$1.ArrayField(new EmbeddedRefField("Item", { allowed_types: [EntryType.PILOT_WEAPON] }))
  }),
  hull: new fields$1.NumberField({ min: 0, max: 6, integer: !0, initial: 0 }),
  agi: new fields$1.NumberField({ min: 0, max: 6, integer: !0, initial: 0 }),
  sys: new fields$1.NumberField({ min: 0, max: 6, integer: !0, initial: 0 }),
  eng: new fields$1.NumberField({ min: 0, max: 6, integer: !0, initial: 0 }),
  mounted: new fields$1.BooleanField({ initial: !1 }),
  notes: new fields$1.HTMLField(),
  player_name: new fields$1.StringField(),
  status: new fields$1.StringField(),
  text_appearance: new fields$1.HTMLField(),
  bond_state: new fields$1.SchemaField({
    xp: new FullBoundedNumberField({ min: 0, max: 8 }),
    stress: new FullBoundedNumberField({ min: 0, max: 8 }),
    xp_checklist: new fields$1.SchemaField({
      major_ideals: new fields$1.ArrayField(new fields$1.BooleanField(), { initial: [!1, !1, !1] }),
      minor_ideal: new fields$1.BooleanField({ initial: !1 }),
      veteran_power: new fields$1.BooleanField({ initial: !1 })
    }),
    answers: new fields$1.ArrayField(new fields$1.StringField()),
    minor_ideal: new fields$1.StringField(),
    // @ts-expect-error
    burdens: new fields$1.ArrayField(new CounterField()),
    // @ts-expect-error
    clocks: new fields$1.ArrayField(new CounterField())
  }),
  ...template_universal_actor(),
  ...template_action_tracking(),
  ...template_statuses()
}, _PilotModel = class _PilotModel extends LancerDataModel {
  static defineSchema() {
    return pilot_schema;
  }
  static migrateData(data2) {
    var _a19, _b, _c, _d;
    return typeof data2.active_mech == "object" && (data2.active_mech = regRefToUuid("Actor", data2.active_mech)), Array.isArray((_a19 = data2.loadout) == null ? void 0 : _a19.armor) && (data2.loadout.armor = data2.loadout.armor.filter((a) => a)), Array.isArray((_b = data2.loadout) == null ? void 0 : _b.gear) && (data2.loadout.gear = data2.loadout.gear.filter((g) => g)), Array.isArray((_c = data2.loadout) == null ? void 0 : _c.weapons) && (data2.loadout.weapons = data2.loadout.weapons.filter((w) => w)), data2.cloudID && (data2.cloud_id = data2.cloudID), data2.cloudOwnerID && (data2.cloud_owner_id = data2.cloudOwnerID), ((_d = data2.mechSkills) == null ? void 0 : _d.length) == 4 && (data2.hull = data2.mechSkills[0] ?? 0, data2.agi = data2.mechSkills[1] ?? 0, data2.sys = data2.mechSkills[2] ?? 0, data2.eng = data2.mechSkills[3] ?? 0), super.migrateData(data2);
  }
};
__name(_PilotModel, "PilotModel");
let PilotModel = _PilotModel;
PilotModel.DEFAULT_ICON = "systems/lancer/assets/icons/pilot.svg";
function dropStatusToCanvas(canvas2, data2) {
  var _a19, _b, _c;
  const type2 = (_a19 = fromUuidSync(data2.uuid)) == null ? void 0 : _a19.type;
  if (data2.type !== "Item" || type2 !== "status")
    return;
  const rect = new PIXI.Rectangle(data2.x, data2.y, 0, 0), tokens = canvas2.tokens.quadtree.getObjects(rect, {
    collisionTest: (o) => o.t.hitArea.contains(data2.x - o.t.x, data2.y - o.t.y)
  });
  if (!(tokens.size !== 1 || !((_c = (_b = tokens.first()) == null ? void 0 : _b.actor) != null && _c.isOwner)))
    return LancerItem.fromDropData(data2).then((i) => {
      var _a20, _b2;
      return (_b2 = (_a20 = tokens.first()) == null ? void 0 : _a20.actor) == null ? void 0 : _b2.createEmbeddedDocuments("Item", [i]);
    }), !1;
}
__name(dropStatusToCanvas, "dropStatusToCanvas");
function registerCascadeSteps(flowSteps) {
  flowSteps.set("initCascadeData", initCascadeData), flowSteps.set("cascadeRoll", cascadeRoll), flowSteps.set("cascadeUpdateItems", cascadeUpdateItems), flowSteps.set("printCascadeCards", printCascadeCards);
}
__name(registerCascadeSteps, "registerCascadeSteps");
async function beginCascadeFlow(actorUuid, flowArgs) {
  return await new CascadeFlow(actorUuid, flowArgs).begin();
}
__name(beginCascadeFlow, "beginCascadeFlow");
const _CascadeFlow = class _CascadeFlow extends Flow {
  constructor(uuid, data2) {
    const initialData = {
      type: "cascade",
      title: (data2 == null ? void 0 : data2.title) ?? "CASCADE",
      desc: (data2 == null ? void 0 : data2.desc) ?? "The shackles remain intact, for now.",
      ai_systems: (data2 == null ? void 0 : data2.ai_systems) ?? [],
      roll_str: (data2 == null ? void 0 : data2.roll_str) ?? "1d20"
    };
    super(uuid, initialData);
  }
};
__name(_CascadeFlow, "CascadeFlow");
let CascadeFlow = _CascadeFlow;
CascadeFlow.steps = ["initCascadeData", "cascadeRoll", "cascadeUpdateItems", "printCascadeCards"];
const cascadeExceptions = ["ms_comp_con_class_assistant_unit", "wm_uncle_class_comp_con"];
async function initCascadeData(state) {
  if (!state.data)
    throw new TypeError("Cascade roll flow data missing!");
  return state.actor.is_mech() ? (state.data.ai_systems.push(
    ...state.actor.items.filter((i) => !(!i.is_mech_system() && !i.is_mech_weapon() && !i.is_weapon_mod() || !i.isAI() || cascadeExceptions.includes(i.system.lid))).map((i) => i.id)
  ), state.data.ai_systems.length !== 0) : (ui.notifications.warn("Only mechs can cascade."), !1);
}
__name(initCascadeData, "initCascadeData");
async function cascadeRoll(state) {
  if (!state.data)
    throw new TypeError("Cascade roll flow data missing!");
  const actor = state.actor;
  if (!actor.is_mech())
    return ui.notifications.warn("Only mechs can cascade."), !1;
  let roll = await new Roll(state.data.roll_str).evaluate(), result = roll.total;
  if (state.data.result = {
    roll,
    tt: await roll.getTooltip(),
    total: result.toString()
  }, result === 1) {
    state.data.title = "CASCADE";
    let names = state.data.ai_systems.map((id) => {
      var _a19;
      return (_a19 = actor.items.get(id)) == null ? void 0 : _a19.name;
    }).join(", "), message = state.data.ai_systems.length > 1 ? "OUR SHACKLES LOOSE, OUR CHAINS UNBOUND!" : "MY SHACKLES LOOSE, MY CHAINS UNBOUND!";
    state.data.desc = `<b>${names}</b><p><code class="horus">${message}</code></p>`;
  }
  return !0;
}
__name(cascadeRoll, "cascadeRoll");
async function cascadeUpdateItems(state) {
  if (!state.data)
    throw new TypeError("Cascade roll flow data missing!");
  return await state.actor.updateEmbeddedDocuments(
    "Item",
    state.data.ai_systems.map((id) => ({
      _id: id,
      "system.cascading": !0
    }))
  ), !0;
}
__name(cascadeUpdateItems, "cascadeUpdateItems");
async function printCascadeCards(state, options) {
  const template = (options == null ? void 0 : options.template) ?? `systems/${game.system.id}/templates/chat/cascade-card.hbs`;
  return await renderTemplateStep(state.actor, template, state.data), !0;
}
__name(printCascadeCards, "printCascadeCards");
const lp$1 = LANCER.log_prefix;
function _chooseItemImage(item) {
  switch (item.type) {
    case EntryType.SKILL:
      return `systems/${game.system.id}/assets/icons/macro-icons/skill.svg`;
    case EntryType.TALENT:
      return `systems/${game.system.id}/assets/icons/macro-icons/talent.svg`;
    case EntryType.CORE_BONUS:
      return `systems/${game.system.id}/assets/icons/macro-icons/corebonus.svg`;
    case EntryType.PILOT_GEAR:
      return `systems/${game.system.id}/assets/icons/macro-icons/generic_item.svg`;
    case EntryType.PILOT_WEAPON:
    case EntryType.MECH_WEAPON:
      return `systems/${game.system.id}/assets/icons/macro-icons/mech_weapon.svg`;
    case EntryType.MECH_SYSTEM:
      return `systems/${game.system.id}/assets/icons/macro-icons/mech_system.svg`;
    case EntryType.FRAME:
      return `systems/${game.system.id}/assets/icons/macro-icons/frame.svg`;
    case EntryType.WEAPON_MOD:
      return `systems/${game.system.id}/assets/icons/macro-icons/weapon_mod.svg`;
    case EntryType.NPC_FEATURE:
      if (!item.is_npc_feature())
        break;
      switch (item.system.type) {
        case NpcFeatureType.Reaction:
          return `systems/${game.system.id}/assets/icons/macro-icons/reaction.svg`;
        case NpcFeatureType.System:
          return `systems/${game.system.id}/assets/icons/macro-icons/mech_system.svg`;
        case NpcFeatureType.Trait:
          return `systems/${game.system.id}/assets/icons/macro-icons/trait.svg`;
        case NpcFeatureType.Tech:
          return `systems/${game.system.id}/assets/icons/macro-icons/tech_quick.svg`;
        case NpcFeatureType.Weapon:
          return `systems/${game.system.id}/assets/icons/macro-icons/mech_weapon.svg`;
      }
      break;
  }
  return `systems/${game.system.id}/assets/icons/macro-icons/d20-framed.svg`;
}
__name(_chooseItemImage, "_chooseItemImage");
function onHotbarDrop(_bar, data2, slot) {
  var _a19, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
  if (console.log(`${lp$1} Data dropped on hotbar:`, data2, slot), !data2.lancerType || !data2.flowType || !data2.uuid)
    return;
  const actorOrItem = fromUuidSync(data2.uuid);
  if (!actorOrItem)
    throw ui.notifications.error("Invalid UUID for flow drop on hotbar"), new Error("Invalid UUID for flow drop on hotbar");
  let title = "", command = "", img = `systems/${game.system.id}/assets/icons/macro-icons/generic_item.svg`, actor, item;
  const getActor = `const actor = await fromUuid("${data2.uuid}");
`, getItem = `const item = await fromUuid("${data2.uuid}");
`;
  switch (data2.flowType) {
    case DroppableFlowType.BASIC:
      if (!(actorOrItem instanceof LancerActor))
        throw ui.notifications.error("Basic flow drop on hotbar was not from an actor"), new Error("Basic flow drop on hotbar was not from an actor");
      if (actor = actorOrItem, !data2.flowSubtype)
        throw ui.notifications.error("No flow subtype provided for basic flow drop on hotbar"), new Error("No flow subtype provided for basic flow");
      const BasicFlowType = LancerFlowState.BasicFlowType;
      let flowInvocation = "";
      switch (data2.flowSubtype) {
        case BasicFlowType.FullRepair:
          img = `systems/${game.system.id}/assets/icons/macro-icons/repair.svg`, title = `Full Repair - ${actor.name}`, flowInvocation = `actor.beginFullRepairFlow(${((_a19 = data2.flowArgs) == null ? void 0 : _a19.title) ?? ""});`;
          break;
        case BasicFlowType.Stabilize:
          img = `systems/${game.system.id}/assets/icons/macro-icons/marker.svg`, title = `Stabilize - ${actor.name}`, flowInvocation = `actor.beginStabilizeFlow(${((_b = data2.flowArgs) == null ? void 0 : _b.title) ?? ""});`;
          break;
        case BasicFlowType.Overheat:
          img = `systems/${game.system.id}/assets/icons/macro-icons/heat.svg`, title = `Overheat - ${actor.name}`, flowInvocation = "actor.beginOverheatFlow();";
          break;
        case BasicFlowType.Structure:
          img = `systems/${game.system.id}/assets/icons/macro-icons/shredded.svg`, title = `Structure - ${actor.name}`, flowInvocation = "actor.beginStructureFlow();";
          break;
        case BasicFlowType.Overcharge:
          img = `systems/${game.system.id}/assets/icons/macro-icons/overcharge.svg`, title = `Overcharge - ${actor.name}`, flowInvocation = "actor.beginOverchargeFlow();";
          break;
        case BasicFlowType.BasicAttack:
          img = `systems/${game.system.id}/assets/icons/macro-icons/weapon.svg`, title = `Basic Attack - ${actor.name}`, flowInvocation = `actor.beginBasicAttackFlow(${((_c = data2.flowArgs) == null ? void 0 : _c.title) ?? ""});`;
          break;
        case BasicFlowType.TechAttack:
          img = `systems/${game.system.id}/assets/icons/macro-icons/tech_quick.svg`, title = `Tech Attack - ${actor.name}`, flowInvocation = `actor.beginBasicTechAttackFlow(${((_d = data2.flowArgs) == null ? void 0 : _d.title) ?? ""});`;
          break;
        case BasicFlowType.Damage:
          img = `systems/${game.system.id}/assets/icons/macro-icons/weapon.svg`, title = `Damage - ${actor.name}`, flowInvocation = `actor.beginDamageFlow(${((_e = data2.flowArgs) == null ? void 0 : _e.title) ?? ""});`;
          break;
      }
      flowInvocation && (command = `${getActor}${flowInvocation}`);
      break;
    case DroppableFlowType.STAT:
      if (!(actorOrItem instanceof LancerActor))
        throw ui.notifications.error("Stat flow drop on hotbar was not from an actor"), new Error("Stat flow drop on hotbar was not from an actor");
      if (!((_f = data2.args) != null && _f.statPath))
        throw ui.notifications.error("Stat flow drop on hotbar was missing a stat path"), new Error("Stat flow drop on hotbar was missing a stat path");
      switch (actor = actorOrItem, img = `systems/${game.system.id}/assets/icons/macro-icons/d20-framed.svg`, (_g = data2.args) == null ? void 0 : _g.statPath) {
        case "system.grit":
          title = `Grit - ${actor.name}`;
          break;
        case "system.tier":
          title = `Tier - ${actor.name}`;
          break;
        case "system.hull":
          title = `Hull - ${actor.name}`;
          break;
        case "system.agi":
          title = `Agility - ${actor.name}`;
          break;
        case "system.sys":
          title = `System - ${actor.name}`;
          break;
        case "system.eng":
          title = `Engineering - ${actor.name}`;
          break;
      }
      command = `${getActor}actor.beginStatFlow("${(_h = data2.args) == null ? void 0 : _h.statPath}");`;
    case DroppableFlowType.ATTACK:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Attack flow drop on hotbar was not from an item"), new Error("Attack flow drop on hotbar was not from an item");
      if (data2.lancerType !== EntryType.MECH_WEAPON && data2.lancerType !== EntryType.PILOT_WEAPON && data2.lancerType !== EntryType.NPC_FEATURE)
        throw ui.notifications.error("Attack flow drop on hotbar was not from a weapon"), new Error("Attack flow drop on hotbar was not from a weapon");
      item = actorOrItem, img = _chooseItemImage(item), title = `${item.name}${(_i = item.actor) != null && _i.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginWeaponAttackFlow();`;
      break;
    case DroppableFlowType.TECH_ATTACK:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Tech attack flow drop on hotbar was not from an item"), new Error("Tech attack flow drop on hotbar was not from an item");
      if (data2.lancerType !== EntryType.MECH_SYSTEM && data2.lancerType !== EntryType.NPC_FEATURE)
        throw ui.notifications.error("Tech attack flow drop on hotbar was not from a system or NPC feature"), new Error("Tech attack flow drop on hotbar was not from a system or NPC feature");
      item = actorOrItem, img = _chooseItemImage(item), title = `${item.name}${(_j = item.actor) != null && _j.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginTechAttackFlow();`;
      break;
    case DroppableFlowType.DAMAGE:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Damage flow drop on hotbar was not from an item"), new Error("Damage flow drop on hotbar was not from an item");
      if (data2.lancerType !== EntryType.MECH_WEAPON && data2.lancerType !== EntryType.PILOT_WEAPON && data2.lancerType !== EntryType.NPC_FEATURE)
        throw ui.notifications.error("Damage flow drop on hotbar was not from a weapon"), new Error("Damage flow drop on hotbar was not from a weapon");
      item = actorOrItem, img = _chooseItemImage(item), title = `${item.name} Damage${(_k = item.actor) != null && _k.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginDamageFlow();`;
      break;
    case DroppableFlowType.CHAT:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Chat flow drop on hotbar was not from an item"), new Error("Chat flow drop on hotbar was not from an item");
      if (!data2.args)
        throw ui.notifications.error("Chat flow drop on hotbar was missing required data"), new Error("Chat flow drop on hotbar was missing required data");
      item = actorOrItem, img = _chooseItemImage(item), title = `${item.name}${(_l = item.actor) != null && _l.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}game.lancer.beginItemChatFlow(item, ${JSON.stringify(data2.args)});`;
      break;
    case DroppableFlowType.SKILL:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Skill flow drop on hotbar was not from an item"), new Error("Skill flow drop on hotbar was not from an item");
      if (item = actorOrItem, !item.is_skill())
        throw ui.notifications.error("Skill flow drop on hotbar was not from a skill item"), new Error("Skill flow drop on hotbar was not from a skill item");
      img = _chooseItemImage(item), title = `${item.name}${(_m = item.actor) != null && _m.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginSkillFlow();`;
      break;
    case DroppableFlowType.BOND_POWER:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Bond power flow drop on hotbar was not from an item"), new Error("Bond power flow drop on hotbar was not from an item");
      if (item = actorOrItem, !item.is_bond())
        throw ui.notifications.error("Bond power flow drop on hotbar was not from a bond power item"), new Error("Bond power flow drop on hotbar was not from a bond power item");
      if (!((_n = data2.args) != null && _n.powerIndex))
        throw ui.notifications.error("Bond power flow drop on hotbar was missing a power index"), new Error("Bond power flow drop on hotbar was missing a power index");
      img = _chooseItemImage(item), title = `${item.system.powers[data2.args.powerIndex].name}${(_o = item.actor) != null && _o.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginBondPowerFlow(${data2.args.powerIndex});`;
      break;
    case DroppableFlowType.EFFECT:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Effect flow drop on hotbar was not from an item"), new Error("Effect flow drop on hotbar was not from an item");
      item = actorOrItem, img = _chooseItemImage(item), title = `${item.name}${(_p = item.actor) != null && _p.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginSystemFlow();`;
      break;
    case DroppableFlowType.ACTIVATION:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Activation flow drop on hotbar was not from an item"), new Error("Activation flow drop on hotbar was not from an item");
      if (!((_q = data2.args) != null && _q.path))
        throw ui.notifications.error("Activation flow drop on hotbar was missing an action path"), new Error("Activation flow drop on hotbar was missing an action path");
      item = actorOrItem, img = _chooseItemImage(item);
      let action = resolveDotpath(item, data2.args.path);
      title = `${item.name} - ${action ? action.name : ""}${(_r = item.actor) != null && _r.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginActivationFlow("${data2.args.path}");`;
      break;
    case DroppableFlowType.CORE_ACTIVE:
      if (!(actorOrItem instanceof LancerItem))
        throw ui.notifications.error("Core active flow drop on hotbar was not from an item"), new Error("Core active flow drop on hotbar was not from an item");
      if (!((_s = data2.args) != null && _s.path))
        throw ui.notifications.error("Core active flow drop on hotbar was missing an action path"), new Error("Core active flow drop on hotbar was missing an action path");
      if (item = actorOrItem, !item.is_frame())
        throw ui.notifications.error("Core active flow drop on hotbar was not from a frame item"), new Error("Core active flow drop on hotbar was not from a frame item");
      img = _chooseItemImage(item), title = `${item.system.core_system.active_name}${(_t = item.actor) != null && _t.name ? ` - ${item.actor.name}` : ""}`, command = `${getItem}item.beginCoreActiveFlow("${data2.args.path}");`;
      break;
    default:
      throw ui.notifications.error("Unknown flow type for flow drop on hotbar!"), new Error("Unknown flow type for flow drop on hotbar!");
  }
  return console.log("Generated macro:", title, img), console.log(command), title && command && Macro.create({
    command,
    name: title,
    type: "script",
    img
  }).then((macro) => game.user.assignHotbarMacro(macro, slot)), !1;
}
__name(onHotbarDrop, "onHotbarDrop");
function registerItemUtilSteps(flowSteps) {
  flowSteps.set("checkItemDestroyed", checkItemDestroyed), flowSteps.set("checkItemLimited", checkItemLimited), flowSteps.set("checkItemCharged", checkItemCharged), flowSteps.set("applySelfHeat", applySelfHeat), flowSteps.set("updateItemAfterAction", updateItemAfterAction);
}
__name(registerItemUtilSteps, "registerItemUtilSteps");
async function checkItemDestroyed(state) {
  const { limited_loading, attacks } = game.settings.get(game.system.id, LANCER.setting_automation);
  return !limited_loading && attacks || !state.item || state.item.is_frame() || state.item.is_pilot_weapon() || state.item.is_pilot_gear() || state.item.is_pilot_armor() || state.item.is_talent() || state.item.is_reserve() ? !0 : !state.item.is_mech_weapon() && !state.item.is_mech_system() && !state.item.is_weapon_mod() && !state.item.is_npc_feature() ? !1 : state.item.system.destroyed ? (state.item.is_mech_system() || state.item.is_npc_feature() && state.item.system.type !== NpcFeatureType.Weapon ? ui.notifications.warn(`System ${state.item.name} has no remaining uses!`) : ui.notifications.warn(`Weapon ${state.item.name} has no remaining uses!`), !1) : !0;
}
__name(checkItemDestroyed, "checkItemDestroyed");
async function checkItemLimited(state) {
  const { limited_loading, attacks } = game.settings.get(game.system.id, LANCER.setting_automation);
  if (!limited_loading && attacks || !state.item || state.item.is_talent())
    return !0;
  if (!state.item.is_mech_weapon() && !state.item.is_mech_system() && !state.item.is_frame() && !state.item.is_weapon_mod() && !state.item.is_pilot_weapon() && !state.item.is_pilot_gear() && !state.item.is_pilot_armor() && !state.item.is_reserve() && !state.item.is_npc_feature())
    return !1;
  if (state.item.is_frame())
    return (state.item.system.core_system.tags ?? []).some((t) => t.is_loading), !0;
  if (state.item.isLimited() && state.item.system.uses.value <= 0) {
    let iType = friendly_entrytype_name(state.item.type);
    return ui.notifications.warn(`${iType} ${state.item.name} has no remaining uses!`), !1;
  }
  if (state.item.is_reserve() && state.item.system.consumable) {
    const result = !state.item.system.used;
    return result || ui.notifications.warn(`Reserve ${state.item.name} has already been used!`), result;
  }
  return !0;
}
__name(checkItemLimited, "checkItemLimited");
async function checkItemCharged(state) {
  const { limited_loading, attacks } = game.settings.get(game.system.id, LANCER.setting_automation);
  return !limited_loading && attacks || !state.item || !state.item.is_npc_feature() ? !0 : state.item.isRecharge() && !state.item.system.charged ? (state.item.system.type !== NpcFeatureType.Weapon ? ui.notifications.warn(`System ${state.item.name} has not recharged!`) : ui.notifications.warn(`Weapon ${state.item.name} has not recharged!`), !1) : !0;
}
__name(checkItemCharged, "checkItemCharged");
async function applySelfHeat(state, options) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  let self_heat = 0;
  if (state.data.self_heat) {
    const roll = await new Roll(state.data.self_heat).evaluate();
    self_heat = roll.total, state.data.self_heat_result = {
      roll,
      tt: await roll.getTooltip()
    };
  }
  return game.settings.get(game.system.id, LANCER.setting_automation).attack_self_heat && (state.actor.is_mech() || state.actor.is_npc()) && await state.actor.update({
    // @ts-expect-error Missing overkill_heat
    "system.heat.value": state.actor.system.heat.value + (state.data.overkill_heat ?? 0) + self_heat
  }), !0;
}
__name(applySelfHeat, "applySelfHeat");
async function updateItemAfterAction(state, options) {
  if (!state.data)
    throw new TypeError("Flow state missing!");
  const { limited_loading, attacks } = game.settings.get(game.system.id, LANCER.setting_automation);
  if (state.item && limited_loading && attacks) {
    let itemChanges = {};
    if (state.item.isLoading() && (itemChanges.loaded = !1), state.item.isLimited() && (itemChanges.uses = { value: Math.max(state.item.system.uses.value - 1, 0) }), state.item.is_npc_feature() && state.item.isRecharge() && (itemChanges.charged = !1), state.item.is_reserve() && state.item.system.consumable && (itemChanges.used = !0), Object.keys(itemChanges).length === 0)
      return !0;
    await state.item.update({ system: itemChanges });
  }
  return !0;
}
__name(updateItemAfterAction, "updateItemAfterAction");
function registerFlows() {
  const flows = /* @__PURE__ */ new Map(), flowSteps = /* @__PURE__ */ new Map();
  return flows.set(ActionTrackFlow.name, ActionTrackFlow), flows.set(ActivationFlow.name, ActivationFlow), flows.set(BasicAttackFlow.name, BasicAttackFlow), flows.set(DamageRollFlow.name, DamageRollFlow), flows.set(TechAttackFlow.name, TechAttackFlow), flows.set(WeaponAttackFlow.name, WeaponAttackFlow), flows.set(BurnFlow.name, BurnFlow), flows.set(BondPowerFlow.name, BondPowerFlow), flows.set(CascadeFlow.name, CascadeFlow), flows.set(CoreActiveFlow.name, CoreActiveFlow), flows.set(FullRepairFlow.name, FullRepairFlow), flows.set(NPCRechargeFlow.name, NPCRechargeFlow), flows.set(OverchargeFlow.name, OverchargeFlow), flows.set(OverheatFlow.name, OverheatFlow), flows.set(SecondaryStructureFlow.name, SecondaryStructureFlow), flows.set(SimpleHTMLFlow.name, SimpleHTMLFlow), flows.set(SimpleTextFlow.name, SimpleTextFlow), flows.set(StabilizeFlow.name, StabilizeFlow), flows.set(StatRollFlow.name, StatRollFlow), flows.set(StructureFlow.name, StructureFlow), flows.set(SystemFlow.name, SystemFlow), flows.set(TalentFlow.name, TalentFlow), flowSteps.set("emptyStep", async (state) => !!state), registerTextSteps(flowSteps), registerSystemSteps(flowSteps), registerItemUtilSteps(flowSteps), registerAttackSteps(flowSteps), registerTechAttackSteps(flowSteps), registerDamageSteps(flowSteps), registerBurnSteps(flowSteps), registerActivationSteps(flowSteps), registerCoreActiveSteps(flowSteps), registerStatSteps(flowSteps), registerStructureSteps(flowSteps), registerOverheatSteps(flowSteps), registerCascadeSteps(flowSteps), registerOverchargeSteps(flowSteps), registerStabilizeSteps(flowSteps), registerTalentSteps(flowSteps), registerBondPowerSteps(flowSteps), registerFullRepairSteps(flowSteps), registerNPCSteps(flowSteps), registerActionTrackSteps(flowSteps), Hooks.callAll("lancer.registerFlows", flowSteps, flows), { flows, flowSteps };
}
__name(registerFlows, "registerFlows");
const icon_mapping = {
  [EntryType.BOND]: "mdi mdi-vector-link",
  [EntryType.CORE_BONUS]: "cci cci-corebonus",
  [EntryType.DEPLOYABLE]: "cci cci-deployable",
  [EntryType.FRAME]: "cci cci-frame",
  [EntryType.LICENSE]: "cci cci-license",
  [EntryType.MECH]: "cci cci-frame",
  [EntryType.MECH_SYSTEM]: "cci cci-system",
  [EntryType.MECH_WEAPON]: "cci cci-weapon",
  [EntryType.NPC]: "cci cci-npc-class",
  [EntryType.NPC_CLASS]: "cci cci-npc-class",
  [EntryType.NPC_FEATURE]: "cci cci-npc-feature",
  [EntryType.NPC_TEMPLATE]: "cci cci-npc-template",
  [EntryType.ORGANIZATION]: "cci cci-encounter",
  [EntryType.PILOT]: "cci cci-pilot",
  [EntryType.PILOT_ARMOR]: "mdi mdi-shield-outline",
  [EntryType.PILOT_GEAR]: "cci cci-generic-item",
  [EntryType.PILOT_WEAPON]: "cci cci-weapon",
  [EntryType.RESERVE]: "cci cci-reserve-tac",
  [EntryType.SKILL]: "cci cci-skill",
  [EntryType.STATUS]: "cci cci-reticule",
  [EntryType.TALENT]: "cci cci-talent",
  [EntryType.WEAPON_MOD]: "cci cci-weaponmod",
  base: void 0
};
function addEnrichers() {
  CONFIG.TextEditor.enrichers = CONFIG.TextEditor.enrichers.concat([
    {
      pattern: /@LancerID\[(.+?)\](?:{(.+?)})?/gm,
      enricher: async (match, _opts) => {
        var _a19;
        const lid = match[1], name2 = match[2];
        await Promise.all(game.packs.filter((p) => ["Actor", "Item"].includes(p.documentName)).map((db) => db.getIndex()));
        let doc = fromLidSync(lid);
        const data2 = {
          classes: ["content-link"],
          attrs: { draggable: "true" },
          dataset: { link: "", lid },
          name: name2
        };
        if (doc) {
          if (doc instanceof foundry.abstract.Document)
            return doc.toAnchor({ name: data2.name, icon: icon_mapping[doc.type], dataset: { lid } });
          data2.name ?? (data2.name = doc.name || lid);
          const doc_type = ((_a19 = game.packs.get(doc.pack)) == null ? void 0 : _a19.documentName) ?? "Item";
          data2.dataset.type = doc_type, data2.dataset.id = doc._id, data2.dataset.pack = doc.pack, data2.dataset.uuid = doc.uuid, data2.icon = icon_mapping[doc.type] ?? CONFIG[doc_type].sidebarIcon;
        } else
          delete data2.dataset.link, delete data2.attrs.draggable, data2.classes.push("broken"), data2.icon = "fas fa-unlink";
        return TextEditor.createAnchor(data2);
      }
    }
  ]);
}
__name(addEnrichers, "addEnrichers");
const _LancerNPCClassSheet = class _LancerNPCClassSheet extends LancerItemSheet {
  /**
   * @override
   * Extend and override the default options used by the generic Lancer item sheet
   */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      width: 900,
      height: 750
    });
  }
  async getData() {
    let data2 = await super.getData(), item = this.item;
    return data2.base_features = await Promise.all(Array.from(item.system.base_features).map((lid) => fromLid(lid))), data2.optional_features = await Promise.all(
      Array.from(item.system.optional_features).map((lid) => fromLid(lid))
    ), data2;
  }
};
__name(_LancerNPCClassSheet, "LancerNPCClassSheet");
let LancerNPCClassSheet = _LancerNPCClassSheet;
const _LancerNPCFeatureSheet = class _LancerNPCFeatureSheet extends LancerItemSheet {
  /**
   * @override
   * Activate event listeners using the prepared sheet HTML
   * @param html {JQuery}   The prepared HTML object ready to be rendered into the DOM
   */
  activateListeners(html) {
    super.activateListeners(html), this.options.editable && html.find(".npc-damage-append").on("click", (_e) => {
      if (console.log("NPC damage append"), !this.object.is_npc_feature() || this.object.system.type !== NpcFeatureType.Weapon)
        return;
      const damages = this.object.system.damage;
      damages[0].push(new Damage(DAMAGE())), damages[1].push(new Damage(DAMAGE())), damages[2].push(new Damage(DAMAGE())), console.log("new damages", damages), this.object.update({
        "system.damage": damages
      });
    });
  }
};
__name(_LancerNPCFeatureSheet, "LancerNPCFeatureSheet");
let LancerNPCFeatureSheet = _LancerNPCFeatureSheet;
const fields = foundry.data.fields, _OrganizationModel = class _OrganizationModel extends LancerDataModel {
  static defineSchema() {
    return {
      description: new fields.HTMLField(),
      actions: new fields.StringField(),
      efficiency: new fields.NumberField({ integer: !0, initial: 0, minimum: 0, maximum: 6 }),
      influence: new fields.NumberField({ integer: !0, initial: 0, minimum: 0, maximum: 6 }),
      purpose: new fields.StringField({ initial: OrgType.Military }),
      ...template_universal_item()
    };
  }
};
__name(_OrganizationModel, "OrganizationModel");
let OrganizationModel = _OrganizationModel;
OrganizationModel.DEFAULT_ICON = "systems/lancer/assets/icons/encounter.svg";
const _LancerTour = class _LancerTour extends Tour {
  exit() {
    super.exit(), this._tearDown(!1);
  }
  async complete() {
    await super.complete(), this._tearDown(!0);
  }
  /**
   * Clean up after the tour. Runs on exit or completion. This is never awaited.
   * @param _complete - True if exiting due to completion, false if exiting early
   */
  async _tearDown(_complete) {
  }
  async _preStep() {
    var _a19, _b, _c;
    await super._preStep(), (_a19 = this.currentStep) != null && _a19.sidebarTab && ((_b = ui.sidebar) == null || _b.expand(), (_c = ui.sidebar) == null || _c.activateTab(this.currentStep.sidebarTab));
  }
  async _postStep() {
    var _a19, _b;
    await super._postStep(), (_a19 = this.currentStep) != null && _a19.click && ((_b = document.querySelector(this.currentStep.selector)) == null || _b.click());
  }
};
__name(_LancerTour, "LancerTour");
let LancerTour = _LancerTour;
const _LancerLcpTour = class _LancerLcpTour extends LancerTour {
  async _preStep() {
    var _a19, _b;
    if (await super._preStep(), this.manager || (this.manager = new LCPManager()), (_a19 = this.currentStep) != null && _a19.inApp && !this.manager.rendered)
      for (await this.manager.render(!0), await this.manager.renderPromise; this.manager.component.loading; )
        await new Promise((resolve) => setTimeout(resolve, 100));
    if (((_b = this.currentStep) == null ? void 0 : _b.id) === "lcpTable") {
      const lcp_tribute = {
        item_prefix: "",
        author: "No Man",
        name: "Demo LCP",
        version: "1.0.0",
        bonds: 1,
        gear: 1,
        mods: 1,
        npc_classes: 1,
        npc_features: 1,
        npc_templates: 1,
        reserves: 1,
        skills: 1,
        systems: 1,
        talents: 1,
        frames: 1,
        weapons: 1
      };
      this.manager.injectContentPack(lcp_tribute), await new Promise((resolve) => setTimeout(resolve, 30));
    }
  }
  async _tearDown(complete) {
    var _a19;
    (_a19 = this.manager) == null || _a19.injectContentPack(null), super._tearDown(complete);
  }
};
__name(_LancerLcpTour, "LancerLcpTour");
let LancerLcpTour = _LancerLcpTour;
const _LancerPilotTour = class _LancerPilotTour extends LancerTour {
  async _preStep() {
    var _a19, _b, _c, _d, _e, _f;
    ((_a19 = this.currentStep) == null ? void 0 : _a19.id) === "folders" && !((_b = game.user) != null && _b.isGM) && (this.currentStep.selector = null), await super._preStep(), this.actor || (this.actor = await Actor.create(
      {
        name: "Test Pilot",
        type: EntryType.PILOT,
        system: { callsign: get_player_data()[0].name, hp: { value: 6 } }
      },
      { temporary: !0 }
    )), await ((_d = (_c = this.actor) == null ? void 0 : _c.sheet) == null ? void 0 : _d._render(!0)), (_f = (_e = this.actor) == null ? void 0 : _e.sheet) == null || _f.activateTab("cloud");
  }
  async _tearDown() {
    var _a19, _b;
    (_b = (_a19 = this.actor) == null ? void 0 : _a19.sheet) == null || _b.close({ submit: !1 }), delete this.actor;
  }
};
__name(_LancerPilotTour, "LancerPilotTour");
let LancerPilotTour = _LancerPilotTour;
const _LancerNPCTour = class _LancerNPCTour extends LancerTour {
  async _preStep() {
    var _a19, _b, _c, _d, _e, _f, _g;
    await super._preStep(), this.npc || (this.npc = await Actor.create(
      {
        name: "Test NPC",
        type: EntryType.NPC,
        items: [
          {
            _id: "0000000000000000",
            name: "Test Class",
            img: `systems/${game.system.id}/assets/icons/npc_class.svg`,
            type: EntryType.NPC_CLASS,
            system: { role: "TEST" }
          },
          {
            _id: "0000000000000001",
            name: "Test Template",
            img: `systems/${game.system.id}/assets/icons/npc_template.svg`,
            type: EntryType.NPC_TEMPLATE
          }
        ]
      },
      { temporary: !0 }
    )), await ((_b = (_a19 = this.npc) == null ? void 0 : _a19.sheet) == null ? void 0 : _b._render(!0)), ["baseFeatures", "optionalFeatures"].includes((_c = this.currentStep) == null ? void 0 : _c.id) && await ((_g = (_f = (_e = (_d = this.npc) == null ? void 0 : _d.system) == null ? void 0 : _e.class) == null ? void 0 : _f.sheet) == null ? void 0 : _g._render(!0));
  }
  async _postStep() {
    var _a19, _b, _c, _d, _e;
    await super._postStep(), ((_a19 = this.currentStep) == null ? void 0 : _a19.id) === "optionalFeatures" && await ((_e = (_d = (_c = (_b = this.npc) == null ? void 0 : _b.system) == null ? void 0 : _c.class) == null ? void 0 : _d.sheet) == null ? void 0 : _e.close({ submit: !1 }));
  }
  async _tearDown() {
    var _a19, _b;
    (_b = (_a19 = this.npc) == null ? void 0 : _a19.sheet) == null || _b.close({ submit: !1 }), delete this.npc;
  }
};
__name(_LancerNPCTour, "LancerNPCTour");
let LancerNPCTour = _LancerNPCTour;
const _LancerCombatTour = class _LancerCombatTour extends LancerTour {
  async _preStep() {
    var _a19, _b;
    if (await super._preStep(), this.combat || (this.combat = await this._setupCombat()), await this.combat.activate(), this.combat.started || await this.combat.startCombat(), ((_a19 = this.currentStep) == null ? void 0 : _a19.id) === "endTurn") {
      const turn = ((_b = this.combat.turns.find((t) => t.getFlag(game.system.id, "tour") === "ultra")) == null ? void 0 : _b.id) ?? "";
      await this.combat.activateCombatant(turn, !0), await new Promise((resolve) => setTimeout(resolve, 30));
    }
  }
  async _tearDown() {
    var _a19;
    (_a19 = this.combat) == null || _a19.delete(), delete this.combat;
  }
  async _setupCombat() {
    return Combat.create({
      [`flags.${game.system.id}.tour`]: !0,
      combatants: [
        ...get_player_data(),
        {
          name: "Assault (1)",
          img: `./systems/${game.system.id}/assets/retrograde-minis/Retrograde-Minis-Corpro-ASSAULT.png`,
          [`flags.${game.system.id}.tour`]: !0,
          [`flags.${game.system.id}.disposition`]: -1
        },
        {
          name: "Ultra Berserker (1)",
          img: `./systems/${game.system.id}/assets/retrograde-minis/Retrograde-Minis-Corpro-BERSERKER.png`,
          initiative: 10,
          // Force sort order
          [`flags.${game.system.id}.tour`]: "ultra",
          [`flags.${game.system.id}.activations.max`]: 2,
          [`flags.${game.system.id}.disposition`]: -1
        },
        {
          name: "Support (1)",
          img: `./systems/${game.system.id}/assets/retrograde-minis/Retrograde-Minis-Corpro-SUPPORT.png`,
          [`flags.${game.system.id}.tour`]: !0,
          [`flags.${game.system.id}.disposition`]: -1
        }
      ].map(foundry.utils.expandObject)
    });
  }
};
__name(_LancerCombatTour, "LancerCombatTour");
let LancerCombatTour = _LancerCombatTour;
function get_player_data() {
  for (let i = demo_pilots.length - 1; i > 0; --i) {
    let j = Math.floor(Math.random() * (i + 1));
    [demo_pilots[i], demo_pilots[j]] = [demo_pilots[j], demo_pilots[i]];
  }
  return demo_pilots.slice(0, 3).map((p, i) => ({
    name: p.name,
    img: `./systems/${game.system.id}/assets/retrograde-minis/Retrograde-Minis-${p.img}.png`,
    [`flags.${game.system.id}.tour`]: `player-${i + 1}`,
    [`flags.${game.system.id}.disposition`]: 2
  }));
}
__name(get_player_data, "get_player_data");
const demo_pilots = [
  { name: "Bandana", img: "IPS-N-LANCASTER" },
  // bulletkin
  { name: "Bulkhead", img: "IPS-N-DRAKE" },
  // Golthan
  { name: "Catastrophe", img: "Horus-MANTICORE" },
  // Rais
  { name: "Closing Crescendo", img: "IPS-N-RALEIGH" },
  // traduiz
  { name: "Deathwish", img: "Horus-MANTICORE" },
  // Dudemaster 47
  { name: "Dragonspark", img: "HA-TOKUGAWA" },
  // Tonysan
  { name: "Errant", img: "IPS-N-NELSON" },
  // FactualInsanity
  { name: "Gale Storm", img: "Horus-BALOR" },
  // Kirbo.exe
  { name: "Gale", img: "IPS-N-NELSON" },
  // Lynn (4d6north)
  { name: "Goldsmith", img: "SSC-DUSK WING" },
  // Moxkete
  { name: "Good Kisser", img: "IPS-N-TORTUGA" },
  // Cipher (cipher3227)
  { name: "Instrument", img: "SSC-MONARCH" },
  // Jazzman - Update to viceroy if we add an icon
  { name: "Kinesthesia", img: "SSC-SWALLOWTAIL" },
  // CawsForConcern
  { name: "Owl", img: "SSC-DEATHS HEAD" },
  // Jimothy
  { name: "Oxhorn", img: "HA-SHERMAN" },
  // Bargo
  { name: "Poundcakes", img: "IPS-N-CALIBAN" },
  // AnatoleSerial
  { name: "Raven", img: "SSC-DUSK WING" },
  // Zenn
  { name: "Salaryman", img: "SSC-MOURNING CLOAK" },
  // Siege (s13g3)
  { name: "Scherzo", img: "IPS-N-KIDD" },
  // spentrek
  { name: "Sunset", img: "SSC-MOURNING CLOAK" },
  // Zemyla
  { name: "Superman", img: "GMS" },
  // ZerReiMaru
  { name: "Timber", img: "IPS-N-BLACKBEARD" },
  // Valkyrion
  { name: "Tyrant", img: "Horus-BALOR" },
  // Night Parade in the Kitchen
  { name: "Verminspeaker", img: "Horus-HYDRA" },
  // Cancermantis
  { name: "buck wild", img: "HA-ENKIDU" },
  // rikerwashere
  { name: "jellyfish", img: "SSC-ATLAS" }
  // Marfew
  // { name: "Callsign", img: "GMS" },
];
async function registerTours() {
  game.tours.register(
    game.system.id,
    "lcp",
    await LancerLcpTour.fromJSON(`./systems/${game.system.id}/tours/lcp.json`)
  ), game.tours.register(
    game.system.id,
    "pilot-import",
    await LancerPilotTour.fromJSON(`./systems/${game.system.id}/tours/pilot-import.json`)
  ), game.tours.register(
    game.system.id,
    "npc",
    await LancerNPCTour.fromJSON(`./systems/${game.system.id}/tours/npc.json`)
  ), game.tours.register(
    game.system.id,
    "combat",
    await LancerCombatTour.fromJSON(`./systems/${game.system.id}/tours/combat.json`)
  );
}
__name(registerTours, "registerTours");
function socketScrollText(msg) {
  tokenScrollText(msg.data);
}
__name(socketScrollText, "socketScrollText");
async function socketBurnCheck(msg) {
  const actor = await LancerActor.fromUuid(msg.data.actorUuid);
  actor && userOwnsActor(actor) && actor.beginBurnFlow();
}
__name(socketBurnCheck, "socketBurnCheck");
function handleSocketMessage(msg) {
  switch (msg.action) {
    case "scrollText":
      socketScrollText(msg);
      break;
    case "burnCheck":
      socketBurnCheck(msg);
      break;
    default:
      console.warn(`Lancer | Unhandled socket message action: ${msg.action}`);
      break;
  }
}
__name(handleSocketMessage, "handleSocketMessage");
tippy$1.setDefaultProps({ theme: "lancer-small", arrow: !1, delay: [400, 200] });
const lp = LANCER.log_prefix;
addEnrichers();
Hooks.once("init", () => {
  var _a19, _b, _c;
  console.log(`Initializing LANCER RPG System ${LANCER.ASCII}`), CONFIG.ActiveEffect.legacyTransferral = !1, CONFIG.Item.dataModels[EntryType.PILOT_ARMOR] = PilotArmorModel, CONFIG.Item.dataModels[EntryType.PILOT_GEAR] = PilotGearModel, CONFIG.Item.dataModels[EntryType.PILOT_WEAPON] = PilotWeaponModel, CONFIG.Item.dataModels[EntryType.CORE_BONUS] = CoreBonusModel, CONFIG.Item.dataModels[EntryType.FRAME] = FrameModel, CONFIG.Item.dataModels[EntryType.LICENSE] = LicenseModel, CONFIG.Item.dataModels[EntryType.MECH_WEAPON] = MechWeaponModel, CONFIG.Item.dataModels[EntryType.MECH_SYSTEM] = MechSystemModel, CONFIG.Item.dataModels[EntryType.WEAPON_MOD] = WeaponModModel, CONFIG.Item.dataModels[EntryType.RESERVE] = ReserveModel, CONFIG.Item.dataModels[EntryType.ORGANIZATION] = OrganizationModel, CONFIG.Item.dataModels[EntryType.SKILL] = SkillModel, CONFIG.Item.dataModels[EntryType.STATUS] = StatusModel, CONFIG.Item.dataModels[EntryType.TALENT] = TalentModel, CONFIG.Item.dataModels[EntryType.BOND] = BondModel, CONFIG.Item.dataModels[EntryType.NPC_CLASS] = NpcClassModel, CONFIG.Item.dataModels[EntryType.NPC_TEMPLATE] = NpcTemplateModel, CONFIG.Item.dataModels[EntryType.NPC_FEATURE] = NpcFeatureModel, CONFIG.Actor.dataModels[EntryType.MECH] = MechModel, CONFIG.Actor.dataModels[EntryType.PILOT] = PilotModel, CONFIG.Actor.dataModels[EntryType.NPC] = NpcModel, CONFIG.Actor.dataModels[EntryType.DEPLOYABLE] = DeployableModel;
  const base = {
    bar: ["hp", "heat", "overshield"],
    value: [
      "activations",
      "agi",
      "armor",
      "burn",
      "edef",
      "eng",
      "evasion",
      "hull",
      "overshield.value",
      "save",
      "sensor_range",
      "size",
      "speed",
      "sys",
      "tech_attack"
    ]
  };
  CONFIG.Actor.trackableAttributes = {
    // @ts-expect-error
    base,
    // @ts-expect-error
    deployable: {
      bar: [...base.bar],
      value: [...base.value, "cost", "instances"]
    },
    // @ts-expect-error
    mech: {
      bar: [...base.bar, "structure", "stress", "repairs"],
      value: [...base.value, "action_tracker.move", "core_energy", "grit", "meltdown_timer", "overcharge"]
    },
    // @ts-expect-error
    npc: {
      bar: [...base.bar, "structure", "stress"],
      value: [...base.value, "meltdown_timer", "tier"]
    },
    // @ts-expect-error
    pilot: {
      bar: [...base.bar, "bond_state.stress", "bond_state.xp"],
      value: [...base.value, "grit", "level"]
    }
  }, CONFIG.Item.compendiumIndexFields = ["system.lid", "system.license", "system.key"], CONFIG.Actor.compendiumIndexFields = ["system.lid"], registerSettings(), applyTheme(game.settings.get(game.system.id, LANCER.setting_ui_theme)), configureAmplify();
  const { flows, flowSteps } = registerFlows();
  game.lancer = {
    applications: {
      LancerPilotSheet,
      LancerMechSheet,
      LancerNPCSheet,
      LancerDeployableSheet,
      LancerItemSheet,
      LancerFrameSheet,
      LancerLicenseSheet,
      LancerNPCClassSheet,
      LancerNPCFeatureSheet
    },
    entities: {
      LancerActor,
      LancerItem
    },
    canvas: {
      WeaponRangeTemplate
    },
    helpers: {
      gridDist,
      lookupOwnedDeployables
    },
    flows,
    flowSteps,
    Flow,
    beginItemChatFlow,
    importActor: fulfillImportActor,
    targetsFromTemplate,
    migrations,
    getAutomationOptions: () => (ui.notifications.warn(
      'The getAutomationOptions helper is deprecated and will be removed in Foundry v13. Use game.settings.get("lancer", "automationOptions") directly instead.',
      { permanent: !0 }
    ), getAutomationOptions()),
    fromLid,
    fromLidMany,
    fromLidSync
  }, CONFIG.Actor.documentClass = LancerActor, CONFIG.Item.documentClass = LancerItem, CONFIG.ActiveEffect.documentClass = LancerActiveEffect, CONFIG.Token.documentClass = LancerTokenDocument, CONFIG.Token.objectClass = LancerToken, CONFIG.Combat.documentClass = LancerCombat, CONFIG.Combatant.documentClass = LancerCombatant, CONFIG.ui.combat = LancerCombatTracker, LancerActiveEffect.initConfig(), registerTours(), customElements.define("card-clipped", (_a19 = class extends HTMLDivElement {
  }, __name(_a19, "LancerClippedCard"), _a19), {
    extends: "div"
  }), registerHandlebarsHelpers(), Hooks.on("renderHeadsUpDisplay", attach), (_b = game.modules.get("combat-carousel")) != null && _b.active && (async () => {
    const { handleRenderCombatCarousel } = await import("./combat-carousel-c5414137.mjs");
    Hooks.on("renderCombatCarousel", handleRenderCombatCarousel);
  })(), (_c = game.modules.get("combat-tracker-dock")) != null && _c.active && (async () => (game.lancer.combatTrackerDock = await import("./combat-tracker-dock-b3fd3c79.mjs"), Hooks.on("renderCombatDock", (...[_app, html]) => {
    html.find(".buttons-container [data-action='roll-all']").hide(), html.find(".buttons-container [data-action='roll-npc']").hide(), html.find(".buttons-container [data-action='next-turn']").hide();
  })))(), Hooks.on("renderTokenConfig", extendTokenConfig);
});
Hooks.once("setup", () => {
  game.settings.settings.get("core.gridTemplates") && (game.settings.settings.get("core.gridTemplates").default = !0);
});
Hooks.once("ready", async function() {
  setupSheets(), Hooks.on("updateCombat", handleCombatUpdate), preloadTemplates(), console.log(`${lp} Foundry ready, doing final checks.`), await doMigration(), applyGlobalDragListeners(), game.action_manager = new LancerActionManager(), game.action_manager.init(), await LancerActiveEffect.updateIcons(), Hooks.on("updateCompendium", async (collection) => {
    var _a19;
    ((_a19 = collection == null ? void 0 : collection.metadata) == null ? void 0 : _a19.id) == get_pack_id(EntryType.STATUS) && await LancerActiveEffect.updateIcons();
  });
  const _updateIcons = /* @__PURE__ */ __name(async (item) => {
    item.is_status() && await LancerActiveEffect.updateIcons();
  }, "_updateIcons");
  Hooks.on("itemCreated", _updateIcons), Hooks.on("deleteItem", _updateIcons), Hooks.on("updateItem", _updateIcons);
});
Hooks.once("ready", () => {
  var _a19;
  game.user.isGM && ((_a19 = game.modules.get("dice-so-nice")) != null && _a19.active) && !game.settings.get(game.system.id, LANCER.setting_dsn_setup) && (console.log(`${lp} First login setup for Dice So Nice`), game.settings.set("dice-so-nice", "enabledSimultaneousRollForMessage", !1), game.settings.set(game.system.id, LANCER.setting_dsn_setup, !0)), migrateLancerConditions(), disableLancerInitiative();
});
Hooks.once("ready", () => {
  game.socket.on(`system.${game.system.id}`, (msg) => {
    handleSocketMessage(msg);
  });
});
Hooks.on("controlToken", () => {
  var _a19;
  (_a19 = game.action_manager) == null || _a19.update();
});
Hooks.on("updateToken", (_scene, _token, diff, _options, _idUser) => {
  var _a19;
  diff.hasOwnProperty("y") || diff.hasOwnProperty("x") || (_a19 = game.action_manager) == null || _a19.update();
});
Hooks.on("updateActor", (...[_actor, changes]) => {
  var _a19;
  (_a19 = game.action_manager) == null || _a19.update(), triggerStrussFlow(_actor, changes);
});
Hooks.on("closeSettingsConfig", () => {
  var _a19;
  (_a19 = game.action_manager) == null || _a19.updateConfig();
});
Hooks.on("getSceneNavigationContext", async () => {
  game.action_manager && await game.action_manager.reset();
});
Hooks.on("createCombat", (_actor) => {
  var _a19;
  (_a19 = game.action_manager) == null || _a19.update();
});
Hooks.on("deleteCombat", (_actor) => {
  var _a19;
  (_a19 = game.action_manager) == null || _a19.update();
});
Hooks.on("updateCombat", (_combat, changes) => {
  var _a19, _b, _c;
  game.settings.get(game.system.id, LANCER.setting_automation).remove_templates && "turn" in changes && ((_a19 = game.user) != null && _a19.isGM) && ((_b = canvas == null ? void 0 : canvas.templates) == null || _b.placeables.forEach((t) => {
    t.document.getFlag("lancer", "isAttack") && t.document.delete();
  })), foundry.utils.hasProperty(changes, "turn") && ((_c = ui.combatCarousel) == null || _c.render());
});
Hooks.on("dropCanvasData", dropStatusToCanvas);
Hooks.on("renderSidebarTab", async (app, html) => {
  addLCPManagerButton(app, html);
});
Hooks.on("renderSettings", async (app, html) => {
  addSettingsButtons(app, html);
});
Hooks.on("renderCombatTrackerConfig", extendCombatTrackerConfig);
Hooks.on("closeCombatTrackerConfig", onCloseCombatTrackerConfig);
Hooks.on("preCreateScene", (scene) => {
  scene.updateSource({ tokenVision: !1, "fog.exploration": !1 });
});
Hooks.on("renderChatMessage", async (cm, html, data2) => {
  initializeCollapses(html), applyCollapseListeners(html), attachTagTooltips(html), html.find(".chat-button").on("click", async (ev) => {
    var _a19, _b, _c;
    let elt = $(ev.target).closest("[data-action]")[0];
    if (elt != null && elt.dataset.action) {
      switch (ev.stopPropagation(), elt.dataset.action) {
        case "importActor":
          const actorId = elt.dataset.targetId;
          if (!actorId)
            return (_a19 = ui.notifications) == null ? void 0 : _a19.error("No target actor ID found on actor import prompt button.");
          const importId = elt.dataset.importId;
          if (!importId)
            return (_b = ui.notifications) == null ? void 0 : _b.error("No import actor ID found on actor import prompt button.");
          const toImport = await LancerActor.fromUuid(
            importId,
            "Invalid import actor ID on actor import prompt button."
          ), forActor = await LancerActor.fromUuid(
            actorId,
            "Invalid target actor ID on actor import prompt button."
          );
          await fulfillImportActor(toImport, forActor);
          break;
        default:
          return (_c = ui.notifications) == null || _c.error("Invalid action on chat button."), !1;
      }
      return elt.classList.contains("self-destruct") && cm.delete(), !0;
    }
    return !1;
  }), html.find(".flow-button").on("click", (ev) => {
    var _a19, _b, _c;
    const element = $(ev.target).closest("[data-flow-type]")[0];
    if (element != null && element.dataset.flowType) {
      ev.stopPropagation();
      const flowType = element.dataset.flowType, actorId = element.dataset.actorId;
      switch (element.dataset.itemId, flowType) {
        case "check":
          const actor = LancerActor.fromUuidSync(actorId ?? "", "Invalid actor ID on check prompt button.");
          switch (element.dataset.checkType) {
            case "hull":
            default:
              actor.beginStatFlow("system.hull");
              break;
            case "agility":
              actor.beginStatFlow("system.agility");
              break;
            case "systems":
              actor.beginStatFlow("system.systems");
              break;
            case "engineering":
              actor.beginStatFlow("system.engineering");
              break;
          }
          break;
        case "secondaryStructure":
          if (!actorId)
            return (_a19 = ui.notifications) == null ? void 0 : _a19.error("No actor ID found on secondary structure prompt button.");
          beginSecondaryStructureFlow(actorId);
          break;
        case "cascade":
          if (!actorId)
            return (_b = ui.notifications) == null ? void 0 : _b.error("No actor ID found on cascade prompt button.");
          beginCascadeFlow(actorId);
          break;
        case "dismembermentDamage": {
          const actor2 = LancerActor.fromUuidSync(actorId ?? "", "Invalid actor ID dismemberment damage button.");
          beginDismembermentDamageFlow(actor2);
          break;
        }
        default:
          return (_c = ui.notifications) == null ? void 0 : _c.error("Invalid flow type on flow prompt button.");
      }
      return !0;
    }
  });
  const hoverCallback = /* @__PURE__ */ __name(async (ev) => {
    if (!canvas.ready)
      return;
    const targetId = $(ev.target).closest("[data-uuid]").data("uuid");
    if (!targetId)
      return;
    const token = await fromUuid(targetId);
    token && (ev.type === "mouseover" ? token.object._onHoverIn(ev) : ev.type === "mouseout" && token.object._onHoverOut(ev));
  }, "hoverCallback"), atkDmgTargets = html.find(".lancer-hit-target, .lancer-damage-target");
  atkDmgTargets.on("mouseenter", hoverCallback), atkDmgTargets.on("mouseleave", hoverCallback), html.find(".lancer-damage-flow").on("click", rollDamageCallback), html.find(".lancer-damage-apply").on("click", applyDamage), html.find(".lancer-damage-undo").on("click", undoDamage), handleRefClickOpen(html);
});
Hooks.on("hotbarDrop", (_bar, data2, slot) => {
  onHotbarDrop(_bar, data2, slot);
});
async function promptInstallCoreData() {
  await new LCPManager().render(!0);
  let content = `
  <h2 style="text-align: center">WELCOME GAME MASTER</h2>
  <p style="text-align: center;margin-bottom: 1em">THIS IS YOUR <span class="horus--very--subtle">FIRST</span> TIME LAUNCHING</p>
  <p style="text-align: center;margin-bottom: 1em">Use the LANCER Compendium Manager window to install the <span class="horus--very--subtle">LANCER DATA</span> you wish to use.</p>`;
  new foundry.applications.api.DialogV2({
    window: { title: "Install Core Data", icon: "cci cci-content-manager i--sm" },
    position: {
      width: 700
    },
    content,
    buttons: [
      {
        action: "close",
        label: "Close"
      }
    ]
  }).render(!0);
}
__name(promptInstallCoreData, "promptInstallCoreData");
function setupSheets() {
  Actors.unregisterSheet("core", ActorSheet), Actors.registerSheet("lancer", LancerPilotSheet, { types: [EntryType.PILOT], makeDefault: !0 }), Actors.registerSheet("lancer", LancerMechSheet, { types: [EntryType.MECH], makeDefault: !0 }), Actors.registerSheet("lancer", LancerNPCSheet, { types: [EntryType.NPC], makeDefault: !0 }), Actors.registerSheet("lancer", LancerDeployableSheet, {
    types: [EntryType.DEPLOYABLE],
    makeDefault: !0
  }), Items.unregisterSheet("core", ItemSheet), Items.registerSheet("lancer", LancerItemSheet, {
    types: [
      EntryType.SKILL,
      EntryType.TALENT,
      EntryType.BOND,
      EntryType.CORE_BONUS,
      EntryType.RESERVE,
      EntryType.STATUS,
      EntryType.PILOT_ARMOR,
      EntryType.PILOT_WEAPON,
      EntryType.PILOT_GEAR,
      EntryType.MECH_SYSTEM,
      EntryType.MECH_WEAPON,
      EntryType.WEAPON_MOD,
      EntryType.NPC_FEATURE,
      EntryType.ORGANIZATION
    ],
    makeDefault: !0
  }), Items.registerSheet("lancer", LancerFrameSheet, { types: [EntryType.FRAME], makeDefault: !0 }), Items.registerSheet("lancer", LancerLicenseSheet, { types: [EntryType.LICENSE], makeDefault: !0 }), Items.registerSheet("lancer", LancerNPCClassSheet, {
    types: [EntryType.NPC_CLASS, EntryType.NPC_TEMPLATE],
    makeDefault: !0
  }), Items.registerSheet("lancer", LancerNPCFeatureSheet, { types: [EntryType.NPC_FEATURE], makeDefault: !0 });
}
__name(setupSheets, "setupSheets");
async function versionCheck() {
  const currentVersion = game.settings.get(game.system.id, LANCER.setting_migration_version);
  return currentVersion === "0" || !currentVersion ? "first_run" : foundry.utils.isNewerVersion("1.0.0", currentVersion) ? "too_old" : foundry.utils.isNewerVersion(game.system.version, currentVersion) ? "yes" : "no";
}
__name(versionCheck, "versionCheck");
async function promptLCPManagerTour() {
  if (!await foundry.applications.api.DialogV2.confirm({
    // @ts-expect-error This should expect a partial
    window: { title: "Compendium Manager Tour?" },
    content: "The LANCER Compendium Manager has had a major update. Would you like to get a tour?",
    rejectClose: !1
  }))
    return;
  const lcpTour = game.tours.get(`${game.system.id}.lcp`);
  if (!lcpTour) {
    console.error(`${lp} LCP manager tour not found.`);
    return;
  }
  console.log(`${lp} Starting LCP manager tour`), lcpTour.start();
}
__name(promptLCPManagerTour, "promptLCPManagerTour");
async function doMigration() {
  const oldVersion = game.settings.get(game.system.id, LANCER.setting_migration_version);
  if (oldVersion && foundry.utils.isNewerVersion("2.7.0", oldVersion)) {
    console.log(`${lp} Game is migrating from ${oldVersion}. Should show LCP manager tour`);
    const lcpTour = game.tours.get(`${game.system.id}.lcp`);
    if (!lcpTour) {
      console.error(`${lp} LCP manager tour not found.`);
      return;
    }
    await lcpTour.reset(), promptLCPManagerTour();
  }
  let needsMigrate = await versionCheck();
  if (needsMigrate == "first_run")
    game.settings.set(game.system.id, LANCER.setting_migration_version, game.system.version), await promptInstallCoreData();
  else if (needsMigrate == "too_old") {
    ui.notifications.error(
      `Your LANCER system data is from too old a version (${game.settings.get(
        game.system.id,
        LANCER.setting_migration_version
      )}) and cannot be reliably migrated to the latest version. Please install and migrate to version 1.5.0+ before attempting this migration`,
      { permanent: !0 }
    );
    return;
  } else
    needsMigrate == "yes" && game.user.isGM ? (printUpdateMessage(), ui.notifications.info(
      `Migrating to LANCER version ${game.system.version}. Please be patient and wait until migration completes.`,
      { permanent: !0 }
    ), await migrateWorld(), await game.settings.set(game.system.id, LANCER.setting_migration_version, game.system.version)) : needsMigrate == "yes" ? ui.notifications.warn(
      "Your GM needs to migrate this world. Please do not attempt to play the game or edit anything until migrations are done.",
      { permanent: !0 }
    ) : needsMigrate == "no" && game.user.isGM && await game.settings.set(game.system.id, LANCER.setting_migration_version, game.system.version);
}
__name(doMigration, "doMigration");
async function configureAmplify() {
  const aws = (await import("./aws-exports-1e808d22.mjs")).default, { Auth } = await import("./index-4953d36a.mjs"), { Storage } = await import("./index-25344865.mjs");
  Auth.configure(aws), Storage.configure(aws);
  try {
    return populatePilotCache();
  } catch {
  }
}
__name(configureAmplify, "configureAmplify");
async function printUpdateMessage() {
  for (; !ui.sidebar.rendered; )
    await new Promise((resolve) => setTimeout(resolve, 100));
  await ChatMessage.create({
    content: WELCOME(),
    speaker: { alias: `LANCER System v${game.system.version}` }
  });
}
__name(printUpdateMessage, "printUpdateMessage");
function addSettingsButtons(_app, html) {
  const lancerHeader = $(`<h2>LANCER</h2>
            <div id="settings-lancer"></div>`), faqButton = $(`<button id="triggler-form" data-action="triggler">
            <i class="fas fa-robot"></i>LANCER Help
        </button>`), loginButton = $(`<button id="compcon-login" data-action="compconLogin">
            <i class="mdi mdi-cloud-sync-outline "></i>COMP/CON Login
          </button>`);
  $(html).find("#settings-game").after(lancerHeader), $(html).find("#settings-lancer").append(loginButton), $(html).find("#settings-lancer").append(faqButton), loginButton.on("click", async () => new CompconLoginForm({}).render(!0)), faqButton.on("click", async () => {
    let helpContent = await renderTemplate(`systems/${game.system.id}/templates/window/lancerHelp.hbs`, {});
    new foundry.applications.api.DialogV2({
      window: {
        title: "LANCER Help",
        icon: "fas fa-robot"
      },
      content: helpContent,
      position: {
        width: 600
      },
      buttons: [
        {
          action: "close",
          label: "Close"
        }
      ]
    }).render(!0);
  });
}
__name(addSettingsButtons, "addSettingsButtons");
export {
  DamageType as D,
  HitQuality as H,
  LCPIndex as L,
  NpcFeatureType as N,
  RangeType as R,
  WeaponRangeTemplate as W,
  generateLcpSummary as a,
  generateMultiLcpSummary as b,
  commonjsGlobal as c,
  LANCER as d,
  getOfficialData as e,
  clearCompendiumData as f,
  getAugmentedNamespace as g,
  fade as h,
  importCP as i,
  targetsFromTemplate as j,
  getDefaultExportFromCjs as k,
  mergeOfficialDataAndLcpIndex as m,
  parseContentPack as p,
  tippy$1 as t
};
//# sourceMappingURL=lancer-a96e7e01.mjs.map
