more
This commit is contained in:
parent
37087d08a7
commit
0b9ff1363b
45 changed files with 680 additions and 890 deletions
206
js/items.js
206
js/items.js
|
|
@ -27,6 +27,137 @@ function passiveFoodDecayRate(item) {
|
|||
return PASSIVE_FOOD_DECAY_PER_SECOND * sizeMul * typeMul;
|
||||
}
|
||||
|
||||
function drawOvalWaterDropSprite(ctx, r, palette = {}) {
|
||||
const fill = palette.fill || "rgba(86, 157, 224, 0.82)";
|
||||
const stroke = palette.stroke || "rgba(45, 101, 168, 0.52)";
|
||||
const highlight = palette.highlight || "rgba(255,255,255,0.64)";
|
||||
ctx.save();
|
||||
ctx.fillStyle = fill;
|
||||
ctx.strokeStyle = stroke;
|
||||
ctx.lineWidth = Math.max(1.6, r * 0.13);
|
||||
// Horizontal oval item droplet silhouette for fallen water / zunda juice / mercury; rain overlay itself is a separate diagonal-line effect.
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(0, 0, r * 1.42, r * 0.56, -0.04, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 0.72;
|
||||
ctx.fillStyle = highlight;
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(-r * 0.46, -r * 0.16, r * 0.34, r * 0.13, -0.18, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawSleepTabletSprite(ctx, r) {
|
||||
ctx.save();
|
||||
ctx.rotate(-0.18);
|
||||
ctx.fillStyle = "#ebe4ff";
|
||||
ctx.strokeStyle = "rgba(74, 60, 144, 0.72)";
|
||||
ctx.lineWidth = Math.max(1.8, r * 0.14);
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(0, 0, r * 0.92, r * 0.66, 0, 0, Math.PI * 2);
|
||||
ctx.fill(); ctx.stroke();
|
||||
ctx.fillStyle = "rgba(112, 91, 188, 0.82)";
|
||||
ctx.beginPath();
|
||||
ctx.arc(r * 0.12, -r * 0.04, r * 0.38, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = "#ebe4ff";
|
||||
ctx.beginPath();
|
||||
ctx.arc(r * 0.28, -r * 0.11, r * 0.38, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 0.52;
|
||||
ctx.strokeStyle = "rgba(255,255,255,0.94)";
|
||||
ctx.lineWidth = Math.max(1.2, r * 0.08);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(-r * 0.56, -r * 0.28);
|
||||
ctx.quadraticCurveTo(-r * 0.14, -r * 0.48, r * 0.48, -r * 0.20);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawLaxativeTabletSprite(ctx, r) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = "#f4d49a";
|
||||
ctx.strokeStyle = "rgba(98, 61, 29, 0.82)";
|
||||
ctx.lineWidth = Math.max(1.8, r * 0.14);
|
||||
roundedRect(ctx, -r * 1.02, -r * 0.54, r * 2.04, r * 1.08, r * 0.34);
|
||||
ctx.fill(); ctx.stroke();
|
||||
// Embedded zunchi mound motif: silhouette-based, not color-only.
|
||||
ctx.fillStyle = "rgba(96, 70, 38, 0.88)";
|
||||
ctx.strokeStyle = "rgba(56, 39, 22, 0.42)";
|
||||
ctx.lineWidth = Math.max(1.0, r * 0.07);
|
||||
const lumps = [
|
||||
[-0.38, 0.11, 0.25, 0.17],
|
||||
[-0.12, -0.03, 0.29, 0.20],
|
||||
[0.20, 0.10, 0.27, 0.18],
|
||||
[0.03, -0.23, 0.20, 0.14],
|
||||
];
|
||||
for (const [x,y,w,h] of lumps) {
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(r*x, r*y, r*w, r*h, 0, 0, Math.PI * 2);
|
||||
ctx.fill(); ctx.stroke();
|
||||
}
|
||||
ctx.globalAlpha = 0.45;
|
||||
ctx.strokeStyle = "rgba(255,255,255,0.90)";
|
||||
ctx.lineWidth = Math.max(1.0, r * 0.07);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(-r * 0.68, -r * 0.32);
|
||||
ctx.quadraticCurveTo(-r * 0.24, -r * 0.48, r * 0.46, -r * 0.26);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawMysteryTabletSprite(ctx, r) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = "#f3ecff";
|
||||
ctx.strokeStyle = "rgba(91, 55, 150, 0.84)";
|
||||
ctx.lineWidth = Math.max(1.9, r * 0.15);
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(0, 0, r * 0.94, r * 0.78, 0.10, 0, Math.PI * 2);
|
||||
ctx.fill(); ctx.stroke();
|
||||
ctx.fillStyle = "rgba(91,55,150,0.92)";
|
||||
ctx.font = `bold ${Math.round(r * 1.35)}px ui-rounded, sans-serif`;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText("?", 0, -r * 0.04);
|
||||
ctx.globalAlpha = 0.52;
|
||||
ctx.strokeStyle = "rgba(255,255,255,0.90)";
|
||||
ctx.lineWidth = Math.max(1.1, r * 0.08);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(-r * 0.52, -r * 0.34);
|
||||
ctx.quadraticCurveTo(-r * 0.12, -r * 0.54, r * 0.42, -r * 0.28);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawBulletSprite(ctx, r) {
|
||||
ctx.save();
|
||||
ctx.rotate(0.0);
|
||||
const g = ctx.createLinearGradient(-r, 0, r, 0);
|
||||
g.addColorStop(0, "#b06f23");
|
||||
g.addColorStop(0.48, "#f4c46a");
|
||||
g.addColorStop(1, "#a05a1f");
|
||||
ctx.fillStyle = g;
|
||||
ctx.strokeStyle = "rgba(87, 51, 22, 0.78)";
|
||||
ctx.lineWidth = Math.max(1.7, r * 0.13);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(r * 0.86, 0);
|
||||
ctx.quadraticCurveTo(r * 0.42, -r * 0.52, -r * 0.34, -r * 0.52);
|
||||
ctx.lineTo(-r * 0.88, -r * 0.40);
|
||||
ctx.lineTo(-r * 0.88, r * 0.40);
|
||||
ctx.lineTo(-r * 0.34, r * 0.52);
|
||||
ctx.quadraticCurveTo(r * 0.42, r * 0.52, r * 0.86, 0);
|
||||
ctx.closePath();
|
||||
ctx.fill(); ctx.stroke();
|
||||
ctx.strokeStyle = "rgba(255,237,176,0.62)";
|
||||
ctx.lineWidth = Math.max(1.0, r * 0.07);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(-r * 0.44, -r * 0.34);
|
||||
ctx.lineTo(r * 0.42, -r * 0.20);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
class Item {
|
||||
constructor(type, x, y) {
|
||||
this.id = crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
|
||||
|
|
@ -624,15 +755,15 @@ class Item {
|
|||
}
|
||||
} else if (typeof isParamEffectItemType === "function" && isParamEffectItemType(this.type)) {
|
||||
const meta = {
|
||||
laxative: { fill: "#eef0b8", stroke: "#879046", accent: "#dfe770", kind: "pill" },
|
||||
laxative: { fill: "#f1d18a", stroke: "#774c1f", accent: "#5f3a1b", kind: "laxative" },
|
||||
protein: { fill: "#f4a24f", stroke: "#b45b27", accent: "#ffe2b9", kind: "powder" },
|
||||
niteropu: { fill: "#8a79d0", stroke: "#4c3f91", accent: "#d8d1ff", kind: "powder" },
|
||||
ammo: { fill: "#ffe8b6", stroke: "#b37a26", accent: "#d0942f", kind: "box" },
|
||||
mystery_drug: { fill: "#e9ffe8", stroke: "#4a9b65", accent: "#9de7ad", kind: "pill" },
|
||||
mercury: { fill: "rgba(216,219,220,0.98)", stroke: "rgba(198,202,204,0.98)", accent: "rgba(162,169,174,0.98)", kind: "droplet" },
|
||||
ammo: { fill: "#f4c46a", stroke: "#6f431f", accent: "#ffe8a8", kind: "bullet" },
|
||||
mystery_drug: { fill: "#dff4ff", stroke: "#27587b", accent: "#437c97", kind: "mystery" },
|
||||
mercury: { fill: "rgba(210,216,222,0.94)", stroke: "rgba(112,122,132,0.62)", accent: "rgba(255,255,255,0.72)", kind: "droplet" },
|
||||
giant_drug: { fill: "#ffe3cf", stroke: "#c9632f", accent: "#ffb47b", kind: "pill" },
|
||||
dwarf_drug: { fill: "#e9e9ff", stroke: "#6967ac", accent: "#b8b5f4", kind: "pill" },
|
||||
zunda_juice: { fill: "rgba(134,224,91,0.98)", stroke: "rgba(76,168,57,0.98)", accent: "rgba(202,255,186,0.98)", kind: "droplet" },
|
||||
zunda_juice: { fill: "rgba(125,218,82,0.94)", stroke: "rgba(63,150,50,0.62)", accent: "rgba(238,255,226,0.72)", kind: "droplet" },
|
||||
}[this.type] || { fill: "#fffaf1", stroke: "#8d6f48", accent: "#ddd", kind: "pill" };
|
||||
const localR = this.r * (this.type === "giant_drug" ? 1.08 : (this.type === "dwarf_drug" ? 0.92 : 1));
|
||||
ctx.rotate(Math.sin(this.seed) * 0.10);
|
||||
|
|
@ -662,29 +793,13 @@ class Item {
|
|||
ctx.fill();
|
||||
ctx.restore();
|
||||
} else if (meta.kind === "droplet") {
|
||||
ctx.save();
|
||||
ctx.lineCap = "round";
|
||||
ctx.strokeStyle = meta.stroke;
|
||||
ctx.lineWidth = Math.max(2.2, localR * 0.16);
|
||||
ctx.globalAlpha = 0.92;
|
||||
const lean = -localR * 0.34;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(localR * 0.18, -localR * 0.90);
|
||||
ctx.lineTo(localR * 0.18 + lean, localR * 0.42);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 0.70;
|
||||
ctx.fillStyle = meta.fill;
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(localR * 0.18 + lean, localR * 0.54, localR * 0.24, localR * 0.38, -0.18, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 0.50;
|
||||
ctx.strokeStyle = meta.accent;
|
||||
ctx.lineWidth = Math.max(1.0, localR * 0.07);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(localR * 0.10, -localR * 0.72);
|
||||
ctx.lineTo(localR * 0.10 + lean * 0.72, localR * 0.18);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
drawOvalWaterDropSprite(ctx, localR, { fill: meta.fill, stroke: meta.stroke, highlight: meta.accent });
|
||||
} else if (meta.kind === "laxative") {
|
||||
drawLaxativeTabletSprite(ctx, localR);
|
||||
} else if (meta.kind === "mystery") {
|
||||
drawMysteryTabletSprite(ctx, localR);
|
||||
} else if (meta.kind === "bullet") {
|
||||
drawBulletSprite(ctx, localR);
|
||||
} else if (meta.kind === "box") {
|
||||
ctx.fillStyle = meta.fill;
|
||||
ctx.strokeStyle = meta.stroke;
|
||||
|
|
@ -721,19 +836,7 @@ class Item {
|
|||
ctx.restore();
|
||||
}
|
||||
} else if (this.type === "sleep_drug") {
|
||||
ctx.fillStyle = "#f5f0ff";
|
||||
ctx.strokeStyle = "rgba(112, 83, 170, 0.55)";
|
||||
ctx.lineWidth = 2;
|
||||
ctx.rotate(-0.45);
|
||||
roundedRect(ctx, -this.r * 0.95, -this.r * 0.45, this.r * 1.90, this.r * 0.90, this.r * 0.45);
|
||||
ctx.fill(); ctx.stroke();
|
||||
ctx.fillStyle = "rgba(152, 116, 218, 0.58)";
|
||||
ctx.fillRect(-1, -this.r * 0.42, 2, this.r * 0.84);
|
||||
ctx.rotate(0.45);
|
||||
ctx.fillStyle = "rgba(255,255,255,0.58)";
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(-this.r * 0.36, -this.r * 0.16, this.r * 0.25, this.r * 0.09, -0.20, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
drawSleepTabletSprite(ctx, this.r);
|
||||
} else if (this.type === "genkotsu") {
|
||||
const img = typeof getRenderableImage === "function" ? getRenderableImage("genkotsu", "genkotsu") : images.get("genkotsu");
|
||||
const impact = clamp(this.impactFlash || 0, 0, 1);
|
||||
|
|
@ -786,22 +889,11 @@ class Item {
|
|||
ctx.fillStyle = "rgba(255,255,255,0.54)";
|
||||
ctx.beginPath(); ctx.arc(-this.r * 0.32, -this.r * 0.18, 2.8, 0, Math.PI * 2); ctx.fill();
|
||||
} else if (this.type === "water") {
|
||||
ctx.save();
|
||||
ctx.lineCap = "round";
|
||||
ctx.strokeStyle = "rgba(198, 202, 204, 0.98)";
|
||||
ctx.lineWidth = Math.max(2.0, this.r * 0.16);
|
||||
const lean = -this.r * 0.34;
|
||||
ctx.globalAlpha = 0.86;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.r * 0.18, -this.r * 0.90);
|
||||
ctx.lineTo(this.r * 0.18 + lean, this.r * 0.42);
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 0.58;
|
||||
ctx.fillStyle = "rgba(216, 219, 220, 0.98)";
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(this.r * 0.18 + lean, this.r * 0.54, this.r * 0.24, this.r * 0.38, -0.18, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
drawOvalWaterDropSprite(ctx, this.r, {
|
||||
fill: "rgba(86, 157, 224, 0.82)",
|
||||
stroke: "rgba(45, 101, 168, 0.52)",
|
||||
highlight: "rgba(255,255,255,0.68)",
|
||||
});
|
||||
} else if (this.type === "grass") {
|
||||
const growth = this.growth ?? clamp(this.amount / 120, 0, 1);
|
||||
const stage = growth < 0.22 ? "sprout" : growth < 0.48 ? "young" : "mature";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue