Strengthen final-league placement and returns
This commit is contained in:
1 parent
bfc70d7388
commit
e3faeb0a3a
5 files changed
+101
-8
No files matched your search
+5
-3
@@ -1250,17 +1250,19 @@ const OPPONENTS = [
|
||||
line: 'HE GAVE LESSONS ON THIS COURT.', speed: 1.16, pace: 1.22, wide: 1.20, flub: 0.70 },
|
||||
// THE BRUTE, not "THE BULK": the gore mode's stats screen has called this body THE BRUTE since it
|
||||
// was the pole-dragger (ENEMIES.g below), and one character may not carry two names.
|
||||
// Final-league returns hunt the open court (smart) and have individual quality caps. Earlier
|
||||
// opponents keep random lanes and racketQMax. Brute's legs must clear even league 4's fastest.
|
||||
{ short: 'BRUTE', name: 'THE BRUTE', fam: 'br', h: 2.0,
|
||||
line: 'NOTHING GETS PAST HIM TWICE.', speed: 1.02, pace: 1.34, wide: 1.24, flub: 0.66 },
|
||||
line: 'NOTHING GETS PAST HIM TWICE.', speed: 1.12, pace: 1.34, wide: 1.24, flub: 0.66, smart: 0.20, qMax: 0.60 },
|
||||
{ short: 'DIRECTOR', name: 'THE DIRECTOR', fam: 'dr',
|
||||
line: 'HE CAN HAVE YOU REMOVED.', speed: 1.26, pace: 1.28, wide: 1.28, flub: 0.60 },
|
||||
line: 'HE CAN HAVE YOU REMOVED.', speed: 1.26, pace: 1.28, wide: 1.28, flub: 0.60, smart: 0.40, qMax: 0.65 },
|
||||
// 18: the man whose name is on the honours board. `h` is WORLD height (zombieH reads it, so the
|
||||
// serve aims at the body actually drawn): four family rolls could not make the art itself bulky
|
||||
// against the pose sheet — see _famroll.py's pair-reference note — so his size is stature.
|
||||
// Six new rungs stand between him and the start now, so he took the step up Oliver asked for:
|
||||
// he reads the court faster, hits harder, paints wider, and misses half as often as he did.
|
||||
{ short: 'CHAMPION', name: 'THE CHAMPION', fam: 'ch', h: 2.1,
|
||||
line: 'HE RETURNS EVERYTHING.', speed: 1.45, pace: 1.42, wide: 1.36, flub: 0.38 },
|
||||
line: 'HE RETURNS EVERYTHING.', speed: 1.45, pace: 1.42, wide: 1.36, flub: 0.38, smart: 0.60, qMax: 0.70 },
|
||||
];
|
||||
|
||||
// Who opponent N is. This used to reuse the chapter roster's cycling (bossArt) so the two lists
|
||||
|
||||
+10
-4
@@ -1444,11 +1444,13 @@ function trySwing(ch, isAI, qCap = TUNE.aiQualityMax) {
|
||||
// finger is usually still down at contact, and the vector under it NOW is the aim the player
|
||||
// means — the released flickAim only carries it when the ball arrives after the finger lifted.
|
||||
const flick = isAI ? null : (G.swipe || takeFlickAim());
|
||||
// SMART AIM (G.diff.smart, classic difficulty): with this probability the CPU plays the OPEN
|
||||
// SMART AIM (classic difficulty or the solo match foe): with this probability the CPU plays the OPEN
|
||||
// COURT — the corner away from where you stand — instead of rolling a random lane. Random aim
|
||||
// sends a third of everything straight back to your racket; hunting the open corner is what
|
||||
// makes a hard CPU feel like it is PLAYING you. ax is an absolute court lane (see doHit).
|
||||
const smart = isAI && G.diff && Math.random() < (G.diff.smart || 0);
|
||||
const smartChance = G.diff ? (G.diff.smart || 0) : G.match && !G.net ? (ch.foe?.smart || 0) : 0;
|
||||
// Keep the old random sequence for classic and for foes without smart aim.
|
||||
const smart = isAI && (G.diff || smartChance) && Math.random() < smartChance;
|
||||
const aim = isAI
|
||||
? { ax: smart ? (P.x > 0.6 ? -1 : P.x < -0.6 ? 1 : (Math.random() < 0.5 ? -1 : 1))
|
||||
: [ -1, 0, 1 ][Math.floor(Math.random() * 3)],
|
||||
@@ -1545,8 +1547,12 @@ function racketAI(rz, dt) {
|
||||
// body had actually learned. The champion's near-zero flub is exactly what this opens.
|
||||
+ (G.match && G.match.surprised ? TUNE.surpFlub * learnK(rz) : 0);
|
||||
if (Math.random() < flub) rz.swingCool = 0.5; // whiff — it hesitates (rarer per rung of the ladder)
|
||||
else { rz.swingT = TUNE.swingWindup + TUNE.swingWindow / 2;
|
||||
trySwing(rz, true, TUNE.racketQMax + TUNE.duelQBonus * duelSkill()); rz.swingT = -1; rz.swingCool = 0.3; }
|
||||
else {
|
||||
const qCap = G.match && !G.net ? (rz.foe?.qMax ?? TUNE.racketQMax)
|
||||
: TUNE.racketQMax + TUNE.duelQBonus * duelSkill();
|
||||
rz.swingT = TUNE.swingWindup + TUNE.swingWindow / 2;
|
||||
trySwing(rz, true, qCap); rz.swingT = -1; rz.swingCool = 0.3;
|
||||
}
|
||||
// the lean is SPENT at the racket, either way — matchReady clears it when a point ends unmet
|
||||
if (G.match) G.match.surprised = G.match.expected = false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user