gotchi-battler-game-logic 2.0.8 → 4.0.0

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 (74) hide show
  1. package/.cursor/rules/cursor-rules.mdc +67 -0
  2. package/.cursor/rules/directory-structure.mdc +63 -0
  3. package/.cursor/rules/self-improvement.mdc +64 -0
  4. package/.cursor/rules/tech-stack.mdc +99 -0
  5. package/README.md +7 -3
  6. package/eslint.config.js +31 -0
  7. package/game-logic/index.js +2 -5
  8. package/game-logic/v1.4/constants.js +0 -23
  9. package/game-logic/v1.4/index.js +64 -56
  10. package/game-logic/v1.5/constants.js +0 -23
  11. package/game-logic/v1.5/index.js +27 -21
  12. package/game-logic/v1.6/constants.js +0 -23
  13. package/game-logic/v1.6/index.js +27 -21
  14. package/game-logic/v1.7/constants.js +0 -23
  15. package/game-logic/v1.7/helpers.js +18 -3
  16. package/game-logic/v1.7/index.js +24 -18
  17. package/game-logic/v1.8/constants.js +112 -0
  18. package/game-logic/v1.8/helpers.js +628 -0
  19. package/game-logic/v1.8/index.js +832 -0
  20. package/game-logic/v2.0/constants.js +112 -0
  21. package/game-logic/v2.0/helpers.js +713 -0
  22. package/game-logic/v2.0/index.js +782 -0
  23. package/game-logic/v2.0/statuses.json +439 -0
  24. package/package.json +11 -4
  25. package/schemas/crystal.js +14 -0
  26. package/schemas/effect.js +25 -0
  27. package/schemas/gotchi.js +53 -0
  28. package/schemas/ingameteam.js +14 -0
  29. package/schemas/item.js +13 -0
  30. package/schemas/leaderskill.js +15 -0
  31. package/schemas/leaderskillstatus.js +12 -0
  32. package/schemas/special.js +22 -0
  33. package/schemas/team.js +24 -0
  34. package/schemas/team.json +254 -116
  35. package/scripts/balancing/createCSV.js +1 -1
  36. package/scripts/balancing/createTrainingGotchis.js +267 -0
  37. package/scripts/balancing/extractOnchainTraits.js +61 -0
  38. package/scripts/balancing/fixTrainingGotchis.js +41 -41
  39. package/scripts/balancing/processSims.js +6 -6
  40. package/scripts/balancing/sims.js +10 -17
  41. package/scripts/balancing/v1.7/mapGotchi.js +119 -0
  42. package/scripts/balancing/v1.7/setTeamPositions.js +2 -2
  43. package/scripts/balancing/v1.7/training_gotchis_traits.json +520 -0
  44. package/scripts/balancing/v1.7.1/mapGotchi.js +119 -0
  45. package/scripts/balancing/v1.7.1/setTeamPositions.js +2 -2
  46. package/scripts/balancing/v1.7.1/training_gotchis_traits.json +520 -0
  47. package/scripts/balancing/v1.7.2/mapGotchi.js +157 -0
  48. package/scripts/balancing/v1.7.2/setTeamPositions.js +2 -2
  49. package/scripts/balancing/v1.7.2/training_gotchis_traits.json +520 -0
  50. package/scripts/balancing/v1.7.3/class_combos.js +44 -0
  51. package/scripts/balancing/v1.7.3/mapGotchi.js +164 -0
  52. package/scripts/balancing/v1.7.3/setTeamPositions.js +122 -0
  53. package/scripts/balancing/v1.7.3/training_gotchis.json +22402 -0
  54. package/scripts/balancing/v1.7.3/training_gotchis_traits.json +37 -0
  55. package/scripts/balancing/v1.7.3/trait_combos.json +10 -0
  56. package/scripts/data/dungeon_mob_1.json +87 -0
  57. package/scripts/data/dungeon_mob_2.json +87 -0
  58. package/scripts/data/immaterialTeam1.json +374 -0
  59. package/scripts/data/immaterialTeam2.json +365 -0
  60. package/scripts/data/tournaments.json +5 -0
  61. package/scripts/generateAllSpecialsLogs.js +93 -0
  62. package/scripts/generateSpecialLogs.js +94 -0
  63. package/scripts/runCampaignBattles.js +41 -0
  64. package/scripts/runLocalBattle.js +6 -3
  65. package/scripts/runLocalDungeon.js +52 -0
  66. package/scripts/runPvPBattle.js +16 -0
  67. package/scripts/runRealBattle.js +8 -8
  68. package/scripts/simRealBattle.js +8 -8
  69. package/scripts/validateBattle.js +23 -16
  70. package/scripts/validateTournament.js +9 -9
  71. package/tests/getModifiedStats.test.js +78 -0
  72. package/utils/errors.js +13 -13
  73. package/utils/transforms.js +2 -8
  74. package/scripts/output/.gitkeep +0 -0
@@ -0,0 +1,365 @@
1
+ {
2
+ "formation": {
3
+ "front": [
4
+ null,
5
+ {
6
+ "id": 7,
7
+ "onchainId": 23921,
8
+ "name": "Godly",
9
+ "type": "gotchi",
10
+ "visualCode": "wEth-Common1-Rare_Low-160-416-202-124-70-70-417",
11
+ "level": 72,
12
+ "speed": 191,
13
+ "health": 862,
14
+ "attack": 210,
15
+ "defense": 133,
16
+ "criticalRate": 50.1,
17
+ "criticalDamage": 168.1,
18
+ "resist": 152,
19
+ "focus": 152,
20
+ "createdAt": "2025-11-24T16:54:05.374Z",
21
+ "updatedAt": "2025-11-24T16:54:05.374Z",
22
+ "gotchiClass": "troll",
23
+ "special": "furious_bash",
24
+ "leaderSkill": "smash",
25
+ "item": null,
26
+ "crystalSlot1": null,
27
+ "crystalSlot2": null,
28
+ "crystalSlot3": null,
29
+ "crystalSlot4": null,
30
+ "crystalSlot5": null,
31
+ "crystalSlot6": null,
32
+ "specialExpanded": {
33
+ "code": "furious_bash",
34
+ "name": "Furious Bash",
35
+ "initialCooldown": 1,
36
+ "cooldown": 3,
37
+ "actionType": "attack",
38
+ "actionMultiplier": 1,
39
+ "monstersOnly": false,
40
+ "notes": "50 % chance for Troll to gain +SPD.",
41
+ "gotchiClass": "troll",
42
+ "target": "enemy_random",
43
+ "effects": [
44
+ {
45
+ "id": 99,
46
+ "effectType": "status",
47
+ "value": null,
48
+ "chance": 0.5,
49
+ "special": "furious_bash",
50
+ "target": "self",
51
+ "status": "spd_up"
52
+ }
53
+ ]
54
+ },
55
+ "leaderSkillExpanded": {
56
+ "code": "smash",
57
+ "name": "Smash!",
58
+ "description": "Your team gets +CRD.",
59
+ "monstersOnly": false,
60
+ "gotchiClass": "troll",
61
+ "statuses": [
62
+ {
63
+ "leaderSkill": "smash",
64
+ "status": "crd_up",
65
+ "stackCount": 1
66
+ }
67
+ ]
68
+ }
69
+ },
70
+ null,
71
+ {
72
+ "id": 9,
73
+ "onchainId": 8062,
74
+ "name": "Magestic",
75
+ "type": "gotchi",
76
+ "visualCode": "Uni-UNI-Rare_High-15-13-14-48-217-217-237",
77
+ "level": 71,
78
+ "speed": 185,
79
+ "health": 854,
80
+ "attack": 175,
81
+ "defense": 132,
82
+ "criticalRate": 50.2,
83
+ "criticalDamage": 157.7,
84
+ "resist": 181,
85
+ "focus": 173,
86
+ "createdAt": "2025-11-24T16:54:05.374Z",
87
+ "updatedAt": "2025-11-24T16:54:05.374Z",
88
+ "gotchiClass": "cleaver",
89
+ "special": "sword_breaker",
90
+ "leaderSkill": "sharp_wits",
91
+ "item": null,
92
+ "crystalSlot1": null,
93
+ "crystalSlot2": null,
94
+ "crystalSlot3": null,
95
+ "crystalSlot4": null,
96
+ "crystalSlot5": null,
97
+ "crystalSlot6": null,
98
+ "specialExpanded": {
99
+ "code": "sword_breaker",
100
+ "name": "Sword Breaker",
101
+ "initialCooldown": 3,
102
+ "cooldown": 1,
103
+ "actionType": "attack",
104
+ "actionMultiplier": 1.2,
105
+ "monstersOnly": false,
106
+ "notes": "May apply −2 CRT (50% chance per stack).",
107
+ "gotchiClass": "cleaver",
108
+ "target": "enemy_random",
109
+ "effects": [
110
+ {
111
+ "id": 29,
112
+ "effectType": "status",
113
+ "value": null,
114
+ "chance": 0.5,
115
+ "special": "sword_breaker",
116
+ "target": "same_as_attack",
117
+ "status": "crt_down"
118
+ },
119
+ {
120
+ "id": 30,
121
+ "effectType": "status",
122
+ "value": null,
123
+ "chance": 0.5,
124
+ "special": "sword_breaker",
125
+ "target": "same_as_attack",
126
+ "status": "crt_down"
127
+ }
128
+ ]
129
+ },
130
+ "leaderSkillExpanded": {
131
+ "code": "sharp_wits",
132
+ "name": "Sharp Wits",
133
+ "description": "Your team gets +FOC.",
134
+ "monstersOnly": false,
135
+ "gotchiClass": "cleaver",
136
+ "statuses": [
137
+ {
138
+ "leaderSkill": "sharp_wits",
139
+ "status": "foc_up",
140
+ "stackCount": 1
141
+ }
142
+ ]
143
+ }
144
+ },
145
+ null
146
+ ],
147
+ "back": [
148
+ {
149
+ "id": 6,
150
+ "onchainId": 13681,
151
+ "name": "Artemis",
152
+ "type": "gotchi",
153
+ "visualCode": "USDC-MythicalLow2_H2-Common-258-368-259-63-315-386-261",
154
+ "level": 98,
155
+ "speed": 178,
156
+ "health": 1328,
157
+ "attack": 193,
158
+ "defense": 166,
159
+ "criticalRate": 45.1,
160
+ "criticalDamage": 175.4,
161
+ "resist": 186,
162
+ "focus": 217,
163
+ "createdAt": "2025-11-24T16:54:05.373Z",
164
+ "updatedAt": "2025-11-24T16:54:05.373Z",
165
+ "gotchiClass": "mage",
166
+ "special": "tornado",
167
+ "leaderSkill": "obsessive_studies",
168
+ "item": null,
169
+ "crystalSlot1": null,
170
+ "crystalSlot2": null,
171
+ "crystalSlot3": null,
172
+ "crystalSlot4": null,
173
+ "crystalSlot5": null,
174
+ "crystalSlot6": null,
175
+ "specialExpanded": {
176
+ "code": "tornado",
177
+ "name": "Tornado",
178
+ "initialCooldown": 2,
179
+ "cooldown": 3,
180
+ "actionType": "none",
181
+ "actionMultiplier": null,
182
+ "monstersOnly": false,
183
+ "notes": "Each enemy has a 25 % chance to be Feared.",
184
+ "gotchiClass": "mage",
185
+ "target": "all_enemies",
186
+ "effects": [
187
+ {
188
+ "id": 87,
189
+ "effectType": "status",
190
+ "value": null,
191
+ "chance": 0.25,
192
+ "special": "tornado",
193
+ "target": "same_as_attack",
194
+ "status": "fear"
195
+ }
196
+ ]
197
+ },
198
+ "leaderSkillExpanded": {
199
+ "code": "obsessive_studies",
200
+ "name": "Obsessive Studies",
201
+ "description": "Your team gets -DEF and +2 FOC.",
202
+ "monstersOnly": false,
203
+ "gotchiClass": "mage",
204
+ "statuses": [
205
+ {
206
+ "leaderSkill": "obsessive_studies",
207
+ "status": "def_down",
208
+ "stackCount": 1
209
+ },
210
+ {
211
+ "leaderSkill": "obsessive_studies",
212
+ "status": "foc_up",
213
+ "stackCount": 2
214
+ }
215
+ ]
216
+ }
217
+ },
218
+ null,
219
+ {
220
+ "id": 8,
221
+ "onchainId": 19172,
222
+ "name": "Gatekeeper",
223
+ "type": "gotchi",
224
+ "visualCode": "Dai-UncommonLow2-Mythical_High-160-263-262-62-51-312-261",
225
+ "level": 72,
226
+ "speed": 194,
227
+ "health": 863,
228
+ "attack": 176,
229
+ "defense": 156,
230
+ "criticalRate": 38.5,
231
+ "criticalDamage": 168.9,
232
+ "resist": 153,
233
+ "focus": 186,
234
+ "createdAt": "2025-11-24T16:54:05.374Z",
235
+ "updatedAt": "2025-11-24T16:54:05.374Z",
236
+ "gotchiClass": "mage",
237
+ "special": "tornado",
238
+ "leaderSkill": "obsessive_studies",
239
+ "item": null,
240
+ "crystalSlot1": null,
241
+ "crystalSlot2": null,
242
+ "crystalSlot3": null,
243
+ "crystalSlot4": null,
244
+ "crystalSlot5": null,
245
+ "crystalSlot6": null,
246
+ "specialExpanded": {
247
+ "code": "tornado",
248
+ "name": "Tornado",
249
+ "initialCooldown": 2,
250
+ "cooldown": 3,
251
+ "actionType": "none",
252
+ "actionMultiplier": null,
253
+ "monstersOnly": false,
254
+ "notes": "Each enemy has a 25 % chance to be Feared.",
255
+ "gotchiClass": "mage",
256
+ "target": "all_enemies",
257
+ "effects": [
258
+ {
259
+ "id": 87,
260
+ "effectType": "status",
261
+ "value": null,
262
+ "chance": 0.25,
263
+ "special": "tornado",
264
+ "target": "same_as_attack",
265
+ "status": "fear"
266
+ }
267
+ ]
268
+ },
269
+ "leaderSkillExpanded": {
270
+ "code": "obsessive_studies",
271
+ "name": "Obsessive Studies",
272
+ "description": "Your team gets -DEF and +2 FOC.",
273
+ "monstersOnly": false,
274
+ "gotchiClass": "mage",
275
+ "statuses": [
276
+ {
277
+ "leaderSkill": "obsessive_studies",
278
+ "status": "def_down",
279
+ "stackCount": 1
280
+ },
281
+ {
282
+ "leaderSkill": "obsessive_studies",
283
+ "status": "foc_up",
284
+ "stackCount": 2
285
+ }
286
+ ]
287
+ }
288
+ },
289
+ null,
290
+ {
291
+ "id": 10,
292
+ "onchainId": 4751,
293
+ "name": "best ever",
294
+ "type": "gotchi",
295
+ "visualCode": "Yfi-Common1-Mythical_High-0-0-0-0-0-0-0",
296
+ "level": 41,
297
+ "speed": 158,
298
+ "health": 662,
299
+ "attack": 156,
300
+ "defense": 117,
301
+ "criticalRate": 37.5,
302
+ "criticalDamage": 148.1,
303
+ "resist": 135,
304
+ "focus": 136,
305
+ "createdAt": "2025-11-24T16:54:05.374Z",
306
+ "updatedAt": "2025-11-24T16:54:05.374Z",
307
+ "gotchiClass": "mage",
308
+ "special": "tornado",
309
+ "leaderSkill": "obsessive_studies",
310
+ "item": null,
311
+ "crystalSlot1": null,
312
+ "crystalSlot2": null,
313
+ "crystalSlot3": null,
314
+ "crystalSlot4": null,
315
+ "crystalSlot5": null,
316
+ "crystalSlot6": null,
317
+ "specialExpanded": {
318
+ "code": "tornado",
319
+ "name": "Tornado",
320
+ "initialCooldown": 2,
321
+ "cooldown": 3,
322
+ "actionType": "none",
323
+ "actionMultiplier": null,
324
+ "monstersOnly": false,
325
+ "notes": "Each enemy has a 25 % chance to be Feared.",
326
+ "gotchiClass": "mage",
327
+ "target": "all_enemies",
328
+ "effects": [
329
+ {
330
+ "id": 87,
331
+ "effectType": "status",
332
+ "value": null,
333
+ "chance": 0.25,
334
+ "special": "tornado",
335
+ "target": "same_as_attack",
336
+ "status": "fear"
337
+ }
338
+ ]
339
+ },
340
+ "leaderSkillExpanded": {
341
+ "code": "obsessive_studies",
342
+ "name": "Obsessive Studies",
343
+ "description": "Your team gets -DEF and +2 FOC.",
344
+ "monstersOnly": false,
345
+ "gotchiClass": "mage",
346
+ "statuses": [
347
+ {
348
+ "leaderSkill": "obsessive_studies",
349
+ "status": "def_down",
350
+ "stackCount": 1
351
+ },
352
+ {
353
+ "leaderSkill": "obsessive_studies",
354
+ "status": "foc_up",
355
+ "stackCount": 2
356
+ }
357
+ ]
358
+ }
359
+ }
360
+ ]
361
+ },
362
+ "leader": 6,
363
+ "name": "Immaterial Team 2",
364
+ "owner": "0xfe698c212526f15cc25af671beba14aac309457f"
365
+ }
@@ -63,5 +63,10 @@
63
63
  "id": 15,
64
64
  "name": "RF8 100K GHST Tournament",
65
65
  "gameLogicVersion": "v1.6"
66
+ },
67
+ {
68
+ "id": 18,
69
+ "name": "RF9 100K GHST Tournament 1",
70
+ "gameLogicVersion": "v1.7"
66
71
  }
67
72
  ]
@@ -0,0 +1,93 @@
1
+ // Generate logs which test the sequences for all special attacks
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const seedrandom = require('seedrandom')
5
+ const { attack } = require('../game-logic/v2.0')
6
+ const { getAlive, prepareTeams, getLogGotchis, simplifyTeam } = require('../game-logic/v2.0/helpers')
7
+ const ninjaSpecials = require('../../gotchi-battler-backend/data/specials_ninja.json')
8
+ const enlightenedSpecials = require('../../gotchi-battler-backend/data/specials_enlightened.json')
9
+ const cleaverSpecials = require('../../gotchi-battler-backend/data/specials_cleaver.json')
10
+ const tankSpecials = require('../../gotchi-battler-backend/data/specials_tank.json')
11
+ const cursedSpecials = require('../../gotchi-battler-backend/data/specials_cursed.json')
12
+ const healerSpecials = require('../../gotchi-battler-backend/data/specials_healer.json')
13
+ const mageSpecials = require('../../gotchi-battler-backend/data/specials_mage.json')
14
+ const trollSpecials = require('../../gotchi-battler-backend/data/specials_troll.json')
15
+
16
+ const specials = [
17
+ ...ninjaSpecials, ...enlightenedSpecials,
18
+ ...cleaverSpecials, ...tankSpecials,
19
+ ...cursedSpecials, ...healerSpecials,
20
+ ...mageSpecials, ...trollSpecials
21
+ ]
22
+
23
+ const main = async () => {
24
+ // Mock the game loop
25
+ let team1 = require('./data/immaterialTeam1.json')
26
+ let team2 = require('./data/immaterialTeam2.json')
27
+
28
+ team1 = JSON.parse(JSON.stringify(team1))
29
+ team2 = JSON.parse(JSON.stringify(team2))
30
+
31
+ const seed = 'randomseed'
32
+ const rng = seedrandom(seed)
33
+
34
+ // Give all gotchis 100000 health for testing
35
+ const allAliveGotchis = [...getAlive(team1), ...getAlive(team2)]
36
+ allAliveGotchis.forEach(x => {
37
+ x.health = 1000000
38
+ })
39
+
40
+ prepareTeams(allAliveGotchis, team1, team2)
41
+
42
+ const logs = {
43
+ meta: {
44
+ seed,
45
+ timestamp: new Date(),
46
+ type: 'pvp',
47
+ campaign: {},
48
+ isBoss: false
49
+ },
50
+ gotchis: getLogGotchis(allAliveGotchis),
51
+ layout: {
52
+ teams: [
53
+ simplifyTeam(team1),
54
+ simplifyTeam(team2)
55
+ ]
56
+ },
57
+ turns: [],
58
+ result: {},
59
+ debug: []
60
+ }
61
+
62
+ let turnCounter = 0
63
+ for (const special of specials) {
64
+
65
+ // Make each gotchi do each special
66
+
67
+ for (const gotchi of allAliveGotchis) {
68
+ const specialResults = attack({
69
+ ...gotchi,
70
+ special: special.code,
71
+ specialExpanded: special
72
+ }, team1, team2, rng, true)
73
+ logs.turns.push({
74
+ index: turnCounter,
75
+ skipTurn: null,
76
+ action: {
77
+ user: gotchi.id,
78
+ name: special.code,
79
+ effects: specialResults.effects
80
+ },
81
+ statusEffects: [],
82
+ statusesExpired: specialResults.statusesExpired
83
+ })
84
+ turnCounter++
85
+ }
86
+ }
87
+
88
+ // Save logs to file
89
+ fs.writeFileSync(path.join(__dirname, 'output', 'gotchi-sequences.json'), JSON.stringify(logs, null, 2))
90
+ }
91
+
92
+ // node scripts/generateAllSpecialsLogs.js
93
+ main()
@@ -0,0 +1,94 @@
1
+ // Generate logs which test the sequences for all special attacks
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const seedrandom = require('seedrandom')
5
+ const { attack } = require('../game-logic/v2.0')
6
+ const { getAlive, prepareTeams, getLogGotchis, simplifyTeam } = require('../game-logic/v2.0/helpers')
7
+ const ninjaSpecials = require('../../gotchi-battler-backend/data/specials_ninja.json')
8
+ const enlightenedSpecials = require('../../gotchi-battler-backend/data/specials_enlightened.json')
9
+ const cleaverSpecials = require('../../gotchi-battler-backend/data/specials_cleaver.json')
10
+ const tankSpecials = require('../../gotchi-battler-backend/data/specials_tank.json')
11
+ const cursedSpecials = require('../../gotchi-battler-backend/data/specials_cursed.json')
12
+ const healerSpecials = require('../../gotchi-battler-backend/data/specials_healer.json')
13
+ const mageSpecials = require('../../gotchi-battler-backend/data/specials_mage.json')
14
+ const trollSpecials = require('../../gotchi-battler-backend/data/specials_troll.json')
15
+
16
+ const specials = [
17
+ ...ninjaSpecials, ...enlightenedSpecials,
18
+ ...cleaverSpecials, ...tankSpecials,
19
+ ...cursedSpecials, ...healerSpecials,
20
+ ...mageSpecials, ...trollSpecials
21
+ ]
22
+
23
+ const main = async () => {
24
+ for (const special of specials) {
25
+ // Mock the game loop
26
+ let team1 = require('./data/immaterialTeam1.json')
27
+ let team2 = require('./data/immaterialTeam2.json')
28
+
29
+ team1 = JSON.parse(JSON.stringify(team1))
30
+ team2 = JSON.parse(JSON.stringify(team2))
31
+
32
+ const seed = 'randomseed'
33
+ const rng = seedrandom(seed)
34
+
35
+ // Give all gotchis 100000 health for testing
36
+ const allAliveGotchis = [...getAlive(team1), ...getAlive(team2)]
37
+ allAliveGotchis.forEach(x => {
38
+ x.health = 1000000
39
+ })
40
+
41
+ prepareTeams(allAliveGotchis, team1, team2)
42
+
43
+ const logs = {
44
+ meta: {
45
+ seed,
46
+ timestamp: new Date(),
47
+ type: 'pvp',
48
+ campaign: {},
49
+ isBoss: false
50
+ },
51
+ gotchis: getLogGotchis(allAliveGotchis),
52
+ layout: {
53
+ teams: [
54
+ simplifyTeam(team1),
55
+ simplifyTeam(team2)
56
+ ]
57
+ },
58
+ turns: [],
59
+ result: {},
60
+ debug: []
61
+ }
62
+
63
+ let turnCounter = 0
64
+
65
+ // Do the special attack 10 times in a row
66
+ for (let i = 0; i < 10; i++) {
67
+ const specialResults = attack({
68
+ ...allAliveGotchis[0],
69
+ special: special.code,
70
+ specialExpanded: special
71
+ }, team1, team2, rng, true)
72
+
73
+ logs.turns.push({
74
+ index: turnCounter,
75
+ skipTurn: null,
76
+ action: {
77
+ user: allAliveGotchis[0].id,
78
+ name: special.code,
79
+ actionEffects: specialResults.actionEffects,
80
+ additionalEffects: specialResults.additionalEffects
81
+ },
82
+ statusEffects: [],
83
+ statusesExpired: specialResults.statusesExpired
84
+ })
85
+ turnCounter++
86
+ }
87
+
88
+ // Save logs to file
89
+ fs.writeFileSync(path.join(__dirname, 'output', 'specials', `${special.code}.json`), JSON.stringify(logs, null, 2))
90
+ }
91
+ }
92
+
93
+ // node scripts/generateSpecialLogs.js
94
+ main()
@@ -0,0 +1,41 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const { battle } = require('..')
4
+
5
+ const campaigns = [
6
+ 'yield_fields',
7
+ 'daark_forest',
8
+ 'caaverns',
9
+ 'defi_desert',
10
+ 'laughing_peaks',
11
+ 'mount_oomf'
12
+ ]
13
+
14
+ const team1 = require('./data/immaterialTeam1.json')
15
+
16
+ for (const campaign of campaigns) {
17
+ const campaignDir = path.join(__dirname, 'data', 'campaign', campaign)
18
+ const files = fs.readdirSync(campaignDir).filter(file => file.endsWith('.json'))
19
+
20
+ for (const file of files) {
21
+ const team2 = require(path.join(campaignDir, file))
22
+
23
+ const results = battle(team1, team2, 'randomseed', {
24
+ debug: false,
25
+ type: 'pve',
26
+ campaign: {
27
+ biome: file.split('_s')[0],
28
+ stage: file.split('_b')[0],
29
+ battle: file.replace('.json', '')
30
+ },
31
+ isBoss: file.includes('b6')
32
+ })
33
+
34
+ const resultsDir = path.join(__dirname, 'output', 'campaign', campaign)
35
+
36
+ // Write output to /scripts/output/campaign/<campaign>/<file>-results.json
37
+ fs.writeFileSync(path.join(resultsDir, file.replace('.json', '-results.json')), JSON.stringify(results, null, '\t'))
38
+ }
39
+ }
40
+
41
+ // node scripts/runCampaignBattles.js
@@ -4,10 +4,13 @@ const { battle } = require('..')
4
4
 
5
5
  // Edit these json files to test different battles
6
6
  // NOTE: Only the in-game stats (speed, health, crit etc..) are used in the game logic
7
- const team1 = require('./data/team1.json')
8
- const team2 = require('./data/team2.json')
7
+ const team1 = require('./data/oggyMaxi.json')
8
+ const team2 = require('./data/wagdiddly.json')
9
9
 
10
- const results = battle(team1, team2, "82807311112923564712218359337695919195403960526804010606215202651499586140469", true)
10
+ const results = battle(team1, team2, '82807311112923564712218359337695919195403960526804010606215202651499586140469', {
11
+ debug: true,
12
+ type: 'pvp'
13
+ })
11
14
 
12
15
  const timestamp = new Date().getTime()
13
16
  const resultsFilename = `results-${timestamp}.json`
@@ -0,0 +1,52 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const { battle } = require('..')
4
+
5
+ // Edit these json files to test different battles
6
+ // NOTE: Only the in-game stats (speed, health, crit etc..) are used in the game logic
7
+ const team1 = require('./data/team1.json')
8
+ const mob1 = require('./data/dungeon_mob_1.json')
9
+ const mob2 = require('./data/dungeon_mob_2.json')
10
+
11
+ const mobs = {
12
+ 'DUNGEON_1_MOB_1': mob1,
13
+ 'DUNGEON_1_MOB_2': mob2,
14
+ }
15
+
16
+ const scenario = {
17
+ 'id': 'scenario123',
18
+ 'name': 'Dungeon 1',
19
+ 'battles': [
20
+ {
21
+ 'id': 'battle1',
22
+ 'environment': 'DUNGEON_1_1',
23
+ 'mob': 'DUNGEON_1_MOB_1',
24
+ },
25
+ {
26
+ 'id': 'battle2',
27
+ 'environment': 'DUNGEON_1_2',
28
+ 'mob': 'DUNGEON_1_MOB_2',
29
+ }
30
+ ]
31
+ }
32
+
33
+ for (let i = 0; i < scenario.battles.length; i++) {
34
+ const scenarioBattle = scenario.battles[i]
35
+ const logs = battle(team1, mobs[scenarioBattle.mob], 'arandomseed', true)
36
+
37
+ scenarioBattle.logs = logs
38
+
39
+ if (logs.result.winner === 1) {
40
+ team1.startingState = logs.result.winningTeam
41
+ } else {
42
+ break
43
+ }
44
+ }
45
+
46
+ const timestamp = new Date().getTime()
47
+ const resultsFilename = `results-${timestamp}.json`
48
+ fs.writeFileSync(path.join(__dirname, 'output', resultsFilename), JSON.stringify(scenario, null, '\t'))
49
+
50
+ console.log(`Results written to ${path.join(__dirname, 'output', resultsFilename)}`)
51
+
52
+ // node scripts/runLocalDungeon.js