gotchi-battler-game-logic 3.0.0 → 4.0.1

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 (61) 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 +4 -0
  6. package/eslint.config.js +31 -0
  7. package/game-logic/index.js +2 -6
  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 +2 -2
  16. package/game-logic/v1.7/index.js +24 -18
  17. package/game-logic/v1.8/constants.js +0 -23
  18. package/game-logic/v1.8/helpers.js +2 -2
  19. package/game-logic/v1.8/index.js +25 -19
  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 +252 -114
  35. package/scripts/balancing/createTrainingGotchis.js +44 -44
  36. package/scripts/balancing/extractOnchainTraits.js +3 -3
  37. package/scripts/balancing/fixTrainingGotchis.js +41 -41
  38. package/scripts/balancing/processSims.js +5 -5
  39. package/scripts/balancing/sims.js +8 -15
  40. package/scripts/balancing/v1.7/setTeamPositions.js +2 -2
  41. package/scripts/balancing/v1.7.1/setTeamPositions.js +2 -2
  42. package/scripts/balancing/v1.7.2/setTeamPositions.js +2 -2
  43. package/scripts/balancing/v1.7.3/setTeamPositions.js +2 -2
  44. package/scripts/data/dungeon_mob_1.json +87 -0
  45. package/scripts/data/dungeon_mob_2.json +87 -0
  46. package/scripts/data/immaterialTeam1.json +374 -0
  47. package/scripts/data/immaterialTeam2.json +365 -0
  48. package/scripts/generateAllSpecialsLogs.js +93 -0
  49. package/scripts/generateSpecialLogs.js +94 -0
  50. package/scripts/runCampaignBattles.js +41 -0
  51. package/scripts/runLocalBattle.js +6 -3
  52. package/scripts/runLocalDungeon.js +52 -0
  53. package/scripts/runPvPBattle.js +15 -0
  54. package/scripts/runRealBattle.js +8 -8
  55. package/scripts/simRealBattle.js +8 -8
  56. package/scripts/validateBattle.js +12 -14
  57. package/scripts/validateTournament.js +9 -9
  58. package/tests/getModifiedStats.test.js +78 -0
  59. package/utils/errors.js +13 -13
  60. package/utils/transforms.js +2 -8
  61. package/scripts/output/.gitkeep +0 -0
@@ -35,20 +35,20 @@ const {
35
35
  * @returns {Object} logs The battle logs
36
36
  */
37
37
  const gameLoop = (team1, team2, seed, debug) => {
38
- if (!team1) throw new Error("Team 1 not found")
39
- if (!team2) throw new Error("Team 2 not found")
40
- if (!seed) throw new Error("Seed not found")
38
+ if (!team1) throw new Error('Team 1 not found')
39
+ if (!team2) throw new Error('Team 2 not found')
40
+ if (!seed) throw new Error('Seed not found')
41
41
 
42
42
  // Validate team objects
43
43
  const team1Validation = validator.validate(team1, teamSchema)
44
44
  if (!team1Validation) {
45
45
  console.error('Team 1 validation failed: ', JSON.stringify(validator.getLastErrors(), null, 2))
46
- throw new Error(`Team 1 validation failed`)
46
+ throw new Error('Team 1 validation failed')
47
47
  }
48
48
  const team2Validation = validator.validate(team2, teamSchema)
49
49
  if (!team2Validation) {
50
50
  console.error('Team 2 validation failed: ', JSON.stringify(validator.getLastErrors(), null, 2))
51
- throw new Error(`Team 2 validation failed`)
51
+ throw new Error('Team 2 validation failed')
52
52
  }
53
53
 
54
54
  // Make deep copy of team objects to avoid modifying the original objects
@@ -70,7 +70,7 @@ const gameLoop = (team1, team2, seed, debug) => {
70
70
  ]
71
71
  },
72
72
  turns: []
73
- };
73
+ }
74
74
 
75
75
  // Used for turn by turn health and status summaries
76
76
  // Deleted if not in development or no errors
@@ -98,7 +98,7 @@ const gameLoop = (team1, team2, seed, debug) => {
98
98
  turnLogs.statusesExpired = [...turnLogs.statusesExpired, ...getExpiredStatuses(team1, team2)]
99
99
  }
100
100
 
101
- logs.turns.push({index: turnCounter, ...turnLogs})
101
+ logs.turns.push({ index: turnCounter, ...turnLogs })
102
102
 
103
103
  if (debug) {
104
104
  logs.debug.push({
@@ -304,12 +304,10 @@ const attack = (attackingGotchi, attackingTeam, defendingTeam, defendingTargets,
304
304
  }
305
305
 
306
306
  // Deal with start of turn status effects
307
- const handleStatusEffects = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
307
+ const handleStatusEffects = (attackingGotchi, attackingTeam, defendingTeam) => {
308
308
  const statusEffects = []
309
309
  const passiveEffects = []
310
310
 
311
- const modifiedAttackingGotchi = getModifiedStats(attackingGotchi)
312
-
313
311
  // Check for global status effects
314
312
  const allAliveGotchis = [...getAlive(attackingTeam), ...getAlive(defendingTeam)]
315
313
 
@@ -511,7 +509,7 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
511
509
  const modifiedAttackingGotchi = getModifiedStats(attackingGotchi)
512
510
 
513
511
  switch (specialId) {
514
- case 1:
512
+ case 1: {
515
513
  // Spectral Strike - ignore armor and appply bleed status
516
514
  // get single target
517
515
  const ssTarget = getTarget(defendingTeam, rng)
@@ -533,10 +531,11 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
533
531
  noResistSpeedPenalty: true
534
532
  })
535
533
  break
536
- case 2:
534
+ }
535
+ case 2: {
537
536
  // Meditate - Boost own speed, magic, physical by 30%
538
537
 
539
- // Check if gotchi already has power_up_2 status
538
+ // Check if gotchi already has power_up_2 status
540
539
  if (attackingGotchi.statuses.includes('power_up_2')) {
541
540
  specialNotDone = true
542
541
  break
@@ -555,7 +554,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
555
554
  }
556
555
  ]
557
556
  break
558
- case 3:
557
+ }
558
+ case 3: {
559
559
  // Cleave - attack all enemies in a row (that have the most gotchis) for 75% damage
560
560
  // Find row with most gotchis
561
561
  const cleaveRow = getAlive(defendingTeam, 'front').length > getAlive(defendingTeam, 'back').length ? 'front' : 'back'
@@ -567,7 +567,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
567
567
  noPassiveStatuses: true
568
568
  })
569
569
  break
570
- case 4:
570
+ }
571
+ case 4: {
571
572
  // Taunt - add taunt status to self
572
573
 
573
574
  // Check if gotchi already has taunt status
@@ -589,7 +590,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
589
590
  }
590
591
  ]
591
592
  break
592
- case 5:
593
+ }
594
+ case 5: {
593
595
  // Curse - attack random enemy for 50% damage, apply fear status and remove all buffs
594
596
 
595
597
  const curseTarget = getTarget(defendingTeam, rng)
@@ -666,7 +668,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
666
668
  }
667
669
 
668
670
  break
669
- case 6:
671
+ }
672
+ case 6: {
670
673
  // Blessing - Heal all non-healer allies and remove all debuffs
671
674
 
672
675
  // Get all alive non-healer allies on the attacking team
@@ -754,7 +757,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
754
757
  }
755
758
 
756
759
  break
757
- case 7:
760
+ }
761
+ case 7: {
758
762
  // Thunder - Attack all enemies for 50% damage and apply stun status
759
763
 
760
764
  const thunderTargets = getAlive(defendingTeam)
@@ -775,7 +779,8 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
775
779
  })
776
780
 
777
781
  break
778
- case 8:
782
+ }
783
+ case 8: {
779
784
  // Devestating Smash - Attack random enemy for 200% damage
780
785
 
781
786
  const smashTarget = getTarget(defendingTeam, rng)
@@ -810,6 +815,7 @@ const specialAttack = (attackingGotchi, attackingTeam, defendingTeam, rng) => {
810
815
  }
811
816
 
812
817
  break
818
+ }
813
819
  }
814
820
 
815
821
  return {
@@ -0,0 +1,112 @@
1
+ const PASSIVES = ['sharp_blades', 'cloud_of_zen', 'frenzy', 'fortify', 'spread_the_fear', 'cleansing_aura', 'channel_the_coven', 'clan_momentum']
2
+ const DEBUFF_STATUSES = ['bleed', 'stun', 'fear']
3
+ const BUFF_STATUSES = ['taunt']
4
+
5
+ const BUFF_MULT_EFFECTS = {
6
+ cloud_of_zen: {
7
+ magic: 0.138,
8
+ physical: 0.138
9
+ },
10
+ power_up_2: {
11
+ magic: 0.75,
12
+ physical: 0.50
13
+ },
14
+ frenzy: {
15
+ crit: 1.14
16
+ },
17
+ fortify: {
18
+ armor: 1
19
+ },
20
+ taunt: {
21
+ armor: 1.65
22
+ },
23
+ channel_the_coven: {
24
+ magic: 0.18
25
+ },
26
+ clan_momentum: {
27
+ physical: 0.16
28
+ }
29
+ }
30
+
31
+ const BUFF_FLAT_EFFECTS = {
32
+
33
+ }
34
+
35
+ // Combine all buffs
36
+ const BUFFS = [...PASSIVES, ...BUFF_STATUSES, ...Object.keys(BUFF_MULT_EFFECTS), ...Object.keys(BUFF_FLAT_EFFECTS)]
37
+
38
+ const DEBUFF_MULT_EFFECTS = {
39
+ fear: {
40
+ resist: 1
41
+ },
42
+ stun: {
43
+ speed: 0.23
44
+ }
45
+ }
46
+
47
+ const DEBUFF_FLAT_EFFECTS = {
48
+
49
+ }
50
+
51
+ // Combine all debuffs
52
+ const DEBUFFS = [...DEBUFF_STATUSES, ...Object.keys(DEBUFF_MULT_EFFECTS), ...Object.keys(DEBUFF_FLAT_EFFECTS)]
53
+
54
+ const MULTS = {
55
+ // General
56
+ FRONT_ROW_ATK_BONUS: 1.1,
57
+ FRONT_ROW_DEF_NERF: 0.8,
58
+ EXPIRE_LEADERSKILL: 0,
59
+ SPEED_PENALTY: 2.5,
60
+ MAX_STATUSES: 3,
61
+ CRIT_MULTIPLIER_FAST: 2,
62
+ CRIT_MULTIPLIER_SLOW: 2,
63
+ // Ninja
64
+ SHARP_BLADES_BLEED_CHANCE: 0.76,
65
+ BLEED_DAMAGE: 10,
66
+ SPECTRAL_STRIKE_DAMAGE: 1.25,
67
+ // Enlightened
68
+ // Cleaver
69
+ CLEAVE_DAMAGE: 1.55,
70
+ // Tank
71
+ COUNTER_SPEED_MULTIPLIER: 0.5,
72
+ FORTIFY_COUNTER_CHANCE: 32,
73
+ COUNTER_DAMAGE: 1.9,
74
+ FORTIFY_COUNTER_DAMAGE: 1.9,
75
+ // Cursed
76
+ SPREAD_THE_FEAR_CHANCE: 0.84,
77
+ SPREAD_THE_FEAR_SPEED_PENALTY: 0,
78
+ SPREAD_THE_FEAR_CURSE_DAMAGE: 1.3,
79
+ CURSE_DAMAGE: 1.2,
80
+ CURSE_HEAL: 1,
81
+ CURSE_SPEED_PENALTY: 0,
82
+ // Healer
83
+ CLEANSING_AURA_REGEN: 0.2,
84
+ CLEANSING_AURA_NON_HEALER_REGEN: 0.1,
85
+ CLEANSING_AURA_HEAL: 3.4,
86
+ CLEANSING_AURA_HEAL_SPEED_PENALTY: 1,
87
+ BLESSING_HEAL: 2.7,
88
+ BLESSING_HEAL_SPEED_PENALTY: 1,
89
+ BLESSING_HEAL_CRIT_MULTIPLIER: 1.25,
90
+ // Mage
91
+ CHANNEL_THE_COVEN_STUN_CHANCE: 0.9,
92
+ THUNDER_STUN_CHANCE: 0.65,
93
+ THUNDER_DAMAGE: 1,
94
+ // Troll
95
+ CLAN_MOMENTUM_CHANCE: 0.9,
96
+ DEVESTATING_SMASH_X2_CHANCE: 0.65,
97
+ DEVESTATING_SMASH_DAMAGE: 2.5,
98
+ DEVESTATING_SMASH_X2_DAMAGE: 1.9,
99
+ }
100
+
101
+ module.exports = {
102
+ PASSIVES,
103
+ DEBUFF_STATUSES,
104
+ BUFF_STATUSES,
105
+ BUFF_MULT_EFFECTS,
106
+ BUFF_FLAT_EFFECTS,
107
+ BUFFS,
108
+ DEBUFF_MULT_EFFECTS,
109
+ DEBUFF_FLAT_EFFECTS,
110
+ DEBUFFS,
111
+ MULTS
112
+ }