Skip to content

Commit 1202bd5

Browse files
committed
gerador de personagem movido para repositório próprio
1 parent 65a79ad commit 1202bd5

40 files changed

Lines changed: 883 additions & 241 deletions

docs/extras/js/generator.js

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
const BASE_PATH = "/gerador_personagem/datasets/generic/npcs/";
2+
const STRUCTURE_PATH = "/gerador_personagem/datasets/generic/npcs/structure/";
3+
4+
const STRUCTURE = [
5+
"connectors.yaml",
6+
"precedence.yaml",
7+
"roles.yaml",
8+
"templates.yaml"
9+
];
210

311
const DATASETS = [
412
"age.yaml",
513
"arms.yaml",
14+
"attire.yaml",
615
"beard.yaml",
716
"body_locations.yaml",
817
"constitution.yaml",
@@ -30,6 +39,14 @@ const DATASETS = [
3039
"voice.yaml",
3140
];
3241

42+
function pick(arr) {
43+
return arr[Math.floor(Math.random() * arr.length)];
44+
}
45+
46+
function capitalize(text) {
47+
return text.charAt(0).toUpperCase() + text.slice(1);
48+
}
49+
3350
function bindUI() {
3451
const btn = document.getElementById("generate");
3552

@@ -52,12 +69,35 @@ async function loadTranslation(lang) {
5269
return translations;
5370
}
5471

55-
function translateTrait(tableId, trait, translations) {
72+
function translateTrait(tableId, trait, translations, gender) {
5673
if (!trait) return null;
5774
if (!translations || !translations[tableId]) return trait.text;
5875

59-
// retorna o texto traduzido se existir, senão mantém o original
60-
return translations[tableId][trait.id] ?? trait.text;
76+
const entry = translations[tableId][trait.id];
77+
78+
// não existe tradução
79+
if (!entry) return trait.text;
80+
81+
// caso simples: string direta
82+
if (typeof entry === "string") {
83+
return entry;
84+
}
85+
86+
// caso com variação de gênero
87+
if (typeof entry === "object") {
88+
// tenta o gênero específico
89+
if (gender && entry[gender]) {
90+
return entry[gender];
91+
}
92+
93+
// fallback neutro
94+
if (entry.neutral) {
95+
return entry.neutral;
96+
}
97+
}
98+
99+
// último fallback
100+
return trait.text;
61101
}
62102

63103
function pickRandomItems(array, n) {
@@ -122,6 +162,56 @@ function isGeneratorPage() {
122162
return document.getElementById("npc-generator-root") !== null;
123163
}
124164

165+
function buildParagraphs(traits, structure) {
166+
const fragmentsByRole = {};
167+
168+
// 1. gerar núcleo (age + gender)
169+
const ageId = traits.age.id;
170+
const genderId = traits.gender.id;
171+
172+
const coreOptions =
173+
structure.templates.templates?.[ageId]?.[genderId] ??
174+
["An individual"];
175+
176+
fragmentsByRole.core = [pick(coreOptions)];
177+
178+
// 2. processar outros traits
179+
for (const [key, trait] of Object.entries(traits)) {
180+
if (key === "age" || key === "gender") continue;
181+
182+
const role = structure.roles.roles[key];
183+
if (!role) continue;
184+
185+
fragmentsByRole[role] ??= [];
186+
fragmentsByRole[role].push(trait.text);
187+
}
188+
189+
// 3. ordenar por precedência
190+
const orderedRoles = structure.precedence.precedence;
191+
192+
const parts = [];
193+
194+
for (const role of orderedRoles) {
195+
const items = fragmentsByRole[role];
196+
if (!items || items.length === 0) continue;
197+
198+
const connector = pick(structure.connectors.connectors[role] ?? [""]);
199+
const joined = items.join(" and ");
200+
201+
parts.push(
202+
connector
203+
? `${connector} ${joined}`
204+
: joined
205+
);
206+
}
207+
208+
// 4. montar parágrafo
209+
const paragraph =
210+
capitalize(parts.join(", ").replace(/\s+,/g, ",")) + ".";
211+
212+
return [paragraph];
213+
}
214+
125215
function renderOutput(paragraphs) {
126216
const output = document.getElementById("output");
127217
output.innerHTML = "";
@@ -159,8 +249,8 @@ async function generateCharacter() {
159249
const age = resolveTrait("age", ageSelection);
160250
const gender = resolveTrait("gender", genderSelection);
161251

162-
if (age) output.push(`Age: ${translateTrait("age", age, translations)}`);
163-
if (gender) output.push(`Gender: ${translateTrait("gender", gender, translations)}`);
252+
if (age) output.push(`age: ${translateTrait("age", age, translations)}`);
253+
if (gender) output.push(`gender: ${translateTrait("gender", gender, translations)}`);
164254

165255
// Escolher 3 tabelas aleatórias restantes
166256
const otherTableIds = Object.keys(NPC_TABLES).filter(
@@ -173,16 +263,15 @@ async function generateCharacter() {
173263
const table = NPC_TABLES[tableId];
174264
const trait = resolveRandomTrait(table);
175265
if (trait) {
176-
const text = translateTrait(tableId, trait, translations);
177-
output.push(`${tableId.charAt(0).toUpperCase() + tableId.slice(1)}: ${text}`);
178-
179-
/*
180-
const categoryName = translations[tableId]._name ?? tableId;
181-
output.push(`${categoryName}: ${translateTrait(tableId, trait, translations)}`);
182-
*/
266+
const text = translateTrait(tableId, trait, translations, gender);
267+
output.push(`${tableId}: ${text}`);
183268
}
184269
}
185270

271+
//console.log(output)
272+
//formatted_output = buildParagraphs(output, NPC_STRUCTURE)
273+
274+
//renderOutput(formatted_output);
186275
renderOutput(output);
187276
}
188277

@@ -194,6 +283,7 @@ document.addEventListener("DOMContentLoaded", () => {
194283

195284
async function initGenerator() {
196285
const rawTables = {};
286+
const rawStructure = {};
197287

198288
// carregar todos os datasets
199289
for (const file of DATASETS) {
@@ -205,6 +295,14 @@ async function initGenerator() {
205295
// salvar globalmente
206296
window.NPC_TABLES = rawTables;
207297

298+
for (const file of STRUCTURE) {
299+
const raw = await loadYAML(STRUCTURE_PATH + file);
300+
const table = normalizeTable(raw);
301+
rawStructure[table.id] = table;
302+
}
303+
304+
window.NPC_STRUCTURE = rawStructure;
305+
208306
bindUI();
209307
}
210308

docs/gerador_personagem/datasets/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ id: translation
4949

5050
**Constraints** respect relationship rules between items, whether of the same category or different categories. They are used to indicate three possible relationships:
5151

52-
**Allowed**: Contains an item, list of items, or category that are allowed in combination with the item in question.
52+
**Requires**: Contains an item, list of items, or category that is necessary for the item in question to be applied.
5353

54-
**Forbidden**: Contains an item, list of items, or category that are prohibited in combination with the item in question.
54+
**Excludes**: Contains an item, list of items, or category that cannot exist in combination with the item in question.
5555

5656
Most items do not have **constraints**, but they exist to prevent impossible situations such as a character having both "flashy hairstyle" and being "bald" at the same time.

docs/gerador_personagem/datasets/README_ptBR.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ Os arquivos *Yaml* de tradução são uma versão simplificada dos arquivos prin
4646

4747
**Constraints** respesentam regras de relacionamento entre itens, seja de mesma categoria ou de categorias diferentes. Ela são usadas para indicar tres possíveis relacionamentos:
4848

49-
**Allowed**: Contem um item, lista de item ou categoria que são permitidos em combinação com o item em questão.
49+
**Requires**: Contem um item, lista de item ou categoria que são necessários para que o item em questão pode ser aplicado.
5050

51-
**Forbidden**: Contem um item, lista de item ou categoria que são proibidos em combinação com o item em questão.
51+
**Excludes**: Contem um item, lista de item ou categoria que não podem existir em combinação com o item em questão.
5252

5353
A Maioria dos itens não possue **constrants**, mas elas existem para evitar situações impossíveis como um personagem possuir ao mesmo tempo "penteado espalhafatoso" e "careca".

docs/gerador_personagem/datasets/generic/npcs/age.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
age:
22
weight: 1
33
selection:
4-
type: single # single | multiple
4+
type: single
55
required: true
66
traits:
77
- id: child
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
arms:
22
selection:
33
type: multiple
4-
required: false
5-
min: 0
6-
max: 2
7-
allow_duplicates: false
4+
required: false
85
traits:
96
- id: flabby_arms
107
text: "Flabby arms"
118
weight: 1.5
129
constraints:
13-
min_age: 12
14-
10+
1511
- id: missing_arm_hair
1612
text: "Patches of missing hair on arms"
1713
weight: 1.2
1814
constraints:
19-
min_age: 14
20-
15+
2116
- id: toned_arms
2217
text: "Toned arms"
2318
weight: 1.8
2419
constraints:
25-
min_age: 16
20+
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
attire:
2+
weight: 1
3+
selection:
4+
type: multiple
5+
required: false
6+
traits:
7+
- id: ragged_clothes
8+
text: "Ragged clothes, full of tears and loose threads"
9+
weight: 8
10+
11+
- id: patched_clothes
12+
text: "Old clothes covered in patches of different fabrics"
13+
weight: 7
14+
15+
- id: filthy_elegant
16+
text: "Elegant outfits, but stained and dirty"
17+
weight: 6
18+
19+
- id: overly_elegant
20+
text: "Clothes too refined for the situation"
21+
weight: 5
22+
23+
- id: colorful_mismatch
24+
text: "Extremely colorful clothes, without any harmony between them"
25+
weight: 6
26+
27+
- id: faded_colors
28+
text: "Clothes with vibrant colors, but faded by the sun and time"
29+
weight: 5
30+
31+
- id: dark_layers
32+
text: "Several layers of dark clothing"
33+
weight: 4
34+
35+
- id: oversized_hat
36+
text: "An enormous hat that seems too big for your head"
37+
weight: 6
38+
39+
- id: exotic_hat
40+
text: "A hat of exotic, unusual shape or of unknown origin"
41+
weight: 5
42+
43+
- id: hood_always_on
44+
text: "A hood constantly raised, hiding part of the face"
45+
weight: 5
46+
47+
- id: torn_cloak
48+
text: "A torn cloak that has seen better days"
49+
weight: 7
50+
51+
- id: luxurious_cloak
52+
text: "A cloak of fine fabric, heavy and clearly expensive"
53+
weight: 4
54+
55+
- id: ceremonial_robes
56+
text: "Ceremonial robes that seem out of place outside of rituals"
57+
weight: 3
58+
59+
- id: traveler_clothes
60+
text: "Practical traveler's clothes, worn from long journeys"
61+
weight: 6
62+
63+
- id: military_remains
64+
text: "Remains of an old, incomplete, and adapted military uniform"
65+
weight: 4
66+
67+
- id: noble_ruins
68+
text: "Costumes that were once elegant, but are now out of fashion and damaged"
69+
weight: 3
70+
71+
- id: heavy_jewelry
72+
text: "Accessories and jewelry too large for everyday use"
73+
weight: 5
74+
75+
- id: strange_talismans
76+
text: "Strange talismans hanging all over the body"
77+
weight: 6
78+
79+
- id: noisy_accessories
80+
text: "Pendants and metal pieces that make noise when moved"
81+
weight: 4
82+
83+
- id: bone_decorations
84+
text: "Ornaments made of bones, teeth, or claws"
85+
weight: 4
86+
87+
- id: religious_symbols
88+
text: "Religious symbols displayed in an exaggerated way"
89+
weight: 5
90+
91+
- id: poor_quality
92+
text: "Visibly inferior quality and poorly sewn clothing"
93+
weight: 7
94+
95+
- id: pristine_clothes
96+
text: "Impeccable clothing, too clean for the situation"
97+
weight: 4
98+
99+
- id: bloodstained
100+
text: "Clothing stained with dried blood, old or recent"
101+
weight: 4
102+
103+
- id: weathered
104+
text: "Clothing battered by weather, wind, rain and dust"
105+
weight: 6
106+
107+
- id: cultural_attire
108+
text: "Clothing typical of an unusual culture in the region"
109+
weight: 5
110+
111+
- id: theatrical_style
112+
text: "Exaggerated, almost theatrical clothing"
113+
weight: 4
114+
115+
- id: hood_and_mask
116+
text: "Hood combined with a partial or total mask"
117+
weight: 3
118+
119+
- id: stitched_symbols
120+
text: "Strange symbols stitched or embroidered on the clothing"
121+
weight: 5
122+
123+
- id: improvised_clothes
124+
text: "Improvised clothing made from unexpected materials"
125+
weight: 4
126+
127+
- id: dangling_charms
128+
text: "Small charms hanging from belts, sleeves, or boots"
129+
weight: 6

0 commit comments

Comments
 (0)