AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
WildGrowthTickScalingTest.cpp File Reference

Tests for Wild Growth tick scaling formula. More...

#include "gtest/gtest.h"
#include <cmath>
#include <cstdint>
#include <numeric>
#include <vector>

Go to the source code of this file.

Classes

class  WildGrowthTickScalingTest
 

Functions

 TEST_F (WildGrowthTickScalingTest, FirstTickIsHighest)
 
 TEST_F (WildGrowthTickScalingTest, LastTickIsLowest)
 
 TEST_F (WildGrowthTickScalingTest, TicksAreMonotonicallyDecreasing)
 
 TEST_F (WildGrowthTickScalingTest, TotalHealingPreserved)
 
 TEST_F (WildGrowthTickScalingTest, MiddleTickEqualsBase)
 
 TEST_F (WildGrowthTickScalingTest, TickValues_WithSpellPower)
 
 TEST_F (WildGrowthTickScalingTest, TickValues_RawBaseOnly_WouldBeBroken)
 
 TEST_F (WildGrowthTickScalingTest, T10_2P_ReducesReduction)
 
 TEST_F (WildGrowthTickScalingTest, T10_2P_TotalHealingPreserved)
 

Detailed Description

Tests for Wild Growth tick scaling formula.

Wild Growth heals with a front-loaded pattern: first tick heals most, each subsequent tick heals less. The formula (from spell_dru_wild_growth_aura):

bonus = 6.0 - baseReduction * (tickNumber - 1) amount = baseTick + baseTick * bonus / 100

Where baseTick MUST include caster spell power bonuses (set via DoEffectCalcAmount, which runs after SpellHealingBonusDone in CalculateAmount). See TrinityCore issue #21281.

baseReduction defaults to 2.0, reduced by T10 Restoration 2P Bonus. Wild Growth has 7 ticks (7s duration, 1s amplitude).

Definition in file WildGrowthTickScalingTest.cpp.

Function Documentation

◆ TEST_F() [1/9]

TEST_F ( WildGrowthTickScalingTest  ,
FirstTickIsHighest   
)
81{
82 // baseTick=600 simulates a spell-power-inclusive value
83 auto ticks = CalcAllTicks(600);
84
85 for (int i = 1; i < TOTAL_TICKS; ++i)
86 EXPECT_GT(ticks[0], ticks[i]) << "Tick 1 should be highest, but tick " << (i + 1) << " is higher";
87}

◆ TEST_F() [2/9]

TEST_F ( WildGrowthTickScalingTest  ,
LastTickIsLowest   
)
90{
91 auto ticks = CalcAllTicks(600);
92
93 for (int i = 0; i < TOTAL_TICKS - 1; ++i)
94 EXPECT_LT(ticks[TOTAL_TICKS - 1], ticks[i]) << "Tick 7 should be lowest, but tick " << (i + 1) << " is lower";
95}

◆ TEST_F() [3/9]

TEST_F ( WildGrowthTickScalingTest  ,
MiddleTickEqualsBase   
)
119{
120 // Tick 4 (middle) has 0% bonus, so it equals baseTick exactly
121 int32_t const baseTick = 600;
122 int32_t tick4 = CalcWildGrowthTickAmount(baseTick, 4, DEFAULT_REDUCTION);
123
124 EXPECT_EQ(tick4, baseTick);
125}

◆ TEST_F() [4/9]

TEST_F ( WildGrowthTickScalingTest  ,
T10_2P_ReducesReduction   
)
173{
174 // T10 2P reduces the drop rate. If bonus amount is 30%,
175 // baseReduction = 2.0 - 2.0 * 30/100 = 1.4
176 float baseReduction = DEFAULT_REDUCTION;
177 float t10BonusAmount = 30.0f;
178 baseReduction -= baseReduction * t10BonusAmount / 100.0f;
179 EXPECT_FLOAT_EQ(baseReduction, 1.4f);
180
181 auto ticks = CalcAllTicks(600, baseReduction);
182
183 // With reduced drop-off, ticks are more uniform
184 // First tick: 600 + 6% = 636 (unchanged, bonus starts at 6%)
185 EXPECT_EQ(ticks[0], 636);
186 // Last tick: 600 + (6 - 1.4*6)% = 600 + (-2.4)% = 600 - 14.4 -> 586
187 EXPECT_EQ(ticks[TOTAL_TICKS - 1], 586);
188
189 // Range is smaller with T10 2P
190 int32_t rangeWithT10 = ticks[0] - ticks[TOTAL_TICKS - 1];
191 auto normalTicks = CalcAllTicks(600);
192 int32_t rangeNormal = normalTicks[0] - normalTicks[TOTAL_TICKS - 1];
193
194 EXPECT_LT(rangeWithT10, rangeNormal) << "T10 2P should reduce tick-to-tick variance";
195}

◆ TEST_F() [5/9]

TEST_F ( WildGrowthTickScalingTest  ,
T10_2P_TotalHealingPreserved   
)
198{
199 float baseReduction = DEFAULT_REDUCTION;
200 baseReduction -= baseReduction * 30.0f / 100.0f;
201
202 int32_t const baseTick = 600;
203 auto ticks = CalcAllTicks(baseTick, baseReduction);
204
205 int32_t totalHealing = std::accumulate(ticks.begin(), ticks.end(), 0);
206 int32_t expectedTotal = baseTick * TOTAL_TICKS;
207
208 // With T10 2P the scaling is asymmetric (bonus starts at +6% but
209 // only drops by 1.4% per tick instead of 2%), so total healing is
210 // slightly higher than 7 * baseTick. This is expected and matches TC.
211 EXPECT_GT(totalHealing, expectedTotal);
212 // Should not exceed ~2% above baseline
213 EXPECT_LT(totalHealing, expectedTotal * 102 / 100);
214}

◆ TEST_F() [6/9]

TEST_F ( WildGrowthTickScalingTest  ,
TicksAreMonotonicallyDecreasing   
)
98{
99 auto ticks = CalcAllTicks(600);
100
101 for (int i = 1; i < TOTAL_TICKS; ++i)
102 EXPECT_LE(ticks[i], ticks[i - 1]) << "Tick " << (i + 1) << " should be <= tick " << i;
103}

◆ TEST_F() [7/9]

TEST_F ( WildGrowthTickScalingTest  ,
TickValues_RawBaseOnly_WouldBeBroken   
)
154{
155 // If baseTick were only the raw base (206) without spell power,
156 // ticks would be far too low. This documents the bug from
157 // TrinityCore #21281 / AC's CallScriptEffectCalcAmountHandlers
158 // ordering issue.
159 int32_t const rawBase = 206;
160 auto ticks = CalcAllTicks(rawBase);
161
162 // Tick 1 without spell power: 206 + 6% = 218
163 EXPECT_EQ(ticks[0], 218);
164 // This is ~1/3 of the correct value (636), matching the player report
165 EXPECT_LT(ticks[0], 636 / 2) << "Raw base ticks are less than half the SP-inclusive value";
166}

◆ TEST_F() [8/9]

TEST_F ( WildGrowthTickScalingTest  ,
TickValues_WithSpellPower   
)
132{
133 // baseTick = 600 (raw base ~206 + spell power ~394)
134 int32_t const baseTick = 600;
135 auto ticks = CalcAllTicks(baseTick);
136
137 // Tick 1: 600 + 6% = 636
138 EXPECT_EQ(ticks[0], 636);
139 // Tick 2: 600 + 4% = 624
140 EXPECT_EQ(ticks[1], 624);
141 // Tick 3: 600 + 2% = 612
142 EXPECT_EQ(ticks[2], 612);
143 // Tick 4: 600 + 0% = 600
144 EXPECT_EQ(ticks[3], 600);
145 // Tick 5: 600 - 2% = 588
146 EXPECT_EQ(ticks[4], 588);
147 // Tick 6: 600 - 4% = 576
148 EXPECT_EQ(ticks[5], 576);
149 // Tick 7: 600 - 6% = 564
150 EXPECT_EQ(ticks[6], 564);
151}

◆ TEST_F() [9/9]

TEST_F ( WildGrowthTickScalingTest  ,
TotalHealingPreserved   
)
106{
107 // Sum of all ticks should equal 7 * baseTick (scaling is symmetric)
108 int32_t const baseTick = 600;
109 auto ticks = CalcAllTicks(baseTick);
110
111 int32_t totalHealing = std::accumulate(ticks.begin(), ticks.end(), 0);
112 int32_t expectedTotal = baseTick * TOTAL_TICKS;
113
114 // Allow +-1 per tick for integer truncation
115 EXPECT_NEAR(totalHealing, expectedTotal, TOTAL_TICKS);
116}