Skip to content

Commit

Permalink
feature(TTW): Spymaster's Web Trinket (WoWAnalyzer#7089)
Browse files Browse the repository at this point in the history
* feature(TTW): Spymaster's Web Trinket

* Update personal contributor entry

* Update personal contributor entry

* feature(TTW): Spymaster's Web Trinket

Review comments

---------

Co-authored-by: Danny Janse <[email protected]>
Co-authored-by: J David Smith <[email protected]>
Co-authored-by: Putro <[email protected]>
  • Loading branch information
4 people authored Oct 3, 2024
1 parent 55f3566 commit 33be06d
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import SpellLink from 'interface/SpellLink';

// prettier-ignore
export default [
change(date(2024, 10, 4), <>Added simple statistics for <ItemLink id={ITEMS.SPYMASTERS_WEB.id}/>.</>, Vetyst),
change(date(2024, 10, 3), 'Fixed rendering of the Header on the character log browser.', Vetyst),
change(date(2024, 9, 30), 'Add Classic Cata Firelands raid zone, headshots, and placeholder image', jazminite),
change(date(2024, 9, 30), 'Enchant checker now detects Spellthreads', Sref),
Expand Down
10 changes: 5 additions & 5 deletions src/CONTRIBUTORS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,14 +564,14 @@ export const HawkCorrigan: Contributor = {
};
export const Vetyst: Contributor = {
nickname: 'Vetyst',
github: 'djanse',
discord: 'vetyst#0001',
github: 'vetyst',
discord: 'vetyst',
avatar: avatar('vetyst-avatar.png'),
mains: [
{
name: 'Vetyst',
spec: SPECS.BALANCE_DRUID,
link: 'https://worldofwarcraft.com/en-gb/character/tarren-mill/vetyst',
name: 'Vetiest',
spec: SPECS.SHADOW_PRIEST,
link: 'https://worldofwarcraft.com/en-gb/character/ragnaros/vetiest',
},
],
};
Expand Down
5 changes: 5 additions & 0 deletions src/common/ITEMS/thewarwithin/trinkets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const trinkets = {
name: 'Signet of the Priory',
icon: 'inv_arathordungeon_signet_color1',
},
SPYMASTERS_WEB: {
id: 220202,
name: "Spymaster's Web",
icon: 'inv_11_0_raid_spymastersweb_purple',
},
} satisfies Record<string, Item>;

export default trinkets;
11 changes: 11 additions & 0 deletions src/common/SPELLS/thewarwithin/trinkets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ const spells = {
name: 'Bolstering Light',
icon: 'inv_arathordungeon_signet_color1',
},
// Spymaster's Web
SPYMASTERS_WEB: {
id: 444959,
name: "Spymaster's Web",
icon: 'ability_spy',
},
SPYMASTERS_REPORT: {
id: 451199,
name: "Spymaster's Report",
icon: 'inv_nerubianspiderling2_black',
},
} satisfies Record<string, Spell>;

export default spells;
1 change: 1 addition & 0 deletions src/parser/core/CASTS_THAT_ARENT_CASTS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const spells: number[] = [
SPELLS.CLOUDBURST_TOTEM_RECALL.id, // Cloudburst reactivation
TALENTS_SHAMAN.SPIRITWALKERS_GRACE_TALENT.id,
SPELLS.FERAL_LUNGE_NOT_A_CAST.id, // duplicate event of regular Feral Lunge cast
SPELLS.HEALING_RAIN_TOTEMIC.id,
//endregion

//region warlock
Expand Down
2 changes: 2 additions & 0 deletions src/parser/core/CombatLogParser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ import SporeTender from 'parser/retail/modules/items/dragonflight/enchants/Spore
import WaftingDevotion from 'parser/retail/modules/items/dragonflight/enchants/WaftingDevotion';
import WaftingWrit from 'parser/retail/modules/items/dragonflight/enchants/WaftingWrit';
import SignetOfThePriory from 'parser/retail/modules/items/thewarwithin/trinkets/SignetOfThePriory';
import SpymastersWeb from 'parser/retail/modules/items/thewarwithin/trinkets/SpymastersWeb';
import FriendlyCompatNormalizer from './FriendlyCompatNormalizer';
import {
AuthorityOfRadiantPower,
Expand Down Expand Up @@ -218,6 +219,7 @@ class CombatLogParser {
stormridersFury: StormridersFury,
authorityOfTheDepths: AuthorityOfTheDepths,
signetOfThePriory: SignetOfThePriory,
spymastersWeb: SpymastersWeb,

// Embellishments
darkmoonSigilAscension: DarkmoonSigilAscension,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import ITEMS from 'common/ITEMS/thewarwithin/trinkets';
import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import Abilities from 'parser/core/modules/Abilities';
import SPELLS from 'common/SPELLS/thewarwithin/trinkets';
import SPELL_CATEGORY from 'parser/core/SPELL_CATEGORY';
import Statistic from 'parser/ui/Statistic';
import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER';
import Events, { ApplyBuffEvent, ApplyBuffStackEvent, CastEvent } from 'parser/core/Events';
import BoringItemValueText from 'parser/ui/BoringItemValueText';
import { formatDuration, formatNumber } from 'common/format';
import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY';
import { calculatePrimaryStat } from 'parser/core/stats';

type SpymastersWebCast = {
timestamp: number;
stacks: number;
};

/**
* Based on the stats provided on wowhead.
*
* https://www.wowhead.com/item=220202/spymasters-web
*/
const SPYMASTERS_WEB_BASE_ILVL = 571;
const SPYMASTERS_WEB_BASE_GAIN = 515;

export default class SpymastersWeb extends Analyzer.withDependencies({
abilities: Abilities,
}) {
protected currentReportStackCount: number = 0;
protected primaryStatBonus: number = 0;
protected SpymastersWebCasts: SpymastersWebCast[] = [];

constructor(options: Options) {
super(options);

// Ensure the combatant has the trinket.
this.active = this.selectedCombatant.hasTrinket(ITEMS.SPYMASTERS_WEB.id);
if (!this.active) {
return;
}

// Add the ability to the spellbook of the current combatant.
this.deps.abilities.add({
spell: SPELLS.SPYMASTERS_WEB.id,
category: SPELL_CATEGORY.ITEMS,
cooldown: 20,
});

this.addEventListener(
Events.applybuff.by(SELECTED_PLAYER).spell(SPELLS.SPYMASTERS_REPORT),
this._onBuffApply,
);
this.addEventListener(
Events.applybuffstack.by(SELECTED_PLAYER).spell(SPELLS.SPYMASTERS_REPORT),
this._onBuffApply,
);
this.addEventListener(
Events.cast.by(SELECTED_PLAYER).spell(SPELLS.SPYMASTERS_WEB),
this._onCast,
);

// Calculate the primary stat bonus we'd receive per stack when the on use effect of the tricket is cast.
this.primaryStatBonus = calculatePrimaryStat(
SPYMASTERS_WEB_BASE_ILVL,
SPYMASTERS_WEB_BASE_GAIN,
this.selectedCombatant.getTrinket(ITEMS.SPYMASTERS_WEB.id)?.itemLevel,
);
}

_onBuffApply(event: ApplyBuffStackEvent | ApplyBuffEvent) {
// Increase the current stack report stack count.
this.currentReportStackCount += 1;
}

_onCast(event: CastEvent) {
this.SpymastersWebCasts.push({
timestamp: event.timestamp,
stacks: this.currentReportStackCount,
});

// Reset the stack count to zero.
this.currentReportStackCount = 0;
}

statistic() {
const castRows = this.SpymastersWebCasts.map((cast: SpymastersWebCast, index: number) => {
const castTime = cast.timestamp - this.owner.fight.start_time;
const intellectGained = cast.stacks * this.primaryStatBonus;

return (
<tr key={index}>
<td>{formatDuration(castTime)}</td>
<td>{cast.stacks}</td>
<td>{formatNumber(intellectGained)}</td>
</tr>
);
});

return (
<Statistic
position={STATISTIC_ORDER.OPTIONAL(99)}
category={STATISTIC_CATEGORY.ITEMS}
size="flexible"
dropdown={
<>
<table className="table table-condensed">
<thead>
<tr>
<th>Cast</th>
<th>Stacks on Use</th>
<th>Intellect Gained</th>
</tr>
</thead>
<tbody>{castRows}</tbody>
</table>
</>
}
>
<BoringItemValueText item={ITEMS.SPYMASTERS_WEB}>
{this.SpymastersWebCasts.length} Casts
</BoringItemValueText>
</Statistic>
);
}
}

0 comments on commit 33be06d

Please sign in to comment.