Refactor JSON card generation to allow for more card types

Rather than trying all settings and using what exists, declare what
should exist (via calling appropriate functions), per card type
This commit is contained in:
Adam Goldsmith 2021-10-09 22:16:24 -04:00
parent e96795030a
commit 8e3ab9e43e
1 changed files with 230 additions and 104 deletions

View File

@ -88,16 +88,6 @@ const tag_replacements = {
"<svs>": "", // 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,36 +121,54 @@ function build_card(component, pack_code, cycle_prefix, copies) {
return str;
}
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'),
return {
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
// "Game Text" tab
traits: substitute_tags(String(component.settings.get('Traits'))),
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')),
};
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
};
}
function is_unique() {
if (component.settings.getBoolean('Unique')) {
return { is_unique: true };
} else {
return {};
}
}
function health_and_sanity() {
const card_data = {};
const raw_health = component.settings.get('Stamina');
if (raw_health && raw_health != 'None' && raw_health != '-') {
if (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 != '-') {
if (raw_sanity != 'None' && raw_sanity != '-') {
card_data.sanity = int_or_null(raw_sanity);
}
return card_data;
}
function skill_icons() {
const card_data = {};
const skills = {
Agility: 0,
Intellect: 0,
@ -178,59 +188,166 @@ function build_card(component, pack_code, cycle_prefix, copies) {
}
}
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));
}
}
const subtitle = component.settings.get('Subtitle');
if (subtitle && subtitle != '') {
card_data.subname = String(subtitle);
return card_data;
}
function faction() {
const faction = component.settings.get('CardClass');
if (faction) {
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()
);
}
// TODO: parse out some keywords into their own fields
function cost() {
return { cost: int_or_null(component.settings.get('ResourceCost')) };
}
// order by keys
const ordered_card_data = Object.keys(card_data).sort().reduce(
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;
},
{}
);
}
return ordered_card_data;
// TODO: parse out some keywords into their own fields
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) {
@ -335,10 +452,20 @@ function run() {
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);
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');
@ -348,7 +475,6 @@ function run() {
export_dir.mkdir();
exportCard(component, target_file);
}
}
} catch (ex) {
println(ex);
println('Error while processing ' + child.name + ', skipping file');