Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/locales/en/character.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"trinkets": "Trinkets",
"main_hand": "Main Hand",
"off_hand": "Off Hand",
"ranged": "Ranged",
"weapons": "Weapons"
}
}
16 changes: 15 additions & 1 deletion sim/core/attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ func getWeaponMaxRange(item *Item) float64 {
return 40
}

func getWeaponMinRange(item *Item) float64 {
// TBC ANNI: Deadzone will disable MH swings right now
// switch item.RangedWeaponType {
// case proto.RangedWeaponType_RangedWeaponTypeThrown:
// case proto.RangedWeaponType_RangedWeaponTypeUnknown:
// case proto.RangedWeaponType_RangedWeaponTypeWand:
// return 0.
// default:
// return 5
// }

return 0
}

func newWeaponFromItem(item *Item, critMultiplier float64, bonusDps float64) Weapon {
normalizedWeaponSpeed := 2.4
if item.WeaponType == proto.WeaponType_WeaponTypeDagger {
Expand All @@ -77,7 +91,7 @@ func newWeaponFromItem(item *Item, critMultiplier float64, bonusDps float64) Wea
NormalizedSwingSpeed: normalizedWeaponSpeed,
CritMultiplier: critMultiplier,
AttackPowerPerDPS: DefaultAttackPowerPerDPS,
MinRange: 0, // no more deadzone in MoP
MinRange: getWeaponMinRange(item),
MaxRange: getWeaponMaxRange(item),
}
}
Expand Down
14 changes: 14 additions & 0 deletions sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,20 @@ func (character *Character) HasOH() bool {
return character.OffHand().ID != 0
}

// Returns the ranged weapon if one is equipped, and null otherwise.
func (character *Character) GetRangedWeapon() *Item {
weapon := character.Ranged()
if weapon.ID == 0 ||
weapon.RangedWeaponType == proto.RangedWeaponType_RangedWeaponTypeIdol ||
weapon.RangedWeaponType == proto.RangedWeaponType_RangedWeaponTypeLibram ||
weapon.RangedWeaponType == proto.RangedWeaponType_RangedWeaponTypeTotem ||
weapon.RangedWeaponType == proto.RangedWeaponType_RangedWeaponTypeSigil {
return nil
} else {
return weapon
}
}

func (character *Character) HasRangedWeapon() bool {
return character.Ranged() != nil
}
Expand Down
26 changes: 13 additions & 13 deletions sim/core/statweight.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ func (s *UnitStats) ToProto() *proto.UnitStats {
}
}

// // Infer missing stat weight values for HitRating and CritRating if school-specific components were calculated, then call ToProto(). Kept as a separate method in case we want to use the UnitStats struct for other applications
// // than just stat weights.
// func (s *UnitStats) ExportWeights() *proto.UnitStats {
// if s.Stats[stats.HitRating] == 0 {
// s.Stats[stats.HitRating] = s.PseudoStats[proto.PseudoStat_PseudoStatPhysicalHitPercent]/PhysicalHitRatingPerHitPercent + s.PseudoStats[proto.PseudoStat_PseudoStatSpellHitPercent]/SpellHitRatingPerHitPercent
// }

// if s.Stats[stats.CritRating] == 0 {
// s.Stats[stats.CritRating] = (s.PseudoStats[proto.PseudoStat_PseudoStatPhysicalCritPercent] + s.PseudoStats[proto.PseudoStat_PseudoStatSpellCritPercent]) / CritRatingPerCritPercent
// }

// return s.ToProto()
// }
// Infer missing stat weight values for HitRating and CritRating if school-specific components were calculated, then call ToProto(). Kept as a separate method in case we want to use the UnitStats struct for other applications
// than just stat weights.
func (s *UnitStats) ExportWeights() *proto.UnitStats {
if s.Stats[stats.AllHitRating] == 0 {
s.Stats[stats.AllHitRating] = s.PseudoStats[proto.PseudoStat_PseudoStatMeleeHitPercent]/PhysicalHitRatingPerHitPercent + s.PseudoStats[proto.PseudoStat_PseudoStatSpellHitPercent]/SpellHitRatingPerHitPercent
}

if s.Stats[stats.AllCritRating] == 0 {
s.Stats[stats.AllCritRating] = (s.PseudoStats[proto.PseudoStat_PseudoStatMeleeCritPercent] + s.PseudoStats[proto.PseudoStat_PseudoStatSpellCritPercent]) / SpellCritRatingPerCritPercent
}

return s.ToProto()
}

type StatWeightValues struct {
Weights UnitStats
Expand Down
13 changes: 8 additions & 5 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,11 +675,14 @@ func (unit *Unit) GetCurrentPowerBar() PowerBarType {
// Stat dependencies that apply both to players/pets (represented as Character
// structs) and to NPCs (represented as Target structs).
func (unit *Unit) addUniversalStatDependencies() {
// unit.AddStatDependency(stats.HitRating, stats.PhysicalHitPercent, 1/PhysicalHitRatingPerHitPercent)
// unit.AddStatDependency(stats.HitRating, stats.SpellHitPercent, 1/SpellHitRatingPerHitPercent)
// unit.AddStatDependency(stats.ExpertiseRating, stats.SpellHitPercent, 1/SpellHitRatingPerHitPercent)
// unit.AddStatDependency(stats.CritRating, stats.PhysicalCritPercent, 1/CritRatingPerCritPercent)
// unit.AddStatDependency(stats.CritRating, stats.SpellCritPercent, 1/CritRatingPerCritPercent)
unit.AddStatDependency(stats.MeleeHitRating, stats.PhysicalHitPercent, 1/PhysicalHitRatingPerHitPercent)
unit.AddStatDependency(stats.AllHitRating, stats.PhysicalHitPercent, 1/PhysicalHitRatingPerHitPercent)
unit.AddStatDependency(stats.SpellHitRating, stats.SpellHitPercent, 1/SpellHitRatingPerHitPercent)
unit.AddStatDependency(stats.AllHitRating, stats.SpellHitPercent, 1/SpellHitRatingPerHitPercent)
unit.AddStatDependency(stats.MeleeCritRating, stats.PhysicalCritPercent, 1/PhysicalCritRatingPerCritPercent)
unit.AddStatDependency(stats.AllCritRating, stats.PhysicalCritPercent, 1/PhysicalCritRatingPerCritPercent)
unit.AddStatDependency(stats.SpellCritRating, stats.SpellCritPercent, 1/SpellCritRatingPerCritPercent)
unit.AddStatDependency(stats.AllCritRating, stats.SpellCritPercent, 1/SpellCritRatingPerCritPercent)
}

func (unit *Unit) finalize() {
Expand Down
4 changes: 2 additions & 2 deletions ui/core/components/gear_picker/filters_menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ export class FiltersMenu extends BaseModal {
});
}
}

} else if (slot == ItemSlot.ItemSlotRanged) {
const rangedweapontypes = player.getPlayerClass().rangedWeaponTypes;
if (rangedweapontypes.length < 1) {
if (rangedweapontypes.length <= 1) {
return;
}
const rangedWeaponTypeSection = this.newSection(i18n.t('gear_tab.gear_picker.filters.ranged_weapon_type'));
Expand Down
1 change: 1 addition & 0 deletions ui/core/components/gear_picker/gear_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default class GearPicker extends Component {
ItemSlot.ItemSlotWrist,
ItemSlot.ItemSlotMainHand,
ItemSlot.ItemSlotOffHand,
ItemSlot.ItemSlotRanged
].map(slot => new ItemPicker(leftSideRef.value!, this, simUI, player, slot));

const rightItemPickers = [
Expand Down
1 change: 0 additions & 1 deletion ui/core/components/gear_picker/item_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ export default class ItemList<T extends ItemListType> {

if (
label === SelectorModalTabs.Items &&
player.getPlayerClass().weaponTypes.length > 0 &&
(currentSlot === ItemSlot.ItemSlotMainHand || (currentSlot === ItemSlot.ItemSlotOffHand && player.getClass() === Class.ClassWarrior))
) {
if (show1hWeaponRef.value) makeShow1hWeaponsSelector(show1hWeaponRef.value, player.sim);
Expand Down
2 changes: 2 additions & 0 deletions ui/core/components/individual_sim_ui/bulk/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum BulkSimItemSlot {
ItemSlotTrinket,
ItemSlotMainHand,
ItemSlotOffHand,
ItemSlotRanged,
ItemSlotHandWeapon, // Weapon grouping slot for specs that can dual-wield
}

Expand Down Expand Up @@ -49,6 +50,7 @@ export const itemSlotToBulkSimItemSlot: Map<ItemSlot, BulkSimItemSlot> = new Map
[ItemSlot.ItemSlotTrinket2, BulkSimItemSlot.ItemSlotTrinket],
[ItemSlot.ItemSlotMainHand, BulkSimItemSlot.ItemSlotMainHand],
[ItemSlot.ItemSlotOffHand, BulkSimItemSlot.ItemSlotOffHand],
[ItemSlot.ItemSlotRanged, BulkSimItemSlot.ItemSlotRanged],
]);

export const bulkSimItemSlotToSingleItemSlot: Map<BulkSimItemSlot, ItemSlot> = new Map([
Expand Down
35 changes: 20 additions & 15 deletions ui/core/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export class Player<SpecType extends Spec> {
}
this.hiddenMCDs = this.specConfig.hiddenMCDs || new Array<number>();

for (let i = 0; i < ItemSlot.ItemSlotOffHand + 1; ++i) {
for (let i = 0; i < ItemSlot.ItemSlotRanged + 1; ++i) {
this.itemEPCache[i] = new Map();
}

Expand Down Expand Up @@ -498,7 +498,7 @@ export class Player<SpecType extends Spec> {
this.enchantEPCache = new Map();
this.randomSuffixEPCache = new Map();
this.upgradeEPCache = new Map();
for (let i = 0; i < ItemSlot.ItemSlotOffHand + 1; ++i) {
for (let i = 0; i < ItemSlot.ItemSlotRanged + 1; ++i) {
this.itemEPCache[i] = new Map();
}
}
Expand Down Expand Up @@ -568,6 +568,9 @@ export class Player<SpecType extends Spec> {
}

setCurrentStats(eventID: EventID, newStats: PlayerStats) {
newStats.finalStats?.stats.forEach((element, index) => {
console.log("Stat %d - %d", index, element)
});
this.currentStats = newStats;
this.currentStatsEmitter.emit(eventID);
}
Expand Down Expand Up @@ -1282,33 +1285,35 @@ export class Player<SpecType extends Spec> {
});
} else if (Player.WEAPON_SLOTS.includes(slot)) {
itemData = filterItems(itemData, item => {
if (item.handType == HandType.HandTypeUnknown && item.rangedWeaponType == RangedWeaponType.RangedWeaponTypeUnknown) {
return false;
}

if (!filters.weaponTypes.includes(item.weaponType) && item.handType > HandType.HandTypeUnknown) {
if (!filters.weaponTypes.includes(item.weaponType)) {
return false;
}

if (!filters.oneHandedWeapons && item.handType != HandType.HandTypeTwoHand) {
return false;
}
if (!filters.twoHandedWeapons && item.handType == HandType.HandTypeTwoHand) {
return false;
}

// Ranged weapons are equiped in MH slot from MoP onwards
if (!filters.rangedWeaponTypes.includes(item.rangedWeaponType) && item.rangedWeaponType > RangedWeaponType.RangedWeaponTypeUnknown) {
const minSpeed = slot == ItemSlot.ItemSlotMainHand ? filters.minMhWeaponSpeed : filters.minOhWeaponSpeed;
const maxSpeed = slot == ItemSlot.ItemSlotMainHand ? filters.maxMhWeaponSpeed : filters.maxOhWeaponSpeed;
if (minSpeed > 0 && item.weaponSpeed < minSpeed) {
return false;
}
if (maxSpeed > 0 && item.weaponSpeed > maxSpeed) {
return false;
}

let minSpeed = slot == ItemSlot.ItemSlotMainHand ? filters.minMhWeaponSpeed : filters.minOhWeaponSpeed;
let maxSpeed = slot == ItemSlot.ItemSlotMainHand ? filters.maxMhWeaponSpeed : filters.maxOhWeaponSpeed;
if (item.rangedWeaponType > 0) {
minSpeed = filters.minRangedWeaponSpeed;
maxSpeed = filters.maxRangedWeaponSpeed;
return true;
});
} else if (slot == ItemSlot.ItemSlotRanged) {
itemData = filterItems(itemData, item => {
if (!filters.rangedWeaponTypes.includes(item.rangedWeaponType)) {
return false;
}

const minSpeed = filters.minRangedWeaponSpeed;
const maxSpeed = filters.maxRangedWeaponSpeed;
if (minSpeed > 0 && item.weaponSpeed < minSpeed) {
return false;
}
Expand Down
10 changes: 5 additions & 5 deletions ui/core/proto_utils/equipped_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ export const getWeaponStatsBySlot = (item: Item, slot: ItemSlot, upgradeStep: 0)
if (item.weaponSpeed > 0) {
const weaponDps = getWeaponDPS(item, upgradeStep);
if (slot === ItemSlot.ItemSlotMainHand) {
if (item.rangedWeaponType > RangedWeaponType.RangedWeaponTypeUnknown) {
itemStats = itemStats.withPseudoStat(PseudoStat.PseudoStatRangedDps, weaponDps);
} else {
itemStats = itemStats.withPseudoStat(PseudoStat.PseudoStatMainHandDps, weaponDps);
}
itemStats = itemStats.withPseudoStat(PseudoStat.PseudoStatMainHandDps, weaponDps);
} else if (slot === ItemSlot.ItemSlotOffHand) {
itemStats = itemStats.withPseudoStat(PseudoStat.PseudoStatOffHandDps, weaponDps);
} else if (slot === ItemSlot.ItemSlotRanged) {
itemStats = itemStats.withPseudoStat(PseudoStat.PseudoStatRangedDps, weaponDps);
}
}
return itemStats;
Expand Down Expand Up @@ -263,7 +261,9 @@ export class EquippedItem {

withDynamicStats() {
const item = this.item;
console.log("ASDF")
const scalingOptions = item.scalingOptions[0];

item.stats = new Stats().asProtoArray().map((_, index) => scalingOptions.stats[index] || 0);
item.weaponDamageMin = scalingOptions.weaponDamageMin;
item.weaponDamageMax = scalingOptions.weaponDamageMax;
Expand Down
10 changes: 10 additions & 0 deletions ui/core/proto_utils/gear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ abstract class BaseGear {
.some(id => itemIds.includes(id));
}

hasRelic(itemId: number): boolean {
const relicItem = this.getEquippedItem(ItemSlot.ItemSlotRanged);

if (!relicItem) {
return false;
}

return relicItem!.item.id == itemId;
}

/**
* Returns a new Gear set with the item equipped.
*
Expand Down
6 changes: 3 additions & 3 deletions ui/core/proto_utils/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,15 +386,15 @@ export const displayStatOrder: Array<UnitStat> = [
UnitStat.fromStat(Stat.StatMP5),
UnitStat.fromStat(Stat.StatAttackPower),
UnitStat.fromStat(Stat.StatRangedAttackPower),
UnitStat.fromStat(Stat.StatExpertiseRating),
UnitStat.fromStat(Stat.StatArmorPenetration),
UnitStat.fromStat(Stat.StatSpellPenetration),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatMeleeHitPercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatMeleeCritPercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatMeleeHastePercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatRangedHitPercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatRangedCritPercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatRangedHastePercent),
UnitStat.fromStat(Stat.StatExpertiseRating),
UnitStat.fromStat(Stat.StatArmorPenetration),
UnitStat.fromStat(Stat.StatSpellPenetration),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatBlockPercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatDodgePercent),
UnitStat.fromPseudoStat(PseudoStat.PseudoStatParryPercent),
Expand Down
2 changes: 1 addition & 1 deletion ui/core/proto_utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ const itemTypeToSlotsMap: Partial<Record<ItemType, Array<ItemSlot>>> = {
[ItemType.ItemTypeFeet]: [ItemSlot.ItemSlotFeet],
[ItemType.ItemTypeFinger]: [ItemSlot.ItemSlotFinger1, ItemSlot.ItemSlotFinger2],
[ItemType.ItemTypeTrinket]: [ItemSlot.ItemSlotTrinket1, ItemSlot.ItemSlotTrinket2],
[ItemType.ItemTypeRanged]: [ItemSlot.ItemSlotMainHand],
[ItemType.ItemTypeRanged]: [ItemSlot.ItemSlotRanged],
};

export function getEligibleItemSlots(item: Item, isFuryWarrior?: boolean): Array<ItemSlot> {
Expand Down
1 change: 1 addition & 0 deletions ui/i18n/entity_mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export const bulkSlotNamesI18nKeys: Record<BulkSimItemSlot, string> = {
[BulkSimItemSlot.ItemSlotTrinket]: 'trinkets',
[BulkSimItemSlot.ItemSlotMainHand]: 'main_hand',
[BulkSimItemSlot.ItemSlotOffHand]: 'off_hand',
[BulkSimItemSlot.ItemSlotRanged]: 'ranged',
[BulkSimItemSlot.ItemSlotHandWeapon]: 'weapons',
};

Expand Down
Loading