This commit is contained in:
33333-33333 2026-06-21 22:29:00 +09:00
commit 0a6148c73f
67 changed files with 2653 additions and 1519 deletions

View file

@ -13,7 +13,7 @@
]);
function effectLabel(id = "") {
return EFFECT_REGISTRY?.label?.(id) || ITEM_EFFECT_LABELS[id] || id || "不明";
return EFFECT_REGISTRY?.label?.(id) || ITEM_EFFECT_LABELS[id] || id || "\u4e0d\u660e";
}
function sizeDurationScale(item = null) {
@ -23,6 +23,10 @@
return 1;
}
function recordItemChange(tarinai, id = "", reason = "\u30a2\u30a4\u30c6\u30e0\u52b9\u679c") {
tarinai?.recordChangeCause?.(reason, effectLabel(id));
}
function pickRandomEffects(count = 2) {
const pool = [...RANDOM_EFFECT_POOL];
const out = [];
@ -64,12 +68,15 @@
if (!(id in this.itemEffectTimers)) this.itemEffectTimers[id] = 0;
this.itemEffectTimers[id] = Math.max(this.itemEffectTimers[id] || 0, Number(seconds) || 0);
if (id === "laxative") this.laxativePoopTimer = Math.min(Math.max(this.laxativePoopTimer || 3, 0.2), 3);
this.world?.emit?.("effect:applied", { tarinai: this, effectId: id, duration: this.itemEffectTimers[id] || 0 });
recordItemChange(this, id, "\u6642\u9593\u52b9\u679c");
return true;
},
itemSizeMultiplier() {
this.ensureItemEffectState();
if (this.sizeItemMode === "giant_drug") return 3;
if (this.sizeItemMode === "dwarf_drug") return 0.25;
if (this.sizeItemMode === "giant_drug") return EFFECT_REGISTRY?.modifier?.("giant_drug", "sizeMultiplier", 3) ?? 3;
if (this.sizeItemMode === "dwarf_drug") return EFFECT_REGISTRY?.modifier?.("dwarf_drug", "sizeMultiplier", 0.25) ?? 0.25;
return 1;
},
@ -90,6 +97,8 @@
this.powerEffectKind = mode;
this.powerEffectPulse = Math.max(this.powerEffectPulse || 0, 3.2);
this.spawnPowerItemEffect(mode, 1.5);
this.world?.emit?.("effect:applied", { tarinai: this, effectId: mode, permanent: true });
recordItemChange(this, mode, "\u80fd\u529b\u5909\u5316");
return true;
},
@ -102,6 +111,8 @@
this.powerEffectKind = mode;
this.powerEffectPulse = Math.max(this.powerEffectPulse || 0, 4.0);
this.spawnPowerItemEffect(mode, mode === "giant_drug" ? 1.9 : 1.2);
this.world?.emit?.("effect:applied", { tarinai: this, effectId: mode, permanent: true });
recordItemChange(this, mode, "\u4f53\u683c\u5909\u5316");
return true;
},
@ -117,6 +128,8 @@
this.powerEffectKind = "mercury";
this.powerEffectPulse = Math.max(this.powerEffectPulse || 0, 2.7);
this.spawnPowerItemEffect("mercury", 0.95);
this.world?.emit?.("effect:applied", { tarinai: this, effectId: "mercury", permanent: true, multiplier: this.mercuryLifeMultiplier });
recordItemChange(this, "mercury", "\u5bff\u547d\u5909\u5316");
return true;
},
@ -140,6 +153,8 @@
this.powerEffectPulse = Math.max(this.powerEffectPulse || 0, 2.2);
this.refreshEffectiveSize();
this.spawnPowerItemEffect("zunda_juice", 1.4);
this.world?.emit?.("effect:removed", { tarinai: this, effectId: "all_removable", source: "zunda_juice" });
recordItemChange(this, "zunda_juice", "\u52b9\u679c\u89e3\u9664");
return true;
},
@ -147,101 +162,61 @@
this.ensureItemEffectState();
const scale = sizeDurationScale(item);
let applied = [];
if (type === "laxative") {
this.setTimedItemEffect("laxative", Math.round(60 * scale));
this.spawnPowerItemEffect("laxative", 0.75);
applied.push("laxative");
} else if (type === "protein") {
this.setPowerItemMode("protein");
applied.push("protein");
} else if (type === "niteropu") {
this.setPowerItemMode("niteropu");
applied.push("niteropu");
} else if (type === "ammo") {
this.setTimedItemEffect("ammo", Math.round(18 * scale));
this.spawnPowerItemEffect("ammo", 1.1);
applied.push("ammo");
} else if (type === "mercury") {
this.setMercuryEffect();
applied.push("mercury");
} else if (type === "giant_drug") {
this.setSizeItemMode("giant_drug");
applied.push("giant_drug");
} else if (type === "dwarf_drug") {
this.setSizeItemMode("dwarf_drug");
applied.push("dwarf_drug");
} else if (type === "zunda_juice") {
this.clearAllItemEffects();
applied.push("zunda_juice");
} else if (type === "mystery_drug") {
if (type === "mystery_drug") {
const picks = pickRandomEffects(2);
for (const effect of picks) this.applyRandomizedBehaviorEffect(effect, item);
this.mysteryDrugHistory = [...(this.mysteryDrugHistory || []), `${picks.map(effectLabel).join(" + ")}`].slice(-8);
this.bubble("???", 1.2, ITEM_EFFECT_COLORS.mystery_drug);
this.spawnPowerItemEffect("mystery_drug", 1.0);
applied = picks;
} else if (EFFECT_REGISTRY?.apply?.(type, this, { item, scale, source: "item" })) {
applied.push(type);
if (type === "laxative") {
this.spawnPowerItemEffect("laxative", 0.75);
} else if (type === "ammo") {
this.spawnPowerItemEffect("ammo", 1.1);
}
} else {
return false;
}
if (!options.silentLog && this.world?.log) {
const label = type === "mystery_drug" ? `怪しい薬(${applied.map(effectLabel).join(" + ")})` : effectLabel(type);
this.world.log(`${this.name}に${label}の効果が出た。`, "food", { participants: [this] });
const label = type === "mystery_drug" ? `\u602a\u3057\u3044\u85ac(${applied.map(effectLabel).join(" + ")})` : effectLabel(type);
this.world.log(`${this.name}\u306b${label}\u306e\u52b9\u679c\u304c\u51fa\u305f\u3002`, "food", { participants: [this] });
}
this.recordChangeCause?.("\u30a2\u30a4\u30c6\u30e0\u6442\u53d6", applied.map(effectLabel).join(" + ") || effectLabel(type));
return true;
},
applyRandomizedBehaviorEffect(effect = "", item = null) {
const scale = sizeDurationScale(item);
if (effect === "love_mochi") {
this.loveMochiTimer = Math.max(this.loveMochiTimer || 0, 42 * scale + rand(4, 12));
this.stress = clamp(this.stress - 8, 0, 130);
return true;
}
if (effect === "fight_mochi") {
this.fightMochiTimer = Math.max(this.fightMochiTimer || 0, 52 * scale + rand(10, 18));
this.stress = clamp(this.stress + 10, 0, 130);
return true;
}
if (effect === "sleep_drug") return this.infectSleepDisease?.(item) || true;
if (effect === "laxative") { this.setTimedItemEffect("laxative", Math.round(60 * scale)); return true; }
if (effect === "ammo") { this.setTimedItemEffect("ammo", Math.round(18 * scale)); return true; }
if (effect === "protein") return this.setPowerItemMode("protein");
if (effect === "niteropu") return this.setPowerItemMode("niteropu");
if (effect === "mercury") return this.setMercuryEffect();
if (effect === "giant_drug") return this.setSizeItemMode("giant_drug");
if (effect === "dwarf_drug") return this.setSizeItemMode("dwarf_drug");
if (effect === "disease_zunchi") return this.infectZunchiDisease?.(item, true) || true;
if (effect === "disease_sleep") return this.infectSleepDisease?.(item) || true;
if (effect === "disease_explosion") return this.infectExplosionDisease?.(item) || true;
if (effect === "disease_fight") return this.infectFightDisease?.(item) || true;
return false;
return Boolean(EFFECT_REGISTRY?.apply?.(effect, this, { item, scale, source: "mystery_drug" }));
},
diseaseChance(base = 0) {
const b = Math.max(0, Number(base) || 0);
if (this.powerItemMode === "protein") return b * 0.5;
if (this.powerItemMode === "niteropu") return b * 2.0;
if (this.powerItemMode === "protein") return b * (EFFECT_REGISTRY?.modifier?.("protein", "diseaseChanceMultiplier", 0.5) ?? 0.5);
if (this.powerItemMode === "niteropu") return b * (EFFECT_REGISTRY?.modifier?.("niteropu", "diseaseChanceMultiplier", 2.0) ?? 2.0);
return b;
},
outgoingDamage(amount = 0) {
let value = Number(amount) || 0;
if (this.powerItemMode === "protein") value *= 1.75;
if (this.powerItemMode === "niteropu") value *= 0.5;
if (this.sizeItemMode === "giant_drug") value *= 2.0;
if (this.sizeItemMode === "dwarf_drug") value *= 0.25;
let value = (Number(amount) || 0) * (this.geneticStatRatio ? this.geneticStatRatio("attack") : 1);
if (this.powerItemMode === "protein") value *= EFFECT_REGISTRY?.modifier?.("protein", "damageMultiplier", 1.75) ?? 1.75;
if (this.powerItemMode === "niteropu") value *= EFFECT_REGISTRY?.modifier?.("niteropu", "damageMultiplier", 0.5) ?? 0.5;
if (this.sizeItemMode === "giant_drug") value *= EFFECT_REGISTRY?.modifier?.("giant_drug", "damageMultiplier", 2.0) ?? 2.0;
if (this.sizeItemMode === "dwarf_drug") value *= EFFECT_REGISTRY?.modifier?.("dwarf_drug", "damageMultiplier", 0.25) ?? 0.25;
return value;
},
itemSpeedMultiplier() {
let value = this.hasItemEffect("ammo") ? 10 : 1;
if (this.sizeItemMode === "giant_drug") value *= 1.5;
if (this.sizeItemMode === "dwarf_drug") value *= 0.5;
let value = this.hasItemEffect("ammo") ? (EFFECT_REGISTRY?.modifier?.("ammo", "speedMultiplier", 10) ?? 10) : 1;
if (this.sizeItemMode === "giant_drug") value *= EFFECT_REGISTRY?.modifier?.("giant_drug", "speedMultiplier", 1.5) ?? 1.5;
if (this.sizeItemMode === "dwarf_drug") value *= EFFECT_REGISTRY?.modifier?.("dwarf_drug", "speedMultiplier", 0.5) ?? 0.5;
return value;
},
applyFoodHungerRelief(amount = 0) {
if (this.hasItemEffect("laxative")) return 0;
if (this.hasItemEffect("laxative")) return (Number(amount) || 0) * (EFFECT_REGISTRY?.modifier?.("laxative", "hungerReliefMultiplier", 0) ?? 0);
this.hunger -= Number(amount) || 0;
return amount;
},
@ -256,8 +231,8 @@
if (this.hasItemEffect("laxative")) {
this.laxativePoopTimer = Math.max(0, (this.laxativePoopTimer || 3) - step);
while (this.laxativePoopTimer <= 0 && this.hasItemEffect("laxative")) {
this.laxativePoopTimer += 3;
this.forceLaxativePoop();
this.laxativePoopTimer += EFFECT_REGISTRY?.get?.("laxative")?.tickInterval || 3;
EFFECT_REGISTRY?.tick?.("laxative", this, step);
}
} else {
this.laxativePoopTimer = Math.min(Math.max(this.laxativePoopTimer || 3, 0.2), 3);
@ -266,8 +241,7 @@
this.itemDamageTimer = Math.max(0, (this.itemDamageTimer || 1) - step);
while (this.itemDamageTimer <= 0 && !this.dead && (this.sizeItemMode === "giant_drug" || this.sizeItemMode === "dwarf_drug")) {
this.itemDamageTimer += 1;
this.damage?.(1, this.sizeItemMode === "giant_drug" ? "巨大薬" : "矮小薬");
if (this.world?.effects) this.spawnPowerItemEffect(this.sizeItemMode, 0.25);
EFFECT_REGISTRY?.tick?.(this.sizeItemMode, this, step);
}
} else {
this.itemDamageTimer = Math.min(Math.max(this.itemDamageTimer || 1, 0.08), 1);
@ -289,10 +263,14 @@
this.world.spawnZunchi?.(x, y);
this.poopCount = (this.poopCount || 0) + 1;
this.digest = Math.max(0, (this.digest || 0) - 3.0);
this.bubble("ぶりゅっ", 1.2, ITEM_EFFECT_COLORS.laxative);
const now = this.world?.time || 0;
if (now >= (this.nextPoopBubbleAt || -999)) {
this.nextPoopBubbleAt = now + 2.2;
this.bubble("\u3076\u308a\u3085\u3063", 1.2, ITEM_EFFECT_COLORS.laxative);
}
if ((this.world.time || 0) > (this.nextLaxativeLogAt || -999)) {
this.nextLaxativeLogAt = (this.world.time || 0) + 9;
this.world.log?.(`${this.name}は下剤の効果でずんちを放出した。`, "accident", { participants: [this] });
this.world.log?.(`${this.name}\u306f\u4e0b\u5264\u306e\u52b9\u679c\u3067\u305a\u3093\u3061\u3092\u653e\u51fa\u3057\u305f\u3002`, "accident", { participants: [this] });
}
},
@ -338,6 +316,9 @@
o.vy += py * 160;
o.hurtTimer = Math.max(o.hurtTimer || 0, 1.1);
o.fallTimer = Math.max(o.fallTimer || 0, 0.72);
const bumpDamage = Math.max(0.6, Math.min(3.0, speed / 260));
o.damage?.(bumpDamage, "\u5f3e\u85ac\u885d\u7a81");
this.adjustPersonality?.("aggression", 0.012, "after ammo knockback");
this.world.spawnFallEffect?.(o.x, o.y + o.radius * 0.45, 1.05);
audio.damage?.(12);
this.ammoBumpCooldown = 0.12;
@ -363,22 +344,8 @@
activeItemEffectSummary() {
this.ensureItemEffectState();
const rows = [];
const add = (id, timer = 0) => {
const label = effectLabel(id);
const detail = EFFECT_REGISTRY?.display?.(id, timer, this) || "";
rows.push({ id, label, detail });
};
if (this.powerItemMode === "protein") add("protein");
if (this.powerItemMode === "niteropu") add("niteropu");
if (this.lifeItemMode === "mercury") add("mercury");
if (this.sizeItemMode === "giant_drug") add("giant_drug");
if (this.sizeItemMode === "dwarf_drug") add("dwarf_drug");
if ((this.itemEffectTimers.laxative || 0) > 0.04) add("laxative", this.itemEffectTimers.laxative);
if ((this.itemEffectTimers.ammo || 0) > 0.04) add("ammo", this.itemEffectTimers.ammo);
if ((this.loveMochiTimer || 0) > 0.1) add("love_mochi", this.loveMochiTimer);
if ((this.fightMochiTimer || 0) > 0.1) add("fight_mochi", this.fightMochiTimer);
return rows;
if (EFFECT_REGISTRY?.activeSummary) return EFFECT_REGISTRY.activeSummary(this);
return [];
},
}));