This commit is contained in:
33333-33333 2026-07-01 14:41:05 +09:00
commit 4d3fc2cd47
84 changed files with 3429 additions and 3480 deletions

View file

@ -1,82 +1,6 @@
"use strict";
// Item field rendering. Kept separate from construction and lifecycle logic.
function segmentPathCacheKey(item, segments, extra = "") {
const version = Number(item?._mechanicalShapeVersion || 0) || 0;
const len = Array.isArray(segments) ? segments.length : 0;
let h = len * 2654435761;
if (Array.isArray(segments)) {
const step = Math.max(1, Math.floor(len / 24));
for (let i = 0; i < len; i += step) {
const seg = segments[i];
if (!Array.isArray(seg)) continue;
for (let j = 0; j < 4; j += 1) {
h ^= Math.round((Number(seg[j]) || 0) * 10) & 0xffff;
h = Math.imul(h, 16777619);
}
}
}
return `${item?.type || ""}|${version}|${len}|${h >>> 0}|${extra}`;
}
function getSegmentPath(item, segments, extra = "") {
if (typeof Path2D === "undefined" || !Array.isArray(segments)) return null;
const key = segmentPathCacheKey(item, segments, extra);
const cache = item._segmentRenderPathCache || (item._segmentRenderPathCache = Object.create(null));
if (cache.key === key && cache.path) return cache.path;
const path = new Path2D();
for (const seg of segments) {
if (!Array.isArray(seg) || seg.length < 4) continue;
path.moveTo(Number(seg[0]) || 0, Number(seg[1]) || 0);
path.lineTo(Number(seg[2]) || 0, Number(seg[3]) || 0);
}
cache.key = key;
cache.path = path;
return path;
}
function strokeSegments(ctx, item, segments, extra = "") {
const path = getSegmentPath(item, segments, extra);
if (path) {
ctx.stroke(path);
return;
}
ctx.beginPath();
for (const seg of segments || []) {
if (!Array.isArray(seg) || seg.length < 4) continue;
ctx.moveTo(Number(seg[0]) || 0, Number(seg[1]) || 0);
ctx.lineTo(Number(seg[2]) || 0, Number(seg[3]) || 0);
}
ctx.stroke();
}
function mechanicalRenderTier() {
return window.TarinaiPerf.renderQualityTier();
}
function itemShadowQualityTier() {
return window.TarinaiPerf?.shadowQualityTier?.() || "high";
}
function itemShadowsEnabled() {
return itemShadowQualityTier() !== "off";
}
function drawRopeParticlePath(ctx, particles, ox, oy) {
if (!Array.isArray(particles) || particles.length < 2) return false;
const tier = mechanicalRenderTier();
const stride = tier === "low" && particles.length > 10 ? 2 : 1;
ctx.moveTo((Number(particles[0].x) || 0) - ox, (Number(particles[0].y) || 0) - oy);
for (let i = stride; i < particles.length - 1; i += stride) {
ctx.lineTo((Number(particles[i].x) || 0) - ox, (Number(particles[i].y) || 0) - oy);
}
const last = particles[particles.length - 1];
ctx.lineTo((Number(last.x) || 0) - ox, (Number(last.y) || 0) - oy);
return true;
}
Object.assign(Item.prototype, {
draw(ctx, t, lighting = null) {
const lightState = lighting || getLightingState(world);
@ -710,67 +634,51 @@ draw(ctx, t, lighting = null) {
ctx.restore();
} else if (this.type === "fire") {
const r = this.r || 14;
const pulse = 0.82 + Math.sin(t * 10 + this.seed) * 0.12;
const phase = t * 7.0 + this.seed;
ctx.save();
if (itemShadowsEnabled()) {
ctx.shadowColor = "rgba(255,104,28,0.42)";
ctx.shadowBlur = 12;
}
ctx.globalAlpha *= 0.88;
const grad = ctx.createRadialGradient(0, r * 0.22, r * 0.18, 0, 0, r * 1.55);
grad.addColorStop(0, "rgba(255,238,112,0.94)");
grad.addColorStop(0.36, "rgba(255,116,36,0.86)");
grad.addColorStop(1, "rgba(198,32,16,0.08)");
ctx.fillStyle = grad;
ctx.beginPath();
ctx.ellipse(0, r * 0.18, r * 1.25 * pulse, r * 0.72, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "rgba(255,96,24,0.90)";
ctx.strokeStyle = "rgba(255,224,86,0.76)";
ctx.lineWidth = Math.max(1.2, r * 0.10);
for (let i = 0; i < 4; i++) {
const a = -Math.PI / 2 + (i - 1.5) * 0.36 + Math.sin(t * 6 + this.seed + i) * 0.10;
ctx.globalAlpha *= 0.90;
if (typeof drawSimpleFireShape === "function") {
drawSimpleFireShape(ctx, 0, 0, r * 1.12, { phase, shadow: itemShadowsEnabled() });
} else {
ctx.fillStyle = "rgba(236,46,24,0.88)";
ctx.beginPath();
ctx.moveTo(Math.cos(a + 1.7) * r * 0.38, r * 0.48);
ctx.quadraticCurveTo(Math.cos(a) * r * (0.45 + i * 0.08), -r * 0.10, Math.cos(a) * r * 0.38, -r * (1.18 + i * 0.13) * pulse);
ctx.quadraticCurveTo(Math.cos(a - 0.7) * r * 0.20, -r * 0.20, Math.cos(a - 1.4) * r * 0.36, r * 0.48);
ctx.closePath();
ctx.ellipse(0, -r * 0.18, r * 0.48, r * 0.96, 0, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
}
ctx.fillStyle = "rgba(255,236,106,0.92)";
ctx.beginPath();
ctx.ellipse(0, -r * 0.30, r * 0.42, r * 0.82 * pulse, 0, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
} else if (this.type === "firecracker" || this.type === "flame_firecracker") {
const flameMode = this.type === "flame_firecracker";
const fuse = clamp((this.fuseTimer ?? 5) / Math.max(this.fuseMax || 5, 0.1), 0, 1);
const flash = fuse < 0.35 ? (0.5 + Math.sin(t * 20 + this.seed) * 0.5) : 0;
const timerText = String(Math.max(0, Math.ceil(this.fuseTimer ?? 5)));
ctx.rotate(-0.22 + Math.sin(this.seed) * 0.12);
ctx.fillStyle = flash > 0.65 ? "#ffed77" : (flameMode ? "#e76d29" : "#d94b43");
ctx.strokeStyle = "rgba(96,48,34,0.78)";
ctx.fillStyle = flash > 0.65 ? "#ffed77" : (flameMode ? "#d8241f" : "#5a4744");
ctx.strokeStyle = flameMode ? "rgba(96,18,18,0.88)" : "rgba(35,30,29,0.88)";
ctx.lineWidth = 2;
roundedRect(ctx, -this.r * 0.72, -this.r * 0.86, this.r * 1.44, this.r * 1.72, 5);
ctx.fill();
ctx.stroke();
ctx.fillStyle = flameMode ? "#ffbb43" : "#f4d15b";
ctx.fillStyle = flameMode ? "#ff6b32" : "#897065";
ctx.fillRect(-this.r * 0.55, -this.r * 0.54, this.r * 1.1, this.r * 0.20);
ctx.fillRect(-this.r * 0.55, this.r * 0.34, this.r * 1.1, this.r * 0.20);
ctx.strokeStyle = "rgba(74,55,39,0.82)";
ctx.strokeStyle = "rgba(48,38,31,0.86)";
ctx.lineWidth = 2.2;
ctx.beginPath();
ctx.moveTo(0, -this.r * 0.88);
ctx.quadraticCurveTo(this.r * 0.32, -this.r * 1.34, this.r * 0.92, -this.r * 1.42);
ctx.stroke();
ctx.fillStyle = flash > 0.1 ? "rgba(255,221,82,0.92)" : "rgba(255,162,62,0.78)";
ctx.fillStyle = flash > 0.1 ? "rgba(255,221,82,0.92)" : (flameMode ? "rgba(255,80,40,0.78)" : "rgba(188,148,88,0.62)");
ctx.beginPath();
ctx.arc(this.r * 0.98, -this.r * 1.42, 2.5 + flash * 2.2, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "rgba(42,36,29,0.66)";
ctx.font = "bold 10px ui-rounded, sans-serif";
ctx.fillStyle = "rgba(255,246,214,0.92)";
ctx.strokeStyle = flameMode ? "rgba(84,18,14,0.92)" : "rgba(24,22,21,0.92)";
ctx.lineWidth = 2.6;
ctx.font = `bold ${Math.max(10, this.r * 0.72)}px ui-rounded, sans-serif`;
ctx.textAlign = "center";
ctx.fillText(flameMode ? "F" : String(Math.ceil(this.fuseTimer ?? 5)), 0, this.r * 1.42);
ctx.textBaseline = "middle";
ctx.strokeText(timerText, 0, this.r * 0.02);
ctx.fillText(timerText, 0, this.r * 0.02);
} else if (this.type === "fence_v" || this.type === "fence_h" || this.type === "glass_wall" || this.type === "bounce_fence" || this.type === "bounce_fence_v" || this.type === "gate_fence") {
const bounce = this.type === "bounce_fence" || this.type === "bounce_fence_v";
const gate = this.type === "gate_fence";
@ -1020,26 +928,12 @@ draw(ctx, t, lighting = null) {
ctx.strokeStyle = styleNight ? "rgba(180,150,116,0.88)" : "rgba(132,94,54,0.92)";
ctx.lineWidth = 4.2;
ctx.beginPath();
if (particles) {
drawRopeParticlePath(ctx, particles, this.x, this.y);
} else {
const mx = Number.isFinite(Number(pb?.linkScalar?.(this, "midX", NaN))) ? Number(pb.linkScalar(this, "midX", 0)) - this.x : (ax + bx) * 0.5;
const my = Number.isFinite(Number(pb?.linkScalar?.(this, "midY", NaN))) ? Number(pb.linkScalar(this, "midY", 0)) - this.y : (ay + by) * 0.5;
ctx.moveTo(ax, ay);
ctx.quadraticCurveTo(mx, my, bx, by);
}
drawRopeRuntimePath(ctx, particles, this, pb, ax, ay, bx, by);
ctx.stroke();
ctx.strokeStyle = styleNight ? "rgba(236,214,180,0.56)" : "rgba(255,236,190,0.52)";
ctx.lineWidth = 1.5;
ctx.beginPath();
if (particles) {
drawRopeParticlePath(ctx, particles, this.x, this.y);
} else {
const mx = Number.isFinite(Number(pb?.linkScalar?.(this, "midX", NaN))) ? Number(pb.linkScalar(this, "midX", 0)) - this.x : (ax + bx) * 0.5;
const my = Number.isFinite(Number(pb?.linkScalar?.(this, "midY", NaN))) ? Number(pb.linkScalar(this, "midY", 0)) - this.y : (ay + by) * 0.5;
ctx.moveTo(ax, ay);
ctx.quadraticCurveTo(mx, my, bx, by);
}
drawRopeRuntimePath(ctx, particles, this, pb, ax, ay, bx, by);
ctx.stroke();
}
ctx.fillStyle = this.type === "rod" ? (styleNight ? "rgba(120,112,98,0.96)" : "rgba(114,96,72,0.96)") : (styleNight ? "rgba(112,84,54,0.95)" : "rgba(162,112,63,0.95)");