This commit is contained in:
33333-33333 2026-08-08 15:31:31 +09:00
commit 28591233f3
85 changed files with 946 additions and 267 deletions

View file

@ -16,17 +16,28 @@ function tarinaiRoundRectPath(ctx, x, y, w, h, r) {
}
function tarinaiChampionName(name = "") {
const map = { "\u306F": "\u8987", "\u3046": "\u5B87", "\u3045": "\u30A5", "\u3063": "\uFF01" };
return String(name || "").replace(/[\u306F\u3046\u3045\u3063]/g, ch => map[ch] || ch);
const raw = String(name || "");
if (/おちび(?:の王)?$/.test(raw)) return raw.endsWith("の王") ? raw : `${raw}の王`;
const map = { "は": "覇", "う": "宇", "ぅ": "ゥ", "っ": "!" };
return raw.replace(/[はうぅっ]/g, ch => map[ch] || ch);
}
if (typeof window !== "undefined") window.tarinaiChampionName = tarinaiChampionName;
if (typeof globalThis !== "undefined") globalThis.tarinaiChampionName = tarinaiChampionName;
const ACQUIRED_TARINAI_NAME_PREFIXES = ["かしこい", "すごい", "たくましい", "げんきな", "わんぱくな", "ぴかぴかあにゃるの", "しゅーるすとれみんぐ・", "つよい", "もちもちほっぺの", "でかずんぽの", "ちびずんぽの", "すばらしい", "かわいい", "ずんちがくさい", "やさしい", "ゆうかんな", "いいにおいの"];
function acquiredTarinaiBaseName(seed = "", name = "") {
const raw = String(name || "").trim();
if (raw && raw !== "ずんちどれい") return raw.replace(/の王$/, "");
const pick = typeof stableChoice === "function" ? stableChoice(seed || raw || "acquired", "acquired-name-prefix", ACQUIRED_TARINAI_NAME_PREFIXES) : (ACQUIRED_TARINAI_NAME_PREFIXES[0] || "");
return `${pick || ACQUIRED_TARINAI_NAME_PREFIXES[0] || ""}おちび`;
}
class Tarinai { constructor(world, opts = {}) {
if (world && !opts.birthSeed && !opts.familyKey && !opts.id && globalThis.TarinaiSeedFactory.prepareAddOptions) {
opts = globalThis.TarinaiSeedFactory.prepareAddOptions(world, opts) || opts;
}
this.world = world;
this.isAcquiredTarinai = Boolean(opts.isAcquiredTarinai);
this.birthSeed = opts.birthSeed || opts.familyKey || opts.id || (globalThis.TarinaiSeedFactory.childSeed(world?.worldSeed || "", Number(world?.birthSerial || 0) + 1, []) || (crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`));
this.birthSerial = Number.isFinite(opts.birthSerial) ? Number(opts.birthSerial) : (globalThis.TarinaiSeedFactory.serialFromBirthSeed(this.birthSeed) || 0);
const birthProfile = globalThis.TarinaiSeedFactory.birthProfile(this.birthSeed, opts) || {};
@ -34,6 +45,7 @@ class Tarinai { constructor(world, opts = {}) {
this.id = opts.id || "";
this.liveToken = opts.liveToken || 0;
this.name = opts.name || birthProfile.name || makeName(world);
this.acquiredBaseName = opts.acquiredBaseName || null;
this.type = opts.type || birthProfile.type || baseSpriteId();
const typeMeta = SPRITES.find(s => s.id === this.type);
if (typeMeta?.actionOnly || typeMeta?.displayOnly) this.type = birthProfile.type || baseSpriteId();
@ -120,6 +132,29 @@ class Tarinai { constructor(world, opts = {}) {
this.sleeping = false;
this.awakeLockTimer = opts.awakeLockTimer ?? 0;
this.goodMode = opts.goodMode ?? birthProfile.goodMode ?? stableChoice(this.birthSeed || this.familyKey, "good-mode", displayNormalSprites()) ?? "smile";
if (this.isAcquiredTarinai) {
const explicitAcquiredName = this.acquiredBaseName || (Object.prototype.hasOwnProperty.call(opts, "name") ? this.name : "");
this.acquiredBaseName = acquiredTarinaiBaseName(this.birthSeed || this.familyKey, explicitAcquiredName);
this.name = this.acquiredBaseName;
}
if (this.isAcquiredTarinai) {
const acquiredNeeds = { food: 22, sleep: 34, health: 78, safety: 100, social: 90, fulfill: 82 };
const hasExplicitNeedState = Boolean((opts.needs && typeof opts.needs === "object") || (opts.needRaw && typeof opts.needRaw === "object") || (opts.needDisplay && typeof opts.needDisplay === "object") || (opts.needRawBase && typeof opts.needRawBase === "object") || (opts.previousNeeds && typeof opts.previousNeeds === "object"));
if (!hasExplicitNeedState) {
this.needs = { ...acquiredNeeds };
this.needDisplay = { ...acquiredNeeds };
this.needRaw = { ...acquiredNeeds };
this.needRawBase = { ...acquiredNeeds };
this.previousNeeds = { ...acquiredNeeds };
}
if (!Object.prototype.hasOwnProperty.call(opts, "loneliness")) this.loneliness = Math.max(Number(this.loneliness) || 0, 90);
if (!Object.prototype.hasOwnProperty.call(opts, "hunger")) this.hunger = Math.max(Number(this.hunger) || 0, 22);
if (!Object.prototype.hasOwnProperty.call(opts, "energy")) this.energy = Math.min(Number(this.energy) || 0, 45);
if (!Object.prototype.hasOwnProperty.call(opts, "goodMode") && Array.isArray(SPRITES) && SPRITES.some(s => s.id === "jito")) this.goodMode = "jito";
this.stress = typeof calculateStressFromNeeds === "function" ? calculateStressFromNeeds(this.needRaw || this.needs) : this.stress;
this.acquiredStressSpeechAt = Number.isFinite(opts.acquiredStressSpeechAt) ? opts.acquiredStressSpeechAt : ((this.world?.time || 0) + rand(2.8, 6.5));
this.acquiredStressSpeechCooldownUntil = Number.isFinite(opts.acquiredStressSpeechCooldownUntil) ? opts.acquiredStressSpeechCooldownUntil : 0;
}
this.facing = opts.facing ?? (stableUnit(this.familyKey, "facing") < 0.5 ? -1 : 1);
this.visualFacing = opts.visualFacing ?? this.facing;
this.facingLockUntil = opts.facingLockUntil ?? 0;
@ -164,6 +199,9 @@ class Tarinai { constructor(world, opts = {}) {
this.explosionDisease = Boolean(opts.explosionDisease);
this.explosionDiseaseTimer = opts.explosionDiseaseTimer ?? (this.explosionDisease ? 60 : 0);
this.fightDisease = Boolean(opts.fightDisease);
this.mamekusaredakeDisease = Boolean(opts.mamekusaredakeDisease);
this.mamekusaredakeGrowth = Number.isFinite(opts.mamekusaredakeGrowth) ? opts.mamekusaredakeGrowth : 0;
this.mamekusaredakeSpeechAt = Number.isFinite(opts.mamekusaredakeSpeechAt) ? opts.mamekusaredakeSpeechAt : 0;
this.fightDiseaseCooldown = opts.fightDiseaseCooldown ?? 0;
this.lastBleedAt = opts.lastBleedAt ?? -999;
this.favorite = Boolean(opts.favorite);