feedback1b WG: review fixes - off popup without 当前效果, destroyPiece merge test, 奥术 refresh noted

- The popup of a bond the mode never activates no longer shows the 当前效果
  block (its +20 % / +68 % promised an effect 本局禁用 denies); the bond
  text stays. The popup test asserts it.
- ctx.destroyPiece's auto-merge of returned equipment has its own test
  (constructed pair; fails without the call).
- SIM.md and the 奥术 header: an earlier PRTS revision (oldid 386936) forbade
  a unit re-applying while its own instance lasts; an equal hit here
  refreshes it - recorded as a known [ASSUMED] deviation, slightly stronger.
This commit is contained in:
sganggs committed 2026-10-03 03:08:03 +08:00
1 parent 8fa7a85a52
commit 695ece2653
5 files changed
+40 -12

No files matched your search

+8 -5
View File
@@ -390,11 +390,14 @@ catalogue status the same rule (one invisible buff `key` per target whatever app
or icon): the engine default for two same-named buffs (PRTS 作战机制 "同名buff的默认叠加策略buff只能表现出一个"). 奥术 uses
it, so the two players of a pair field compete for one instance instead of multiplying, and so do 灵知's 坚冰 and the
莱恩哈特 / 缄默德克萨斯 RES cuts, once keyed per unit (DESIGN §20.10). "Strongest" = the largest |value|. PRTS 盟约记录's
奥术 note "※同一单位仅可对同一目标同时施加1个该盟约法术伤害提升效果" (2026-03-30 revision: "…持续期间内,无法对该目标施加新的…")
limits each unit to one instance per target; read with the engine default — a newer same-named buff waits inert until
the earlier ones end (PRTS 常见同名状态 "默认叠加方式") — and 巴哈姆特 12316 ("共享型buff會跟對面搶"), one instance is effective
at a time, which is what applyStrongest keeps; strongest rather than earliest, and a unit refreshing its own instance,
stay [ASSUMED] (feedback after 0.1.0).
奥术 note "※同一单位仅可对同一目标同时施加1个该盟约法术伤害提升效果" limits each unit to one instance per target; read with
the engine default — a newer same-named buff waits inert until the earlier ones end (PRTS 常见同名状态 "默认叠加方式") — and
巴哈姆特 12316 ("共享型buff會跟對面搶"), one instance is effective at a time, which is what applyStrongest keeps; strongest
rather than earliest is [ASSUMED]. Known deviation [ASSUMED]: an earlier revision of that note (oldid 386936) read
"同一单位在对同一目标施加的“法术伤害提升”效果的持续期间内,无法对该目标施加新的该盟约的法术伤害提升效果" — no re-application
while the unit's own instance lasts, so it would lapse 3 s after the first hit and return with the next arts hit —
whereas an equal-value hit here refreshes the instance to a fresh 3 s; slightly stronger (at most one attack interval
of coverage per 3 s), kept because the current wording no longer says so (feedback after 0.1.0).
| key | effect | value |
|---|---|---|
+4 -3
View File
@@ -60,10 +60,11 @@ export function BondStrip({ bonds, layersDisabled = false, onOpen, openId = null
/**
* Bond detail popup.
* @param {{ bondId: string, entry?: any, priv?: any, banned?: string[], onClose: Function, onMember?: (chessId:string)=>void,
* place?: 'left'|'beside'|'besideR'|'right'|null, over?: boolean, beside?: 'left'|'right'|null, owner?: string|null }} props —
* place?: 'left'|'beside'|'besideR'|'right'|null, over?: boolean, beside?: 'left'|'right'|null, owner?: string|null, off?: boolean }} props —
* `place`: where it opens (gameLogic bondPopupPlace; `beside: 'left'` = the older spelling of 'beside'); `over`: above the
* detail card; `owner`: the watched teammate's name (`entry` / `priv` are then theirs: ui/watchBonds.js); `off`: the mode
* never activates this bond (gameLogic modeOffBonds — 标准's 10 inactive bonds): 本局禁用 instead of 未激活, with a note
* never activates this bond (gameLogic modeOffBonds — 标准's 10 inactive bonds): 本局禁用 instead of 未激活, with a note, no
* 在场 count and no 当前效果 block (its numbers would promise an effect the mode never gives; the bond text stays)
*/
export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember, place = null, over = false, beside = null, owner = null, off = false }) {
const b = data.lookup('bonds', bondId);
@@ -76,7 +77,7 @@ export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember,
const members = bondMembers(b, priv, banned, (id) => data.lookup('chess', id));
const countsHand = entry?.countsHand ?? b.countsHand;
const next = nextThreshold(count, th);
const hasNow = !!(b.effectDescRaw || b.effectDesc);
const hasNow = !off && !!(b.effectDescRaw || b.effectDesc);
const at = place || (beside === 'left' ? 'beside' : 'left');
return html`<div class=${cx('bpop', 'brackets', `bpop--${at}`, over && 'is-over', owner && 'is-other')} data-place=${at} data-owner=${owner || null}
role="dialog" aria-label=${owner ? `${owner} 的盟约:${b.name}` : `盟约:${b.name}`}>
+5 -3
View File
@@ -19,9 +19,11 @@
// instances multiplied (×5.4 × ×5.6 on a leader at ~250 layers, DESIGN §20.10). PRTS 盟约记录's own
// note "※同一单位仅可对同一目标同时施加1个该盟约法术伤害提升效果" (one instance per unit and target)
// fits it under the engine default (a newer same-named buff waits until the earlier ends, PRTS
// 常见同名状态); strongest vs earliest and a unit refreshing its own stay [ASSUMED]. Re-measured after
// the 0.1.0 report "奥术盟约不生效": it works on the real and the browser path
// (test/sim/feedback1b-arcane.test.js); 标准 never activates it (modeDataDict inactiveBondIdList)
// 常见同名状态); strongest vs earliest is [ASSUMED]. Known deviation [ASSUMED]: an earlier revision
// (oldid 386936) forbade a unit re-applying while its own instance lasts; an equal hit here
// refreshes it to a fresh 3 s (slightly stronger). Re-measured after the 0.1.0 report
// "奥术盟约不生效": it works on the real and the browser path (test/sim/feedback1b-arcane.test.js);
// 标准 never activates it (modeDataDict inactiveBondIdList)
// 坚守 steadShip all operators max HP +(base + per·L); tier 2: 40 % of a non-member operator's damage is borne by
// the members on the field (split evenly, sourceless true damage — already mitigated), members’ thorns
// (base + per·L arts, sourceless but credited to the member hit, ≤ 1 per cd_duration per member)
+17
View File
@@ -11,6 +11,7 @@ import assert from 'node:assert/strict';
import { DATA, makeMatch, give, giveItem, legalTileFor, checkInvariants } from './harness.js';
import { tileKey } from '../../server/match/board.js';
import { applyCard } from '../../server/match/choices.js';
import { makeCtx } from '../../server/match/effectsMeta.js';
const WHITE = 'chess_item_1_05_e_a';
const GOLD = 'chess_item_1_05_e_b';
@@ -134,6 +135,22 @@ test('a promotion that returns equipment merges a returned pair (latent: no norm
checkInvariants(m);
});
test('an effect that removes an operator (ctx.destroyPiece) merges a returned pair (latent: no normal state holds a pair)', () => {
const { m, ps } = prep();
const [a] = deploy(m, ps, [OP]);
// built directly: the carrier's white and a white in the hand — every entry path would have merged them at once
a.items = [ps.newPiece('item', WHITE)];
ps.hand[ps.hand.findIndex((x) => x == null)] = ps.newPiece('item', WHITE);
ps.recompute();
// the path of 突变细胞 / the recruit-and-gift item / the round-start promotion item (builtinMeta, content/items/meta.js)
const ctx = makeCtx(m, ps, { kind: 'item', key: 'item:test' }, 'onRoundStart');
assert.equal(ctx.destroyPiece(a.uid), true);
assert.equal(ps.find(a.uid), null, 'the operator is gone');
assert.deepEqual(count(ps), { white: 0, gold: 1 }, '"在失去该干员…" returns the equipment, then the auto-merge');
checkInvariants(m);
m.dispose();
});
test('random intents around 源石溶剂 (buy, equip / replace, sell, move, destroy) conserve W + 2·G and never leave a pair', () => {
let seed = 11;
const rnd = () => { seed = (seed * 1103515245 + 12345) >>> 0; return seed / 4294967296; };
+6 -1
View File
@@ -94,15 +94,20 @@ test('shop / reward card: a mode-disabled bond tag is struck through with the
assert.ok(tags(null).every((v) => !hasClass(v, 'is-off')), 'no set: as before');
});
test('bond popup: 本局禁用 instead of 未激活, a note, and no misleading member count', () => {
test('bond popup: 本局禁用 instead of 未激活, a note, and no misleading member count or 当前效果 numbers', () => {
const pop = BondPopup({ bondId: 'arcaneShip', entry: null, priv: { board: [], hand: [] }, onClose() {}, off: true });
const text = textOf(pop);
assert.match(text, /本局禁用/);
assert.match(text, /本模式下该盟约不会激活/);
assert.doesNotMatch(text, /在场/);
// the 当前效果 block ("提升20% … 68%") would promise an effect the mode never gives; the bond text (盟约效果) stays
assert.doesNotMatch(text, /当前效果/);
assert.ok(![...walk(pop)].some((v) => hasClass(v, 'bpop__sec--now')), 'no current-effect section');
assert.match(text, /盟约效果/);
const plain = textOf(BondPopup({ bondId: 'arcaneShip', entry: null, priv: { board: [], hand: [] }, onClose() {} }));
assert.match(plain, /未激活/);
assert.match(plain, /在场/);
assert.match(plain, /当前效果/, 'an enabled bond keeps its current-effect block');
});
test('the game screen hands the mode-disabled set to the shop bar, the detail card and the bond popup', () => {