diff --git a/resources/ArkhamDBExport.js b/resources/ArkhamDBExport.js index e6363fe..c1f6f8a 100644 --- a/resources/ArkhamDBExport.js +++ b/resources/ArkhamDBExport.js @@ -88,16 +88,6 @@ const tag_replacements = { "": "", // Small vertical spacer }; -// TODO: handle investigator cards -const card_types = { - "AHLCG-Event-Default": "event", - "AHLCG-Skill-Default": "skill", - "AHLCG-Asset-Default": "asset", - // TODO: actually handle enemy weaknesses - "AHLCG-WeaknessEnemy-Default": "enemy", - "AHLCG-WeaknessTreachery-Default": "treachery", -}; - function int_or_null(inp) { if (inp == 'None') { return null; @@ -118,6 +108,8 @@ function replaceAll(str, search, replace) { return str.split(search).join(replace); } +function UnsupportedComponentError() {} + function build_card(component, pack_code, cycle_prefix, copies) { function substitute_tags(str) { str = str.trim(); @@ -129,108 +121,233 @@ function build_card(component, pack_code, cycle_prefix, copies) { return str; } - const code = cycle_prefix + leftPad(String(component.settings.get('CollectionNumber')), 3, '0'); + function common_data() { + const code = cycle_prefix + leftPad(String(component.settings.get('CollectionNumber')), 3, '0'); - const card_data = { - code: String(code), - deck_limit: 2, // TODO: could be derived? - flavor: substitute_tags(String(component.settings.get('Flavor'))), - illustrator: String(component.settings.get('Artist')), - is_unique: component.settings.getBoolean('Unique'), - name: substitute_tags(String(component.getName())), - pack_code: String(pack_code), - position: int_or_null(component.settings.get('CollectionNumber')), - quantity: copies, - //restrictions: null, // TODO - // TODO: should also handle "Victory" field - text: substitute_tags(String( - component.settings.get('Keywords') + '\n' + component.settings.get('Rules'))), - traits: substitute_tags(String(component.settings.get('Traits'))), - type_code: card_types[component.getFrontTemplateKey()], - xp: int_or_null(component.settings.get('Level')), - }; + return { + name: substitute_tags(String(component.getName())), + pack_code: String(pack_code), + quantity: copies, - const raw_health = component.settings.get('Stamina'); - if (raw_health && raw_health != 'None' && raw_health != '-') { - card_data.health = int_or_null(raw_health); - } - const raw_sanity = component.settings.get('Sanity'); - if (raw_sanity && raw_sanity != 'None' && raw_sanity != '-') { - card_data.sanity = int_or_null(raw_sanity); + // "Game Text" tab + traits: substitute_tags(String(component.settings.get('Traits'))), + text: substitute_tags(String( + component.settings.get('Keywords') + '\n' + component.settings.get('Rules'))), + flavor: substitute_tags(String(component.settings.get('Flavor'))), + // TODO: "Victory" field + + // "Collection" tab + code: String(code), + position: int_or_null(component.settings.get('CollectionNumber')), + + // "Portraits" tab + illustrator: String(component.settings.get('Artist')), + //restrictions: null, // TODO + }; } - const skills = { - Agility: 0, - Intellect: 0, - Combat: 0, - Willpower: 0, - Wild: 0, - }; - for (let i = 1; i<=6; i++) { - let skill_icon = component.settings.get('Skill' + i); - if (skill_icon in skills) { - skills[skill_icon] += 1; - } - } - for (let skill in skills) { - if (skills[skill] > 0) { - card_data["skill_" + skill.toLowerCase()] = skills[skill]; + function is_unique() { + if (component.settings.getBoolean('Unique')) { + return { is_unique: true }; + } else { + return {}; } } - const raw_cost = component.settings.get('ResourceCost'); - if (raw_cost) { - card_data.cost = int_or_null(raw_cost); - } - - const raw_slot = component.settings.get('Slot'); - if (raw_slot && raw_slot != 'None') { - card_data.slot = renameSlot(String(raw_slot)); - const raw_slot2 = component.settings.get('Slot2'); - if (raw_slot2 && raw_slot2 != 'None') { - card_data.slot += '. ' + renameSlot(String(raw_slot2)); + function health_and_sanity() { + const card_data = {}; + const raw_health = component.settings.get('Stamina'); + if (raw_health != 'None' && raw_health != '-') { + card_data.health = int_or_null(raw_health); } + const raw_sanity = component.settings.get('Sanity'); + if (raw_sanity != 'None' && raw_sanity != '-') { + card_data.sanity = int_or_null(raw_sanity); + } + return card_data; } - const subtitle = component.settings.get('Subtitle'); - if (subtitle && subtitle != '') { - card_data.subname = String(subtitle); + function skill_icons() { + const card_data = {}; + const skills = { + Agility: 0, + Intellect: 0, + Combat: 0, + Willpower: 0, + Wild: 0, + }; + for (let i = 1; i <= 6; i++) { + let skill_icon = component.settings.get('Skill' + i); + if (skill_icon in skills) { + skills[skill_icon] += 1; + } + } + for (let skill in skills) { + if (skills[skill] > 0) { + card_data["skill_" + skill.toLowerCase()] = skills[skill]; + } + } + + return card_data; } - const faction = component.settings.get('CardClass'); - if (faction) { + function faction() { + const faction = component.settings.get('CardClass'); if (faction == 'Weakness') { - card_data.subtype_code = "weakness"; - } - else if (faction == 'Basic Weakness') { - card_data.subtype_code = "basicweakness"; - } - else { - card_data.faction_code = String(faction).toLowerCase(); + return { + faction_code: "neutral", + subtype_code: "weakness", + }; + } else if (faction == 'BasicWeakness') { + return { + faction_code: "neutral", + subtype_code: "basicweakness", + }; + } else { + const card_data = { faction_code: String(faction).toLowerCase() }; + const faction2 = component.settings.get('CardClass2'); if (faction2 && faction2 != 'None') { card_data.faction2_code = String(faction2).toLowerCase(); } + + return card_data; } } - if (card_types[component.getFrontTemplateKey()] == 'enemy') { - // TODO: "weakness" or "basicweakness" - card_data.subtype_code = "basicweakness"; + function player_card_common() { + return Object.assign( + { + deck_limit: 2, // TODO: could be derived? + xp: int_or_null(component.settings.get('Level')), + }, + skill_icons(), + faction() + ); + } + + function cost() { + return { cost: int_or_null(component.settings.get('ResourceCost')) }; + } + + function slots() { + const card_data = {}; + const raw_slot = component.settings.get('Slot'); + if (raw_slot != 'None') { + card_data.slot = renameSlot(String(raw_slot)); + const raw_slot2 = component.settings.get('Slot2'); + if (raw_slot2 != 'None') { + card_data.slot += '. ' + renameSlot(String(raw_slot2)); + } + } + + return card_data; + } + + function subtitle() { + const subtitle = component.settings.get('Subtitle'); + if (subtitle != '') { + return { subname: String(subtitle) }; + } else { + return {}; + } + } + + function treachery_subtype() { + switch (String(component.settings.get('Subtype'))) { + // TODO: should "StoryWeakness" be different? + case 'StoryWeakness': + case 'Weakness': + return { subtype_code: "weakness" }; + case 'BasicWeakness': + return { subtype_code: "basicweakness" }; + default: + throw "Unknown Treachery Subtype:" + String(component.settings.get('Subtype')); + } + } + + function enemy() { + let subtype; + switch (component.settings.get('Subtype')) { + case "Basic Weakness": + subtype = "basicweakness"; + break; + case "Weakness": + // TODO: should these be different? + case "Investigator Weakness": + case "Story Weakness": + subtype = "weakness"; + break; + } + + return { + subtype_code: subtype, + // TODO: "per investigator" health + health: int_or_null(component.settings.get('Health')), + horror: int_or_null(component.settings.get('Horror')), + attack: int_or_null(component.settings.get('Attack')), + damage: int_or_null(component.settings.get('Damage')), + damage: int_or_null(component.settings.get('Damage')), + evade: int_or_null(component.settings.get('Evade')), + }; + } + + function order_by_keys(card_data) { + return Object.keys(card_data).sort().reduce( + function(obj, key) { + obj[key] = card_data[key]; + return obj; + }, + {} + ); } // TODO: parse out some keywords into their own fields - // order by keys - const ordered_card_data = Object.keys(card_data).sort().reduce( - function(obj, key) { - obj[key] = card_data[key]; - return obj; - }, - {} - ); - - return ordered_card_data; + println(String(component.getFrontTemplateKey())); + switch (String(component.getFrontTemplateKey())) { + case "AHLCG-Event-Default": + return order_by_keys(Object.assign( + { type_code: "event" }, + common_data(), + player_card_common(), + cost() + )); + case "AHLCG-Skill-Default": + return order_by_keys(Object.assign( + { type_code: "skill" }, + common_data(), + player_card_common() + )); + case "AHLCG-Asset-Default": + println("asdf"); + return order_by_keys(Object.assign( + { type_code: "asset" }, + common_data(), + player_card_common(), + cost(), + subtitle(), + is_unique(), + health_and_sanity(), + slots() + )); + case "AHLCG-WeaknessEnemy-Default": + return order_by_keys(Object.assign( + { type_code: "enemy", }, + common_data(), + is_unique(), + enemy() + )); + case "AHLCG-WeaknessTreachery-Default": + return order_by_keys(Object.assign( + { type_code: "treachery", }, + common_data(), + treachery_subtype() + )); + default: + println("asdfasdfasdf"); + throw new UnsupportedComponentError(); + } } function exportCard(component, file) { @@ -332,23 +449,32 @@ function run() { const cards = []; - for (let child of children) { - try { - let component = ResourceKit.getGameComponentFromFile(child.file); - if (component.getFrontTemplateKey() in card_types) { - printf("Generating JSON/PNG for '%s'...\n", child); - let copies = copyCount(copies_list, child.baseName); - let card_data = build_card(component, pack_code, cycle_prefix, copies); - cards.push(card_data); + for (let child of children) { + try { + let component = ResourceKit.getGameComponentFromFile(child.file); + let copies = copyCount(copies_list, child.baseName); + let card_data; + try { + card_data = build_card(component, pack_code, cycle_prefix, copies); + } catch (ex) { + println(ex); + if (ex instanceof UnsupportedComponentError) { + println("Skipping unsupported component: " + component.getName()); + continue; + } else { + throw ex; + } + } + printf("Generating JSON/PNG for '%s'...\n", child); + cards.push(card_data); - let export_dir = new File(deck_task.file, 'export'); - let target_file = new File(export_dir, card_data.code + '.' + FORMAT); - if (!target_file.exists() || child.file.lastModified() > target_file.lastModified()) { - printf("Image for '%s' is out of date, rebuilding...\n", child); - export_dir.mkdir(); - exportCard(component, target_file); - } - } + let export_dir = new File(deck_task.file, 'export'); + let target_file = new File(export_dir, card_data.code + '.' + FORMAT); + if (!target_file.exists() || child.file.lastModified() > target_file.lastModified()) { + printf("Image for '%s' is out of date, rebuilding...\n", child); + export_dir.mkdir(); + exportCard(component, target_file); + } } catch (ex) { println(ex); println('Error while processing ' + child.name + ', skipping file');