`;
await ChatMessage.create({
user: (o = game.user) == null ? void 0 : o.id,
speaker: a,
content: n
});
}
async function Be(e, t, a) {
const n = await Ce(a), o = e.items.find(
(s) => s.type === "skill" && s.name.toLowerCase() === String(t).toLowerCase()
);
await ht({
actor: e,
actorName: e.name,
actorImg: e.img,
skillName: t,
skillImg: o == null ? void 0 : o.img,
roll: n.roll,
target: n.target,
outcomeLabel: he(n.outcome),
isSuccess: n.isSuccess,
isSpecial: n.isSpecial,
isFumble: n.isFumble
});
}
function oa(e, t) {
const a = t.system.linkedSkillId, n = a ? e.items.get(a) : null;
if ((n == null ? void 0 : n.type) === "skill")
return { name: n.name, target: A(n.system.value), img: n.img };
const o = String(t.system.linkedSkill || "").trim();
if (o) {
const s = e.items.find(
(i) => i.type === "skill" && i.name.toLowerCase() === o.toLowerCase()
);
if (s)
return { name: s.name, target: A(s.system.value), img: s.img };
}
return {
name: o || "Unlinked Skill",
target: 0
};
}
function yt(e) {
return Math.max(0, Math.min(99, Math.floor(e)));
}
async function sa(e, t, a) {
var m;
const o = String(((m = t.system) == null ? void 0 : m.attackType) || "ranged") === "ranged", s = "full", i = foundry.utils.escapeHTML(String((e == null ? void 0 : e.name) || "Attacker")), r = foundry.utils.escapeHTML(String((t == null ? void 0 : t.name) || "Weapon")), l = foundry.utils.escapeHTML(String((e == null ? void 0 : e.img) || "icons/svg/mystery-man.svg")), c = foundry.utils.escapeHTML(String((t == null ? void 0 : t.img) || "icons/svg/sword.svg")), u = `
`;
return new Promise((g) => {
let f = !1;
const d = (y) => {
f || (f = !0, g(y));
};
new Dialog({
title: `${t.name} - Attack Modifiers`,
content: u,
buttons: {
roll: {
label: "Roll Attack",
callback: (y) => {
var le, ce, ue, me, de, ge, pe;
const b = y[0], h = (J) => b == null ? void 0 : b.querySelector(`[name="${J}"]`), p = String(((le = h("aimMode")) == null ? void 0 : le.value) || s), w = p === "unaimed" || p === "partial" || p === "full" ? p : s, v = o ? { unaimed: 0.25, partial: 0.5, full: 1 }[w] : 1, x = A((ce = h("coverMod")) == null ? void 0 : ce.value, 0), I = A((ue = h("movementMod")) == null ? void 0 : ue.value, 0), T = A((me = h("rangeMod")) == null ? void 0 : me.value, 0), R = A((de = h("situationalMod")) == null ? void 0 : de.value, 0), D = A((ge = h("customMod")) == null ? void 0 : ge.value, 0), N = String(((pe = h("customLabel")) == null ? void 0 : pe.value) || "").trim(), C = x + I + T + R + D, U = a + C, re = Math.floor(U * v), Z = yt(re), H = [`Base ${a}`];
if (x && H.push(`Cover ${x >= 0 ? "+" : ""}${x}`), I && H.push(`Movement ${I >= 0 ? "+" : ""}${I}`), T && H.push(`Range ${T >= 0 ? "+" : ""}${T}`), R && H.push(`Situational ${R >= 0 ? "+" : ""}${R}`), D && H.push(`${N || "Custom"} ${D >= 0 ? "+" : ""}${D}`), H.push(`Pre-Aim ${U}`), o) {
const J = w === "unaimed" ? "Quarter" : w === "partial" ? "Half" : "Full";
H.push(`Aim ${J} x${v}`);
}
H.push(`Final ${Z}`), d({
finalTarget: Z,
summary: H.join(" | "),
aimMode: w,
aimMultiplier: v,
flatModifierTotal: C
});
}
},
cancel: {
label: "Cancel",
callback: () => d(null)
}
},
default: "roll",
close: () => d(null)
}, {
classes: ["ringworld-attack-dialog"],
width: 510,
resizable: !1
}).render(!0);
});
}
async function ia(e, t) {
var i, r, l;
const a = Math.max(0, A(t.system.ammoUsedPerAttack));
if (a <= 0)
return { used: !1, remaining: 0, cost: 0, insufficient: !1 };
const n = A((i = t.system.ammo) == null ? void 0 : i.value);
if (A((r = t.system.ammo) == null ? void 0 : r.max) <= 0 && n <= 0)
return { used: !1, remaining: 0, cost: a, insufficient: !1 };
if (n < a)
return (l = ui.notifications) == null || l.warn(`${t.name} is out of ammunition. Reload before attacking.`), { used: !0, remaining: n, cost: a, insufficient: !0 };
const s = n - a;
return await e.updateEmbeddedDocuments("Item", [{ _id: t.id, "system.ammo.value": s }]), { used: !0, remaining: s, cost: a, insufficient: !1 };
}
async function ra(e, t) {
var n, o, s;
const a = A((n = t.system.ammo) == null ? void 0 : n.max);
if (a <= 0) {
(o = ui.notifications) == null || o.info(`${t.name} has no ammunition capacity configured (set Ammo Max on the weapon).`);
return;
}
await e.updateEmbeddedDocuments("Item", [{ _id: t.id, "system.ammo.value": a }]), (s = ui.notifications) == null || s.info(`${t.name} reloaded (${a}/${a}).`);
}
async function la(e, t) {
var i, r, l, c, u, m, g;
const a = Math.max(0, A(t.system.energyUsedPerAttack));
if (a <= 0)
return { sourceLabel: "None", remaining: 0, cost: 0, insufficient: !1 };
if (String(t.system.powerSource || "actor") === "powerPack") {
const f = String(t.system.powerPackId || "");
let d = f ? e.items.get(f) : null;
if ((!d || d.type !== "gear" || !d.system.isPowerPack) && (d = e.items.find(
(h) => {
var p;
return h.type === "gear" && h.system.isPowerPack && !h.system.stowed && A((p = h.system.energy) == null ? void 0 : p.value) >= a;
}
) ?? null, d && (await e.updateEmbeddedDocuments("Item", [{ _id: t.id, "system.powerPackId": d.id }]), (i = ui.notifications) == null || i.info(`${t.name} linked to ${d.name}.`))), !d || d.type !== "gear" || !d.system.isPowerPack)
return (r = ui.notifications) == null || r.warn("Weapon is configured for a power pack but no valid power pack is carried."), { sourceLabel: "Power Pack", remaining: 0, cost: a, insufficient: !0 };
const y = A((l = d.system.energy) == null ? void 0 : l.value);
if (y < a)
return (c = ui.notifications) == null || c.warn(`${d.name} does not have enough energy.`), { sourceLabel: d.name, remaining: y, cost: a, insufficient: !0 };
const b = y - a;
return await e.updateEmbeddedDocuments("Item", [{ _id: d.id, "system.energy.value": b }]), { sourceLabel: d.name, remaining: b, cost: a, insufficient: !1 };
}
const o = A((m = (u = e.system.resources) == null ? void 0 : u.energy) == null ? void 0 : m.value);
if (o < a)
return (g = ui.notifications) == null || g.warn(`${e.name} does not have enough actor energy.`), { sourceLabel: "Actor Energy", remaining: o, cost: a, insufficient: !0 };
const s = o - a;
return await e.update({ "system.resources.energy.value": s }), { sourceLabel: "Actor Energy", remaining: s, cost: a, insufficient: !1 };
}
function ca(e, t) {
var n, o;
if (e.type !== "armor" || !e.system.equipped || e.system.stowed || !((n = e.system.coverage) != null && n[t])) return 0;
const a = A((o = e.system.perLocation) == null ? void 0 : o[t]);
return a > 0 ? a : A(e.system.value);
}
function ua(e, t) {
var o, s;
const a = A((s = (o = e.system.hitLocations) == null ? void 0 : o[t]) == null ? void 0 : s.armor), n = e.items.filter((i) => i.type === "armor").reduce((i, r) => i + ca(r, t), 0);
return a + n;
}
function ma(e, t, a, n, o) {
const s = foundry.utils.deepClone(e.system.conditions ?? {});
return s.unusableLimbs = s.unusableLimbs ?? { rArm: !1, lArm: !1, rLeg: !1, lLeg: !1 }, a <= 0 && ((t === "head" || t === "chest") && (s.unconscious = !0, s.prone = !0), t === "abdomen" && (s.prone = !0, s.unusableLimbs.rLeg = !0, s.unusableLimbs.lLeg = !0), (t === "rArm" || t === "lArm") && (s.unusableLimbs[t] = !0), Gt.includes(t) && (s.unusableLimbs[t] = !0, s.prone = !0)), o <= 0 && (s.dying = !0), (t === "head" || t === "chest" || t === "abdomen") && a <= -n && (s.dying = !0), t === "head" && a <= -n && (s.dead = !0, s.unconscious = !0), s;
}
async function da(e, t) {
const a = e.toggleStatusEffect;
if (typeof a == "function")
try {
await a.call(e, "prone", { active: !!t.prone }), await a.call(e, "unconscious", { active: !!t.unconscious }), await a.call(e, "dead", { active: !!t.dead });
} catch {
}
}
async function ga(e, t, a) {
var d, y, b, h;
const n = (d = e.system.hitLocations) == null ? void 0 : d[t], o = A((y = n == null ? void 0 : n.hp) == null ? void 0 : y.value), s = Math.max(1, A((b = n == null ? void 0 : n.hp) == null ? void 0 : b.max, 1)), i = ua(e, t), r = Math.max(0, a - i), l = o - r, c = Vt(t) ? Math.max(l, -s) : l, m = A((h = e.system.generalHp) == null ? void 0 : h.value) - r, g = ma(e, t, c, s, m), f = {
[`system.hitLocations.${t}.hp.value`]: c,
"system.generalHp.value": m,
"system.conditions": g
};
return await e.update(f), await da(e, g), {
armor: i,
finalDamage: r,
locationValue: c,
generalHpValue: m
};
}
async function wt(e, t, a) {
var c, u;
if (!(/* @__PURE__ */ new Set(["str", "mas", "con", "int", "pow", "dex", "app", "edu", "age"])).has(t)) return;
const o = Math.max(0, A((u = (c = e.system) == null ? void 0 : c.characteristics) == null ? void 0 : u[t], 0)), s = `
`, i = await new Promise((m) => {
let g = !1;
const f = (d) => {
g || (g = !0, m(d));
};
new Dialog({
title: `${a} Check`,
content: s,
buttons: {
roll: {
label: "Roll",
callback: (d) => {
var h, p;
const y = Number(((p = (h = d[0]) == null ? void 0 : h.querySelector("select[name='multiplier']")) == null ? void 0 : p.value) || 1), b = Math.max(1, Math.min(7, Math.floor(y || 1)));
f(b);
}
},
cancel: {
label: "Cancel",
callback: () => f(null)
}
},
default: "roll",
close: () => f(null)
}, {
classes: ["ringworld-attack-dialog"]
}).render(!0);
});
if (!i) return;
const r = yt(o * i), l = await Ce(r);
await ht({
actor: e,
actorName: e.name,
actorImg: e.img,
skillName: `${a} x${i}`,
roll: l.roll,
target: l.target,
outcomeLabel: he(l.outcome),
isSuccess: l.isSuccess,
isSpecial: l.isSpecial,
isFumble: l.isFumble
});
}
function Je(e, t) {
try {
return !!game.settings.get(P, e);
} catch {
return t;
}
}
async function pa(e, t) {
var r, l;
const a = A((l = (r = e.system) == null ? void 0 : r.derivedRolls) == null ? void 0 : l.dodge, 0), n = foundry.utils.escapeHTML(String(e.name || "Target"));
if (!await new Promise((c) => {
let u = !1;
const m = (g) => {
u || (u = !0, c(g));
};
new Dialog({
title: `${e.name} - Dodge Attempt`,
content: `
${n} has been hit${t ? " by a special success" : ""}.
Dodge ${a}%. A successful dodge evades a normal hit; only a special dodge evades a special hit.
`,
buttons: {
dodge: { label: `Dodge (${a}%)`, callback: () => m(!0) },
none: { label: "No Dodge", callback: () => m(!1) }
},
default: "dodge",
close: () => m(!1)
}, {
classes: ["ringworld-attack-dialog"],
width: 420
}).render(!0);
})) return null;
const s = await Ce(a), i = s.isSuccess && (!t || s.isSpecial);
return {
attempted: !0,
roll: s.roll,
target: s.target,
success: s.isSuccess,
special: s.isSpecial,
negated: i
};
}
async function bt(e, t) {
var p, w;
const a = aa(), n = !!a, o = (a == null ? void 0 : a.name) ?? "No Target", s = oa(e, t), i = await sa(e, t, s.target);
if (!i) return;
const r = await ia(e, t);
if (r.insufficient) return;
const l = await la(e, t);
if (l.insufficient) return;
const c = await Ce(i.finalTarget);
if (!c.isSuccess) {
const v = a ? A((p = a.system.generalHp) == null ? void 0 : p.value, 0) : 0;
await Ne({
actor: e,
actorName: e.name,
actorImg: e.img,
targetName: o,
hasTarget: n,
weaponName: t.name,
weaponImg: t.img,
skillName: s.name,
skillImg: s.img,
attackRoll: c.roll,
attackTarget: c.target,
attackOutcomeLabel: he(c.outcome),
isSuccess: !1,
isSpecial: c.isSpecial,
isFumble: c.isFumble,
hitLocationLabel: "-",
hitLocationRoll: null,
rawDamage: 0,
armor: 0,
finalDamage: 0,
remainingLocationHp: 0,
remainingGeneralHp: v,
energySourceLabel: l.sourceLabel,
energyCost: l.cost,
energyRemaining: l.remaining,
ammoUsed: r.used,
ammoCost: r.cost,
ammoRemaining: r.remaining,
dodge: null,
notes: c.isFumble ? `Fumble! The GM should adjudicate a mishap (dropped or damaged weapon, hit an ally, drained power). ${i.summary}` : `Attack failed before damage was rolled. ${i.summary}`
});
return;
}
let u = null;
if (a && Je("promptDefenderDodge", !0) && (u = await pa(a, c.isSpecial)), u != null && u.negated) {
await Ne({
actor: e,
actorName: e.name,
actorImg: e.img,
targetName: o,
hasTarget: n,
weaponName: t.name,
weaponImg: t.img,
skillName: s.name,
skillImg: s.img,
attackRoll: c.roll,
attackTarget: c.target,
attackOutcomeLabel: he(c.outcome),
isSuccess: !1,
isSpecial: c.isSpecial,
isFumble: !1,
hitLocationLabel: "-",
hitLocationRoll: null,
rawDamage: 0,
armor: 0,
finalDamage: 0,
remainingLocationHp: 0,
remainingGeneralHp: A((w = a.system.generalHp) == null ? void 0 : w.value, 0),
energySourceLabel: l.sourceLabel,
energyCost: l.cost,
energyRemaining: l.remaining,
ammoUsed: r.used,
ammoCost: r.cost,
ammoRemaining: r.remaining,
dodge: u,
notes: `${o} dodged the attack. ${i.summary}`
});
return;
}
const m = await Zt(a ?? e);
if (!m) return;
const g = String(t.system.damageFormula || "0").trim() || "0", f = Je("automateSpecialDamage", !0), d = c.isSpecial && f, y = await ye(g);
let b = Math.max(0, A(y.total));
if (d) {
const v = await ye(g);
b += Math.max(0, A(v.total));
}
const h = a ? await ga(a, m.slug, b) : {
armor: 0,
finalDamage: b,
locationValue: 0,
generalHpValue: 0
};
await Ne({
actor: e,
actorName: e.name,
actorImg: e.img,
targetName: o,
hasTarget: n,
weaponName: t.name,
weaponImg: t.img,
skillName: s.name,
skillImg: s.img,
attackRoll: c.roll,
attackTarget: c.target,
attackOutcomeLabel: he(c.outcome),
isSuccess: c.isSuccess,
isSpecial: c.isSpecial,
isFumble: c.isFumble,
hitLocationLabel: m.label,
hitLocationRoll: m.rolled,
rawDamage: b,
armor: h.armor,
finalDamage: h.finalDamage,
remainingLocationHp: h.locationValue,
remainingGeneralHp: h.generalHpValue,
energySourceLabel: l.sourceLabel,
energyCost: l.cost,
energyRemaining: l.remaining,
ammoUsed: r.used,
ammoCost: r.cost,
ammoRemaining: r.remaining,
dodge: u,
notes: [
d ? "Special success: damage dice rolled twice." : "",
a ? "Location and general HP were both reduced by final damage, per Ringworld rules." : "No target selected: roll resolved with no damage application.",
i.summary
].filter(Boolean).join(" ")
});
}
function fa(e) {
var r, l, c, u, m, g, f, d, y;
if (e.type !== "explorer" && e.type !== "creature") return;
const t = A((l = (r = e.system) == null ? void 0 : r.characteristics) == null ? void 0 : l.con, 10), a = A((u = (c = e.system) == null ? void 0 : c.characteristics) == null ? void 0 : u.mas, 10), n = Math.max(1, Math.floor(t + a)), o = (e._source ?? ((m = e.toObject) == null ? void 0 : m.call(e, !1)) ?? {}).system ?? {}, s = (g = o.generalHp) == null ? void 0 : g.value;
e.system.generalHp = e.system.generalHp ?? {}, e.system.generalHp.max = n, e.system.generalHp.value = s == null ? n : Math.min(A(s, n), n), e.system.hitLocations = e.system.hitLocations ?? {}, e.system.hitLocationSchema = e.system.hitLocationSchema ?? "auto";
const i = oe(e);
for (const b of i.entries) {
const h = b.slug, p = e.system.hitLocations[h] ?? {
label: h,
hp: {},
armor: 0
};
p.label = b.label;
const w = Math.max(0.05, A(b.hpFactor, 0.3)), v = Math.max(1, Math.ceil(n * w)), x = (y = (d = (f = o.hitLocations) == null ? void 0 : f[h]) == null ? void 0 : d.hp) == null ? void 0 : y.value;
p.hp = p.hp ?? {}, p.hp.max = v, p.hp.value = x == null ? v : Math.min(A(x, v), v), e.system.hitLocations[h] = p;
}
}
const et = "Ringworld GM Reference";
function ha() {
return [
{
name: "Percentile Outcomes",
content: `
Every check is a d100 roll against a target percentage. The system classifies results automatically:
Success — roll ≤ target.
Special Success — roll ≤ one fifth of the target (minimum 1). Attacks roll their damage dice twice when Automate Special Success Damage is enabled.
Failure — roll > target.
Fumble — roll of 96–100 when the target is below 50, or a natural 100 otherwise. The GM adjudicates a mishap: dropped or damaged weapon, hit an ally, drained power pack.
Characteristic checks use Characteristic × Multiplier (usually ×5): click any characteristic button on a sheet to pick the multiplier.
Ringworld does not use simple initiative. Combat rounds are split into impulses and each combatant acts on a rhythm set by their Action Ranking (AR), which is derived from DEX (lower is faster) and worsened by encumbrance.
Add combatants to the Combat Tracker as normal. The Ringworld impulse panel replaces the core tracker list.
Each combatant schedules an action: a major action (attack, full move, complex task) completes after AR impulses; a minor action (drop prone, shout, draw) completes after 1 impulse.
Advance the clock with Next Completion or +1. When a combatant's action completes, resolve it, then let them schedule the next one.
The floating impulse HUD can be dragged anywhere on screen and mirrors the tracker for quick play.
`
},
{
name: "Attack Workflow",
content: `
Target a token, then press the weapon's Use button on the attacker's sheet. The system walks through the 1984 rules in order:
Aim state (ranged only): unaimed fires at quarter skill, partially aimed at half, fully aimed at full skill. Cover, movement, range and situational modifiers are applied before the aim multiplier.
Ammunition and energy are spent. Projectile weapons with an ammo capacity are blocked when empty — use the Reload button on the weapon row. Energy weapons draw from the actor pool or a linked power pack.
Dodge: on a hit, the defender is offered a Dodge roll (DEX ×5). A successful dodge evades a normal hit; only a special dodge evades a special hit. Disable with the Prompt Defender Dodge setting.
Hit location is rolled on a d20 (or picked manually). Species use their own body schema — puppeteers, dolphins, trinocs, bandersnatchi and kzinti map differently.
Damage is rolled, stacked armor at that location is subtracted, and the result reduces both the location HP and the general HP.
`
},
{
name: "Wounds & Conditions",
content: `
When a hit location reaches 0 HP or less, conditions are applied automatically:
Head or Chest at 0 — unconscious and prone.
Abdomen at 0 — prone, both legs unusable.
Arm at 0 — that arm is unusable.
Leg at 0 — that leg is unusable, and the character falls prone.
General HP at 0 — dying.
Head, chest or abdomen at negative full value — dying; a head at negative full value is death outright.
Limbs cannot go below their negative maximum. Use Reset Conditions on a sheet after treatment or recovery. Prone, unconscious and dead sync to token status icons.
`
},
{
name: "Running the 1984 Rules",
content: `
Quirks of the original boxed set that the system encodes for you:
General HP = CON + MAS. MAS (mass) replaces the familiar SIZ. Location HP scale from general HP by body schema.
Damage modifier comes from STR + MAS and is recomputed automatically when characteristics change.
Skill pools: Education points = (EDU − 10) × 20, Pursuit points = (Age − EDU − 6) × 20, Special points = INT × 10. The character builder on the Skills tab tracks all three.
Skill category caps: each category is capped by a characteristic pair (e.g. Agility by STR + DEX). The builder enforces the caps.
Gravity matters: carried weight is halved in light gravity and doubled in heavy gravity before comparing to the STR limit; over-limit explorers slow to Move 2 and suffer an Action Ranking penalty.
Energy economy: most Ringworld tech runs on power packs (R20/R50/R100). Weapons can draw from a linked pack — keep spares, and remember fumbles can drain them.
`
},
{
name: "GM Quick Start",
content: `
To get a table playing quickly:
Seed the catalog (Items sidebar button) — species, 55 base skills, pursuits, weapons, armor and gear from the boxed set appear in organised folders. This runs automatically for new worlds.
Create Random Explorer (Actors sidebar button) — rolls characteristics by species and gravity, adds base skills and a starter kit.
For bespoke characters, unlock the sheet tools (padlock, top right of the sheet) and use the Character Builder on the Skills tab: pick pursuits, then allocate the three point pools.
Creatures get the same automation — hit locations, dodge, armor stacking — via the creature sheet, with a body schema selector for non-humanoids.
Check System Settings for the automation toggles (special success damage, defender dodge prompts).
`
}
];
}
async function ya() {
var n, o;
if (!((n = game.user) != null && n.isGM)) return !1;
const e = game.journal;
if ((e == null ? void 0 : e.find((s) => {
var i;
return ((i = s.getFlag) == null ? void 0 : i.call(s, P, "gmReference")) === !0;
})) ?? ((o = e == null ? void 0 : e.getName) == null ? void 0 : o.call(e, et))) return !1;
const a = ha().map((s, i) => ({
name: s.name,
type: "text",
sort: (i + 1) * 1e5,
text: {
format: 1,
content: s.content.trim()
}
}));
return await getDocumentClass("JournalEntry").create({
name: et,
pages: a,
flags: {
[P]: {
gmReference: !0
}
},
ownership: { default: 0 }
}), !0;
}
const He = 10, j = {
speciesDefault: "systems/ringworld/assets/icons/species.svg",
skillDefault: "systems/ringworld/assets/icons/skill.svg",
pursuitDefault: "systems/ringworld/assets/icons/pursuit.svg",
weaponMelee: "systems/ringworld/assets/icons/weapon-melee.svg",
weaponRanged: "systems/ringworld/assets/icons/weapon-ranged.svg",
armor: "systems/ringworld/assets/icons/armor.svg",
gearDefault: "systems/ringworld/assets/icons/gear.svg",
powerPackDefault: "systems/ringworld/assets/icons/power-pack.svg"
};
function ve(e) {
return String(e).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}
function wa(e) {
return `systems/ringworld/assets/icons/species/${ve(e)}.svg`;
}
function ba(e) {
return `systems/ringworld/assets/icons/weapon/${ve(e)}.svg`;
}
function ka(e) {
return `systems/ringworld/assets/icons/armor/${ve(e)}.svg`;
}
function va(e) {
return `systems/ringworld/assets/icons/gear/${ve(e)}.svg`;
}
function kt(e) {
return `systems/ringworld/assets/icons/pursuit/${ve(e)}.svg`;
}
const tt = {
rLeg: !0,
lLeg: !0,
abdomen: !0,
chest: !0,
rArm: !0,
lArm: !0,
head: !0
}, xe = {
rLeg: !1,
lLeg: !1,
abdomen: !0,
chest: !0,
rArm: !1,
lArm: !1,
head: !1
}, Sa = {
rLeg: !1,
lLeg: !1,
abdomen: !1,
chest: !1,
rArm: !1,
lArm: !1,
head: !0
}, Aa = {
rLeg: !1,
lLeg: !1,
abdomen: !1,
chest: !1,
rArm: !0,
lArm: !0,
head: !1
}, xa = {
rLeg: !0,
lLeg: !0,
abdomen: !1,
chest: !1,
rArm: !1,
lArm: !1,
head: !1
}, vt = [
{
name: "Human",
playable: !0,
gravity: "normal",
homeworld: "Known Space",
modifiers: { str: 0, mas: 0, con: 0, int: 0, pow: 0, dex: 0, app: 0, edu: 0, age: 0 },
notes: "Baseline human explorer profile."
},
{
name: "Earth Human",
playable: !0,
gravity: "normal",
homeworld: "Earth",
modifiers: { str: 0, mas: 0, con: 0, int: 0, pow: 1, dex: 0, app: 0, edu: 0, age: 0 },
notes: "Earth-line humans with stronger latent psionic potential."
},
{
name: "Kzinti",
playable: !0,
gravity: "heavy",
homeworld: "Kzin",
modifiers: { str: 2, mas: 2, con: 1, int: -1, pow: 0, dex: 0, app: -2, edu: 0, age: 0 },
notes: "Predatory felinoids with high physical strength."
},
{
name: "Pierson's Puppeteer",
playable: !0,
gravity: "light",
homeworld: "Fleet of Worlds",
modifiers: { str: -2, mas: -2, con: -1, int: 2, pow: 1, dex: 1, app: 0, edu: 1, age: 0 },
notes: "Highly intelligent, cautious engineers."
},
{
name: "Dolphin",
playable: !0,
gravity: "normal",
homeworld: "Human Space Oceans",
modifiers: { str: -2, mas: 1, con: 1, int: 0, pow: 0, dex: 0, app: 0, edu: 0, age: 0 },
notes: "Aquatic specialists with enhanced endurance."
},
{
name: "Trinoc",
playable: !0,
gravity: "light",
homeworld: "Trinoc Worlds",
modifiers: { str: -1, mas: -1, con: 0, int: 1, pow: 0, dex: 1, app: 0, edu: 0, age: 0 },
notes: "Three-eyed flyers with excellent perception."
},
{
name: "Martian",
playable: !0,
gravity: "light",
homeworld: "Mars",
modifiers: { str: -1, mas: -1, con: -1, int: 1, pow: 0, dex: 1, app: 0, edu: 0, age: 0 },
notes: "Light-gravity adapted intellect-focused profile."
},
{
name: "Pierin",
playable: !0,
gravity: "normal",
homeworld: "Pierin Space",
modifiers: { str: 0, mas: 0, con: 0, int: 1, pow: 0, dex: 0, app: 1, edu: 0, age: 0 },
notes: "Socially adept, technically curious explorers."
},
{
name: "Boat People",
playable: !0,
gravity: "normal",
homeworld: "Ringworld",
modifiers: { str: 0, mas: 0, con: 1, int: 0, pow: 0, dex: 0, app: 0, edu: -1, age: 0 },
notes: "Ringworld hominids adapted to river and sea cultures."
},
{
name: "Builder",
playable: !0,
gravity: "normal",
homeworld: "Ringworld",
modifiers: { str: 1, mas: 1, con: 0, int: 0, pow: 0, dex: 0, app: -1, edu: 0, age: 0 },
notes: "Ringworld labor stock with robust build."
},
{
name: "Ghoul",
playable: !0,
gravity: "normal",
homeworld: "Ringworld",
modifiers: { str: 0, mas: 0, con: 1, int: -1, pow: 0, dex: 1, app: -2, edu: -1, age: 0 },
notes: "Scavenger subspecies with strong survival instincts."
},
{
name: "Bandersnatchi",
playable: !1,
gravity: "heavy",
homeworld: "Known Space",
modifiers: { str: 4, mas: 4, con: 3, int: 0, pow: 0, dex: -2, app: -3, edu: 0, age: 10 },
notes: "Massive engineered beings; typically GM creature profile."
}
], Pa = [
{
name: "Variable Sword",
equipped: !0,
weight: 1.5,
linkedSkill: "V. Sword, F. Laser",
attackType: "melee",
damageFormula: "1d10+1",
range: { close: "Melee", medium: "-", long: "-" },
energyUsedPerAttack: 1,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "High-energy blade weapon."
},
{
name: "Monofilament Knife",
equipped: !0,
weight: 0.2,
linkedSkill: "Archaic Melee Weapon",
attackType: "melee",
damageFormula: "1d6+1",
range: { close: "Melee", medium: "-", long: "-" },
energyUsedPerAttack: 0,
ammoUsedPerAttack: 0,
powerSource: "actor",
notes: "Fine-edge close combat blade."
},
{
name: "Shock Baton",
equipped: !0,
weight: 1.2,
linkedSkill: "Unarmed Combat",
attackType: "melee",
damageFormula: "1d8+1",
range: { close: "Melee", medium: "-", long: "-" },
energyUsedPerAttack: 1,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "Close-quarters stun baton."
},
{
name: "Flashlight Laser",
equipped: !0,
weight: 0.8,
linkedSkill: "V. Sword, F. Laser",
attackType: "ranged",
damageFormula: "1d10",
range: { close: "Short", medium: "Medium", long: "Long" },
energyUsedPerAttack: 2,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "Compact laser unit."
},
{
name: "Laser Pistol",
equipped: !0,
weight: 1.4,
linkedSkill: "Handgun, Energy",
attackType: "ranged",
damageFormula: "1d10+1",
range: { close: "Short", medium: "Medium", long: "Long" },
energyUsedPerAttack: 2,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "Common energy sidearm."
},
{
name: "Laser Rifle",
equipped: !0,
weight: 4.5,
linkedSkill: "Heavy Weapon, Energy",
attackType: "ranged",
damageFormula: "2d6+2",
range: { close: "Short", medium: "Long", long: "Extreme" },
energyUsedPerAttack: 3,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "Standard long-arm laser weapon."
},
{
name: "Stunner",
equipped: !0,
weight: 1,
linkedSkill: "Handgun, Energy",
attackType: "ranged",
damageFormula: "1d6",
range: { close: "Short", medium: "Medium", long: "Long" },
energyUsedPerAttack: 1,
ammoUsedPerAttack: 0,
powerSource: "powerPack",
notes: "Low-lethality disruption sidearm."
},
{
name: "Handgun (Projectile)",
equipped: !0,
weight: 1.2,
linkedSkill: "Handgun, Projectile",
attackType: "ranged",
damageFormula: "1d10",
range: { close: "Short", medium: "Medium", long: "Long" },
energyUsedPerAttack: 0,
ammoUsedPerAttack: 1,
powerSource: "actor",
notes: "Conventional projectile sidearm."
},
{
name: "Rifle (Projectile)",
equipped: !0,
weight: 5,
linkedSkill: "Heavy Weapon, Projectile",
attackType: "ranged",
damageFormula: "2d6",
range: { close: "Short", medium: "Long", long: "Extreme" },
energyUsedPerAttack: 0,
ammoUsedPerAttack: 1,
powerSource: "actor",
notes: "Conventional projectile rifle."
},
{
name: "Slug Thrower Carbine",
equipped: !0,
weight: 3.8,
linkedSkill: "Heavy Weapon, Projectile",
attackType: "ranged",
damageFormula: "2d6+1",
range: { close: "Short", medium: "Long", long: "Extreme" },
energyUsedPerAttack: 0,
ammoUsedPerAttack: 1,
powerSource: "actor",
notes: "Compact projectile carbine."
}
], La = [
{ name: "Cloth Vest", equipped: !0, weight: 2, value: 1, coverage: xe, notes: "Basic torso protection." },
{ name: "Soft Combat Vest", equipped: !0, weight: 4, value: 2, coverage: xe, notes: "Flexible tactical vest." },
{ name: "Combat Harness", equipped: !0, weight: 5, value: 2, coverage: { ...xe, rArm: !0, lArm: !0 }, notes: "Torso + upper arms." },
{ name: "Armored Coat", equipped: !0, weight: 7, value: 3, coverage: { ...xe, rArm: !0, lArm: !0 }, notes: "Heavy coat with arm plating." },
{ name: "Leg Guards", equipped: !0, weight: 4, value: 2, coverage: xa, notes: "Lower-body armor." },
{ name: "Arm Bracers", equipped: !0, weight: 2, value: 2, coverage: Aa, notes: "Forearm and upper arm guards." },
{ name: "Combat Helmet", equipped: !0, weight: 1.5, value: 2, coverage: Sa, notes: "Cranial protection." },
{ name: "Full Combat Suit", equipped: !0, weight: 12, value: 3, coverage: tt, notes: "Full-body armored suit." },
{ name: "Impact Suit", equipped: !0, weight: 16, value: 4, coverage: tt, notes: "High-end impact and hazard suit." }
], Ia = [
{
name: "Power Pack R20",
weight: 1,
cost: 100,
energyUse: 0,
powerSupplyNotes: "Rechargeable power pack",
isPowerPack: !0,
energy: { value: 20, max: 20 },
notes: "Standard personal battery pack."
},
{
name: "Power Pack R50",
weight: 2,
cost: 220,
energyUse: 0,
powerSupplyNotes: "Rechargeable power pack",
isPowerPack: !0,
energy: { value: 50, max: 50 },
notes: "Extended personal battery pack."
},
{
name: "Power Pack R100",
weight: 4,
cost: 400,
energyUse: 0,
powerSupplyNotes: "Rechargeable power pack",
isPowerPack: !0,
energy: { value: 100, max: 100 },
notes: "High-capacity field battery."
},
{ name: "Portable Generator", weight: 8, cost: 700, energyUse: 0, powerSupplyNotes: "Provides charging capacity", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Portable recharge generator." },
{ name: "MicroMind Unit", weight: 0.5, cost: 900, energyUse: 1, powerSupplyNotes: "Requires external power", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Portable advanced computation module." },
{ name: "Memory Bubble Reader", weight: 0.5, cost: 450, energyUse: 1, powerSupplyNotes: "Standard battery compatible", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Reads and writes memory bubbles." },
{ name: "Autodoc (Portable)", weight: 18, cost: 3500, energyUse: 6, powerSupplyNotes: "High draw medical station", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Field medical support unit." },
{ name: "Medkit", weight: 1, cost: 120, energyUse: 0, powerSupplyNotes: "None", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Manual emergency treatment supplies." },
{ name: "Bioscanner", weight: 1, cost: 300, energyUse: 1, powerSupplyNotes: "Battery or generator", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Vitals and hazard scanning tool." },
{ name: "Survey Scanner", weight: 2, cost: 500, energyUse: 2, powerSupplyNotes: "Battery or generator", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Terrain and structure analysis scanner." },
{ name: "Translator Module", weight: 0.5, cost: 650, energyUse: 1, powerSupplyNotes: "Battery compatible", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Linguistic conversion and support." },
{ name: "Holo Projector", weight: 1.5, cost: 800, energyUse: 2, powerSupplyNotes: "Battery compatible", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Short-range holographic projection." },
{ name: "Stasis Box", weight: 12, cost: 2600, energyUse: 5, powerSupplyNotes: "Continuous power required", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Suspended animation container." },
{ name: "Reactionless Flycycle", weight: 35, cost: 4200, energyUse: 4, powerSupplyNotes: "Vehicle power core", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Single-rider reactionless vehicle." },
{ name: "Field Toolkit", weight: 2, cost: 180, energyUse: 0, powerSupplyNotes: "None", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Mechanical and electronics repair kit." },
{ name: "Vac Suit", weight: 7, cost: 1400, energyUse: 1, powerSupplyNotes: "Suit battery required", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Pressure and vacuum survival suit." },
{ name: "Air Reprocessor", weight: 3, cost: 950, energyUse: 2, powerSupplyNotes: "Continuous power", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Atmosphere recycling support unit." },
{ name: "Signal Beacon", weight: 1, cost: 140, energyUse: 1, powerSupplyNotes: "Battery compatible", isPowerPack: !1, energy: { value: 0, max: 0 }, notes: "Emergency and navigation beacon." }
], be = [
{
name: "Artist",
rollRange: "01-07",
wealthValue: 0,
occupationPointsPerYear: 20,
fixedSkills: ["Athletics", "Computers", "Fast Talk", "Fine Arts", "Hide", "Musicianship", "Observe", "Perform", "Psychology", "Scent", "Theology"],
notes: "Creative specialist pursuit."
},
{
name: "Colonist",
rollRange: "08-27",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Atmospheric Craft", "Bargain", "Ground Vehicle", "Farming", "Handgun, Energy", "Personal Flyer", "Listen", "Heavy Weapon, Energy", "Observe", "Planetology", "Search", "Track"],
notes: "Settlement and frontier operations pursuit."
},
{
name: "Criminal",
rollRange: "28-29",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Bargain", "Computers", "Fast Talk", "Hide", "Personal Flyer", "Handgun, Energy", "Handgun, Projectile", "Sneak", "Unarmed Combat"],
notes: "Underground survival pursuit."
},
{
name: "Dilettante",
rollRange: "30",
wealthValue: 5,
occupationPointsPerYear: 15,
fixedSkills: [],
notes: "Any skills allowed; uses 15 occupation points per year."
},
{
name: "Engineer",
rollRange: "31-36",
wealthValue: 2,
occupationPointsPerYear: 20,
fixedSkills: ["Astronomy", "Chemistry", "Computers", "Engineering", "Ground Vehicle", "Mathematics", "Personal Flyer", "Physics", "Planetology", "Reaction Drive", "Reactionless Drive", "Repair"],
notes: "Technical design and maintenance pursuit."
},
{
name: "Entertainer",
rollRange: "37-38",
wealthValue: 2,
occupationPointsPerYear: 20,
fixedSkills: ["Athletics", "Bargain", "Own Language", "Musicianship", "Observe", "Orate", "Perform", "Psychology", "Search", "Sneak"],
notes: "Performance and social influence pursuit."
},
{
name: "Explorer",
rollRange: "39-52",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Athletics", "Atmospheric Craft", "Bargain", "Biology", "Botany", "Emergency Treatment", "Engineering", "Ground Vehicle", "Handgun, Energy", "Heavy Weapon, Energy", "Hyperdrive", "Observe", "Planetology", "Reactionless Drive", "Repair", "Search", "Track", "Zoology"],
notes: "Survey and expedition pursuit."
},
{
name: "Functionary",
rollRange: "53-56",
wealthValue: 3,
occupationPointsPerYear: 20,
fixedSkills: ["Bargain", "Debate", "Fast Talk", "History", "Law", "Observe", "Orate", "Psychology", "Strategy", "Theology"],
notes: "Administrative and governance pursuit."
},
{
name: "Journalist/Writer",
rollRange: "57-59",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Anthropology", "Bargain", "Computers", "Debate", "History", "Fine Arts", "Own Language", "Law", "Observe", "Psychology", "Search", "Sneak", "Unarmed Combat", "Weapons System"],
notes: "Investigation and reporting pursuit."
},
{
name: "Miner",
rollRange: "60-65",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Atmospheric Craft", "Aquatic Vehicle", "Bargain", "Climb (Custom)", "Computers", "Emergency Treatment", "Engineering", "Handgun, Energy", "Heavy Weapon, Energy", "Observe", "Personal Flyer", "Planetology", "Reaction Drive", "Reactionless Drive", "Repair", "Search"],
notes: "Resource extraction frontier pursuit."
},
{
name: "Pilot",
rollRange: "66-68",
wealthValue: 3,
occupationPointsPerYear: 20,
fixedSkills: ["Astronomy", "Atmospheric Craft", "Computers", "Engineering", "Hyperdrive", "History", "Law", "Mathematics", "Physics", "Reaction Drive", "Reactionless Drive", "Repair", "Strategy", "Weapons System"],
notes: "Flight and spacecraft operations pursuit."
},
{
name: "Police Officer",
rollRange: "69-76",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Atmospheric Craft", "Bargain", "Computers", "Fast Talk", "Emergency Treatment", "Handgun, Energy", "Handgun, Projectile", "Heavy Weapon, Energy", "Heavy Weapon, Projectile", "Law", "Observe", "Personal Flyer", "Psychology", "Search", "Unarmed Combat"],
notes: "Law enforcement and response pursuit."
},
{
name: "Politician",
rollRange: "77-78",
wealthValue: 3,
occupationPointsPerYear: 20,
fixedSkills: ["Bargain", "Computers", "Debate", "Fast Talk", "History", "Orate", "Own Language", "Perform", "Psychology"],
optionalSkillGroups: [
{
choose: 1,
skills: ["Engineering", "Farming", "Second Languages", "Strategy", "Theology"]
}
],
notes: "Public office and influence pursuit."
},
{
name: "Prisoner",
rollRange: "79-80",
wealthValue: 0,
occupationPointsPerYear: 20,
fixedSkills: ["Bargain", "Fast Talk", "Hide", "Observe", "Psychology", "Search", "Sneak", "Unarmed Combat"],
notes: "Carceral survival pursuit."
},
{
name: "Scholar",
rollRange: "81-84",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: [],
optionalSkillGroups: [
{
choose: 2,
skills: ["Anthropology", "Astronomy", "Biology", "Botany", "Chemistry", "Computers", "Engineering", "Fine Arts", "History", "Law", "Mathematics", "Own Language", "Physics", "Planetology", "Second Languages", "Theology", "Zoology"]
}
],
notes: "Academic pursuit; pick up to two listed skills."
},
{
name: "Scientific Researcher",
rollRange: "85-94",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: [],
optionalSkillGroups: [
{
choose: 3,
skills: ["Anthropology", "Astronomy", "Bargain", "Biology", "Botany", "Chemistry", "Computers", "Engineering", "History", "Mathematics", "Observe", "Personal Flyer", "Physics", "Planetology", "Psychology", "Repair", "Search", "Zoology"]
}
],
notes: "Research pursuit; pick up to three listed skills."
},
{
name: "Soldier",
rollRange: "95-98",
wealthValue: 1,
occupationPointsPerYear: 20,
fixedSkills: ["Athletics", "Atmospheric Craft", "Aquatic Vehicle", "Computers", "Emergency Treatment", "Fast Talk", "Ground Vehicle", "Handgun, Energy", "Handgun, Projectile", "Heavy Weapon, Energy", "Heavy Weapon, Projectile"],
notes: "Military operations pursuit."
},
{
name: "Zealot",
rollRange: "99-00",
wealthValue: 0,
occupationPointsPerYear: 20,
fixedSkills: ["Bargain", "Debate", "Fast Talk", "Fine Arts", "Handgun, Energy", "Handgun, Projectile", "Hide", "Own Language", "Law", "Strategy", "Orate", "Psychology", "Theology"],
notes: "Ideological dedication pursuit."
}
];
function St() {
return vt.filter((e) => e.playable);
}
function z(e, t) {
return `${e}:${M(t)}`;
}
function Ma(e) {
var s, i, r, l, c;
const t = (s = getDocumentClass("Item")) == null ? void 0 : s.TYPES;
if (Array.isArray(t)) return t.includes(e);
const a = (r = (i = game == null ? void 0 : game.system) == null ? void 0 : i.documentTypes) == null ? void 0 : r.Item;
if (Array.isArray(a)) return a.includes(e);
if (a && typeof a == "object") return Object.prototype.hasOwnProperty.call(a, e);
const n = (l = CONFIG == null ? void 0 : CONFIG.Item) == null ? void 0 : l.dataModels;
if (n && typeof n == "object" && Object.prototype.hasOwnProperty.call(n, e))
return !0;
const o = (c = game == null ? void 0 : game.model) == null ? void 0 : c.Item;
return !!(o && typeof o == "object" && Object.prototype.hasOwnProperty.call(o, e));
}
function Ca(e) {
return {
key: z("skill", e.name),
folderKey: "skills",
img: we(e.name) || j.skillDefault,
data: {
name: e.name,
type: "skill",
system: {
value: e.base,
category: e.category,
specialization: e.specialization ?? ""
}
}
};
}
function Ra(e) {
const t = wa(e.name) || j.speciesDefault;
return {
key: z("species", e.name),
folderKey: "species",
img: t,
data: {
name: e.name,
type: "species",
system: {
playable: e.playable,
gravity: e.gravity,
homeworld: e.homeworld,
modifiers: e.modifiers,
notes: e.notes
}
}
};
}
function $a(e) {
const t = e.attackType === "melee" ? "weaponMelee" : "weaponRanged", a = ba(e.name) || (e.attackType === "melee" ? j.weaponMelee : j.weaponRanged);
return {
key: z("weapon", e.name),
folderKey: t,
img: a,
data: {
name: e.name,
type: "weapon",
system: {
equipped: e.equipped ?? !0,
stowed: !1,
weight: e.weight ?? 0,
linkedSkill: e.linkedSkill,
linkedSkillId: "",
attackType: e.attackType,
damageFormula: e.damageFormula,
range: e.range,
energyUsedPerAttack: e.energyUsedPerAttack,
ammoUsedPerAttack: e.ammoUsedPerAttack,
powerSource: e.powerSource,
powerPackId: "",
notes: e.notes
}
}
};
}
function Ta(e) {
const t = ka(e.name) || j.armor;
return {
key: z("armor", e.name),
folderKey: "armor",
img: t,
data: {
name: e.name,
type: "armor",
system: {
equipped: e.equipped,
stowed: !1,
weight: e.weight ?? 0,
value: e.value,
coverage: e.coverage,
perLocation: {
rLeg: 0,
lLeg: 0,
abdomen: 0,
chest: 0,
rArm: 0,
lArm: 0,
head: 0
},
notes: e.notes
}
}
};
}
function Da(e) {
const t = va(e.name) || (e.isPowerPack ? j.powerPackDefault : j.gearDefault);
return {
key: z("gear", e.name),
folderKey: "gear",
img: t,
data: {
name: e.name,
type: "gear",
system: {
equipped: e.equipped ?? !0,
stowed: !1,
weight: e.weight,
cost: e.cost,
energyUse: e.energyUse,
powerSupplyNotes: e.powerSupplyNotes,
isPowerPack: e.isPowerPack,
energy: e.energy,
notes: e.notes
}
}
};
}
function Na(e) {
const t = kt(e.name) || j.pursuitDefault;
return {
key: z("pursuit", e.name),
folderKey: "pursuits",
img: t,
data: {
name: e.name,
type: "pursuit",
system: {
wealthValue: e.wealthValue,
occupationPointsPerYear: e.occupationPointsPerYear,
rollRange: e.rollRange,
fixedSkills: e.fixedSkills,
optionalSkillGroups: e.optionalSkillGroups ?? [],
notes: e.notes
}
}
};
}
function Ha(e) {
const t = e.fixedSkills.length ? `Fixed skills: ${e.fixedSkills.join(", ")}` : "Fixed skills: (none)", a = (e.optionalSkillGroups ?? []).map((o) => `Choose ${o.choose}: ${o.skills.join(", ")}`).join(" | "), n = a ? ` Optional: ${a}.` : "";
return `${e.notes} ${t}.${n} Wealth ${e.wealthValue}. Occupation points/year ${e.occupationPointsPerYear}.`;
}
function Oa(e) {
const t = kt(e.name) || j.pursuitDefault, a = `Pursuit: ${e.name}`;
return {
key: z("gear", a),
folderKey: "pursuits",
img: t,
data: {
name: a,
type: "gear",
system: {
equipped: !1,
stowed: !0,
weight: 0,
cost: 0,
energyUse: 0,
powerSupplyNotes: "Pursuit reference",
isPowerPack: !1,
energy: { value: 0, max: 0 },
notes: Ha(e)
},
flags: {
ringworld: {
pursuitData: {
pursuitName: e.name,
rollRange: e.rollRange,
wealthValue: e.wealthValue,
occupationPointsPerYear: e.occupationPointsPerYear,
fixedSkills: e.fixedSkills,
optionalSkillGroups: e.optionalSkillGroups ?? []
}
}
}
}
};
}
async function K(e, t) {
const a = game.folders.find(
(n) => {
var o;
return n.type === "Item" && n.name === e && (((o = n.folder) == null ? void 0 : o.id) ?? null) === t;
}
);
return a || Folder.create({
name: e,
type: "Item",
folder: t,
sorting: "a"
});
}
async function Ea() {
const e = await K("Ringworld Catalog", null), t = await K("Species", e.id), a = await K("Skills", e.id), n = await K("Pursuits", e.id), o = await K("Gear", e.id), s = await K("Armor", o.id), i = await K("Weapons", e.id), r = await K("Melee Weapons", i.id), l = await K("Ranged Weapons", i.id);
return {
species: t.id,
skills: a.id,
pursuits: n.id,
gear: o.id,
armor: s.id,
weaponMelee: r.id,
weaponRanged: l.id
};
}
function Fa() {
const e = Ma("pursuit");
return [
...vt.map(Ra),
...ke.map(Ca),
...e ? be.map(Na) : be.map(Oa),
...Pa.map($a),
...La.map(Ta),
...Ia.map(Da)
];
}
async function Ue(e) {
var r, l, c, u, m, g, f;
if (!((r = game.user) != null && r.isGM)) return { added: 0, updated: 0 };
const t = await Ea(), a = Fa(), n = new Map(
game.items.map((d) => [z(d.type, d.name), d])
), o = [], s = [];
for (const d of a) {
const y = t[d.folderKey], b = n.get(d.key);
if (!b) {
o.push({
...d.data,
img: d.img,
folder: y,
flags: {
ringworld: {
catalog: !0,
catalogKey: d.key
}
}
});
continue;
}
const h = { _id: b.id };
(((l = b.folder) == null ? void 0 : l.id) ?? null) !== y && (h.folder = y), String(b.img || "") !== d.img && (h.img = d.img), ((u = (c = b.flags) == null ? void 0 : c.ringworld) == null ? void 0 : u.catalog) !== !0 && (h["flags.ringworld.catalog"] = !0), ((g = (m = b.flags) == null ? void 0 : m.ringworld) == null ? void 0 : g.catalogKey) !== d.key && (h["flags.ringworld.catalogKey"] = d.key);
const p = foundry.utils.deepClone(b.system ?? {}), w = foundry.utils.mergeObject(p, d.data.system ?? {}, {
inplace: !1,
insertKeys: !0,
insertValues: !0,
overwrite: !1
}), v = foundry.utils.diffObject(p, w);
Object.keys(v).length > 0 && (h.system = w), Object.keys(h).length > 1 && s.push(h);
}
o.length && await Item.createDocuments(o), s.length && await Item.updateDocuments(s);
const i = await ya();
if (e != null && e.notify) {
const d = i ? " GM Reference journal added." : "";
(f = ui.notifications) == null || f.info(`Ringworld catalog synced: +${o.length} new, ${s.length} updated.${d}`);
}
return { added: o.length, updated: s.length };
}
function At() {
return game.items.filter((e) => e.type === "species" && e.system.playable);
}
function G(e) {
return Math.max(1, Math.min(99, Math.floor(e)));
}
async function _(e) {
const t = await ye(e);
return Number(t.total ?? 0);
}
async function Ba() {
let e = 10;
for (; ; ) {
const t = await _("1d6");
if (e += t, t <= 4) break;
}
return G(e);
}
async function Ua(e) {
const t = {
light: { str: "2d6+3", mas: "2d6+3", con: "2d6+6", dex: "2d6+9" },
normal: { str: "2d6+6", mas: "2d6+6", con: "2d6+6", dex: "2d6+6" },
heavy: { str: "2d6+9", mas: "2d6+9", con: "2d6+3", dex: "2d6+6" }
}[e];
return {
str: await _(t.str),
mas: await _(t.mas),
con: await _(t.con),
int: await _("2d6+6"),
pow: await _("2d6+6"),
dex: await _(t.dex),
app: await _("2d6+6"),
edu: await Ba(),
age: await _("1d20+16")
};
}
function Pe(e) {
return e[Math.floor(Math.random() * e.length)];
}
function qa(e) {
const t = ["Ar", "Bel", "Cor", "Den", "Ela", "Far", "Gal", "Hel", "Ira", "Jun", "Kor", "Lys", "Mor", "Nyr", "Or", "Pra", "Qua", "Rin", "Sol", "Tor", "Uri", "Val", "Wen", "Xel", "Yor", "Zen"], a = ["an", "el", "is", "or", "us", "a", "en", "ion", "eth", "al", "ir", "os"];
return `${Pe(t)}${Pe(a)} (${e})`;
}
function Ga(e, t) {
const a = (t == null ? void 0 : t.modifiers) ?? {};
return {
str: G(e.str + Number(a.str || 0)),
mas: G(e.mas + Number(a.mas || 0)),
con: G(e.con + Number(a.con || 0)),
int: G(e.int + Number(a.int || 0)),
pow: G(e.pow + Number(a.pow || 0)),
dex: G(e.dex + Number(a.dex || 0)),
app: G(e.app + Number(a.app || 0)),
edu: G(e.edu + Number(a.edu || 0)),
age: G(e.age + Number(a.age || 0))
};
}
async function xt(e) {
var m, g, f, d;
const t = String(((g = (m = e.system) == null ? void 0 : m.profile) == null ? void 0 : g.gravity) || "normal"), a = t === "light" || t === "heavy" ? t : "normal", n = String(((d = (f = e.system) == null ? void 0 : f.profile) == null ? void 0 : d.species) || ""), s = At().find((y) => y.name === n), i = St().find((y) => y.name === n), r = (s == null ? void 0 : s.system) ?? i ?? null, l = await Ua(a), c = Ga(l, r);
await e.update({
"system.characteristics.str": c.str,
"system.characteristics.mas": c.mas,
"system.characteristics.con": c.con,
"system.characteristics.int": c.int,
"system.characteristics.pow": c.pow,
"system.characteristics.dex": c.dex,
"system.characteristics.app": c.app,
"system.characteristics.edu": c.edu,
"system.characteristics.age": c.age,
"system.profile.chronologicalAge": c.age,
"system.profile.physiologicalAge": c.age
});
const u = e.items.find((y) => y.type === "skill" && y.name.toLowerCase() === "own language");
u && await e.updateEmbeddedDocuments("Item", [{
_id: u.id,
"system.value": Math.min(99, c.int * 5)
}]);
}
async function Va(e) {
const t = [
["weapon", "Laser Pistol"],
["weapon", "Variable Sword"],
["armor", "Soft Combat Vest"],
["gear", "Power Pack R20"],
["gear", "Medkit"],
["gear", "Survey Scanner"]
], a = game.items, n = new Set(e.items.map((s) => `${s.type}:${s.name.toLowerCase()}`)), o = [];
for (const [s, i] of t) {
if (n.has(`${s}:${String(i).toLowerCase()}`)) continue;
const r = a.find((l) => l.type === s && l.name === i);
r && o.push(r.toObject());
}
o.length && await e.createEmbeddedDocuments("Item", o);
}
async function Pt(e) {
var c;
const t = At(), a = St(), n = t.length ? Pe(t) : null, o = n ? null : Pe(a), s = (n == null ? void 0 : n.system) ?? o, i = (n == null ? void 0 : n.name) ?? (o == null ? void 0 : o.name) ?? "Human", r = String(s.gravity || "normal"), l = String(s.homeworld || "Ringworld");
await e.update({
name: qa(i),
"system.profile.species": i,
"system.profile.gravity": r,
"system.profile.homeworld": l
}), await xt(e), await ((c = e.ensureBaseSkills) == null ? void 0 : c.call(e)), await Va(e);
}
async function Lt() {
const t = await getDocumentClass("Actor").create({
name: "Random Explorer",
type: "explorer"
});
return await Pt(t), t;
}
const Ka = ["str", "mas", "con", "int", "pow", "dex", "app", "edu", "age"];
function S(e, t = 0) {
const a = Number(e);
return Number.isFinite(a) ? a : t;
}
function Oe(e) {
return Math.max(1, Math.min(99, Math.floor(e)));
}
function _a(e, t) {
const a = e + t;
return a <= 12 ? "-1d6" : a <= 24 ? "-1d4" : a <= 32 ? "0" : a <= 40 ? "+1d4" : a <= 56 ? "+1d6" : a <= 72 ? "+2d6" : "+3d6";
}
function at(e) {
const t = S(e == null ? void 0 : e.con, 10), a = S(e == null ? void 0 : e.int, 10), n = S(e == null ? void 0 : e.pow, 10), o = S(e == null ? void 0 : e.dex, 10);
return {
health: Math.max(0, Math.min(99, t * 5)),
reasoning: Math.max(0, Math.min(99, a * 5)),
luck: Math.max(0, Math.min(99, n * 5)),
dodge: Math.max(0, Math.min(99, o * 5))
};
}
function ja(e) {
const t = S(e == null ? void 0 : e.str, 10), a = S(e == null ? void 0 : e.dex, 10), n = S(e == null ? void 0 : e.app, 10), o = S(e == null ? void 0 : e.edu, 10), s = S(e == null ? void 0 : e.int, 10), i = S(e == null ? void 0 : e.pow, 10), r = S(e == null ? void 0 : e.con, 10);
return {
agility: Math.max(0, t + a),
communication: Math.max(0, s + n),
knowledge: Math.max(0, s + o),
perception: Math.max(0, i + r),
technical: Math.max(0, a + s)
};
}
function Wa(e) {
return e <= 4 ? 7 : e <= 8 ? 6 : e <= 12 ? 5 : e <= 16 ? 4 : e <= 20 ? 3 : e <= 24 ? 2 : 1;
}
function Ya(e) {
return e === "light" ? 0.5 : e === "heavy" ? 2 : 1;
}
function za(e) {
var t;
return e.type !== "weapon" && e.type !== "armor" && e.type !== "gear" ? !1 : ((t = e.system) == null ? void 0 : t.stowed) !== !0;
}
function Qa(e) {
var t;
return Math.max(0, S((t = e.system) == null ? void 0 : t.weight, 0));
}
function Xa(e, t) {
var y, b, h, p;
const a = String(((y = e == null ? void 0 : e.profile) == null ? void 0 : y.gravity) || "normal"), n = Ya(a), o = t.filter((w) => w.type === "weapon" || w.type === "armor" || w.type === "gear").filter(za).reduce((w, v) => w + Qa(v), 0), s = Math.max(0, o), i = s * n, r = Math.max(0, S((b = e == null ? void 0 : e.characteristics) == null ? void 0 : b.str, 0)), l = Math.max(0, i - r), c = l > 0 ? Math.ceil(l / 10) : 0, u = l > 0, m = Math.max(1, S((h = e == null ? void 0 : e.derived) == null ? void 0 : h.move, 3)), g = Math.max(1, S((p = e == null ? void 0 : e.derived) == null ? void 0 : p.run, m * 2));
return {
rawLoadKg: s,
effectiveLoadKg: i,
limitKg: r,
overLimitKg: l,
actionRankingPenalty: c,
overLimit: u,
currentMove: u ? 2 : m,
currentRun: u ? 4 : g,
gravityMultiplier: n
};
}
class Za extends Actor {
prepareDerivedData() {
if (super.prepareDerivedData(), fa(this), this.type !== "explorer" && this.type !== "creature") return;
const t = this.system ?? {}, a = t.characteristics ?? {}, n = t.profile ?? {};
n.chronologicalAge = S(n.chronologicalAge, S(a.age, 25)), n.physiologicalAge = S(n.physiologicalAge, n.chronologicalAge), t.profile = n, t.combat = t.combat ?? {}, t.combat.damageMod = _a(S(a.str, 10), S(a.mas, 10)), t.derivedRolls = t.derivedRolls ?? {};
const o = at(a);
for (const r of Object.keys(o))
t.derivedRolls[r] = o[r];
t.skillRootMax = t.skillRootMax ?? {};
const s = ja(a);
for (const [r, l] of Object.entries(s))
t.skillRootMax[r] = l;
t.derived = t.derived ?? {}, t.derived.actionRanking = Wa(S(a.dex, 10)), t.derived.move = S(t.derived.move, 3), t.derived.run = S(t.derived.run, Math.max(1, S(t.derived.move, 3) * 2)), t.encumbrance = t.encumbrance ?? {};
const i = Xa(t, this.items);
t.encumbrance.rawLoadKg = i.rawLoadKg, t.encumbrance.effectiveLoadKg = i.effectiveLoadKg, t.encumbrance.limitKg = i.limitKg, t.encumbrance.overLimitKg = i.overLimitKg, t.encumbrance.actionRankingPenalty = i.actionRankingPenalty, t.encumbrance.overLimit = i.overLimit, t.encumbrance.gravityMultiplier = i.gravityMultiplier, t.derived.currentMove = i.currentMove, t.derived.currentRun = i.currentRun, t.finance = t.finance ?? { money: 0, inBank: 0 }, t.finance.money = S(t.finance.money, 0), t.finance.inBank = S(t.finance.inBank, 0), t.notes = t.notes ?? { defects: "", habits: "" }, typeof t.sheetToolsUnlocked != "boolean" && (t.sheetToolsUnlocked = !1), t.characterBuilder = t.characterBuilder ?? {
pursuits: [],
allocations: {},
baseBySkillId: {}
}, t.unconsciousLevel = S(t.unconsciousLevel, 0);
}
get skills() {
return this.items.filter((t) => t.type === "skill");
}
get weapons() {
return this.items.filter((t) => t.type === "weapon");
}
get armors() {
return this.items.filter((t) => t.type === "armor");
}
get gears() {
return this.items.filter((t) => t.type === "gear");
}
async rollSkillById(t) {
const a = this.items.get(t);
!a || a.type !== "skill" || await Be(this, a.name, Number(a.system.value ?? 0));
}
async rollHitLocation() {
await na(this);
}
async useWeaponById(t) {
const a = this.items.get(t);
!a || a.type !== "weapon" || await bt(this, a);
}
async reloadWeaponById(t) {
const a = this.items.get(t);
!a || a.type !== "weapon" || await ra(this, a);
}
async ensureBaseSkills() {
if (this.type !== "explorer" && this.type !== "creature") return 0;
const t = new Set(
this.items.filter((n) => n.type === "skill").map((n) => M(n.name))
), a = ke.filter((n) => !t.has(M(n.name))).map((n) => ({
name: n.name,
type: "skill",
img: we(n.name),
system: {
value: n.base,
category: n.category,
specialization: n.specialization ?? ""
}
}));
return a.length ? (await this.createEmbeddedDocuments("Item", a), a.length) : 0;
}
async rollCharacteristics() {
this.type === "explorer" && await xt(this);
}
async randomizeCharacter() {
this.type === "explorer" && await Pt(this);
}
async applySpeciesItem(t) {
var y, b, h;
if (this.type !== "explorer" && this.type !== "creature") return;
const a = String((t == null ? void 0 : t.name) || "").trim(), n = (t == null ? void 0 : t.system) ?? {}, o = (n == null ? void 0 : n.modifiers) ?? {}, s = ((y = this.system) == null ? void 0 : y.speciesApplied) ?? {}, i = (s == null ? void 0 : s.modifiers) ?? {}, r = ((b = this.system) == null ? void 0 : b.characteristics) ?? {}, l = ((h = this.system) == null ? void 0 : h.profile) ?? {}, c = {}, u = {
str: 0,
mas: 0,
con: 0,
int: 0,
pow: 0,
dex: 0,
app: 0,
edu: 0,
age: 0
};
for (const p of Ka) {
const w = S(i == null ? void 0 : i[p], 0), v = S(o == null ? void 0 : o[p], 0);
u[p] = v;
const I = S(r == null ? void 0 : r[p], p === "age" ? 25 : 10) - w;
c[`system.characteristics.${p}`] = Oe(I + v);
}
const m = S(i == null ? void 0 : i.age, 0), g = u.age, f = S(l == null ? void 0 : l.chronologicalAge, S(r == null ? void 0 : r.age, 25)), d = S(l == null ? void 0 : l.physiologicalAge, f);
c["system.profile.chronologicalAge"] = Oe(f - m + g), c["system.profile.physiologicalAge"] = Oe(d - m + g), a && (c["system.profile.species"] = a), n != null && n.gravity && (c["system.profile.gravity"] = String(n.gravity)), (n == null ? void 0 : n.homeworld) !== void 0 && (c["system.profile.homeworld"] = String(n.homeworld || "")), c["system.speciesApplied"] = {
name: a,
modifiers: u
}, await this.update(c);
}
async rollDerivedCheck(t) {
var s, i, r;
if (this.type !== "explorer" && this.type !== "creature") return;
const a = {
health: "Health Roll",
reasoning: "Reasoning Roll",
luck: "Luck Roll",
dodge: "Dodge Roll"
}, n = at(((s = this.system) == null ? void 0 : s.characteristics) ?? {}), o = S((r = (i = this.system) == null ? void 0 : i.derivedRolls) == null ? void 0 : r[t], n[t]);
await Be(this, a[t], o);
}
}
class Ja extends Item {
async rollSkill() {
var a;
if (this.type !== "skill") return;
const t = this.actor;
if (!t) {
(a = ui.notifications) == null || a.warn("Skill must be owned by an Actor to roll.");
return;
}
await Be(t, this.name, Number(this.system.value ?? 0));
}
async useWeapon() {
var a;
if (this.type !== "weapon") return;
const t = this.actor;
if (!t) {
(a = ui.notifications) == null || a.warn("Weapon must be owned by an Actor to use.");
return;
}
await bt(t, this);
}
}
const en = foundry.appv1.sheets.ActorSheet, qe = {
Agility: "agility",
Communication: "communication",
Knowledge: "knowledge",
Perception: "perception",
Technical: "technical"
}, tn = {
Agility: "STR + DEX",
Communication: "INT + APP",
Knowledge: "INT + EDU",
Perception: "POW + CON",
Technical: "DEX + INT"
}, an = /* @__PURE__ */ new Set([
M("Archaic Melee Weapon"),
M("Archaic Ranged Weapons")
]), nn = M("Hyperdrive");
function fe(e, t) {
return e.name.localeCompare(t.name);
}
function L(e, t = 0) {
const a = Number(e);
return Number.isFinite(a) ? a : t;
}
function F(e, t = 0) {
return Math.max(0, Math.floor(L(e, t)));
}
function Le(e) {
return {
education: F(e == null ? void 0 : e.education, 0),
pursuits: F(e == null ? void 0 : e.pursuits, 0),
special: F(e == null ? void 0 : e.special, 0)
};
}
function on(e) {
const t = String((e == null ? void 0 : e.name) || "").trim(), a = F(e == null ? void 0 : e.years, 0);
return !t || a <= 0 ? null : { name: t, years: a };
}
function It(e) {
const t = Array.isArray(e == null ? void 0 : e.pursuits) ? e.pursuits.map((o) => on(o)).filter((o) => !!o) : [], a = {};
if (e != null && e.allocations && typeof e.allocations == "object")
for (const [o, s] of Object.entries(e.allocations)) {
if (!o) continue;
const i = Le(s);
i.education + i.pursuits + i.special <= 0 || (a[o] = i);
}
const n = {};
if (e != null && e.baseBySkillId && typeof e.baseBySkillId == "object")
for (const [o, s] of Object.entries(e.baseBySkillId))
o && (n[o] = Math.max(0, F(s, 0)));
return {
pursuits: t,
allocations: a,
baseBySkillId: n
};
}
function sn(e) {
return !an.has(M(e));
}
function rn(e) {
return M(e) !== nn;
}
function ln(e) {
const t = new Map(
be.map((n) => [M(n.name), n])
), a = /* @__PURE__ */ new Set();
for (const n of e) {
const o = t.get(M(n.name));
if (o) {
for (const s of o.fixedSkills || [])
a.add(M(s));
for (const s of o.optionalSkillGroups || [])
for (const i of s.skills || [])
a.add(M(i));
}
}
return a;
}
function cn(e) {
const t = F(e == null ? void 0 : e.age, 0), a = F(e == null ? void 0 : e.edu, 0), n = F(e == null ? void 0 : e.int, 0), o = Math.max(0, (a - 10) * 20), s = Math.max(0, t - a - 6), i = s * 20, r = Math.max(0, n * 10);
return {
educationTotal: o,
pursuitsTotal: i,
specialTotal: r,
pursuitYearsTotal: s
};
}
function Q(e, t) {
var m, g, f, d, y, b, h;
const a = cn(((m = e.system) == null ? void 0 : m.characteristics) ?? {}), n = It(((g = e.system) == null ? void 0 : g.characterBuilder) ?? {}), o = be.map((p) => p.name).sort((p, w) => p.localeCompare(w)), s = ln(n.pursuits), i = /* @__PURE__ */ new Map();
let r = 0, l = 0, c = 0;
for (const p of t) {
const w = Le(n.allocations[p.id]), v = w.education + w.pursuits + w.special, x = n.baseBySkillId[p.id], I = (f = $e(p.name)) == null ? void 0 : f.base, T = Math.max(0, L((d = p.system) == null ? void 0 : d.value, 0) - v), R = Math.max(
0,
Number.isFinite(x) ? x : I ?? T
), D = qe[String(((y = p.system) == null ? void 0 : y.category) || "")] ?? "", N = D ? Math.max(0, F((h = (b = e.system) == null ? void 0 : b.skillRootMax) == null ? void 0 : h[D], 0)) : 99, C = Math.max(0, N - R), U = M(p.name), re = sn(p.name), Z = s.has(U), H = rn(p.name);
i.set(p.id, {
allocation: w,
totalAllocated: v,
baseValue: R,
rootCap: N,
maxAllocation: C,
allowsEducation: re,
allowsPursuits: Z,
allowsSpecial: H
}), r += w.education, l += w.pursuits, c += w.special;
}
const u = n.pursuits.reduce((p, w) => p + w.years, 0);
return {
state: n,
education: {
total: a.educationTotal,
spent: r,
remaining: a.educationTotal - r
},
pursuits: {
total: a.pursuitsTotal,
spent: l,
remaining: a.pursuitsTotal - l
},
special: {
total: a.specialTotal,
spent: c,
remaining: a.specialTotal - c
},
pursuitYears: {
total: a.pursuitYearsTotal,
spent: u,
remaining: a.pursuitYearsTotal - u
},
pursuitOptions: o,
pursuitAllowedSkills: s,
bySkillId: i
};
}
function un(e, t) {
var n, o, s, i, r, l, c;
if (e.type !== "armor" || !((n = e.system) != null && n.equipped) || (o = e.system) != null && o.stowed || !((i = (s = e.system) == null ? void 0 : s.coverage) != null && i[t])) return 0;
const a = L((l = (r = e.system) == null ? void 0 : r.perLocation) == null ? void 0 : l[t], 0);
return a > 0 ? a : L((c = e.system) == null ? void 0 : c.value, 0);
}
function mn(e, t) {
var o, s, i;
const a = L((i = (s = (o = e.system) == null ? void 0 : o.hitLocations) == null ? void 0 : s[t]) == null ? void 0 : i.armor, 0), n = e.items.filter((r) => r.type === "armor").reduce((r, l) => r + un(l, t), 0);
return a + n;
}
function nt(e, t, a) {
var r, l;
const n = oe(e).entries.find((c) => c.slug === t), o = ((l = (r = e.system) == null ? void 0 : r.hitLocations) == null ? void 0 : l[t]) ?? {}, s = o.hp ?? {}, i = String(o.label ?? "").trim();
return {
slug: t,
rollRange: a,
label: i || String((n == null ? void 0 : n.label) || t),
armor: L(o.armor, 0),
totalArmor: mn(e, t),
hp: {
value: L(s.value, 0),
max: L(s.max, 0)
}
};
}
function ot(e) {
return e[Math.floor(Math.random() * e.length)];
}
class dn extends en {
isToolsUnlocked() {
var t, a;
return !!((a = (t = this.actor) == null ? void 0 : t.system) != null && a.sheetToolsUnlocked);
}
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "actor", "explorer"],
width: 930,
height: 1460,
tabs: [{ navSelector: ".tabs", contentSelector: ".sheet-body", initial: "overview" }]
});
}
get template() {
return "systems/ringworld/templates/actor/explorer-sheet.hbs";
}
async getData(t) {
var H, le, ce, ue, me, de, ge, pe, J, _e, je, We, Ye, ze, Qe, Xe;
const a = await super.getData(t), n = this.actor;
(H = game.user) != null && H.isGM && n.isOwner && await ((le = n.ensureBaseSkills) == null ? void 0 : le.call(n));
const o = n.items.filter((k) => k.type === "skill").sort(fe), s = Q(n, o), i = n.items.filter((k) => k.type === "weapon").sort(fe), r = n.items.filter((k) => k.type === "armor").sort(fe), l = n.items.filter((k) => k.type === "gear").sort(fe), c = game.items.filter((k) => k.type === "species" && k.system.playable).map((k) => k.name).sort(), u = ea(), m = /* @__PURE__ */ new Map();
for (const k of o) {
const O = M(k.name);
m.has(O) || m.set(O, k);
}
const g = n.system.skillRootMax ?? {}, f = Jt.map((k) => {
const O = qe[k] ?? k.toLowerCase(), De = ke.filter((V) => V.category === k).map((V) => {
var Ze;
const B = m.get(M(V.name)), ee = B ? s.bySkillId.get(B.id) : null;
return {
name: V.name,
base: V.base,
category: V.category,
specialization: V.specialization ?? "",
itemId: (B == null ? void 0 : B.id) ?? null,
icon: (B == null ? void 0 : B.img) || we(V.name),
value: ((Ze = B == null ? void 0 : B.system) == null ? void 0 : Ze.value) ?? V.base,
missing: !B,
allocationTotal: (ee == null ? void 0 : ee.totalAllocated) ?? 0,
allocation: (ee == null ? void 0 : ee.allocation) ?? { education: 0, pursuits: 0, special: 0 }
};
});
return {
category: k,
rootKey: O,
rootFormula: tn[k] ?? "",
rootValue: L(g[O], 0),
rows: De
};
}), d = o.filter((k) => !u.has(M(k.name))).map((k) => {
const O = s.bySkillId.get(k.id);
return {
id: k.id,
name: k.name,
system: k.system,
img: Fe(k.name, k.img || X),
allocationTotal: (O == null ? void 0 : O.totalAllocated) ?? 0,
allocation: (O == null ? void 0 : O.allocation) ?? { education: 0, pursuits: 0, special: 0 }
};
}), y = f.reduce(
(k, O) => k + O.rows.filter((De) => De.missing).length,
0
), b = oe(n), h = new Map(b.entries.map((k) => [k.slug, `${k.min}-${k.max}`])), w = b.entries.map((k) => k.slug).map(
(k) => nt(n, k, h.get(k) ?? "")
), x = b.bodyOrder.map(
(k) => nt(n, k, h.get(k) ?? "")
), I = ((ce = n.system) == null ? void 0 : ce.encumbrance) ?? {}, T = L(I.rawLoadKg, 0), R = L(I.effectiveLoadKg, T), D = L(I.limitKg, L((me = (ue = n.system) == null ? void 0 : ue.characteristics) == null ? void 0 : me.str, 0)), N = L(I.actionRankingPenalty, 0), C = L((ge = (de = n.system) == null ? void 0 : de.derived) == null ? void 0 : ge.actionRanking, 0), U = Math.max(1, C + N), re = `${T.toFixed(1)}kg on-person | ${R.toFixed(1)}kg effective / ${D.toFixed(1)}kg limit | AR +${N} (stowed ignored)`, Z = `${L((J = (pe = n.system) == null ? void 0 : pe.derived) == null ? void 0 : J.currentMove, L((je = (_e = n.system) == null ? void 0 : _e.derived) == null ? void 0 : je.move, 3))}m / ${L((Ye = (We = n.system) == null ? void 0 : We.derived) == null ? void 0 : Ye.currentRun, L((Qe = (ze = n.system) == null ? void 0 : ze.derived) == null ? void 0 : Qe.run, 6))}m`;
return {
...a,
system: n.system,
skills: o,
skillsByCategory: f,
customSkills: d,
missingBaseSkillsCount: y,
weapons: i,
armors: r,
gear: l,
speciesOptions: c,
hitLocations: w,
bodyLocations: x,
hitLocationSchemaOptions: gt(),
currentHitLocationSchema: String(n.system.hitLocationSchema || "auto"),
activeHitLocationSchemaId: b.id,
activeHitLocationSchemaLabel: b.label,
sheetToolsUnlocked: !!((Xe = n.system) != null && Xe.sheetToolsUnlocked),
baseActionRanking: C,
effectiveActionRanking: U,
encumbranceSummary: re,
movementSummary: Z,
builder: {
education: s.education,
pursuits: s.pursuits,
special: s.special,
pursuitYears: s.pursuitYears,
pursuitsList: s.state.pursuits,
pursuitOptions: s.pursuitOptions
}
};
}
async updateBuilderState(t) {
await this.actor.update({
"system.characterBuilder": {
pursuits: t.pursuits,
allocations: t.allocations,
baseBySkillId: t.baseBySkillId
}
});
}
async syncSkillsFromBuilderState(t) {
var o, s, i, r, l, c;
const a = this.actor.items.filter((u) => u.type === "skill"), n = [];
for (const u of a) {
const m = Le(t.allocations[u.id]), g = m.education + m.pursuits + m.special, f = qe[String(((o = u.system) == null ? void 0 : o.category) || "")] ?? "", d = f ? Math.max(0, F((i = (s = this.actor.system) == null ? void 0 : s.skillRootMax) == null ? void 0 : i[f], 0)) : 99;
let y = t.baseBySkillId[u.id];
if (!Number.isFinite(y)) {
const h = (r = $e(u.name)) == null ? void 0 : r.base;
y = Math.max(0, h ?? L((l = u.system) == null ? void 0 : l.value, 0) - g), t.baseBySkillId[u.id] = y;
}
const b = Math.max(0, Math.min(99, Math.min(d, y + g)));
L((c = u.system) == null ? void 0 : c.value, 0) !== b && n.push({ _id: u.id, "system.value": b });
}
n.length && await this.actor.updateEmbeddedDocuments("Item", n);
}
async addOrUpdatePursuit(t, a) {
var c;
if (!this.isToolsUnlocked()) return;
const n = String(t || "").trim(), o = Math.max(0, Math.floor(Number(a) || 0));
if (!n || o <= 0) {
(c = ui.notifications) == null || c.warn("Choose a pursuit and set years above 0.");
return;
}
const s = this.actor.items.filter((u) => u.type === "skill"), i = Q(this.actor, s), r = foundry.utils.deepClone(i.state), l = r.pursuits.findIndex((u) => M(u.name) === M(n));
l >= 0 ? r.pursuits[l].years = o : r.pursuits.push({ name: n, years: o }), await this.updateBuilderState(r);
}
async removePursuit(t) {
if (!this.isToolsUnlocked()) return;
const a = this.actor.items.filter((s) => s.type === "skill"), n = Q(this.actor, a), o = foundry.utils.deepClone(n.state);
t < 0 || t >= o.pursuits.length || (o.pursuits.splice(t, 1), await this.updateBuilderState(o));
}
async resetBuilderAllocations() {
if (!this.isToolsUnlocked()) return;
const t = this.actor.items.filter((o) => o.type === "skill"), a = Q(this.actor, t), n = foundry.utils.deepClone(a.state);
n.allocations = {}, await this.updateBuilderState(n), await this.syncSkillsFromBuilderState(n);
}
async randomizeBuilderAllocations() {
var d, y, b, h;
if (!this.isToolsUnlocked()) return;
await ((y = (d = this.actor).ensureBaseSkills) == null ? void 0 : y.call(d));
const t = this.actor.items.filter((p) => p.type === "skill").sort(fe), a = Q(this.actor, t), n = foundry.utils.deepClone(a.state), o = Math.max(0, a.pursuitYears.total), s = be.map((p) => p.name);
if (n.pursuits = [], o > 0 && s.length > 0) {
const p = Math.min(
s.length,
Math.max(1, Math.min(3, Math.floor(o / 2) || 1))
), w = [...s];
for (let x = 0; x < p && w.length; x += 1) {
const I = Math.floor(Math.random() * w.length);
n.pursuits.push({ name: w[I], years: 1 }), w.splice(I, 1);
}
let v = o - n.pursuits.length;
for (; v > 0 && n.pursuits.length; ) {
const x = ot(n.pursuits);
x.years += 1, v -= 1;
}
}
const i = It(n);
i.allocations = {};
const r = Q(
{ ...this.actor, system: { ...this.actor.system, characterBuilder: i } },
t
);
for (const p of t) {
const w = r.bySkillId.get(p.id);
w && (i.baseBySkillId[p.id] = w.baseValue, i.allocations[p.id] = { education: 0, pursuits: 0, special: 0 });
}
const l = /* @__PURE__ */ new Map();
for (const p of t)
l.set(p.id, 0);
const c = (p) => {
const w = r.bySkillId.get(p);
return w ? Math.max(0, w.maxAllocation) : 0;
}, u = (p, w, v) => {
let x = Math.max(0, p), I = 0;
for (; x > 0 && I < 3e5; ) {
I += 1;
const T = t.filter((N) => {
const C = r.bySkillId.get(N.id);
return !C || !v(N, C) ? !1 : (l.get(N.id) ?? 0) < c(N.id);
});
if (!T.length) break;
const R = ot(T), D = i.allocations[R.id] ?? { education: 0, pursuits: 0, special: 0 };
D[w] += 1, i.allocations[R.id] = D, l.set(R.id, (l.get(R.id) ?? 0) + 1), x -= 1;
}
return x;
}, m = u(
Math.max(0, r.education.total),
"education",
(p, w) => w.allowsEducation
), g = u(
Math.max(0, r.pursuits.total),
"pursuits",
(p, w) => w.allowsPursuits
), f = u(
Math.max(0, r.special.total),
"special",
(p, w) => w.allowsSpecial
);
for (const p of t) {
const w = Le(i.allocations[p.id]);
w.education + w.pursuits + w.special <= 0 && delete i.allocations[p.id];
}
await this.updateBuilderState(i), await this.syncSkillsFromBuilderState(i), m > 0 || g > 0 || f > 0 ? (b = ui.notifications) == null || b.info(
`Random build complete. Unspent points: EDU ${m}, Pursuits ${g}, Special ${f}.`
) : (h = ui.notifications) == null || h.info("Random build complete. All available points allocated.");
}
async promptSkillAllocation(t) {
var y, b, h;
if (!this.isToolsUnlocked()) return;
const a = this.actor.items.get(t);
if (!a || a.type !== "skill") return;
const n = this.actor.items.filter((p) => p.type === "skill"), o = Q(this.actor, n), s = o.bySkillId.get(t);
if (!s) return;
const i = s.allocation, r = Math.max(0, o.education.remaining + i.education), l = Math.max(0, o.pursuits.remaining + i.pursuits), c = Math.max(0, o.special.remaining + i.special), u = Math.max(0, s.maxAllocation), m = `
`, g = await new Promise((p) => {
new Dialog({
title: `${a.name} - Allocate Character Points`,
content: m,
buttons: {
save: {
label: "Apply",
callback: (w) => {
const v = w.find("form")[0];
if (!v) {
p(null);
return;
}
const x = new FormData(v);
p({
education: s.allowsEducation ? F(x.get("education"), i.education) : i.education,
pursuits: s.allowsPursuits ? F(x.get("pursuits"), i.pursuits) : i.pursuits,
special: s.allowsSpecial ? F(x.get("special"), i.special) : i.special
});
}
},
cancel: {
label: "Cancel",
callback: () => p(null)
}
},
default: "save",
close: () => p(null)
}).render(!0);
});
if (!g) return;
const f = g.education + g.pursuits + g.special;
if (f > u) {
(b = ui.notifications) == null || b.warn(`Allocation exceeds this skill's root-cap allowance (${u}).`);
return;
}
if (g.education > r || g.pursuits > l || g.special > c) {
(h = ui.notifications) == null || h.warn("Allocation exceeds remaining pool points.");
return;
}
const d = foundry.utils.deepClone(o.state);
d.baseBySkillId[a.id] = s.baseValue, f <= 0 ? delete d.allocations[a.id] : d.allocations[a.id] = g, await this.updateBuilderState(d), await this.syncSkillsFromBuilderState(d);
}
activateListeners(t) {
super.activateListeners(t), t.find(".toggle-sheet-lock").on("click", async (a) => {
var o;
a.preventDefault();
const n = !this.isToolsUnlocked();
await this.actor.update({ "system.sheetToolsUnlocked": n }), (o = ui.notifications) == null || o.info(n ? "Sheet tools unlocked." : "Sheet tools locked.");
}), t.find(".roll-characteristic").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget, o = String(n.dataset.char || "").trim().toLowerCase(), s = String(n.dataset.label || o.toUpperCase());
o && await wt(this.actor, o, s);
}), t.find(".item-create").on("click", async (a) => {
a.preventDefault();
const n = String(a.currentTarget.dataset.type || "gear"), o = { name: `New ${n}`, type: n };
n === "skill" && (o.img = X, o.system = { value: 0, category: "Technical", specialization: "" }), await this.actor.createEmbeddedDocuments("Item", [o]);
}), t.find(".item-edit").on("click", (a) => {
var s;
a.preventDefault();
const n = a.currentTarget.closest(".item"), o = n ? this.actor.items.get(n.dataset.itemId ?? "") : null;
(s = o == null ? void 0 : o.sheet) == null || s.render(!0);
}), t.find(".item-delete").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.deleteEmbeddedDocuments("Item", [n.dataset.itemId]);
}), t.find(".item-roll-skill").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.rollSkillById(n.dataset.itemId);
}), t.find(".roll-derived").on("click", async (a) => {
a.preventDefault();
const n = String(a.currentTarget.dataset.check || "");
n && await this.actor.rollDerivedCheck(n);
}), t.find(".item-use-weapon").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.useWeaponById(n.dataset.itemId);
}), t.find(".item-reload-weapon").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.reloadWeaponById(n.dataset.itemId);
}), t.find(".item-toggle-equipped").on("click", async (a) => {
var r;
a.preventDefault();
const n = a.currentTarget.closest(".item");
if (!(n != null && n.dataset.itemId)) return;
const o = this.actor.items.get(n.dataset.itemId);
if (!o) return;
const s = !((r = o.system) != null && r.equipped), i = {
_id: o.id,
"system.equipped": s
};
s && (i["system.stowed"] = !1), await this.actor.updateEmbeddedDocuments("Item", [i]);
}), t.find(".item-toggle-stowed").on("click", async (a) => {
var r;
a.preventDefault();
const n = a.currentTarget.closest(".item");
if (!(n != null && n.dataset.itemId)) return;
const o = this.actor.items.get(n.dataset.itemId);
if (!o) return;
const s = !((r = o.system) != null && r.stowed), i = {
_id: o.id,
"system.stowed": s
};
s && (i["system.equipped"] = !1), await this.actor.updateEmbeddedDocuments("Item", [i]);
}), t.find(".roll-hit-location").on("click", async (a) => {
a.preventDefault(), await this.actor.rollHitLocation();
}), t.find(".reset-conditions").on("click", async (a) => {
a.preventDefault(), await this.actor.update({
"system.conditions.prone": !1,
"system.conditions.unconscious": !1,
"system.conditions.dead": !1,
"system.conditions.dying": !1,
"system.conditions.unusableLimbs.rArm": !1,
"system.conditions.unusableLimbs.lArm": !1,
"system.conditions.unusableLimbs.rLeg": !1,
"system.conditions.unusableLimbs.lLeg": !1
});
}), t.find(".populate-base-skills").on("click", async (a) => {
var o, s;
a.preventDefault();
const n = await this.actor.ensureBaseSkills();
n > 0 ? (o = ui.notifications) == null || o.info(`Added ${n} Ringworld base skills.`) : (s = ui.notifications) == null || s.info("All Ringworld base skills are already present.");
}), t.find(".add-base-skill").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget, o = String(n.dataset.skillName || ""), s = String(n.dataset.skillCategory || ""), i = Number(n.dataset.skillBase || 0), r = String(n.dataset.skillSpecialization || "");
o && await this.actor.createEmbeddedDocuments("Item", [{
name: o,
type: "skill",
img: we(o),
system: { value: i, category: s, specialization: r }
}]);
}), t.find(".builder-add-pursuit").on("click", async (a) => {
var i, r;
a.preventDefault();
const n = a.currentTarget.closest(".rw-builder-pursuits");
if (!n) return;
const o = String(((i = n.querySelector(".builder-new-pursuit")) == null ? void 0 : i.value) || ""), s = Number(((r = n.querySelector(".builder-new-years")) == null ? void 0 : r.value) || 0);
await this.addOrUpdatePursuit(o, s);
}), t.find(".builder-update-pursuit").on("click", async (a) => {
var i, r;
a.preventDefault();
const n = a.currentTarget.closest(".builder-pursuit-row");
if (!n) return;
const o = String(((i = n.querySelector(".builder-pursuit-name")) == null ? void 0 : i.value) || ""), s = Number(((r = n.querySelector(".builder-pursuit-years")) == null ? void 0 : r.value) || 0);
await this.addOrUpdatePursuit(o, s);
}), t.find(".builder-remove-pursuit").on("click", async (a) => {
a.preventDefault();
const n = Number(a.currentTarget.dataset.index ?? -1);
!Number.isFinite(n) || n < 0 || await this.removePursuit(n);
}), t.find(".builder-reset-points").on("click", async (a) => {
var n;
a.preventDefault(), await this.resetBuilderAllocations(), (n = ui.notifications) == null || n.info("Character-builder allocations reset.");
}), t.find(".roll-characteristics").on("click", async (a) => {
var n, o, s;
a.preventDefault(), this.isToolsUnlocked() && (await ((o = (n = this.actor).rollCharacteristics) == null ? void 0 : o.call(n)), (s = ui.notifications) == null || s.info("Characteristics rolled."));
}), t.find(".builder-auto-allocate").on("click", async (a) => {
var n, o;
a.preventDefault(), this.isToolsUnlocked() && (await ((o = (n = this.actor).ensureBaseSkills) == null ? void 0 : o.call(n)), await this.randomizeBuilderAllocations());
}), t.find(".builder-skill-allocate").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item"), o = String((n == null ? void 0 : n.dataset.itemId) || "");
o && await this.promptSkillAllocation(o);
});
}
async _onDropItemCreate(t) {
var i, r, l;
const a = Array.isArray(t) ? t : [t], n = a.filter((c) => (c == null ? void 0 : c.type) === "species"), o = a.filter((c) => (c == null ? void 0 : c.type) !== "species");
for (const c of n)
await ((r = (i = this.actor).applySpeciesItem) == null ? void 0 : r.call(i, c));
if (n.length > 0) {
const c = n.map((u) => String((u == null ? void 0 : u.name) || "Species")).join(", ");
(l = ui.notifications) == null || l.info(`Applied species to actor: ${c}`);
}
if (o.length === 0) return [];
const s = o.map((c) => (c == null ? void 0 : c.type) !== "skill" ? c : {
...c,
img: Fe(String((c == null ? void 0 : c.name) || "Skill"), String((c == null ? void 0 : c.img) || ""))
});
return super._onDropItemCreate(Array.isArray(t) ? s : s[0]);
}
}
const gn = foundry.appv1.sheets.ActorSheet;
function Ge(e, t = 0) {
const a = Number(e);
return Number.isFinite(a) ? a : t;
}
function pn(e, t) {
var n, o;
if (e.type !== "armor" || !e.system.equipped || e.system.stowed || !((n = e.system.coverage) != null && n[t])) return 0;
const a = Ge((o = e.system.perLocation) == null ? void 0 : o[t]);
return a > 0 ? a : Ge(e.system.value);
}
class fn extends gn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "actor", "creature"],
width: 860,
height: 780
});
}
get template() {
return "systems/ringworld/templates/actor/creature-sheet.hbs";
}
async getData(t) {
const a = await super.getData(t), n = this.actor, o = oe(n);
return {
...a,
system: n.system,
skills: n.items.filter((s) => s.type === "skill").sort((s, i) => s.name.localeCompare(i.name)),
weapons: n.items.filter((s) => s.type === "weapon"),
armors: n.items.filter((s) => s.type === "armor"),
hitSchemaId: o.id,
hitSchemas: gt().map((s) => ({ id: s.id, label: s.label })),
hitLocations: o.entries.map((s) => {
var c;
const i = ((c = n.system.hitLocations) == null ? void 0 : c[s.slug]) ?? {}, r = Ge(i.armor), l = n.items.filter((u) => u.type === "armor").reduce((u, m) => u + pn(m, s.slug), 0);
return {
slug: s.slug,
rollRange: `${s.min}-${s.max}`,
label: s.label,
armor: r,
apTotal: r + l,
hp: i.hp ?? { value: 1, max: 1 }
};
})
};
}
activateListeners(t) {
super.activateListeners(t), t.find(".item-create").on("click", async (a) => {
a.preventDefault();
const n = String(a.currentTarget.dataset.type || "skill");
await this.actor.createEmbeddedDocuments("Item", [{ name: `New ${n}`, type: n }]);
}), t.find(".item-edit").on("click", (a) => {
var s;
a.preventDefault();
const n = a.currentTarget.closest(".item"), o = n ? this.actor.items.get(n.dataset.itemId ?? "") : null;
(s = o == null ? void 0 : o.sheet) == null || s.render(!0);
}), t.find(".item-delete").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.deleteEmbeddedDocuments("Item", [n.dataset.itemId]);
}), t.find(".item-roll-skill").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.rollSkillById(n.dataset.itemId);
}), t.find(".item-use-weapon").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.useWeaponById(n.dataset.itemId);
}), t.find(".item-reload-weapon").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget.closest(".item");
n != null && n.dataset.itemId && await this.actor.reloadWeaponById(n.dataset.itemId);
}), t.find(".roll-hit-location").on("click", async (a) => {
a.preventDefault(), await this.actor.rollHitLocation();
}), t.find(".roll-characteristic").on("click", async (a) => {
a.preventDefault();
const n = a.currentTarget, o = String(n.dataset.char || "").trim().toLowerCase(), s = String(n.dataset.label || o.toUpperCase());
o && await wt(this.actor, o, s);
}), t.find(".roll-derived").on("click", async (a) => {
a.preventDefault();
const n = String(a.currentTarget.dataset.check || "");
n && await this.actor.rollDerivedCheck(n);
}), t.find(".reset-conditions").on("click", async (a) => {
a.preventDefault(), await this.actor.update({
"system.conditions.prone": !1,
"system.conditions.unconscious": !1,
"system.conditions.dead": !1,
"system.conditions.dying": !1,
"system.conditions.unusableLimbs.rArm": !1,
"system.conditions.unusableLimbs.lArm": !1,
"system.conditions.unusableLimbs.rLeg": !1,
"system.conditions.unusableLimbs.lLeg": !1
});
}), t.find(".rw-portrait-img").on("click", (a) => {
var s, i, r;
a.preventDefault();
const n = ((r = (i = (s = foundry.applications) == null ? void 0 : s.apps) == null ? void 0 : i.FilePicker) == null ? void 0 : r.implementation) ?? globalThis.FilePicker;
new n({
type: "image",
current: this.actor.img,
callback: async (l) => {
await this.actor.update({ img: l });
}
}).render(!0);
});
}
}
const hn = foundry.appv1.sheets.ActorSheet;
class yn extends hn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "actor", "vehicle"],
width: 680,
height: 560
});
}
get template() {
return "systems/ringworld/templates/actor/vehicle-sheet.hbs";
}
async getData(t) {
return {
...await super.getData(t),
system: this.actor.system
};
}
}
const wn = foundry.appv1.sheets.ItemSheet;
class bn extends wn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "skill"],
width: 520,
height: 420
});
}
get template() {
return "systems/ringworld/templates/item/skill-sheet.hbs";
}
async getData(t) {
return {
...await super.getData(t),
system: this.item.system
};
}
activateListeners(t) {
super.activateListeners(t), t.find(".roll-skill").on("click", async (a) => {
a.preventDefault(), await this.item.rollSkill();
});
}
}
const kn = foundry.appv1.sheets.ItemSheet;
class vn extends kn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "weapon"],
width: 620,
height: 620
});
}
get template() {
return "systems/ringworld/templates/item/weapon-sheet.hbs";
}
async getData(t) {
const a = await super.getData(t), n = this.item.actor;
return {
...a,
system: this.item.system,
skills: n ? n.items.filter((o) => o.type === "skill") : [],
powerPacks: n ? n.items.filter((o) => o.type === "gear" && o.system.isPowerPack) : []
};
}
activateListeners(t) {
super.activateListeners(t), t.find(".use-weapon").on("click", async (a) => {
a.preventDefault(), await this.item.useWeapon();
});
}
}
const Sn = foundry.appv1.sheets.ItemSheet;
class An extends Sn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "armor"],
width: 620,
height: 560
});
}
get template() {
return "systems/ringworld/templates/item/armor-sheet.hbs";
}
async getData(t) {
return {
...await super.getData(t),
system: this.item.system
};
}
}
const xn = foundry.appv1.sheets.ItemSheet;
class Pn extends xn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "gear"],
width: 620,
height: 520
});
}
get template() {
return "systems/ringworld/templates/item/gear-sheet.hbs";
}
async getData(t) {
return {
...await super.getData(t),
system: this.item.system
};
}
}
const Ln = foundry.appv1.sheets.ItemSheet;
class In extends Ln {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "species"],
width: 620,
height: 560
});
}
get template() {
return "systems/ringworld/templates/item/species-sheet.hbs";
}
async getData(t) {
return {
...await super.getData(t),
system: this.item.system
};
}
}
const Mn = foundry.appv1.sheets.ItemSheet;
function st(e) {
return Array.isArray(e) ? e.map((t) => String(t)) : [];
}
class Cn extends Mn {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ringworld", "sheet", "item", "pursuit"],
width: 680,
height: 620
});
}
get template() {
return "systems/ringworld/templates/item/pursuit-sheet.hbs";
}
async getData(t) {
const a = await super.getData(t), n = this.item.system ?? {}, o = st(n.fixedSkills), s = Array.isArray(n.optionalSkillGroups) ? n.optionalSkillGroups.map((i) => ({
choose: Number((i == null ? void 0 : i.choose) ?? 1),
skills: st(i == null ? void 0 : i.skills)
})) : [];
return {
...a,
system: n,
fixedSkills: o,
optionalGroups: s
};
}
}
const Mt = "impulseState", Ve = `${P}.impulseHudPos`, Rn = [
{ value: "draw", label: "Draw / Stow Weapon" },
{ value: "aim", label: "Aim Ranged Weapon" },
{ value: "melee", label: "Melee Attack" },
{ value: "stand", label: "Stand / Recover" },
{ value: "perception", label: "Perception Skill" },
{ value: "unarmed", label: "Unarmed Combat" }
], $n = [
{ value: "fire", label: "Fire Ranged Weapon" },
{ value: "fall", label: "Fall" },
{ value: "rise", label: "Rise (Kneeling to Stand/Run)" },
{ value: "minorCustom", label: "Other Minor Action" }
];
function q(e, t = 0) {
const a = Number(e);
return Number.isFinite(a) ? a : t;
}
function W(e) {
return String(e ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
}
function Ke(e) {
return e <= 4 ? 7 : e <= 8 ? 6 : e <= 12 ? 5 : e <= 16 ? 4 : e <= 20 ? 3 : e <= 24 ? 2 : 1;
}
function Te(e) {
switch (e) {
case "draw":
return "Draw / Stow";
case "aim":
return "Aim";
case "melee":
return "Melee Attack";
case "stand":
return "Stand / Recover";
case "perception":
return "Perception";
case "unarmed":
return "Unarmed Combat";
case "fire":
return "Fire Ranged Weapon";
case "fall":
return "Fall";
case "rise":
return "Rise";
case "minorCustom":
return "Minor Action";
default:
return String(e);
}
}
function Y(e) {
var t, a, n;
return Math.max(1, q((n = (a = (t = e == null ? void 0 : e.actor) == null ? void 0 : t.system) == null ? void 0 : a.characteristics) == null ? void 0 : n.dex, 10));
}
function Ct(e) {
var a, n;
const t = q((n = (a = e == null ? void 0 : e.flags) == null ? void 0 : a[P]) == null ? void 0 : n.actionRanking, 0);
return t > 0 ? t : Ke(Y(e));
}
function Rt(e) {
var a, n, o;
const t = q((o = (n = (a = e == null ? void 0 : e.actor) == null ? void 0 : a.system) == null ? void 0 : n.encumbrance) == null ? void 0 : o.actionRankingPenalty, 0);
return Math.max(0, Math.trunc(t));
}
async function $t(e) {
var n, o;
const t = Ke(Y(e));
return q((o = (n = e == null ? void 0 : e.flags) == null ? void 0 : n[P]) == null ? void 0 : o.actionRanking, 0) !== t && await e.update({ [`flags.${P}.actionRanking`]: t }), t;
}
function se(e) {
const t = foundry.utils.deepClone(e.getFlag(P, Mt) ?? {}), a = Array.isArray(t.queue) ? t.queue : [];
return {
currentImpulse: Math.max(1, q(t.currentImpulse, 1)),
queue: a
};
}
async function ie(e, t) {
await e.setFlag(P, Mt, {
currentImpulse: Math.max(1, q(t.currentImpulse, 1)),
queue: Array.isArray(t.queue) ? t.queue : []
});
}
function te(e, t) {
return [...e].sort((a, n) => {
if (a.completeImpulse !== n.completeImpulse) return a.completeImpulse - n.completeImpulse;
const o = Y(t.combatants.get(a.combatantId));
return Y(t.combatants.get(n.combatantId)) - o;
});
}
function Se(e, t) {
const a = new Set(t.combatants.map((n) => n.id));
return e.filter((n) => a.has(n.combatantId));
}
function Tn() {
try {
const e = localStorage.getItem(Ve);
if (!e) return null;
const t = JSON.parse(e), a = q(t == null ? void 0 : t.left, NaN), n = q(t == null ? void 0 : t.top, NaN);
return !Number.isFinite(a) || !Number.isFinite(n) ? null : { left: a, top: n };
} catch {
return null;
}
}
function Dn(e) {
try {
localStorage.setItem(
Ve,
JSON.stringify({ left: Math.round(e.left), top: Math.round(e.top) })
);
} catch {
}
}
function Nn() {
try {
localStorage.removeItem(Ve);
} catch {
}
}
function Hn(e, t) {
const n = t.offsetWidth || 300, o = t.offsetHeight || 220, s = Math.max(8, window.innerWidth - n - 8), i = Math.max(8, window.innerHeight - o - 8);
return {
left: Math.min(Math.max(8, e.left), s),
top: Math.min(Math.max(8, e.top), i)
};
}
function it(e, t) {
const a = e.get(0);
if (!a) return;
const n = Hn(t, a);
e.css({
left: `${n.left}px`,
top: `${n.top}px`,
right: "auto",
bottom: "auto"
});
}
function On(e) {
const t = e.get(0);
if (!t) return;
const a = e.find(".rw-imp-mini-head");
if (!a.length) return;
const n = Tn();
n && it(e, n);
let o = !1, s = 0, i = 0, r = 0, l = 0;
a.on("mousedown", (c) => {
var g;
const u = c;
if (u.button !== 0 || (g = u.target) != null && g.closest("button")) return;
u.preventDefault();
const m = t.getBoundingClientRect();
s = u.clientX, i = u.clientY, r = m.left, l = m.top, o = !0, e.addClass("dragging"), e.css({ left: `${r}px`, top: `${l}px`, right: "auto", bottom: "auto" }), $(document).on("mousemove.ringworldImpulseHudDrag", (f) => {
if (!o) return;
const d = f, y = d.clientX - s, b = d.clientY - i;
it(e, { left: r + y, top: l + b });
}), $(document).one("mouseup.ringworldImpulseHudDrag", () => {
o = !1, e.removeClass("dragging"), $(document).off("mousemove.ringworldImpulseHudDrag");
const f = t.getBoundingClientRect();
Dn({ left: f.left, top: f.top });
});
}), a.on("dblclick", () => {
Nn(), e.css({ left: "", top: "", right: "", bottom: "" });
});
}
function Tt(e, t) {
return te(Se(t, e), e).map((a) => {
const n = e.combatants.get(a.combatantId);
return {
combatantId: a.combatantId,
name: String((n == null ? void 0 : n.name) || "Unknown"),
label: Te(a.kind),
completeImpulse: a.completeImpulse,
dex: Y(n)
};
});
}
function Dt(e, t = 8) {
return e.length ? e.slice(0, t).map((a) => `
${W(a.name)}${W(a.label)} @ ${a.completeImpulse}
`).join("") : '
No actions queued.
';
}
function Nt(e, t) {
var n;
const a = !((n = game.user) != null && n.isGM);
e.find(".rw-mini-next").prop("disabled", a).on("click", async (o) => {
o.preventDefault(), await Ie(t, "next");
}), e.find(".rw-mini-step").prop("disabled", a).on("click", async (o) => {
o.preventDefault(), await Ie(t, "step");
}), e.find(".rw-mini-reset").prop("disabled", a).on("click", async (o) => {
o.preventDefault(), await Ht(t);
});
}
function En(e) {
var s;
const t = (s = ui == null ? void 0 : ui.chat) == null ? void 0 : s.element;
if (!(t != null && t.length) || (t.find(".ringworld-impulse-chat-marker").remove(), !e)) return;
const a = se(e), n = Tt(e, a.queue), o = $(`
Impulse ${a.currentImpulse}Queued ${n.length}
${Dt(n, 5)}
`);
Nt(o, e), t.prepend(o);
}
function Fn(e) {
if ($("#ringworld-impulse-hud").remove(), !e) return;
const a = se(e), n = Tt(e, a.queue), o = $(`
Impulse ${a.currentImpulse}Queued ${n.length}
${Dt(n, 8)}
`);
Nt(o, e), $("body").append(o), On(o);
}
function E(e) {
En(e), Fn(e);
}
async function Ae() {
var e, t;
return (e = game.user) != null && e.isGM ? !0 : ((t = ui.notifications) == null || t.warn("Only the GM can modify Ringworld impulse sequencing."), !1);
}
async function rt(e, t, a, n) {
var h, p, w, v;
if (!await Ae()) return;
const o = e.combatants.get(t);
if (!o) return;
const s = se(e), i = s.currentImpulse, r = await $t(o), l = Rt(o), c = q((p = (h = o.flags) == null ? void 0 : h[P]) == null ? void 0 : p.impulseModifier, 0), u = Math.max(1, r + l), g = Math.max(1, (n ? u : 1) + c), f = i + g, d = {
id: foundry.utils.randomID(),
actorId: ((w = o.actor) == null ? void 0 : w.id) ?? null,
combatantId: t,
kind: a,
major: n,
startImpulse: i,
completeImpulse: f
}, y = Se(
s.queue.filter((x) => x.combatantId !== t),
e
);
y.push(d), await ie(e, {
currentImpulse: i,
queue: te(y, e)
}), await o.update({
[`flags.${P}.pendingEventId`]: d.id,
[`flags.${P}.pendingKind`]: a,
[`flags.${P}.actionRanking`]: r,
[`flags.${P}.effectiveActionRanking`]: u
});
const b = n ? `AR ${r} + Enc ${l}${c ? ` ${c > 0 ? "+" : ""} Imp ${c}` : ""}` : `Minor 1${c ? ` ${c > 0 ? "+" : ""} Imp ${c}` : ""}`;
(v = ui.notifications) == null || v.info(
`${o.name}: ${Te(a)} completes on impulse ${f} (${b} => ${g}).`
), E(e);
}
async function Bn(e, t) {
if (!await Ae()) return;
const a = e.combatants.get(t);
if (!a) return;
const n = se(e), o = Se(
n.queue.filter((s) => s.combatantId !== t),
e
);
await ie(e, {
currentImpulse: n.currentImpulse,
queue: te(o, e)
}), await a.update({
[`flags.${P}.pendingEventId`]: null,
[`flags.${P}.pendingKind`]: "",
[`flags.${P}.aimState`]: {
active: !1,
targetId: null,
sinceImpulse: null
}
}), E(e);
}
async function Un(e, t, a) {
var i;
const n = e.combatants.get(t.combatantId);
if (!n) return;
const o = {
[`flags.${P}.pendingEventId`]: null,
[`flags.${P}.pendingKind`]: ""
};
t.kind === "aim" && (o[`flags.${P}.aimState`] = {
active: !0,
targetId: t.targetTokenId ?? null,
sinceImpulse: a
}), await n.update(o);
const s = `
Impulse ${a} Completion
${W(n.name)} completes ${W(Te(t.kind))}.
DEX ${Y(n)} | AR ${Ct(n)}
`;
await ChatMessage.create({
user: (i = game.user) == null ? void 0 : i.id,
speaker: ChatMessage.getSpeaker({ actor: n.actor ?? void 0 }),
content: s
});
}
async function Ie(e, t) {
var c;
if (!await Ae()) return;
const a = se(e), n = te(Se(a.queue, e), e), o = a.currentImpulse;
let s = o + 1;
if (t === "next") {
const u = n.map((m) => m.completeImpulse).filter((m) => m >= o).sort((m, g) => m - g)[0];
Number.isFinite(u) && (s = u);
}
const i = n.filter((u) => u.completeImpulse === s), r = n.filter((u) => u.completeImpulse !== s);
await ie(e, {
currentImpulse: s,
queue: r
});
const l = te(i, e);
for (const u of l)
await Un(e, u, s);
l.length || (c = ui.notifications) == null || c.info(`Impulse advanced to ${s}.`), E(e);
}
async function Ht(e) {
if (await Ae()) {
await ie(e, { currentImpulse: 1, queue: [] });
for (const t of e.combatants)
await t.update({
[`flags.${P}.pendingEventId`]: null,
[`flags.${P}.pendingKind`]: "",
[`flags.${P}.aimState`]: {
active: !1,
targetId: null,
sinceImpulse: null
},
[`flags.${P}.actionRanking`]: Ke(Y(t)),
[`flags.${P}.effectiveActionRanking`]: null,
[`flags.${P}.impulseModifier`]: 0
});
E(e);
}
}
function qn(e, t) {
var u;
const a = "find" in t ? t : $(t);
if (!(a != null && a.length)) return;
a.addClass("ringworld-impulse-mode ringworld-impulse-only");
const n = (e == null ? void 0 : e.viewed) ?? game.combat;
if (!n) return;
const o = se(n), s = te(Se(o.queue, n), n);
s.length !== o.queue.length && ie(n, { currentImpulse: o.currentImpulse, queue: s }), a.find(
".token-initiative, .combatant-initiative, .initiative, [data-action='rollInitiative'], [data-control='rollInitiative'], .combatant .fa-dice-d20"
).addClass("rw-hide-initiative"), a.find(".ringworld-impulse-panel").remove();
const i = (u = game.user) != null && u.isGM ? "" : "disabled", r = n.combatants.map((m) => {
var T, R, D, N;
const g = Ct(m), f = Rt(m), d = q((R = (T = m.flags) == null ? void 0 : T[P]) == null ? void 0 : R.impulseModifier, 0), y = Math.max(1, g + f), b = Y(m), h = s.find((C) => C.combatantId === m.id), p = h ? `${Te(h.kind)} @ ${h.completeImpulse}` : "Ready", w = (N = (D = m.flags) == null ? void 0 : D[P]) == null ? void 0 : N.aimState, v = w != null && w.active ? `Aiming since ${w.sinceImpulse}` : "Not aiming", x = Rn.map((C) => {
const U = h != null && h.major && (h == null ? void 0 : h.kind) === C.value ? "selected" : "";
return ``;
}).join(""), I = $n.map((C) => {
const U = !(h != null && h.major) && (h == null ? void 0 : h.kind) === C.value ? "selected" : "";
return ``;
}).join("");
return `