()
| 477 | } |
| 478 | |
| 479 | getHeroStats () { |
| 480 | // Translate from raw hero properties into appropriate display values for the PlayHeroesModal. |
| 481 | // Adapted from https://docs.google.com/a/codecombat.com/spreadsheets/d/1BGI1bzT4xHvWA81aeyIaCKWWw9zxn7-MwDdydmB5vw4/edit#gid=809922675 |
| 482 | const heroClass = this.get('heroClass') |
| 483 | if (!heroClass) return |
| 484 | if (this.get('kind') === 'Junior Hero') return |
| 485 | |
| 486 | const components = this.get('components') || [] |
| 487 | const equipsConfig = components.find(c => c.original === LevelComponent.EquipsID)?.config |
| 488 | const movesConfig = components.find(c => c.original === LevelComponent.MovesID)?.config |
| 489 | |
| 490 | if (!equipsConfig) { |
| 491 | console.warn(`${this.get('name')} is not an equipping hero, but you are asking for its hero stats. (Did you project away components?)`) |
| 492 | return |
| 493 | } |
| 494 | |
| 495 | if (!movesConfig) { |
| 496 | console.warn(`${this.get('name')} is not a moving hero, but you are asking for its hero stats.`) |
| 497 | return |
| 498 | } |
| 499 | |
| 500 | const programmableConfig = components.find(c => LevelComponent.ProgrammableIDs.includes(c.original))?.config |
| 501 | if (!programmableConfig) { |
| 502 | console.warn(`${this.get('name')} is not a Programmable hero, but you are asking for its hero stats.`) |
| 503 | return |
| 504 | } |
| 505 | |
| 506 | this.classStatAverages ??= { |
| 507 | attack: { Warrior: 7.5, Ranger: 5, Wizard: 2.5 }, |
| 508 | health: { Warrior: 7.5, Ranger: 5, Wizard: 3.5 }, |
| 509 | } |
| 510 | |
| 511 | const rawNumbers = { |
| 512 | attack: equipsConfig.attackDamageFactor ?? 1, |
| 513 | health: equipsConfig.maxHealthFactor ?? 1, |
| 514 | speed: movesConfig.maxSpeed, |
| 515 | } |
| 516 | |
| 517 | const stats = {} |
| 518 | |
| 519 | for (const prop of ['attack', 'health']) { |
| 520 | const stat = rawNumbers[prop] |
| 521 | const classSpecificScore = stat < 1 ? 10 - (5 / stat) : stat * 5 |
| 522 | const classAverage = this.classStatAverages[prop][heroClass] |
| 523 | |
| 524 | stats[prop] = { |
| 525 | relative: Math.round(2 * ((classAverage - 2.5) + (classSpecificScore / 2))) / 2 / 10, |
| 526 | absolute: stat |
| 527 | } |
| 528 | const pieces = ([1, 2, 3].map((num) => $.i18n.t(`choose_hero.${prop}_${num}`))) |
| 529 | const percent = Math.round(stat * 100) + '%' |
| 530 | const className = $.i18n.t(`general.${_.string.slugify(this.get('heroClass'))}`) |
| 531 | stats[prop].description = [pieces[0], percent, pieces[1], className, pieces[2]].join(' ') |
| 532 | } |
| 533 | |
| 534 | const minSpeed = 4 |
| 535 | const maxSpeed = 16 |
| 536 | const speedRange = maxSpeed - minSpeed |
no test coverage detected