Playtest #5 follow-up: boss-field blowers show in the normal rounds; 联防 timer restart confirmed
- act2 m01: the boss field's row-6 blower machines stand under the bench in the normal and 联防 views again
(the user: "吹风机原版道中也该有"); the integration-QA filter (BOSS_WALL_ROW) is removed from the 3D and 2D
boards, so every device on a built tile is drawn in every view, as the workstream had it
- 联防: a knocked-out operator's redeploy timer restarting in full is confirmed by the user ("进联防复活时间确实是
重新算"); the [ASSUMED] tags in DESIGN §5.5 / §6.1 / §19.3, META §4 and unite.js say so
- DESIGN §19 intro / §19.7 and the docs-consistency assertions updated; 2595 unit tests, all render browser suites green
This commit is contained in:
1 parent
15291c2293
commit
e6628f0cfe
7 files changed
+53
-60
No files matched your search
@@ -5,9 +5,9 @@
|
||||
// const board = buildBoard(stage, { uv: resolveUvTable(tiles), crate?: objMesh, area?: AREAS.normal })
|
||||
// → { grid, buckets: { board, decal, pipe }, gates: [{ r, c, kind: 'start'|'end' }], devices: [...],
|
||||
// terrain: { water, mire, smog, infection: [[r,c]…] }, edges: [...cyan field edge strips], bounds, stats }
|
||||
// `devices` = the active stage devices standing on a built tile — the separator row 13 included (act2 m01's blowers at
|
||||
// the top edge of the normal / 联防 field); the boss field's (rows ≤ 6: its row-6 blowers) only when the boss field is
|
||||
// built — user playtest #5 item 6 (stageDevices).
|
||||
// `devices` = the active stage devices standing on a built tile — separator walls included (act2 m01's blowers: the
|
||||
// row-13 ones at the top edge of the normal / 联防 field, the row-6 ones at its bottom edge and at the top edge of the
|
||||
// Final Assault field — user playtest #5 item 6 and its follow-up).
|
||||
//
|
||||
// World space = render/projection.js: x = col, y = row, z = height (up); tile (r,c) covers [c±½]×[r±½].
|
||||
// Heights follow render/style.js TILE_H (the Pixi layers stand units on the same tops: tiles.js heightAt).
|
||||
@@ -52,8 +52,7 @@ const CONTENT_OF = (g) => g !== '#' && g !== 'X';
|
||||
* boss field): the devices standing on it act on the field — act2 m01's 源石流发生装置 #001/#002 (#101/#102) at (13, 5 /
|
||||
* 9 / 13 / 17) blow DOWN into rows 12–10 — and the official normal rounds show those machines at the field's top edge
|
||||
* (user playtest #5 item 6: the wind lanes worked but the blowers were missing; the 2D board always drew row 13). The
|
||||
* row-6 wall under the bench is built in these views too (in leftNormal), without the boss field's devices on it
|
||||
* (stageDevices).
|
||||
* row-6 wall under the bench is built in these views too (in leftNormal), with the boss field's blowers standing on it.
|
||||
*/
|
||||
export const AREAS = Object.freeze({
|
||||
normal: Object.freeze([Object.freeze({ r0: 6, r1: 13, c0: 0, c1: 10 }), Object.freeze({ r0: 13, r1: 18, c0: 6, c1: 14 })]),
|
||||
@@ -440,7 +439,7 @@ export function buildBoard(stage, opts = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
const devices = opts.devices === false ? [] : stageDevices(stage, grid, opts.area || null);
|
||||
const devices = opts.devices === false ? [] : stageDevices(stage, grid);
|
||||
for (const d of devices) {
|
||||
if (d.kind === 'platform' || d.kind === 'sealedFloor' || d.kind === 'waterPlatform') slabDevice(board, decal, UVT, d, grid);
|
||||
}
|
||||
@@ -487,23 +486,16 @@ export function tube(g, a, b, rad, seg = 8, col = [1, 1, 1]) {
|
||||
|
||||
const DEVICE_KINDS = new Set(['crate', 'platform', 'mound', 'blower', 'turret', 'waterPlatform', 'bush', 'sealedFloor']);
|
||||
|
||||
/** The boss field's top wall — the row under the normal field's bench (rows ≤ this one are the boss field's). */
|
||||
export const BOSS_WALL_ROW = 6;
|
||||
|
||||
/**
|
||||
* Active stage devices standing on drawn tiles: `{ kind, r, c, dir, z0, key, alias, rangeTiles }` — every visible
|
||||
* predefined token of the level is a scene object, a device on the separator row 13 included (act2 m01's 源石流发生装置
|
||||
* #001 / #002 blow DOWN into the normal field: the official normal rounds show them at its top edge although row 13
|
||||
* lies outside every configBlackBoard area rect, user playtest #5 item 6). The boss field's devices (rows ≤ 6, its top
|
||||
* wall under the bench included: act2 m01's #201 / #202 blow DOWN into rows 5–3) are drawn only when `area` builds the
|
||||
* boss field (a rect below row 6): the official normal cameras never show that wall — it lies under the shop bar in
|
||||
* prep and off-screen in battle and in the shop-collapsed prep view — while the remake's prep view showed the boss
|
||||
* round's machines under the bench ("反而在关底吹风机的贴图又出现了"). `area` null = the whole map. The 2D board
|
||||
* (render/tiles.js _stageDevices) follows the same rule.
|
||||
* Active stage devices standing on drawn tiles: `{ kind, r, c, dir, z0, key, alias, rangeTiles }`. Every visible
|
||||
* predefined token of the level is a scene object; a device on a separator wall is drawn wherever that wall is built,
|
||||
* whichever field it blows into (act2 m01: row 6 belongs to both leftNormal and leftBoss, row 13 tops the normal field).
|
||||
* The official client hides none of them by the way they face: the row-13 machines show in the official normal rounds
|
||||
* although row 13 lies outside every configBlackBoard area rect (user playtest #5 item 6), and so do the boss field's
|
||||
* row-6 machines under the bench (user playtest #5 follow-up: "吹风机原版道中也该有").
|
||||
*/
|
||||
export function stageDevices(stage, grid, area = null) {
|
||||
export function stageDevices(stage, grid) {
|
||||
const list = Array.isArray(stage?.devices) ? stage.devices : [];
|
||||
const bossShown = !area || area.some((a) => a.r0 < BOSS_WALL_ROW);
|
||||
const out = [];
|
||||
for (const d of list) {
|
||||
if (!d || !Array.isArray(d.pos) || !Number.isInteger(d.pos[0]) || !Number.isInteger(d.pos[1])) continue;
|
||||
@@ -511,7 +503,6 @@ export function stageDevices(stage, grid, area = null) {
|
||||
const active = typeof d.active === 'boolean' ? d.active : !d.hidden;
|
||||
if (!active) continue;
|
||||
const [r, c] = d.pos;
|
||||
if (r <= BOSS_WALL_ROW && !bossShown) continue;
|
||||
const t = grid?.[r]?.[c];
|
||||
if (!t || !t.drawn) continue;
|
||||
out.push({ kind: d.role, r, c, dir: ['UP', 'DOWN', 'LEFT', 'RIGHT'].includes(d.dir) ? d.dir : 'UP', z0: t.h, key: d.key || null, alias: d.alias || null, rangeTiles: Array.isArray(d.rangeTiles) ? d.rangeTiles : null });
|
||||
|
||||
@@ -45,8 +45,6 @@ export const ROW_KEY = Object.freeze({ blocks: 0, devices: 0.01, surface: 0.02 }
|
||||
export const boxDepthKey = (cam, row) => -cam.depthOf(0, row + 0.45, 0) * 100;
|
||||
|
||||
const ROWS = 19, COLS = 21;
|
||||
/** The boss field's top wall under the normal field's bench (= board3d/layout.js BOSS_WALL_ROW). */
|
||||
const BOSS_WALL_ROW = 6;
|
||||
const PLAYABLE_DIST = 2; // margin tiles farther than this from a playable tile are not drawn
|
||||
const CLIFF_DEPTH = 0.62; // how far the island's edge faces go down to the ground plane (tiles)
|
||||
/** Brightness of the board meshes (vertex colour above 1 lifts the mid-grey board art a little). */
|
||||
@@ -364,9 +362,6 @@ export class TileField {
|
||||
|
||||
_stageDevices() {
|
||||
const list = Array.isArray(this.stage?.devices) ? this.stage.devices : [];
|
||||
// the boss field's devices (rows ≤ 6, its top wall under the bench included) only in the views of the boss field
|
||||
// (board3d/layout.js stageDevices: the official normal cameras never show that wall; user playtest #5 item 6)
|
||||
const bossShown = this.field[0] < BOSS_WALL_ROW;
|
||||
const out = [];
|
||||
for (const d of list) {
|
||||
if (!d || !Array.isArray(d.pos) || !Number.isInteger(d.pos[0]) || !Number.isInteger(d.pos[1])) continue;
|
||||
@@ -374,10 +369,12 @@ export class TileField {
|
||||
const active = typeof d.active === 'boolean' ? d.active : !d.hidden;
|
||||
if (!active) continue;
|
||||
if (d.pos[0] < 0 || d.pos[0] >= ROWS || d.pos[1] < 0 || d.pos[1] >= COLS || d.pos[0] >= 14) continue;
|
||||
if (d.pos[0] <= BOSS_WALL_ROW && !bossShown) continue;
|
||||
const gt = this.grid[d.pos[0]] && this.grid[d.pos[0]][d.pos[1]];
|
||||
// devices stand on the island (playable tiles + the ring around them, dist ≤ 1 — the 3D board's drawn tiles), not
|
||||
// on the faded margin; the separator row 13 above the field included (act2 m01's blowers)
|
||||
// on the faded margin. A device on the field's edge wall is drawn like any other (board3d/layout.js stageDevices):
|
||||
// act2 m01's row-13 blowers top the field and its row-6 ones stand under the bench in the normal views, as in the
|
||||
// official normal rounds (user playtest #5 item 6 and its follow-up); the airflow (_drawFlow) only covers drawn
|
||||
// tiles, so the row-6 machines' shows in the Final Assault view alone
|
||||
if (gt && (!gt.drawn || gt.scenery || gt.dist > 1)) continue;
|
||||
out.push(d);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user