forked from wowsims/wotlk
/
runic_power_helper.go
160 lines (138 loc) · 3.31 KB
/
runic_power_helper.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package core
import (
"fmt"
"time"
)
type RuneCost uint16
func NewRuneCost(rp, blood, frost, unholy, death uint8) RuneCost {
value := int16(0)
if blood == 1 {
value = 1
} else if blood == 2 {
value = 3
}
if frost == 1 {
value += 1 << 2
} else if frost == 2 {
value += 3 << 2
}
if unholy == 1 {
value += 1 << 4
} else if unholy == 2 {
value += 3 << 4
}
if death == 1 {
value += 1 << 6
} else if death == 2 {
value += 3 << 6
} else if death > 2 {
value += 3 << 6 // we cant represent more than 2 death runes
}
value += int16(rp) << 8
return RuneCost(value)
}
func (rc RuneCost) String() string {
return fmt.Sprintf("RP: %d, Blood: %d, Frost: %d, Unholy: %d, Death: %d", rc.RunicPower(), rc.Blood(), rc.Frost(), rc.Unholy(), rc.Death())
}
// HasRune returns if this cost includes a rune portion.
//
// If any bit is set in the rune bits it means that there is a rune cost.
func (rc RuneCost) HasRune() bool {
const runebits = int16(0b11111111)
return runebits&int16(rc) > 0
}
func (rc RuneCost) RunicPower() uint8 {
const rpbits = uint16(0b1111111100000000)
return uint8((uint16(rc) & rpbits) >> 8)
}
func (rc RuneCost) Blood() uint8 {
runes := uint16(rc) & 0b11
switch runes {
case 0b00:
return 0
case 0b01:
return 1
case 0b11:
return 2
}
return 0
}
func (rc RuneCost) Frost() uint8 {
runes := uint16(rc) & 0b1100
switch runes {
case 0:
return 0
case 0b0100:
return 1
case 0b1100:
return 2
}
return 0
}
func (rc RuneCost) Unholy() uint8 {
runes := uint16(rc) & 0b110000
switch runes {
case 0:
return 0
case 0b010000:
return 1
case 0b110000:
return 2
}
return 0
}
func (rc RuneCost) Death() uint8 {
runes := uint16(rc) & 0b11000000
switch runes {
case 0:
return 0
case 0b01000000:
return 1
case 0b11000000:
return 2
}
return 0
}
func (rp *RunicPowerBar) GainDeathRuneMetrics(sim *Simulation, spell *Spell, currRunes int32, newRunes int32) {
if !rp.isACopy {
metrics := rp.deathRuneGainMetrics
metrics.AddEvent(1, float64(newRunes)-float64(currRunes))
if sim.Log != nil {
rp.unit.Log(sim, "Gained 1.000 death rune from %s (%d --> %d).", metrics.ActionID, currRunes, newRunes)
}
}
}
func (rp *RunicPowerBar) CancelBloodTap(sim *Simulation) {
if rp.btslot == -1 {
return
}
rp.ConvertFromDeath(sim, rp.btslot)
bloodTapAura := rp.unit.GetAura("Blood Tap")
bloodTapAura.Deactivate(sim)
rp.btslot = -1
}
func (rp *RunicPowerBar) CorrectBloodTapConversion(sim *Simulation, bloodGainMetrics *ResourceMetrics, deathGainMetrics *ResourceMetrics, spell *Spell) {
// 1. converts a blood rune -> death rune
// 2. then convert one inactive blood or death rune -> active
slot := int8(-1)
if rp.runeStates&isDeaths[0] == 0 {
slot = 0
} else if rp.runeStates&isDeaths[1] == 0 {
slot = 1
}
if slot > -1 {
rp.btslot = slot
rp.ConvertToDeath(sim, slot, sim.CurrentTime+time.Second*20)
}
slot = -1
if rp.runeStates&isSpents[0] == isSpents[0] {
slot = 0
} else if rp.runeStates&isSpents[1] == isSpents[1] {
slot = 1
}
if slot > -1 {
rp.RegenRune(sim, sim.CurrentTime, slot)
}
// if PA isn't running, make it run 20s from now to disable BT
rp.launchPA(sim, sim.CurrentTime+20.0*time.Second)
}