From 54d0cf761a0b779e978e3676da9085eb5ff6da79 Mon Sep 17 00:00:00 2001 From: rizkyaz0 Date: Sun, 4 Oct 2026 07:32:46 +0700 Subject: [PATCH] Perhalus tampilan Bayangan: filter lebih gelap dan ungu (hasil hitung warna per nada), aura lebih tipis, lapisan warna ungu hanya sebagai cadangan bila peramban tanpa ctx.filter --- game.js | 13 +++++++------ story.css | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/game.js b/game.js index 5236a79..34e561e 100644 --- a/game.js +++ b/game.js @@ -212,10 +212,11 @@ function vsAbort(){vsToken++;vsHold=false;window.VS?.cancel?.();} // ---- Bayangan: bos rahasia Arcade (RENCANA 3.6) ---- // startMatch({..., shadow: true}) membuat lawan salinan karakter pemain (id sama; state hero dan dummy tetap terpisah, jurus dan CPU memakai data yang sama): - // HP +40%, damage ke pemain +10% (receiveHit dan dotDamage lewat foeDamage), sprite digelapkan dan diungukan (filter kanvas + lapisan warna, tanpa gambar baru) + // HP +40%, damage ke pemain +10% (receiveHit dan dotDamage lewat foeDamage), sprite digelapkan dan diungukan (filter kanvas, atau lapisan warna bila tanpa ctx.filter; tanpa gambar baru) // dengan aura serta percikan ungu. Bar HP dan penentu waktu habis memakai skala HP dasar (dummyHpShown) supaya +40% tidak menggeser tampilan atau hasil. // Percikan memakai fxr() (pengacak kosmetik), jadi tidak memengaruhi hasil pertandingan. - const SHADOW = { hp: 1.4, damage: 1.1, filter: 'grayscale(.8) brightness(.58) contrast(1.25)', tint: '#6a2fe0', tintAlpha: .42, aura: '139,92,246', wisp: '#a78bfa' }; + const SHADOW = { hp: 1.4, damage: 1.1, filter: 'grayscale(1) brightness(.46) sepia(1) hue-rotate(228deg) saturate(2.2)', tint: '#3b1d86', tintAlpha: .62, aura: '139,92,246', wisp: '#a78bfa' }; + const FILTER_OK = typeof ctx.filter === 'string'; // peramban tanpa ctx.filter (Safari lama) memakai lapisan warna ungu saja const DUMMY_MAX = BALANCE.dummyMax; let shadowFoe = false; function setShadowFoe(on) { shadowFoe = !!on; BALANCE.dummyMax = shadowFoe ? Math.round(DUMMY_MAX * SHADOW.hp) : DUMMY_MAX; hudIdentity = ''; } @@ -223,10 +224,10 @@ const dummyHpShown = () => currentDummyHP() * DUMMY_MAX / BALANCE.dummyMax; function drawShadowAura() { const x = dummy.x, y = dummy.y - 88, k = .5 + .5 * Math.sin(realTime * 3.4), g = ctx.createRadialGradient(x, y, 10, x, y, 150); - g.addColorStop(0, `rgba(${SHADOW.aura},${(.34 + .14 * k).toFixed(3)})`); g.addColorStop(1, `rgba(${SHADOW.aura},0)`); + g.addColorStop(0, `rgba(${SHADOW.aura},${(.2 + .08 * k).toFixed(3)})`); g.addColorStop(1, `rgba(${SHADOW.aura},0)`); ctx.save(); ctx.fillStyle = g; ctx.beginPath(); ctx.arc(x, y, 150, 0, 7); ctx.fill(); ctx.restore(); } - // Lapisan warna ungu hanya di piksel sprite (seperti kilat putih drawFlash); tetap membedakan Bayangan di peramban tanpa ctx.filter. + // Lapisan warna ungu hanya di piksel sprite (seperti kilat putih drawFlash); dipakai hanya bila peramban tidak punya ctx.filter. function drawShadowTint(img, r, dx, dy) { flashCv.width = r.w; flashCv.height = r.h; flashCx.drawImage(img, r.x, r.y, r.w, r.h, 0, 0, r.w, r.h); flashCx.globalCompositeOperation = 'source-atop'; flashCx.fillStyle = SHADOW.tint; flashCx.fillRect(0, 0, r.w, r.h); flashCx.globalCompositeOperation = 'source-over'; @@ -2504,9 +2505,9 @@ if(!m||!img)return; const r=m.frame_layout.rows[pose.state][pose.frame]; ctx.save();ctx.translate(Math.round(dummy.x),Math.round(dummy.y));{const om=CF[opponentCharacter]?(cfFormOn(opponentCharacter,'enemy')?CF[opponentCharacter].mode?.form?.metrics:CF[opponentCharacter].metrics):null,k=stateK(om,pose.state);ctx.scale((dummy.facing||-1)*k,k);}ctx.imageSmoothingEnabled=false; - if(shadowFoe)ctx.filter=SHADOW.filter; + if(shadowFoe&&FILTER_OK)ctx.filter=SHADOW.filter; ctx.drawImage(img,r.x,r.y,r.w,r.h,-m.cell.width/2,-(m.cell.height-m.cell.safe_margin_y),r.w,r.h); - if(shadowFoe){ctx.filter='none';drawShadowTint(img,r,-m.cell.width/2,-(m.cell.height-m.cell.safe_margin_y));} + if(shadowFoe){if(FILTER_OK)ctx.filter='none';else drawShadowTint(img,r,-m.cell.width/2,-(m.cell.height-m.cell.safe_margin_y));} if(dummy.flash>0)drawFlash(dummy,img,r,-m.cell.width/2,-(m.cell.height-m.cell.safe_margin_y));ctx.restore(); if(dummy.action && !dummy.action.fired && dummy.action.type!=='ultimate') { ctx.save();ctx.strokeStyle='#f0b15e';ctx.lineWidth=2;ctx.globalAlpha=.7; diff --git a/story.css b/story.css index 24f63d0..42e756d 100644 --- a/story.css +++ b/story.css @@ -14,7 +14,7 @@ .st-fig.l{left:3vw;animation:st-in-l .6s .08s cubic-bezier(.2,.9,.25,1) both} .st-fig.r{right:3vw;animation:st-in-r .6s .18s cubic-bezier(.2,.9,.25,1) both} .st-fig.r img{transform:scaleX(-1)} -.st-fig.shadow img{filter:grayscale(1) brightness(.62) sepia(1) hue-rotate(228deg) saturate(2.8) drop-shadow(0 0 22px #7c4dffcc)} +.st-fig.shadow img{filter:grayscale(1) brightness(.5) sepia(1) hue-rotate(228deg) saturate(2.2) drop-shadow(0 0 22px #7c4dffcc)} /* Kartu teks: berada di antara potret dan tepi kanan; tinggi dibatasi layar, isi di tengah (margin auto agar tidak terpotong bila meluap). */ .st-card{position:absolute;z-index:3;left:calc(3vw + var(--aw) + 2.5vw);right:4vw;top:clamp(34px,8vh,72px);bottom:clamp(26px,6vh,56px);display:flex;flex-direction:column;overflow:hidden auto;scrollbar-width:none} .st-card::-webkit-scrollbar{display:none} @@ -94,10 +94,10 @@ body:has(#story-screen) #meta-toasts{visibility:hidden} #vs-screen.vs-shadow{--pr:#5b34c2} #vs-screen.vs-shadow .vs-bg:after{background:radial-gradient(ellipse at 50% 50%,#0c0524b8 25%,#07031af2 100%)} #vs-screen.vs-shadow .vs-slash{background:linear-gradient(180deg,#f1eaff,#8b5cf6);box-shadow:0 0 20px #b49cff} -#vs-screen.vs-shadow .vs-side.r .vs-art{filter:grayscale(1) brightness(.62) sepia(1) hue-rotate(228deg) saturate(2.8) drop-shadow(0 14px 18px #000b) drop-shadow(0 0 20px #7c4dffaa)} +#vs-screen.vs-shadow .vs-side.r .vs-art{filter:grayscale(1) brightness(.5) sepia(1) hue-rotate(228deg) saturate(2.2) drop-shadow(0 14px 18px #000b) drop-shadow(0 0 20px #7c4dffaa)} .fighter.fighter-two.shadow-foe .life-fill{background:linear-gradient(180deg,#e9deff 0,#bba3ff 25%,#8059e6 28%,#6a46d4)} .fighter.fighter-two.shadow-foe .life-fill.reserve-fill{background:linear-gradient(180deg,#cdb8ff,#8a64ee 35%,#4d2fae)} .fighter.fighter-two.shadow-foe #enemy-name{color:#dccfff;text-shadow:2px 2px 0 #1a0f3a,0 0 14px #8b5cf699} -#enemy-portrait.shadow-foe{filter:grayscale(1) brightness(.72) sepia(1) hue-rotate(228deg) saturate(2.6)} -.rs-fighter.lose.shadow .rs-art{filter:grayscale(1) brightness(.55) sepia(1) hue-rotate(228deg) saturate(2.6) drop-shadow(0 10px 12px #0008);opacity:.9} +#enemy-portrait.shadow-foe{filter:grayscale(1) brightness(.6) sepia(1) hue-rotate(228deg) saturate(2.2)} +.rs-fighter.lose.shadow .rs-art{filter:grayscale(1) brightness(.5) sepia(1) hue-rotate(228deg) saturate(2.2) drop-shadow(0 10px 12px #0008);opacity:.9} .rs-fighter.lose.shadow .rs-plate small{color:#b79cff}