Skip to content

Commit

Permalink
feat: apply HotA 1.7.2 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
rudnovd committed Jan 1, 2025
1 parent 200ac39 commit 7e26088
Show file tree
Hide file tree
Showing 16 changed files with 250 additions and 140 deletions.
12 changes: 6 additions & 6 deletions src/assets/database/creatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3098,7 +3098,7 @@ export const creatures: Array<Creature> = [
ranged: true,
hexes: 2,
speed: 0,
cost: { gold: 2500 },
cost: { gold: 1500 },
shots: 24,
description: 'Ranged (24 Shots)',
},
Expand Down Expand Up @@ -3507,7 +3507,7 @@ export const creatures: Array<Creature> = [
ranged: true,
hexes: 2,
speed: 0,
cost: { gold: 4000 },
cost: { gold: 3000 },
shots: 8,
description: 'Ranged (8 shots)',
},
Expand Down Expand Up @@ -3583,7 +3583,7 @@ export const creatures: Array<Creature> = [
townId: Towns.Factory,
attack: 6,
defense: 5,
minDamage: 2,
minDamage: 3,
maxDamage: 4,
health: 14,
speed: 6,
Expand All @@ -3603,7 +3603,7 @@ export const creatures: Array<Creature> = [
townId: Towns.Factory,
attack: 7,
defense: 5,
minDamage: 2,
minDamage: 3,
maxDamage: 5,
health: 16,
speed: 7,
Expand Down Expand Up @@ -3856,7 +3856,7 @@ export const creatures: Array<Creature> = [
level: 7,
ranged: false,
cost: {
gold: 2500,
gold: 2200,
crystal: 1,
},
description: 'Mechanical, Can attack with a Heat stroke instead of moving',
Expand All @@ -3878,7 +3878,7 @@ export const creatures: Array<Creature> = [
level: 7,
ranged: false,
cost: {
gold: 4000,
gold: 3500,
crystal: 2,
},
description: 'Mechanical, Can attack with a Heat stroke instead of moving',
Expand Down
13 changes: 10 additions & 3 deletions src/components/PageFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
<a href="https://github.com/rudnovd/heroes3tools" target="_blank" rel="noopener">
🌟{{ t('components.pageFooter.sourceCode') }}
</a>
<a href="https://t.me/heroes3toolsbot" target="_blank" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brand-telegram"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4" /></svg>
<a href="https://t.me/heroes3toolsbot" class="telegram-link" target="_blank" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brand-telegram"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4" /></svg>
Telegram version
</a>
<span>{{ t('components.pageFooter.hotaVersion') }}: 1.7.1</span>
<span>{{ t('components.pageFooter.hotaVersion') }}: 1.7.2</span>
<component
:is="needRefresh ? 'button' : 'span'"
:class="{ 'need-refresh': needRefresh }"
Expand Down Expand Up @@ -175,6 +176,12 @@ footer {
}
}
.telegram-link {
display: inline-flex;
gap: 2px;
align-items: center;
}
.need-refresh {
color: red;
Expand Down
44 changes: 33 additions & 11 deletions src/models/Battle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ export class Battle {
modifiedDefenderCreature = this.calculateWithNegativeEffects(this.attacker, modifiedDefenderCreature)

if (this.attacker.hero) {
modifiedAttackerCreature = this.calculateWithHeroModificators(this.attacker.hero, modifiedAttackerCreature)
modifiedAttackerCreature = this.calculateWithHeroModifiers(this.attacker.hero, modifiedAttackerCreature)
}
if (this.defender.hero) {
modifiedDefenderCreature = this.calculateWithHeroModificators(this.defender.hero, modifiedDefenderCreature)
modifiedDefenderCreature = this.calculateWithHeroModifiers(this.defender.hero, modifiedDefenderCreature)
}

if (this.attacker.terrain && this.defender.terrain) {
Expand All @@ -103,6 +103,24 @@ export class Battle {
const attackerCalculation = this.calculateDamageValues(modifiedAttackerCreature, modifiedDefenderCreature)
const defenderCalculation = this.calculateDamageValues(modifiedDefenderCreature, modifiedAttackerCreature)

const isMachine = modifiedAttackerCreature.id === Creatures.Cannon || modifiedAttackerCreature.id === Creatures.Ballista
if (this.attacker.hero?.skills.artillery && isMachine) {
defenderCalculation.minDamage = Math.floor(defenderCalculation.minDamage * 0.4)
defenderCalculation.maxDamage = Math.floor(defenderCalculation.maxDamage * 0.4)
defenderCalculation.averageDamage = Math.floor(defenderCalculation.averageDamage * 0.4)
defenderCalculation.minKills = Math.floor(defenderCalculation.minDamage / modifiedDefenderCreature.health)
defenderCalculation.maxKills = Math.floor(defenderCalculation.maxDamage / modifiedDefenderCreature.health)
defenderCalculation.averageKills = Math.floor(defenderCalculation.averageDamage / modifiedDefenderCreature.health)
}
if (this.defender.hero?.skills.artillery && isMachine) {
attackerCalculation.minDamage = Math.floor(attackerCalculation.minDamage * 0.4)
attackerCalculation.maxDamage = Math.floor(attackerCalculation.maxDamage * 0.4)
attackerCalculation.averageDamage = Math.floor(attackerCalculation.averageDamage * 0.4)
attackerCalculation.minKills = Math.floor(attackerCalculation.minDamage / modifiedAttackerCreature.health)
attackerCalculation.maxKills = Math.floor(attackerCalculation.maxDamage / modifiedAttackerCreature.health)
attackerCalculation.averageKills = Math.floor(attackerCalculation.averageDamage / modifiedAttackerCreature.health)
}

this.attacker.activeCreature = {
...this.attacker.activeCreature,
...modifiedAttackerCreature,
Expand Down Expand Up @@ -166,9 +184,10 @@ export class Battle {
return -Math.round(-damage)
}

private calculateWithHeroModificators(hero: HeroInstance, target: CreatureInstance) {
private calculateWithHeroModifiers(hero: HeroInstance, target: CreatureInstance) {
if (hero.specialtySpell)
target = Modificators.heroSpecialtySpell(hero, target)

target = Modificators.hero(hero, target)
target = Modificators.heroSkills(hero, target)
if (target.id === Creatures.Ballista || target.id === Creatures.Cannon) {
Expand Down Expand Up @@ -426,7 +445,13 @@ export class Battle {
damage += damage * 0.25
}
else if (spell.id === specialtySpell) {
const bonus = Math.floor(initiator.hero.level / target.level) * 0.03
let bonus: number
if ([Spells.MeteorShower, Spells.ChainLightning, Spells.Resurrection, Spells.AnimateDead].includes(spell.id)) {
bonus = Math.floor(initiator.hero.level / target.level) * 0.05
}
else {
bonus = Math.floor(initiator.hero.level / target.level) * 0.1
}
if (bonus) {
damage += Math.ceil(damage * bonus)
}
Expand All @@ -445,15 +470,12 @@ export class Battle {
return damage

if (initiator.hero.skills.sorcery) {
let sorceryBonus = initiator.hero.skills.sorcery * 0.05
let sorceryBonus = initiator.hero.skills.sorcery * 0.1

if (initiator.hero.specialtySkill === SecondarySkills.Sorcery) {
sorceryBonus += initiator.hero.level * 0.05
}

// Max sorcery bonus
if (sorceryBonus > 0.96) {
sorceryBonus = 0.96
const bonus = initiator.hero.level * 0.05
const MAX_SORCERY_BONUS = 0.96
sorceryBonus += initiator.hero.level * bonus > MAX_SORCERY_BONUS ? MAX_SORCERY_BONUS : bonus
}

damage += damage * sorceryBonus
Expand Down
2 changes: 1 addition & 1 deletion src/modules/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const Effects = {

// if battle side has hero with Bless specialty then add damageBonus value
if (initiator.hero && initiator.hero.specialtySpell === Spells.Bless) {
damageBonus += Math.floor(initiator.hero.level / target.level) * 0.03
damageBonus += Math.floor(initiator.hero.level / target.level) * 0.1
}

if (!initiator.hero || !initiator.hero.skills.water || initiator.hero.skills.water <= 1) {
Expand Down
113 changes: 91 additions & 22 deletions src/modules/modificators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,64 +10,90 @@ export const Modificators = {
switch (hero.specialtySpell) {
case Spells.Bloodlust:
if (target.level === 1 || target.level === 2) {
attack += 3
attack += 10
}
else if (target.level === 3 || target.level === 4) {
attack += 2
attack += 8
}
else if (target.level === 5 || target.level === 6) {
attack += 1
attack += 6
}
else if (target.level === 7) {
attack += 4
}
break
case Spells.Prayer:
if (target.level === 1 || target.level === 2) {
if (target.level === 1 || target.level === 2 || target.level === 3 || target.level === 4) {
attack += 3
defense += 3
}
else if (target.level === 3 || target.level === 4) {
else if (target.level === 5 || target.level === 6) {
attack += 2
defense += 2
}
else if (target.level === 5 || target.level === 6) {
else if (target.level === 7) {
attack += 1
defense += 1
}
break
case Spells.Precision:
if (target.level === 1 || target.level === 2) {
attack += 3
attack += 10
}
else if (target.level === 3 || target.level === 4) {
attack += 2
attack += 8
}
else if (target.level === 5 || target.level === 6) {
attack += 1
attack += 6
}
else if (target.level === 7) {
attack += 4
}
break
case Spells.StoneSkin:
if (target.level === 1 || target.level === 2) {
defense += 3
defense += 10
}
else if (target.level === 3 || target.level === 4) {
defense += 2
defense += 8
}
else if (target.level === 5 || target.level === 6) {
defense += 1
defense += 6
}
else if (target.level === 7) {
defense += 4
}
break
case Spells.Weakness:
if (target.level === 1 || target.level === 2) {
attack -= 3
attack -= 4
}
else if (target.level === 3 || target.level === 4) {
attack -= 2
attack -= 6
}
else if (target.level === 5 || target.level === 6) {
attack -= 1
attack -= 8
}
else if (target.level === 7) {
attack -= 10
}
break
case Spells.DisruptingRay:
defense -= 2
defense -= 10
break
case Spells.Slayer:
if (target.level === 1 || target.level === 2) {
attack += 20
}
else if (target.level === 3 || target.level === 4) {
attack += 16
}
else if (target.level === 5 || target.level === 6) {
attack += 12
}
else if (target.level === 7) {
attack += 8
}
break
default:
break
Expand Down Expand Up @@ -96,12 +122,53 @@ export const Modificators = {
},

hero: (hero: HeroInstance, target: CreatureInstance): CreatureInstance => {
let { attack, speed, defense } = target
let { attack, speed, defense, minDamage, maxDamage } = target

if (hero.specialtyUnit?.includes(target.id)) {
attack += Math.ceil(Math.floor(hero.level / target.level) * (attack * 0.05))
defense += Math.ceil(Math.floor(hero.level / target.level) * (defense * 0.05))
speed++
if (target.id === Creatures.WaterElemental || target.id === Creatures.IceElemental) {
attack += 12
}
else if (target.id === Creatures.FireElemental || target.id === Creatures.EnergyElemental) {
attack += 3
defense += 4
minDamage += 2
maxDamage += 2
}
else if (target.id === Creatures.EarthElemental || target.id === Creatures.MagmaElemental) {
attack += 3
defense += 2
minDamage += 5
maxDamage += 5
}
else if (target.id === Creatures.PsychicElemental || target.id === Creatures.MagicElemental) {
attack += 5
defense += 5
}
else if (target.id === Creatures.Devil || target.id === Creatures.ArchDevil) {
attack += 10
defense += 10
speed++
}
else if (target.id === Creatures.Behemoth || target.id === Creatures.AncientBehemoth) {
attack += 10
defense += 10
minDamage += 10
maxDamage += 10
}
else if (target.id === Creatures.Ballista) {
attack += Math.ceil(Math.floor(hero.level / target.level) * (attack * 0.3))
defense += Math.ceil(Math.floor(hero.level / target.level) * (defense * 0.3))
}
else if (target.level === 1) {
attack += Math.ceil(Math.floor(hero.level / target.level) * (attack * 0.1))
defense += Math.ceil(Math.floor(hero.level / target.level) * (defense * 0.1))
speed++
}
else {
attack += Math.ceil(Math.floor(hero.level / target.level) * (attack * 0.2))
defense += Math.ceil(Math.floor(hero.level / target.level) * (defense * 0.2))
speed++
}
}

attack += hero.stats.attack
Expand All @@ -111,6 +178,8 @@ export const Modificators = {
...target,
attack,
defense,
minDamage,
maxDamage,
speed,
}
},
Expand Down Expand Up @@ -200,8 +269,8 @@ export const Modificators = {
let { minDamage, maxDamage } = target

if (target.id === Creatures.Ballista) {
minDamage = (hero.stats.attack + 1) * 2
maxDamage = (hero.stats.attack + 1) * 3
minDamage = (hero.stats.attack + 5) * 2
maxDamage = (hero.stats.attack + 5) * 3
}
else if (target.id === Creatures.Cannon) {
minDamage = (hero.stats.attack + 1) * 4
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/effects/bless.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ describe('bless spell effect', () => {

const { attacker } = battle.calculate()

expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 75, maxDamage: 75 })
expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 81, maxDamage: 81 })
})

it('11 Ogre Magi vs 59 Halberdiers', () => {
Expand All @@ -219,7 +219,7 @@ describe('bless spell effect', () => {

const { attacker } = battle.calculate()

expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 225, maxDamage: 225 })
expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 244, maxDamage: 244 })
})

it('11 Ogre Magi vs 20 Halberdiers', () => {
Expand All @@ -238,7 +238,7 @@ describe('bless spell effect', () => {

const { attacker } = battle.calculate()

expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 245, maxDamage: 245 })
expect(attacker.activeCreature.calculation).toMatchObject({ minDamage: 264, maxDamage: 264 })
})
})

Expand Down
Loading

0 comments on commit 7e26088

Please sign in to comment.