feedback5 O8: two additive engine rules for the 自选 kits — a 屏障 of one damage type and a profile's own target exclusion
- buffs.js makeBuff / damage.js absorbShields: a shield buff with `shieldType` ('phys' | 'arts' | 'true' | 'elemental')
absorbs that damage type only (夜莺 S2 法术护盾 "屏障能吸收…法术伤害"); a shield without a type absorbs every type as
before (PRTS 术语释义 屏障 "若无特殊说明,屏障可吸收全种类伤害"); shields are still spent oldest first.
- targeting.js canTargetEnemy: a profile's `skipEnemy(e)` (a kit trait) keeps such an enemy out of the unit's normal
targets, its block targets and its skill-trigger target condition (嵯峨 劝善 "嵯峨不攻击重伤单位").
- docs/SIM.md §3 / §4 / §8, professions.js profile field list.
No content uses either yet: golden unchanged (roster 49, bonds 46, fields 22, matches 17, standins 10, diy 6 match).
Test: test/sim/feedback5-o8-engine.test.js (2).
This commit is contained in:
1 parent
742f478526
commit
db7a177164
6 files changed
+115
-12
No files matched your search
@@ -155,6 +155,9 @@ export function makeBuff(b) {
|
||||
tags: b.tags ?? [],
|
||||
shield: b.shield ?? (b.mods && b.mods.shield) ?? 0,
|
||||
shieldHits: b.shieldHits ?? 0,
|
||||
// a 屏障 that absorbs one damage type only (damage.js absorbShields): 'phys' | 'arts' | 'true' | 'elemental'; null =
|
||||
// every type (PRTS 术语释义 屏障 "若无特殊说明,屏障可吸收全种类伤害") — 夜莺 S2 法术护盾 "能吸收…法术伤害"
|
||||
shieldType: b.shieldType ?? null,
|
||||
persist: !!b.persist,
|
||||
status: b.status ?? null,
|
||||
visible: b.visible ?? false,
|
||||
|
||||
+13
-7
@@ -5,7 +5,8 @@
|
||||
// → dodge (phys/arts, canDodge) → mitigation (phys: DEF, arts: RES, true: none)
|
||||
// → × source dmgDealtMul (× phys/artsDealtMul) × target dmgTakenMul (not for 元素伤害) × type-taken mul × dmg.mul
|
||||
// → 限伤 (leaders in boss / hidden battles: a hit of ceil(final) ≥ BOSS_HIT_LIMIT is cancelled, see leaderHitCancelled)
|
||||
// → shields (hit-negating barriers first, then HP shields) → HP loss (boss pool routing) → 'damaged' hook
|
||||
// → shields (hit-negating barriers first, then HP shields; a typed one — buff `shieldType` — only its damage type)
|
||||
// → HP loss (boss pool routing) → 'damaged' hook
|
||||
// → SP-on-hurt / TAKE_DAMAGE trigger → fatal/kill.
|
||||
// Damage-dealt stats (the source's `stats.dmg`, the player's `damageDealt`) count only HP removed from the other side:
|
||||
// self and friendly damage (a 源石溶剂 drain, an operator's own 流失) is the target's `taken` and keeps the kill credit.
|
||||
@@ -180,14 +181,19 @@ export function leaderHitCancelled(battle, target, amount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Absorb damage with shields on `target`. Returns the remaining amount. */
|
||||
export function absorbShields(battle, target, amount) {
|
||||
/**
|
||||
* Absorb damage with shields on `target`. Returns the remaining amount. `type` = the damage type: a shield buff with a
|
||||
* `shieldType` absorbs only that type (夜莺 S2 "屏障能吸收…法术伤害"); one without absorbs every type (PRTS 术语释义 屏障
|
||||
* "若无特殊说明,屏障可吸收全种类伤害"). Older shields first (buff order: "优先消耗先生成的屏障").
|
||||
*/
|
||||
export function absorbShields(battle, target, amount, type = null) {
|
||||
if (amount <= 0) return 0;
|
||||
let changed = false;
|
||||
let rest = amount;
|
||||
const absorbs = (b) => !b.shieldType || b.shieldType === type;
|
||||
for (let i = 0; i < target.buffs.length && rest > 0; i++) {
|
||||
const b = target.buffs[i];
|
||||
if (b.shieldHits > 0) {
|
||||
if (b.shieldHits > 0 && absorbs(b)) {
|
||||
b.shieldHits--;
|
||||
rest = 0;
|
||||
if (b.shieldHits <= 0 && !(b.shield > 0) && !b.mods && !b.flags) { battle._removeBuffAt(target, i); i--; }
|
||||
@@ -197,7 +203,7 @@ export function absorbShields(battle, target, amount) {
|
||||
}
|
||||
for (let i = 0; i < target.buffs.length && rest > 0; i++) {
|
||||
const b = target.buffs[i];
|
||||
if (b.shield > 0) {
|
||||
if (b.shield > 0 && absorbs(b)) {
|
||||
const take = Math.min(b.shield, rest);
|
||||
b.shield -= take;
|
||||
rest -= take;
|
||||
@@ -247,7 +253,7 @@ export function dealDamage(battle, source, target, dmgIn) {
|
||||
// recognise their own (tagged) damage — never re-create such a loss with a fresh loseHp.
|
||||
if (ts.flags.hitCount || ts.flags.hitCountArts) {
|
||||
const counts = !(ts.flags.hitCountArts && !ts.flags.hitCount && type === 'phys');
|
||||
return applyHpLoss(battle, source, target, absorbShields(battle, target, counts ? 1 : 0), dmg);
|
||||
return applyHpLoss(battle, source, target, absorbShields(battle, target, counts ? 1 : 0, type), dmg);
|
||||
}
|
||||
// 无来源 damage (element bursts) takes nothing from its source's stats; the source still gets the credit below
|
||||
const ss = source && source.s && !dmg.sourceless ? source.s : null;
|
||||
@@ -267,7 +273,7 @@ export function dealDamage(battle, source, target, dmgIn) {
|
||||
// 限伤: a leader's hit of ≥ BOSS_HIT_LIMIT in a boss / hidden battle is cancelled before it reaches shields / HP — what
|
||||
// ran before it (the attack, its SP, `hit` hook effects, separate element 损伤) stays; nothing after it happens
|
||||
if (final > 0 && leaderHitCancelled(battle, target, final)) return 0;
|
||||
final = absorbShields(battle, target, final);
|
||||
final = absorbShields(battle, target, final, type);
|
||||
return applyHpLoss(battle, source, target, final, dmg);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// noHeal bool (cannot be healed by others) blockFly bool onHitStatus {key, duration, value}
|
||||
// dmgMul(battle, unit, target) → number afterHit(battle, unit, target, {dealt,x,y})
|
||||
// canAttack(battle, unit) → bool afterAttack(battle, unit, targets)
|
||||
// skipEnemy(enemy) → bool (an enemy the unit never selects — targeting.js canTargetEnemy; 嵯峨 "不攻击重伤单位")
|
||||
// hitsFn(battle, unit) → n install(battle, unit) — per-unit hooks, called once at setup
|
||||
// dollNoAttack bool (傀儡师: its <替身> makes no normal attack and casts no skill — 归溟幽灵鲨, kit trait)
|
||||
// tb — the unit's trait blackboard (data `trait.bb`), used for tunables (module upgrades included on elites)
|
||||
|
||||
@@ -74,7 +74,11 @@ export function enemyStealthed(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Can `attacker` (ally) target enemy `e` at all (ignoring range)? */
|
||||
/**
|
||||
* Can `attacker` (ally) target enemy `e` at all (ignoring range)? A profile's own exclusion `skipEnemy(e)` (a kit trait:
|
||||
* 嵯峨 劝善 "嵯峨不攻击重伤单位") keeps such an enemy out of the unit's normal targets, the enemies it blocks
|
||||
* (blockedTargets) and the target condition of its skill triggers (they pass `unit.profile`).
|
||||
*/
|
||||
export function canTargetEnemy(attacker, e, profile) {
|
||||
if (!e.alive || e.hidden || !e.deployed) return false;
|
||||
const f = e.s.flags;
|
||||
@@ -82,6 +86,7 @@ export function canTargetEnemy(attacker, e, profile) {
|
||||
if (f.stealth && enemyStealthed(e)) return false;
|
||||
if (e.isFlying && !(profile && profile.canHitFly)) return false;
|
||||
if (profile && profile.groundOnly && e.isFlying) return false;
|
||||
if (profile && typeof profile.skipEnemy === 'function' && profile.skipEnemy(e)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user