warrior

package
v0.0.113 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2024 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SpellFlagBleed = core.SpellFlagAgentReserved1
	ArmsTree       = 0
	FuryTree       = 1
	ProtTree       = 2
)
View Source
const (
	SpellMaskSpecialAttack int64 = 1 << iota

	// Abilities that don't cost rage and aren't attacks
	SpellMaskBattleShout
	SpellMaskBerserkerRage
	SpellMaskCommandingShout
	SpellMaskRecklessness
	SpellMaskShieldWall
	SpellMaskLastStand
	SpellMaskDeadlyCalm
	SpellMaskCharge

	// Abilities that cost rage but aren't attacks
	SpellMaskDemoShout
	SpellMaskInnerRage
	SpellMaskShieldBlock
	SpellMaskDeathWish
	SpellMaskSweepingStrikes

	// Special attacks
	SpellMaskCleave
	SpellMaskColossusSmash
	SpellMaskExecute
	SpellMaskHeroicStrike
	SpellMaskHeroicThrow
	SpellMaskOverpower
	SpellMaskRend
	SpellMaskRevenge
	SpellMaskShatteringThrow
	SpellMaskSlam
	SpellMaskSunderArmor
	SpellMaskThunderClap
	SpellMaskWhirlwind
	SpellMaskWhirlwindOh
	SpellMaskShieldSlam
	SpellMaskConcussionBlow
	SpellMaskDevastate
	SpellMaskShockwave
	SpellMaskVictoryRush
	SpellMaskBloodthirst
	SpellMaskRagingBlow
	SpellMaskMortalStrike
	SpellMaskBladestorm
	SpellMaskHeroicLeap

	SpellMaskShouts = SpellMaskCommandingShout | SpellMaskBattleShout
)
View Source
const EnableOverpowerTag = "EnableOverpower"
View Source
const EnrageTag = "EnrageEffect"
View Source
const InnerRageExclusionTag = "InnerRageDeadlyCalm"
View Source
const ShoutExpirationThreshold = time.Second * 3
View Source
const SpellMaskNone int64 = 0

Variables

View Source
var ItemSetColossalDragonplateArmor = core.NewItemSet(core.ItemSet{
	Name: "Colossal Dragonplate Armor",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			character := agent.GetCharacter()
			actionID := core.ActionID{SpellID: 105909}

			shieldAura := character.RegisterAura(core.Aura{
				Label:    "Shield of Fury",
				ActionID: actionID,
				Duration: 6 * time.Second,
				OnGain: func(aura *core.Aura, sim *core.Simulation) {

				},
				OnExpire: func(aura *core.Aura, sim *core.Simulation) {

				},
			})

			core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
				Name:           "Shield of Fury Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnSpellHitDealt,
				ClassSpellMask: SpellMaskRevenge,
				Outcome:        core.OutcomeLanded,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {

					shieldAura.Activate(sim)
				},
			})
		},
		4: func(agent core.Agent) {

		},
	},
})
View Source
var ItemSetColossalDragonplateBattlegear = core.NewItemSet(core.ItemSet{
	Name: "Colossal Dragonplate Battlegear",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			character := agent.GetCharacter()

			mod := character.AddDynamicMod(core.SpellModConfig{
				ClassMask:  SpellMaskHeroicStrike,
				Kind:       core.SpellMod_PowerCost_Flat,
				FloatValue: -10,
			})

			actionID := core.ActionID{SpellID: 105860}
			buffAura := character.RegisterAura(core.Aura{
				Label:    "Volatile Outrage",
				ActionID: actionID,
				Duration: 15 * time.Second,
				OnGain: func(aura *core.Aura, sim *core.Simulation) {
					mod.Activate()
				},
				OnExpire: func(aura *core.Aura, sim *core.Simulation) {
					mod.Deactivate()
				},
			})

			core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
				Name:           "Volatile Outrage Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnCastComplete,
				ClassSpellMask: SpellMaskInnerRage,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					buffAura.Activate(sim)
				},
			})
		},
		4: func(agent core.Agent) {
			warrior := agent.(WarriorAgent).GetWarrior()

			actionID := core.ActionID{SpellID: 108126}
			procCS := warrior.RegisterSpell(core.SpellConfig{
				ActionID:    actionID,
				SpellSchool: core.SpellSchoolPhysical,
				Flags:       core.SpellFlagNoOnDamageDealt | core.SpellFlagNoOnCastComplete,
				Cast: core.CastConfig{
					DefaultCast: core.Cast{
						GCD: 0,
					},
				},
				ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
					warrior.ColossusSmashAuras.Get(target).Activate(sim)
				},
			})

			core.MakeProcTriggerAura(&warrior.Unit, core.ProcTrigger{
				Name:           "Warrior T13 4P Bloodthirst Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnSpellHitDealt,
				ClassSpellMask: SpellMaskBloodthirst,
				ProcChance:     0.06,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					procCS.Cast(sim, result.Target)
				},
			})

			core.MakeProcTriggerAura(&warrior.Unit, core.ProcTrigger{
				Name:           "Warrior T13 4P Mortal Strike Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnSpellHitDealt,
				ClassSpellMask: SpellMaskMortalStrike,
				ProcChance:     0.13,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					procCS.Cast(sim, result.Target)
				},
			})
		},
	},
})
View Source
var ItemSetEarthenBattleplate = core.NewItemSet(core.ItemSet{
	Name: "Earthen Battleplate",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			agent.GetCharacter().AddStaticMod(core.SpellModConfig{
				ClassMask:  SpellMaskShieldSlam,
				Kind:       core.SpellMod_DamageDone_Flat,
				FloatValue: 0.05,
			})
		},
		4: func(agent core.Agent) {
			agent.GetCharacter().AddStaticMod(core.SpellModConfig{
				ClassMask:  SpellMaskShieldWall,
				Kind:       core.SpellMod_Cooldown_Multiplier,
				FloatValue: -0.5,
			})
		},
	},
})
View Source
var ItemSetEarthenWarplate = core.NewItemSet(core.ItemSet{
	Name: "Earthen Warplate",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			agent.GetCharacter().AddStaticMod(core.SpellModConfig{
				ClassMask:  SpellMaskBloodthirst | SpellMaskMortalStrike,
				Kind:       core.SpellMod_DamageDone_Flat,
				FloatValue: 0.05,
			})
		},
		4: func(agent core.Agent) {
			character := agent.GetCharacter()
			actionID := core.ActionID{SpellID: 90294}

			apDep := make([]*stats.StatDependency, 3)
			for i := 1; i <= 3; i++ {
				apDep[i-1] = character.NewDynamicMultiplyStat(stats.AttackPower, 1.0+float64(i)*0.01)
			}

			buff := character.RegisterAura(core.Aura{
				Label:     "Rage of the Ages",
				ActionID:  actionID,
				Duration:  30 * time.Second,
				MaxStacks: 3,
				OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) {

					if oldStacks > 0 {
						character.DisableDynamicStatDep(sim, apDep[oldStacks-1])
					}
					if newStacks > 0 {
						character.EnableDynamicStatDep(sim, apDep[newStacks-1])
					}
				},
			})

			core.MakeProcTriggerAura(&agent.GetCharacter().Unit, core.ProcTrigger{
				Name:           "Rage of the Ages Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnCastComplete,
				ClassSpellMask: SpellMaskOverpower | SpellMaskRagingBlow,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					buff.Activate(sim)
					buff.AddStack(sim)
				},
			})
		},
	},
})
View Source
var ItemSetGladiatorsBattlegear = core.NewItemSet(core.ItemSet{
	ID:   909,
	Name: "Gladiator's Battlegear",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			agent.GetCharacter().AddStats(stats.Stats{
				stats.Strength: 70,
			})
		},
		4: func(agent core.Agent) {
			agent.GetCharacter().AddStats(stats.Stats{
				stats.Strength: 90,
			})
		},
	},
})
View Source
var ItemSetMoltenGiantBattleplate = core.NewItemSet(core.ItemSet{
	Name: "Molten Giant Battleplate",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			character := agent.GetCharacter()
			actionID := core.ActionID{SpellID: 23922}

			// TODO (4.2): Test if this rolls damage over like deep wounds or just resets it
			var shieldSlamDamage float64 = 0.0
			debuff := character.RegisterSpell(core.SpellConfig{
				ActionID:    actionID.WithTag(3),
				SpellSchool: core.SpellSchoolFire,
				ProcMask:    core.ProcMaskEmpty,
				Flags:       core.SpellFlagPassiveSpell,

				DamageMultiplier: 1,
				ThreatMultiplier: 1,

				Dot: core.DotConfig{
					Aura: core.Aura{
						Label: "Combust",
					},
					NumberOfTicks: 2,
					TickLength:    2 * time.Second,
					OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) {
						dot.Snapshot(target, shieldSlamDamage/float64(dot.BaseTickCount))
					},
					OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) {
						dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick)
					},
				},

				ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
					spell.Dot(target).Apply(sim)
				},
			})

			core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
				Name:           "Combust Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnSpellHitDealt,
				ClassSpellMask: SpellMaskShieldSlam,
				Outcome:        core.OutcomeLanded,

				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					shieldSlamDamage = result.Damage * 0.2
					debuff.Cast(sim, result.Target)
				},
			})
		},
		4: func(agent core.Agent) {
			character := agent.GetCharacter()

			character.RegisterAura(core.Aura{
				Label:    "T12 4P Bonus",
				ActionID: core.ActionID{SpellID: 99242},
				Duration: 10 * time.Second,
				OnGain: func(aura *core.Aura, sim *core.Simulation) {
					character.PseudoStats.BaseParryChance += 0.06
				},
				OnExpire: func(aura *core.Aura, sim *core.Simulation) {
					character.PseudoStats.BaseParryChance -= 0.06
				},
			})

		},
	},
})
View Source
var ItemSetMoltenGiantWarplate = core.NewItemSet(core.ItemSet{
	Name: "Molten Giant Warplate",
	Bonuses: map[int32]core.ApplyEffect{
		2: func(agent core.Agent) {
			character := agent.GetCharacter()
			actionID := core.ActionID{SpellID: 99233}

			warrior := agent.(WarriorAgent).GetWarrior()
			talentReduction := time.Duration(warrior.Talents.BoomingVoice*3) * time.Second

			buff := character.RegisterAura(core.Aura{
				Label:    "Burning Rage",
				ActionID: actionID,
				Duration: 12*time.Second - talentReduction,
				OnGain: func(aura *core.Aura, sim *core.Simulation) {
					character.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] *= 1.1
				},
				OnExpire: func(aura *core.Aura, sim *core.Simulation) {
					character.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.1
				},
			})

			core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
				Name:           "Burning Rage Trigger",
				ActionID:       actionID,
				ClassSpellMask: SpellMaskShouts,
				Callback:       core.CallbackOnCastComplete,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					buff.Activate(sim)
				},
			})
		},
		4: func(agent core.Agent) {
			character := agent.GetCharacter()

			actionID := core.ActionID{SpellID: 99237}

			fieryAttackActionID := core.ActionID{}
			if character.Spec == proto.Spec_SpecArmsWarrior {
				fieryAttackActionID.SpellID = 12294
			}
			if character.Spec == proto.Spec_SpecFuryWarrior {
				fieryAttackActionID.SpellID = 85288
			}

			fieryAttack := character.RegisterSpell(core.SpellConfig{
				ActionID:    fieryAttackActionID.WithTag(3),
				SpellSchool: core.SpellSchoolFire,
				ProcMask:    core.ProcMaskEmpty,
				Flags:       core.SpellFlagMeleeMetrics | core.SpellFlagPassiveSpell,

				CritMultiplier:   character.DefaultMeleeCritMultiplier(),
				DamageMultiplier: 1,
				ThreatMultiplier: 1,

				ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
					baseDamage := spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower())
					spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMagicCrit)
				},
			})

			core.MakeProcTriggerAura(&character.Unit, core.ProcTrigger{
				Name:           "Fiery Attack Trigger",
				ActionID:       actionID,
				Callback:       core.CallbackOnSpellHitDealt,
				ClassSpellMask: SpellMaskMortalStrike | SpellMaskRagingBlow,
				ProcChance:     0.3,
				Outcome:        core.OutcomeLanded,
				Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
					fieryAttack.Cast(sim, result.Target)
				},
			})
		},
	},
})
View Source
var TalentTreeSizes = [3]int{20, 21, 20}

Functions

This section is empty.

Types

type RageMultiplierCB

type RageMultiplierCB func() float64

Rather than update a variable somewhere for one effect (Fury's Unshackled Fury) just take a callback to fetch its multiplier when needed

type SpellEffectWeaponDmgPctConfig

type SpellEffectWeaponDmgPctConfig struct {
	BaseWeapon_Pct    float64
	Coefficient       float64
	EffectPerLevel    float64
	BaseSpellLevel    int32
	MaxSpellLevel     int32
	ClassSpellScaling float64
}

func (*SpellEffectWeaponDmgPctConfig) CalcAddedSpellDamage

func (config *SpellEffectWeaponDmgPctConfig) CalcAddedSpellDamage() float64

func (*SpellEffectWeaponDmgPctConfig) CalcSpellDamagePct

func (config *SpellEffectWeaponDmgPctConfig) CalcSpellDamagePct() float64

type Stance

type Stance uint8
const (
	StanceNone          = 0
	BattleStance Stance = 1 << iota
	DefensiveStance
	BerserkerStance
)

type Warrior

type Warrior struct {
	core.Character

	ClassSpellScaling float64

	Talents *proto.WarriorTalents

	WarriorInputs

	// Current state
	Stance                 Stance
	EnrageEffectMultiplier float64
	CriticalBlockChance    []float64 // Can be gained as non-prot via certain talents and spells
	PrecisionKnown         bool

	BattleShout     *core.Spell
	CommandingShout *core.Spell
	BattleStance    *core.Spell
	DefensiveStance *core.Spell
	BerserkerStance *core.Spell

	BerserkerRage     *core.Spell
	ColossusSmash     *core.Spell
	DemoralizingShout *core.Spell
	Execute           *core.Spell
	Overpower         *core.Spell
	Rend              *core.Spell
	Revenge           *core.Spell
	ShieldBlock       *core.Spell
	Slam              *core.Spell
	SunderArmor       *core.Spell
	ThunderClap       *core.Spell
	Whirlwind         *core.Spell
	DeepWounds        *core.Spell
	Charge            *core.Spell

	HeroicStrike *core.Spell
	Cleave       *core.Spell

	BattleStanceAura    *core.Aura
	DefensiveStanceAura *core.Aura
	BerserkerStanceAura *core.Aura

	BerserkerRageAura *core.Aura
	BloodsurgeAura    *core.Aura
	SuddenDeathAura   *core.Aura
	ShieldBlockAura   *core.Aura
	ThunderstruckAura *core.Aura
	InnerRageAura     *core.Aura

	DemoralizingShoutAuras core.AuraArray
	SunderArmorAuras       core.AuraArray
	ThunderClapAuras       core.AuraArray
	ColossusSmashAuras     core.AuraArray
	// contains filtered or unexported fields
}

func NewWarrior

func NewWarrior(character *core.Character, talents string, inputs WarriorInputs) *Warrior

func (*Warrior) AddPartyBuffs

func (warrior *Warrior) AddPartyBuffs(_ *proto.PartyBuffs)

func (*Warrior) AddRaidBuffs

func (warrior *Warrior) AddRaidBuffs(raidBuffs *proto.RaidBuffs)

func (*Warrior) ApplyCommonTalents

func (warrior *Warrior) ApplyCommonTalents()

Applies the effects of "common" talents: talents in the first two rows of each tree that any spec could theoretically take Because cata restricts you to 10 points in a different tree, anything more is inaccessible. The rest of the trees are handled in each spec's implementation

func (*Warrior) ApplyGlyphs

func (warrior *Warrior) ApplyGlyphs()

func (*Warrior) CanApplySunderAura

func (warrior *Warrior) CanApplySunderAura(target *core.Unit) bool

func (*Warrior) GetCharacter

func (warrior *Warrior) GetCharacter() *core.Character

func (*Warrior) GetCriticalBlockChance

func (warrior *Warrior) GetCriticalBlockChance() float64

func (*Warrior) HasMajorGlyph

func (warrior *Warrior) HasMajorGlyph(glyph proto.WarriorMajorGlyph) bool

func (*Warrior) HasMinorGlyph

func (warrior *Warrior) HasMinorGlyph(glyph proto.WarriorMinorGlyph) bool

func (*Warrior) HasPrimeGlyph

func (warrior *Warrior) HasPrimeGlyph(glyph proto.WarriorPrimeGlyph) bool

func (*Warrior) Initialize

func (warrior *Warrior) Initialize()

func (*Warrior) IntensifyRageCooldown

func (warrior *Warrior) IntensifyRageCooldown(baseCd time.Duration) time.Duration

func (*Warrior) MakeShoutSpellHelper

func (warrior *Warrior) MakeShoutSpellHelper(actionID core.ActionID, spellMask int64, allyAuras core.AuraArray) *core.Spell

func (*Warrior) RecklessnessDeadlyCalmLock

func (warrior *Warrior) RecklessnessDeadlyCalmLock() *core.Timer

Shared cooldown for Deadly Calm and Recklessness Activation

func (*Warrior) RegisterBerserkerRageSpell

func (warrior *Warrior) RegisterBerserkerRageSpell()

func (*Warrior) RegisterCharge

func (warrior *Warrior) RegisterCharge()

func (*Warrior) RegisterCleaveSpell

func (warrior *Warrior) RegisterCleaveSpell()

func (*Warrior) RegisterColossusSmash

func (warrior *Warrior) RegisterColossusSmash()

func (*Warrior) RegisterDeepWounds

func (warrior *Warrior) RegisterDeepWounds()

func (*Warrior) RegisterDemoralizingShoutSpell

func (warrior *Warrior) RegisterDemoralizingShoutSpell()

func (*Warrior) RegisterExecuteSpell

func (warrior *Warrior) RegisterExecuteSpell()

func (*Warrior) RegisterHeroicLeap

func (warrior *Warrior) RegisterHeroicLeap()

func (*Warrior) RegisterHeroicStrikeSpell

func (warrior *Warrior) RegisterHeroicStrikeSpell()

func (*Warrior) RegisterHeroicThrow

func (warrior *Warrior) RegisterHeroicThrow()

TODO: No patch notes for this ability, need to validate the damage and threat coefficients haven't changed

func (*Warrior) RegisterInnerRage

func (warrior *Warrior) RegisterInnerRage()

func (*Warrior) RegisterOverpowerSpell

func (warrior *Warrior) RegisterOverpowerSpell()

func (*Warrior) RegisterRecklessnessCD

func (warrior *Warrior) RegisterRecklessnessCD()

func (*Warrior) RegisterRendSpell

func (warrior *Warrior) RegisterRendSpell()

TODO (maybe) https://github.com/magey/wotlk-warrior/issues/23 - Rend is not benefitting from Two-Handed Weapon Specialization

func (*Warrior) RegisterRevengeSpell

func (warrior *Warrior) RegisterRevengeSpell()

func (*Warrior) RegisterShatteringThrowCD

func (warrior *Warrior) RegisterShatteringThrowCD()

func (*Warrior) RegisterShieldBlockCD

func (warrior *Warrior) RegisterShieldBlockCD()

func (*Warrior) RegisterShieldWallCD

func (warrior *Warrior) RegisterShieldWallCD()

func (*Warrior) RegisterShouts

func (warrior *Warrior) RegisterShouts()

func (*Warrior) RegisterSlamSpell

func (warrior *Warrior) RegisterSlamSpell()

func (*Warrior) RegisterSunderArmor

func (warrior *Warrior) RegisterSunderArmor() *core.Spell

func (*Warrior) RegisterThunderClapSpell

func (warrior *Warrior) RegisterThunderClapSpell()

func (*Warrior) RegisterWhirlwindSpell

func (warrior *Warrior) RegisterWhirlwindSpell()

func (*Warrior) Reset

func (warrior *Warrior) Reset(_ *core.Simulation)

func (*Warrior) StanceMatches

func (warrior *Warrior) StanceMatches(other Stance) bool

func (*Warrior) TryApplySunderArmorEffect

func (warrior *Warrior) TryApplySunderArmorEffect(sim *core.Simulation, target *core.Unit)

type WarriorAgent

type WarriorAgent interface {
	GetWarrior() *Warrior
}

Agent is a generic way to access underlying warrior on any of the agents.

type WarriorInputs

type WarriorInputs struct {
	StanceSnapshot bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL