-
Notifications
You must be signed in to change notification settings - Fork 41
Mistweaver implementation #380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/monk-mistweaver
Are you sure you want to change the base?
Changes from 34 commits
b181ff2
fb1ada6
5fb6473
eeec9ce
78e9266
72d980a
6aa67fc
d685e5e
80b9f3e
2687aab
ce9108c
2bdec85
668dd2a
bf11a9e
26cca5c
590b2ab
93a5f01
aaf950e
2cdfa93
7c773ef
ea67b07
8e59baa
42ca540
22ba653
0f986db
b173c2d
ce8f36a
bc16a63
10f82a9
09f417e
67ca075
894f836
5563765
9b5d21a
258aa4c
b4dcd50
eb1e58c
ff438d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ package core | |
|
|
||
| import ( | ||
| "fmt" | ||
| "slices" | ||
| "time" | ||
|
|
||
| "github.com/wowsims/mop/sim/core/proto" | ||
|
|
@@ -23,6 +24,8 @@ type APLRotation struct { | |
| // If true, can recast channel when interrupted. | ||
| allowChannelRecastOnInterrupt bool | ||
|
|
||
| //Checking for cast-while-channeling spells to allow the APL to not evaluate during channels unless absolutely necessary | ||
| allowCastWhileChanneling bool | ||
| // Used inside of actions/value to determine whether they will occur during the prepull or regular rotation. | ||
| parsingPrepull bool | ||
|
|
||
|
|
@@ -265,6 +268,11 @@ func (rot *APLRotation) reset(sim *Simulation) { | |
| rot.inLoop = false | ||
| rot.interruptChannelIf = nil | ||
| rot.allowChannelRecastOnInterrupt = false | ||
|
|
||
| //rot.allowCastWhileChanneling = slices.ContainsFunc(rot.unit.Spellbook, func(spell *Spell) bool { | ||
|
NerdEgghead marked this conversation as resolved.
|
||
| // return spell.Flags.Matches(SpellFlagCastWhileChanneling) | ||
| //}) | ||
|
Comment on lines
+269
to
+271
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General comment: delete any unused commented code like this for cleanliness once you are done debugging. |
||
|
|
||
| for _, action := range rot.allAPLActions() { | ||
| action.impl.Reset(sim) | ||
| } | ||
|
|
@@ -282,7 +290,12 @@ func (apl *APLRotation) DoNextAction(sim *Simulation) { | |
| return | ||
| } | ||
|
|
||
| if apl.unit.ChanneledDot != nil { | ||
| //Probably not the best solution, added so apl evaluates if a spell can be cast while channeling during runtime rather than on reset | ||
| apl.allowCastWhileChanneling = slices.ContainsFunc(apl.unit.Spellbook, func(spell *Spell) bool { | ||
| return spell.Flags.Matches(SpellFlagCastWhileChanneling) | ||
| }) | ||
|
|
||
| if apl.unit.ChanneledDot != nil && !apl.allowCastWhileChanneling { | ||
| return | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there's a simpler solution for this: you can permanently add |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -571,10 +571,11 @@ func (spell *Spell) CanCast(sim *Simulation, target *Unit) bool { | |
| } | ||
|
|
||
| // While casting or channeling, no other action is possible | ||
| if spell.Unit.Hardcast.Expires > sim.CurrentTime { | ||
| if (spell.Unit.Hardcast.Expires > sim.CurrentTime || spell.Unit.IsChanneling(sim)) && !spell.Flags.Matches(SpellFlagCastWhileChanneling) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should add the same correction to the |
||
| //if sim.Log != nil { | ||
| // sim.Log("Cant cast because already casting/channeling") | ||
| //} | ||
|
|
||
| return false | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -471,6 +471,10 @@ func (unit *Unit) InitialCastSpeed() float64 { | |
| return unit.initialCastSpeed | ||
| } | ||
|
|
||
| func (unit *Unit) IsChanneling(sim *Simulation) bool { | ||
| return unit.ChanneledDot != nil | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
|
||
| func (unit *Unit) SpellGCD() time.Duration { | ||
| return max(GCDMin, unit.ApplyCastSpeed(GCDDefault)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,6 +68,7 @@ func blackoutKickSpellConfig(monk *Monk, isSEFClone bool, overrides core.SpellCo | |
| func (monk *Monk) registerBlackoutKick() { | ||
| chiMetrics := monk.NewChiMetrics(blackoutKickActionID) | ||
| chiCost := int32(2) | ||
| manaMetrics := monk.NewManaMetrics(blackoutKickActionID) | ||
|
|
||
| monk.RegisterSpell(blackoutKickSpellConfig(monk, false, core.SpellConfig{ | ||
| Cast: core.CastConfig{ | ||
|
|
@@ -92,6 +93,11 @@ func (monk *Monk) registerBlackoutKick() { | |
| } else { | ||
| monk.SpendChi(sim, chiCost, chiMetrics) | ||
| } | ||
|
|
||
| if monk.MuscleMemoryAura.IsActive() { | ||
| result.Damage += result.Damage * 1.5 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably become a 0.5 DamageDonePct SpellMod on the Aura itself, because right now you are actually not going a 150% mod, but 250%. (100% of the original result + 150% of the original result * 1.5) |
||
| monk.AddMana(sim, monk.MaxMana()*0.04, manaMetrics) | ||
| } | ||
| } | ||
|
|
||
| spell.DealOutcome(sim, result) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,7 +73,8 @@ func (monk *Monk) registerJab() { | |
| Refund: 0.8, | ||
| }, | ||
| ManaCost: core.ManaCostOptions{ | ||
| BaseCostPercent: core.TernaryFloat64(monk.StanceMatches(WiseSerpent), 8, 0), | ||
| //This is wrong? But works? | ||
| BaseCostPercent: core.TernaryFloat64(monk.StanceMatches(WiseSerpent), 0, 8), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reminder to figure out what the underlying bug is here and fix it
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit confused myself, the intention behind the original I assume was to have the mana cost be set if the player is in wise serpent stance. However when running the sim the mana cost of jab was zero. Replacing it with the above now had it properly costing mana or simply replacing it with the mana cost sans TernaryFloat64 also works and doesn't seem to disrupt the other monk sims from what I can tell. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would leave in the costs, and then if needed based on the active Stance aura enable/disable a SpellMod that reduces the costs |
||
| }, | ||
|
|
||
| Cast: core.CastConfig{ | ||
|
|
@@ -84,6 +85,7 @@ func (monk *Monk) registerJab() { | |
| }, | ||
|
|
||
| ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { | ||
|
|
||
| baseDamage := monk.CalculateMonkStrikeDamage(sim, spell) | ||
| result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMeleeSpecialHitAndCrit) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package mistweaver | ||
|
|
||
| import ( | ||
| "time" | ||
|
|
||
| "github.com/wowsims/mop/sim/core" | ||
| "github.com/wowsims/mop/sim/monk" | ||
| ) | ||
|
|
||
| func (mw *MistweaverMonk) registerEnvelopingMist() { | ||
| actionID := core.ActionID{SpellID: 124682} | ||
| chiMetrics := mw.NewChiMetrics(actionID) | ||
| spellCoeff := 0.45 | ||
|
|
||
| mw.enevelopingMist = mw.RegisterSpell(core.SpellConfig{ | ||
| ActionID: actionID, | ||
| SpellSchool: core.SpellSchoolNature, | ||
| ProcMask: core.ProcMaskSpellHealing, | ||
| Flags: core.SpellFlagHelpful | core.SpellFlagAPL, // | core.SpellFlagCastWhileChanneling, | ||
|
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you intend to comment out the extra flag here? |
||
| ClassSpellMask: monk.MonkSpellEnvelopingMist, | ||
|
|
||
| ManaCost: core.ManaCostOptions{BaseCostPercent: 0}, | ||
|
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can just omit this field if the cost is 0. |
||
| Cast: core.CastConfig{ | ||
| DefaultCast: core.Cast{ | ||
| GCD: core.GCDDefault, | ||
| CastTime: time.Millisecond * 2000, | ||
| }, | ||
| }, | ||
| DamageMultiplier: 1, | ||
| ThreatMultiplier: 1, | ||
| CritMultiplier: mw.DefaultCritMultiplier(), | ||
|
|
||
| ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { | ||
| return mw.GetChi() >= 3 | ||
| }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General comment for code readability: use |
||
|
|
||
| ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { | ||
|
|
||
| mw.SpendChi(sim, 3, chiMetrics) | ||
| spell.RelatedDotSpell.Cast(sim, &mw.Unit) | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be cast on the supplied |
||
| }, | ||
| }) | ||
|
|
||
| mw.enevelopingMist.RelatedDotSpell = mw.RegisterSpell(core.SpellConfig{ | ||
| ActionID: actionID, | ||
| SpellSchool: core.SpellSchoolNature, | ||
| ProcMask: core.ProcMaskSpellHealing, | ||
| Flags: core.SpellFlagHelpful, | ||
| //ClassSpellMask: monk.MonkSpellEnvelopingMist, | ||
|
|
||
|
Comment on lines
+51
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you intend to comment out the spell mask here? |
||
| DamageMultiplier: 1, | ||
| ThreatMultiplier: 1, | ||
| CritMultiplier: mw.DefaultCritMultiplier(), | ||
| Hot: core.DotConfig{ | ||
| Aura: core.Aura{ | ||
| Label: "Enveloping Mist", | ||
| }, | ||
| NumberOfTicks: 6, | ||
| TickLength: 1 * time.Second, | ||
| AffectedByCastSpeed: true, | ||
| HasteReducesDuration: true, | ||
| OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { | ||
| dot.SnapshotBaseDamage = 0 + mw.CalcScalingSpellDmg(spellCoeff) | ||
| dot.SnapshotAttackerMultiplier = dot.Spell.CasterHealingMultiplier() | ||
| }, | ||
|
|
||
| OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { | ||
| dot.CalcAndDealPeriodicSnapshotHealing(sim, target, dot.OutcomeTick) | ||
|
|
||
| }, | ||
| }, | ||
|
|
||
| ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { | ||
| //Targets only mw currently | ||
| hot := spell.Hot(&mw.Unit) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment - if you use the |
||
|
|
||
| hot.Apply(sim) | ||
|
|
||
| }, | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| package mistweaver | ||
|
|
||
| import ( | ||
| "math" | ||
| "time" | ||
|
|
||
| "github.com/wowsims/mop/sim/core" | ||
| "github.com/wowsims/mop/sim/core/stats" | ||
| "github.com/wowsims/mop/sim/monk" | ||
| ) | ||
|
|
||
| func (mw *MistweaverMonk) registerManaTea() { | ||
|
|
||
| buffActionID := core.ActionID{SpellID: 115294} | ||
| stackActionID := core.ActionID{SpellID: 123766} | ||
| manaMetrics := mw.NewManaMetrics(buffActionID) | ||
| manaPerTick := 0.0 | ||
| //numerOFTicks := 6 | ||
|
|
||
| mw.Monk.RegisterOnChiSpent(func(sim *core.Simulation, chiSpent int32) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| accumulatedChi := mw.outstandingChi + chiSpent | ||
|
|
||
| for accumulatedChi >= 4 { | ||
|
|
||
| mw.AddBrewStacks(sim, 1) | ||
| accumulatedChi -= 4 | ||
| } | ||
|
|
||
| mw.outstandingChi = accumulatedChi | ||
|
|
||
| }) | ||
|
|
||
| mw.ManaTeaStackAura = mw.RegisterAura(core.Aura{ | ||
| Label: "Mana Tea Stacks" + mw.Label, | ||
| ActionID: stackActionID, | ||
| Duration: time.Hour, | ||
| MaxStacks: 10, | ||
| }) | ||
|
|
||
| mw.Monk.RegisterOnNewBrewStacks(func(sim *core.Simulation, stacksToAdd int32) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| mw.ManaTeaStackAura.Activate(sim) | ||
|
|
||
| procChance := mw.GetStat(stats.SpellCritPercent) | ||
|
|
||
| if sim.Proc(math.Mod(procChance, 1), "Mana Tea") { | ||
| stacksToAdd += 1 | ||
| } | ||
|
Comment on lines
+43
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem correct, it would set the proc chance to 99% if your current Spell Crit chance is 1.99% for example. |
||
|
|
||
| mw.ManaTeaStackAura.SetStacks(sim, mw.ManaTeaStackAura.GetStacks()+stacksToAdd) | ||
| }) | ||
|
|
||
| mw.RegisterSpell(core.SpellConfig{ | ||
| ActionID: buffActionID, | ||
| Flags: core.SpellFlagAPL | core.SpellFlagNoOnCastComplete | core.SpellFlagHelpful | core.SpellFlagChanneled, | ||
| ClassSpellMask: monk.MonkSpellManaTea, | ||
|
|
||
| Cast: core.CastConfig{ | ||
| DefaultCast: core.Cast{ | ||
| GCD: time.Millisecond * 1000, | ||
| }, | ||
| }, | ||
|
|
||
| Hot: core.DotConfig{ | ||
| SelfOnly: true, | ||
| Aura: core.Aura{ | ||
| Label: "Mana Tea", | ||
| Duration: 3 * time.Second, //Set at activation | ||
| }, | ||
| NumberOfTicks: 6, | ||
| TickLength: 500 * time.Millisecond, | ||
| AffectedByCastSpeed: false, //? | ||
| OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { | ||
| mw.manaTeaAura = dot.Aura | ||
| }, | ||
|
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General comment for readability: replace any unused function inputs (in this case |
||
| OnTick: func(sim *core.Simulation, target *core.Unit, spell *core.Dot) { | ||
| mw.AddMana(sim, manaPerTick, manaMetrics) | ||
|
|
||
| mw.ManaTeaStackAura.SetStacks(sim, mw.ManaTeaStackAura.GetStacks()-1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can simplify this to |
||
|
|
||
| }, | ||
| }, | ||
|
|
||
| ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { | ||
|
|
||
| return mw.ManaTeaStackAura.GetStacks() > 0 | ||
| }, | ||
|
|
||
| ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { | ||
| manaPerTick = mw.MaxMana() * 0.05 //Patched to restore 5% instead of original 4% | ||
|
|
||
| hot := spell.SelfHot() | ||
| stacksToUse := min(mw.ManaTeaStackAura.GetStacks(), 6.0) | ||
| hot.Duration = time.Duration(stacksToUse) * 500 * time.Millisecond | ||
| hot.BaseTickCount = stacksToUse | ||
| hot.Activate(sim) | ||
| //mw.ManaTeaStackAura.SetStacks(sim, mw.ManaTeaStackAura.GetStacks()-1) | ||
|
|
||
| //spell.SelfHot().Apply(sim) | ||
|
|
||
| }, | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,17 @@ func NewMistweaverMonk(character *core.Character, options *proto.Player) *Mistwe | |
|
|
||
| type MistweaverMonk struct { | ||
| *monk.Monk | ||
|
|
||
| ManaTeaStackAura *core.Aura | ||
|
|
||
| renewingMist *core.Spell | ||
| enevelopingMist *core.Spell | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo, should be |
||
| JadeSerpentAura *core.Aura | ||
| //May move this to monk as both ww and mw use this | ||
| outstandingChi int32 | ||
|
|
||
| manaTeaAura *core.Aura | ||
| } | ||
|
|
||
| func (mw *MistweaverMonk) GetMonk() *monk.Monk { | ||
|
|
@@ -68,11 +79,21 @@ func (mw *MistweaverMonk) ApplyTalents() { | |
| } | ||
|
|
||
| func (mw *MistweaverMonk) Reset(sim *core.Simulation) { | ||
| mw.outstandingChi = 0 | ||
| mw.Monk.Reset(sim) | ||
| } | ||
|
|
||
| func (mw *MistweaverMonk) RegisterSpecializationEffects() { | ||
| mw.RegisterMastery() | ||
| mw.registerRenewingMist() | ||
| mw.registerSurgingMist() | ||
| mw.registerSoothingMist() | ||
| mw.registerEnvelopingMist() | ||
| mw.registerUplift() | ||
| mw.registerRevival() | ||
| mw.registerSummonJadeSerpentStatue() | ||
| mw.registerManaTea() | ||
| mw.registerPassives() | ||
| } | ||
|
|
||
| func (mw *MistweaverMonk) RegisterMastery() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field could be removed if you go with my previous suggestion.