import { pluralize } from "../string_utils.js";
import Model from "./model.js";
import Relationship from "./relationship.js";
const REL_LABELS = new Map(
Object.entries({
deceased: "(now deceased), and",
absent: "(now absent), and",
married: "married to",
divorced: "divorced from",
separated: "separated from",
couple: "lives with",
}),
);
function couple(ch1) {
if (!ch1.partner) {
return `<li>${ch1.name.toString()} (${ch1.age})</li>`;
}
const ch2 = ch1.partner;
const relationship = ch1.relationship;
let relLabel = REL_LABELS.get(relationship);
let arr = ["<li>"];
if (ch1.name.family === ch2.name.family) {
arr.push(ch1.name.given);
arr.push(relLabel);
arr.push(ch2.name.given);
arr.push(ch2.name.toLastNameString());
} else {
arr.push(ch1.name.toString());
arr.push(relLabel);
arr.push(ch2.name.toString());
}
if (!ch1.status && !ch2.status) {
arr.push(`(Ages ${ch1.age} and ${ch2.age}).`);
} else {
if (ch1.status && ch1.status === ch2.status) {
arr.push(`(Died at ages ${ch1.age} and ${ch2.age}).`);
} else {
if (ch1.status) {
arr.push(`(${ch1.name.given} died at age ${ch1.age};`);
arr.push(`${ch2.name.given} is now age ${ch2.age}).`);
}
if (ch2.status) {
arr.push(`(${ch2.name.given} died at age ${ch2.age};`);
arr.push(`${ch1.name.given} is now age ${ch1.age}).`);
}
}
}
if (ch1.children?.length > 0) {
arr.push("They have " + pluralize(`{|}{1 |}child{ren}: `, ch1.children.length));
arr.push("<ul>");
for (const child of ch1.children) {
if (child.partner) {
arr.push(couple(child));
} else if (child.status) {
arr.push(`<li>${child.name} (${child.status} ${child.age})</li>`);
} else {
arr.push(`<li>${child.name} (${child.age})</li>`);
}
}
arr.push("</ul>");
}
arr.push("</li>");
return arr.join(" ");
}
/**
* A family. This means (in the context of this game), a set of parents with some kids,
* some of whom may themselves be in family objects with kids, etc. One of the building
* blocks of encounters and homesteads, at the least.
*
* @extends Model
* @property {Character} parent - The parent character who heads this family. Always female because
* we trace kinship matrilinearly during generation.
* @property {number} generation - The generation number of this family (1 for the founding generation,
* 2 for parents with children, and so forth).
* @property {string} familyName - The surname shared by members of this family, derived from the male
* partner’s last name of the original parent. Actual people in the family will have different names
* for all the normal reasons.
* @property {Character[]} members - All characters in the family.
*/
class Family extends Model {
constructor(params) {
super(params);
this.familyName = params.parent.male
? params.parent.name.family
: params.parent.partner.name.family;
this.parent = params.parent;
this.generation = params.generation;
}
get members() {
function addPerson(p) {
if (p.status !== "deceased") {
all.push(p);
}
if (p.partner && p.partner.status !== "deceased") {
all.push(p.partner);
}
for (const child of p.children ?? []) {
addPerson(child);
}
}
const all = [];
addPerson(this.parent);
return all;
}
getOldestRelationship() {
const older = this.parent.age >= this.parent.partner.age ? this.parent : this.parent.partner;
const younger = this.parent.age < this.parent.partner.age ? this.parent : this.parent.partner;
return new Relationship({ older, younger, relName: this.parent.relationship });
}
toString() {
return `<h4>Family Tree</h4>${this.toFamilyTree()}<h4>Roster</h4>${this.toRoster()}`;
}
toFamilyTree() {
return `<ul>${couple(this.parent)}</ul>`;
}
toRoster() {
return this.members.map((ch) => ch.toString()).join("");
}
}
export default Family;