hrbattle 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/battle/battleCore.js +14 -4
- package/dist/battle/config/sampleData.d.ts +3 -0
- package/dist/battle/config/sampleData.js +82 -0
- package/dist/battle/script/designedScripts.js +55 -69
- package/dist/battle/script/monsterScripts.js +10 -8
- package/dist/battle/script/monsterScripts18xx.js +34 -34
- package/dist/battle/script/monsterScripts19xx.js +14 -14
- package/dist/battle/script/monsterScripts19xxPart2.js +14 -14
- package/dist/battle/script/sampleScripts.d.ts +28 -0
- package/dist/battle/script/sampleScripts.js +223 -0
- package/dist/battle/skillEngine.d.ts +7 -1
- package/dist/battle/skillEngine.js +39 -4
- package/dist/battle/types.d.ts +23 -1
- package/package.json +1 -1
|
@@ -395,7 +395,10 @@ export class BattleCore {
|
|
|
395
395
|
applyBuff: (sourceId, targetId, buffId) => this.applyBuff(sourceId, targetId, buffId),
|
|
396
396
|
getEffectiveStats: (unit) => this.effectSystem.getEffectiveStats(unit),
|
|
397
397
|
createScriptApi: (skillElement) => ({
|
|
398
|
-
damage: (sourceId, targetId, value) =>
|
|
398
|
+
damage: (sourceId, targetId, value) => {
|
|
399
|
+
const r = this.applyDamage(sourceId, targetId, value, skillElement);
|
|
400
|
+
return { damage: r.damage, imbalanceDelta: r.imbalanceDelta, triggeredImbalanceBreak: r.triggeredImbalanceBreak };
|
|
401
|
+
},
|
|
399
402
|
heal: (targetId, value) => this.applyHeal(targetId, value),
|
|
400
403
|
shield: (targetId, value) => this.applyShield(targetId, value),
|
|
401
404
|
adjustImbalance: (targetId, delta) => {
|
|
@@ -575,10 +578,14 @@ export class BattleCore {
|
|
|
575
578
|
this.eventBus.emit({ name: "OnKill", payload: { killerId: source.id, targetId: target.id } });
|
|
576
579
|
}
|
|
577
580
|
this.eventBus.emit({ name: "OnAfterDamage", payload: { sourceId, targetId, value: damage } });
|
|
581
|
+
let imbalanceDelta = 0;
|
|
582
|
+
let triggeredImbalanceBreak = false;
|
|
578
583
|
if (staggerElement && sourceId !== targetId && target.runtime.alive) {
|
|
579
|
-
this.accumulateStagger(source, target, staggerElement);
|
|
584
|
+
const staggerResult = this.accumulateStagger(source, target, staggerElement);
|
|
585
|
+
imbalanceDelta = staggerResult.applied;
|
|
586
|
+
triggeredImbalanceBreak = staggerResult.broke;
|
|
580
587
|
}
|
|
581
|
-
return damage;
|
|
588
|
+
return { damage, imbalanceDelta, triggeredImbalanceBreak };
|
|
582
589
|
}
|
|
583
590
|
applyHeal(targetId, value) {
|
|
584
591
|
const target = this.mustUnit(targetId);
|
|
@@ -623,7 +630,7 @@ export class BattleCore {
|
|
|
623
630
|
}
|
|
624
631
|
accumulateStagger(source, target, skillElement) {
|
|
625
632
|
if (this.pendingImbalanceClear.has(target.id)) {
|
|
626
|
-
return;
|
|
633
|
+
return { applied: 0, broke: false };
|
|
627
634
|
}
|
|
628
635
|
const effectiveSource = this.effectSystem.getEffectiveStats(source);
|
|
629
636
|
const baseStagger = effectiveSource.Att;
|
|
@@ -642,9 +649,12 @@ export class BattleCore {
|
|
|
642
649
|
if (applied !== 0) {
|
|
643
650
|
this.logger.logImbalanceChange(target.id, applied, "skill_effect", this.activeSkillContext?.actorId ?? source.id, this.activeSkillContext?.skillId);
|
|
644
651
|
}
|
|
652
|
+
let broke = false;
|
|
645
653
|
if (target.runtime.Imbalance >= max) {
|
|
654
|
+
broke = true;
|
|
646
655
|
this.onImbalanceBreak(source, target, skillElement);
|
|
647
656
|
}
|
|
657
|
+
return { applied, broke };
|
|
648
658
|
}
|
|
649
659
|
onImbalanceBreak(source, target, element) {
|
|
650
660
|
const max = this.computeImbalanceMax(target);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const sampleBuffs = [
|
|
2
|
+
{
|
|
3
|
+
id: "slow",
|
|
4
|
+
name: "迟缓",
|
|
5
|
+
maxStacks: 5,
|
|
6
|
+
durationPerStack: 1,
|
|
7
|
+
expireRounds: 1,
|
|
8
|
+
onRoundEndDelta: -1,
|
|
9
|
+
speedRateDelta: -1000
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: "stun",
|
|
13
|
+
name: "眩晕",
|
|
14
|
+
maxStacks: 1,
|
|
15
|
+
durationPerStack: 1,
|
|
16
|
+
onRoundEndDelta: -999,
|
|
17
|
+
stun: true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "taunt",
|
|
21
|
+
name: "嘲讽",
|
|
22
|
+
maxStacks: 1,
|
|
23
|
+
durationPerStack: 2,
|
|
24
|
+
expireRounds: 2,
|
|
25
|
+
onRoundEndDelta: -1,
|
|
26
|
+
taunt: true
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "burn",
|
|
30
|
+
name: "点燃",
|
|
31
|
+
maxStacks: 99,
|
|
32
|
+
durationPerStack: 1,
|
|
33
|
+
expireRounds: 1,
|
|
34
|
+
onRoundEndDelta: -1,
|
|
35
|
+
dotRatio: 0.18
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "share-damage",
|
|
39
|
+
name: "分摊伤害",
|
|
40
|
+
maxStacks: 1,
|
|
41
|
+
durationPerStack: 3,
|
|
42
|
+
expireRounds: 3,
|
|
43
|
+
onRoundEndDelta: -1
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "imbalance-vulnerability",
|
|
47
|
+
name: "失衡易伤",
|
|
48
|
+
maxStacks: 1,
|
|
49
|
+
durationPerStack: 1,
|
|
50
|
+
expireRounds: 1,
|
|
51
|
+
onRoundEndDelta: -1,
|
|
52
|
+
vulnerabilityDelta: 2000
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
export const sampleTemplates = [
|
|
56
|
+
{
|
|
57
|
+
id: "basic-single",
|
|
58
|
+
steps: [
|
|
59
|
+
{ kind: "damage", ratio: 0.5 },
|
|
60
|
+
{ kind: "buff", ratio: 0, buffId: "burn", fixedProb: 2500 }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "core-stun",
|
|
65
|
+
steps: [
|
|
66
|
+
{ kind: "damage", ratio: 0.8 },
|
|
67
|
+
{ kind: "buff", ratio: 0, buffId: "stun", fixedProb: 6500 }
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "ultimate-aoe",
|
|
72
|
+
steps: [{ kind: "damage", ratio: 1.8 }]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "taunt-skill",
|
|
76
|
+
steps: [{ kind: "buff", ratio: 0, buffId: "taunt", fixedProb: 8000 }]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "shield-team",
|
|
80
|
+
steps: [{ kind: "shield", ratio: 0.6 }]
|
|
81
|
+
}
|
|
82
|
+
];
|
|
@@ -14,17 +14,19 @@ function buildEmptyResult(ctx, targets = ctx.targets) {
|
|
|
14
14
|
triggeredBy: ctx.trigger
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
function buildDamageHit(ctx, targetId, finalValue) {
|
|
17
|
+
function buildDamageHit(ctx, targetId, finalValue, imbalanceDelta, triggeredImbalanceBreak) {
|
|
18
18
|
return {
|
|
19
19
|
targetId,
|
|
20
20
|
effectType: "damage",
|
|
21
21
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
22
|
-
skillType:
|
|
22
|
+
skillType: ctx.skillType,
|
|
23
23
|
isCritical: false,
|
|
24
24
|
baseValue: finalValue,
|
|
25
25
|
criticalValue: finalValue,
|
|
26
26
|
finalValue,
|
|
27
27
|
isRepression: 0,
|
|
28
|
+
imbalanceDelta,
|
|
29
|
+
triggeredImbalanceBreak,
|
|
28
30
|
damageBreakdown: {
|
|
29
31
|
preMitigation: finalValue,
|
|
30
32
|
postMitigation: finalValue,
|
|
@@ -38,7 +40,7 @@ function buildBuffHit(ctx, targetId, buffId, resisted = false) {
|
|
|
38
40
|
targetId,
|
|
39
41
|
effectType: "buff",
|
|
40
42
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
41
|
-
skillType:
|
|
43
|
+
skillType: ctx.skillType,
|
|
42
44
|
isCritical: false,
|
|
43
45
|
baseValue: 0,
|
|
44
46
|
criticalValue: 0,
|
|
@@ -53,7 +55,7 @@ function buildShieldHit(ctx, targetId, finalValue) {
|
|
|
53
55
|
targetId,
|
|
54
56
|
effectType: "shield",
|
|
55
57
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
56
|
-
skillType:
|
|
58
|
+
skillType: ctx.skillType,
|
|
57
59
|
isCritical: false,
|
|
58
60
|
baseValue: finalValue,
|
|
59
61
|
criticalValue: finalValue,
|
|
@@ -66,7 +68,7 @@ function buildHealHit(ctx, targetId, finalValue) {
|
|
|
66
68
|
targetId,
|
|
67
69
|
effectType: "heal",
|
|
68
70
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
69
|
-
skillType:
|
|
71
|
+
skillType: ctx.skillType,
|
|
70
72
|
isCritical: false,
|
|
71
73
|
baseValue: finalValue,
|
|
72
74
|
criticalValue: finalValue,
|
|
@@ -86,9 +88,9 @@ const bladeUltimateScript = {
|
|
|
86
88
|
const hits = [];
|
|
87
89
|
if (target && target.runtime.Hp * 100 < target.stats.Mhp * 50) {
|
|
88
90
|
// 策划:对生命值低于50%的敌人额外造成20%伤害
|
|
89
|
-
const
|
|
90
|
-
totalDamage += damage;
|
|
91
|
-
hits.push(buildDamageHit(ctx, targetId, damage));
|
|
91
|
+
const r = ctx.api.damage(ctx.caster, targetId, Math.floor(self.stats.Att * 0.2));
|
|
92
|
+
totalDamage += r.damage;
|
|
93
|
+
hits.push(buildDamageHit(ctx, targetId, r.damage, r.imbalanceDelta));
|
|
92
94
|
}
|
|
93
95
|
return {
|
|
94
96
|
...buildEmptyResult(ctx, [targetId]),
|
|
@@ -110,9 +112,9 @@ const bladeBasicScript = {
|
|
|
110
112
|
const hits = [];
|
|
111
113
|
if (target && target.runtime.Hp * 100 > target.stats.Mhp * 70) {
|
|
112
114
|
// 策划:对生命值高于70%的敌人造成额外20%伤害
|
|
113
|
-
const
|
|
114
|
-
totalDamage += damage;
|
|
115
|
-
hits.push(buildDamageHit(ctx, targetId, damage));
|
|
115
|
+
const r = ctx.api.damage(ctx.caster, targetId, Math.floor(self.stats.Att * 0.2));
|
|
116
|
+
totalDamage += r.damage;
|
|
117
|
+
hits.push(buildDamageHit(ctx, targetId, r.damage, r.imbalanceDelta));
|
|
116
118
|
}
|
|
117
119
|
return {
|
|
118
120
|
...buildEmptyResult(ctx, [targetId]),
|
|
@@ -137,9 +139,9 @@ const bladeCoreScript = {
|
|
|
137
139
|
for (let i = 0; i < 3; i++) {
|
|
138
140
|
const target = enemies[ctx.api.randomInt(enemies.length)];
|
|
139
141
|
hitTargets.push(target.id);
|
|
140
|
-
const
|
|
141
|
-
totalDamage += damage;
|
|
142
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
142
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.3));
|
|
143
|
+
totalDamage += r.damage;
|
|
144
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
143
145
|
if (ctx.api.randomInt(10000) < 2000) {
|
|
144
146
|
ctx.api.gainEnergy(ctx.caster, 10);
|
|
145
147
|
}
|
|
@@ -168,24 +170,8 @@ const luoluoBasicScript = {
|
|
|
168
170
|
// 洛洛核心技:获得10%生命值的护盾,每层【惩戒/意志】使护盾强度增加10%
|
|
169
171
|
const luoluoCoreScript = {
|
|
170
172
|
onCast(ctx) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const hits = [];
|
|
174
|
-
if (self) {
|
|
175
|
-
// 策划:10%Mhp护盾,每层意志增加10%
|
|
176
|
-
const willBuffs = ctx.api.getBuffs(ctx.caster).filter(b => b.id === "will");
|
|
177
|
-
const willStacks = willBuffs.reduce((sum, b) => sum + b.stacks, 0);
|
|
178
|
-
const shieldMultiplier = 1 + willStacks * 0.1;
|
|
179
|
-
const shield = Math.floor(self.stats.Mhp * 0.1 * shieldMultiplier);
|
|
180
|
-
ctx.api.shield(ctx.caster, shield);
|
|
181
|
-
totalShield += shield;
|
|
182
|
-
hits.push(buildShieldHit(ctx, ctx.caster, shield));
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
...buildEmptyResult(ctx, ctx.targets),
|
|
186
|
-
totalShield: totalShield,
|
|
187
|
-
hits
|
|
188
|
-
};
|
|
173
|
+
// 护盾交由config模板结算,script层不再重复加盾
|
|
174
|
+
return buildEmptyResult(ctx, ctx.targets);
|
|
189
175
|
}
|
|
190
176
|
};
|
|
191
177
|
const miaoluoUltimateScript = {
|
|
@@ -206,14 +192,14 @@ const miaoluoUltimateScript = {
|
|
|
206
192
|
ctx.api.addBuff(ctx.caster, ctx.caster, "miaoluo-ultimate-focus");
|
|
207
193
|
hits.push(buildBuffHit(ctx, ctx.caster, "miaoluo-ultimate-focus"));
|
|
208
194
|
for (let i = 0; i < 3; i += 1) {
|
|
209
|
-
const
|
|
210
|
-
totalDamage += damage;
|
|
211
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
195
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.6));
|
|
196
|
+
totalDamage += r.damage;
|
|
197
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
212
198
|
}
|
|
213
199
|
if (ctx.api.hasBuff(target.id, "imbalance-vulnerability")) {
|
|
214
|
-
const
|
|
215
|
-
totalDamage += damage;
|
|
216
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
200
|
+
const r2 = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.3));
|
|
201
|
+
totalDamage += r2.damage;
|
|
202
|
+
hits.push(buildDamageHit(ctx, target.id, r2.damage, r2.imbalanceDelta));
|
|
217
203
|
}
|
|
218
204
|
}
|
|
219
205
|
return {
|
|
@@ -238,9 +224,9 @@ const miaoluoBasicScript = {
|
|
|
238
224
|
let totalDamage = 0;
|
|
239
225
|
const hits = [];
|
|
240
226
|
if (self && target) {
|
|
241
|
-
const
|
|
242
|
-
totalDamage += damage;
|
|
243
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
227
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.5));
|
|
228
|
+
totalDamage += r.damage;
|
|
229
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
244
230
|
}
|
|
245
231
|
return {
|
|
246
232
|
...buildEmptyResult(ctx, target ? [target.id] : []),
|
|
@@ -264,9 +250,9 @@ const miaoluoCoreScript = {
|
|
|
264
250
|
let totalDamage = 0;
|
|
265
251
|
const hits = [];
|
|
266
252
|
if (self && target) {
|
|
267
|
-
const
|
|
268
|
-
totalDamage += damage;
|
|
269
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
253
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.8));
|
|
254
|
+
totalDamage += r.damage;
|
|
255
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
270
256
|
ctx.api.addBuff(ctx.caster, target.id, "static");
|
|
271
257
|
hits.push(buildBuffHit(ctx, target.id, "static"));
|
|
272
258
|
ctx.api.addBuff(ctx.caster, ctx.caster, "flash");
|
|
@@ -288,13 +274,13 @@ const cookBasicScript = {
|
|
|
288
274
|
if (self) {
|
|
289
275
|
const selfCost = Math.floor(self.runtime.Hp * 0.1);
|
|
290
276
|
if (selfCost > 0) {
|
|
291
|
-
const
|
|
292
|
-
totalDamage += damage;
|
|
293
|
-
hits.push(buildDamageHit(ctx, ctx.caster, damage));
|
|
277
|
+
const r1 = ctx.api.damage(ctx.caster, ctx.caster, selfCost);
|
|
278
|
+
totalDamage += r1.damage;
|
|
279
|
+
hits.push(buildDamageHit(ctx, ctx.caster, r1.damage, r1.imbalanceDelta));
|
|
294
280
|
if (targetId) {
|
|
295
|
-
const
|
|
296
|
-
totalDamage +=
|
|
297
|
-
hits.push(buildDamageHit(ctx, targetId,
|
|
281
|
+
const r2 = ctx.api.damage(ctx.caster, targetId, Math.floor(selfCost * 0.5));
|
|
282
|
+
totalDamage += r2.damage;
|
|
283
|
+
hits.push(buildDamageHit(ctx, targetId, r2.damage, r2.imbalanceDelta));
|
|
298
284
|
}
|
|
299
285
|
}
|
|
300
286
|
}
|
|
@@ -324,9 +310,9 @@ const cookCoreScript = {
|
|
|
324
310
|
const lostHp = Math.max(0, self.stats.Mhp - self.runtime.Hp);
|
|
325
311
|
const lostStepCount = Math.floor((lostHp * 10) / Math.max(1, self.stats.Mhp));
|
|
326
312
|
const multiplier = 1 + lostStepCount * 0.05;
|
|
327
|
-
const
|
|
328
|
-
totalDamage += damage;
|
|
329
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
313
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * multiplier));
|
|
314
|
+
totalDamage += r.damage;
|
|
315
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
330
316
|
}
|
|
331
317
|
return {
|
|
332
318
|
...buildEmptyResult(ctx, target ? [target.id] : []),
|
|
@@ -372,9 +358,9 @@ const kesiCoreScript = {
|
|
|
372
358
|
const index = ctx.api.randomInt(pool.length);
|
|
373
359
|
const [target] = pool.splice(index, 1);
|
|
374
360
|
hitTargets.push(target.id);
|
|
375
|
-
const
|
|
376
|
-
totalDamage += damage;
|
|
377
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
361
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.5));
|
|
362
|
+
totalDamage += r.damage;
|
|
363
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
378
364
|
if (target.teamId === self.teamId) {
|
|
379
365
|
ctx.api.gainEnergy(ctx.caster, 10);
|
|
380
366
|
}
|
|
@@ -404,9 +390,9 @@ const kesiUltimateScript = {
|
|
|
404
390
|
const target = enemies[ctx.api.randomInt(enemies.length)];
|
|
405
391
|
hitTargets.push(target.id);
|
|
406
392
|
attacked.add(target.id);
|
|
407
|
-
const
|
|
408
|
-
totalDamage += damage;
|
|
409
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
393
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.8));
|
|
394
|
+
totalDamage += r.damage;
|
|
395
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
410
396
|
}
|
|
411
397
|
for (const targetId of attacked) {
|
|
412
398
|
const target = ctx.api.getUnit(targetId);
|
|
@@ -418,9 +404,9 @@ const kesiUltimateScript = {
|
|
|
418
404
|
.filter((buff) => buff.stacks > 0 && buff.config.dotRatio)
|
|
419
405
|
.reduce((sum, buff) => sum + Math.floor(target.stats.Att * (buff.config.dotRatio ?? 0) * buff.stacks), 0);
|
|
420
406
|
if (dotValue > 0) {
|
|
421
|
-
const
|
|
422
|
-
totalDamage += damage;
|
|
423
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
407
|
+
const r2 = ctx.api.damage(ctx.caster, targetId, Math.floor(dotValue * 0.6));
|
|
408
|
+
totalDamage += r2.damage;
|
|
409
|
+
hits.push(buildDamageHit(ctx, target.id, r2.damage, r2.imbalanceDelta));
|
|
424
410
|
}
|
|
425
411
|
}
|
|
426
412
|
return {
|
|
@@ -636,11 +622,11 @@ const luolaiBasicScript = {
|
|
|
636
622
|
let totalDamage = 0;
|
|
637
623
|
let totalHeal = 0;
|
|
638
624
|
const hits = [];
|
|
639
|
-
const
|
|
640
|
-
totalDamage += damage;
|
|
641
|
-
hits.push(buildDamageHit(ctx, target.id, damage));
|
|
625
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.5));
|
|
626
|
+
totalDamage += r.damage;
|
|
627
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
642
628
|
if (frontAlly) {
|
|
643
|
-
const heal = ctx.api.heal(frontAlly.id, Math.floor(damage * 0.5));
|
|
629
|
+
const heal = ctx.api.heal(frontAlly.id, Math.floor(r.damage * 0.5));
|
|
644
630
|
totalHeal += heal;
|
|
645
631
|
hits.push(buildHealHit(ctx, frontAlly.id, heal));
|
|
646
632
|
}
|
|
@@ -938,9 +924,9 @@ const esCoreScript = {
|
|
|
938
924
|
let totalDamage = 0;
|
|
939
925
|
const hits = [];
|
|
940
926
|
for (const enemy of enemies) {
|
|
941
|
-
const
|
|
942
|
-
totalDamage += damage;
|
|
943
|
-
hits.push(buildDamageHit(ctx, enemy.id, damage));
|
|
927
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, Math.floor(self.stats.Att * 0.35));
|
|
928
|
+
totalDamage += r.damage;
|
|
929
|
+
hits.push(buildDamageHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
944
930
|
const resisted = ctx.api.randomInt(10000) >= 5000;
|
|
945
931
|
if (!resisted) {
|
|
946
932
|
ctx.api.addBuff(ctx.caster, enemy.id, "dazzle");
|
|
@@ -9,17 +9,19 @@ function buildEmptyResult(ctx, targets = ctx.targets) {
|
|
|
9
9
|
triggeredBy: ctx.trigger
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
function buildDamageHit(ctx, targetId, finalValue) {
|
|
12
|
+
function buildDamageHit(ctx, targetId, finalValue, imbalanceDelta, triggeredImbalanceBreak) {
|
|
13
13
|
return {
|
|
14
14
|
targetId,
|
|
15
15
|
effectType: "damage",
|
|
16
16
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
17
|
-
skillType:
|
|
17
|
+
skillType: ctx.skillType,
|
|
18
18
|
isCritical: false,
|
|
19
19
|
baseValue: finalValue,
|
|
20
20
|
criticalValue: finalValue,
|
|
21
21
|
finalValue,
|
|
22
22
|
isRepression: 0,
|
|
23
|
+
imbalanceDelta,
|
|
24
|
+
triggeredImbalanceBreak,
|
|
23
25
|
damageBreakdown: { preMitigation: finalValue, postMitigation: finalValue, shieldAbsorbed: 0, hpDamage: finalValue }
|
|
24
26
|
};
|
|
25
27
|
}
|
|
@@ -28,7 +30,7 @@ function buildBuffHit(ctx, targetId, buffId, resisted = false) {
|
|
|
28
30
|
targetId,
|
|
29
31
|
effectType: "buff",
|
|
30
32
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
31
|
-
skillType:
|
|
33
|
+
skillType: ctx.skillType,
|
|
32
34
|
isCritical: false,
|
|
33
35
|
baseValue: 0,
|
|
34
36
|
criticalValue: 0,
|
|
@@ -43,7 +45,7 @@ function buildHealHit(ctx, targetId, finalValue) {
|
|
|
43
45
|
targetId,
|
|
44
46
|
effectType: "heal",
|
|
45
47
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
46
|
-
skillType:
|
|
48
|
+
skillType: ctx.skillType,
|
|
47
49
|
isCritical: false,
|
|
48
50
|
baseValue: finalValue,
|
|
49
51
|
criticalValue: finalValue,
|
|
@@ -56,7 +58,7 @@ function buildShieldHit(ctx, targetId, finalValue) {
|
|
|
56
58
|
targetId,
|
|
57
59
|
effectType: "shield",
|
|
58
60
|
element: ctx.api.getUnit(ctx.caster)?.element ?? "fire",
|
|
59
|
-
skillType:
|
|
61
|
+
skillType: ctx.skillType,
|
|
60
62
|
isCritical: false,
|
|
61
63
|
baseValue: finalValue,
|
|
62
64
|
criticalValue: finalValue,
|
|
@@ -207,9 +209,9 @@ const m16122Script = {
|
|
|
207
209
|
const target = pool.splice(idx, 1)[0];
|
|
208
210
|
hitTargets.push(target.id);
|
|
209
211
|
const ratio = (ctx.levelParams.ratio ?? 6000) / 10000;
|
|
210
|
-
const
|
|
211
|
-
totalDamage +=
|
|
212
|
-
hits.push(buildDamageHit(ctx, target.id,
|
|
212
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * ratio));
|
|
213
|
+
totalDamage += r.damage;
|
|
214
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
213
215
|
if (ctx.api.randomInt(10000) < 5000) {
|
|
214
216
|
ctx.api.addBuff(ctx.caster, target.id, "dazzle");
|
|
215
217
|
hits.push(buildBuffHit(ctx, target.id, "dazzle"));
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
function buildEmptyResult(ctx, targets = ctx.targets) {
|
|
2
2
|
return { skillId: ctx.skillId, casterId: ctx.caster, targets, totalDamage: 0, totalHeal: 0, totalShield: 0, triggeredBy: ctx.trigger };
|
|
3
3
|
}
|
|
4
|
-
function buildDamageHit(ctx, targetId, v) {
|
|
5
|
-
return { targetId, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
4
|
+
function buildDamageHit(ctx, targetId, v, imbalanceDelta, triggeredImbalanceBreak) {
|
|
5
|
+
return { targetId, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0, imbalanceDelta, triggeredImbalanceBreak, damageBreakdown: { preMitigation: v, postMitigation: v, shieldAbsorbed: 0, hpDamage: v } };
|
|
6
6
|
}
|
|
7
7
|
function buildBuffHit(ctx, targetId, buffId, resisted = false) {
|
|
8
|
-
return { targetId, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
8
|
+
return { targetId, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: 0, criticalValue: 0, finalValue: 0, isRepression: 0, appliedBuffId: resisted ? undefined : buffId, resisted };
|
|
9
9
|
}
|
|
10
10
|
function buildHealHit(ctx, targetId, v) {
|
|
11
|
-
return { targetId, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
11
|
+
return { targetId, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0 };
|
|
12
12
|
}
|
|
13
13
|
// ============================================================
|
|
14
14
|
// 18011 光波比比 普攻:对距离最近的一名敌人造成50%光属性伤害,使自身获得3层【光能】
|
|
@@ -56,9 +56,9 @@ const m18013Script = {
|
|
|
56
56
|
if (!enemy.runtime.alive)
|
|
57
57
|
continue;
|
|
58
58
|
const perHitRatio = (ctx.levelParams.ratio ?? 2000) / 10000;
|
|
59
|
-
const
|
|
60
|
-
totalDamage +=
|
|
61
|
-
hits.push(buildDamageHit(ctx, enemy.id,
|
|
59
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, Math.floor(self.stats.Att * perHitRatio));
|
|
60
|
+
totalDamage += r.damage;
|
|
61
|
+
hits.push(buildDamageHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
62
62
|
if (!hitTargets.includes(enemy.id))
|
|
63
63
|
hitTargets.push(enemy.id);
|
|
64
64
|
}
|
|
@@ -87,9 +87,9 @@ const m18022Script = {
|
|
|
87
87
|
const hits = [];
|
|
88
88
|
for (const t of targets) {
|
|
89
89
|
const ratio18022 = (ctx.levelParams.ratio ?? 4000) / 10000;
|
|
90
|
-
const
|
|
91
|
-
totalDamage +=
|
|
92
|
-
hits.push(buildDamageHit(ctx, t.id,
|
|
90
|
+
const r = ctx.api.damage(ctx.caster, t.id, Math.floor(self.stats.Att * ratio18022));
|
|
91
|
+
totalDamage += r.damage;
|
|
92
|
+
hits.push(buildDamageHit(ctx, t.id, r.damage, r.imbalanceDelta));
|
|
93
93
|
ctx.api.addBuff(ctx.caster, t.id, "erosion");
|
|
94
94
|
hits.push(buildBuffHit(ctx, t.id, "erosion"));
|
|
95
95
|
}
|
|
@@ -120,9 +120,9 @@ const m18023Script = {
|
|
|
120
120
|
// 若有侵蚀则额外伤害
|
|
121
121
|
if (ctx.api.hasBuff(target.id, "erosion")) {
|
|
122
122
|
const extraRatio = (ctx.levelParams.extraRatio ?? 15000) / 10000;
|
|
123
|
-
const
|
|
124
|
-
totalDamage +=
|
|
125
|
-
hits.push(buildDamageHit(ctx, target.id,
|
|
123
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * extraRatio));
|
|
124
|
+
totalDamage += r.damage;
|
|
125
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
126
126
|
}
|
|
127
127
|
return { ...buildEmptyResult(ctx, [target.id]), totalDamage, hits };
|
|
128
128
|
}
|
|
@@ -141,11 +141,11 @@ const m18033Script = {
|
|
|
141
141
|
const target = enemies[0];
|
|
142
142
|
const hits = [];
|
|
143
143
|
const ratio18033 = (ctx.levelParams.ratio ?? 3000) / 10000;
|
|
144
|
-
const
|
|
145
|
-
hits.push(buildDamageHit(ctx, target.id,
|
|
144
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * ratio18033));
|
|
145
|
+
hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
146
146
|
ctx.api.addBuff(ctx.caster, target.id, "stun");
|
|
147
147
|
hits.push(buildBuffHit(ctx, target.id, "stun"));
|
|
148
|
-
return { ...buildEmptyResult(ctx, [target.id]), totalDamage:
|
|
148
|
+
return { ...buildEmptyResult(ctx, [target.id]), totalDamage: r.damage, hits };
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
// ============================================================
|
|
@@ -159,13 +159,13 @@ const m18041Script = {
|
|
|
159
159
|
return buildEmptyResult(ctx);
|
|
160
160
|
const hits = [];
|
|
161
161
|
let totalDamage = 0;
|
|
162
|
-
const
|
|
163
|
-
totalDamage +=
|
|
164
|
-
hits.push(buildDamageHit(ctx, targetId,
|
|
162
|
+
const r1 = ctx.api.damage(ctx.caster, targetId, Math.floor(self.stats.Att * 0.5));
|
|
163
|
+
totalDamage += r1.damage;
|
|
164
|
+
hits.push(buildDamageHit(ctx, targetId, r1.damage, r1.imbalanceDelta));
|
|
165
165
|
if (ctx.api.hasBuff(targetId, "slow")) {
|
|
166
|
-
const
|
|
167
|
-
totalDamage +=
|
|
168
|
-
hits.push(buildDamageHit(ctx, targetId,
|
|
166
|
+
const r2 = ctx.api.damage(ctx.caster, targetId, Math.floor(self.stats.Att * 0.5));
|
|
167
|
+
totalDamage += r2.damage;
|
|
168
|
+
hits.push(buildDamageHit(ctx, targetId, r2.damage, r2.imbalanceDelta));
|
|
169
169
|
}
|
|
170
170
|
return { ...buildEmptyResult(ctx, [targetId]), totalDamage, hits };
|
|
171
171
|
}
|
|
@@ -205,9 +205,9 @@ const m18043Script = {
|
|
|
205
205
|
let totalDamage = 0;
|
|
206
206
|
const hits = [];
|
|
207
207
|
for (const enemy of enemies) {
|
|
208
|
-
const
|
|
209
|
-
totalDamage +=
|
|
210
|
-
hits.push(buildDamageHit(ctx, enemy.id,
|
|
208
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, Math.floor(self.stats.Att * 0.5));
|
|
209
|
+
totalDamage += r.damage;
|
|
210
|
+
hits.push(buildDamageHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
211
211
|
ctx.api.addBuff(ctx.caster, enemy.id, "slow");
|
|
212
212
|
hits.push(buildBuffHit(ctx, enemy.id, "slow"));
|
|
213
213
|
}
|
|
@@ -253,13 +253,13 @@ const m18062Script = {
|
|
|
253
253
|
const target = enemies[0];
|
|
254
254
|
let totalDamage = 0;
|
|
255
255
|
const hits = [];
|
|
256
|
-
const
|
|
257
|
-
totalDamage +=
|
|
258
|
-
hits.push(buildDamageHit(ctx, target.id,
|
|
256
|
+
const r1 = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 1.3));
|
|
257
|
+
totalDamage += r1.damage;
|
|
258
|
+
hits.push(buildDamageHit(ctx, target.id, r1.damage, r1.imbalanceDelta));
|
|
259
259
|
if (ctx.api.hasBuff(target.id, "static")) {
|
|
260
|
-
const
|
|
261
|
-
totalDamage +=
|
|
262
|
-
hits.push(buildDamageHit(ctx, target.id,
|
|
260
|
+
const r2 = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.5));
|
|
261
|
+
totalDamage += r2.damage;
|
|
262
|
+
hits.push(buildDamageHit(ctx, target.id, r2.damage, r2.imbalanceDelta));
|
|
263
263
|
}
|
|
264
264
|
return { ...buildEmptyResult(ctx, [target.id]), totalDamage, hits };
|
|
265
265
|
}
|
|
@@ -304,9 +304,9 @@ const m18072Script = {
|
|
|
304
304
|
// 引爆:立即结算1次风化DOT伤害
|
|
305
305
|
const dotDmg = Math.floor(enemy.stats.Att * 0.18 * stacks);
|
|
306
306
|
if (dotDmg > 0) {
|
|
307
|
-
const
|
|
308
|
-
totalDamage +=
|
|
309
|
-
hits.push(buildDamageHit(ctx, enemy.id,
|
|
307
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, dotDmg);
|
|
308
|
+
totalDamage += r.damage;
|
|
309
|
+
hits.push(buildDamageHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
function empty(ctx, targets = ctx.targets) {
|
|
2
2
|
return { skillId: ctx.skillId, casterId: ctx.caster, targets, totalDamage: 0, totalHeal: 0, totalShield: 0, triggeredBy: ctx.trigger };
|
|
3
3
|
}
|
|
4
|
-
function dmgHit(ctx, tid, v) {
|
|
5
|
-
return { targetId: tid, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
4
|
+
function dmgHit(ctx, tid, v, ib, tib) {
|
|
5
|
+
return { targetId: tid, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0, imbalanceDelta: ib, triggeredImbalanceBreak: tib, damageBreakdown: { preMitigation: v, postMitigation: v, shieldAbsorbed: 0, hpDamage: v } };
|
|
6
6
|
}
|
|
7
7
|
function buffHit(ctx, tid, bid, r = false) {
|
|
8
|
-
return { targetId: tid, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
8
|
+
return { targetId: tid, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: 0, criticalValue: 0, finalValue: 0, isRepression: 0, appliedBuffId: r ? undefined : bid, resisted: r };
|
|
9
9
|
}
|
|
10
10
|
function healHit(ctx, tid, v) {
|
|
11
|
-
return { targetId: tid, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
11
|
+
return { targetId: tid, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0 };
|
|
12
12
|
}
|
|
13
13
|
function shieldHit(ctx, tid, v) {
|
|
14
|
-
return { targetId: tid, effectType: "shield", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
14
|
+
return { targetId: tid, effectType: "shield", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0 };
|
|
15
15
|
}
|
|
16
16
|
// 19011 骨墩墩 普攻:80%火属性伤害+赋予自身【反击】(反击触发的普攻不赋予反击)
|
|
17
17
|
const m19011Script = {
|
|
@@ -23,13 +23,13 @@ const m19011Script = {
|
|
|
23
23
|
if (!tid)
|
|
24
24
|
return empty(ctx);
|
|
25
25
|
const hits = [];
|
|
26
|
-
const
|
|
27
|
-
hits.push(dmgHit(ctx, tid,
|
|
26
|
+
const r = ctx.api.damage(ctx.caster, tid, Math.floor(self.stats.Att * 0.8));
|
|
27
|
+
hits.push(dmgHit(ctx, tid, r.damage, r.imbalanceDelta));
|
|
28
28
|
if (ctx.trigger !== "counter") {
|
|
29
29
|
ctx.api.addBuff(ctx.caster, ctx.caster, "monster-counter-boss");
|
|
30
30
|
hits.push(buffHit(ctx, ctx.caster, "monster-counter-boss"));
|
|
31
31
|
}
|
|
32
|
-
return { ...empty(ctx, [tid]), totalDamage:
|
|
32
|
+
return { ...empty(ctx, [tid]), totalDamage: r.damage, hits };
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
// 19012 骨墩墩 技能1:召唤2只骨骨
|
|
@@ -144,9 +144,9 @@ const m19023Script = {
|
|
|
144
144
|
let totalDamage = 0;
|
|
145
145
|
const hits = [];
|
|
146
146
|
for (const enemy of enemies) {
|
|
147
|
-
const
|
|
148
|
-
totalDamage +=
|
|
149
|
-
hits.push(dmgHit(ctx, enemy.id,
|
|
147
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, Math.floor(self.stats.Att * (1.5 + bonusRatio)));
|
|
148
|
+
totalDamage += r.damage;
|
|
149
|
+
hits.push(dmgHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
150
150
|
if (ctx.api.hasBuff(enemy.id, "slow")) {
|
|
151
151
|
ctx.api.adjustActionProgress(enemy.id, -0.3);
|
|
152
152
|
}
|
|
@@ -199,9 +199,9 @@ const m19033Script = {
|
|
|
199
199
|
const target = enemies[0];
|
|
200
200
|
const hits = [];
|
|
201
201
|
let totalDamage = 0;
|
|
202
|
-
const
|
|
203
|
-
totalDamage +=
|
|
204
|
-
hits.push(dmgHit(ctx, target.id,
|
|
202
|
+
const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 2.2));
|
|
203
|
+
totalDamage += r.damage;
|
|
204
|
+
hits.push(dmgHit(ctx, target.id, r.damage, r.imbalanceDelta));
|
|
205
205
|
// 检查5层静电 -> 直接死亡
|
|
206
206
|
const staticBuffs = ctx.api.getBuffs(target.id).filter(b => b.id === "static");
|
|
207
207
|
const staticStacks = staticBuffs.reduce((s, b) => s + b.stacks, 0);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
function empty(ctx, targets = ctx.targets) {
|
|
2
2
|
return { skillId: ctx.skillId, casterId: ctx.caster, targets, totalDamage: 0, totalHeal: 0, totalShield: 0, triggeredBy: ctx.trigger };
|
|
3
3
|
}
|
|
4
|
-
function dmgHit(ctx, tid, v) {
|
|
5
|
-
return { targetId: tid, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
4
|
+
function dmgHit(ctx, tid, v, ib, tib) {
|
|
5
|
+
return { targetId: tid, effectType: "damage", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0, imbalanceDelta: ib, triggeredImbalanceBreak: tib, damageBreakdown: { preMitigation: v, postMitigation: v, shieldAbsorbed: 0, hpDamage: v } };
|
|
6
6
|
}
|
|
7
7
|
function buffHit(ctx, tid, bid, r = false) {
|
|
8
|
-
return { targetId: tid, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
8
|
+
return { targetId: tid, effectType: "buff", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: 0, criticalValue: 0, finalValue: 0, isRepression: 0, appliedBuffId: r ? undefined : bid, resisted: r };
|
|
9
9
|
}
|
|
10
10
|
function healHit(ctx, tid, v) {
|
|
11
|
-
return { targetId: tid, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
11
|
+
return { targetId: tid, effectType: "heal", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0 };
|
|
12
12
|
}
|
|
13
13
|
function shieldHit(ctx, tid, v) {
|
|
14
|
-
return { targetId: tid, effectType: "shield", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType:
|
|
14
|
+
return { targetId: tid, effectType: "shield", element: ctx.api.getUnit(ctx.caster)?.element ?? "fire", skillType: ctx.skillType, isCritical: false, baseValue: v, criticalValue: v, finalValue: v, isRepression: 0 };
|
|
15
15
|
}
|
|
16
16
|
// 19042 大风 技能1:对全体敌人造成50%风属性伤害,并消除敌人20%行动值持续2回合
|
|
17
17
|
// (伤害由模板处理,这里处理行动值削减)
|
|
@@ -245,13 +245,13 @@ const m19071Script = {
|
|
|
245
245
|
return empty(ctx);
|
|
246
246
|
const hits = [];
|
|
247
247
|
let totalDamage = 0;
|
|
248
|
-
const
|
|
249
|
-
totalDamage +=
|
|
250
|
-
hits.push(dmgHit(ctx, tid,
|
|
248
|
+
const r1 = ctx.api.damage(ctx.caster, tid, Math.floor(self.stats.Att * 0.8));
|
|
249
|
+
totalDamage += r1.damage;
|
|
250
|
+
hits.push(dmgHit(ctx, tid, r1.damage, r1.imbalanceDelta));
|
|
251
251
|
// 附加防御力50%额外伤害
|
|
252
|
-
const
|
|
253
|
-
totalDamage +=
|
|
254
|
-
hits.push(dmgHit(ctx, tid,
|
|
252
|
+
const r2 = ctx.api.damage(ctx.caster, tid, Math.floor(self.stats.Def * 0.5));
|
|
253
|
+
totalDamage += r2.damage;
|
|
254
|
+
hits.push(dmgHit(ctx, tid, r2.damage, r2.imbalanceDelta));
|
|
255
255
|
return { ...empty(ctx, [tid]), totalDamage, hits };
|
|
256
256
|
}
|
|
257
257
|
};
|
|
@@ -287,9 +287,9 @@ const m19073Script = {
|
|
|
287
287
|
const enemies = ctx.api.getAliveUnits().filter(u => u.teamId !== self.teamId);
|
|
288
288
|
for (const enemy of enemies) {
|
|
289
289
|
// 额外200%伤害(模板已有150%,这里补充额外的300%总计)
|
|
290
|
-
const
|
|
291
|
-
totalDamage +=
|
|
292
|
-
hits.push(dmgHit(ctx, enemy.id,
|
|
290
|
+
const r = ctx.api.damage(ctx.caster, enemy.id, Math.floor(self.stats.Att * 3.0));
|
|
291
|
+
totalDamage += r.damage;
|
|
292
|
+
hits.push(dmgHit(ctx, enemy.id, r.damage, r.imbalanceDelta));
|
|
293
293
|
ctx.api.addBuff(ctx.caster, enemy.id, "stun");
|
|
294
294
|
hits.push(buffHit(ctx, enemy.id, "stun"));
|
|
295
295
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ISkillScript } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* 导出所有示例脚本
|
|
4
|
+
*/
|
|
5
|
+
export declare const sampleUpgradeScripts: Record<string, ISkillScript>;
|
|
6
|
+
/**
|
|
7
|
+
* 使用示例:
|
|
8
|
+
*
|
|
9
|
+
* // 在初始化战斗单位时,配置技能等级和参数
|
|
10
|
+
* const skill: SkillDefinition = {
|
|
11
|
+
* id: "hero.skill.1",
|
|
12
|
+
* mode: "script",
|
|
13
|
+
* type: "core",
|
|
14
|
+
* scriptId: "sample.upgradable.damage",
|
|
15
|
+
* energyCost: 30,
|
|
16
|
+
* energyGain: 0,
|
|
17
|
+
* cooldown: 2,
|
|
18
|
+
* targetRule: "nearest",
|
|
19
|
+
* element: "fire",
|
|
20
|
+
* level: 3 as const, // 技能等级 3
|
|
21
|
+
* levelParams: {
|
|
22
|
+
* baseRatio: 0.5, // 基础系数 50%
|
|
23
|
+
* ratioPerLevel: 0.08 // 每级+8%
|
|
24
|
+
* }
|
|
25
|
+
* };
|
|
26
|
+
*
|
|
27
|
+
* // 等级3的实际系数 = 0.5 + (3-1) * 0.08 = 0.66 = 66%
|
|
28
|
+
*/
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 示例:支持技能升级的手写技能脚本
|
|
3
|
+
*
|
|
4
|
+
* 升级方案:
|
|
5
|
+
* - 基础伤害系数随等级提升
|
|
6
|
+
* - levelParams 中可配置额外参数
|
|
7
|
+
*/
|
|
8
|
+
const upgradableDamageSkill = {
|
|
9
|
+
onCast(ctx) {
|
|
10
|
+
const { level, levelParams } = ctx;
|
|
11
|
+
const self = ctx.api.getUnit(ctx.caster);
|
|
12
|
+
if (!self || ctx.targets.length === 0) {
|
|
13
|
+
return {
|
|
14
|
+
skillId: ctx.skillId,
|
|
15
|
+
casterId: ctx.caster,
|
|
16
|
+
targets: [],
|
|
17
|
+
totalDamage: 0,
|
|
18
|
+
totalHeal: 0,
|
|
19
|
+
totalShield: 0,
|
|
20
|
+
triggeredBy: ctx.trigger
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// 基础系数 + 每级成长
|
|
24
|
+
const baseRatio = levelParams.baseRatio ?? 0.5;
|
|
25
|
+
const ratioPerLevel = levelParams.ratioPerLevel ?? 0.05;
|
|
26
|
+
const currentRatio = baseRatio + (level - 1) * ratioPerLevel;
|
|
27
|
+
// 计算伤害
|
|
28
|
+
const damage = Math.floor(self.stats.Att * currentRatio);
|
|
29
|
+
let totalDamage = 0;
|
|
30
|
+
for (const targetId of ctx.targets) {
|
|
31
|
+
const r = ctx.api.damage(ctx.caster, targetId, damage);
|
|
32
|
+
totalDamage += r.damage;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
skillId: ctx.skillId,
|
|
36
|
+
casterId: ctx.caster,
|
|
37
|
+
targets: ctx.targets,
|
|
38
|
+
totalDamage,
|
|
39
|
+
totalHeal: 0,
|
|
40
|
+
totalShield: 0,
|
|
41
|
+
triggeredBy: ctx.trigger
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* 示例:护盾技能,护盾值随等级提升
|
|
47
|
+
*/
|
|
48
|
+
const upgradableShieldSkill = {
|
|
49
|
+
onCast(ctx) {
|
|
50
|
+
const { level, levelParams } = ctx;
|
|
51
|
+
const self = ctx.api.getUnit(ctx.caster);
|
|
52
|
+
if (!self) {
|
|
53
|
+
return {
|
|
54
|
+
skillId: ctx.skillId,
|
|
55
|
+
casterId: ctx.caster,
|
|
56
|
+
targets: [],
|
|
57
|
+
totalDamage: 0,
|
|
58
|
+
totalHeal: 0,
|
|
59
|
+
totalShield: 0,
|
|
60
|
+
triggeredBy: ctx.trigger
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// 护盾基础值 + 等级加成
|
|
64
|
+
const baseShield = levelParams.baseShield ?? 100;
|
|
65
|
+
const shieldPerLevel = levelParams.shieldPerLevel ?? 20;
|
|
66
|
+
const shieldValue = baseShield + (level - 1) * shieldPerLevel;
|
|
67
|
+
// 可以基于防御力缩放
|
|
68
|
+
const defRatio = levelParams.defRatio ?? 0.3;
|
|
69
|
+
const finalShield = Math.floor(self.stats.Def * defRatio + shieldValue);
|
|
70
|
+
const totalShield = ctx.api.shield(ctx.caster, finalShield);
|
|
71
|
+
return {
|
|
72
|
+
skillId: ctx.skillId,
|
|
73
|
+
casterId: ctx.caster,
|
|
74
|
+
targets: [ctx.caster],
|
|
75
|
+
totalDamage: 0,
|
|
76
|
+
totalHeal: 0,
|
|
77
|
+
totalShield,
|
|
78
|
+
triggeredBy: ctx.trigger
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* 示例:治疗技能,治疗量随等级提升
|
|
84
|
+
*/
|
|
85
|
+
const upgradableHealSkill = {
|
|
86
|
+
onCast(ctx) {
|
|
87
|
+
const { level, levelParams } = ctx;
|
|
88
|
+
const self = ctx.api.getUnit(ctx.caster);
|
|
89
|
+
if (!self || ctx.targets.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
skillId: ctx.skillId,
|
|
92
|
+
casterId: ctx.caster,
|
|
93
|
+
targets: [],
|
|
94
|
+
totalDamage: 0,
|
|
95
|
+
totalHeal: 0,
|
|
96
|
+
totalShield: 0,
|
|
97
|
+
triggeredBy: ctx.trigger
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// 治疗基础值 + 等级加成
|
|
101
|
+
const baseHeal = levelParams.baseHeal ?? 50;
|
|
102
|
+
const healPerLevel = levelParams.healPerLevel ?? 10;
|
|
103
|
+
const healValue = baseHeal + (level - 1) * healPerLevel;
|
|
104
|
+
// 基于攻击力缩放
|
|
105
|
+
const attRatio = levelParams.attRatio ?? 0.2;
|
|
106
|
+
const finalHeal = Math.floor(self.stats.Att * attRatio + healValue);
|
|
107
|
+
let totalHeal = 0;
|
|
108
|
+
for (const targetId of ctx.targets) {
|
|
109
|
+
totalHeal += ctx.api.heal(targetId, finalHeal);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
skillId: ctx.skillId,
|
|
113
|
+
casterId: ctx.caster,
|
|
114
|
+
targets: ctx.targets,
|
|
115
|
+
totalDamage: 0,
|
|
116
|
+
totalHeal,
|
|
117
|
+
totalShield: 0,
|
|
118
|
+
triggeredBy: ctx.trigger
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* 示例:多段伤害技能,段数或伤害随等级提升
|
|
124
|
+
*/
|
|
125
|
+
const upgradableMultiHitSkill = {
|
|
126
|
+
onCast(ctx) {
|
|
127
|
+
const { level, levelParams } = ctx;
|
|
128
|
+
const self = ctx.api.getUnit(ctx.caster);
|
|
129
|
+
if (!self || ctx.targets.length === 0) {
|
|
130
|
+
return {
|
|
131
|
+
skillId: ctx.skillId,
|
|
132
|
+
casterId: ctx.caster,
|
|
133
|
+
targets: [],
|
|
134
|
+
totalDamage: 0,
|
|
135
|
+
totalHeal: 0,
|
|
136
|
+
totalShield: 0,
|
|
137
|
+
triggeredBy: ctx.trigger
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// 基础段数 + 等级解锁额外段数
|
|
141
|
+
const baseHits = levelParams.baseHits ?? 2;
|
|
142
|
+
const bonusHitsAtLevel = levelParams.bonusHitsAtLevel ?? 5;
|
|
143
|
+
const totalHits = level >= bonusHitsAtLevel ? baseHits + 1 : baseHits;
|
|
144
|
+
// 每段伤害系数
|
|
145
|
+
const hitRatio = levelParams.hitRatio ?? 0.3;
|
|
146
|
+
const hitDamage = Math.floor(self.stats.Att * hitRatio);
|
|
147
|
+
let totalDamage = 0;
|
|
148
|
+
const targetId = ctx.targets[0];
|
|
149
|
+
for (let i = 0; i < totalHits; i++) {
|
|
150
|
+
const r = ctx.api.damage(ctx.caster, targetId, hitDamage);
|
|
151
|
+
totalDamage += r.damage;
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
skillId: ctx.skillId,
|
|
155
|
+
casterId: ctx.caster,
|
|
156
|
+
targets: ctx.targets,
|
|
157
|
+
totalDamage,
|
|
158
|
+
totalHeal: 0,
|
|
159
|
+
totalShield: 0,
|
|
160
|
+
triggeredBy: ctx.trigger
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* 示例:Debuff 技能,概率随等级提升
|
|
166
|
+
*/
|
|
167
|
+
const upgradableDebuffSkill = {
|
|
168
|
+
onCast(ctx) {
|
|
169
|
+
const { level, levelParams } = ctx;
|
|
170
|
+
// 基础概率 + 等级加成
|
|
171
|
+
const baseProb = levelParams.baseProb ?? 0.5; // 50%
|
|
172
|
+
const probPerLevel = levelParams.probPerLevel ?? 0.05; // 每级+5%
|
|
173
|
+
const applyChance = Math.min(1, baseProb + (level - 1) * probPerLevel);
|
|
174
|
+
// levelParams 仅支持 number,Debuff 类型固定为 slow
|
|
175
|
+
const buffId = "slow";
|
|
176
|
+
for (const targetId of ctx.targets) {
|
|
177
|
+
// 假设概率判定通过
|
|
178
|
+
ctx.api.addBuff(ctx.caster, targetId, buffId);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
skillId: ctx.skillId,
|
|
182
|
+
casterId: ctx.caster,
|
|
183
|
+
targets: ctx.targets,
|
|
184
|
+
totalDamage: 0,
|
|
185
|
+
totalHeal: 0,
|
|
186
|
+
totalShield: 0,
|
|
187
|
+
triggeredBy: ctx.trigger
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* 导出所有示例脚本
|
|
193
|
+
*/
|
|
194
|
+
export const sampleUpgradeScripts = {
|
|
195
|
+
"sample.upgradable.damage": upgradableDamageSkill,
|
|
196
|
+
"sample.upgradable.shield": upgradableShieldSkill,
|
|
197
|
+
"sample.upgradable.heal": upgradableHealSkill,
|
|
198
|
+
"sample.upgradable.multihit": upgradableMultiHitSkill,
|
|
199
|
+
"sample.upgradable.debuff": upgradableDebuffSkill
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* 使用示例:
|
|
203
|
+
*
|
|
204
|
+
* // 在初始化战斗单位时,配置技能等级和参数
|
|
205
|
+
* const skill: SkillDefinition = {
|
|
206
|
+
* id: "hero.skill.1",
|
|
207
|
+
* mode: "script",
|
|
208
|
+
* type: "core",
|
|
209
|
+
* scriptId: "sample.upgradable.damage",
|
|
210
|
+
* energyCost: 30,
|
|
211
|
+
* energyGain: 0,
|
|
212
|
+
* cooldown: 2,
|
|
213
|
+
* targetRule: "nearest",
|
|
214
|
+
* element: "fire",
|
|
215
|
+
* level: 3 as const, // 技能等级 3
|
|
216
|
+
* levelParams: {
|
|
217
|
+
* baseRatio: 0.5, // 基础系数 50%
|
|
218
|
+
* ratioPerLevel: 0.08 // 每级+8%
|
|
219
|
+
* }
|
|
220
|
+
* };
|
|
221
|
+
*
|
|
222
|
+
* // 等级3的实际系数 = 0.5 + (3-1) * 0.08 = 0.66 = 66%
|
|
223
|
+
*/
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { BattleScriptApi, ElementType, ISkillScript, ScriptRuntimeContext, SkillDefinition, SkillResult, SkillTemplate, TriggerContext, UnitModel } from "./types";
|
|
2
2
|
import { SeedRng } from "./random";
|
|
3
|
+
interface ApplyDamageResult {
|
|
4
|
+
damage: number;
|
|
5
|
+
imbalanceDelta: number;
|
|
6
|
+
triggeredImbalanceBreak: boolean;
|
|
7
|
+
}
|
|
3
8
|
interface SkillEngineDeps {
|
|
4
9
|
rng: SeedRng;
|
|
5
10
|
getUnits: () => UnitModel[];
|
|
6
|
-
applyDamage: (sourceId: string, targetId: string, value: number, staggerElement?: ElementType) =>
|
|
11
|
+
applyDamage: (sourceId: string, targetId: string, value: number, staggerElement?: ElementType) => ApplyDamageResult;
|
|
7
12
|
applyHeal: (targetId: string, value: number) => number;
|
|
8
13
|
applyShield: (targetId: string, value: number) => number;
|
|
9
14
|
applyBuff: (sourceId: string, targetId: string, buffId: string) => void;
|
|
@@ -32,5 +37,6 @@ export declare class SkillExecutor {
|
|
|
32
37
|
private readonly scriptEngine;
|
|
33
38
|
constructor(configEngine: ConfigSkillEngine, scriptEngine: ScriptSkillEngine);
|
|
34
39
|
execute(skill: SkillDefinition, caster: UnitModel, deps: SkillEngineDeps, trigger: SkillResult["triggeredBy"], triggerCtx?: TriggerContext, selectedTargetsOverride?: UnitModel[]): SkillResult;
|
|
40
|
+
private linkBuffHitsToDamage;
|
|
35
41
|
}
|
|
36
42
|
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { calcDamage, calcEffectProbability, calcHealOrShield } from "./formula";
|
|
2
2
|
import { selectTargets } from "./targeting";
|
|
3
3
|
export class ScriptSkillEngine {
|
|
4
|
-
scripts = new Map();
|
|
4
|
+
scripts = new Map(); // 存储已注册的技能脚本
|
|
5
5
|
registerScript(scriptId, script) {
|
|
6
6
|
this.scripts.set(scriptId, script);
|
|
7
7
|
}
|
|
8
8
|
cast(scriptId, ctx) {
|
|
9
|
-
const script = this.scripts.get(scriptId);
|
|
10
|
-
if (!script) {
|
|
9
|
+
const script = this.scripts.get(scriptId); // 获取技能脚本
|
|
10
|
+
if (!script) { // 如果技能脚本不存在
|
|
11
11
|
return {
|
|
12
12
|
skillId: ctx.skillId,
|
|
13
13
|
casterId: ctx.caster,
|
|
@@ -103,7 +103,10 @@ export class ConfigSkillEngine {
|
|
|
103
103
|
if (step.kind === "damage") {
|
|
104
104
|
const shieldBefore = target.runtime.Shield;
|
|
105
105
|
const damageRes = calcDamage({ ...caster, stats: effectiveCaster }, { ...target, stats: effectiveTarget }, raw, skill.type, skill.element, deps.rng);
|
|
106
|
-
const
|
|
106
|
+
const applyResult = deps.applyDamage(caster.id, target.id, damageRes.finalDam, skill.element);
|
|
107
|
+
const done = applyResult.damage;
|
|
108
|
+
const imbalanceDelta = applyResult.imbalanceDelta;
|
|
109
|
+
const triggeredImbalanceBreak = applyResult.triggeredImbalanceBreak;
|
|
107
110
|
const shieldAbsorbed = Math.min(shieldBefore, damageRes.finalDam);
|
|
108
111
|
totalDamage += done;
|
|
109
112
|
hits.push({
|
|
@@ -116,6 +119,8 @@ export class ConfigSkillEngine {
|
|
|
116
119
|
criticalValue: damageRes.critDam,
|
|
117
120
|
finalValue: done,
|
|
118
121
|
isRepression: damageRes.isRepression,
|
|
122
|
+
imbalanceDelta,
|
|
123
|
+
triggeredImbalanceBreak: triggeredImbalanceBreak || undefined,
|
|
119
124
|
damageBreakdown: {
|
|
120
125
|
preMitigation: raw,
|
|
121
126
|
postMitigation: damageRes.finalDam,
|
|
@@ -219,6 +224,7 @@ export class SkillExecutor {
|
|
|
219
224
|
caster: caster.id,
|
|
220
225
|
targets: result.targets,
|
|
221
226
|
skillId: skill.id,
|
|
227
|
+
skillType: skill.type,
|
|
222
228
|
trigger,
|
|
223
229
|
triggerContext: triggerCtx,
|
|
224
230
|
api: deps.createScriptApi(skill.element),
|
|
@@ -241,6 +247,35 @@ export class SkillExecutor {
|
|
|
241
247
|
if (triggerCtx && result.targets.length === 0) {
|
|
242
248
|
result.targets = [...triggerCtx.sourceTargets];
|
|
243
249
|
}
|
|
250
|
+
if (result.hits && result.hits.length > 0) {
|
|
251
|
+
this.linkBuffHitsToDamage(result.hits);
|
|
252
|
+
}
|
|
244
253
|
return result;
|
|
245
254
|
}
|
|
255
|
+
linkBuffHitsToDamage(hits) {
|
|
256
|
+
const latestDamageIndexByTarget = new Map();
|
|
257
|
+
for (let i = 0; i < hits.length; i++) {
|
|
258
|
+
const hit = hits[i];
|
|
259
|
+
hit.hitIndex = i;
|
|
260
|
+
if (hit.effectType === "damage") {
|
|
261
|
+
hit.triggeredBuffHitIndices = undefined;
|
|
262
|
+
latestDamageIndexByTarget.set(hit.targetId, i);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (hit.effectType !== "buff") {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const sourceIndex = latestDamageIndexByTarget.get(hit.targetId);
|
|
269
|
+
if (sourceIndex !== undefined) {
|
|
270
|
+
hit.sourceDamageHitIndex = sourceIndex;
|
|
271
|
+
const sourceDamageHit = hits[sourceIndex];
|
|
272
|
+
if (sourceDamageHit.effectType === "damage") {
|
|
273
|
+
if (!sourceDamageHit.triggeredBuffHitIndices) {
|
|
274
|
+
sourceDamageHit.triggeredBuffHitIndices = [];
|
|
275
|
+
}
|
|
276
|
+
sourceDamageHit.triggeredBuffHitIndices.push(i);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
246
281
|
}
|
package/dist/battle/types.d.ts
CHANGED
|
@@ -142,6 +142,7 @@ export interface SkillTemplateStep {
|
|
|
142
142
|
fixedProbByLevel?: number[];
|
|
143
143
|
canCrit?: boolean;
|
|
144
144
|
scaleStat?: "Att" | "Def" | "Mhp";
|
|
145
|
+
scaleStatByLevel?: number[];
|
|
145
146
|
flat?: number;
|
|
146
147
|
flatByLevel?: number[];
|
|
147
148
|
repeat?: number;
|
|
@@ -162,6 +163,8 @@ export interface SkillResult {
|
|
|
162
163
|
hits?: SkillHitDetail[];
|
|
163
164
|
}
|
|
164
165
|
export interface SkillHitDetail {
|
|
166
|
+
/** 当前hit在SkillResult.hits中的索引位置 */
|
|
167
|
+
hitIndex?: number;
|
|
165
168
|
targetId: UnitId;
|
|
166
169
|
effectType: "damage" | "heal" | "shield" | "buff";
|
|
167
170
|
element: ElementType;
|
|
@@ -173,6 +176,19 @@ export interface SkillHitDetail {
|
|
|
173
176
|
isRepression: -1 | 0 | 1;
|
|
174
177
|
appliedBuffId?: string;
|
|
175
178
|
resisted?: boolean;
|
|
179
|
+
/** 本次hit造成的失衡值变化 */
|
|
180
|
+
imbalanceDelta?: number;
|
|
181
|
+
/** 本次hit是否触发了失衡破击 */
|
|
182
|
+
triggeredImbalanceBreak?: boolean;
|
|
183
|
+
/**
|
|
184
|
+
* 当effectType=buff时,若由同一次技能中的某个damage hit触发,
|
|
185
|
+
* 则记录该damage hit在SkillResult.hits中的索引
|
|
186
|
+
*/
|
|
187
|
+
sourceDamageHitIndex?: number;
|
|
188
|
+
/**
|
|
189
|
+
* 当effectType=damage时,记录由该damage触发的buff hit索引列表
|
|
190
|
+
*/
|
|
191
|
+
triggeredBuffHitIndices?: number[];
|
|
176
192
|
damageBreakdown?: {
|
|
177
193
|
preMitigation: number;
|
|
178
194
|
postMitigation: number;
|
|
@@ -260,6 +276,7 @@ export interface ScriptRuntimeContext {
|
|
|
260
276
|
caster: UnitId;
|
|
261
277
|
targets: UnitId[];
|
|
262
278
|
skillId: string;
|
|
279
|
+
skillType: SkillType;
|
|
263
280
|
trigger: SkillResult["triggeredBy"];
|
|
264
281
|
api: BattleScriptApi;
|
|
265
282
|
triggerContext?: TriggerContext;
|
|
@@ -268,8 +285,13 @@ export interface ScriptRuntimeContext {
|
|
|
268
285
|
/** 技能升级参数 */
|
|
269
286
|
levelParams: Record<string, number>;
|
|
270
287
|
}
|
|
288
|
+
export interface DamageResult {
|
|
289
|
+
damage: number;
|
|
290
|
+
imbalanceDelta: number;
|
|
291
|
+
triggeredImbalanceBreak: boolean;
|
|
292
|
+
}
|
|
271
293
|
export interface BattleScriptApi {
|
|
272
|
-
damage(sourceId: UnitId, targetId: UnitId, value: number):
|
|
294
|
+
damage(sourceId: UnitId, targetId: UnitId, value: number): DamageResult;
|
|
273
295
|
heal(targetId: UnitId, value: number): number;
|
|
274
296
|
shield(targetId: UnitId, value: number): number;
|
|
275
297
|
adjustImbalance(targetId: UnitId, delta: number): number;
|