From 426193444157bcd0bbe4b6ad72edba37cd27a26a Mon Sep 17 00:00:00 2001 From: Roland Salardon Date: Sun, 16 Aug 2026 16:28:10 +0200 Subject: [PATCH 1/2] fix(rotation): Berserk end skill (-41) on full buff removal EI books `BerserkEndSkill` (-41) when the Berserk buff (29502) is fully removed via `remove_all`. - Added `29502: -41` to `_BUFF_LOSS_CASTS` - Added `29502` to `_BUFF_LOSS_REMOVE_ALL_ONLY` (remove_all is the only trigger) - Added `kind == "apply"` guard to `_BUFF_GAIN_SELF_ONLY` branch to avoid matching remove_all - Test: `test_berserk_loss_is_booked_as_berserk_end` Signed-off-by: Roland Salardon --- .../src/gw2_analytics/rotation.py | 6 ++-- libs/gw2_analytics/tests/test_rotation.py | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/libs/gw2_analytics/src/gw2_analytics/rotation.py b/libs/gw2_analytics/src/gw2_analytics/rotation.py index 04138008..56dbbf2a 100644 --- a/libs/gw2_analytics/src/gw2_analytics/rotation.py +++ b/libs/gw2_analytics/src/gw2_analytics/rotation.py @@ -154,6 +154,7 @@ 62769: 62861, 13135: 13106, 77265: 76730, + 29502: -41, # Berserk (end): BuffLossCastFinder(BerserkEndSkill, BerserkBuff) } _BUFF_GIVE_CASTS = { 41815: 45789, @@ -292,7 +293,7 @@ #: strip is not a cast. Only the entries verified against Elite Insights are #: listed; the rest keep the historical "any removal" behaviour until they #: are checked the same way. -_BUFF_LOSS_REMOVE_ALL_ONLY = {29446, 62769} +_BUFF_LOSS_REMOVE_ALL_ONLY = {29446, 62769, 29502} #: BuffGainCastFinder books the buff gained by the player itself; arcdps #: also re-emits these buffs with ``src=0`` (env) for trait/sigil pulses, #: which EI excludes via ``!bae.Initial``. Self-apply gating reproduces @@ -880,7 +881,8 @@ def add_instant(source: int, skill_id: int, time_ms: int, icd: int = 50) -> None and elite_specs.get(event.target_agent_id) is EliteSpec.WEAVER ) or ( - event.skill_id in _BUFF_GAIN_SELF_ONLY + event.kind == "apply" + and event.skill_id in _BUFF_GAIN_SELF_ONLY and event.source_agent_id != event.target_agent_id ) or ( diff --git a/libs/gw2_analytics/tests/test_rotation.py b/libs/gw2_analytics/tests/test_rotation.py index 0f7c60f6..71aae8d4 100644 --- a/libs/gw2_analytics/tests/test_rotation.py +++ b/libs/gw2_analytics/tests/test_rotation.py @@ -1568,3 +1568,36 @@ def casts(**kwargs: Any) -> list[int]: assert casts() == [5492] assert casts(elite_specs={7: EliteSpec.TEMPEST}) == [5492] assert casts(elite_specs={7: EliteSpec.WEAVER}) == [43470] + + +def test_berserk_loss_is_booked_as_berserk_end() -> None: + """EI books ``BerserkEndSkill`` (-41) when the Berserk buff is fully removed.""" + origin = 42_000_000 + + def casts(*events: Event) -> list[int]: + return [ + cast.skill_id + for cast in build_skill_rotation( + list(events), duration_ms=1_000, start_time_ms=origin + ) + ] + + gain = BoonApplyEvent( + time_ms=origin + 100, + source_agent_id=7, + target_agent_id=7, + skill_id=29502, + duration_ms=5_000, + stacks=1, + ) + end = BoonApplyEvent( + time_ms=origin + 5_100, + source_agent_id=0, + target_agent_id=7, + skill_id=29502, + duration_ms=0, + stacks=0, + kind="remove_all", + ) + assert casts(gain) == [30435] + assert casts(gain, end) == [30435, -41] From 0602ecc576d79680a9e39ac96d28c5b0f2d075ed Mon Sep 17 00:00:00 2001 From: Roland Salardon Date: Sun, 16 Aug 2026 16:32:18 +0200 Subject: [PATCH 2/2] style(test): ruff format test_rotation.py Signed-off-by: Roland Salardon --- libs/gw2_analytics/tests/test_rotation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/gw2_analytics/tests/test_rotation.py b/libs/gw2_analytics/tests/test_rotation.py index 71aae8d4..7d4fa5ee 100644 --- a/libs/gw2_analytics/tests/test_rotation.py +++ b/libs/gw2_analytics/tests/test_rotation.py @@ -1577,9 +1577,7 @@ def test_berserk_loss_is_booked_as_berserk_end() -> None: def casts(*events: Event) -> list[int]: return [ cast.skill_id - for cast in build_skill_rotation( - list(events), duration_ms=1_000, start_time_ms=origin - ) + for cast in build_skill_rotation(list(events), duration_ms=1_000, start_time_ms=origin) ] gain = BoonApplyEvent(