/
calc.go
122 lines (119 loc) · 3.71 KB
/
calc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package pokemonbattlelib
func CalcMoveDamage(weather Weather, user, receiver *Pokemon, move *Move) (damage uint) {
switch move.Id {
// Fixed damage moves
case MoveSuperFang:
return uint(receiver.CurrentHP / 2)
// Moves that use damage formula
default:
// Compute base damage
levelEffect := uint((2 * user.Level / 5) + 2)
movePower := move.Power()
attack := user.Attack()
defense := receiver.Defense()
// Move modifiers
if move.Category() == MoveCategorySpecial {
attack = user.SpecialAttack()
defense = receiver.SpecialDefense()
}
// Weather modifiers
if weather == WeatherSandstorm {
if receiver.EffectiveType()&TypeRock != 0 {
defense = (defense * 150) / 100
}
if move.Id == MoveSolarBeam {
movePower /= 2
}
}
if weather == WeatherHail && move.Id == MoveSolarBeam {
movePower /= 2
}
if weather == WeatherFog {
if move.Id == MoveWeatherBall {
movePower *= 2
} else if move.Id == MoveSolarBeam {
movePower /= 2
}
}
damage = uint((((levelEffect * movePower * attack / defense) / 50) + 2))
}
// Other modifiers
moveType := move.Type()
if move.Id == MoveJudgment && user.HeldItem.Category() == ItemCategoryPlates {
moveType = typeItemData[user.HeldItem]
}
elementalEffect := GetElementalEffect(moveType, receiver.EffectiveType())
// Account for ground type moves on grounded Pokemon
if moveType&TypeGround > 0 && receiver.Type&TypeFlying > 0 && receiver.IsGrounded() {
elementalEffect -= NoEffect
}
if move.Id == MoveStruggle {
elementalEffect = 0
}
if elementalEffect > NormalEffect {
damage <<= elementalEffect
} else if elementalEffect < NormalEffect {
damage >>= elementalEffect * -1 // bitshift operand must be positive
}
if user.Ability == AbilityIronFist && move.Flags()&FlagPunch != 0 {
damage = (damage * 120) / 100
}
// Weather type modifier
if rain, sun := weather == WeatherRain, weather == WeatherHarshSunlight; (rain && move.Type() == TypeWater) || (sun && move.Type() == TypeFire) {
damage = (damage * 150) / 100
} else if (rain && moveType == TypeFire) || (sun && moveType == TypeWater) {
damage /= 2
}
// Stab modifier
if move != nil && move.Id != MoveStruggle && user.EffectiveType()&moveType != 0 {
if user.Ability == AbilityAdaptability {
damage *= 2
} else {
damage = (damage * 150) / 100
}
}
// Item modifiers
switch user.HeldItem {
case ItemExpertBelt:
if elementalEffect >= SuperEffective {
damage = (damage * 120) / 100
}
case ItemChoiceBand, ItemChoiceScarf, ItemChoiceSpecs:
if lastMove := user.metadata[MetaLastMove]; lastMove != nil && lastMove != move {
blog.Panicf("cannot use move blocked by %s", user.HeldItem.Name())
}
case ItemLifeOrb:
damage = (damage * 130) / 100
case ItemMuscleBand:
if move.Category() == MoveCategoryPhysical {
damage = (damage * 110) / 100
}
case ItemWiseGlasses:
if move.Category() == MoveCategorySpecial {
damage = (damage * 110) / 100
}
}
if c := user.HeldItem.Category(); c == ItemCategoryPlates || c == ItemCategoryTypeEnhancement {
if moveType == typeItemData[user.HeldItem] {
damage = (damage * 120) / 100
}
}
return damage
}
// Calculate the accuracy of a move, accounting for weather/evasion/held items/etc.
func CalcAccuracy(weather Weather, user, receiver *Pokemon, move *Move) uint {
evasion := receiver.Evasion()
accuracy := (move.Accuracy() * user.Accuracy() * evasion) / (100 * 100) // multiply by 100 twice because the user's accuracy and target's evasion are out of 100
if weather == WeatherFog {
accuracy = (accuracy * 3) / 5
}
switch user.HeldItem {
case ItemWideLens:
accuracy = (accuracy * 110) / 100
}
switch receiver.HeldItem {
case ItemBrightPowder, ItemLaxIncense:
accuracy -= accuracy / 10
}
return accuracy
}