When automatic combat starts, each side is evaluated for their spellcasting ability in 6 categories, based on known spells.
Oneshotbuff
This is a special category that has the sum of the defined values of known combat global enchantments. This category influences the combat only once during turn 1 and can be of any amount. In general, assume each known combat global adds 2-9 to this value.
All remaining categories take the value of the best known spell in the category, ignoring all weaker spells, and range from 0 (no spells known) to 10 (best very rare).
Buff
Spells that help the unit survive.
Examples : Resist Magic, Mystic Surge, Invisibility.
Ranged Buff
Spells that help the army deal more ranged damage, usually by slowing down enemy units or increasing ranged attack power.
Example : Web, Entangle, Flame Blade, Mystic Surge, Construct Catapult
Direct Damage
Spells that damage enemy units or render them unable to defend against damage or fight back.
Examples : Lightning Bolt, Mystic Surge.
This is the only category where the best spell is rated 15, not 10. This is neccesary to preserve the balance between realms as Chaos doesn't really do anything else.
Curse
Spells that deal damage or weaken units by targeting their resistance.
Examples : Weakness, Possession, Massacre
Summon
Spells that give you new units or otherwise contribute to the hit points of your army directly.
Examples : Wild Boars, Healing, Construct Catapult
If you know every spell in one realm, you have this many total "levels" :
Life, Nature has 44
Sorcery has 51
Chaos has 49
Death has 52
I believe this does match the actual combat casting value of each realm well enough - Chaos, Death and Sorcery are powerful, while Life and Nature are good but somewhat less focused on combat spells than the other three.
Once these (and army stats) are calculated, combat starts.
The order of phases are
1. Defender spellcasting
2. Defender ranged (if applicable)
3. Defender melee (if applicable)
then the same order for the attacker, then repeat until one side dies.
We'll only focus on spellcasting at the moment.
First, the amount of MP used for the turn is determined. This is usually 40 for turn 1, 20 for each turn afterwards, or less if the wizard doesn't have more skill or mana remaining, but high casting skill wizards use 50 and 30 instead.
On turn 1, "oneshotbuff" takes effect. (remember, this will always use 40 or 50 MP unless the wizard has less)
This grants the army ("oneshotbuff level" * MP * 33 /400) percentage extra hit points.
Example 1 : the wizard knows only Prayer. Prayer is worth 7 levels.
(7*40*33) / 400 = 23% additional hp to the army.
Example 2 : the wizard knows Prayer, Mass Invisibility and Call Lighting for a sum of 7+8+8 = 23 levels.
(23*40*33) / 400 = 75% additional hp to the army.
Basically, each "oneshotbuff" level is worth 3.3% additional HP for the army unless the wizard cannot afford the initial 40 MP. (or it's worth 4.1% if their casting skill is 200 or more which allowed them to use 50 MP on this phase)
After this, on turn 1 as well as all other turns, all 5 remaining categories are applied - individually weak but we are basically pretending the AI casts 5 spells at the same time but each at 1/5 the "normal" power :
Buff adds ("buff level"*MP*/100) % HP.
For example level 5 at 20 MP would add 1% HP. (However, as long as the wizard has mana, they can use this every turn.)
At max level and max (30) MP spending this basically adds 3% HP per combat turn to the army. (which is as good as 15% if they had the ability to pick this category instead of requiring to use all 5 at equal weight.)
RangedBuff adds the exact same percentage (calculated from the rangedbuff level of course) but to all ranged attack powers in the stack instead.
Direct Damage deals ("direct damage level"*MP*12 /2000) magical ranged damage to the opposing army.
For example at level 7 (doom bolt) this deals 0.84 damage per 20 Mp spent.
(again, if this wasn't only the 1/5th of the casting available, we could be doing 4.2 damage per 20 MP but that feature does not exist yet.)
...this feels underpowered for a Doom Bolt as it's only 8 damage per 40 MP instead of 12. So let's try to look at another spell.
Fire Bolt is level 4, so it's 0.48 damage, or would be 2.25 at full power for 20 MP, 4.5 damage at 40 MP.
This feels even more underrated than Doom Bolt even if I pretend the enemy might have high armor (which is not part of the formula at all here.)
My mistake here is that I have in the code as comment "40 MP at max level is worth 12 damage" but that's just not right. Doom Bolt is worth 12 damage but Doom Bolt is level 7 not 10. (also this category doesn't even max at 10 anyway but we have to pretend it does otherwise the extra levels we game chaos have no meaning.)
...so to improve accuracy, this formula should change to "/1400" instead of "/2000" for accurate Doom Bolt but there is a catch. Doom Bolt has the worth damage per mana ratio in the game in exchange for consistency and ignoring armor.
So we should decide how much damage we want from direct damage spells, because this amount is too low.
For reference, Fire Bolt and Fire Ball are level 4 direct damage spells, Lightning Bolt is 6, Warp Lightning is level 8, Flame Strike is 12, Apocalypse is 15.
In real combat, Warp Lightning deals roughly 12 damage for 30 MP. That would put Lightning Bolt at 7.5 damage which isn't so far off, and Flame Strike at 36 which is a reasonable average. (9 units take much more but 1 unit takes much less)
So if we go with that then the improved formula should be
("direct damage level"*MP*12 /1200)
Curse category next which deals "Curse Level"*MP*(13-Enemy average resistance)/750.
Example : Petrify, enemy resistance of 7. Petrify counts as level 5.
Damage is (5*20*6)/750 = 0.8.
They would be 4 damage if it wasn't dividing up casting to 5 categories.
Well...not very good. I mean, for a 60% chance to kill an enemy unit, we assume that's worth 4 damage.
So let's try to look at this from a different angle. An average unit has about 15 HP.
Each 1 missing save modifier is 10% chance the unit dies, so 1.5 damage.
Out baseline is petrify which does this for 20 MP and is rated level 5.
So we want (5*20)/X = 1.5 which means X= 66.
Except, again, that's for the full casting power but we use only 1/5 of it, so 330, making the formula
"Curse Level"*MP*(13-Enemy average resistance)/330.
Finally, we have
Summonig
Which gives the army HP and Melee attack power equal to
"Summoning Level"*MP/1000 times the stats of a Wild Boar unit which is 15 HP and 720 Melee.
This has one problem - the melee formula was updated meanwhile.
Currently a Wild Boar would be 600*40*4 / 200 = 480 melee.
A bigger problem is, Wild Boars are not the pinnacle of summoning. They are what you get for level 10 but the Boar itself is categorized as a level 3 spell.
So this should correctly be "SummoningLevel"*MP/300 instead.
This should fix the inaccuracies in the formula and might show why stronger wizards had problems, as all three categories that contribute in a relevant way against ranged garrisons were underrated.
However, we probably still should design some sort of a ruleset that determines a percentage of casting power spent on each category instead of defaulting to using 205 on each.
For example, if my only combat spell is Fire Bolt and have 100 mana, then I won't do "I spend 20 MP on Fire Bolt, then I cannot use the rest because I need to save the other 80 MP for summoning and buffing spells but I don't have any", no, I would do "I cast Fire Bolt from all 100 MP".
While that's the most obvious mistake (spending on categories the wizard doesn't even have), I think we need more detail than that and spend higher on the categories that actually are more relevant for the current battle.
For example if we greatly outnumber the enemy army then using the buff category (to boost our advantage) or using one of the damage categories (to kill the enemy and end the combat faster, denying enemy casting to be relevant) are good tactics, while summoning is wasted MP (it gives much less than buffing by percentage). Another example, if the enemy has very high attack power but low hit points, then direct damage is great but buffing our own durability is bad. If they have high resistance then preferring direct damage spells over curse spells is a correct choice.
etc.... the part I'm not sure about is how to handle this. Unlike casting a spell in normal combat, here we aren't picking one best option but distribute a total of 100% between the 5 possible choices. It is valid to pick 0% but should be avoided as much as possible because dong so reduces the relevance of the AI obtaining new spells of those categories. At the same time, if we don't do enough weighting and stay close to the :use everything" then we get stuck with the current system where mana is spent on categories that don't help winning at all.
Oneshotbuff
This is a special category that has the sum of the defined values of known combat global enchantments. This category influences the combat only once during turn 1 and can be of any amount. In general, assume each known combat global adds 2-9 to this value.
All remaining categories take the value of the best known spell in the category, ignoring all weaker spells, and range from 0 (no spells known) to 10 (best very rare).
Buff
Spells that help the unit survive.
Examples : Resist Magic, Mystic Surge, Invisibility.
Ranged Buff
Spells that help the army deal more ranged damage, usually by slowing down enemy units or increasing ranged attack power.
Example : Web, Entangle, Flame Blade, Mystic Surge, Construct Catapult
Direct Damage
Spells that damage enemy units or render them unable to defend against damage or fight back.
Examples : Lightning Bolt, Mystic Surge.
This is the only category where the best spell is rated 15, not 10. This is neccesary to preserve the balance between realms as Chaos doesn't really do anything else.
Curse
Spells that deal damage or weaken units by targeting their resistance.
Examples : Weakness, Possession, Massacre
Summon
Spells that give you new units or otherwise contribute to the hit points of your army directly.
Examples : Wild Boars, Healing, Construct Catapult
If you know every spell in one realm, you have this many total "levels" :
Life, Nature has 44
Sorcery has 51
Chaos has 49
Death has 52
I believe this does match the actual combat casting value of each realm well enough - Chaos, Death and Sorcery are powerful, while Life and Nature are good but somewhat less focused on combat spells than the other three.
Once these (and army stats) are calculated, combat starts.
The order of phases are
1. Defender spellcasting
2. Defender ranged (if applicable)
3. Defender melee (if applicable)
then the same order for the attacker, then repeat until one side dies.
We'll only focus on spellcasting at the moment.
First, the amount of MP used for the turn is determined. This is usually 40 for turn 1, 20 for each turn afterwards, or less if the wizard doesn't have more skill or mana remaining, but high casting skill wizards use 50 and 30 instead.
On turn 1, "oneshotbuff" takes effect. (remember, this will always use 40 or 50 MP unless the wizard has less)
This grants the army ("oneshotbuff level" * MP * 33 /400) percentage extra hit points.
Example 1 : the wizard knows only Prayer. Prayer is worth 7 levels.
(7*40*33) / 400 = 23% additional hp to the army.
Example 2 : the wizard knows Prayer, Mass Invisibility and Call Lighting for a sum of 7+8+8 = 23 levels.
(23*40*33) / 400 = 75% additional hp to the army.
Basically, each "oneshotbuff" level is worth 3.3% additional HP for the army unless the wizard cannot afford the initial 40 MP. (or it's worth 4.1% if their casting skill is 200 or more which allowed them to use 50 MP on this phase)
After this, on turn 1 as well as all other turns, all 5 remaining categories are applied - individually weak but we are basically pretending the AI casts 5 spells at the same time but each at 1/5 the "normal" power :
Buff adds ("buff level"*MP*/100) % HP.
For example level 5 at 20 MP would add 1% HP. (However, as long as the wizard has mana, they can use this every turn.)
At max level and max (30) MP spending this basically adds 3% HP per combat turn to the army. (which is as good as 15% if they had the ability to pick this category instead of requiring to use all 5 at equal weight.)
RangedBuff adds the exact same percentage (calculated from the rangedbuff level of course) but to all ranged attack powers in the stack instead.
Direct Damage deals ("direct damage level"*MP*12 /2000) magical ranged damage to the opposing army.
For example at level 7 (doom bolt) this deals 0.84 damage per 20 Mp spent.
(again, if this wasn't only the 1/5th of the casting available, we could be doing 4.2 damage per 20 MP but that feature does not exist yet.)
...this feels underpowered for a Doom Bolt as it's only 8 damage per 40 MP instead of 12. So let's try to look at another spell.
Fire Bolt is level 4, so it's 0.48 damage, or would be 2.25 at full power for 20 MP, 4.5 damage at 40 MP.
This feels even more underrated than Doom Bolt even if I pretend the enemy might have high armor (which is not part of the formula at all here.)
My mistake here is that I have in the code as comment "40 MP at max level is worth 12 damage" but that's just not right. Doom Bolt is worth 12 damage but Doom Bolt is level 7 not 10. (also this category doesn't even max at 10 anyway but we have to pretend it does otherwise the extra levels we game chaos have no meaning.)
...so to improve accuracy, this formula should change to "/1400" instead of "/2000" for accurate Doom Bolt but there is a catch. Doom Bolt has the worth damage per mana ratio in the game in exchange for consistency and ignoring armor.
So we should decide how much damage we want from direct damage spells, because this amount is too low.
For reference, Fire Bolt and Fire Ball are level 4 direct damage spells, Lightning Bolt is 6, Warp Lightning is level 8, Flame Strike is 12, Apocalypse is 15.
In real combat, Warp Lightning deals roughly 12 damage for 30 MP. That would put Lightning Bolt at 7.5 damage which isn't so far off, and Flame Strike at 36 which is a reasonable average. (9 units take much more but 1 unit takes much less)
So if we go with that then the improved formula should be
("direct damage level"*MP*12 /1200)
Curse category next which deals "Curse Level"*MP*(13-Enemy average resistance)/750.
Example : Petrify, enemy resistance of 7. Petrify counts as level 5.
Damage is (5*20*6)/750 = 0.8.
They would be 4 damage if it wasn't dividing up casting to 5 categories.
Well...not very good. I mean, for a 60% chance to kill an enemy unit, we assume that's worth 4 damage.
So let's try to look at this from a different angle. An average unit has about 15 HP.
Each 1 missing save modifier is 10% chance the unit dies, so 1.5 damage.
Out baseline is petrify which does this for 20 MP and is rated level 5.
So we want (5*20)/X = 1.5 which means X= 66.
Except, again, that's for the full casting power but we use only 1/5 of it, so 330, making the formula
"Curse Level"*MP*(13-Enemy average resistance)/330.
Finally, we have
Summonig
Which gives the army HP and Melee attack power equal to
"Summoning Level"*MP/1000 times the stats of a Wild Boar unit which is 15 HP and 720 Melee.
This has one problem - the melee formula was updated meanwhile.
Currently a Wild Boar would be 600*40*4 / 200 = 480 melee.
A bigger problem is, Wild Boars are not the pinnacle of summoning. They are what you get for level 10 but the Boar itself is categorized as a level 3 spell.
So this should correctly be "SummoningLevel"*MP/300 instead.
This should fix the inaccuracies in the formula and might show why stronger wizards had problems, as all three categories that contribute in a relevant way against ranged garrisons were underrated.
However, we probably still should design some sort of a ruleset that determines a percentage of casting power spent on each category instead of defaulting to using 205 on each.
For example, if my only combat spell is Fire Bolt and have 100 mana, then I won't do "I spend 20 MP on Fire Bolt, then I cannot use the rest because I need to save the other 80 MP for summoning and buffing spells but I don't have any", no, I would do "I cast Fire Bolt from all 100 MP".
While that's the most obvious mistake (spending on categories the wizard doesn't even have), I think we need more detail than that and spend higher on the categories that actually are more relevant for the current battle.
For example if we greatly outnumber the enemy army then using the buff category (to boost our advantage) or using one of the damage categories (to kill the enemy and end the combat faster, denying enemy casting to be relevant) are good tactics, while summoning is wasted MP (it gives much less than buffing by percentage). Another example, if the enemy has very high attack power but low hit points, then direct damage is great but buffing our own durability is bad. If they have high resistance then preferring direct damage spells over curse spells is a correct choice.
etc.... the part I'm not sure about is how to handle this. Unlike casting a spell in normal combat, here we aren't picking one best option but distribute a total of 100% between the 5 possible choices. It is valid to pick 0% but should be avoided as much as possible because dong so reduces the relevance of the AI obtaining new spells of those categories. At the same time, if we don't do enough weighting and stay close to the :use everything" then we get stuck with the current system where mana is spent on categories that don't help winning at all.