Steady the gold ring, and move the praise word off the ball
Oliver: the target ring twitches sometimes, and "shot of the day", "textbook" etc. cover the ball. The timed ring re-solved every frame and a small shift in the auto-run's target moved its moment by up to 158 ms in a frame; the drawn cue now counts down on its own clock and eases toward each solve (p99 jump 100 -> 17 ms). The rally's praise word rose straight into the struck ball's path (and a serve's sat on the far bounce, where the return comes back); it now lands under the player, behind his feet, and stays put. Same moment, out of the way. v371. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8e4b298d92
commit
d561050af8
7 files changed
+50
-8
No files matched your search
+25
-2
@@ -87,6 +87,16 @@ let praiseN = 0;
|
||||
// the word must land at the IMPACT, not at the release (Oliver: "the reactions are playing after
|
||||
// shooting the ball, not when the ball hits"). A serve arms it on ball.praise and the contact/
|
||||
// bounce pops it; a rally hit pops it at the racket, where contact and praise are the same moment.
|
||||
// ...and in a rally it lands BELOW THE PLAYER, just behind his feet, and stays put (Oliver, 2026-10-14:
|
||||
// "die Nachrichten wie shot of the day, textbook verdecken manchmal den Ball"). On the contact it rose
|
||||
// straight into the path of the ball he had just struck; a serve's word sat on the far bounce, which
|
||||
// is exactly where the return comes back through. The MOMENT is unchanged — only where it is drawn.
|
||||
// Gore keeps its words on the bodies they belong to.
|
||||
function praisePop(w, x, y, z) {
|
||||
if (rallyFeel() || G.mode === 'tennis') popText(P.x, 0, P.z + TUNE.praiseBehind, w, undefined, true);
|
||||
else popText(x, y, z, w);
|
||||
}
|
||||
|
||||
function praiseWord() {
|
||||
if (G.praiseT > 0) return null;
|
||||
G.praiseT = TUNE.praiseEvery;
|
||||
@@ -410,7 +420,7 @@ function doHit(ch, quality, aim) {
|
||||
if (quality > 0.999 && ch.side === 'P') { // the rally hit: a real 45 ms window (perfectMs)
|
||||
G.hitstop = 0.05; pock(0.5, 1600);
|
||||
const w = praiseWord(); // a rally hit IS the impact — the word pops right on the contact
|
||||
if (w) popText(ball.x, ball.y, ball.z, w);
|
||||
if (w) praisePop(w, ball.x, ball.y, ball.z);
|
||||
}
|
||||
ch.pose = 'swing'; ch.poseT = 0;
|
||||
if (G.net && ch.side === 'P') netSendShot(); // netplay: the shot IS the sync unit
|
||||
@@ -1320,7 +1330,7 @@ function onBounce() {
|
||||
pock(0.35, 500);
|
||||
if (ball.scored) return; // a called ball still bounces and still sounds; it just cannot score twice
|
||||
// a deferred praise word that met no body lands with the ball — the DRAW was still perfect
|
||||
if (ball.praise) { popText(ball.x, 0.3, ball.z, ball.praise); ball.praise = null; }
|
||||
if (ball.praise) { praisePop(ball.praise, ball.x, 0.3, ball.z); ball.praise = null; }
|
||||
if (G.mode === 'splatter' && ball.bomb && ball.bounces === 1) { // a bomb that missed everyone still blows up
|
||||
explode(ball.x, ball.z); ball.bomb = false;
|
||||
spentBall(); return;
|
||||
@@ -2306,6 +2316,19 @@ export function update(dt) {
|
||||
// mid-stride left him welded to a single run frame — the "stuck mid-animation" report.
|
||||
// vx/vz die with the mover too, or the speed ghosts would trail a body that stopped dead.
|
||||
else { P.vx = 0; P.vz = 0; if (P.pose === 'run' && G.dodgeT <= 0) { P.pose = 'idle'; P.poseT = 0; } }
|
||||
// THE GOLD RING, STEADY (Oliver, 2026-10-14: "der Treffer-/Zielkreis zittert jetzt manchmal").
|
||||
// ringCue re-solves every frame against where the auto-run is taking him, and a target that shifts
|
||||
// a few centimetres moved the predicted moment by a frame or two — the ring's size twitched and its
|
||||
// gold blinked. The drawn cue COUNTS DOWN on its own clock and only eases toward each fresh solve
|
||||
// (TUNE.ringSmooth), and a frame with no solve holds it instead of dropping it.
|
||||
if (G.phase === 'rally' && ball.active && ball.lastHit === 'O' && (rallyFeel() || G.mode === 'tennis')) {
|
||||
const c = ringCue();
|
||||
if (c && !G.ring) G.ring = { ...c };
|
||||
else if (c) { const e = G.ring.eta - dt; G.ring = { ...c, eta: e + (c.eta - e) * Math.min(1, dt * TUNE.ringSmooth) }; }
|
||||
else if (G.ring && (G.ring.hold = (G.ring.hold || 0) + dt) < 0.12) G.ring.eta -= dt;
|
||||
else G.ring = null;
|
||||
if (G.ring) G.ring.gold = Math.abs(G.ring.eta - G.ring.sweet) < G.ring.band;
|
||||
} else G.ring = null;
|
||||
// The sidestep runs in EVERY phase — that is the entire point of it, since a boss fight is spent
|
||||
// in 'pretoss' where the block above never runs. Same clamp as the walk, so it cannot carry him
|
||||
// off the edge of the screen either.
|
||||
|
||||
Reference in new issue
Block a user