Where do base healing/damage amounts come from?

The numbers are likely based on tiered formulas (i.e. from level 1-60, one formula, from level 60-70, another, etc). Considering you are managing an addon, I'd recommend the approach that Wowhead takes. Wowhead doesn't calculate these values on the fly. They save the values on the server-side and reuse them.

Considering Wowhead is a reliable source for in-game data, I'd recommend simply scraping your values from Wowhead and using those.


UPDATED

To expand on the tables in the link, I dug into the Wowhead code just deep enough to determine how some of these values are used for Greater Healing Wave. Note that all of the data and functions used are visible in the $WH JavaScript object.

The link has 2 JSON objects:

  1. The $WH.g_convertScalingSpell.SD object lists scaling values for different distribution types. Each element is an array with 15 values.
  2. The $WH.g_convertScalingSpell.SV object lists scaling values for different levels. Each element is an array with 12 values.

The function where the magic happens is the $WH.g_convertScalingSpell function. Basically, it accepts a level and a scaling type, then uses the tables to match up the two and calculate the final value. A quick glance at the $WH object shows there are a couple more g_convert functions for different values.

While I can't speak on behalf of what all of the values of the scaling tables represent, I can expose the formula used in the $WH.g_convertScalingSpell function.

a = $WH.g_convertScalingSpell.SD[ distribution_type ]
b = $WH.g_convertScalingSpell.SV[ level ]
c = b[a[3] - 1] * (min(level, a[14]) + (a[13] * max(0, level - a[14]))) / level

Then, using c, an object is built out with multiple min, max, and avg values. Only the first min and max values are visible in Greater Healing Wave's tooltip. The value i displayed below is evaluated at 0, 1, and 2. If you are only interested in the first object that is built, you can omit the i entirely, as it's value is 0.

avg = a[4 + i] * c * (a[1] > 0 ? cast / a[1] : 1)
min = round(avg) - floor(avg * a[7 + i] / 2)
max = round(avg) + floor(avg * a[7 + i] / 2)

And if you are curious, the cast value (casting time in milliseconds) comes from this formula, and is only rounded after calculations, prior to displaying the value to the user:

cast = min(a[1], a[1] > 0 && level > 1 ? a[0] + (((level - 1) * (a[1] - a[0])) / (a[2] - 1)) : a[0])

When applying this, you have to know the desired distribution type. This is found in an HTML comment in the tooltip's markup, starting with a question mark. So, to show the example of Greater Healing Wave, the HTML comment is <!--?77472:68:85:85:355:0:1000-->. While I do not know what all of the values are, I know the first few are spellId, minLevel, maxLevel, defaultLevel, and distScale.

Let's do the math:

a = $WH.g_convertScalingSpell.SD[355]
  = [3000, 3000, 20, 7, 9.564, 0, 0, 0.133, 0, 0, 0, 0, 0, 1, 0]

b = $WH.g_convertScalingSpell.SV[85]
  = [1125.23, 1029.49, 1125.23, 1125.23, 945.189, 1125.23, 1004.49, 937.33, 962.336, 0, 986.626, 443]

c = b[a[3] - 1] * (min(level, a[14]) + (a[13] * max(0, level - a[14]))) / level
  = b[7    - 1] * (min(85,    0    ) + (1     * max(0, 85    - 0    ))) / 85
  = b[6]        * (min(85,    0    ) + (1     * max(0, 85           ))) / 85
  = 1004.49 * (min(85, 0) + (1 * max(0, 85))) / 85
  = 1004.49 * (0 + (1 * 85)) / 85
  = 1004.49 * 85 / 85
  = 1004.49

And then the spell values:

cast = min(a[1], a[1] > 0 && level > 1 ? a[0] + (((level - 1) * (a[1] - a[0])) / (a[2] - 1)) : a[0])
     = min(3000, 3000 > 0 && 85    > 1 ? 3000 + (((85    - 1) * (3000 - 3000)) / (20   - 1)) : 3000)
     = min(3000, true && true ? 3000 + ((84 * 0) / (19)) : 3000)
     = min(3000, true ? 3000 + (0 / 19) : 3000)
     = min(3000, 3000 + 0)
     = 3000

avg = a[4 + i] * c * (a[1] > 0 ? cast / a[1] : 1)
    = a[4 + 0] * c * (a[1] > 0 ? 3000 / a[1] : 1)
    = 9.564    * c * (3000 > 0 ? 3000 / 3000 : 1)
    = 9.564    * c * (true ? 1 : 1)
    = 9.564 * 1004.49
    = 9606.942360000001

min = round(avg)        - floor(avg               * a[7 + i] / 2)
    = round(8964.62412) - floor(9606.942360000001 * a[7 + 0] / 2)
    = 9607              - floor(9606.942360000001 * 0.133    / 2)
    = 9607              - floor(1277.7233338800002           / 2)
    = 9607              - floor(638.8616669400001               )
    = 9607 - 638
    = 8969

max = round(avg)        + floor(avg               * a[7 + i] / 2)
    = 9607 + 638
    = 10245

Hope this helps!


These are hardcoded numbers in the game based on blizzard's complicated history of balance. Spells used to have fixed base damage/healing per rank, but when spell ranks were removed the bases were changed to scale by level.

Each expansion has its own powercurve, so you will find sharp differences in ability damage/healing at levels above the highest rank for the spell in the previous expansion. In your HolyLight example, you can see this at level 58 clearly, where levels 59+ use TBC power curve while 0-58 use the original power curve. This was originally to stop you downranking low level spells to save mana costs, so you had to use the higher mana cost new spells rather than the dirt-cheap old spells.

It doesn't have to make any sense, blizzard only balances for the current expansion, and downstream changes to lower levels are essentially not given a thought as long as they don't completely break levelling.