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") }