User Tools

Site Tools


user:loggy:castingaiexample

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
user:loggy:castingaiexample [2022/02/15 20:56]
loggy created
user:loggy:castingaiexample [2022/12/14 04:18] (current)
loggy
Line 4: Line 4:
  
 ===== The colossus and the werewolf ===== ===== The colossus and the werewolf =====
 +
 +**This was run on 5.54. In 5.57 the cached offensive flag was replaced by a simple switch to an offensive effect number, meaning that this part of the discussion no longer applies**
  
 I wrote primarily for myself to better understand this case. In places it won't be structured logically, but rather it represents how I thought about the discrepancy. I wrote primarily for myself to better understand this case. In places it won't be structured logically, but rather it represents how I thought about the discrepancy.
Line 162: Line 164:
   The score for damaging effects is 10 * strength value = 120   The score for damaging effects is 10 * strength value = 120
      
 +===== Hypotheticals and Blade Wind =====
 +
 +AKA: "Why does the casting AI love to cast ??Blade Wind???"
 +
 +A lot of the values that come up in my rather lengthy and dry notes aren't going to be really meaningful, so let's pick a competitor, something like say the fairly humble ??Falling Fires??. Notably, Blade Wind is 4x the fatigue cost, and gets penalised for that, but let's forget about that for now. I'll get back to that later if I remember.
 +
 +For the sake of this, I'm assuming "base" casting levels (that is {{path>F3E3}}), which means the spells have the following stats. The casting AI does resolve the scaling correctly for the caster when running its numbers, but that's a needless complication here.
 +
 +  * Falling fires: aoe 3, nreff 1, 15pts AP fire
 +  * Blade wind: aoe 0, nreff 35, 14pts mundane slashing
 +
 +Let's assume (as is the case in most battles) that we're not dealing with things within 5 range of the mage, as that uses different stuff for blade wind. For AoE spreading, both of them fall under...
 +
 +   If the spell's AoE is 0 or 1, OR the spell's number of effects is 1:
 +       square spread = 1
 +       accurate square weight = max(1, aoe) * number of effects * 20
 +       inaccurate square weight = max(1, aoe) * number of effects * 10
 +
 +
 +This means mages are looking at 3x3 boxes (1 square deviation in all directions from the square being considered) of units. The weights (more on what these are used for later are):
 +
 +Falling fires: accurate = 60, inaccurate = 30
 +Blade wind: accurate = 700, inaccurate = 350
 +    
 +==== Unit Scores ====
 +
 +Now we're onto unit scores, which are a numeric value of how much the AI rates casting the spell on one specific unit - how many are then in the considered area is the basis of the spell score. Let's, for the sake of examples, look at fully packed squares of two unit types. For the sake of an example, I'm picking ??Barbarian#139?? and ??Wolf??. I originally set out to do this analysis with ??Heavy Infantry#39?? vs the Barbarians but ran into a slight issue. I've left the calcs for the heavy infantry below, which themselves might be interesting...
 +
 +I'll pull all the relevant values together when they're needed later. The calculation method with real unit numbers is here mostly for curiosity's sake.
 +
 +=== Barbarian ===
 +
 +7 prot, 13 hp, 12 strength. 
 +
 +== Falling Fires ==
 +
 +  * This is AP, so we add (1- prot/2) rounded down.
 +  * Final damage = 15 (base) + (1 - 7/2) = 15 + (1 - 3) = 13.
 +  * This does not exceed target max hp + 5 (18) so doesn't need to be capped to that value
 +  * Strength value = 12 (str) - 10 (constant) + 13 (final damage) = 15
 +  * Final score for damaging effects = strength value * friendly bias (this is just 1 for hostiles, and -1 for friends) * 10.
 +  * = 150
 +
 +== Blade Wind ==
 +
 +  * This isn't AP, so we add (1 - 7) = -6
 +  * Final damage = 14 - 6 = 8
 +  * Spell is single target and doesn't ignore shields, multiply by 2/3 and round down = 16/3 = 5
 +  * Strength value = 12 (str) - 10 (constant) + 5 (final damage) = 7
 +  * Final score = 70
 +
 +=== Wolf ===
 +
 +8 hp, 9 str, 2 prot.
 +
 +== Falling Fires ==
 +
 +  * This is AP, so we add (1- prot/2) rounded down.
 +  * Final damage = 15 (base) + (1 - 2/2) = 15 + (1 - 1) = 15.
 +  * This does exceed target max hp + 5 (13) so gets lowered to this
 +  * Strength value = 9 (str) - 10 (constant) + 13 (final damage) = 12
 +  * Final score for damaging effects = strength value * friendly bias (this is just 1 for hostiles, and -1 for friends) * 10.
 +  * = 120
 +
 +== Blade Wind ==
 +
 +  * This isn't AP, so we add (1 - 2) = -1
 +  * Final damage = 14 - 1 = 13
 +  * Spell is single target and doesn't ignore shields, multiply by 2/3 and round down = 24/3 = 8
 +  * Strength value = 9 (str) - 10 (constant) + 8 (final damage) = 7
 +  * Final score = 70
 +
 +=== Heavy Infantry ===
 +
 +10 hp, 10 str, 14 prot.
 +
 +== Falling Fires ==
 +
 +  * This is AP, so we add (1- prot/2) rounded down.
 +  * Final damage = 15 (base) + (1 - 14/2) = 15 + (1 - 7) = 9.
 +  * This does not exceed target max hp + 5 (18) so doesn't need to be capped to that value
 +  * Strength value = 10 (str) - 10 (constant) + 9 (final damage) = 9
 +  * Final score for damaging effects = strength value * friendly bias (this is just 1 for hostiles, and -1 for friends) * 10.
 +  * = 90
 +
 +== Blade Wind ==
 +
 +  * This isn't AP, so we add (1 - 14) = -13
 +  * Final damage = 14 - 13 = 1
 +  * Spell is single target and doesn't ignore shields, multiply by 2/3 and round down = 2/3 = 0
 +  * Strength value = 10(str) - 10 (constant) + 0 (final damage) = 0
 +  * Final score = 0
 +  * Aka: the casting AI won't want to do this at all!
 +
 +==== Square totals ====
 +
 +Adapted from the notes:
 +
 +    Check a square of tiles containing units. As per the above, this is a 3x3 box, for 9 squares total.
 +    
 +       - Sum the unit scores of the things in that square.
 +       - If there was more than one thing in the square, and the spell affects only 1 person, divide the summed score by the number of units in the square
 +       - If the square struck was the originally picked square at the centre of the 3x3 spread...
 +         - add (this square's score * accurate square weight) to the spell score at this location. 
 +       - Otherwise, add (this square's score * inaccurate square weight) to the spell score.
 +
 +=== Wolf ===
 +
 +== Falling Fires ==
 +
 +Relevant values from above:
 +
 +  * Spellunitscore = 120
 +  * accurate weight = 60
 +  * inaccurate weight = 30
 +
 +Onto new calculation:
 +
 +  * A square of wolves has three of them, so total unit score for each square = 360.
 +  * Falling Fires has AoE > one person, so we're not dividing anything.
 +  * Because we're dealing with a 3x3 box of all the same unit, we get 8 "secondary" squares that use the inaccurate weight, and 1 "primary" square that uses the accurate weight, and can just multiply up accordingly
 +  * = 8 * (360*30) + (60*360) = 86400 + 21600 = 108000
 +
 +== Blade Wind ==
 +
 +Relevant values from above:
 +
 +  * Spellunitscore = 70
 +  * accurate weight = 700
 +  * inaccurate weight = 350
 +
 +Onto new calculation:
 +
 +  * A square of wolves has three of them, so total unit score for each square = 210.
 +  * Blade Wind is AoE = one person, so we divide by the number of units in the square and go back to 70 again.
 +  * Same deal, 8 squares with the inaccurate weight, 1 with the accurate weight.
 +  * = 8 * (70*350) + (70*700) = 196000 + 49000 = 245000
 +
 +=== Barbarian ===
 +
 +== Falling Fires ==
 +
 +Relevant values from above:
 +
 +  * Spellunitscore = 150
 +  * accurate weight = 60
 +  * inaccurate weight = 30
 +
 +Becomes...
 +
 +  * One square's total unit score = 450
 +  * = 8 * (450*30) + (60*450) = 108000 + 27000 = 135000
 +
 +== Blade Wind ==
 +
 +Relevant values from above:
 +
 +  * Spellunitscore = 70
 +  * accurate weight = 700
 +  * inaccurate weight = 350
 +
 +These numbers are exactly the same as the wolves. We end up at 245000 here too.
 +
 +==== Theoretical results =====
 +
 +If you've read the debug log and seen the spell scores before, you'll notice that these are extremely large compared to what you get there: the game divides them by 100 and throws some randomness in there before working with them. If you opened up the game and actually did this, you'd also run into this, but assuming I haven't fallen flat on my face somewhere along the way, the numbers should line up fairly well. (Both of these units are undisciplined, trying this in reality requires getting fully "dense" formations)
 +
 +There are other things not included, there's an increase to targeting nearby (but as mentioned above, this changes the weights for blade wind if less than 5 squares away), and a penalty for targeting further away, but that's percentage based and ultimately hits both of the spells we're dealing with here in much the same way.
 +
 +^ Unit ^ ??Blade Wind?? ^ ??Falling Fires?? ^
 +| ??Wolf?? | 2450 | 1080 |
 +| ??Barbarian#39?? | 2450 | 1350 |
 +
 +For the sake of completeness, and to maybe deal with the fact I've gone this deep without even opening up Dominions in anything except a disassembler, I thought I should quickly get some real values for comparison.
 +
 +==== Practical Testing ====
 +
 +The above mentioned precision and distance factors need taking into account. Dominions does not output the scores before they are applied. Due to the fact this needs 3x3 packed squares, I modded off undisciplined (via #clearspec) for these units to make my life a LOT easier. This doesn't affect their stats or anything else that matters, as per the above.
 +
 +I empowered a Mound King (it was what I had laying around) and foward positioned him against a bunch of the respective unit types on hold and attack.
 +
 +=== Barbarians ===
 +
 +   best Falling Fires this far, 26 18 (500 pnts) (midedge 60 30, marg 1, pot 27, hostile 1)
 +   best Falling Fires this far, 27 18 (518 pnts) (midedge 60 30, marg 1, pot 27, hostile 1)
 +   best Falling Fires this far, 27 19 (519 pnts) (midedge 60 30, marg 1, pot 27, hostile 1)
 +   
 +All of these coordinates are 3x3 boxes packed with barbarians. The caster himself is at (53, 20). The first entry is one square further away than the next two. The total distance between the caster and the middle line (27, 18) is %%sqrt((53-27)^2 + (20-18)^2)%% = 26 squares, once rounded down. Even unrounded it's only marginally larger than that anyway (Python's float implementations comes up with 26.076...)
 +
 +Above I predicted a whopping 1350, and got something a bit under half of what I expected. Notably, it falls foul of: 
 +
 +    If the spell's (NOT FINAL) precision is less than 20:
 +
 +    score = max(1, (score * 10)/max(10, distance from caster))
 +
 +Putting 1350 into this gives max(1, (1350*10)/26) = 519. A little randomness later, and we're about where we'd expect to be...
 +
 +   best Blade Wind this far, 24 17 (443 pnts) (midedge 307 153, marg 2, pot 27, hostile 1)
 +   best Blade Wind this far, 26 17 (713 pnts) (midedge 307 153, marg 2, pot 27, hostile 1)
 +   best Blade Wind this far, 25 18 (727 pnts) (midedge 307 153, marg 2, pot 27, hostile 1)
 +   best Blade Wind this far, 26 18 (914 pnts) (midedge 307 153, marg 2, pot 27, hostile 1)
 +
 +These scores are highly variable. The highest one, (26, 18), is further away than falling fires we looked at, and comes to 27 squares away after Pythagorus %%- math.sqrt((53-26)**2 + (20-18)**2) = 27.073%%
 +
 +
 +The range modification: 2340*10/27 = 866. Definitely the correct ballpark, but the randomness liekly did its thing - it's set to (80 + openended d40)% of the calculated value, and the casting AI output doesn't output lower scores, meaning this last one might have rolled an especially big d40.
 +
 +
 +The high fatigue penalty is, usefully, applied after these values are written to the log. In any case, this was the first cast of the battle, and when starting at 0 fatigue neither of these spells suffered from it.
 +
  
 +But, how much damage is Blade Wind really going to do in reality anyway?
user/loggy/castingaiexample.1644958578.txt.gz · Last modified: 2022/02/15 20:56 by loggy