System development, WIP
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
export const SYSTEM_ID = "fvtt-machine-gods-noxian-expanse"
|
||||
export const ASCII = `
|
||||
Machine Gods of the Noxian Expanse
|
||||
`
|
||||
|
||||
const dieChoiceLabels = values => Object.fromEntries(values.map(value => [value, value === "depleted" ? "Depleted" : value.toUpperCase()]))
|
||||
const keyedNameChoices = (items, key) => Object.fromEntries(items.map(item => [item[key], item.name]))
|
||||
const toIconSlug = name => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")
|
||||
const itemIcon = slug => `systems/${SYSTEM_ID}/assets/icons/${slug}.svg`
|
||||
const withItemIcons = items => items.map(item => ({ ...item, img: itemIcon(toIconSlug(item.name)) }))
|
||||
let localized = false
|
||||
|
||||
function localizeEntryLabels(entries, prefix) {
|
||||
for (const [key, entry] of Object.entries(entries)) {
|
||||
entry.label = game.i18n.localize(`${prefix}.${key}`)
|
||||
}
|
||||
}
|
||||
|
||||
function localizeChoiceLabels(entries, prefix) {
|
||||
for (const key of Object.keys(entries)) {
|
||||
entries[key] = game.i18n.localize(`${prefix}.${key}`)
|
||||
}
|
||||
}
|
||||
|
||||
export const SYSTEM = {
|
||||
id: SYSTEM_ID,
|
||||
actorTypes: {
|
||||
character: { id: "character", label: "Character" },
|
||||
creature: { id: "creature", label: "Creature" },
|
||||
companion: { id: "companion", label: "Companion" },
|
||||
},
|
||||
itemTypes: {
|
||||
weapon: { id: "weapon", label: "Weapon", icon: itemIcon("weapon") },
|
||||
armor: { id: "armor", label: "Armor", icon: itemIcon("armor") },
|
||||
shield: { id: "shield", label: "Shield", icon: itemIcon("shield") },
|
||||
equipment: { id: "equipment", label: "Equipment", icon: itemIcon("equipment") },
|
||||
"resonance-core": { id: "resonance-core", label: "Resonance Core", icon: itemIcon("resonance-core") },
|
||||
artifact: { id: "artifact", label: "Artifact", icon: itemIcon("artifact") },
|
||||
feature: { id: "feature", label: "Feature", icon: itemIcon("feature") },
|
||||
},
|
||||
abilities: {
|
||||
agility: { id: "agility", label: "Agility" },
|
||||
presence: { id: "presence", label: "Presence" },
|
||||
strength: { id: "strength", label: "Strength" },
|
||||
toughness: { id: "toughness", label: "Toughness" },
|
||||
},
|
||||
abilityOrder: ["agility", "presence", "strength", "toughness"],
|
||||
conditions: {
|
||||
bleeding: { id: "bleeding", label: "Bleeding", hasValue: true },
|
||||
blinded: { id: "blinded", label: "Blinded" },
|
||||
burning: { id: "burning", label: "Burning" },
|
||||
fatigued: { id: "fatigued", label: "Fatigued", hasValue: true },
|
||||
infected: { id: "infected", label: "Infected" },
|
||||
poisoned: { id: "poisoned", label: "Poisoned" },
|
||||
prone: { id: "prone", label: "Prone" },
|
||||
restrained: { id: "restrained", label: "Restrained" },
|
||||
starved: { id: "starved", label: "Starved" },
|
||||
stunned: { id: "stunned", label: "Stunned", hasValue: true },
|
||||
},
|
||||
usageDice: ["d12", "d10", "d8", "d6", "d4", "depleted"],
|
||||
usageDieChoices: dieChoiceLabels(["d12", "d10", "d8", "d6", "d4", "depleted"]),
|
||||
armorDice: ["d12", "d10", "d8", "d6", "d4", "d2", "0"],
|
||||
armorDieChoices: dieChoiceLabels(["d12", "d10", "d8", "d6", "d4", "d2", "0"]),
|
||||
omenDice: ["d2", "d4", "d6", "d8"],
|
||||
omenDieChoices: dieChoiceLabels(["d2", "d4", "d6", "d8"]),
|
||||
weaponCategories: {
|
||||
melee: "Melee",
|
||||
ranged: "Ranged",
|
||||
},
|
||||
resonanceList: {
|
||||
accelerate: "Accelerate",
|
||||
blast: "Blast",
|
||||
"breathe-water": "Breathe Water",
|
||||
cauterize: "Cauterize",
|
||||
"create-illusion": "Create Illusion",
|
||||
distract: "Distract",
|
||||
"eagle-eye": "Eagle Eye",
|
||||
"empower-weapon": "Empower Weapon",
|
||||
fireball: "Fireball",
|
||||
hover: "Hover",
|
||||
"influence-mind": "Influence Mind",
|
||||
"knit-flesh": "Knit Flesh",
|
||||
"light-construct": "Light Construct",
|
||||
mirage: "Mirage",
|
||||
"negate-injury": "Negate Injury",
|
||||
paralyze: "Paralyze",
|
||||
shield: "Shield",
|
||||
shock: "Shock",
|
||||
shroud: "Shroud",
|
||||
"summon-mist": "Summon Mist",
|
||||
},
|
||||
starterWeapons: withItemIcons([
|
||||
{ name: "Club", damage: "1d4", category: "melee", range: "Touch" },
|
||||
{ name: "Dagger", damage: "1d4", category: "melee", range: "Touch" },
|
||||
{ name: "Handaxe", damage: "1d6", category: "melee", range: "Touch" },
|
||||
{ name: "Quarterstaff", damage: "1d4", category: "melee", range: "Touch" },
|
||||
{ name: "Whip", damage: "1d4", category: "melee", range: "Near" },
|
||||
{ name: "Shortbow", damage: "1d6", category: "ranged", range: "Near/Far" },
|
||||
{ name: "Spear", damage: "1d6", category: "melee", range: "Near" },
|
||||
{ name: "Longsword", damage: "1d8", category: "melee", range: "Touch" },
|
||||
{ name: "Heavy Crossbow", damage: "1d10", category: "ranged", range: "Far" },
|
||||
{ name: "Rapier", damage: "1d6", category: "melee", range: "Touch" },
|
||||
{ name: "Halberd", damage: "1d10", category: "melee", range: "Near" },
|
||||
{ name: "Maul", damage: "1d10", category: "melee", range: "Touch" },
|
||||
]),
|
||||
starterArmor: withItemIcons([
|
||||
{ name: "Clothing (Average)", type: "armor", armorDie: "d2", penalty: 0 },
|
||||
{ name: "Helm", type: "armor", armorDie: "d2", penalty: 0 },
|
||||
{ name: "Medium Shield", type: "shield", armorDie: "d4", penalty: 0 },
|
||||
{ name: "Gambeson", type: "armor", armorDie: "d4", penalty: 0 },
|
||||
{ name: "Padded Leather", type: "armor", armorDie: "d4", penalty: 1 },
|
||||
{ name: "Chain Shirt", type: "armor", armorDie: "d6", penalty: 1 },
|
||||
{ name: "Half Plate", type: "armor", armorDie: "d8", penalty: 2 },
|
||||
{ name: "Full Plate", type: "armor", armorDie: "d10", penalty: 2 },
|
||||
]),
|
||||
starterEquipment: withItemIcons([
|
||||
{ name: "Rations", type: "equipment", subtype: "consumable", quantity: 1, usageDie: "d8", consumable: true },
|
||||
{ name: "Waterskin", type: "equipment", subtype: "travel", quantity: 1, usageDie: "d8", consumable: true },
|
||||
{ name: "Sack", type: "equipment", subtype: "container", quantity: 1, usageDie: "depleted", consumable: false },
|
||||
{ name: "Backpack", type: "equipment", subtype: "container", quantity: 1, usageDie: "depleted", consumable: false },
|
||||
{ name: "Rope", type: "equipment", subtype: "tool", quantity: 1, usageDie: "depleted", consumable: false },
|
||||
{ name: "Medical Supplies", type: "equipment", subtype: "tool", quantity: 1, usageDie: "d6", consumable: true },
|
||||
]),
|
||||
equipmentSubtypes: {
|
||||
gear: "Gear",
|
||||
consumable: "Consumable",
|
||||
travel: "Travel",
|
||||
container: "Container",
|
||||
tool: "Tool",
|
||||
},
|
||||
starterCores: withItemIcons([
|
||||
{ name: "Accelerate Core", type: "resonance-core", resonationId: "accelerate", usageDie: "d6" },
|
||||
{ name: "Blast Core", type: "resonance-core", resonationId: "blast", usageDie: "d6" },
|
||||
{ name: "Cauterize Core", type: "resonance-core", resonationId: "cauterize", usageDie: "d6" },
|
||||
{ name: "Empower Weapon Core", type: "resonance-core", resonationId: "empower-weapon", usageDie: "d6" },
|
||||
]),
|
||||
sampleArtifacts: withItemIcons([
|
||||
{ name: "Shiver Lens", type: "artifact", artifactId: "shiver-lens", usageDie: "d6", description: "A cracked lens that reveals hidden heat signatures." },
|
||||
{ name: "Processional Halo", type: "artifact", artifactId: "processional-halo", usageDie: "d6", description: "A floating crown of light that amplifies solemn commands." },
|
||||
{ name: "Null Forge Spike", type: "artifact", artifactId: "null-forge-spike", usageDie: "d4", description: "A ritual spike used to jam malfunctioning relics into silence." },
|
||||
{ name: "Lux Relay Idol", type: "artifact", artifactId: "lux-relay-idol", usageDie: "d6", description: "A palm-sized relay that stores and redirects ambient luminance." },
|
||||
]),
|
||||
artifactChoices: keyedNameChoices([
|
||||
{ name: "Shiver Lens", artifactId: "shiver-lens" },
|
||||
{ name: "Processional Halo", artifactId: "processional-halo" },
|
||||
{ name: "Null Forge Spike", artifactId: "null-forge-spike" },
|
||||
{ name: "Lux Relay Idol", artifactId: "lux-relay-idol" },
|
||||
], "artifactId"),
|
||||
sampleFeatures: withItemIcons([
|
||||
{ name: "Akimbo Hit Priest", type: "feature", featureId: "akimbo-hit-priest", description: "Once per round after hitting with an attack, suffer Fatigued (1) to attack again." },
|
||||
{ name: "Ambivalent Slouch", type: "feature", featureId: "ambivalent-slouch", description: "Gain +1 carrying capacity and reduce armor or shield Agility penalties by 1." },
|
||||
{ name: "Avaricious Gubbingrifter", type: "feature", featureId: "avaricious-gubbingrifter", description: "Gain three random resonance cores and -1 DR to invoking resonations." },
|
||||
{ name: "Backbiter", type: "feature", featureId: "backbiter", description: "When you win initiative, first-round attacks bypass 2d6 armor." },
|
||||
{ name: "Chart Reading Maniac", type: "feature", featureId: "chart-reading-maniac", description: "Gain an extra exploration turn per day and reroll one exploration or ruin table per day." },
|
||||
{ name: "Liturgicantal Blesswell", type: "feature", featureId: "liturgicantal-blesswell", description: "Restore d4 HP d4 times per full rest and repair one usage die by a step once per day." },
|
||||
]),
|
||||
featureChoices: keyedNameChoices([
|
||||
{ name: "Akimbo Hit Priest", featureId: "akimbo-hit-priest" },
|
||||
{ name: "Ambivalent Slouch", featureId: "ambivalent-slouch" },
|
||||
{ name: "Avaricious Gubbingrifter", featureId: "avaricious-gubbingrifter" },
|
||||
{ name: "Backbiter", featureId: "backbiter" },
|
||||
{ name: "Chart Reading Maniac", featureId: "chart-reading-maniac" },
|
||||
{ name: "Liturgicantal Blesswell", featureId: "liturgicantal-blesswell" },
|
||||
], "featureId"),
|
||||
companions: {
|
||||
noble: {
|
||||
name: "Beguiled Noble",
|
||||
hp: 6,
|
||||
morale: 9,
|
||||
armorDie: "d4",
|
||||
attackLabel: "Blade",
|
||||
attackDamage: "1d6",
|
||||
},
|
||||
mercenary: {
|
||||
name: "Dustland Mercenary",
|
||||
hp: 8,
|
||||
morale: 7,
|
||||
armorDie: "d4",
|
||||
attackLabel: "Cleaver",
|
||||
attackDamage: "1d4+2",
|
||||
},
|
||||
pickpocket: {
|
||||
name: "Scrapling Pickpocket",
|
||||
hp: 3,
|
||||
morale: 4,
|
||||
armorDie: "0",
|
||||
attackLabel: "Folding Knife",
|
||||
attackDamage: "1d2",
|
||||
},
|
||||
cantor: {
|
||||
name: "Silicon Cantor",
|
||||
hp: 4,
|
||||
morale: 6,
|
||||
armorDie: "0",
|
||||
attackLabel: "Book Thump",
|
||||
attackDamage: "1",
|
||||
},
|
||||
},
|
||||
tables: {
|
||||
eucatastrophe: [
|
||||
"Recover d4 HP.",
|
||||
"Invoke the resonation again immediately.",
|
||||
"Synchronize one additional artifact for the day.",
|
||||
"Gain -1 DR to invoking resonations for five minutes.",
|
||||
"Increase daily resonation uses by 2 for the day.",
|
||||
"Gain +1 carrying capacity for the day.",
|
||||
"Gain -4 DR to your next check within five minutes.",
|
||||
"Gain +1 max HP for the day.",
|
||||
"Recover one omen.",
|
||||
"Borrow a random nearby feature or increase a random ability by 1 until end of day."
|
||||
],
|
||||
catastrophe: [
|
||||
"You are reduced to 0 HP.",
|
||||
"The resonation targets the wrong creature.",
|
||||
"A random nearby artifact explodes.",
|
||||
"The resonation is cast twice at random targets.",
|
||||
"You become Restrained for five minutes.",
|
||||
"You are knocked Prone and suffer Stunned (2).",
|
||||
"Your worn armor is consumed.",
|
||||
"Suffer Fatigued (1), doubling if repeated the same day.",
|
||||
"Discard one omen.",
|
||||
"All artifacts desynchronize and you cannot invoke resonations for the day."
|
||||
],
|
||||
triumphs: [
|
||||
"Discover a useful resource.",
|
||||
"Gain -3 DR to your next check within five minutes.",
|
||||
"Discard a condition or recover d2 HP.",
|
||||
"Grant a nearby ally -2 DR on their next check.",
|
||||
"Ignore all penalties on your next check.",
|
||||
"Discard Prone and Restrained, then move immediately.",
|
||||
"Restore a weapon or armor usage die by one step.",
|
||||
"Take an immediate action or find 3d10 coins.",
|
||||
"Take an immediate action or gain -2 DR to your next check.",
|
||||
"Move one point from one ability to another for one hour."
|
||||
],
|
||||
mishaps: [
|
||||
"Downgrade involved equipment usage dice or suffer d4 damage bypassing armor.",
|
||||
"A hostile random creature investigates.",
|
||||
"Start an uncontrolled fire or suffer d4 damage bypassing armor.",
|
||||
"Suffer Infected.",
|
||||
"Suffer +1 DR on checks until you fully rest.",
|
||||
"You cannot invoke resonations for d8 hours.",
|
||||
"Suffer +3 DR on your next check this hour.",
|
||||
"Suffer d6 damage bypassing armor, minimum 1 HP remaining.",
|
||||
"Suffer Bleeding (1) in combat or d4 damage bypassing armor outside combat.",
|
||||
"Roll twice on the mishaps table and take both results."
|
||||
],
|
||||
breakResults: {
|
||||
1: "Unconscious for d4 rounds, then wake with d4 HP.",
|
||||
2: "As above, and a random working limb becomes useless until treated.",
|
||||
3: "As above, and without emergency treatment you die in d2 hours.",
|
||||
4: "Immediate death."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function localizeSystemConfig() {
|
||||
if (localized) return
|
||||
localized = true
|
||||
|
||||
localizeEntryLabels(SYSTEM.actorTypes, "MGNE.ActorTypes")
|
||||
localizeEntryLabels(SYSTEM.itemTypes, "MGNE.ItemTypes")
|
||||
localizeEntryLabels(SYSTEM.abilities, "MGNE.Abilities")
|
||||
localizeEntryLabels(SYSTEM.conditions, "MGNE.Conditions")
|
||||
localizeChoiceLabels(SYSTEM.weaponCategories, "MGNE.WeaponCategories")
|
||||
localizeChoiceLabels(SYSTEM.resonanceList, "MGNE.Resonations")
|
||||
localizeChoiceLabels(SYSTEM.equipmentSubtypes, "MGNE.EquipmentSubtypes")
|
||||
SYSTEM.usageDieChoices.depleted = game.i18n.localize("MGNE.Common.Depleted")
|
||||
}
|
||||
Reference in New Issue
Block a user