gotchi-battler-game-logic 2.0.8 → 3.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.
- package/README.md +3 -3
- package/game-logic/index.js +2 -1
- package/game-logic/v1.7/helpers.js +16 -1
- package/game-logic/v1.8/constants.js +135 -0
- package/game-logic/v1.8/helpers.js +628 -0
- package/game-logic/v1.8/index.js +826 -0
- package/package.json +1 -1
- package/schemas/team.json +2 -2
- package/scripts/balancing/createCSV.js +1 -1
- package/scripts/balancing/createTrainingGotchis.js +267 -0
- package/scripts/balancing/extractOnchainTraits.js +61 -0
- package/scripts/balancing/processSims.js +1 -1
- package/scripts/balancing/sims.js +2 -2
- package/scripts/balancing/v1.7/mapGotchi.js +119 -0
- package/scripts/balancing/v1.7/training_gotchis_traits.json +520 -0
- package/scripts/balancing/v1.7.1/mapGotchi.js +119 -0
- package/scripts/balancing/v1.7.1/training_gotchis_traits.json +520 -0
- package/scripts/balancing/v1.7.2/mapGotchi.js +157 -0
- package/scripts/balancing/v1.7.2/training_gotchis_traits.json +520 -0
- package/scripts/balancing/v1.7.3/class_combos.js +44 -0
- package/scripts/balancing/v1.7.3/mapGotchi.js +164 -0
- package/scripts/balancing/v1.7.3/setTeamPositions.js +122 -0
- package/scripts/balancing/v1.7.3/training_gotchis.json +22402 -0
- package/scripts/balancing/v1.7.3/training_gotchis_traits.json +37 -0
- package/scripts/balancing/v1.7.3/trait_combos.json +10 -0
- package/scripts/data/tournaments.json +5 -0
- package/scripts/validateBattle.js +11 -2
package/package.json
CHANGED
package/schemas/team.json
CHANGED
|
@@ -108,13 +108,13 @@
|
|
|
108
108
|
"type": "integer"
|
|
109
109
|
},
|
|
110
110
|
"crit": {
|
|
111
|
-
"type": "
|
|
111
|
+
"type": "number"
|
|
112
112
|
},
|
|
113
113
|
"armor": {
|
|
114
114
|
"type": "integer"
|
|
115
115
|
},
|
|
116
116
|
"evade": {
|
|
117
|
-
"type": "
|
|
117
|
+
"type": "number"
|
|
118
118
|
},
|
|
119
119
|
"resist": {
|
|
120
120
|
"type": "integer"
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
|
|
3
|
+
const specials = [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"class": "Ninja",
|
|
7
|
+
"name": "Spectral strike",
|
|
8
|
+
"cooldown": 0,
|
|
9
|
+
"leaderPassive": "Sharpen blades"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": 2,
|
|
13
|
+
"class": "Enlightened",
|
|
14
|
+
"name": "Meditate",
|
|
15
|
+
"cooldown": 0,
|
|
16
|
+
"leaderPassive": "Cloud of Zen"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 3,
|
|
20
|
+
"class": "Cleaver",
|
|
21
|
+
"name": "Cleave",
|
|
22
|
+
"cooldown": 2,
|
|
23
|
+
"leaderPassive": "Frenzy"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": 4,
|
|
27
|
+
"class": "Tank",
|
|
28
|
+
"name": "Taunt",
|
|
29
|
+
"cooldown": 0,
|
|
30
|
+
"leaderPassive": "Fortify"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": 5,
|
|
34
|
+
"class": "Cursed",
|
|
35
|
+
"name": "Curse",
|
|
36
|
+
"cooldown": 0,
|
|
37
|
+
"leaderPassive": "Spread the fear"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": 6,
|
|
41
|
+
"class": "Healer",
|
|
42
|
+
"name": "Blessing",
|
|
43
|
+
"cooldown": 0,
|
|
44
|
+
"leaderPassive": "Cleansing Aura"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 7,
|
|
48
|
+
"class": "Mage",
|
|
49
|
+
"name": "Thunder",
|
|
50
|
+
"cooldown": 2,
|
|
51
|
+
"leaderPassive": "Channel the coven"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": 8,
|
|
55
|
+
"class": "Troll",
|
|
56
|
+
"name": "Devestating Smash",
|
|
57
|
+
"cooldown": 2,
|
|
58
|
+
"leaderPassive": "Clan momentum"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
const powerLevels = ['Godlike', 'Mythical', 'Legendary', 'Rare', 'Uncommon', 'Common', 'Garbage']
|
|
64
|
+
const traitCombos = [
|
|
65
|
+
'++++', '+++-', '++-+', '++--', '+-++', '+-+-', '+--+', '+---',
|
|
66
|
+
'-+++', '-++-', '-+-+', '-+--', '--++', '--+-', '---+', '----'
|
|
67
|
+
]
|
|
68
|
+
const classes = ['Ninja','Enlightened','Cleaver','Tank','Cursed','Healer', 'Mage', 'Troll']
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
// Create training gotchi objects like below for all combinations of powerLevels, traitCombos and classes
|
|
72
|
+
// {
|
|
73
|
+
// "id": 1,
|
|
74
|
+
// "snapshotBlock": 0,
|
|
75
|
+
// "onchainId": 1000001,
|
|
76
|
+
// "name": "Godlike ++++ Ninja",
|
|
77
|
+
// "brs": 783,
|
|
78
|
+
// "nrg": 110,
|
|
79
|
+
// "agg": 98,
|
|
80
|
+
// "spk": 101,
|
|
81
|
+
// "brn": 107,
|
|
82
|
+
// "eyc": 94,
|
|
83
|
+
// "eys": 94,
|
|
84
|
+
// "kinship": 0,
|
|
85
|
+
// "xp": 0,
|
|
86
|
+
// "speed": 161,
|
|
87
|
+
// "health": 587,
|
|
88
|
+
// "crit": 25,
|
|
89
|
+
// "armor": 0,
|
|
90
|
+
// "evade": 16,
|
|
91
|
+
// "resist": 0,
|
|
92
|
+
// "magic": 486,
|
|
93
|
+
// "physical": 196,
|
|
94
|
+
// "accuracy": 95,
|
|
95
|
+
// "attack": "magic",
|
|
96
|
+
// "actionDelay": 0.617,
|
|
97
|
+
// "specialId": 1,
|
|
98
|
+
// "svgFront": "https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/ninja_godlike_front.png",
|
|
99
|
+
// "svgBack": "https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/ninja_godlike_back.png",
|
|
100
|
+
// "svgLeft": "https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/ninja_godlike_left.png",
|
|
101
|
+
// "svgRight": "https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/ninja_godlike_right.png",
|
|
102
|
+
// "createdAt": "2023-09-09 12:10:01",
|
|
103
|
+
// "updatedAt": "2024-06-05 16:34:00",
|
|
104
|
+
// "special": {
|
|
105
|
+
// "id": 1,
|
|
106
|
+
// "class": "Ninja",
|
|
107
|
+
// "name": "Spectral strike",
|
|
108
|
+
// "cooldown": 0,
|
|
109
|
+
// "leaderPassive": "Sharpen blades"
|
|
110
|
+
// }
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
const main = (version) => {
|
|
114
|
+
const trainingGotchisTraits = require(`./v${version}/training_gotchis_traits.json`)
|
|
115
|
+
const { mapGotchi } = require(`./v${version}/mapGotchi.js`)
|
|
116
|
+
|
|
117
|
+
const trainingGotchis = []
|
|
118
|
+
|
|
119
|
+
let id = 1
|
|
120
|
+
traitCombos.forEach((t) => {
|
|
121
|
+
powerLevels.forEach((p) => {
|
|
122
|
+
for (let index = 0; index < t.length; index ++) {
|
|
123
|
+
const c = t[index]
|
|
124
|
+
|
|
125
|
+
const gotchi = {
|
|
126
|
+
id,
|
|
127
|
+
snapshotBlock: 0,
|
|
128
|
+
onchainId: 1000000 + id,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Based on the position of the trait in the traitCombos array, we can determine the class of the gotchi
|
|
132
|
+
// e.g. if the first trait is positive then add ninja, if it's negative then add enlightened
|
|
133
|
+
const className = classes[index * 2 + (c === '+' ? 0 : 1)]
|
|
134
|
+
|
|
135
|
+
// e.g Godlike ++++ Mage
|
|
136
|
+
gotchi.name = `${p} ${t} ${className}`
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* This is for versions <= 1.7.2
|
|
140
|
+
*/
|
|
141
|
+
// const trainingGotchiTraits = trainingGotchisTraits[p.toLowerCase()][className.toLowerCase()]
|
|
142
|
+
|
|
143
|
+
// if (!trainingGotchiTraits) {
|
|
144
|
+
// throw new Error(`No traits found for ${p} ${className}`)
|
|
145
|
+
// }
|
|
146
|
+
|
|
147
|
+
// gotchi.brs = trainingGotchiTraits.brs
|
|
148
|
+
// gotchi.nrg = trainingGotchiTraits.nrg[t[0] === '-' ? 0 : 1]
|
|
149
|
+
// gotchi.agg = trainingGotchiTraits.agg[t[1] === '-' ? 0 : 1]
|
|
150
|
+
// gotchi.spk = trainingGotchiTraits.spk[t[2] === '-' ? 0 : 1]
|
|
151
|
+
// gotchi.brn = trainingGotchiTraits.brn[t[3] === '-' ? 0 : 1]
|
|
152
|
+
// gotchi.eys = trainingGotchiTraits.eys[1] // These are always in index 1
|
|
153
|
+
// gotchi.eyc = trainingGotchiTraits.eyc[1] // These are always in index 1
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* This is for versions >= 1.7.3
|
|
157
|
+
*/
|
|
158
|
+
const trainingGotchiTraits = trainingGotchisTraits[p.toLowerCase()]
|
|
159
|
+
|
|
160
|
+
if (!trainingGotchiTraits) {
|
|
161
|
+
throw new Error(`No traits found for ${p}`)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
gotchi.brs = trainingGotchiTraits.brs
|
|
165
|
+
gotchi.nrg = trainingGotchiTraits.traits[t[0] === '-' ? 0 : 1]
|
|
166
|
+
gotchi.agg = trainingGotchiTraits.traits[t[1] === '-' ? 0 : 1]
|
|
167
|
+
gotchi.spk = trainingGotchiTraits.traits[t[2] === '-' ? 0 : 1]
|
|
168
|
+
gotchi.brn = trainingGotchiTraits.traits[t[3] === '-' ? 0 : 1]
|
|
169
|
+
gotchi.eys = trainingGotchiTraits.eyes
|
|
170
|
+
gotchi.eyc = trainingGotchiTraits.eyes
|
|
171
|
+
|
|
172
|
+
gotchi.kinship = 0
|
|
173
|
+
gotchi.xp = 0
|
|
174
|
+
|
|
175
|
+
// Map the in game stats to the gotchi
|
|
176
|
+
mapGotchi(gotchi)
|
|
177
|
+
gotchi.attack = t[3] === '-' ? 'physical' : 'magic'
|
|
178
|
+
gotchi.actionDelay = Math.round(((100 / gotchi.speed) + Number.EPSILON) * 1000) / 1000
|
|
179
|
+
|
|
180
|
+
gotchi.specialId = classes.indexOf(className) + 1
|
|
181
|
+
gotchi.svgFront = `https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/${className.toLowerCase()}_${p.toLowerCase()}_front.png`
|
|
182
|
+
gotchi.svgBack = `https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/${className.toLowerCase()}_${p.toLowerCase()}_back.png`
|
|
183
|
+
gotchi.svgLeft = `https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/${className.toLowerCase()}_${p.toLowerCase()}_left.png`
|
|
184
|
+
gotchi.svgRight = `https://storage.googleapis.com/gotchi-battler-qa_gotchis/training/${className.toLowerCase()}_${p.toLowerCase()}_right.png`
|
|
185
|
+
gotchi.createdAt = "2023-09-09 12:10:01"
|
|
186
|
+
gotchi.updatedAt = "2024-06-05 16:34:00"
|
|
187
|
+
gotchi.special = specials.find(s => s.id === gotchi.specialId)
|
|
188
|
+
|
|
189
|
+
trainingGotchis.push(gotchi)
|
|
190
|
+
|
|
191
|
+
id++
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const avgGotchis = createAvgGotchs(trainingGotchis)
|
|
197
|
+
|
|
198
|
+
trainingGotchis.push(...avgGotchis)
|
|
199
|
+
|
|
200
|
+
fs.writeFileSync(`./training_gotchis.json`, JSON.stringify(trainingGotchis, null, 2))
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const createAvgGotchs = (trainingGotchis) => {
|
|
204
|
+
const statsToOverwrite = ["speed", "health", "crit", "armor", "evade", "resist", "accuracy"]
|
|
205
|
+
|
|
206
|
+
const avgGotchis = [];
|
|
207
|
+
|
|
208
|
+
// Add magic gotchis
|
|
209
|
+
['magic', 'physical'].forEach((brainValue) => {
|
|
210
|
+
powerLevels.forEach((powerLevel) => {
|
|
211
|
+
classes.forEach((className) => {
|
|
212
|
+
// Find all gotchis with the same class and power level
|
|
213
|
+
// Names are in the format "Godlike ++++ Ninja"
|
|
214
|
+
const gotchis = trainingGotchis.filter(gotchi => gotchi.name.includes(powerLevel) && gotchi.name.includes(className))
|
|
215
|
+
|
|
216
|
+
// Copy over one of the gotchis
|
|
217
|
+
const avgGotchi = JSON.parse(JSON.stringify(gotchis[0]))
|
|
218
|
+
|
|
219
|
+
// Add an id
|
|
220
|
+
avgGotchi.id = trainingGotchis.length + avgGotchis.length + 1
|
|
221
|
+
|
|
222
|
+
// Overwrite the name
|
|
223
|
+
avgGotchi.name = `${powerLevel} avg-${brainValue} ${className}`
|
|
224
|
+
|
|
225
|
+
// Overwrite the stats
|
|
226
|
+
statsToOverwrite.forEach((stat) => {
|
|
227
|
+
const total = gotchis.reduce((acc, gotchi) => acc + gotchi[stat], 0)
|
|
228
|
+
|
|
229
|
+
if (['speed', 'health', 'armor', 'resist', 'magic', 'physical', 'accuracy'].includes(stat)) {
|
|
230
|
+
avgGotchi[stat] = Math.round(total / gotchis.length)
|
|
231
|
+
} else {
|
|
232
|
+
// Round to 2 decimal places
|
|
233
|
+
avgGotchi[stat] = Math.round((total / gotchis.length) * 100) / 100
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
// Get the highest/lowest magic value
|
|
238
|
+
const magicValues = gotchis.map(gotchi => gotchi.magic)
|
|
239
|
+
const highestMagic = Math.max(...magicValues)
|
|
240
|
+
const lowestMagic = Math.min(...magicValues)
|
|
241
|
+
|
|
242
|
+
// Get the highest/lowest physical value
|
|
243
|
+
const physicalValues = gotchis.map(gotchi => gotchi.physical)
|
|
244
|
+
const highestPhysical = Math.max(...physicalValues)
|
|
245
|
+
const lowestPhysical = Math.min(...physicalValues)
|
|
246
|
+
|
|
247
|
+
// If this is a magic gotchi then set the magic value to the highest
|
|
248
|
+
if (brainValue === 'magic') {
|
|
249
|
+
avgGotchi.magic = highestMagic
|
|
250
|
+
avgGotchi.physical = lowestPhysical
|
|
251
|
+
avgGotchi.attack = 'magic'
|
|
252
|
+
} else {
|
|
253
|
+
avgGotchi.magic = lowestMagic
|
|
254
|
+
avgGotchi.physical = highestPhysical
|
|
255
|
+
avgGotchi.attack = 'physical'
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
avgGotchis.push(avgGotchi)
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
return avgGotchis
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// node scripts/balancing/createTrainingGotchis.js
|
|
267
|
+
main('1.7.3')
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const trainingGotchis = require('./v1.7/training_gotchis.json')
|
|
3
|
+
|
|
4
|
+
const onchainTraitNames = [
|
|
5
|
+
'nrg',
|
|
6
|
+
'agg',
|
|
7
|
+
'spk',
|
|
8
|
+
'brn',
|
|
9
|
+
'eys',
|
|
10
|
+
'eyc'
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
const main = () => {
|
|
14
|
+
const onchainTraits = {}
|
|
15
|
+
|
|
16
|
+
// Loop through all training gotchis ids 1-448 and extract the onchain traits
|
|
17
|
+
for (let i = 1; i < 449; i++) {
|
|
18
|
+
const gotchi = trainingGotchis[i]
|
|
19
|
+
|
|
20
|
+
const powerLevel = gotchi.name.split(' ')[0].toLowerCase()
|
|
21
|
+
const gotchiClass = gotchi.name.split(' ')[2].toLowerCase()
|
|
22
|
+
|
|
23
|
+
if (!onchainTraits[powerLevel]) {
|
|
24
|
+
onchainTraits[powerLevel] = {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!onchainTraits[powerLevel][gotchiClass]) {
|
|
28
|
+
onchainTraits[powerLevel][gotchiClass] = {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!onchainTraits[powerLevel][gotchiClass].brs) {
|
|
32
|
+
onchainTraits[powerLevel][gotchiClass].brs = gotchi.brs
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onchainTraitNames.forEach((trait) => {
|
|
36
|
+
if (!onchainTraits[powerLevel][gotchiClass][trait]) {
|
|
37
|
+
onchainTraits[powerLevel][gotchiClass][trait] = []
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (gotchi[trait] < 50) {
|
|
41
|
+
if (!onchainTraits[powerLevel][gotchiClass][trait][0]) {
|
|
42
|
+
onchainTraits[powerLevel][gotchiClass][trait][0] = gotchi[trait]
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
if (!onchainTraits[powerLevel][gotchiClass][trait][1]) {
|
|
46
|
+
onchainTraits[powerLevel][gotchiClass][trait][1] = gotchi[trait]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fs.writeFileSync('./training_gotchis_traits.json', JSON.stringify(onchainTraits, (key, value) => {
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
return JSON.stringify(value); // Convert array to a string
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}, 2).replace(/"\[(.*?)\]"/g, "[$1]"))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// node scripts/balancing/extractOnchainTraits.js
|
|
61
|
+
main()
|
|
@@ -196,7 +196,7 @@ const main = async (executionId, numOfTasks, gameLogicVersion) => {
|
|
|
196
196
|
})
|
|
197
197
|
|
|
198
198
|
if(process.env.CLOUD_RUN_JOB) {
|
|
199
|
-
const bucket = storage.bucket('gotchi-battler-sims-v1-7-
|
|
199
|
+
const bucket = storage.bucket('gotchi-battler-sims-v1-7-3')
|
|
200
200
|
|
|
201
201
|
// Get number of files in the bucket
|
|
202
202
|
const [files] = await bucket.getFiles()
|
|
@@ -259,9 +259,9 @@ module.exports = runSims
|
|
|
259
259
|
// 2nd argument is the sims version
|
|
260
260
|
// 3rd argument is the game logic version
|
|
261
261
|
// 4th argument is the number of sims per matchup
|
|
262
|
-
// node scripts/balancing/sims.js 0 v1.7.
|
|
262
|
+
// node scripts/balancing/sims.js 0 v1.7.3 v1.7 3 true
|
|
263
263
|
if (require.main === module) {
|
|
264
|
-
const simsVersion = process.env.SIMS_VERSION || process.argv[3] || 'v1.7.
|
|
264
|
+
const simsVersion = process.env.SIMS_VERSION || process.argv[3] || 'v1.7.3'
|
|
265
265
|
const gameLogicVersion = process.env.GAME_LOGIC_VERSION || process.argv[4] || 'v1.7'
|
|
266
266
|
const simsPerMatchup = parseInt(process.env.SIMS_PER_MATCHUP) || parseInt(process.argv[5]) || 3
|
|
267
267
|
const useAvg = process.env.USE_AVG || process.argv[6] === 'true' || false
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const mapTeam = (team) => {
|
|
2
|
+
for(const gotchi of team.formation.front) {
|
|
3
|
+
if (gotchi) mapGotchi(gotchi)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
for(const gotchi of team.formation.back) {
|
|
7
|
+
if (gotchi) mapGotchi(gotchi)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// This is copied/hacked from the mapGotchi function in the backend
|
|
12
|
+
const mapGotchi = (gotchi) => {
|
|
13
|
+
const traitMaps = {
|
|
14
|
+
speed: {
|
|
15
|
+
baseFormula: 100,
|
|
16
|
+
multiplier: 1,
|
|
17
|
+
traitKey: 0,
|
|
18
|
+
isNegative: false
|
|
19
|
+
},
|
|
20
|
+
health: {
|
|
21
|
+
baseFormula: 'brs*0.75',
|
|
22
|
+
multiplier: 12,
|
|
23
|
+
traitKey: 0,
|
|
24
|
+
isNegative: true
|
|
25
|
+
},
|
|
26
|
+
crit: {
|
|
27
|
+
baseFormula: 0,
|
|
28
|
+
multiplier: 0.5,
|
|
29
|
+
traitKey: 1,
|
|
30
|
+
isNegative: false
|
|
31
|
+
},
|
|
32
|
+
armor: {
|
|
33
|
+
baseFormula: 0,
|
|
34
|
+
multiplier: 2,
|
|
35
|
+
traitKey: 1,
|
|
36
|
+
isNegative: true
|
|
37
|
+
},
|
|
38
|
+
evade: {
|
|
39
|
+
baseFormula: 0,
|
|
40
|
+
multiplier: 0.3,
|
|
41
|
+
traitKey: 2,
|
|
42
|
+
isNegative: false
|
|
43
|
+
},
|
|
44
|
+
resist: {
|
|
45
|
+
baseFormula: 0,
|
|
46
|
+
multiplier: 1,
|
|
47
|
+
traitKey: 2,
|
|
48
|
+
isNegative: true
|
|
49
|
+
},
|
|
50
|
+
magic: {
|
|
51
|
+
baseFormula: 'brs*0.25',
|
|
52
|
+
multiplier: 5,
|
|
53
|
+
traitKey: 3,
|
|
54
|
+
isNegative: false
|
|
55
|
+
},
|
|
56
|
+
physical: {
|
|
57
|
+
baseFormula: 'brs*0.25',
|
|
58
|
+
multiplier: 5,
|
|
59
|
+
traitKey: 3,
|
|
60
|
+
isNegative: true
|
|
61
|
+
},
|
|
62
|
+
accuracy: {
|
|
63
|
+
baseFormula: 50,
|
|
64
|
+
multiplier: 0.5,
|
|
65
|
+
traitKey: 45,
|
|
66
|
+
isNegative: false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const traitValue = (trait) => {
|
|
71
|
+
return trait < 50 ? 50 - trait : trait - 50 + 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const onchainVals = [
|
|
75
|
+
gotchi.nrg,
|
|
76
|
+
gotchi.agg,
|
|
77
|
+
gotchi.spk,
|
|
78
|
+
gotchi.brn,
|
|
79
|
+
gotchi.eyc,
|
|
80
|
+
gotchi.eys
|
|
81
|
+
]
|
|
82
|
+
// Convert trait value to in-game value
|
|
83
|
+
const traitValues = onchainVals.map(x => { return traitValue(x) })
|
|
84
|
+
|
|
85
|
+
// Map traits
|
|
86
|
+
for(const trait in traitMaps) {
|
|
87
|
+
const traitMap = traitMaps[trait]
|
|
88
|
+
const onchainVal = onchainVals[traitMap.traitKey]
|
|
89
|
+
|
|
90
|
+
let base = traitMap.baseFormula
|
|
91
|
+
|
|
92
|
+
// If baseFormula is a string and contains a * then it is a formula
|
|
93
|
+
if (typeof traitMap.baseFormula === 'string' && traitMap.baseFormula.includes('*')) {
|
|
94
|
+
const formula = traitMap.baseFormula.split('*')
|
|
95
|
+
|
|
96
|
+
if (!gotchi[formula[0]]) throw new Error('Trait not found: ', formula[0])
|
|
97
|
+
|
|
98
|
+
base = Math.round(Number(gotchi[formula[0]]) * Number(formula[1]))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let newTrait
|
|
102
|
+
if (trait !== 'accuracy') {
|
|
103
|
+
if (traitMap.isNegative) {
|
|
104
|
+
newTrait = onchainVal < 50 ? Math.round(base + (traitValues[traitMap.traitKey] * traitMap.multiplier)) : base
|
|
105
|
+
} else {
|
|
106
|
+
newTrait = onchainVal < 50 ? base : Math.round(base + (traitValues[traitMap.traitKey] * traitMap.multiplier))
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
newTrait = base + ((traitValues[4] + traitValues[5]) * traitMap.multiplier)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (newTrait !== gotchi[trait]) gotchi[trait] = newTrait
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
mapGotchi,
|
|
118
|
+
mapTeam
|
|
119
|
+
}
|