Skip to content

Commit 660d294

Browse files
authored
Merge pull request #45 from wowsims/fix/monk-and-crit-multi
[WIP] Brewmaster/Windwalker implementation
2 parents edc6916 + d828a54 commit 660d294

79 files changed

Lines changed: 10709 additions & 1532 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

proto/apl.proto

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ message APLAction {
8585
}
8686
}
8787

88-
// NextIndex: 99
88+
// NextIndex: 100
8989
message APLValue {
9090
UUID uuid = 87;
9191

@@ -125,6 +125,7 @@ message APLValue {
125125
APLValueCurrentSolarEnergy current_solar_energy = 68;
126126
APLValueCurrentLunarEnergy current_lunar_energy = 69;
127127
APLValueCurrentGenericResource current_generic_resource = 75;
128+
APLValueMaxHealth max_health = 99;
128129
APLValueMaxComboPoints max_combo_points = 94;
129130
APLValueMaxEnergy max_energy = 88;
130131
APLValueMaxFocus max_focus = 89;
@@ -472,6 +473,7 @@ message APLValueCurrentRunicPower {}
472473
message APLValueCurrentSolarEnergy {}
473474
message APLValueCurrentLunarEnergy {}
474475
message APLValueCurrentGenericResource {}
476+
message APLValueMaxHealth {}
475477
message APLValueMaxComboPoints {}
476478
message APLValueMaxEnergy {}
477479
message APLValueMaxFocus {}
@@ -701,4 +703,4 @@ message APLValueShamanFireElementalDuration {
701703
}
702704

703705
message APLValueMonkCurrentChi {}
704-
message APLValueMonkMaxChi {}
706+
message APLValueMonkMaxChi {}

sim/common/cata/other_effects.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ func init() {
148148
Timer: sharedTimer,
149149
},
150150
},
151+
ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool {
152+
return character.HasManaBar()
153+
},
151154
ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) {
152155
for _, aoeTarget := range sim.Encounter.TargetUnits {
153156
spell.CalcAndDealDamage(sim, aoeTarget, storedMana, spell.OutcomeMagicHitAndCrit)
@@ -477,6 +480,9 @@ func init() {
477480
Duration: time.Minute * 2,
478481
},
479482
},
483+
ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool {
484+
return character.HasManaBar()
485+
},
480486
ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
481487
procAura.Deactivate(sim)
482488
// can not regain stacks for 30 seconds

sim/core/apl_value.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
122122
value = rot.newValueCurrentComboPoints(config.GetCurrentComboPoints(), config.Uuid)
123123
case *proto.APLValue_CurrentRunicPower:
124124
value = rot.newValueCurrentRunicPower(config.GetCurrentRunicPower(), config.Uuid)
125+
case *proto.APLValue_MaxHealth:
126+
value = rot.newValueMaxHealth(config.GetMaxHealth(), config.Uuid)
125127
case *proto.APLValue_MaxComboPoints:
126128
value = rot.newValueMaxComboPoints(config.GetMaxComboPoints(), config.Uuid)
127129
case *proto.APLValue_MaxEnergy:

sim/core/apl_values_resources.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ func (value *APLValueCurrentHealthPercent) String() string {
6363
return fmt.Sprintf("Current Health %%")
6464
}
6565

66+
type APLValueMaxHealth struct {
67+
DefaultAPLValueImpl
68+
unit *Unit
69+
}
70+
71+
func (rot *APLRotation) newValueMaxHealth(_ *proto.APLValueMaxHealth, uuid *proto.UUID) APLValue {
72+
unit := rot.unit
73+
if !unit.HasHealthBar() {
74+
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Health", unit.Label)
75+
return nil
76+
}
77+
return &APLValueMaxHealth{
78+
unit: unit,
79+
}
80+
}
81+
func (value *APLValueMaxHealth) Type() proto.APLValueType {
82+
return proto.APLValueType_ValueTypeFloat
83+
}
84+
func (value *APLValueMaxHealth) GetFloat(sim *Simulation) float64 {
85+
return value.unit.MaxHealth()
86+
}
87+
func (value *APLValueMaxHealth) String() string {
88+
return "Max Health"
89+
}
90+
6691
type APLValueCurrentMana struct {
6792
DefaultAPLValueImpl
6893
unit UnitReference
@@ -124,7 +149,7 @@ type APLValueCurrentRage struct {
124149
unit *Unit
125150
}
126151

127-
func (rot *APLRotation) newValueCurrentRage(config *proto.APLValueCurrentRage, uuid *proto.UUID) APLValue {
152+
func (rot *APLRotation) newValueCurrentRage(_ *proto.APLValueCurrentRage, uuid *proto.UUID) APLValue {
128153
unit := rot.unit
129154
if !unit.HasRageBar() {
130155
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Rage", unit.Label)
@@ -149,7 +174,7 @@ type APLValueCurrentFocus struct {
149174
unit *Unit
150175
}
151176

152-
func (rot *APLRotation) newValueCurrentFocus(config *proto.APLValueCurrentFocus, uuid *proto.UUID) APLValue {
177+
func (rot *APLRotation) newValueCurrentFocus(_ *proto.APLValueCurrentFocus, uuid *proto.UUID) APLValue {
153178
unit := rot.unit
154179
if !unit.HasFocusBar() {
155180
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Focus", unit.Label)
@@ -260,7 +285,7 @@ type APLValueCurrentEnergy struct {
260285
unit *Unit
261286
}
262287

263-
func (rot *APLRotation) newValueCurrentEnergy(config *proto.APLValueCurrentEnergy, uuid *proto.UUID) APLValue {
288+
func (rot *APLRotation) newValueCurrentEnergy(_ *proto.APLValueCurrentEnergy, uuid *proto.UUID) APLValue {
264289
unit := rot.unit
265290
if !unit.HasEnergyBar() {
266291
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Energy", unit.Label)
@@ -368,7 +393,7 @@ type APLValueCurrentComboPoints struct {
368393
unit *Unit
369394
}
370395

371-
func (rot *APLRotation) newValueCurrentComboPoints(config *proto.APLValueCurrentComboPoints, uuid *proto.UUID) APLValue {
396+
func (rot *APLRotation) newValueCurrentComboPoints(_ *proto.APLValueCurrentComboPoints, uuid *proto.UUID) APLValue {
372397
unit := rot.unit
373398
if !unit.HasEnergyBar() {
374399
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Combo Points", unit.Label)
@@ -418,7 +443,7 @@ type APLValueCurrentRunicPower struct {
418443
unit *Unit
419444
}
420445

421-
func (rot *APLRotation) newValueCurrentRunicPower(config *proto.APLValueCurrentRunicPower, uuid *proto.UUID) APLValue {
446+
func (rot *APLRotation) newValueCurrentRunicPower(_ *proto.APLValueCurrentRunicPower, uuid *proto.UUID) APLValue {
422447
unit := rot.unit
423448
if !unit.HasRunicPowerBar() {
424449
rot.ValidationMessageByUUID(uuid, proto.LogLevel_Warning, "%s does not use Runic Power", unit.Label)

sim/core/attack.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,19 @@ func (aa *AutoAttacks) UpdateSwingTimers(sim *Simulation) {
724724
}
725725
}
726726

727+
// Desyncss the offhand swing
728+
func (aa *AutoAttacks) DesyncOffHand(sim *Simulation, readyAt time.Duration) {
729+
if !aa.AutoSwingMelee { // if not auto swinging, don't auto restart.
730+
return
731+
}
732+
733+
if aa.IsDualWielding {
734+
aa.oh.swingAt = readyAt + aa.oh.curSwingDuration
735+
aa.oh.swingAt += aa.oh.curSwingDuration / 2
736+
sim.rescheduleWeaponAttack(aa.oh.swingAt)
737+
}
738+
}
739+
727740
// StopMeleeUntil should be used whenever a non-melee spell is cast. It stops melee, then restarts it
728741
// at end of cast, but with a reset swing timer (as if swings had just landed).
729742
func (aa *AutoAttacks) StopMeleeUntil(sim *Simulation, readyAt time.Duration, desyncOH bool) {
@@ -735,14 +748,10 @@ func (aa *AutoAttacks) StopMeleeUntil(sim *Simulation, readyAt time.Duration, de
735748
sim.rescheduleWeaponAttack(aa.mh.swingAt)
736749

737750
if aa.IsDualWielding {
738-
aa.oh.swingAt = readyAt + aa.oh.curSwingDuration
739-
if desyncOH {
740-
// Used by warrior to desync offhand after unglyphed Shattering Throw.
741-
aa.oh.swingAt += aa.oh.curSwingDuration / 2
742-
}
743-
sim.rescheduleWeaponAttack(aa.oh.swingAt)
751+
aa.DesyncOffHand(sim, readyAt)
744752
}
745753
}
754+
746755
func (aa *AutoAttacks) StopRangedUntil(sim *Simulation, readyAt time.Duration) {
747756
if !aa.AutoSwingRanged { // if not auto swinging, don't auto restart.
748757
return

sim/core/aura.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func (aura *Aura) ExpiresAt() time.Duration {
254254
}
255255

256256
// Adds a handler to be called OnGain, in addition to any current handlers.
257-
func (aura *Aura) ApplyOnGain(newOnGain OnGain) {
257+
func (aura *Aura) ApplyOnGain(newOnGain OnGain) *Aura {
258258
oldOnGain := aura.OnGain
259259
if oldOnGain == nil {
260260
aura.OnGain = newOnGain
@@ -264,10 +264,12 @@ func (aura *Aura) ApplyOnGain(newOnGain OnGain) {
264264
newOnGain(aura, sim)
265265
}
266266
}
267+
268+
return aura
267269
}
268270

269271
// Adds a handler to be called OnExpire, in addition to any current handlers.
270-
func (aura *Aura) ApplyOnExpire(newOnExpire OnExpire) {
272+
func (aura *Aura) ApplyOnExpire(newOnExpire OnExpire) *Aura {
271273
oldOnExpire := aura.OnExpire
272274
if oldOnExpire == nil {
273275
aura.OnExpire = newOnExpire
@@ -277,6 +279,8 @@ func (aura *Aura) ApplyOnExpire(newOnExpire OnExpire) {
277279
newOnExpire(aura, sim)
278280
}
279281
}
282+
283+
return aura
280284
}
281285

282286
type AuraFactory func(*Simulation) *Aura

sim/core/mana.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func (unit *Unit) AddMana(sim *Simulation, amount float64, metrics *ResourceMetr
8686

8787
oldMana := unit.CurrentMana()
8888
newMana := min(oldMana+amount, unit.MaxMana())
89+
8990
metrics.AddEvent(amount, newMana-oldMana)
9091

9192
if sim.Log != nil {

sim/core/statweight.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func buildStatWeightRequests(swr *proto.StatWeightsRequest) *proto.StatWeightReq
158158
}
159159

160160
// Do half the iterations with a positive, and half with a negative value for better accuracy.
161-
const defaultStatMod = 40.0 // match to the impact of a single gem
161+
const defaultStatMod = 160.0 // match to the impact of a single gem
162162
statModsLow := make([]float64, stats.UnitStatsLen)
163163
statModsHigh := make([]float64, stats.UnitStatsLen)
164164

sim/monk/apl_values.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (value *APLValueCurrentChi) Type() proto.APLValueType {
3232
return proto.APLValueType_ValueTypeInt
3333
}
3434
func (value *APLValueCurrentChi) GetInt(_ *core.Simulation) int32 {
35-
return value.monk.ComboPoints()
35+
return value.monk.GetChi()
3636
}
3737
func (value *APLValueCurrentChi) String() string {
3838
return "Current Chi"

sim/monk/attack.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,53 +27,46 @@ $offhigh=$?!s124146[${$MWB/2/$mws}][${$OWB/2/$ows}]
2727
$low=${$<stnc>*($<bm>*$<dwm>*(($mwb)/($MWS)+$<offm>*$<offlow>)+$<apc>-1)}
2828
$high=${$<stnc>*($<bm>*$<dwm>*(($MWB)/($MWS)+$<offm>*$<offhigh>)+$<apc>+1)}
2929
*/
30+
var DualWieldModifier = 0.898882275
31+
3032
func (monk *Monk) CalculateMonkStrikeDamage(sim *core.Simulation, spell *core.Spell) float64 {
3133
totalDamage := 0.0
3234
ap := spell.MeleeAttackPower()
3335

3436
staffOrPolearm := false
35-
hasMainHand := false
3637
mh := monk.MainHand()
3738
mhw := monk.WeaponFromMainHand(monk.DefaultCritMultiplier())
3839
if mh != nil && mh.WeaponType != proto.WeaponType_WeaponTypeUnknown {
3940
staffOrPolearm = mh.WeaponType == proto.WeaponType_WeaponTypeStaff || mh.WeaponType == proto.WeaponType_WeaponTypePolearm
4041
dmg := mhw.BaseDamage(sim) / mhw.SwingSpeed
4142
totalDamage += dmg
42-
hasMainHand = true
4343

4444
if sim.Log != nil {
4545
monk.Log(sim, "[DEBUG] main hand weapon damage portion for %s: td=%0.3f, wd=%0.3f, ws=%0.3f",
46-
spell.ActionID, totalDamage, dmg, mhw.SwingSpeed, ap)
46+
spell.ActionID, totalDamage, dmg, mhw.SwingSpeed)
4747
}
4848
}
4949

50-
hasOffHand := false
5150
oh := monk.OffHand()
5251
if oh != nil && oh.WeaponType != proto.WeaponType_WeaponTypeUnknown {
5352
ohw := monk.WeaponFromOffHand(monk.DefaultCritMultiplier())
5453
dmg := ohw.BaseDamage(sim) / ohw.SwingSpeed * 0.5
5554
totalDamage += dmg
56-
hasOffHand = true
5755

5856
if sim.Log != nil {
5957
monk.Log(sim, "[DEBUG] off hand weapon damage portion for %s: td=%0.3f, wd=%0.3f, ws=%0.3f",
60-
spell.ActionID, totalDamage, dmg, ohw.SwingSpeed, ap)
58+
spell.ActionID, totalDamage, dmg, ohw.SwingSpeed)
6159
}
6260
}
6361

64-
// When not wielding a staff or polearm, total damage is multiplied by 0.898882275.
62+
// When not wielding a staff or polearm, total damage is multiplied by DualWieldModifier.
6563
if !staffOrPolearm {
66-
totalDamage *= 0.898882275
64+
totalDamage *= DualWieldModifier
6765
}
6866

69-
apMod := monk.GetAttackPowerPerDPS()
67+
apMod := 1.0 / core.DefaultAttackPowerPerDPS
7068

71-
if !hasMainHand && !hasOffHand {
72-
// Unarmed
73-
totalDamage += mhw.CalculateWeaponDamage(sim, ap)
74-
} else {
75-
totalDamage += apMod * ap
76-
}
69+
totalDamage += apMod * ap
7770

7871
if sim.Log != nil {
7972
monk.Log(sim, "[DEBUG] total weapon damage for %s: td=%0.3f, apmod=%0.3f, ap=%0.3f",

0 commit comments

Comments
 (0)