Perbaiki tick DoT yang menaikkan hitungan kombo (hanya ledakan terjadwal yang dihitung)

This commit is contained in:
rizkyaz0 2026-10-03 06:51:04 +07:00
parent 7293c1e4b8
commit 13b47140f9
1 changed files with 15 additions and 12 deletions

27
game.js
View File

@ -977,7 +977,7 @@
cfx.hazards.push({ x: p.x, owner: p.owner, t: 0, life: L.life, radius: L.radius, dps: L.dps, img: 'fx-' + id + '-' + L.asset, acc: 0, shown: 0 });
effects.push({ type: 'cf-fx', asset: id + '-impact', x: p.x, y: CONFIG.groundY - 24, facing: 1, life: .4, maxLife: .4, size: 220 });
spawnParticles(p.x, CONFIG.groundY - 12, p.color, 14, 260, 'dust'); trauma = Math.min(1, trauma + .2); sound('heavy');
if (bwAlive(target) && Math.abs(target.x - p.x) < L.radius && target.y > CONFIG.groundY - 120) dotDamage(target, L.burst, p.color);
if (bwAlive(target) && Math.abs(target.x - p.x) < L.radius && target.y > CONFIG.groundY - 120) dotDamage(target, L.burst, p.color, true, true);
}
function updateCf(dt) {
fxTick(dt);
@ -988,7 +988,7 @@
if (e.homing && bwAlive(target)) { const want = Math.atan2(target.y - 90 - e.y, target.x - e.x), cur = Math.atan2(e.vy, e.vx); let d = want - cur; d = Math.atan2(Math.sin(d), Math.cos(d)); const ang = cur + clamp(d, -6 * dt, 6 * dt), sp = Math.hypot(e.vx, e.vy); e.vx = Math.cos(ang) * sp; e.vy = Math.sin(ang) * sp; }
e.x += e.vx * dt; e.y += e.vy * dt;
if (!e.hit && bwAlive(target) && Math.abs(e.x - target.x) < (e.rx || 70) && Math.abs(e.y - (target.y - 85)) < (e.ry || 120)) {
dotDamage(target, e.damage, e.color); sound('hit'); spawnParticles(target.x, target.y - 85, e.color, 8, 220); trauma = Math.min(1, trauma + .15);
dotDamage(target, e.damage, e.color, true, true); sound('hit'); spawnParticles(target.x, target.y - 85, e.color, 8, 220); trauma = Math.min(1, trauma + .15);
if (e.single) { cfx.ents.splice(n, 1); continue; } e.hit = true;
}
if (e.life <= 0 || e.x < -260 || e.x > W + 260) cfx.ents.splice(n, 1);
@ -999,7 +999,7 @@
if (m.t >= m.delay) {
effects.push({ type: 'cf-fx', asset: m.asset, x: m.x, y: CONFIG.groundY - 26, facing: 1, life: .4, maxLife: .4, size: 200 });
spawnParticles(m.x, CONFIG.groundY - 10, m.color, 8, 200, 'dust'); sound('hit'); trauma = Math.min(1, trauma + .12);
if (bwAlive(target) && Math.abs(target.x - m.x) < m.radius && target.y > CONFIG.groundY - 140) dotDamage(target, m.damage, m.color);
if (bwAlive(target) && Math.abs(target.x - m.x) < m.radius && target.y > CONFIG.groundY - 140) dotDamage(target, m.damage, m.color, true, true);
cfx.marks.splice(n, 1);
}
}
@ -1044,7 +1044,7 @@
effects.push({ type: 'cf-pillar', img: 'fx-' + id + '-' + U.asset, x, y: CONFIG.groundY, life: .6, maxLife: .6, h: U.h || 320 });
effects.push({ type: 'cf-fx', asset: id + '-impact', x, y: CONFIG.groundY - 24, facing: 1, life: .4, maxLife: .4, size: 220 });
spawnParticles(x, CONFIG.groundY - 10, col, 10, 240, 'dust'); trauma = Math.min(1, trauma + .18); sound('hit');
if (bwAlive(target)) dotDamage(target, U.damage ?? 3, col);
if (bwAlive(target)) dotDamage(target, U.damage ?? 3, col, true, true);
}
}
if (!s.finished && s.t >= endAct && U.finisher) {
@ -1053,7 +1053,7 @@
effects.push({ type: 'cf-fx', asset: id + '-' + (F2.asset || 'burst'), x: target.x, y: CONFIG.groundY - 130, facing: 1, life: .55, maxLife: .55, size: 560 });
for (let q = 0; q < 3; q++) spawnParticles(target.x, CONFIG.groundY - 12, q === 1 ? '#fff1c8' : col, 22, 460, 'dust');
trauma = 1; hitstop = Math.max(hitstop, .14); sound('heavy');
if (bwAlive(target)) { if (target === dummy) { if (!hitDummy(F2.damage, 360, col, a.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, F2.damage, col); } else if (!window.__game.receiveHit(F2.damage, { shake: 2 })) dotDamage(hero, F2.damage, col); }
if (bwAlive(target)) { if (target === dummy) { if (!hitDummy(F2.damage, 360, col, a.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, F2.damage, col, true, true); } else if (!window.__game.receiveHit(F2.damage, { shake: 2 })) dotDamage(hero, F2.damage, col); }
}
s.phase = s.t < .78 ? 'cutin' : 'roaring';
if (s.t >= endAct + (U.tail ?? .5)) {
@ -1458,10 +1458,13 @@
}
function bwAlive(target) { return target === dummy ? !dummy.ko && dummy.state !== 'down' && dummy.state !== 'recover' : hero.hp > 0; }
// Damage over time / scripted damage: no hurt animation, no knockback, no cooldown refunds; K.O. still applies.
function dotDamage(target, amount, color = '#9bd05a', numbers = true) {
// Only discrete scripted bursts (combo = true) count as combo hits; per-tick DoT must not feed the combo rank, the damage reducer or coins.
function dotDamage(target, amount, color = '#9bd05a', numbers = true, combo = false) {
if (amount <= 0 || menuOpen || (match && match.phase !== 'fight') || !bwAlive(target)) return false;
if (target === dummy) {
dummy.damage += amount; totalDamage += amount; comboHits++; bestCombo = Math.max(bestCombo, comboHits); comboDamage += amount; comboTimer = 2.3;
dummy.damage += amount; totalDamage += amount;
if (combo) { comboHits++; bestCombo = Math.max(bestCombo, comboHits); comboTimer = 2.3; }
if (combo || comboTimer > 0) comboDamage += amount;
if (numbers) damageNumbers.push({ x: dummy.x + (random() - .5) * 30, y: dummy.y - 120, amount, kind: Feel.classify(amount), life: .9, maxLife: .9, color });
if (amount >= Feel.table.medium) dummy.flash = dummy.flashMax = Feel.table.hit.medium.flash;
if (dummy.damage >= BALANCE.dummyMax) { dummy.ko = true; dummy.state = 'down'; dummy.vy = -330; dummy.vx = 0; dummy.fallDirection = hero.x <= dummy.x ? 1 : -1; announce('K.O.', .9); }
@ -1488,7 +1491,7 @@
effects.push({ type: 'browo-fx', asset: 'browo-sunburst', x: caster.x, y: caster.y - 95, facing: 1, life: .5, maxLife: .5, size: 320 });
spawnParticles(caster.x, caster.y - 95, '#8fd14f', 12, 260); trauma = Math.min(1, trauma + .12); sound('heavy');
if (Math.abs(target.x - caster.x) < D.radius && Math.abs(target.y - caster.y) < 130 && bwAlive(target)) {
dotDamage(target, D.pulseDamage, '#cfe9a0'); bwLock(tk, D.gap + D.stunExtra); bwPoison(tk);
dotDamage(target, D.pulseDamage, '#cfe9a0', true, true); bwLock(tk, D.gap + D.stunExtra); bwPoison(tk);
spawnParticles(target.x, target.y - 85, '#7be04a', 10, 200);
}
}
@ -1521,7 +1524,7 @@
const f = bwx.fires[n], target = f.owner === 'enemy' ? hero : dummy, tk = f.owner === 'enemy' ? 'player' : 'enemy';
f.t += dt; if (f.t < 0) continue;
const near = Math.abs(target.x - f.x) < F2.radius && target.y > CONFIG.groundY - 120 && bwAlive(target);
if (!f.lit) { f.lit = true; effects.push({ type: 'browo-fx', asset: 'browo-impact', x: f.x, y: CONFIG.groundY - 30, facing: 1, life: .4, maxLife: .4, size: 200 }); spawnParticles(f.x, CONFIG.groundY - 40, '#ff8a3a', 10, 220); sound('hit'); if (near) dotDamage(target, F2.ignite, '#ff9a4a'); }
if (!f.lit) { f.lit = true; effects.push({ type: 'browo-fx', asset: 'browo-impact', x: f.x, y: CONFIG.groundY - 30, facing: 1, life: .4, maxLife: .4, size: 200 }); spawnParticles(f.x, CONFIG.groundY - 40, '#ff8a3a', 10, 220); sound('hit'); if (near) dotDamage(target, F2.ignite, '#ff9a4a', true, true); }
if (near) inside[tk] = true;
if (f.t > F2.life) bwx.fires.splice(n, 1);
}
@ -1556,7 +1559,7 @@
effects.push({ type: 'browo-tree', x, y: CONFIG.groundY, life: .6, maxLife: .6 });
effects.push({ type: 'browo-fx', asset: 'browo-impact', x, y: CONFIG.groundY - 24, facing: 1, life: .4, maxLife: .4, size: 220 });
spawnParticles(x, CONFIG.groundY - 10, '#a47a3a', 10, 240, 'dust'); trauma = Math.min(1, trauma + .18); sound('hit');
if (bwAlive(target)) dotDamage(target, U.treeDamage, '#9bd05a');
if (bwAlive(target)) dotDamage(target, U.treeDamage, '#9bd05a', true, true);
}
// The giant palm: rises, leans back, then comes down on the rival.
if (!s.giant && s.t >= U.giantAt) {
@ -1573,7 +1576,7 @@
effects.push({ type: 'browo-fx', asset: 'browo-sunburst', x: tx, y: CONFIG.groundY - 120, facing: 1, life: .5, maxLife: .5, size: 520 });
for (let q = 0; q < 3; q++) spawnParticles(tx, CONFIG.groundY - 12, q === 1 ? '#fff1c8' : '#a47a3a', 22, 460, 'dust');
trauma = 1; hitstop = Math.max(hitstop, .14); sound('heavy');
if (bwAlive(target)) { if (target === dummy) { if (!hitDummy(U.giantDamage, 360, '#ffe08a', a.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, U.giantDamage, '#ffe08a'); } else if (!window.__game.receiveHit(U.giantDamage, { shake: 2 })) dotDamage(hero, U.giantDamage, '#ffe08a'); }
if (bwAlive(target)) { if (target === dummy) { if (!hitDummy(U.giantDamage, 360, '#ffe08a', a.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, U.giantDamage, '#ffe08a', true, true); } else if (!window.__game.receiveHit(U.giantDamage, { shake: 2 })) dotDamage(hero, U.giantDamage, '#ffe08a'); }
}
}
s.phase = s.t < U.cutinDuration ? 'cutin' : s.t < U.treesAt ? 'roaring' : 'fading';
@ -1614,7 +1617,7 @@
effects.push({ type: 'browo-fx', asset: 'browo-sunburst', x: tw.x, y: CONFIG.groundY - 150, facing: 1, life: .55, maxLife: .55, size: 620 });
for (let q = 0; q < 3; q++) spawnParticles(tw.x, CONFIG.groundY - 60, q === 1 ? '#fff1c8' : '#ff7a30', 24, 520);
trauma = 1; hitstop = Math.max(hitstop, .14); sound('heavy');
if (bwAlive(target) && Math.abs(target.x - tw.x) < U.radius * 1.4) { if (target === dummy) { if (!hitDummy(U.blast, 400, '#ffb060', tw.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, U.blast, '#ffb060'); } else if (!window.__game.receiveHit(U.blast, { shake: 2 })) dotDamage(hero, U.blast, '#ffb060'); }
if (bwAlive(target) && Math.abs(target.x - tw.x) < U.radius * 1.4) { if (target === dummy) { if (!hitDummy(U.blast, 400, '#ffb060', tw.x, CONFIG.groundY - 100, true, true, 2)) dotDamage(dummy, U.blast, '#ffb060', true, true); } else if (!window.__game.receiveHit(U.blast, { shake: 2 })) dotDamage(hero, U.blast, '#ffb060'); }
}
}
s.phase = s.t < U.cutinDuration ? 'cutin' : 'roaring';