Skip to content

Commit

Permalink
Merge pull request #4117 from Horatio27/itemswap_fixes
Browse files Browse the repository at this point in the history
Fixes for Item Swapping UI and APL
  • Loading branch information
Horatio27 authored Dec 29, 2023
2 parents e4141c0 + 09d39b8 commit b70dc25
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 89 deletions.
2 changes: 1 addition & 1 deletion sim/core/apl_actions_misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func (action *APLActionItemSwap) Execute(sim *Simulation) {
if action.swapSet == proto.APLActionItemSwap_Main {
action.character.ItemSwap.reset(sim)
} else {
action.character.ItemSwap.SwapItems(sim, action.character.ItemSwap.slots, true)
action.character.ItemSwap.SwapItems(sim, action.character.ItemSwap.slots)
}
}
func (action *APLActionItemSwap) String() string {
Expand Down
1 change: 0 additions & 1 deletion sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ func (character *Character) Finalize() {
}

character.majorCooldownManager.finalize()
character.ItemSwap.finalize()
}

func (character *Character) FillPlayerStats(playerStats *proto.PlayerStats) {
Expand Down
48 changes: 7 additions & 41 deletions sim/core/item_swaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ type ItemSwap struct {
// Which slots to actually swap.
slots []proto.ItemSlot

// Used for resetting
initialEquippedItems [3]Item
initialUnequippedItems [3]Item

// Holds items that are currently not equipped
unEquippedItems [3]Item
swapped bool
Expand Down Expand Up @@ -164,7 +160,7 @@ func (swap *ItemSwap) CalcStatChanges(slots []proto.ItemSlot) stats.Stats {
return newStats
}

func (swap *ItemSwap) SwapItems(sim *Simulation, slots []proto.ItemSlot, useGCD bool) {
func (swap *ItemSwap) SwapItems(sim *Simulation, slots []proto.ItemSlot) {
if !swap.IsEnabled() {
return
}
Expand Down Expand Up @@ -201,12 +197,12 @@ func (swap *ItemSwap) SwapItems(sim *Simulation, slots []proto.ItemSlot, useGCD
character.AutoAttacks.StopMeleeUntil(sim, sim.CurrentTime, false)
}

if useGCD {
// If GCD is ready then use the GCD, otherwise we assume it's being used along side a spell.
if character.GCD.IsReady(sim) {
newGCD := sim.CurrentTime + 1500*time.Millisecond
if newGCD > character.GCD.ReadyAt() {
character.SetGCDTimer(sim, newGCD)
}
character.SetGCDTimer(sim, newGCD)
}

swap.swapped = !swap.swapped
}

Expand Down Expand Up @@ -269,42 +265,12 @@ func (swap *ItemSwap) swapWeapon(slot proto.ItemSlot) {
}
}

func (swap *ItemSwap) finalize() {
if !swap.IsEnabled() {
return
}

swap.initialEquippedItems = getInitialEquippedItems(swap.character)
swap.initialUnequippedItems = swap.unEquippedItems
}

func (swap *ItemSwap) reset(sim *Simulation) {
if !swap.IsEnabled() {
if !swap.IsEnabled() || !swap.IsSwapped() {
return
}

slots := [3]proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}
for i, slot := range slots {
swap.character.Equipment[slot] = swap.initialEquippedItems[i]
swap.swapWeapon(slot)
}

swap.unEquippedItems = swap.initialUnequippedItems
swap.swapped = false

for _, onSwap := range swap.onSwapCallbacks {
onSwap(sim)
}
}

func getInitialEquippedItems(character *Character) [3]Item {
var items [3]Item

for i := range items {
items[i] = character.Equipment[i+int(offset)]
}

return items
swap.SwapItems(sim, swap.slots)
}

func toItem(itemSpec *proto.ItemSpec) Item {
Expand Down
16 changes: 8 additions & 8 deletions sim/deathknight/dps/rotation_unholy_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,26 +169,26 @@ func (dk *DpsDeathknight) weaponSwapCheck(sim *core.Simulation) bool {
if dk.ur.mhSwap == WeaponSwap_BlackMagic {
if !dk.ur.mhSwapped && shouldSwapBm {
// Swap to BM
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand})
dk.ur.mhSwapped = true
} else if dk.ur.mhSwapped && shouldSwapBackFromBm {
// Swap to Normal set and set BM Icd tracker
dk.ur.bmIcd = dk.ur.blackMagicProc.ExpiresAt() + 35*time.Second
dk.ur.mhSwapped = false
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand})
}
}

if dk.ur.ohSwap == WeaponSwap_BlackMagic {
if !dk.ur.ohSwapped && shouldSwapBm {
// Swap to BM
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand})
dk.ur.ohSwapped = true
} else if dk.ur.ohSwapped && shouldSwapBackFromBm {
// Swap to Normal set and set BM Icd tracker
dk.ur.bmIcd = dk.ur.blackMagicProc.ExpiresAt() + 35*time.Second
dk.ur.ohSwapped = false
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand})
}
}

Expand All @@ -200,24 +200,24 @@ func (dk *DpsDeathknight) weaponSwapCheck(sim *core.Simulation) bool {
if dk.ur.mhSwap == WeaponSwap_Berserking {
if !dk.ur.mhSwapped && !dk.ur.berserkingMh.IsActive() && shouldSwapBerserking {
// Swap to Berserking
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand})
dk.ur.mhSwapped = true
} else if dk.ur.mhSwapped && (dk.ur.berserkingMh.IsActive() || shouldSwapBackfromBerserking) {
// Swap to Normal set
dk.ur.mhSwapped = false
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand})
}
}

if dk.ur.ohSwap == WeaponSwap_Berserking {
if !dk.ur.ohSwapped && !dk.ur.berserkingOh.IsActive() && shouldSwapBerserking {
// Swap to Berserking
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand})
dk.ur.ohSwapped = true
} else if dk.ur.ohSwapped && (dk.ur.berserkingOh.IsActive() || shouldSwapBackfromBerserking) {
// Swap to Normal set
dk.ur.ohSwapped = false
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand}, true)
dk.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotOffHand})
}
}

Expand Down
2 changes: 1 addition & 1 deletion sim/shaman/enhancement/enhancement.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (enh *EnhancementShaman) Initialize() {

if !enh.IsUsingAPL {
enh.RegisterPrepullAction(-time.Second, func(sim *core.Simulation) {
enh.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand}, false)
enh.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand, proto.ItemSlot_ItemSlotOffHand})
})
}
}
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 @@ -57,7 +57,7 @@ func (shaman *Shaman) registerFireElementalTotem() {

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

// Add a dummy aura to show in metrics
Expand Down
2 changes: 1 addition & 1 deletion sim/warlock/rotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ func (warlock *Warlock) OnGCDReady(sim *core.Simulation) {
// after-GCD actions
if ac.Spell == warlock.Corruption && warlock.ItemSwap.IsEnabled() && warlock.ItemSwap.IsSwapped() {
warlock.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand,
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}, true)
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged})
}

return
Expand Down
2 changes: 1 addition & 1 deletion sim/warlock/warlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (warlock *Warlock) Reset(sim *core.Simulation) {

if !warlock.IsUsingAPL {
warlock.ItemSwap.SwapItems(sim, []proto.ItemSlot{proto.ItemSlot_ItemSlotMainHand,
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged}, false)
proto.ItemSlot_ItemSlotOffHand, proto.ItemSlot_ItemSlotRanged})
}
warlock.corrRefreshList = make([]time.Duration, len(warlock.Env.Encounter.TargetUnits))
warlock.setupCooldowns(sim)
Expand Down
43 changes: 19 additions & 24 deletions ui/core/components/gear_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,21 @@ export class ItemPicker extends Component {
}
}

export class IconItemSwapPicker<SpecType extends Spec, ValueType> extends Input<Player<SpecType>, ValueType> {
private readonly config: InputConfig<Player<SpecType>, ValueType>;
export class IconItemSwapPicker extends Component {

private readonly iconAnchor: HTMLAnchorElement;
private readonly socketsContainerElem: HTMLElement;
private readonly player: Player<SpecType>;
private readonly player: Player<any>;
private readonly slot: ItemSlot;

// All items and enchants that are eligible for this slot
private _items: Array<Item> = [];
private _enchants: Array<Enchant> = [];

constructor(parent: HTMLElement, simUI: SimUI, player: Player<SpecType>, slot: ItemSlot, config: InputConfig<Player<SpecType>, ValueType>) {
super(parent, 'icon-picker-root', player, config)
constructor(parent: HTMLElement, simUI: SimUI, player: Player<any>, slot: ItemSlot) {
super(parent, 'icon-picker-root')
this.rootElem.classList.add('icon-picker');
this.player = player;
this.config = config;
this.slot = slot;

this.iconAnchor = document.createElement('a');
Expand All @@ -333,12 +332,12 @@ export class IconItemSwapPicker<SpecType extends Spec, ValueType> extends Input<
this._enchants = this.player.getEnchants(slot);
const gearData = {
equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => {
let isg = this.player.getItemSwapGear();
this.player.setItemSwapGear(eventID, isg.withEquippedItem(this.slot, equippedItem, player.canDualWield2H()));
this.inputChanged(eventID);
let curIsg = player.getItemSwapGear();
curIsg = curIsg.withEquippedItem(slot, equippedItem, player.canDualWield2H())
player.setItemSwapGear(eventID, curIsg);
},
getEquippedItem: () => this.player.getItemSwapGear().getEquippedItem(this.slot),
changeEvent: config.changedEvent(player),
changeEvent: player.itemSwapChangeEmitter,
}

this.iconAnchor.addEventListener('click', (event: Event) => {
Expand All @@ -352,31 +351,27 @@ export class IconItemSwapPicker<SpecType extends Spec, ValueType> extends Input<
gearData: gearData,
});
});
}).finally(() => this.init());
}
});

getInputElem(): HTMLElement {
return this.iconAnchor;
}
getInputValue(): ValueType {
return this.player.getItemSwapGear().toProto() as unknown as ValueType
player.itemSwapChangeEmitter.on(() => {
this.update(player.getItemSwapGear().getEquippedItem(slot));
});
}

setInputValue(newValue: ValueType): void {
update(newItem: EquippedItem | null) {
this.iconAnchor.style.backgroundImage = `url('${getEmptySlotIconUrl(this.slot)}')`;
this.iconAnchor.removeAttribute('data-wowhead');
this.iconAnchor.href = "#";
this.socketsContainerElem.innerText = '';

const equippedItem = this.player.getItemSwapGear().getEquippedItem(this.slot);
if (equippedItem) {
if (newItem) {
this.iconAnchor.classList.add("active")

equippedItem.asActionId().fillAndSet(this.iconAnchor, true, true);
this.player.setWowheadData(equippedItem, this.iconAnchor);
newItem.asActionId().fillAndSet(this.iconAnchor, true, true);
this.player.setWowheadData(newItem, this.iconAnchor);

equippedItem.allSocketColors().forEach((socketColor, gemIdx) => {
this.socketsContainerElem.appendChild(createGemContainer(socketColor, equippedItem.gems[gemIdx]));
newItem.allSocketColors().forEach((socketColor, gemIdx) => {
this.socketsContainerElem.appendChild(createGemContainer(socketColor, newItem.gems[gemIdx]));
});
} else {
this.iconAnchor.classList.remove("active")
Expand Down
12 changes: 2 additions & 10 deletions ui/core/components/item_swap_picker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Spec, ItemSlot, ItemSpec } from '../proto/common.js';
import { Spec, ItemSlot } from '../proto/common.js';
import { Player } from '../player.js';
import { Component } from './component.js';
import { IconItemSwapPicker } from './gear_picker.js'
Expand Down Expand Up @@ -70,15 +70,7 @@ export class ItemSwapPicker<SpecType extends Spec> extends Component {
swapButton.addEventListener('click', _event => { this.swapWithGear(TypedEvent.nextEventID(), player) });

this.itemSlots.forEach(itemSlot => {
new IconItemSwapPicker(itemSwapContainer, simUI, player, itemSlot, {
getValue: (player: Player<any>) => player.getItemSwapGear().getEquippedItem(itemSlot)?.asSpec() || ItemSpec.create(),
setValue: (eventID: EventID, player: Player<any>, newValue: ItemSpec) => {
let curIsg = player.getItemSwapGear();
curIsg = curIsg.withEquippedItem(itemSlot, player.sim.db.lookupItemSpec(newValue), player.canDualWield2H())
player.setItemSwapGear(eventID, curIsg);
},
changedEvent: (player: Player<any>) => player.itemSwapChangeEmitter,
});
new IconItemSwapPicker(itemSwapContainer, simUI, player, itemSlot)
});
}

Expand Down

0 comments on commit b70dc25

Please sign in to comment.