This commit is contained in:
33333-33333 2026-06-24 18:49:17 +09:00
commit d875df8600
22 changed files with 625 additions and 496 deletions

View file

@ -336,6 +336,7 @@ function drawToolItemPreview(ctx, type = "", opts = {}) {
if (!ctx || !type) return false;
const w = Math.max(1, Number(opts.width || ctx.canvas?.width || 72));
const h = Math.max(1, Number(opts.height || ctx.canvas?.height || 72));
const watermark = !!opts.watermark;
const localR = previewItemRadiusFor(type);
const item = Object.create(Item.prototype);
Object.assign(item, {
@ -371,7 +372,10 @@ function drawToolItemPreview(ctx, type = "", opts = {}) {
if (type === "water") item.amount = 50;
ctx.save();
ctx.clearRect(0, 0, w, h);
ctx.translate(w / 2, h / 2 + (type === "signboard" ? 11 : type === "genkotsu" ? 12 : type === "fence_v" || type === "fence_h" ? 1 : 4));
const baseOffsetY = type === "signboard" ? 11 : type === "genkotsu" ? 12 : type === "fence_v" || type === "fence_h" ? 1 : 4;
const centerX = watermark ? w * 0.78 : w / 2;
const centerY = watermark ? (h * 0.80 + baseOffsetY * 0.15) : (h / 2 + baseOffsetY);
ctx.translate(centerX, centerY);
const scaleMap = {
genkotsu: 0.52,
bed: 0.80,
@ -386,7 +390,14 @@ function drawToolItemPreview(ctx, type = "", opts = {}) {
oshibyo: 0.92,
firecracker: 0.90,
};
ctx.scale(scaleMap[type] || 0.92, scaleMap[type] || 0.92);
let scale = scaleMap[type] || 0.92;
if (isConsumableSpriteType(type)) scale *= 1.95;
else if (["grass", "water", "water_bowl", "zunda_juice"].includes(type)) scale *= 1.85;
else if (type === "duplicator") scale *= 1.55;
else if (["signboard", "bed", "nest_box", "ant_nest", "pushpin", "oshibyo", "fence_v", "fence_h", "firecracker", "genkotsu"].includes(type)) scale *= 1.08;
else if (typeof isParamEffectItemType === "function" && isParamEffectItemType(type)) scale *= 1.35;
if (watermark) scale *= 1.42;
ctx.scale(scale, scale);
try {
item.draw(ctx, 0, typeof getLightingState === "function" ? getLightingState(globalThis.world) : null);
} catch (err) {
@ -472,7 +483,7 @@ class Item {
this.stageTimer = 0;
this.fertility = 0;
this.freshness = 1;
this.spawnGrace = 1.2;
this.spawnGrace = 10.0;
this.zunchiVariant = stableUnit(this.id, "zunchi-variant") < 0.5 ? "zunchi" : "zunchi_02";
}
if (type === "ant_nest") {
@ -955,7 +966,7 @@ class Item {
this.deletable = false;
this.pinTargetId = t.id;
const faceDir = t.facingDir ? t.facingDir() : (t.facing || 1);
const visualSide = faceDir;
const visualSide = isOshibyo ? -faceDir : faceDir;
this.pinVisualSide = visualSide;
this.pinAttachAngle = isOshibyo ? visualSide * 0.36 : Math.atan2(dy || -1, dx || visualSide);
this.pinAttachDistance = isOshibyo ? (t.radius || 16) * 0.72 : clamp(distToTarget || (t.radius || 16) * 0.58, (t.radius || 16) * 0.20, (t.radius || 16) * 0.74);
@ -1004,7 +1015,7 @@ class Item {
t.stuckPushpinId = this.id;
this.deletable = false;
const faceDir = t.facingDir ? t.facingDir() : (t.facing || 1);
const visualSide = faceDir;
const visualSide = isOshibyo ? -faceDir : faceDir;
this.pinVisualSide = visualSide;
this.x = isOshibyo ? t.x + visualSide * (t.radius || 16) * 0.72 : t.x + visualSide * (t.radius || 16) * 0.36;
this.y = isOshibyo ? t.y + (t.radius || 16) * 0.42 : t.y - (t.radius || 16) * 0.04;
@ -1171,31 +1182,31 @@ class Item {
updateZunchi(dt, worldRef) {
const rainy = worldRef.weather === "light_rain";
const rainBoost = rainy ? 1.95 : 1;
const decayBoost = rainy ? 2.15 : 1;
const rainBoost = rainy ? 1.28 : 1;
const decayBoost = rainy ? 1.35 : 1;
let waterBoost = 0;
const nearby = worldRef.nearbyItems ? worldRef.nearbyItems(this.x, this.y, 84) : (worldRef.items || []);
for (const it of nearby) {
if (it.type !== "water") continue;
waterBoost += clamp(1 - distXY(this.x, this.y, it.x, it.y) / 80, 0, 1);
}
this.stageTimer += dt * 2.0 * (rainBoost + waterBoost * 1.3);
this.stageTimer += dt * 0.70 * (rainBoost + waterBoost * 0.65);
const decayDt = (this.spawnGrace || 0) > 0 ? 0 : dt;
if (this.stage === "fresh") {
this.freshness = clamp(1 - this.stageTimer / 110, 0, 1);
this.amount -= decayDt * 0.05 * decayBoost;
this.amount -= decayDt * 0.018 * decayBoost;
if (this.stageTimer > 110) { this.stage = "dry"; this.stageTimer = 0; }
} else if (this.stage === "dry") {
this.freshness = clamp(0.55 - this.stageTimer / 220, 0.20, 0.55);
this.amount -= decayDt * 0.09 * decayBoost;
this.amount -= decayDt * 0.032 * decayBoost;
if (this.stageTimer > 150) { this.stage = "decomposing"; this.stageTimer = 0; this.fertility = 0.35; }
} else if (this.stage === "decomposing") {
this.fertility = clamp(this.fertility + dt * 0.015, 0, 1);
this.amount -= decayDt * 0.12 * decayBoost;
this.amount -= decayDt * 0.046 * decayBoost;
if (this.stageTimer > 190) { this.stage = "fertile_soil"; this.stageTimer = 0; this.amount = Math.min(this.amount, 140); }
} else if (this.stage === "fertile_soil") {
this.fertility = clamp(1 - this.stageTimer / 360, 0, 1);
this.amount -= decayDt * 0.26 * decayBoost;
this.amount -= decayDt * 0.090 * decayBoost;
}
}
get dead() {
@ -1522,6 +1533,7 @@ class Item {
} else if (this.type === "signboard") {
ctx.save();
const boardGrad = ctx.createLinearGradient(0, -this.r * 1.28, 0, this.r * 0.12);
const boardHalfW = this.r * 1.20;
boardGrad.addColorStop(0, styleNight ? "#d5cab8" : "#fff8e8");
boardGrad.addColorStop(0.55, styleNight ? "#c0b29a" : "#f3e3c6");
boardGrad.addColorStop(1, styleNight ? "#aa9a82" : "#dfc397");
@ -1533,7 +1545,7 @@ class Item {
ctx.stroke();
ctx.fillStyle = boardGrad;
ctx.strokeStyle = styleNight ? "#63513c" : "#a77e48";
roundedRect(ctx, -this.r * 1.36, -this.r * 1.28, this.r * 2.72, this.r * 1.38, this.r * 0.18);
roundedRect(ctx, -boardHalfW, -this.r * 1.28, boardHalfW * 2, this.r * 1.38, this.r * 0.18);
ctx.fill();
ctx.stroke();
ctx.strokeStyle = styleNight ? "rgba(103,83,58,0.36)" : "rgba(167,126,72,0.38)";
@ -1541,12 +1553,12 @@ class Item {
for (let i = 0; i < 3; i++) {
const y = -this.r * 1.02 + i * this.r * 0.36;
ctx.beginPath();
ctx.moveTo(-this.r * 1.12, y);
ctx.quadraticCurveTo(-this.r * 0.12, y + Math.sin(this.seed + i) * 2, this.r * 1.12, y + Math.cos(this.seed + i) * 2);
ctx.moveTo(-boardHalfW * 0.82, y);
ctx.quadraticCurveTo(-this.r * 0.12, y + Math.sin(this.seed + i) * 2, boardHalfW * 0.82, y + Math.cos(this.seed + i) * 2);
ctx.stroke();
}
ctx.fillStyle = "rgba(255,255,255,0.28)";
roundedRect(ctx, -this.r * 1.12, -this.r * 1.10, this.r * 2.24, this.r * 0.20, this.r * 0.08);
roundedRect(ctx, -boardHalfW * 0.82, -this.r * 1.10, boardHalfW * 1.64, this.r * 0.20, this.r * 0.08);
ctx.fill();
const raw = String(this.text || "").replace(/\r/g, "").trim();
if (raw) {