feedback5 WM: merge feedback4 (896dd5d, the coming 0.1.4) — PRs #150 #66 #146 #74 #72 #103 #149 #109 #160 ported into the split layout
Ported by hand: - #109 kit hunks → kits/ops (the tier files stay re-export shims): 宴 chess_char_1_18-utage.js, 野鬃 chess_char_1_19-wildmn.js, 砾 chess_char_2_12-gravel.js, 斯卡蒂 chess_char_3_05-skadi.js, 伊内丝 chess_char_4_04-ines.js, 缄默德克萨斯 chess_char_4_16-texas2.js, 耀骑士临光 chess_char_6_17-nearl2.js. The +/- lines are identical to #109's tier1/2/3/4/6 diffs. - #109 generic.js against W5D's own-duration passives (一击即退): the deployment window is computed where #109 computes it, with W5D's case included. Both forms run #109's duration lifecycle (activateOnDeploy, spType 'none', the skill's own mods), and W5D's 冲锋号令 DP start effect is kept. - #103 room.js through i18n phase 1: t('{name}邀请你加入卫戍协议:盟约【{difficulty}】') with the translated difficulty name (the Chinese text is the PR's), plus its English line in public/i18n/en.json. - data/assets.json: feedback5's manifest plus #72's audio.bgm.combatAlts (after boss, the plan order). files +3 and bytes +5 037 595 as measured on feedback4; the hash is recomputed with the generator's contentHash. No other data/ file changed. - docs: DESIGN §5.6 (#109's timed deployment paragraph before feedback5's trigger rules; "Permanent passive skills are always on"), SIM §7.4 (both generic passive cases). - Auto-merged and checked: #149 bond-bar fold (still in screens/game.js), #160 skills.js / spine.js, #109 skills.js / snapshot.js, #66 addon/battle.js (restTile / isDown live in sim/battle/tiles.js), #150 units.js, #72 audio.js / plan.mjs, #74 plan.mjs / docs. Where the PRs met feedback5 work: - 突袭 (W5L, GitHub #49): raidPoll counts a skill that needs no SP while it is on. That is a passive, as before, or a #109 deploy-timed skill while its window runs. Once the window has ended only the idle trigger is left. Without this change 缄默德克萨斯 / 宴 lost #49. research 02 §3.18 says so. - Tests changed to #109's representation: bonds_addon #49 test (kind 'duration', activateOnDeploy) plus a new test (window over → idle trigger only), and standin.test.js's 预备干员 PASSIVE branch (the skill's mods instead of the generic:passive buff). Golden regenerated on the merged code. Attribution: each PR's gameplay change was reverted alone in a scratch copy, and all three together. With all three reverted the digests equal feedback5's exactly. Every moved scenario was replayed and fields the unit that explains it. - #160 only (0.5 s skill events of deploy passives; events.skill only): roster-001/006/025/049, bond-arcaneShip-low, bond-emptyShip-high, bond-investShip-high, bond-kjeragShip-low, bond-siracusaShip-low/high, bond-victoriaShip-low, bond-yanShip-high, boss-boss_2/4/6-solo, hidden-boss_8/10-solo, standin-03/05/08/10, diy-005/006 (普罗旺斯 S1, 琳琅诗怀雅 S1/S2, 星熊 S2, 凯瑟琳 S1, Misery S3 as stand-in / 自选 prototype). - #109 only (deploy-timed skill state and lifecycle; 突袭 技能就绪 limited to the window; generic 一击即退): roster-003/004/005/021/023/024/039/041/042/046/047, bond-egirShip-high, bond-indomShip-high, bond-kazimierzShip-low/high, hidden-boss_8-pair, standin-01, coop4-FUNNY-6, coop2-NORMAL-8-serverrun. - #66 only (灵巧's aura stays only for a killed member, from its body tile): roster-028, coop2-NORMAL-3, coop3-ABYSS-5, coop4-ABYSS-7, solo-HARD-9-boosted. - #109 + #160: roster-002, roster-029, bond-investShip-low, bond-raidShip-low/high, bond-suntShip-low, bond-visiShip-high. - #66 + #160: roster-008, roster-027. - #66 + #109: roster-022, roster-040, bond-indomShip-low, boss-boss_2/4/6-pair, hidden-boss_10-pair, standin-06, coop2-HARD-4, coop2-NORMAL-14-standins. - all three: roster-010, roster-012, roster-031. 69 scenarios. Every other digest is unchanged.
This commit is contained in:
commit
a0a7660287
55 files changed
+2140
-736
No files matched your search
@@ -28,9 +28,10 @@
|
||||
// "附带…凋亡/灼燃/神经损伤" + ep_damage_ratio ⇒ element damage on hit (× damage dealt when the text says "伤害N%的…损伤",
|
||||
// else × ATK); "屏障" + shield_max_hp_ratio / hp_ratio ⇒ self shield at start decaying over its duration (砾, 新约能天使);
|
||||
// "立即流失N%当前生命" + hp_ratio ⇒ self HP loss at start (宴, 风丸); hp_ratio + "恢复/回复…生命" ⇒ self heal at start.
|
||||
// Passive skills only apply stat mods (for bb.duration s when the text says "N秒内": 宴; for the skill's own duration
|
||||
// when an ON_DEPLOY passive says "部署后…" without one in its blackboard: 一击即退, duration 10 — PRTS 技能 持续 10) and
|
||||
// the self/counter effects above — their scales describe procs (bombs, sword rain, counters) that need a kit.
|
||||
// Passive skills with stat mods + bb.duration + "N秒内" use a deployment duration (宴), and so do the ON_DEPLOY passives that
|
||||
// say "部署后…" with the skill's own duration and none in their blackboard (一击即退, duration 10 — PRTS 技能 持续 10):
|
||||
// kind 'duration', activateOnDeploy (#109); other passives apply stat mods and the self/counter effects above — their
|
||||
// scales describe procs (bombs, sword rain, counters) that need a hand-authored kit.
|
||||
// "立即获得N点部署费用" + cost ⇒ +cost DP for the player at the start (冲锋号令); an AUTO skill that does nothing else
|
||||
// fires as soon as its SP is full (as 德克萨斯's kit casts the same skill: kits/ops/chess_char_1_08-texas.js).
|
||||
// genericTalents(def): the talents a generic kit can apply exactly — an unconditional stat line ("攻击力+8%",
|
||||
@@ -112,10 +113,8 @@ export function genericSkillSpec(sk, bb = sk?.bb ?? {}, def = null) {
|
||||
if (!sk) return null;
|
||||
const g = getter(bb);
|
||||
const ga = attackGetter(bb);
|
||||
const kind = genericKind(sk, bb);
|
||||
let kind = genericKind(sk, bb);
|
||||
const desc = String(sk.description || '');
|
||||
const passive = kind === 'passive';
|
||||
const timed = kind === 'duration' || kind === 'ammo' || kind === 'toggle';
|
||||
// "受到攻击时…造成…" numbers belong to a counter effect (the operator's own, or an ally's: 刺玫 "该角色受到攻击时")
|
||||
const counterCtx = /受到(敌人的)?攻击时/.test(desc);
|
||||
const counterText = counterCtx && !/该(角色|干员|单位)受到攻击时/.test(desc);
|
||||
@@ -154,9 +153,21 @@ export function genericSkillSpec(sk, bb = sk?.bb ?? {}, def = null) {
|
||||
set('resIgnoreFlat', g('magic_resist_penetrate_fixed'));
|
||||
set('defIgnoreFlat', g('def_penetrate_fixed'));
|
||||
|
||||
// Effect inference keeps the original kind; a deployment window only changes the lifecycle.
|
||||
const passive = kind === 'passive';
|
||||
const timed = kind === 'duration' || kind === 'ammo' || kind === 'toggle';
|
||||
// a passive stat buff limited in time ("部署后…在14秒内攻击力+65%", 宴) runs as a duration skill from every deployment;
|
||||
// so does an ON_DEPLOY passive whose duration is the skill's own (一击即退 "部署后攻击力+X%,防御力+Y%", duration 10, no bb key)
|
||||
const ownDuration = num(bb.duration) === undefined && sk.duration > 0 && /^部署后/.test(desc) ? sk.duration : 0;
|
||||
const passiveTimed = passive && Object.keys(mods).length
|
||||
? (num(bb.duration) > 0 && /\d+(\.\d+)?秒内/.test(desc) ? num(bb.duration) : ownDuration)
|
||||
: 0;
|
||||
if (passiveTimed) kind = 'duration';
|
||||
|
||||
// ---- targeting / attack override (never for passives: their scales describe procs)
|
||||
const targeting = {};
|
||||
const attack = {};
|
||||
if (passiveTimed && /攻击[^。;]*(造成|变为|变成)[^。;]*法术伤害|伤害类型变为法术/.test(desc)) attack.dmgType = 'arts';
|
||||
const mt = ga('max_target');
|
||||
if (!passive && mt !== undefined && mt > 0) targeting.maxTargets = Math.floor(mt);
|
||||
const ext = g('ability_range_forward_extend');
|
||||
@@ -278,17 +289,12 @@ export function genericSkillSpec(sk, bb = sk?.bb ?? {}, def = null) {
|
||||
id: sk.id,
|
||||
name: sk.name,
|
||||
kind,
|
||||
duration: kind === 'duration' ? sk.duration : (kind === 'ammo' && sk.duration > 0 ? sk.duration : undefined),
|
||||
duration: kind === 'duration' ? (passiveTimed || sk.duration) : (kind === 'ammo' && sk.duration > 0 ? sk.duration : undefined),
|
||||
ammo,
|
||||
};
|
||||
|
||||
// passive stat buffs limited in time ("部署后…在14秒内攻击力+65%", 宴) become a timed buff at each deployment; so do the
|
||||
// ON_DEPLOY passives whose duration is the skill's own (一击即退 "部署后攻击力+X%,防御力+Y%", duration 10, no bb key)
|
||||
const ownDuration = num(bb.duration) === undefined && sk.duration > 0 && /^部署后/.test(desc) ? sk.duration : 0;
|
||||
const passiveTimed = passive && Object.keys(mods).length
|
||||
? (num(bb.duration) > 0 && /\d+(\.\d+)?秒内/.test(desc) ? num(bb.duration) : ownDuration)
|
||||
: 0;
|
||||
if (Object.keys(mods).length && !passiveTimed) spec.mods = mods;
|
||||
if (passiveTimed) Object.assign(spec, { activateOnDeploy: true, spCost: 0, spType: 'none', trigger: 'NEVER' });
|
||||
if (Object.keys(mods).length) spec.mods = mods;
|
||||
if (Object.keys(targeting).length) spec.targeting = targeting;
|
||||
// instant/charges skills act on the next attack: mods/targeting without an explicit attack still need one
|
||||
if (!Object.keys(attack).length && (kind === 'instant' || kind === 'charges') && (spec.mods || spec.targeting)) spec.attack = {};
|
||||
@@ -303,10 +309,6 @@ export function genericSkillSpec(sk, bb = sk?.bb ?? {}, def = null) {
|
||||
// ---- start / end effects
|
||||
const starts = [];
|
||||
const ends = [];
|
||||
if (passiveTimed) {
|
||||
const m = { ...mods };
|
||||
starts.push(({ battle, unit }) => battle.addBuff(unit, { key: `generic:passive:${sk.id ?? 'skill'}`, duration: passiveTimed, mods: m, tags: ['skill'] }));
|
||||
}
|
||||
if (gainsDp) {
|
||||
starts.push(({ battle, unit }) => {
|
||||
battle.addDp(unit.ownerId, dpGain);
|
||||
|
||||
Reference in new issue
Block a user