hrbattle 1.0.4 → 1.0.6

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.
Files changed (46) hide show
  1. package/dist/battle/battleCore.js +2 -0
  2. package/dist/battle/config/json/designed-buffs.json +14 -11
  3. package/dist/battle/config/json/designed-hero-skill-books.json +5 -5
  4. package/dist/battle/config/json/designed-skill-templates.json +32 -30
  5. package/dist/battle/effectSystem.d.ts +1 -0
  6. package/dist/battle/effectSystem.js +18 -0
  7. package/dist/battle/script/designedScripts.js +36 -81
  8. package/dist/battle/script/monsterScripts19xxPart2.js +12 -5
  9. package/dist/battle/types.d.ts +3 -0
  10. package/dist/index.d.ts +1 -1
  11. package/package.json +4 -2
  12. package/src/battle/battleCore.ts +950 -0
  13. package/src/battle/config/json/designed-buffs.json +611 -0
  14. package/src/battle/config/json/designed-hero-skill-books.json +146 -0
  15. package/src/battle/config/json/designed-monster-skill-books.json +310 -0
  16. package/src/battle/config/json/designed-roster.json +438 -0
  17. package/src/battle/config/json/designed-skill-templates.json +87 -0
  18. package/src/battle/config/jsonConfigLoader.ts +139 -0
  19. package/src/battle/config/sampleData.ts +85 -0
  20. package/src/battle/effectSystem.ts +207 -0
  21. package/src/battle/eventBus.ts +34 -0
  22. package/src/battle/formula.ts +135 -0
  23. package/src/battle/logger.ts +93 -0
  24. package/src/battle/random.ts +19 -0
  25. package/src/battle/script/designedScripts.ts +994 -0
  26. package/src/battle/script/monsterScripts.ts +278 -0
  27. package/src/battle/script/monsterScripts18xx.ts +324 -0
  28. package/src/battle/script/monsterScripts19xx.ts +266 -0
  29. package/src/battle/script/monsterScripts19xxPart2.ts +400 -0
  30. package/src/battle/script/sampleScripts.ts +257 -0
  31. package/src/battle/skillEngine.ts +344 -0
  32. package/src/battle/targeting.ts +68 -0
  33. package/src/battle/turnbar.ts +47 -0
  34. package/src/battle/types.ts +375 -0
  35. package/src/cocos-adapter/BattleFacade.ts +27 -0
  36. package/src/cocos-adapter/ReusableBattleFacade.ts +78 -0
  37. package/src/cocos-adapter/clientBattleResult.ts +593 -0
  38. package/src/index.ts +45 -0
  39. package/tests/battle.spec.ts +786 -0
  40. package/tests/battleResultOutput.test.ts +124 -0
  41. package/tests/config.spec.ts +41 -0
  42. package/tests/json-loader.spec.ts +28 -0
  43. package/tests/reusable-battle-facade.spec.ts +41 -0
  44. package/tests/roster.spec.ts +35 -0
  45. package/tests/skill-level-upgrade.spec.ts +198 -0
  46. package/tests/targeting.spec.ts +101 -0
@@ -642,6 +642,8 @@ export class BattleCore {
642
642
  else if (rep === -1) {
643
643
  stagger = Math.floor(stagger * 7000 / 10000);
644
644
  }
645
+ const takenRate = 10000 + this.effectSystem.getImbalanceTakenRate(target.id);
646
+ stagger = Math.max(0, Math.floor(stagger * takenRate / 10000));
645
647
  const max = this.computeImbalanceMax(target);
646
648
  const from = target.runtime.Imbalance;
647
649
  target.runtime.Imbalance = Math.min(max, from + stagger);
@@ -39,6 +39,7 @@
39
39
  "durationPerStack": 1,
40
40
  "onRoundEndDelta": -1,
41
41
  "expireRounds": 1,
42
+ "speedRateDelta": -1000,
42
43
  "applyOnElementBreakElements": ["water"]
43
44
  },
44
45
  {
@@ -89,7 +90,7 @@
89
90
  "durationPerStack": 1,
90
91
  "onRoundEndDelta": -1,
91
92
  "expireRounds": 1,
92
- "defDelta": -1000,
93
+ "allElementResistDelta": -1000,
93
94
  "applyOnElementBreakElements": ["dark"]
94
95
  },
95
96
  {
@@ -99,7 +100,7 @@
99
100
  "durationPerStack": 1,
100
101
  "onRoundEndDelta": -1,
101
102
  "expireRounds": 1,
102
- "defDelta": -1000
103
+ "defenseRateDelta": -1000
103
104
  },
104
105
  {
105
106
  "id": "def-break",
@@ -112,11 +113,12 @@
112
113
  },
113
114
  {
114
115
  "id": "pierce",
115
- "name": "穿透",
116
+ "name": "穿孔",
116
117
  "maxStacks": 1,
117
118
  "durationPerStack": 2,
118
119
  "onRoundEndDelta": -1,
119
- "expireRounds": 2
120
+ "expireRounds": 2,
121
+ "imbalanceTakenRateDelta": 2000
120
122
  },
121
123
  {
122
124
  "id": "counter",
@@ -138,12 +140,12 @@
138
140
  },
139
141
  {
140
142
  "id": "flash",
141
- "name": "闪光",
143
+ "name": "闪击",
142
144
  "maxStacks": 3,
143
145
  "durationPerStack": 1,
144
146
  "onRoundEndDelta": -1,
145
147
  "expireRounds": 1,
146
- "imbalanceRateDelta": 800,
148
+ "assistRateDelta": 1500,
147
149
  "critRateDelta": 1500
148
150
  },
149
151
  {
@@ -157,11 +159,13 @@
157
159
  },
158
160
  {
159
161
  "id": "will",
160
- "name": "意志",
162
+ "name": "惩戒",
161
163
  "maxStacks": 999,
162
164
  "durationPerStack": 999999999,
163
165
  "onRoundEndDelta": 0,
164
- "expireRounds": 999999999
166
+ "expireRounds": 999999999,
167
+ "defenseRateDelta": 300,
168
+ "effectHitDelta": 300
165
169
  },
166
170
  {
167
171
  "id": "rage",
@@ -170,7 +174,7 @@
170
174
  "durationPerStack": 999999999,
171
175
  "onRoundEndDelta": 0,
172
176
  "expireRounds": 999999999,
173
- "speedDelta": 1000
177
+ "speedRateDelta": 1000
174
178
  },
175
179
  {
176
180
  "id": "cook-restraint",
@@ -282,7 +286,6 @@
282
286
  "durationPerStack": 9999999,
283
287
  "onRoundEndDelta": 0,
284
288
  "expireRounds": 9999999,
285
- "speedDelta": 1000,
286
289
  "speedRateDelta": 1000
287
290
  },
288
291
  {
@@ -382,7 +385,7 @@
382
385
  "durationPerStack": 2,
383
386
  "onRoundEndDelta": -1,
384
387
  "expireRounds": 2,
385
- "defDelta": 2000
388
+ "defenseRateDelta": 2000
386
389
  },
387
390
  {
388
391
  "id": "pela-crit-up",
@@ -6,7 +6,7 @@
6
6
  "role": "歼灭",
7
7
  "skills": [
8
8
  { "id": "11011", "type": "basic", "mode": "hybrid", "energyCost": 0, "energyGain": 20, "cooldown": 0, "targetRule": "nearest", "element": "rock", "configTemplateId": "common.basic.single.50", "scriptId": "cook.basic.script", "level": 1 },
9
- { "id": "11012", "type": "core", "mode": "script", "energyCost": 0, "energyGain": 30, "cooldown": 2, "targetRule": "nearest", "element": "rock", "scriptId": "cook.core.script", "level": 1 },
9
+ { "id": "11012", "type": "core", "mode": "hybrid", "energyCost": 0, "energyGain": 30, "cooldown": 2, "targetRule": "nearest", "element": "rock", "configTemplateId": "cook.core.single", "scriptId": "cook.core.script", "level": 1 },
10
10
  { "id": "11014", "type": "ultimate", "mode": "hybrid", "energyCost": 70, "energyGain": 0, "cooldown": 4, "targetRule": "nearest", "element": "rock", "configTemplateId": "cook.ultimate.slash", "scriptId": "cook.ultimate.script", "level": 1 },
11
11
  { "id": "11013", "type": "passive", "mode": "script", "energyCost": 0, "energyGain": 0, "cooldown": 0, "targetRule": "self", "element": "rock", "scriptId": "cook.passive.script", "level": 1, "activateOnBattleStart": true }
12
12
  ]
@@ -17,9 +17,9 @@
17
17
  "element": "thunder",
18
18
  "role": "歼灭",
19
19
  "skills": [
20
- { "id": "11021", "type": "basic", "mode": "script", "energyCost": 0, "energyGain": 20, "cooldown": 0, "targetRule": "lowestHpEnemy", "element": "thunder", "scriptId": "miaoluo.basic.script", "level": 1 },
21
- { "id": "11022", "type": "core", "mode": "script", "energyCost": 0, "energyGain": 30, "cooldown": 2, "targetRule": "lowestHpEnemy", "element": "thunder", "scriptId": "miaoluo.core.script", "level": 1 },
22
- { "id": "11024", "type": "ultimate", "mode": "script", "energyCost": 60, "energyGain": 0, "cooldown": 4, "targetRule": "lowestHpEnemy", "element": "thunder", "scriptId": "miaoluo.ultimate.script", "level": 1 },
20
+ { "id": "11021", "type": "basic", "mode": "config", "energyCost": 0, "energyGain": 20, "cooldown": 0, "targetRule": "lowestHpEnemy", "element": "thunder", "configTemplateId": "miaoluo.basic.flash", "level": 1 },
21
+ { "id": "11022", "type": "core", "mode": "hybrid", "energyCost": 0, "energyGain": 30, "cooldown": 2, "targetRule": "lowestHpEnemy", "element": "thunder", "configTemplateId": "miaoluo.core.lowhp", "scriptId": "miaoluo.core.script", "level": 1 },
22
+ { "id": "11024", "type": "ultimate", "mode": "hybrid", "energyCost": 60, "energyGain": 0, "cooldown": 4, "targetRule": "lowestHpEnemy", "element": "thunder", "configTemplateId": "miaoluo.ultimate.triple", "scriptId": "miaoluo.ultimate.script", "level": 1 },
23
23
  { "id": "11023", "type": "passive", "mode": "script", "energyCost": 0, "energyGain": 0, "cooldown": 0, "targetRule": "self", "element": "thunder", "scriptId": "miaoluo.passive.script", "level": 1, "activateOnBattleStart": true }
24
24
  ]
25
25
  },
@@ -37,7 +37,7 @@
37
37
  },
38
38
  {
39
39
  "heroId": "blade",
40
- "heroName": "布莱德",
40
+ "heroName": "",
41
41
  "element": "water",
42
42
  "role": "歼灭",
43
43
  "skills": [
@@ -1,41 +1,43 @@
1
1
  [
2
2
  { "id": "common.basic.single.50", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
3
- { "id": "cook.ultimate.slash", "steps": [{ "kind": "damage", "ratio": 4, "scaleStat": "Att" }] },
4
- { "id": "miaoluo.basic.flash", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
5
- { "id": "miaoluo.core.lowhp", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }] },
3
+ { "id": "cook.ultimate.slash", "steps": [{ "kind": "damage", "ratio": 4, "ratioByLevel": [4, 4.6, 5.2, 5.8, 6.4], "scaleStat": "Att" }] },
4
+ { "id": "cook.core.single", "steps": [{ "kind": "damage", "ratio": 1, "ratioByLevel": [1, 1.15, 1.3, 1.45, 1.6], "scaleStat": "Att" }] },
5
+ { "id": "miaoluo.basic.flash", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
6
+ { "id": "miaoluo.core.lowhp", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }] },
7
+ { "id": "miaoluo.ultimate.triple", "steps": [{ "kind": "damage", "ratio": 0.6, "ratioByLevel": [0.6, 0.69, 0.78, 0.87, 0.96], "scaleStat": "Att", "repeat": 3 }] },
6
8
  { "id": "blade.basic.slow", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
7
- { "id": "blade.core.aoe", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
8
- { "id": "blade.ultimate.strike", "steps": [{ "kind": "damage", "ratio": 3, "scaleStat": "Att" }] },
9
- { "id": "luoluo.basic.will", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "dazzle", "fixedProb": 5000 }] },
10
- { "id": "luoluo.core.taunt", "steps": [{ "kind": "shield", "ratio": 0.1, "scaleStat": "Mhp" }] },
11
- { "id": "luoluo.ultimate.def-aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "taunt", "fixedProb": 5000 }] },
12
- { "id": "rudy.basic.single", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
13
- { "id": "rudy.core.stun", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "stun", "fixedProb": 6500 }] },
9
+ { "id": "blade.core.aoe", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
10
+ { "id": "blade.ultimate.strike", "steps": [{ "kind": "damage", "ratio": 3, "ratioByLevel": [3, 3.45, 3.9, 4.35, 4.8], "scaleStat": "Att" }] },
11
+ { "id": "luoluo.basic.will", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "dazzle", "fixedProb": 5000, "fixedProbByLevel": [5000, 5500, 6000, 6500, 7000] }] },
12
+ { "id": "luoluo.core.taunt", "steps": [{ "kind": "shield", "ratio": 0.1, "ratioByLevel": [0.1, 0.12, 0.14, 0.16, 0.18], "scaleStat": "Mhp" }] },
13
+ { "id": "luoluo.ultimate.def-aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "taunt", "fixedProb": 5000, "fixedProbByLevel": [5000, 5500, 6000, 6500, 7000] }] },
14
+ { "id": "rudy.basic.single", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
15
+ { "id": "rudy.core.stun", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "stun", "fixedProb": 6500, "fixedProbByLevel": [6500, 7000, 7500, 8000, 8500] }] },
14
16
  { "id": "rudy.core.defense-buff", "steps": [{ "kind": "buff", "ratio": 0, "buffId": "def-up", "fixedProb": 10000 }] },
15
17
  { "id": "rudy.ultimate.team-shield", "steps": [{ "kind": "shield", "ratio": 0.2, "ratioByLevel": [0.2, 0.26, 0.32, 0.38, 0.44], "scaleStat": "Mhp" }] },
16
- { "id": "es.basic.single", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
17
- { "id": "es.core.damage", "steps": [{ "kind": "damage", "ratio": 0.35, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "dazzle", "fixedProb": 5000 }] },
18
+ { "id": "es.basic.single", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
19
+ { "id": "es.core.damage", "steps": [{ "kind": "damage", "ratio": 0.35, "ratioByLevel": [0.35, 0.4, 0.46, 0.51, 0.56], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "dazzle", "fixedProb": 5000, "fixedProbByLevel": [5000, 5500, 6000, 6500, 7000] }] },
18
20
  { "id": "es.core.heal", "steps": [{ "kind": "heal", "ratio": 0.4, "ratioByLevel": [0.4, 0.48, 0.56, 0.64, 0.72], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "bless", "fixedProb": 10000 }] },
19
- { "id": "es.ultimate.light-aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }] },
20
- { "id": "kesi.basic.double-near", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
21
- { "id": "kesi.core.random", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
22
- { "id": "kesi.ultimate.dot-burst", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }] },
21
+ { "id": "es.ultimate.light-aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }] },
22
+ { "id": "kesi.basic.double-near", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
23
+ { "id": "kesi.core.random", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
24
+ { "id": "kesi.ultimate.dot-burst", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }] },
23
25
  { "id": "kleiwu.basic.single", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
24
- { "id": "kleiwu.basic.dual", "steps": [{ "kind": "damage", "ratio": 0.3, "scaleStat": "Att" }] },
25
- { "id": "kleiwu.core.backlash", "steps": [{ "kind": "damage", "ratio": 1.2, "scaleStat": "Att" }] },
26
- { "id": "kleiwu.core.split", "steps": [{ "kind": "damage", "ratio": 1.2, "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.4, "scaleStat": "Att" }] },
27
- { "id": "kleiwu.ultimate.aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.8, "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
28
- { "id": "ailisha.basic.fire", "steps": [{ "kind": "damage", "ratio": 0.7, "scaleStat": "Att" }] },
26
+ { "id": "kleiwu.basic.dual", "steps": [{ "kind": "damage", "ratio": 0.3, "ratioByLevel": [0.3, 0.35, 0.39, 0.44, 0.48], "scaleStat": "Att" }] },
27
+ { "id": "kleiwu.core.backlash", "steps": [{ "kind": "damage", "ratio": 1.2, "ratioByLevel": [1.2, 1.38, 1.56, 1.74, 1.92], "scaleStat": "Att" }] },
28
+ { "id": "kleiwu.core.split", "steps": [{ "kind": "damage", "ratio": 1.2, "ratioByLevel": [1.2, 1.38, 1.56, 1.74, 1.92], "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.4, "ratioByLevel": [0.4, 0.46, 0.52, 0.58, 0.64], "scaleStat": "Att" }] },
29
+ { "id": "kleiwu.ultimate.aoe", "steps": [{ "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.8, "ratioByLevel": [0.8, 0.92, 1.04, 1.16, 1.28], "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }, { "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
30
+ { "id": "ailisha.basic.fire", "steps": [{ "kind": "damage", "ratio": 0.7, "ratioByLevel": [0.7, 0.81, 0.91, 1.02, 1.12], "scaleStat": "Att" }] },
29
31
  { "id": "ailisha.core.share", "steps": [{ "kind": "buff", "ratio": 0, "buffId": "share-damage", "fixedProb": 10000 }] },
30
- { "id": "ailisha.ultimate.hp-aoe", "steps": [{ "kind": "damage", "ratio": 1.2, "scaleStat": "Att" }] },
31
- { "id": "luolai.basic.random", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }] },
32
- { "id": "luolai.core.hot", "steps": [{ "kind": "heal", "ratio": 0.1, "scaleStat": "Mhp" }, { "kind": "buff", "ratio": 0, "buffId": "condense", "fixedProb": 10000 }] },
33
- { "id": "luolai.ultimate.heal", "steps": [{ "kind": "heal", "ratio": 0.2, "scaleStat": "Mhp" }, { "kind": "buff", "ratio": 0, "buffId": "condense", "fixedProb": 10000 }] },
34
- { "id": "tier.basic.weathering", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 3000 }] },
35
- { "id": "tier.core.double", "steps": [{ "kind": "damage", "ratio": 0.6, "scaleStat": "Att", "repeat": 2 }, { "kind": "buff", "ratio": 0, "buffId": "pierce", "fixedProb": 3000 }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 3000 }] },
36
- { "id": "tier.ultimate.single", "steps": [{ "kind": "damage", "ratio": 2.5, "scaleStat": "Att" }] },
37
- { "id": "tier.ultimate.aoe", "steps": [{ "kind": "damage", "ratio": 0.7, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "def-break", "fixedProb": 8000 }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 10000 }] },
38
- { "id": "pela.basic.speed", "steps": [{ "kind": "damage", "ratio": 0.5, "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "speed-up", "fixedProb": 10000 }] },
32
+ { "id": "ailisha.ultimate.hp-aoe", "steps": [{ "kind": "damage", "ratio": 1.2, "ratioByLevel": [1.2, 1.38, 1.56, 1.74, 1.92], "scaleStat": "Att" }] },
33
+ { "id": "luolai.basic.random", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
34
+ { "id": "luolai.core.hot", "steps": [{ "kind": "heal", "ratio": 0.1, "ratioByLevel": [0.1, 0.12, 0.14, 0.16, 0.18], "scaleStat": "Mhp" }, { "kind": "buff", "ratio": 0, "buffId": "condense", "fixedProb": 10000 }] },
35
+ { "id": "luolai.ultimate.heal", "steps": [{ "kind": "heal", "ratio": 0.2, "ratioByLevel": [0.2, 0.24, 0.28, 0.32, 0.36], "scaleStat": "Mhp" }, { "kind": "buff", "ratio": 0, "buffId": "condense", "fixedProb": 10000 }] },
36
+ { "id": "tier.basic.weathering", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 3000, "fixedProbByLevel": [3000, 3500, 4000, 4500, 5000] }] },
37
+ { "id": "tier.core.double", "steps": [{ "kind": "damage", "ratio": 0.6, "ratioByLevel": [0.6, 0.69, 0.78, 0.87, 0.96], "scaleStat": "Att", "repeat": 2 }, { "kind": "buff", "ratio": 0, "buffId": "pierce", "fixedProb": 3000, "fixedProbByLevel": [3000, 3500, 4000, 4500, 5000] }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 3000, "fixedProbByLevel": [3000, 3500, 4000, 4500, 5000] }] },
38
+ { "id": "tier.ultimate.single", "steps": [{ "kind": "damage", "ratio": 2.5, "ratioByLevel": [2.5, 2.88, 3.25, 3.63, 4], "scaleStat": "Att" }] },
39
+ { "id": "tier.ultimate.aoe", "steps": [{ "kind": "damage", "ratio": 0.7, "ratioByLevel": [0.7, 0.81, 0.91, 1.02, 1.12], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "def-break", "fixedProb": 8000, "fixedProbByLevel": [8000, 8500, 9000, 9500, 10000] }, { "kind": "buff", "ratio": 0, "buffId": "weathering", "fixedProb": 10000 }] },
40
+ { "id": "pela.basic.speed", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }, { "kind": "buff", "ratio": 0, "buffId": "speed-up", "fixedProb": 10000 }] },
39
41
  { "id": "pela.core.support", "steps": [{ "kind": "buff", "ratio": 0, "buffId": "damage-up", "fixedProb": 10000 }] },
40
42
  { "id": "pela.ultimate.team-buff", "steps": [{ "kind": "buff", "ratio": 0, "buffId": "attack-up", "fixedProb": 10000 }] },
41
43
  { "id": "m.basic.water.50", "steps": [{ "kind": "damage", "ratio": 0.5, "ratioByLevel": [0.5, 0.58, 0.66, 0.74, 0.82], "scaleStat": "Att" }] },
@@ -9,6 +9,7 @@ export declare class EffectSystem {
9
9
  getBuffs(unitId: UnitId): BuffInstance[];
10
10
  getBuffConfigs(): BuffConfig[];
11
11
  hasBuff(unitId: UnitId, buffId: string): boolean;
12
+ getImbalanceTakenRate(unitId: UnitId): number;
12
13
  getEffectiveStats(unit: UnitModel): UnitStats;
13
14
  addBuff(owner: UnitModel, sourceId: UnitId, buffId: string): void;
14
15
  removeBuff(owner: UnitModel, buffId: string): void;
@@ -21,6 +21,12 @@ export class EffectSystem {
21
21
  hasBuff(unitId, buffId) {
22
22
  return this.getBuffs(unitId).some((b) => b.id === buffId && b.stacks > 0);
23
23
  }
24
+ getImbalanceTakenRate(unitId) {
25
+ return this.getBuffs(unitId).reduce((total, buff) => {
26
+ const stacks = Math.max(1, buff.stacks);
27
+ return total + (buff.config.imbalanceTakenRateDelta ?? 0) * stacks;
28
+ }, 0);
29
+ }
24
30
  getEffectiveStats(unit) {
25
31
  const buffs = this.getBuffs(unit.id);
26
32
  const stat = { ...unit.stats };
@@ -54,11 +60,23 @@ export class EffectSystem {
54
60
  if (cfg.effectHitDelta) {
55
61
  stat.pEHR += cfg.effectHitDelta * stacks;
56
62
  }
63
+ if (cfg.assistRateDelta) {
64
+ stat.pAR += cfg.assistRateDelta * stacks;
65
+ }
57
66
  if (cfg.damageRateDelta) {
58
67
  stat.pBSDI += cfg.damageRateDelta * stacks;
59
68
  stat.pESDI += cfg.damageRateDelta * stacks;
60
69
  stat.pFSDI += cfg.damageRateDelta * stacks;
61
70
  }
71
+ if (cfg.allElementResistDelta) {
72
+ stat.pFDI_Def += cfg.allElementResistDelta * stacks;
73
+ stat.pTDI_Def += cfg.allElementResistDelta * stacks;
74
+ stat.pWDI_Def += cfg.allElementResistDelta * stacks;
75
+ stat.pRDI_Def += cfg.allElementResistDelta * stacks;
76
+ stat.pADI_Def += cfg.allElementResistDelta * stacks;
77
+ stat.pLDI_Def += cfg.allElementResistDelta * stacks;
78
+ stat.pDDI_Def += cfg.allElementResistDelta * stacks;
79
+ }
62
80
  if (cfg.vulnerabilityDelta) {
63
81
  stat.pVulnerability += cfg.vulnerabilityDelta * stacks;
64
82
  }
@@ -155,47 +155,43 @@ const bladeCoreScript = {
155
155
  };
156
156
  const luoluoBasicScript = {
157
157
  onCast(ctx) {
158
- ctx.api.addBuff(ctx.caster, ctx.caster, "will");
159
- return {
160
- skillId: ctx.skillId,
161
- casterId: ctx.caster,
162
- targets: ctx.targets,
163
- totalDamage: 0,
164
- totalHeal: 0,
165
- totalShield: 0,
166
- triggeredBy: ctx.trigger
167
- };
158
+ return buildEmptyResult(ctx, ctx.targets);
168
159
  }
169
160
  };
170
161
  // 洛洛核心技:获得10%生命值的护盾,每层【惩戒/意志】使护盾强度增加10%
171
162
  const luoluoCoreScript = {
172
163
  onCast(ctx) {
173
- // 护盾交由config模板结算,script层不再重复加盾
174
- return buildEmptyResult(ctx, ctx.targets);
164
+ const self = ctx.api.getUnit(ctx.caster);
165
+ if (!self) {
166
+ return buildEmptyResult(ctx, ctx.targets);
167
+ }
168
+ const willStacks = ctx.api
169
+ .getBuffs(ctx.caster)
170
+ .filter((buff) => buff.id === "will")
171
+ .reduce((total, buff) => total + buff.stacks, 0);
172
+ if (willStacks <= 0) {
173
+ return buildEmptyResult(ctx, ctx.targets);
174
+ }
175
+ // 基础护盾由 config 模板提供;这里补上每层惩戒额外 +10% 基础护盾强度。
176
+ const extraShield = Math.floor(self.stats.Mhp * 0.01 * willStacks);
177
+ const totalShield = ctx.api.shield(ctx.caster, extraShield);
178
+ return {
179
+ ...buildEmptyResult(ctx, ctx.targets),
180
+ totalShield,
181
+ hits: [buildShieldHit(ctx, ctx.caster, totalShield)]
182
+ };
175
183
  }
176
184
  };
177
185
  const miaoluoUltimateScript = {
178
186
  onCast(ctx) {
179
187
  const self = ctx.api.getUnit(ctx.caster);
180
- const target = ctx.api
181
- .getAliveUnits()
182
- .filter((unit) => self && unit.teamId !== self.teamId)
183
- .sort((a, b) => {
184
- if (a.runtime.Hp !== b.runtime.Hp) {
185
- return a.runtime.Hp - b.runtime.Hp;
186
- }
187
- return a.position - b.position;
188
- })[0];
188
+ const targetId = ctx.targets[0];
189
+ const target = targetId ? ctx.api.getUnit(targetId) : undefined;
189
190
  let totalDamage = 0;
190
191
  const hits = [];
191
192
  if (self && target) {
192
193
  ctx.api.addBuff(ctx.caster, ctx.caster, "miaoluo-ultimate-focus");
193
194
  hits.push(buildBuffHit(ctx, ctx.caster, "miaoluo-ultimate-focus"));
194
- for (let i = 0; i < 3; i += 1) {
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));
198
- }
199
195
  if (ctx.api.hasBuff(target.id, "imbalance-vulnerability")) {
200
196
  const r2 = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * 0.3));
201
197
  totalDamage += r2.damage;
@@ -211,56 +207,21 @@ const miaoluoUltimateScript = {
211
207
  };
212
208
  const miaoluoBasicScript = {
213
209
  onCast(ctx) {
214
- const self = ctx.api.getUnit(ctx.caster);
215
- const target = ctx.api
216
- .getAliveUnits()
217
- .filter((unit) => self && unit.teamId !== self.teamId)
218
- .sort((a, b) => {
219
- if (a.runtime.Hp !== b.runtime.Hp) {
220
- return a.runtime.Hp - b.runtime.Hp;
221
- }
222
- return a.position - b.position;
223
- })[0];
224
- let totalDamage = 0;
225
- const hits = [];
226
- if (self && target) {
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));
230
- }
231
- return {
232
- ...buildEmptyResult(ctx, target ? [target.id] : []),
233
- totalDamage,
234
- hits
235
- };
210
+ return buildEmptyResult(ctx, ctx.targets);
236
211
  }
237
212
  };
238
213
  const miaoluoCoreScript = {
239
214
  onCast(ctx) {
240
- const self = ctx.api.getUnit(ctx.caster);
241
- const target = ctx.api
242
- .getAliveUnits()
243
- .filter((unit) => self && unit.teamId !== self.teamId)
244
- .sort((a, b) => {
245
- if (a.runtime.Hp !== b.runtime.Hp) {
246
- return a.runtime.Hp - b.runtime.Hp;
247
- }
248
- return a.position - b.position;
249
- })[0];
250
- let totalDamage = 0;
215
+ const targetId = ctx.targets[0];
251
216
  const hits = [];
252
- if (self && target) {
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));
256
- ctx.api.addBuff(ctx.caster, target.id, "static");
257
- hits.push(buildBuffHit(ctx, target.id, "static"));
217
+ if (targetId) {
218
+ ctx.api.addBuff(ctx.caster, targetId, "static");
219
+ hits.push(buildBuffHit(ctx, targetId, "static"));
258
220
  ctx.api.addBuff(ctx.caster, ctx.caster, "flash");
259
221
  hits.push(buildBuffHit(ctx, ctx.caster, "flash"));
260
222
  }
261
223
  return {
262
- ...buildEmptyResult(ctx, target ? [target.id] : []),
263
- totalDamage,
224
+ ...buildEmptyResult(ctx, targetId ? [targetId] : []),
264
225
  hits
265
226
  };
266
227
  }
@@ -294,25 +255,19 @@ const cookBasicScript = {
294
255
  const cookCoreScript = {
295
256
  onCast(ctx) {
296
257
  const self = ctx.api.getUnit(ctx.caster);
297
- const enemies = ctx.api
298
- .getAliveUnits()
299
- .filter((unit) => self && unit.teamId !== self.teamId)
300
- .sort((a, b) => {
301
- if (b.runtime.Hp !== a.runtime.Hp) {
302
- return b.runtime.Hp - a.runtime.Hp;
303
- }
304
- return a.position - b.position;
305
- });
306
- const target = enemies[0];
258
+ const targetId = ctx.targets[0];
259
+ const target = targetId ? ctx.api.getUnit(targetId) : undefined;
307
260
  let totalDamage = 0;
308
261
  const hits = [];
309
262
  if (self && target) {
310
263
  const lostHp = Math.max(0, self.stats.Mhp - self.runtime.Hp);
311
264
  const lostStepCount = Math.floor((lostHp * 10) / Math.max(1, self.stats.Mhp));
312
- const multiplier = 1 + lostStepCount * 0.05;
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));
265
+ const extraRatio = lostStepCount * 0.05;
266
+ if (extraRatio > 0) {
267
+ const r = ctx.api.damage(ctx.caster, target.id, Math.floor(self.stats.Att * extraRatio));
268
+ totalDamage += r.damage;
269
+ hits.push(buildDamageHit(ctx, target.id, r.damage, r.imbalanceDelta));
270
+ }
316
271
  }
317
272
  return {
318
273
  ...buildEmptyResult(ctx, target ? [target.id] : []),
@@ -81,9 +81,12 @@ const m19052Script = {
81
81
  // 驱散1个负面效果(简化:移除第一个debuff)
82
82
  const debuffs = ctx.api.getBuffs(ally.id).filter(b => {
83
83
  const c = b.config;
84
- return (c.defDelta && c.defDelta < 0) || (c.speedRateDelta && c.speedRateDelta < 0) ||
84
+ return (c.defDelta && c.defDelta < 0) || (c.defenseRateDelta && c.defenseRateDelta < 0) ||
85
+ (c.speedRateDelta && c.speedRateDelta < 0) ||
85
86
  (c.vulnerabilityDelta && c.vulnerabilityDelta > 0) || c.stun || c.dotRatio ||
86
- (c.effectResDelta && c.effectResDelta < 0);
87
+ (c.effectResDelta && c.effectResDelta < 0) ||
88
+ (c.allElementResistDelta && c.allElementResistDelta < 0) ||
89
+ (c.imbalanceTakenRateDelta && c.imbalanceTakenRateDelta > 0);
87
90
  });
88
91
  if (debuffs.length > 0) {
89
92
  ctx.api.removeBuff(ally.id, debuffs[0].id);
@@ -327,9 +330,12 @@ const m19074Script = {
327
330
  const newBuff = buffs.find(b => b.id === data.buffId);
328
331
  if (newBuff) {
329
332
  const c = newBuff.config;
330
- const isDebuff = (c.defDelta && c.defDelta < 0) || (c.speedRateDelta && c.speedRateDelta < 0) ||
333
+ const isDebuff = (c.defDelta && c.defDelta < 0) || (c.defenseRateDelta && c.defenseRateDelta < 0) ||
334
+ (c.speedRateDelta && c.speedRateDelta < 0) ||
331
335
  (c.vulnerabilityDelta && c.vulnerabilityDelta > 0) || c.stun || c.dotRatio ||
332
- (c.effectResDelta && c.effectResDelta < 0);
336
+ (c.effectResDelta && c.effectResDelta < 0) ||
337
+ (c.allElementResistDelta && c.allElementResistDelta < 0) ||
338
+ (c.imbalanceTakenRateDelta && c.imbalanceTakenRateDelta > 0);
333
339
  if (isDebuff) {
334
340
  ctx.api.removeBuff(ctx.caster, data.buffId);
335
341
  }
@@ -361,7 +367,8 @@ const m19075Script = {
361
367
  (c.defenseRateDelta && c.defenseRateDelta > 0) ||
362
368
  (c.speedRateDelta && c.speedRateDelta > 0) ||
363
369
  (c.damageRateDelta && c.damageRateDelta > 0) ||
364
- (c.critRateDelta && c.critRateDelta > 0);
370
+ (c.critRateDelta && c.critRateDelta > 0) ||
371
+ (c.assistRateDelta && c.assistRateDelta > 0);
365
372
  if (isBeneficial) {
366
373
  ctx.api.removeBuff(ctx.caster, b.id);
367
374
  }
@@ -87,11 +87,14 @@ export interface BuffConfig {
87
87
  critDamageDelta?: number;
88
88
  healEffectDelta?: number;
89
89
  effectHitDelta?: number;
90
+ assistRateDelta?: number;
90
91
  damageRateDelta?: number;
91
92
  effectResDelta?: number;
93
+ allElementResistDelta?: number;
92
94
  energyRecoveryRateDelta?: number;
93
95
  vulnerabilityDelta?: number;
94
96
  imbalanceRateDelta?: number;
97
+ imbalanceTakenRateDelta?: number;
95
98
  damageShareToSourceRatio?: number;
96
99
  reactiveCounter?: boolean;
97
100
  reactiveCounterPriority?: number;
package/dist/index.d.ts CHANGED
@@ -10,4 +10,4 @@ export { ConfigSkillEngine, ScriptSkillEngine, SkillExecutor } from "./battle/sk
10
10
  export { designedScripts } from "./battle/script/designedScripts";
11
11
  export { loadBattleJsonConfigBundle, validateBattleJsonConfigBundle, buildBattleUnitsFromJsonBundle } from "./battle/config/jsonConfigLoader";
12
12
  export type { BattleJsonConfigBundle, HeroInput } from "./battle/config/jsonConfigLoader";
13
- export type { BattleScriptApi, BattleConfig, BattleInitUnit, BuffConfig, ISkillScript, SkillDefinition, SkillExecMode, SkillTemplate, UnitModel, UnitStats } from "./battle/types";
13
+ export type { BattleScriptApi, BattleConfig, BattleInitUnit, BuffConfig, ElementType, ISkillScript, SkillDefinition, SkillExecMode, SkillTemplate, SkillType, TargetRule, UnitModel, UnitStats } from "./battle/types";
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "hrbattle",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "一个基于回合制战斗引擎,支持技能脚本、buff系统和效果解析。",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "files": [
9
- "dist"
9
+ "dist",
10
+ "src",
11
+ "tests"
10
12
  ],
11
13
  "scripts": {
12
14
  "build": "tsc",