Skip to content

Commit

Permalink
Implement item swapping in APL
Browse files Browse the repository at this point in the history
  • Loading branch information
jimmyt857 committed Dec 23, 2023
1 parent 8c11e5c commit dd20c99
Show file tree
Hide file tree
Showing 31 changed files with 407 additions and 389 deletions.
3 changes: 3 additions & 0 deletions proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ message Player {
Consumes consumes = 4;
UnitStats bonus_stats = 36;

bool enable_item_swap = 46;
ItemSwap item_swap = 45;

IndividualBuffs buffs = 15;

oneof spec {
Expand Down
14 changes: 13 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ message APLListItem {
APLAction action = 3; // The action to be performed.
}

// NextIndex: 17
// NextIndex: 18
message APLAction {
APLValue condition = 1; // If set, action will only execute if value is true or != 0.

Expand All @@ -73,6 +73,7 @@ message APLAction {
APLActionActivateAura activate_aura = 13;
APLActionCancelAura cancel_aura = 10;
APLActionTriggerICD trigger_icd = 11;
APLActionItemSwap item_swap = 17;
}
}

Expand Down Expand Up @@ -249,6 +250,17 @@ message APLActionTriggerICD {
ActionID aura_id = 1;
}

message APLActionItemSwap {
enum SwapSet {
Unknown = 0;
Main = 1;
Swap1 = 2;
}

// The set to swap to.
SwapSet swap_set = 1;
}

///////////////////////////////////////////////////////////////////////////
// VALUES
///////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 2 additions & 0 deletions proto/ui.proto
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ message SavedSettings {
Cooldowns cooldowns = 6;
string rotation_json = 8;
repeated Profession professions = 9;
bool enable_item_swap = 18;
ItemSwap item_swap = 17;

int32 reaction_time_ms = 10;
int32 channel_clip_delay_ms = 14;
Expand Down
2 changes: 2 additions & 0 deletions sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return rot.newActionCancelAura(config.GetCancelAura())
case *proto.APLAction_TriggerIcd:
return rot.newActionTriggerICD(config.GetTriggerIcd())
case *proto.APLAction_ItemSwap:
return rot.newActionItemSwap(config.GetItemSwap())
default:
return nil
}
Expand Down
44 changes: 44 additions & 0 deletions sim/core/apl_actions_misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"fmt"

"github.com/wowsims/wotlk/sim/core/proto"
)

Expand Down Expand Up @@ -117,3 +118,46 @@ func (action *APLActionTriggerICD) Execute(sim *Simulation) {
func (action *APLActionTriggerICD) String() string {
return fmt.Sprintf("Trigger ICD(%s)", action.aura.ActionID)
}

type APLActionItemSwap struct {
defaultAPLActionImpl
character *Character
swapSet proto.APLActionItemSwap_SwapSet
}

func (rot *APLRotation) newActionItemSwap(config *proto.APLActionItemSwap) APLActionImpl {
if config.SwapSet == proto.APLActionItemSwap_Unknown {
rot.ValidationWarning("Unknown item swap set")
return nil
}

character := rot.unit.Env.Raid.GetPlayerFromUnit(rot.unit).GetCharacter()
if !character.ItemSwap.IsEnabled() {
if config.SwapSet != proto.APLActionItemSwap_Main {
rot.ValidationWarning("No swap set configured in Settings.")
}
return nil
}

return &APLActionItemSwap{
character: character,
swapSet: config.SwapSet,
}
}
func (action *APLActionItemSwap) IsReady(sim *Simulation) bool {
return (action.swapSet == proto.APLActionItemSwap_Main) == action.character.ItemSwap.IsSwapped()
}
func (action *APLActionItemSwap) Execute(sim *Simulation) {
if sim.Log != nil {
action.character.Log(sim, "Item Swap to set %s", action.swapSet)
}

if action.swapSet == proto.APLActionItemSwap_Main {
action.character.ItemSwap.reset(sim)
} else {
action.character.ItemSwap.SwapItems(sim, action.character.ItemSwap.slots, true)
}
}
func (action *APLActionItemSwap) String() string {
return fmt.Sprintf("Item Swap(%s)", action.swapSet)
}
4 changes: 4 additions & 0 deletions sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character
}
character.PseudoStats.InFrontOfTarget = player.InFrontOfTarget

if player.EnableItemSwap && player.ItemSwap != nil {
character.enableItemSwap(player.ItemSwap, character.DefaultMeleeCritMultiplier(), character.DefaultMeleeCritMultiplier(), 0)
}

return character
}

Expand Down
60 changes: 44 additions & 16 deletions sim/core/item_swaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ type ItemSwap struct {
ohCritMultiplier float64
rangedCritMultiplier float64

// Which slots to actually swap.
slots []proto.ItemSlot

// Used for resetting
initialEquippedItems [3]Item
initialUnequippedItems [3]Item
Expand All @@ -33,15 +36,49 @@ TODO All the extra parameters here and the code in multiple places for handling
we'll need to figure out something cleaner as this will be quite error-prone
*/
func (character *Character) EnableItemSwap(itemSwap *proto.ItemSwap, mhCritMultiplier float64, ohCritMultiplier float64, rangedCritMultiplier float64) {
items := getItems(itemSwap)
func (character *Character) enableItemSwap(itemSwap *proto.ItemSwap, mhCritMultiplier float64, ohCritMultiplier float64, rangedCritMultiplier float64) {
var slots []proto.ItemSlot
hasMhSwap := itemSwap.MhItem != nil && itemSwap.MhItem.Id != 0
hasOhSwap := itemSwap.OhItem != nil && itemSwap.OhItem.Id != 0
hasRangedSwap := itemSwap.RangedItem != nil && itemSwap.RangedItem.Id != 0

mainItems := [3]Item{
character.Equipment[proto.ItemSlot_ItemSlotMainHand],
character.Equipment[proto.ItemSlot_ItemSlotOffHand],
character.Equipment[proto.ItemSlot_ItemSlotRanged],
}
swapItems := [3]Item{
toItem(itemSwap.MhItem),
toItem(itemSwap.OhItem),
toItem(itemSwap.RangedItem),
}

// Handle MH and OH together, because present MH + empty OH --> swap MH and unequip OH
if hasMhSwap || hasOhSwap {
if swapItems[0].ID != mainItems[0].ID {
slots = append(slots, proto.ItemSlot_ItemSlotMainHand)
}
if swapItems[1].ID != mainItems[1].ID {
slots = append(slots, proto.ItemSlot_ItemSlotOffHand)
}
}
if hasRangedSwap {
if swapItems[2].ID != mainItems[2].ID {
slots = append(slots, proto.ItemSlot_ItemSlotRanged)
}
}

if len(slots) == 0 {
return
}

character.ItemSwap = ItemSwap{
character: character,
mhCritMultiplier: mhCritMultiplier,
ohCritMultiplier: ohCritMultiplier,
rangedCritMultiplier: rangedCritMultiplier,
unEquippedItems: items,
slots: slots,
unEquippedItems: swapItems,
swapped: false,
}
}
Expand Down Expand Up @@ -161,7 +198,10 @@ func (swap *ItemSwap) SwapItems(sim *Simulation, slots []proto.ItemSlot, useGCD
}

if useGCD {
character.SetGCDTimer(sim, 1500*time.Millisecond+sim.CurrentTime)
newGCD := sim.CurrentTime + 1500*time.Millisecond
if newGCD > character.GCD.ReadyAt() {
character.SetGCDTimer(sim, newGCD)
}
}
swap.swapped = !swap.swapped
}
Expand Down Expand Up @@ -261,18 +301,6 @@ func getInitialEquippedItems(character *Character) [3]Item {
return items
}

func getItems(itemSwap *proto.ItemSwap) [3]Item {
var items [3]Item

if itemSwap != nil {
items[0] = toItem(itemSwap.MhItem)
items[1] = toItem(itemSwap.OhItem)
items[2] = toItem(itemSwap.RangedItem)
}

return items
}

func toItem(itemSpec *proto.ItemSpec) Item {
if itemSpec == nil {
return Item{}
Expand Down
4 changes: 0 additions & 4 deletions sim/deathknight/dps/dps_deathknight.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ func NewDpsDeathknight(character *core.Character, player *proto.Player) *DpsDeat
AutoSwingMelee: true,
})

if dpsDk.Talents.SummonGargoyle && dpsDk.Rotation.UseGargoyle && dpsDk.Rotation.EnableWeaponSwap {
dpsDk.EnableItemSwap(dpsDk.Rotation.WeaponSwap, dpsDk.DefaultMeleeCritMultiplier(), dpsDk.DefaultMeleeCritMultiplier(), 0)
}

dpsDk.br.dk = dpsDk
dpsDk.sr.dk = dpsDk
dpsDk.ur.dk = dpsDk
Expand Down
13 changes: 6 additions & 7 deletions sim/shaman/enhancement/enhancement.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ func NewEnhancementShaman(character *core.Character, options *proto.Player) *Enh

enh.ApplySyncType(enhOptions.Options.SyncType)

if enh.Totems.UseFireElemental && enhOptions.Rotation.EnableItemSwap {
enh.EnableItemSwap(enhOptions.Rotation.ItemSwap, enh.DefaultMeleeCritMultiplier(), enh.DefaultMeleeCritMultiplier(), 0)
}

if enhOptions.Rotation.LightningboltWeave {
enh.maelstromWeaponMinStack = enhOptions.Rotation.MaelstromweaponMinStack
} else {
Expand Down Expand Up @@ -136,9 +132,12 @@ func (enh *EnhancementShaman) Initialize() {
})
}
enh.DelayDPSCooldowns(3 * time.Second)
enh.RegisterPrepullAction(-time.Second, func(sim *core.Simulation) {
enh.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand}, false)
})

if !enh.IsUsingAPL {
enh.RegisterPrepullAction(-time.Second, func(sim *core.Simulation) {
enh.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand}, false)
})
}
}

func (enh *EnhancementShaman) Reset(sim *core.Simulation) {
Expand Down
2 changes: 1 addition & 1 deletion sim/shaman/fire_elemental_totem.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (shaman *Shaman) registerFireElementalTotem() {
shaman.FireElemental.EnableWithTimeout(sim, shaman.FireElemental, fireTotemDuration)

//TODO handle more then one swap if the fight is greater then 5 mins, for now will just do the one.
if shaman.FireElementalTotem.SpellMetrics[target.Index].Casts == 1 {
if !shaman.IsUsingAPL && shaman.FireElementalTotem.SpellMetrics[target.Index].Casts == 1 {
shaman.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand}, true)
}

Expand Down
10 changes: 4 additions & 6 deletions sim/warlock/warlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,10 @@ func (warlock *Warlock) Reset(sim *core.Simulation) {
warlock.petStmBonusSP = 0
}

warlock.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand,
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}, false)
if !warlock.IsUsingAPL {
warlock.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand,
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}, false)
}
warlock.corrRefreshList = make([]time.Duration, len(warlock.Env.Encounter.TargetUnits))
warlock.setupCooldowns(sim)
}
Expand Down Expand Up @@ -236,10 +238,6 @@ func NewWarlock(character *core.Character, options *proto.Player) *Warlock {

warlock.Infernal = warlock.NewInfernal()

if warlock.Rotation.Type == proto.Warlock_Rotation_Affliction && warlock.Rotation.EnableWeaponSwap {
warlock.EnableItemSwap(warlock.Rotation.WeaponSwap, 1, 1, 1)
}

warlock.applyWeaponImbue()
wotlk.ConstructValkyrPets(&warlock.Character)

Expand Down
10 changes: 0 additions & 10 deletions sim/warlock/warlock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ func TestAffliction(t *testing.T) {
Glyphs: AfflictionGlyphs,
Consumes: FullConsumes,
SpecOptions: core.SpecOptionsCombo{Label: "Affliction Warlock", SpecOptions: DefaultAfflictionWarlock},
OtherSpecOptions: []core.SpecOptionsCombo{
{Label: "AffItemSwap", SpecOptions: afflictionItemSwap},
},

ItemFilter: ItemFilter,
}))
Expand Down Expand Up @@ -129,13 +126,6 @@ var DefaultAfflictionWarlock = &proto.Player_Warlock{
},
}

var afflictionItemSwap = &proto.Player_Warlock{
Warlock: &proto.Warlock{
Options: defaultAfflictionOptions,
Rotation: afflictionItemSwapRotation,
},
}

var defaultAfflictionOptions = &proto.Warlock_Options{
Armor: proto.Warlock_Options_FelArmor,
Summon: proto.Warlock_Options_Felhunter,
Expand Down
Loading

0 comments on commit dd20c99

Please sign in to comment.