Added npc generator v1
This commit is contained in:
@@ -78,7 +78,6 @@
|
|||||||
"region": "Region",
|
"region": "Region",
|
||||||
"upbringing": "Upbringing",
|
"upbringing": "Upbringing",
|
||||||
"school": "School",
|
"school": "School",
|
||||||
"schoolrank": "Rank",
|
|
||||||
"roles": "Roles",
|
"roles": "Roles",
|
||||||
"distinctions": "Distinctions",
|
"distinctions": "Distinctions",
|
||||||
"distinctionstip": "Reroll up to two dice of your choice when a distinction helps you on a check.",
|
"distinctionstip": "Reroll up to two dice of your choice when a distinction helps you on a check.",
|
||||||
@@ -519,6 +518,119 @@
|
|||||||
"generchar_disclaimer": "Warning, this will erase character's current data!",
|
"generchar_disclaimer": "Warning, this will erase character's current data!",
|
||||||
"generchar_errors": "Clear errors before continuing!"
|
"generchar_errors": "Clear errors before continuing!"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"random": "Random",
|
||||||
|
"gender": {
|
||||||
|
"title": "Gender",
|
||||||
|
"male": "Male",
|
||||||
|
"female": "Female"
|
||||||
|
},
|
||||||
|
"char_generator": {
|
||||||
|
"title": "Character Generator",
|
||||||
|
"head_bt_title": "Char. Generator",
|
||||||
|
"generate": "Generate",
|
||||||
|
"average_value": "Average value",
|
||||||
|
"attributes": "Attributes (rings, skills, confrontation ranks)",
|
||||||
|
"social": "Social standing (honor, glory, status)",
|
||||||
|
"demeanor": "Demeanor & rings affinities",
|
||||||
|
"peculiarities": "Advantages and Disadvantages",
|
||||||
|
"items": "Armure, Armes, et Objets",
|
||||||
|
"narrative": "Narrative (fluff)",
|
||||||
|
"age": "Age",
|
||||||
|
"marital_status": {
|
||||||
|
"title": "Marital Status",
|
||||||
|
"married": "Married",
|
||||||
|
"betrothed": "Betrothed",
|
||||||
|
"unmarried": "Unmarried",
|
||||||
|
"widowed": "Widowed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"clans": {
|
||||||
|
"title": "Clans",
|
||||||
|
"imperial": "Imperial",
|
||||||
|
"crab": "Crab",
|
||||||
|
"crane": "Crane",
|
||||||
|
"dragon": "Dragon",
|
||||||
|
"lion": "Lion",
|
||||||
|
"phoenix": "Phoenix",
|
||||||
|
"scorpion": "Scorpion",
|
||||||
|
"unicorn": "Unicorn",
|
||||||
|
"mantis": "Mantis",
|
||||||
|
"ronin": "Ronin",
|
||||||
|
"badger": "Badger",
|
||||||
|
"bat": "Bat",
|
||||||
|
"boar": "Boar",
|
||||||
|
"dragonfly": "Dragonfly",
|
||||||
|
"firefly": "Firefly",
|
||||||
|
"hare": "Hare",
|
||||||
|
"monkey": "Monkey",
|
||||||
|
"oriole": "Oriole",
|
||||||
|
"ox": "Ox",
|
||||||
|
"sparrow": "Sparrow",
|
||||||
|
"tortoise": "Tortoise",
|
||||||
|
"ivory_kingdoms": "Ivory Kingdoms",
|
||||||
|
"qamarist": "Qamarist",
|
||||||
|
"ujik": "Ujik"
|
||||||
|
},
|
||||||
|
"demeanor": {
|
||||||
|
"adaptable": "Adaptable",
|
||||||
|
"aggressive": "Aggressive",
|
||||||
|
"ambitious": "Ambitious",
|
||||||
|
"amiable": "Amiable",
|
||||||
|
"analytical": "Analytical",
|
||||||
|
"angry": "Angry",
|
||||||
|
"arrogant": "Arrogant",
|
||||||
|
"assertive": "Assertive",
|
||||||
|
"beguiling": "Beguiling",
|
||||||
|
"bitter": "Bitter",
|
||||||
|
"bold": "Bold",
|
||||||
|
"calculating": "Calculating",
|
||||||
|
"calm": "Calm",
|
||||||
|
"capricious": "Capricious",
|
||||||
|
"cautious": "Cautious",
|
||||||
|
"clever": "Clever",
|
||||||
|
"confused": "Confused",
|
||||||
|
"courageous": "Courageous",
|
||||||
|
"cowardly": "Cowardly",
|
||||||
|
"curious": "Curious",
|
||||||
|
"dependable": "Dependable",
|
||||||
|
"detached": "Detached",
|
||||||
|
"disheartened": "Disheartened",
|
||||||
|
"enraged": "Enraged",
|
||||||
|
"feral": "Feral",
|
||||||
|
"fickle": "Fickle",
|
||||||
|
"fierce": "Fierce",
|
||||||
|
"flighty": "Flighty",
|
||||||
|
"flippant": "Flippant",
|
||||||
|
"friendly": "Friendly",
|
||||||
|
"gruff": "Gruff",
|
||||||
|
"hungry": "Hungry",
|
||||||
|
"intense": "Intense",
|
||||||
|
"intimidating": "Intimidating",
|
||||||
|
"irritable": "Irritable",
|
||||||
|
"loyal": "Loyal",
|
||||||
|
"mischievous": "Mischievous",
|
||||||
|
"morose": "Morose",
|
||||||
|
"nurturing": "Nurturing",
|
||||||
|
"obstinate": "Obstinate",
|
||||||
|
"opportunistic": "Opportunistic",
|
||||||
|
"passionate": "Passionate",
|
||||||
|
"playful": "Playful",
|
||||||
|
"power_hungry": "Power hungry",
|
||||||
|
"proud": "Proud",
|
||||||
|
"restrained": "Restrained",
|
||||||
|
"scheming": "Scheming",
|
||||||
|
"serene": "Serene",
|
||||||
|
"serious": "Serious",
|
||||||
|
"shrewd": "Shrewd",
|
||||||
|
"stubborn": "Stubborn",
|
||||||
|
"suspicious": "Suspicious",
|
||||||
|
"teasing": "Teasing",
|
||||||
|
"territorial": "Territorial",
|
||||||
|
"uncertain": "Uncertain",
|
||||||
|
"unenthused": "Unenthused",
|
||||||
|
"vain": "Vain",
|
||||||
|
"wary": "Wary"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
"region": "Region",
|
"region": "Region",
|
||||||
"upbringing": "Upbringing",
|
"upbringing": "Upbringing",
|
||||||
"school": "Escuela",
|
"school": "Escuela",
|
||||||
"schoolrank": "Rango",
|
|
||||||
"roles": "Funciones",
|
"roles": "Funciones",
|
||||||
"distinctions": "Distinciones",
|
"distinctions": "Distinciones",
|
||||||
"distinctionstip": "Puedes volver a lanzar hasta dos dados si una distición te ayuda en la tirada.",
|
"distinctionstip": "Puedes volver a lanzar hasta dos dados si una distición te ayuda en la tirada.",
|
||||||
@@ -519,6 +518,119 @@
|
|||||||
"generchar_disclaimer": "Advertencia, esto borrará los datos actuales del personaje!",
|
"generchar_disclaimer": "Advertencia, esto borrará los datos actuales del personaje!",
|
||||||
"generchar_errors": "Borrar los errores antes de continuar!"
|
"generchar_errors": "Borrar los errores antes de continuar!"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"random": "Random",
|
||||||
|
"gender": {
|
||||||
|
"title": "Gender",
|
||||||
|
"male": "Male",
|
||||||
|
"female": "Female"
|
||||||
|
},
|
||||||
|
"char_generator": {
|
||||||
|
"title": "Character Generator",
|
||||||
|
"head_bt_title": "Char. Generator",
|
||||||
|
"generate": "Generate",
|
||||||
|
"average_value": "Average value",
|
||||||
|
"attributes": "Attributes (rings, skills, confrontation ranks)",
|
||||||
|
"social": "Social standing (honor, glory, status)",
|
||||||
|
"demeanor": "Demeanor & rings affinities",
|
||||||
|
"peculiarities": "Advantages and Disadvantages",
|
||||||
|
"items": "Armure, Armes, et Objets",
|
||||||
|
"narrative": "Narrative (fluff)",
|
||||||
|
"age": "Age",
|
||||||
|
"marital_status": {
|
||||||
|
"title": "Marital Status",
|
||||||
|
"married": "Married",
|
||||||
|
"betrothed": "Betrothed",
|
||||||
|
"unmarried": "Unmarried",
|
||||||
|
"widowed": "Widowed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"clans": {
|
||||||
|
"title": "Clans",
|
||||||
|
"imperial": "Imperial",
|
||||||
|
"crab": "Crab",
|
||||||
|
"crane": "Crane",
|
||||||
|
"dragon": "Dragon",
|
||||||
|
"lion": "Lion",
|
||||||
|
"phoenix": "Phoenix",
|
||||||
|
"scorpion": "Scorpion",
|
||||||
|
"unicorn": "Unicorn",
|
||||||
|
"mantis": "Mantis",
|
||||||
|
"ronin": "Ronin",
|
||||||
|
"badger": "Badger",
|
||||||
|
"bat": "Bat",
|
||||||
|
"boar": "Boar",
|
||||||
|
"dragonfly": "Dragonfly",
|
||||||
|
"firefly": "Firefly",
|
||||||
|
"hare": "Hare",
|
||||||
|
"monkey": "Monkey",
|
||||||
|
"oriole": "Oriole",
|
||||||
|
"ox": "Ox",
|
||||||
|
"sparrow": "Sparrow",
|
||||||
|
"tortoise": "Tortoise",
|
||||||
|
"ivory_kingdoms": "Ivory Kingdoms",
|
||||||
|
"qamarist": "Qamarist",
|
||||||
|
"ujik": "Ujik"
|
||||||
|
},
|
||||||
|
"demeanor": {
|
||||||
|
"adaptable": "Adaptable",
|
||||||
|
"aggressive": "Aggressive",
|
||||||
|
"ambitious": "Ambitious",
|
||||||
|
"amiable": "Amiable",
|
||||||
|
"analytical": "Analytical",
|
||||||
|
"angry": "Angry",
|
||||||
|
"arrogant": "Arrogant",
|
||||||
|
"assertive": "Assertive",
|
||||||
|
"beguiling": "Beguiling",
|
||||||
|
"bitter": "Bitter",
|
||||||
|
"bold": "Bold",
|
||||||
|
"calculating": "Calculating",
|
||||||
|
"calm": "Calm",
|
||||||
|
"capricious": "Capricious",
|
||||||
|
"cautious": "Cautious",
|
||||||
|
"clever": "Clever",
|
||||||
|
"confused": "Confused",
|
||||||
|
"courageous": "Courageous",
|
||||||
|
"cowardly": "Cowardly",
|
||||||
|
"curious": "Curious",
|
||||||
|
"dependable": "Dependable",
|
||||||
|
"detached": "Detached",
|
||||||
|
"disheartened": "Disheartened",
|
||||||
|
"enraged": "Enraged",
|
||||||
|
"feral": "Feral",
|
||||||
|
"fickle": "Fickle",
|
||||||
|
"fierce": "Fierce",
|
||||||
|
"flighty": "Flighty",
|
||||||
|
"flippant": "Flippant",
|
||||||
|
"friendly": "Friendly",
|
||||||
|
"gruff": "Gruff",
|
||||||
|
"hungry": "Hungry",
|
||||||
|
"intense": "Intense",
|
||||||
|
"intimidating": "Intimidating",
|
||||||
|
"irritable": "Irritable",
|
||||||
|
"loyal": "Loyal",
|
||||||
|
"mischievous": "Mischievous",
|
||||||
|
"morose": "Morose",
|
||||||
|
"nurturing": "Nurturing",
|
||||||
|
"obstinate": "Obstinate",
|
||||||
|
"opportunistic": "Opportunistic",
|
||||||
|
"passionate": "Passionate",
|
||||||
|
"playful": "Playful",
|
||||||
|
"power_hungry": "Power hungry",
|
||||||
|
"proud": "Proud",
|
||||||
|
"restrained": "Restrained",
|
||||||
|
"scheming": "Scheming",
|
||||||
|
"serene": "Serene",
|
||||||
|
"serious": "Serious",
|
||||||
|
"shrewd": "Shrewd",
|
||||||
|
"stubborn": "Stubborn",
|
||||||
|
"suspicious": "Suspicious",
|
||||||
|
"teasing": "Teasing",
|
||||||
|
"territorial": "Territorial",
|
||||||
|
"uncertain": "Uncertain",
|
||||||
|
"unenthused": "Unenthused",
|
||||||
|
"vain": "Vain",
|
||||||
|
"wary": "Wary"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
"region": "Région",
|
"region": "Région",
|
||||||
"upbringing": "Education",
|
"upbringing": "Education",
|
||||||
"school": "Ecole",
|
"school": "Ecole",
|
||||||
"schoolrank": "Rang",
|
|
||||||
"roles": "Rôles",
|
"roles": "Rôles",
|
||||||
"distinctions": "Aptitudes",
|
"distinctions": "Aptitudes",
|
||||||
"distinctionstip": "Lorsque vous effectuez un test auquel s'applique une aptitude, vous pouvez relancer jusqu'à 2 dés.",
|
"distinctionstip": "Lorsque vous effectuez un test auquel s'applique une aptitude, vous pouvez relancer jusqu'à 2 dés.",
|
||||||
@@ -519,6 +518,119 @@
|
|||||||
"generchar_disclaimer": "Attention cela écrasera les données de votre personnage actuel !",
|
"generchar_disclaimer": "Attention cela écrasera les données de votre personnage actuel !",
|
||||||
"generchar_errors": "Corriger les erreurs pour poursuivre !"
|
"generchar_errors": "Corriger les erreurs pour poursuivre !"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"random": "Aléatoire",
|
||||||
|
"gender": {
|
||||||
|
"title": "Genre",
|
||||||
|
"male": "Homme",
|
||||||
|
"female": "Femme"
|
||||||
|
},
|
||||||
|
"char_generator": {
|
||||||
|
"title": "Générateur de personnage",
|
||||||
|
"head_bt_title": "Générateur",
|
||||||
|
"generate": "Générer",
|
||||||
|
"average_value": "Valeur moyenne",
|
||||||
|
"attributes": "Attributs (anneaux, compétences, rangs de confrontation)",
|
||||||
|
"social": "Position sociale (honneur, gloire, statut)",
|
||||||
|
"demeanor": "Comportement et affinités avec les anneaux",
|
||||||
|
"peculiarities": "Avantages et désavantages",
|
||||||
|
"items": "Armure, Armes, et Objets",
|
||||||
|
"narrative": "Narration (fluff)",
|
||||||
|
"age": "Age",
|
||||||
|
"marital_status": {
|
||||||
|
"title": "État civil",
|
||||||
|
"married": "Marié(e)",
|
||||||
|
"betrothed": "Fiancé(e)",
|
||||||
|
"unmarried": "Célibataire",
|
||||||
|
"widowed": "Veuf/Veuve"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"clans": {
|
||||||
|
"title": "Clans",
|
||||||
|
"imperial": "Impérial",
|
||||||
|
"crab": "Crabe",
|
||||||
|
"crane": "Grue",
|
||||||
|
"dragon": "Dragon",
|
||||||
|
"lion": "Lion",
|
||||||
|
"phoenix": "Phénix",
|
||||||
|
"scorpion": "Scorpion",
|
||||||
|
"unicorn": "Licorne",
|
||||||
|
"mantis": "Mante",
|
||||||
|
"ronin": "Ronin",
|
||||||
|
"badger": "Blaireau",
|
||||||
|
"bat": "Chauve-souris",
|
||||||
|
"boar": "Sanglier",
|
||||||
|
"dragonfly": "Libellule",
|
||||||
|
"firefly": "Luciole",
|
||||||
|
"hare": "Lièvre",
|
||||||
|
"monkey": "Singe",
|
||||||
|
"oriole": "Loriot",
|
||||||
|
"ox": "Boeuf",
|
||||||
|
"sparrow": "Moineau",
|
||||||
|
"tortoise": "Tortue",
|
||||||
|
"ivory_kingdoms": "Royaumes d'Ivoire",
|
||||||
|
"qamarist": "Qamarist",
|
||||||
|
"ujik": "Ujik"
|
||||||
|
},
|
||||||
|
"demeanor": {
|
||||||
|
"adaptable": "Adaptable",
|
||||||
|
"aggressive": "Agressive",
|
||||||
|
"ambitious": "Ambitieuse",
|
||||||
|
"amiable": "Sympathique",
|
||||||
|
"analytical": "Réfléchie",
|
||||||
|
"angry": "Enervée",
|
||||||
|
"arrogant": "Arrogante",
|
||||||
|
"assertive": "Assurée",
|
||||||
|
"beguiling": "Séduisante",
|
||||||
|
"bitter": "Amère",
|
||||||
|
"bold": "Audacieuse",
|
||||||
|
"calculating": "Calculatrice",
|
||||||
|
"calm": "Calme",
|
||||||
|
"capricious": "Capricieuse",
|
||||||
|
"cautious": "Prudente",
|
||||||
|
"clever": "Astucieuse",
|
||||||
|
"confused": "Confuse",
|
||||||
|
"courageous": "Courageuse",
|
||||||
|
"cowardly": "Lâche",
|
||||||
|
"curious": "Curieuse",
|
||||||
|
"dependable": "Fiable",
|
||||||
|
"detached": "Détachée",
|
||||||
|
"disheartened": "Découragée",
|
||||||
|
"enraged": "Enragée",
|
||||||
|
"feral": "Sauvage",
|
||||||
|
"fickle": "Inconstante",
|
||||||
|
"fierce": "Féroce",
|
||||||
|
"flighty": "Volage",
|
||||||
|
"flippant": "Désinvolte",
|
||||||
|
"friendly": "Amicale",
|
||||||
|
"gruff": "Bourrue",
|
||||||
|
"hungry": "Affamée",
|
||||||
|
"intense": "Intense",
|
||||||
|
"intimidating": "Intimidante",
|
||||||
|
"irritable": "Irritable",
|
||||||
|
"loyal": "Fidèle",
|
||||||
|
"mischievous": "Malicieuse",
|
||||||
|
"morose": "Morose",
|
||||||
|
"nurturing": "Encourageante",
|
||||||
|
"obstinate": "Obstinée",
|
||||||
|
"opportunistic": "Opportuniste",
|
||||||
|
"passionate": "Passionnée",
|
||||||
|
"playful": "Enjouée",
|
||||||
|
"power_hungry": "Avide de pouvoir",
|
||||||
|
"proud": "Fière",
|
||||||
|
"restrained": "Restreinte",
|
||||||
|
"scheming": "Intrigante",
|
||||||
|
"serene": "Sereine",
|
||||||
|
"serious": "Sérieuse",
|
||||||
|
"shrewd": "Astucieuse",
|
||||||
|
"stubborn": "Têtue",
|
||||||
|
"suspicious": "Soupçonneuse",
|
||||||
|
"teasing": "Taquine",
|
||||||
|
"territorial": "Territoriale",
|
||||||
|
"uncertain": "Incertaine",
|
||||||
|
"unenthused": "Peu enthousiaste",
|
||||||
|
"vain": "Vaine",
|
||||||
|
"wary": "Méfiante"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,10 +130,7 @@ export class ActorL5r5e extends Actor {
|
|||||||
|
|
||||||
// No automation for npc as they cheat in stats
|
// No automation for npc as they cheat in stats
|
||||||
if (this.data.type === "character") {
|
if (this.data.type === "character") {
|
||||||
data.endurance = (Number(data.rings.earth) + Number(data.rings.fire)) * 2;
|
ActorL5r5e.computeDerivedAttributes(data);
|
||||||
data.composure = (Number(data.rings.earth) + Number(data.rings.water)) * 2;
|
|
||||||
data.focus = Number(data.rings.air) + Number(data.rings.fire);
|
|
||||||
data.vigilance = Math.ceil((Number(data.rings.air) + Number(data.rings.water)) / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attributes bars
|
// Attributes bars
|
||||||
@@ -151,6 +148,16 @@ export class ActorL5r5e extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set derived attributes (endurance, composure, focus, vigilance) from rings values
|
||||||
|
*/
|
||||||
|
static computeDerivedAttributes(data) {
|
||||||
|
data.endurance = (Number(data.rings.earth) + Number(data.rings.fire)) * 2;
|
||||||
|
data.composure = (Number(data.rings.earth) + Number(data.rings.water)) * 2;
|
||||||
|
data.focus = Number(data.rings.air) + Number(data.rings.fire);
|
||||||
|
data.vigilance = Math.ceil((Number(data.rings.air) + Number(data.rings.water)) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a Ring/Skill point to the current actor if the item is a advancement
|
* Add a Ring/Skill point to the current actor if the item is a advancement
|
||||||
* @param {Item} item
|
* @param {Item} item
|
||||||
|
|||||||
111
system/scripts/actors/character-generator-dialog.js
Normal file
111
system/scripts/actors/character-generator-dialog.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { CharacterGenerator } from "./character-generator.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* L5R NPC Generator form
|
||||||
|
*
|
||||||
|
* @extends {FormApplication}
|
||||||
|
*/
|
||||||
|
export class CharacterGeneratorDialog extends FormApplication {
|
||||||
|
/**
|
||||||
|
* Current actor data
|
||||||
|
*/
|
||||||
|
actor = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload Object
|
||||||
|
*/
|
||||||
|
object = {
|
||||||
|
avg_rings: 3,
|
||||||
|
clan: "random",
|
||||||
|
gender: "random",
|
||||||
|
generateAttributes: true,
|
||||||
|
generateDemeanor: true,
|
||||||
|
generateName: true,
|
||||||
|
generateNarrative: true,
|
||||||
|
generatePeculiarities: true,
|
||||||
|
generateItems: true,
|
||||||
|
generateSocial: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign the default options
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
static get defaultOptions() {
|
||||||
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||||
|
id: "l5r5e-character-generator-dialog",
|
||||||
|
classes: ["l5r5e", "character-generator-dialog"],
|
||||||
|
template: CONFIG.l5r5e.paths.templates + "actors/character-generator-dialog.html",
|
||||||
|
title: game.i18n.localize("l5r5e.char_generator.title"),
|
||||||
|
// width: 600,
|
||||||
|
// height: 360,
|
||||||
|
resizable: false,
|
||||||
|
closeOnSubmit: false,
|
||||||
|
submitOnClose: false,
|
||||||
|
submitOnChange: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a unique and dynamic element ID for the rendered ActorSheet application
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
|
return `l5r5e-npc-generator-dialog-${this.actor.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create dialog
|
||||||
|
*/
|
||||||
|
constructor(actor = null, options = {}) {
|
||||||
|
super({}, options);
|
||||||
|
this.actor = actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct and return the data object used to render the HTML template for this form application.
|
||||||
|
* @param options
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
async getData(options = null) {
|
||||||
|
const clans = Object.keys(CharacterGenerator.clansAndFamilies).map((e) => ({
|
||||||
|
id: e,
|
||||||
|
label: game.i18n.localize("l5r5e.clans." + e),
|
||||||
|
}));
|
||||||
|
return {
|
||||||
|
...super.getData(options),
|
||||||
|
isNpc: this.actor.type === "npc",
|
||||||
|
clanList: [{ id: "random", label: game.i18n.localize("l5r5e.random") }, ...clans],
|
||||||
|
genderList: [
|
||||||
|
{ id: "random", label: game.i18n.localize("l5r5e.random") },
|
||||||
|
{ id: "male", label: game.i18n.localize("l5r5e.gender.male") },
|
||||||
|
{ id: "female", label: game.i18n.localize("l5r5e.gender.female") },
|
||||||
|
],
|
||||||
|
data: this.object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called upon form submission after form data is validated
|
||||||
|
* @param event The initial triggering submission event
|
||||||
|
* @param formData The object of validated form data with which to update the object
|
||||||
|
* @returns A Promise which resolves once the update operation has completed
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
// Generate datas
|
||||||
|
const generator = new CharacterGenerator({
|
||||||
|
avgRingsValue: formData.avg_rings,
|
||||||
|
clanName: formData.clan,
|
||||||
|
gender: formData.gender,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update current Object with new data to keep selection
|
||||||
|
this.object = formData;
|
||||||
|
|
||||||
|
// Update actor with selection
|
||||||
|
const updatedDatas = await generator.toActor(this.actor, formData);
|
||||||
|
await this.actor.update(updatedDatas);
|
||||||
|
|
||||||
|
this.render(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
522
system/scripts/actors/character-generator.js
Normal file
522
system/scripts/actors/character-generator.js
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
/**
|
||||||
|
* L5R Character generator base object
|
||||||
|
*/
|
||||||
|
export class CharacterGenerator {
|
||||||
|
//<editor-fold desc="Config Datas">
|
||||||
|
static clansAndFamilies = {
|
||||||
|
// Majors
|
||||||
|
imperial: ["Miya", "Otomo", "Seppun"],
|
||||||
|
crab: ["Hida", "Kaiu", "Hiruma", "Yasuki", "Kuni"],
|
||||||
|
crane: ["Asahina", "Daidoji", "Doji", "Kakita"],
|
||||||
|
dragon: ["Kitsuki", "Mirumoto", "Togashi"],
|
||||||
|
lion: ["Akodo", "Ikoma", "Kitsu", "Matsu"],
|
||||||
|
phoenix: ["Agasha", "Asako", "Isawa", "Shiba"],
|
||||||
|
scorpion: ["Bayushi", "Shosuro", "Soshi", "Yogo"],
|
||||||
|
unicorn: ["Ide", "Iuchi", "Moto", "Shinjo", "Utaku"],
|
||||||
|
mantis: ["(mantis)"], // no family name, boat name
|
||||||
|
|
||||||
|
// Minors
|
||||||
|
ronin: ["(ronin)"], // can be anything
|
||||||
|
badger: ["Ichiro"],
|
||||||
|
bat: ["Komori"],
|
||||||
|
boar: ["Heichi"],
|
||||||
|
dragonfly: ["Tonbo"],
|
||||||
|
firefly: ["Hotaru"],
|
||||||
|
hare: ["Ujina", "Usagi"],
|
||||||
|
monkey: ["Toku", "Fuzake"],
|
||||||
|
oriole: ["Tsi"],
|
||||||
|
ox: ["Morito"],
|
||||||
|
sparrow: ["Suzume"],
|
||||||
|
tortoise: ["Kasuga"],
|
||||||
|
// ivory_kingdoms
|
||||||
|
// qamarist
|
||||||
|
// ujik
|
||||||
|
};
|
||||||
|
|
||||||
|
static demeanorList = [
|
||||||
|
{ id: "adaptable", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "adaptable", mod: { water: 2, earth: -2 } },
|
||||||
|
{ id: "aggressive", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "aggressive", mod: { fire: 2, water: -2 } },
|
||||||
|
{ id: "ambitious", mod: { fire: 2, water: -2 } },
|
||||||
|
{ id: "amiable", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "analytical", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "angry", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "arrogant", mod: { fire: 2, water: -2 } },
|
||||||
|
{ id: "assertive", mod: { earth: 2, air: -2 } },
|
||||||
|
{ id: "assertive", mod: { earth: 2, air: 2 } },
|
||||||
|
{ id: "beguiling", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "beguiling", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "bitter", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "bold", mod: { fire: 1, earth: -1 } },
|
||||||
|
{ id: "calculating", mod: { air: 2, fire: -2 } },
|
||||||
|
{ id: "calm", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "capricious", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "cautious", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "clever", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "confused", mod: { fire: 1, void: 1, air: -2 } },
|
||||||
|
{ id: "courageous", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "cowardly", mod: { earth: 2, fire: -2 } },
|
||||||
|
{ id: "curious", mod: { earth: 1, void: -2 } },
|
||||||
|
{ id: "curious", mod: { fire: 1, void: 1, air: -2 } },
|
||||||
|
{ id: "dependable", mod: { fire: 1, water: 1, earth: -2 } },
|
||||||
|
{ id: "detached", mod: { earth: 1, fire: 1, void: -2 } },
|
||||||
|
{ id: "disheartened", mod: { fire: 1, earth: -1 } },
|
||||||
|
{ id: "enraged", mod: { air: 1, fire: -2 } },
|
||||||
|
{ id: "feral", mod: { air: 2, fire: -2 } },
|
||||||
|
{ id: "fickle", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "fierce", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "flighty", mod: { air: 2, fire: -2 } },
|
||||||
|
{ id: "flighty", mod: { water: 2, fire: -2 } },
|
||||||
|
{ id: "flippant", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "friendly", mod: { fire: 1, earth: -2, water: -2 } },
|
||||||
|
{ id: "gruff", mod: { water: 2, earth: -2 } },
|
||||||
|
{ id: "hungry", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "intense", mod: { air: 2, water: -2 } },
|
||||||
|
{ id: "intense", mod: { fire: 2, water: -2 } },
|
||||||
|
{ id: "intimidating", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "irritable", mod: { fire: 2, air: -1, water: -1 } },
|
||||||
|
{ id: "loyal", mod: { air: 1, earth: -2, fire: -2 } },
|
||||||
|
{ id: "loyal", mod: { water: 2, fire: -2 } },
|
||||||
|
{ id: "mischievous", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "mischievous", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "mischievous", mod: { earth: 2, fire: -2 } },
|
||||||
|
{ id: "morose", mod: { water: 2, fire: -2 } },
|
||||||
|
{ id: "nurturing", mod: { earth: 2, fire: -2 } },
|
||||||
|
{ id: "obstinate", mod: { earth: 2, air: -2 } },
|
||||||
|
{ id: "obstinate", mod: { water: 2, air: -2 } },
|
||||||
|
{ id: "opportunistic", mod: { water: 2, fire: -2 } },
|
||||||
|
{ id: "passionate", mod: { earth: 2, air: -2 } },
|
||||||
|
{ id: "playful", mod: { earth: 2, water: -2 } },
|
||||||
|
{ id: "playful", mod: { fire: 1, air: 1, void: -2 } },
|
||||||
|
{ id: "power_hungry", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "proud", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "restrained", mod: { earth: 2, air: -2 } },
|
||||||
|
{ id: "scheming", mod: { air: 2, void: -2 } },
|
||||||
|
{ id: "serene", mod: { fire: 2, void: -2 } },
|
||||||
|
{ id: "serene", mod: { void: 2, fire: -2 } },
|
||||||
|
{ id: "serious", mod: { fire: 2, earth: -2 } },
|
||||||
|
{ id: "shrewd", mod: { air: 2, fire: -2 } },
|
||||||
|
{ id: "stubborn", mod: { earth: 2, water: -2 } },
|
||||||
|
{ id: "suspicious", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "teasing", mod: { air: 2, earth: -2 } },
|
||||||
|
{ id: "territorial", mod: { fire: 2, air: -2 } },
|
||||||
|
{ id: "uncertain", mod: { air: 2, fire: -2 } },
|
||||||
|
{ id: "unenthused", mod: { earth: 2, fire: -2 } },
|
||||||
|
{ id: "vain", mod: { earth: 2, air: -2 } },
|
||||||
|
{ id: "wary", mod: { earth: 2, fire: -2 } },
|
||||||
|
];
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload Object
|
||||||
|
*/
|
||||||
|
data = {
|
||||||
|
avgRingsValue: 3, // 1-5
|
||||||
|
clan: "random",
|
||||||
|
family: "",
|
||||||
|
gender: "male",
|
||||||
|
age: 15,
|
||||||
|
honor: 30,
|
||||||
|
glory: 30,
|
||||||
|
status: 30,
|
||||||
|
maritalStatus: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the generator
|
||||||
|
* @param {number} avgRingsValue number between 1 and 5
|
||||||
|
* @param {string} clanName random|crab|crane...
|
||||||
|
* @param {string} gender random|male|female
|
||||||
|
*/
|
||||||
|
constructor({ avgRingsValue = 3, clanName = "random", gender = "random" }) {
|
||||||
|
if (!CharacterGenerator.clansAndFamilies[clanName]) {
|
||||||
|
clanName = "random";
|
||||||
|
}
|
||||||
|
if (clanName === "random") {
|
||||||
|
clanName = CharacterGenerator._getRandomArrayValue(Object.keys(CharacterGenerator.clansAndFamilies));
|
||||||
|
}
|
||||||
|
if (gender === "random" || !["male", "female"].includes(gender)) {
|
||||||
|
gender = Math.random() > 0.5 ? "male" : "female";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.avgRingsValue = CharacterGenerator._sanitizeMinMax(avgRingsValue);
|
||||||
|
this.data.clan = clanName;
|
||||||
|
this.data.family = CharacterGenerator._getRandomFamily(clanName);
|
||||||
|
this.data.gender = gender;
|
||||||
|
this.data.age = CharacterGenerator._randomInt(15, this.data.avgRingsValue * 10 + 15);
|
||||||
|
this.genSocialStanding();
|
||||||
|
this.data.maritalStatus = this.genMaritalStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the gender is male
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
get isMale() {
|
||||||
|
return this.data.gender === "male";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a random value for this array
|
||||||
|
* @param array
|
||||||
|
* @return {*}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _getRandomArrayValue(array) {
|
||||||
|
return array[Math.floor(Math.random() * array.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a random value between min and max
|
||||||
|
* @param {number} min
|
||||||
|
* @param {number} max
|
||||||
|
* @return {number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _randomInt(min, max) {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always return a number between 1 and 5
|
||||||
|
* @param {number} number
|
||||||
|
* @return {number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _sanitizeMinMax(number) {
|
||||||
|
return Math.min(5, Math.max(1, number));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Item from this pack (by id if provided, or random otherwise)
|
||||||
|
* @param {string} packName
|
||||||
|
* @param {string} id
|
||||||
|
* @return {Promise<Document|undefined>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async _getItemFromPack(packName, id = null) {
|
||||||
|
const comp = await game.packs.get(packName);
|
||||||
|
if (!comp) {
|
||||||
|
console.log(`L5R5E | Pack not found[${packName}]`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (id) {
|
||||||
|
return comp.getDocument(id);
|
||||||
|
}
|
||||||
|
if (!comp.indexed) {
|
||||||
|
await comp.getDocuments();
|
||||||
|
}
|
||||||
|
return comp.getDocument(CharacterGenerator._getRandomArrayValue(Array.from(comp.keys())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and return a family name for this clan
|
||||||
|
* @param {string} clanName
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _getRandomFamily(clanName) {
|
||||||
|
let originClan = clanName;
|
||||||
|
|
||||||
|
// Ronin specific, can be any other family name
|
||||||
|
if (clanName === "ronin") {
|
||||||
|
originClan = CharacterGenerator._getRandomArrayValue(
|
||||||
|
Object.keys(CharacterGenerator.clansAndFamilies).filter((e) => e !== "ronin")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return CharacterGenerator._getRandomArrayValue(CharacterGenerator.clansAndFamilies[originClan]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and return a full name
|
||||||
|
* @return {Promise<string>}
|
||||||
|
*/
|
||||||
|
async getRandomizedName() {
|
||||||
|
let table = `Japanese names (${this.isMale ? "Male" : "Female"})`;
|
||||||
|
// switch (this.data.clan) {
|
||||||
|
// case "ivory_kingdoms": table = 'Ivory kingdoms names'; break;
|
||||||
|
// case "qamarist": table = 'Qamarist names'; break;
|
||||||
|
// case "ujik": table = 'Ujik names'; break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const randomNames = await game.l5r5e.HelpersL5r5e.drawManyFromPack("l5r5e.core-name-tables", table, 1, {
|
||||||
|
displayChat: false,
|
||||||
|
});
|
||||||
|
return this.data.family + " " + randomNames?.results[0]?.data.text || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Honor, Glory and Status values
|
||||||
|
*/
|
||||||
|
genSocialStanding() {
|
||||||
|
const karma = Math.random() < 0.66 ? 1 : -1;
|
||||||
|
const rng = (initial, variation) => {
|
||||||
|
return initial + CharacterGenerator._randomInt(5, variation) * karma;
|
||||||
|
};
|
||||||
|
|
||||||
|
let honor = rng(34, this.data.age / 2);
|
||||||
|
switch (this.data.clan) {
|
||||||
|
case "lion":
|
||||||
|
honor += 10;
|
||||||
|
break;
|
||||||
|
case "scorpion":
|
||||||
|
honor -= 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.data.honor = honor;
|
||||||
|
this.data.glory = rng(40, this.data.age / 3);
|
||||||
|
this.data.status = rng(30, this.data.age / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the marriage state
|
||||||
|
* @return {string} unmarried|betrothed|married|widowed
|
||||||
|
*/
|
||||||
|
genMaritalStatus() {
|
||||||
|
const rng = Math.random();
|
||||||
|
if (this.data.age < 20) {
|
||||||
|
return rng < 0.1 ? "married" : rng < 0.4 ? "betrothed" : "unmarried";
|
||||||
|
}
|
||||||
|
if (this.data.age < 30) {
|
||||||
|
return rng < 0.4 ? "married" : rng < 0.7 ? "betrothed" : "unmarried";
|
||||||
|
}
|
||||||
|
return rng < 0.8 ? "married" : rng < 0.9 ? "widowed" : "unmarried";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify the current actor datas with selected options
|
||||||
|
*
|
||||||
|
* @param {ActorL5r5e} actor Actor object
|
||||||
|
* @param {boolean} generateName If true generate a new name
|
||||||
|
* @param {boolean} generateAttributes If true generate rings, attributes, skills and confrontation ranks
|
||||||
|
* @param {boolean} generateSocial If true generate Social Standing
|
||||||
|
* @param {boolean} generateDemeanor If true generate Demeanor and rings affinities
|
||||||
|
* @param {boolean} generatePeculiarities If true generate Advantage and Disadvantage
|
||||||
|
* @param {boolean} generateItems If true generate Armor, Weapons and Items
|
||||||
|
* @param {boolean} generateNarrative If true generate Narrative and fluff
|
||||||
|
* @return {Promise<Object>}
|
||||||
|
*/
|
||||||
|
async toActor(
|
||||||
|
actor,
|
||||||
|
{
|
||||||
|
generateName = true,
|
||||||
|
generateAttributes = true,
|
||||||
|
generateSocial = true,
|
||||||
|
generateDemeanor = true,
|
||||||
|
generatePeculiarities = true,
|
||||||
|
generateItems = true,
|
||||||
|
generateNarrative = true,
|
||||||
|
} = {}
|
||||||
|
) {
|
||||||
|
const actorDatas = actor.data.data;
|
||||||
|
|
||||||
|
// Name
|
||||||
|
const newName = generateName ? await this.getRandomizedName() : actor.data.name;
|
||||||
|
|
||||||
|
// Img (only if default)
|
||||||
|
const folder = "systems/l5r5e/assets/icons/actors";
|
||||||
|
const newImg = [
|
||||||
|
`${folder}/npc.svg`,
|
||||||
|
`${folder}/traditional-japanese-man.svg`,
|
||||||
|
`${folder}/traditional-japanese-woman.svg`,
|
||||||
|
].includes(actor.data.img)
|
||||||
|
? `${folder}/traditional-japanese-${this.isMale ? "man" : "woman"}.svg`
|
||||||
|
: actor.data.img;
|
||||||
|
|
||||||
|
// Generate attributes (rings, attributes, skills, confrontation ranks)
|
||||||
|
if (generateAttributes) {
|
||||||
|
this._generateAttributes(actorDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Social Standing
|
||||||
|
if (generateSocial) {
|
||||||
|
actorDatas.social.honor = this.data.honor;
|
||||||
|
actorDatas.social.glory = this.data.glory;
|
||||||
|
actorDatas.social.status = this.data.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demeanor (npc only)
|
||||||
|
if (generateDemeanor && actor.type === "npc") {
|
||||||
|
this._generateDemeanor(actorDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items types
|
||||||
|
if (generatePeculiarities || generateItems) {
|
||||||
|
const newItemsData = [];
|
||||||
|
|
||||||
|
// Advantage / Disadvantage
|
||||||
|
if (generatePeculiarities) {
|
||||||
|
await this._generatePeculiarities(actor, newItemsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items
|
||||||
|
if (generateItems) {
|
||||||
|
await this._generateItems(actor, newItemsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to actor
|
||||||
|
if (newItemsData.length > 0) {
|
||||||
|
await actor.createEmbeddedDocuments("Item", newItemsData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Narrative
|
||||||
|
if (generateNarrative) {
|
||||||
|
this._generateNarrative(actorDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return actor data
|
||||||
|
return {
|
||||||
|
img: newImg,
|
||||||
|
name: newName,
|
||||||
|
data: actorDatas,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//<editor-fold desc="toActor generators">
|
||||||
|
/**
|
||||||
|
* Generate attributes (rings, attributes, skills, confrontation ranks)
|
||||||
|
* @param {DocumentData.data} actorDatas
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_generateAttributes(actorDatas) {
|
||||||
|
const stats = { min: 5, max: 1 };
|
||||||
|
|
||||||
|
// Rings
|
||||||
|
CONFIG.l5r5e.stances.forEach((ringName) => {
|
||||||
|
// avgRingsValue + (-1|0|1)
|
||||||
|
actorDatas.rings[ringName] = CharacterGenerator._sanitizeMinMax(
|
||||||
|
this.data.avgRingsValue - 1 + Math.floor(Math.random() * 3)
|
||||||
|
);
|
||||||
|
stats.min = Math.min(stats.min, actorDatas.rings[ringName]);
|
||||||
|
stats.max = Math.max(stats.max, actorDatas.rings[ringName]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
game.l5r5e.ActorL5r5e.computeDerivedAttributes(actorDatas);
|
||||||
|
|
||||||
|
// Skills
|
||||||
|
Object.keys(actorDatas.skills).forEach(
|
||||||
|
(skillName) => (actorDatas.skills[skillName] = Math.floor(Math.random() * stats.max))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Confrontation ranks
|
||||||
|
actorDatas.conflict_rank.martial = this.data.avgRingsValue + actorDatas.skills.martial;
|
||||||
|
actorDatas.conflict_rank.social = this.data.avgRingsValue + actorDatas.skills.social;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Demeanor (npc only)
|
||||||
|
* @param {DocumentData.data} actorDatas
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_generateDemeanor(actorDatas) {
|
||||||
|
// demeanor { id: "adaptable", mod: { fire: 2, earth: -2 } },
|
||||||
|
const demeanor = CharacterGenerator._getRandomArrayValue(CharacterGenerator.demeanorList);
|
||||||
|
actorDatas.attitude = game.i18n.localize("l5r5e.demeanor." + demeanor.id);
|
||||||
|
actorDatas.rings_affinities = foundry.utils.mergeObject(
|
||||||
|
{
|
||||||
|
earth: 0,
|
||||||
|
air: 0,
|
||||||
|
water: 0,
|
||||||
|
fire: 0,
|
||||||
|
void: 0,
|
||||||
|
},
|
||||||
|
demeanor.mod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Advantages and Disadvantages
|
||||||
|
* @param {ActorL5r5e} actor
|
||||||
|
* @param {DocumentData[]} newItemsData
|
||||||
|
* @return {Promise<void>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _generatePeculiarities(actor, newItemsData) {
|
||||||
|
// Clear actor peculiarities
|
||||||
|
const deleteIds = actor.data.items.filter((e) => e.type === "peculiarity").map((e) => e.id);
|
||||||
|
if (deleteIds.length > 0) {
|
||||||
|
await actor.deleteEmbeddedDocuments("Item", deleteIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add peculiarities
|
||||||
|
for (const pack of ["adversities", "distinctions", "passions"]) {
|
||||||
|
const item = await CharacterGenerator._getItemFromPack(`l5r5e.core-peculiarities-${pack}`);
|
||||||
|
if (item) {
|
||||||
|
newItemsData.push(foundry.utils.duplicate(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Armor, Weapons, Items
|
||||||
|
* @param {ActorL5r5e} actor
|
||||||
|
* @param {DocumentData[]} newItemsData
|
||||||
|
* @return {Promise<void>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _generateItems(actor, newItemsData) {
|
||||||
|
// Clear actor items
|
||||||
|
const deleteIds = actor.data.items.filter((e) => ["armor", "weapon", "item"].includes(e.type)).map((e) => e.id);
|
||||||
|
|
||||||
|
if (deleteIds.length > 0) {
|
||||||
|
await actor.deleteEmbeddedDocuments("Item", deleteIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items
|
||||||
|
const itemCfg = {
|
||||||
|
armors: [
|
||||||
|
"L5RCoreArm000009", // Common Clothes
|
||||||
|
],
|
||||||
|
weapons: [
|
||||||
|
"L5RCoreWea000036", // Punch
|
||||||
|
"L5RCoreWea000037", // Kick
|
||||||
|
"L5RCoreWea000009", // Wakizashi
|
||||||
|
"L5RCoreWea000007", // Katana
|
||||||
|
"L5RCoreWea000019", // Knife
|
||||||
|
],
|
||||||
|
items: [
|
||||||
|
null, // Random item
|
||||||
|
],
|
||||||
|
};
|
||||||
|
if (this.data.clan === "crab") {
|
||||||
|
itemCfg.armors.push("L5RCoreArm000001"); // Ashigaru Armor
|
||||||
|
itemCfg.weapons.push("L5RCoreWea000017"); // Tetsubō
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const pack in itemCfg) {
|
||||||
|
for (const itemId of itemCfg[pack]) {
|
||||||
|
const item = await CharacterGenerator._getItemFromPack(`l5r5e.core-${pack}`, itemId);
|
||||||
|
if (item) {
|
||||||
|
newItemsData.push(foundry.utils.duplicate(item.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Narrative fluff
|
||||||
|
* @param {DocumentData.data} actorDatas
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_generateNarrative(actorDatas) {
|
||||||
|
// Fill notes with some values that don't appear in sheet
|
||||||
|
actorDatas.notes =
|
||||||
|
`<p>${game.i18n.localize("l5r5e.char_generator.age")}: ${this.data.age}</p>` +
|
||||||
|
`<p>${game.i18n.localize("l5r5e.gender.title")}: ${game.i18n.localize(
|
||||||
|
"l5r5e.gender." + this.data.gender
|
||||||
|
)}</p>` +
|
||||||
|
`<p>${game.i18n.localize("l5r5e.clan")}: ${game.i18n.localize("l5r5e.clans." + this.data.clan)}</p>` +
|
||||||
|
`<p>${game.i18n.localize("l5r5e.char_generator.marital_status.title")}: ${game.i18n.localize(
|
||||||
|
"l5r5e.char_generator.marital_status." + this.data.maritalStatus
|
||||||
|
)}</p>`;
|
||||||
|
|
||||||
|
// data: {
|
||||||
|
// "notes": "",
|
||||||
|
// "description": "",
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BaseCharacterSheetL5r5e } from "./base-character-sheet.js";
|
import { BaseCharacterSheetL5r5e } from "./base-character-sheet.js";
|
||||||
|
import { CharacterGeneratorDialog } from "./character-generator-dialog.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NPC Sheet
|
* NPC Sheet
|
||||||
@@ -16,6 +17,28 @@ export class NpcSheetL5r5e extends BaseCharacterSheetL5r5e {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the NpcGenerator button on top of sheet
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
_getHeaderButtons() {
|
||||||
|
let buttons = super._getHeaderButtons();
|
||||||
|
if (!this.isEditable || this.actor.limited) {
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.unshift({
|
||||||
|
label: game.i18n.localize("l5r5e.char_generator.head_bt_title"),
|
||||||
|
class: "character-generator",
|
||||||
|
icon: "fas fa-cogs",
|
||||||
|
onclick: async () => {
|
||||||
|
await new CharacterGeneratorDialog(this.actor).render(true);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
getData(options = {}) {
|
getData(options = {}) {
|
||||||
const sheetData = super.getData();
|
const sheetData = super.getData();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -170,3 +170,16 @@
|
|||||||
flex: 0 0 calc(50% - 0.25rem);
|
flex: 0 0 calc(50% - 0.25rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.character-generator-dialog {
|
||||||
|
form .body {
|
||||||
|
clear: both;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 3px 0;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
input[type="number"] {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
{{!-- Identity --}}
|
{{!-- Identity --}}
|
||||||
<li>{{#ifCond data.data.template '==' 'pow'}}{{localize 'l5r5e.region'}}{{else}}{{localize 'l5r5e.clan'}}{{/ifCond}} : {{data.data.identity.clan}}</li>
|
<li>{{#ifCond data.data.template '==' 'pow'}}{{localize 'l5r5e.region'}}{{else}}{{localize 'l5r5e.clan'}}{{/ifCond}} : {{data.data.identity.clan}}</li>
|
||||||
<li>{{#ifCond data.data.template '==' 'pow'}}{{localize 'l5r5e.upbringing'}}{{else}}{{localize 'l5r5e.family'}}{{/ifCond}} : {{data.data.identity.family}}</li>
|
<li>{{#ifCond data.data.template '==' 'pow'}}{{localize 'l5r5e.upbringing'}}{{else}}{{localize 'l5r5e.family'}}{{/ifCond}} : {{data.data.identity.family}}</li>
|
||||||
<li>{{localize 'l5r5e.schoolrank'}} : {{data.data.identity.school_rank}}</li>
|
<li>{{localize 'l5r5e.rank'}} : {{data.data.identity.school_rank}}</li>
|
||||||
<li>{{localize 'l5r5e.school'}} : {{data.data.identity.school}}</li>
|
<li>{{localize 'l5r5e.school'}} : {{data.data.identity.school}}</li>
|
||||||
<li>{{localize 'l5r5e.roles'}} : {{data.data.identity.roles}}</li>
|
<li>{{localize 'l5r5e.roles'}} : {{data.data.identity.roles}}</li>
|
||||||
|
|
||||||
|
|||||||
65
system/templates/actors/character-generator-dialog.html
Normal file
65
system/templates/actors/character-generator-dialog.html
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<form class="l5r5e character-generator-dialog" autocomplete="off">
|
||||||
|
<div class="content">
|
||||||
|
<div class="form-group body">
|
||||||
|
<label>
|
||||||
|
{{localize 'l5r5e.clan'}}
|
||||||
|
<select class="attribute-dtype" name="clan">
|
||||||
|
{{#select data.clan}}
|
||||||
|
{{#each clanList as |value|}}
|
||||||
|
<option value="{{value.id}}">{{value.label}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{{localize 'l5r5e.gender.title'}}
|
||||||
|
<select class="attribute-dtype" name="gender">
|
||||||
|
{{#select data.gender}}
|
||||||
|
{{#each genderList as |value|}}
|
||||||
|
<option value="{{value.id}}">{{value.label}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{{localize 'l5r5e.char_generator.average_value'}} <input class="centered-input" type="number" name="avg_rings" value="{{data.avg_rings}}" data-dtype="Number" min="1" max="5" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
{{localize 'l5r5e.char_generator.generate'}}:
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateName" {{checked data.generateName}} />
|
||||||
|
{{localize 'l5r5e.name'}}
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateAttributes" {{checked data.generateAttributes}} />
|
||||||
|
{{localize 'l5r5e.char_generator.attributes'}}
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateSocial" {{checked data.generateSocial}} />
|
||||||
|
{{localize 'l5r5e.char_generator.social'}}
|
||||||
|
</label>
|
||||||
|
{{#if isNpc}}
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateDemeanor" {{checked data.generateDemeanor}} />
|
||||||
|
{{localize 'l5r5e.char_generator.demeanor'}}
|
||||||
|
</label>
|
||||||
|
{{/if}}
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generatePeculiarities" {{checked data.generatePeculiarities}} />
|
||||||
|
{{localize 'l5r5e.char_generator.peculiarities'}}
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateItems" {{checked data.generateItems}} />
|
||||||
|
{{localize 'l5r5e.char_generator.items'}}
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="generateNarrative" {{checked data.generateNarrative}} />
|
||||||
|
{{localize 'l5r5e.char_generator.narrative'}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group footer">
|
||||||
|
<button name="generate" id="generate" type="submit">
|
||||||
|
{{localize 'l5r5e.char_generator.generate'}} <i class='fas fa-arrow-circle-right'></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="attribute-label">
|
<label class="attribute-label">
|
||||||
{{localize 'l5r5e.schoolrank'}}
|
{{localize 'l5r5e.rank'}}
|
||||||
<input type="number" name="data.identity.school_rank" value="{{data.data.identity.school_rank}}" class="select-on-focus" data-dtype="Number" min="0" placeholder="1"/>
|
<input type="number" name="data.identity.school_rank" value="{{data.data.identity.school_rank}}" class="select-on-focus" data-dtype="Number" min="0" placeholder="1"/>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user