Playtest #6 follow-up (v2.5.1): leader HP review — 直接乘算, one debuff instance, 999 layer cap, 限伤; elite to the board; 假想敌:胄 kit
- co-op leaders died within seconds: leader HP is the official data (40 values pinned); bond / strategy / item / 机变 / 特质 "+X%" bonuses now add up (PRTS 直接乘算) instead of compounding; a same-named enemy debuff keeps one (strongest) instance per target (奥术 across a pair field); leader parts pass damage 1:1; fixed co-op pool (the user's call) - official limits read from the client: each bond stops at 999 layers (MAX_GARRISON_STACK); a leader hit of 300000+ in boss / hidden battles is cancelled (MAX_BATTLE_DAMAGE, 限伤) — shared/constants.js switches, research 11 - a merge that consumes a deployed copy puts the elite on that tile and facing (user-confirmed); gold target highlight, promotion effect - 假想敌:胄 per PRTS: one shell, shells within range, any drone death costs 2 % max HP, 剑/锤 sorties and 瘫痪 - DESIGN §20.10–§20.14; 2842 unit tests, all 28 browser suites green; Chrome = Node on boss fields
This commit is contained in:
1 parent
6464e4b46a
commit
620f88c0d8
81 files changed
+4194
-447
No files matched your search
+32
-2
@@ -8,7 +8,10 @@
|
||||
// and the field clear of `hud(kind, size)` = { top, bottom } px of
|
||||
// DOM HUD along the top / bottom edge (projection.js clearHud; user
|
||||
// playtest #5 item 9: the shop bar covered the bench on phones)
|
||||
// view.setPrep(privateState, { editable, canPlace }) hand/temp/board pieces; editable enables drag & drop
|
||||
// view.setPrep(privateState, { editable, canPlace }) hand/temp/board pieces; editable enables drag & drop; a
|
||||
// new board piece flashes (fx.deploy); a merge's elite — on the tile of
|
||||
// the deployed copy it replaced, or on its bench slot — gets the
|
||||
// promotion cue instead (render/promote.js, fx.promote)
|
||||
// view.enterBattle(fieldMeta) m.field { fieldId, kind, rect, stageId, units: [UnitInfo] }
|
||||
// view.pushSnapshot(snap); view.pushEvents(ev | { ev, gt }) b.snap / b.ev wire frames as received (game time in
|
||||
// `gt`; a numeric `t` is accepted for raw Battle snapshots / recordings)
|
||||
@@ -101,6 +104,7 @@ import { AREAS, areaFor, unionAreas } from './board3d/layout.js';
|
||||
import { layoutPen, penSignature } from './pen.js';
|
||||
import { IDENTITY, bossPrepField, tilesToDisp } from './prepfield.js';
|
||||
import { pickOnTile, pickBattle, hitRectAt } from './pick.js';
|
||||
import { promotionsOf } from './promote.js';
|
||||
|
||||
const VENDOR = { pixi: '/vendor/pixi.min.js', spine: '/vendor/pixi-spine.js' };
|
||||
const PIECE_DIRS = new Set(['UP', 'RIGHT', 'DOWN', 'LEFT']);
|
||||
@@ -427,6 +431,10 @@ export async function createFieldView(host, options = {}) {
|
||||
let pendingView = null; // tile band/focus to apply when the camera transition ends
|
||||
const views = new Map(); // key → view (prep: 'p:'+uid; battle: unit id)
|
||||
let prepPieces = []; // { uid, piece, area, idx, row, col, key }
|
||||
// the last prep pieces before a battle / scouting board emptied prepPieces: a merge completed between two preps (a band
|
||||
// or 机变 grant at ROUND_START, a SETTLE merge) is still recognised by the next setPrep (QA 6b)
|
||||
let promoBase = [];
|
||||
const promotions = []; // the last merges cued by setPrep (fx.promote): { uid, id, area, row, col, idx, copies } — dev / tests
|
||||
let battleMeta = null;
|
||||
const infos = new Map(); // battle unit id → UnitInfo
|
||||
// battle ids whose view finished its death / leak fade: a snapshot may still list them for a moment (the sim keeps
|
||||
@@ -845,6 +853,20 @@ export async function createFieldView(host, options = {}) {
|
||||
addList(src.board, 'board');
|
||||
const seen = new Set();
|
||||
const prevBoard = new Set(prepPieces.filter((p) => p.area === 'board').map((p) => p.uid));
|
||||
// merges since the last state (render/promote.js): new elite uid → where its consumed copies stood (their views
|
||||
// still exist until the sweep below) — the elite gets the promotion cue instead of the deploy flash
|
||||
const promoFrom = new Map();
|
||||
const before = prepPieces.length ? prepPieces : promoBase;
|
||||
promoBase = [];
|
||||
for (const [uid, copies] of promotionsOf(before, list, (id) => data.chess(id))) {
|
||||
// the consumed copies' views (gone after a battle rebuilt the scene: their slots instead) — the streaks' origins
|
||||
promoFrom.set(uid, copies.map((g) => {
|
||||
const cv = views.get(g.key);
|
||||
if (cv && !cv.destroyed) return { x: cv.x, y: cv.y, z: cv.z || 0 };
|
||||
const w = slotWorld(g);
|
||||
return w ? { x: w.x, y: w.y, z: w.z || 0 } : null;
|
||||
}).filter(Boolean));
|
||||
}
|
||||
for (const e of list) {
|
||||
if (seen.has(e.uid)) continue; // duplicate uid in bad state: keep the first
|
||||
seen.add(e.uid);
|
||||
@@ -863,7 +885,13 @@ export async function createFieldView(host, options = {}) {
|
||||
v._sig = sig;
|
||||
v.setWorld(w.x, w.y, w.z);
|
||||
views.set(key, v);
|
||||
if (e.area === 'board' && prevBoard.size && !prevBoard.has(e.uid)) { v.onDeploy?.(); fx.deploy(v); }
|
||||
if (promoFrom.has(e.uid)) {
|
||||
// a merge's elite: on the tile of the deployed copy it replaced, or on its bench slot
|
||||
if (e.area === 'board') v.onDeploy?.();
|
||||
fx.promote(v, promoFrom.get(e.uid).filter((f) => Math.abs(f.x - w.x) + Math.abs(f.y - w.y) > 1e-3));
|
||||
promotions.push({ uid: e.uid, id: e.piece.id, area: e.area, row: e.row ?? null, col: e.col ?? null, idx: e.idx ?? null, copies: promoFrom.get(e.uid).length });
|
||||
if (promotions.length > 20) promotions.shift();
|
||||
} else if (e.area === 'board' && prevBoard.size && !prevBoard.has(e.uid)) { v.onDeploy?.(); fx.deploy(v); }
|
||||
} else {
|
||||
const prevHome = v._home;
|
||||
const moved = !prevHome || prevHome.x !== w.x || prevHome.y !== w.y || prevHome.z !== w.z;
|
||||
@@ -1226,6 +1254,7 @@ export async function createFieldView(host, options = {}) {
|
||||
drag.reset();
|
||||
endDragVisual(false);
|
||||
clearViews();
|
||||
if (prepPieces.length) promoBase = prepPieces;
|
||||
prepPieces = [];
|
||||
infos.clear();
|
||||
gone.clear();
|
||||
@@ -1783,6 +1812,7 @@ export async function createFieldView(host, options = {}) {
|
||||
/** Dev hooks (demo / tests). */
|
||||
debug: {
|
||||
app, get cam() { return cam; }, get board3d() { return board3d; }, tiles, views, penViews, interp, fx, ctx, drag, get camKind() { return viewKind(camKind, camOpts); },
|
||||
promotions,
|
||||
// picking (render/pick.js) at canvas px: the prep piece / battle view / pen view there, the ground tile under it
|
||||
pick: { pieceAt, battleUnitAt, penUnitAt, groundTile },
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user