Documentation
¶
Index ¶
- Constants
- Variables
- func RegisterHunter()
- type Hunter
- func (hunter *Hunter) AddPartyBuffs(_ *proto.PartyBuffs)
- func (hunter *Hunter) AddRaidBuffs(raidBuffs *proto.RaidBuffs)
- func (hunter *Hunter) ApplyTalents()
- func (hunter *Hunter) GetCharacter() *core.Character
- func (hunter *Hunter) GetHunter() *Hunter
- func (hunter *Hunter) Initialize()
- func (hunter *Hunter) NewHunterPet() *HunterPet
- func (hunter *Hunter) OnGCDReady(_ *core.Simulation)
- func (hunter *Hunter) Reset(sim *core.Simulation)
- func (hunter *Hunter) TryRaptorStrike(sim *core.Simulation, mhSwingSpell *core.Spell) *core.Spell
- type HunterAgent
- type HunterPet
- type PetAbilityType
- type PetConfig
Constants ¶
const ( SpellFlagShot = core.SpellFlagAgentReserved1 SpellFlagStrike = core.SpellFlagAgentReserved2 SpellFlagSting = core.SpellFlagAgentReserved3 SpellFlagTrap = core.SpellFlagAgentReserved4 )
const ( SpellCode_HunterNone int32 = iota // Shots SpellCode_HunterAimedShot SpellCode_HunterArcaneShot SpellCode_HunterMultiShot // Strikes SpellCode_HunterRaptorStrike SpellCode_HunterRaptorStrikeHit // Stings SpellCode_HunterSerpentSting // Traps SpellCode_HunterExplosiveTrap SpellCode_HunterFreezingTrap SpellCode_HunterImmolationTrap // Other SpellCode_HunterMongooseBite SpellCode_HunterWingClip SpellCode_HunterVolley // Pet Spells SpellCode_HunterPetClaw SpellCode_HunterPetBite SpellCode_HunterPetLightningBreath SpellCode_HunterPetScreech SpellCode_HunterPetScorpidPoison )
const ( KnightLieutenantsChainGauntlets = 16403 BloodGuardsChainGauntlets = 16530 MarshalsChainGrips = 16463 GeneralsChainGloves = 16571 RenatakisCharmofBeasts = 19953 DevilsaurEye = 19991 DevilsaurTooth = 19992 KnightLieutenantsChainVices = 23279 BloodGuardsChainVices = 22862 )
const PetGCD = time.Millisecond * 1600
Pet AI doesn't use abilities immediately, so model this with a 1.6s GCD.
const RaptorStrikeRanks = 8
Variables ¶
var ItemSetBeastmasterArmor = core.NewItemSet(core.ItemSet{ Name: "Beastmaster Armor", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddResistances(8) }, 4: func(agent core.Agent) { c := agent.GetCharacter() actionID := core.ActionID{SpellID: 27785} manaMetrics := c.NewManaMetrics(actionID) core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ ActionID: actionID, Name: "Hunter Armor Energize", Callback: core.CallbackOnSpellHitDealt, Outcome: core.OutcomeLanded, ProcMask: core.ProcMaskWhiteHit, ProcChance: 0.04, Handler: func(sim *core.Simulation, spell *core.Spell, _ *core.SpellResult) { if c.HasManaBar() { c.AddMana(sim, 200, manaMetrics) } }, }) }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStats(stats.Stats{ stats.AttackPower: 40, stats.RangedAttackPower: 40, }) }, 8: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Armor, 200) }, }, })
hhttps://www.wowhead.com/classic/item-set=515/beastmaster-armor
var ItemSetChampionsPursuance = core.NewItemSet(core.ItemSet{ Name: "Champion's Pursuance", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Agility, 20) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 20) }, }, })
https://www.wowhead.com/classic/item-set=543/champions-pursuance
var ItemSetChampionsPursuit = core.NewItemSet(core.ItemSet{ Name: "Champion's Pursuit", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Parry, 1*core.ParryRatingPerParryChance) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 15) }, }, })
https://www.wowhead.com/classic/item-set=361/champions-pursuit
var ItemSetCryptstalkerArmor = core.NewItemSet(core.ItemSet{ Name: "Cryptstalker Armor", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Rapid Fire Duration", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.RapidFireAura.Duration += time.Second * 4 }, })) }, 4: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() hunter.AddStats(stats.Stats{ stats.AttackPower: 50, stats.RangedAttackPower: 50, }) if hunter.pet == nil { return } core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Stalker's Ally", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.pet.AddStatsDynamic(sim, stats.Stats{ stats.AttackPower: 50, stats.RangedAttackPower: 50, }) }, })) }, 6: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() actionID := core.ActionID{SpellID: 28753} manaMetrics := hunter.NewManaMetrics(actionID) hunter.RegisterAura(core.Aura{ Label: "Adrenaline Rush", Duration: core.NeverExpires, OnReset: func(aura *core.Aura, sim *core.Simulation) { aura.Activate(sim) }, OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { if spell.ProcMask.Matches(core.ProcMaskRanged) && result.DidCrit() { hunter.AddMana(sim, 50, manaMetrics) } }, }) }, 8: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Cryptstalker Aimed and Multishot Bonus", OnInit: func(aura *core.Aura, sim *core.Simulation) { if hunter.AimedShot != nil { hunter.AimedShot.Cost.FlatModifier -= 20.0 } hunter.MultiShot.Cost.FlatModifier -= 20.0 }, })) }, }, })
https://www.wowhead.com/classic/item-set=530/cryptstalker-armor
var ItemSetDragonstalkersArmor = core.NewItemSet(core.ItemSet{ Name: "Dragonstalker Armor", Bonuses: map[int32]core.ApplyEffect{ 3: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Improved Aspect of the Hawk", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.AspectOfTheHawkAPMultiplier += 0.25 }, })) }, 5: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() if hunter.pet == nil { return } core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Nature's Ally", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.pet.AddStatDynamic(sim, stats.Stamina, 40) hunter.pet.AddResistancesDynamic(sim, 60) }, })) }, 8: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() debuffAuras := hunter.NewEnemyAuraArray(core.ExposeWeaknessAura) core.MakeProcTriggerAura(&hunter.Unit, core.ProcTrigger{ Name: "T2 - Hunter - Ranged 8P Bonus Trigger", Callback: core.CallbackOnSpellHitDealt, Outcome: core.OutcomeLanded, ProcMask: core.ProcMaskRanged, PPM: 0.5, Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { debuffAuras.Get(result.Target).Activate(sim) }, }) }, }, })
var ItemSetFieldMarshalsPursuit = core.NewItemSet(core.ItemSet{ Name: "Field Marshal's Pursuit", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 20) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Agility, 20) }, }, })
var ItemSetGiantStalkers = core.NewItemSet(core.ItemSet{ Name: "Giantstalker Armor", Bonuses: map[int32]core.ApplyEffect{ 3: func(agent core.Agent) { }, 5: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() if hunter.pet == nil { return } core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Nature's Ally", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.pet.AddStatDynamic(sim, stats.Stamina, 30) hunter.pet.AddResistancesDynamic(sim, 40) }, })) }, 8: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() hunter.RegisterAura(core.Aura{ Label: "Improved Volley and Multishot", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.Volley.BaseDamageMultiplierAdditive += 0.15 hunter.MultiShot.BaseDamageMultiplierAdditive += 0.15 }, }) }, }, })
var ItemSetLieutenantCommandersPursuance = core.NewItemSet(core.ItemSet{ Name: "Lieutenant Commander's Pursuance", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Agility, 20) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 20) }, }, })
https://www.wowhead.com/classic/item-set=550/lieutenant-commanders-pursuance
var ItemSetLieutenantCommandersPursuit = core.NewItemSet(core.ItemSet{ Name: "Lieutenant Commander's Pursuit", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Parry, 1*core.ParryRatingPerParryChance) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 15) }, }, })
https://www.wowhead.com/classic/item-set=362/lieutenant-commanders-pursuit
var ItemSetPredatorsArmor = core.NewItemSet(core.ItemSet{ Name: "Predator's Armor", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() hunter.AddStats(stats.Stats{ stats.AttackPower: 20, stats.RangedAttackPower: 20, }) }, 3: func(agent core.Agent) { }, 5: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Improved Serpent Sting", OnInit: func(aura *core.Aura, sim *core.Simulation) { for _, dot := range hunter.SerpentSting.Dots() { if dot != nil { dot.NumberOfTicks += 1 dot.RecomputeAuraDuration() } } }, })) }, }, })
var ItemSetStrikersGarb = core.NewItemSet(core.ItemSet{ Name: "Striker's Garb", Bonuses: map[int32]core.ApplyEffect{ 3: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Striker's Arcane Shot Bonus", OnInit: func(aura *core.Aura, sim *core.Simulation) { if hunter.ArcaneShot != nil { hunter.ArcaneShot.Cost.Multiplier -= 10.0 } }, })) }, 5: func(agent core.Agent) { hunter := agent.(HunterAgent).GetHunter() core.MakePermanent(hunter.RegisterAura(core.Aura{ Label: "Striker's Rapid Bonus", OnInit: func(aura *core.Aura, sim *core.Simulation) { hunter.RapidFire.CD.Duration -= time.Minute * 2 }, })) }, }, })
https://www.wowhead.com/classic/item-set=509/strikers-garb
var ItemSetWarlordsPursuit = core.NewItemSet(core.ItemSet{ Name: "Warlord's Pursuit", Bonuses: map[int32]core.ApplyEffect{ 2: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Stamina, 20) }, 4: func(agent core.Agent) { }, 6: func(agent core.Agent) { c := agent.GetCharacter() c.AddStat(stats.Agility, 20) }, }, })
var PetConfigs = map[proto.Hunter_Options_PetType]PetConfig{ proto.Hunter_Options_Cat: { Name: "Cat", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: Claw, Health: 0.98, Armor: 1.00, Damage: 1.10, CustomRotation: func(sim *core.Simulation, hp *HunterPet, tryCast func(*core.Spell) bool) { if hp.specialAbility.CD.IsReady(sim) && hp.CurrentFocusPerSecond() > hp.focusDump.Cost.BaseCost/1.6 { if !tryCast(hp.specialAbility) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } else { if !tryCast(hp.focusDump) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } }, }, proto.Hunter_Options_WindSerpent: { Name: "Wind Serpent", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: LightningBreath, Health: 1.00, Armor: 1.00, Damage: 1.07, }, proto.Hunter_Options_Bat: { Name: "Bat", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: Screech, Health: 1.00, Armor: 1.00, Damage: 1.07, CustomRotation: func(sim *core.Simulation, hp *HunterPet, tryCast func(*core.Spell) bool) { if hp.specialAbility.CD.IsReady(sim) { if !tryCast(hp.specialAbility) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } else { if !tryCast(hp.focusDump) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } }, }, proto.Hunter_Options_Bear: { Name: "Bear", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: Claw, Health: 1.08, Armor: 1.05, Damage: 0.91, }, proto.Hunter_Options_Boar: { Name: "Boar", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.04, Armor: 1.09, Damage: 0.90, }, proto.Hunter_Options_CarrionBird: { Name: "Carrion Bird", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: Claw, Health: 1.00, Armor: 1.05, Damage: 1.00, }, proto.Hunter_Options_Owl: { Name: "Owl", MobType: proto.MobType_MobTypeBeast, FocusDump: Claw, Health: 1.00, Armor: 1.00, Damage: 1.07, }, proto.Hunter_Options_Crab: { Name: "Crab", MobType: proto.MobType_MobTypeBeast, FocusDump: Claw, Health: 0.96, Armor: 1.13, Damage: 0.95, }, proto.Hunter_Options_Crocolisk: { Name: "Crocolisk", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 0.95, Armor: 1.10, Damage: 1.00, }, proto.Hunter_Options_Gorilla: { Name: "Gorilla", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.04, Armor: 1.00, Damage: 1.02, }, proto.Hunter_Options_Hyena: { Name: "Hyena", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.00, Armor: 1.05, Damage: 1.00, }, proto.Hunter_Options_Raptor: { Name: "Raptor", MobType: proto.MobType_MobTypeBeast, SpecialAbility: Bite, FocusDump: Claw, Health: 0.95, Armor: 1.03, Damage: 1.10, }, proto.Hunter_Options_Scorpid: { Name: "Scorpid", MobType: proto.MobType_MobTypeBeast, SpecialAbility: ScorpidPoison, FocusDump: Claw, Health: 1.00, Armor: 1.10, Damage: 0.94, CustomRotation: func(sim *core.Simulation, hp *HunterPet, tryCast func(*core.Spell) bool) { target := hp.CurrentTarget if (hp.specialAbility.Dot(target).GetStacks() < hp.specialAbility.Dot(target).MaxStacks || hp.specialAbility.Dot(target).RemainingDuration(sim) < time.Second*3) && hp.CurrentFocus() < 90 { if !tryCast(hp.specialAbility) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } else { if !tryCast(hp.focusDump) && hp.GCD.IsReady(sim) { hp.WaitUntil(sim, sim.CurrentTime+time.Millisecond*500) } } }, }, proto.Hunter_Options_Spider: { Name: "Spider", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.00, Armor: 1.00, Damage: 1.07, }, proto.Hunter_Options_Tallstrider: { Name: "Tallstrider", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.05, Armor: 1.00, Damage: 1.00, }, proto.Hunter_Options_Turtle: { Name: "Turtle", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.00, Armor: 1.13, Damage: 0.90, }, proto.Hunter_Options_Wolf: { Name: "Wolf", MobType: proto.MobType_MobTypeBeast, FocusDump: Bite, Health: 1.00, Armor: 1.05, Damage: 1.00, }, }
Abilities reference: https://wotlk.wowhead.com/hunter-pets https://wotlk.wowhead.com/guides/hunter-dps-best-pets-taming-loyalty-burning-crusade-classic
var RaptorStrikeBaseDamage = [RaptorStrikeRanks + 1]float64{0, 5, 11, 21, 34, 50, 80, 110, 140}
var RaptorStrikeLevel = [RaptorStrikeRanks + 1]int{0, 1, 8, 16, 24, 32, 40, 48, 56}
var RaptorStrikeManaCost = [RaptorStrikeRanks + 1]float64{0, 15, 25, 35, 45, 55, 70, 80, 100}
var RaptorStrikeSpellId = [RaptorStrikeRanks + 1]int32{0, 2973, 14260, 14261, 14262, 14263, 14264, 14265, 14266}
var RaptorStrikeSpellIdMeleeSpecialist = [RaptorStrikeRanks + 1]int32{0, 415335, 415336, 415337, 415338, 415340, 415341, 415342, 415343}
var TalentTreeSizes = [3]int{16, 14, 16}
Functions ¶
func RegisterHunter ¶
func RegisterHunter()
Types ¶
type Hunter ¶
type Hunter struct {
core.Character
Talents *proto.HunterTalents
Options *proto.Hunter_Options
AmmoDPS float64
AmmoDamageBonus float64
NormalizedAmmoDamageBonus float64
// Miscellaneous set bonuses that require extra logic inside of spells
AspectOfTheHawkAPMultiplier float64
AimedShot *core.Spell
ArcaneShot *core.Spell
ExplosiveTrap *core.Spell
ImmolationTrap *core.Spell
FreezingTrap *core.Spell
KillCommand *core.Spell
MultiShot *core.Spell
RapidFire *core.Spell
RaptorStrike *core.Spell
RaptorStrikeHit *core.Spell
MongooseBite *core.Spell
ScorpidSting *core.Spell
SerpentSting *core.Spell
SilencingShot *core.Spell
Volley *core.Spell
WingClip *core.Spell
Shots []*core.Spell
Strikes []*core.Spell
MeleeSpells []*core.Spell
LastShot *core.Spell
// The aura that allows you to cast Mongoose Bite
DefensiveState *core.Aura
RapidFireAura *core.Aura
BestialWrathPetAura *core.Aura
// contains filtered or unexported fields
}
func (*Hunter) AddPartyBuffs ¶
func (hunter *Hunter) AddPartyBuffs(_ *proto.PartyBuffs)
func (*Hunter) AddRaidBuffs ¶
func (*Hunter) ApplyTalents ¶
func (hunter *Hunter) ApplyTalents()
func (*Hunter) GetCharacter ¶
func (*Hunter) Initialize ¶
func (hunter *Hunter) Initialize()
func (*Hunter) NewHunterPet ¶
func (*Hunter) OnGCDReady ¶
func (hunter *Hunter) OnGCDReady(_ *core.Simulation)
func (*Hunter) Reset ¶
func (hunter *Hunter) Reset(sim *core.Simulation)
func (*Hunter) TryRaptorStrike ¶
Returns true if the regular melee swing should be used, false otherwise.
type HunterAgent ¶
type HunterAgent interface {
GetHunter() *Hunter
}
Agent is a generic way to access underlying hunter on any of the agents.
type HunterPet ¶
func (*HunterPet) ExecuteCustomRotation ¶
func (hp *HunterPet) ExecuteCustomRotation(sim *core.Simulation)
func (*HunterPet) Initialize ¶
func (hp *HunterPet) Initialize()
func (*HunterPet) NewPetAbility ¶
func (hp *HunterPet) NewPetAbility(abilityType PetAbilityType, isPrimary bool) *core.Spell
func (*HunterPet) Reset ¶
func (hp *HunterPet) Reset(_ *core.Simulation)
type PetAbilityType ¶
type PetAbilityType int
const ( Unknown PetAbilityType = iota Bite Claw Screech FuriousHowl LightningBreath ScorpidPoison )