User Tools

Site Tools


user:loggy:castingai

This is an old revision of the document!


Loggy's Spellcasting AI reverse engineering notes

This is a complicated topic and won't be finished for a while.

Note for me

The battlefield location array seems to be stored with offsets of ((coord2 * 200) + coord 1) * 0x20

Stupid check

A spell is stupid if:

It is an offensive effect number, its aoe is greater than 600, it does not affect enemies only, and either:

  • The enemy has less than 3 non mindless mages, and the caster's army size outnumbers the opponent's by more than 20 times
  • The enemy has less than 3 non mindless mages, the caster's army size outnumbers the opponent by more than 10 times, and the caster's side has less than 50 troops

"Offensive effect numbers" may include the following:

  • 2, damage [1]
  • 3, fatigue damage [1]
  • 4, cause fear type 1 [1]
  • 7, poison damage [1]
  • 8, remove fatigue? [0]
  • 9, undocumented
  • 10, bless/buff type 1 [0]
  • 11, cause affliction [1]
  • 13, heal [0]
  • 23, buff type 2 [0]
  • 24, damage x3 vs demon/undead [1]
  • 28, enslave [1]
  • 29, charm [1]
  • 32, damage x3 vs larger
  • 33, damage x2 vs smaller
  • 66, paralysis [1]
  • 67, weakness [1]
  • 72, stream of life [1]
  • 73, damage x2 vs magic being [1]
  • 74, damage (raise as soulless on kill) [1]
  • 96, shatter [1]
  • 97, cause fear type 2 [1]
  • 134, chain lightning [1]
  • 142, salt damage [1]
  • test 43, edge of field summon
  • test 99 petrify [1]
  • test 103 drain life [1]
  • test 105 disbelieve [1]
  • test 107 damage demons only [1]
  • test 128 stun/fascinate [1]
  • test 129 interrupt damage [1]
  • 124, undocumented [1]

It is one of the following effects: Wrathful Skies, Fire Storm, Acid Storm, Astral Tempest, or Meteor Shower, and:

  • The caster outnumbers the enemy more than 20 to 1, and there are less than 3 enemy non-mindless mages
  • None of the following three conditions are met:
    • Caster's army size ⇐ enemy army size * 10
    • Enemy army size is 50+ units
    • Enemy has greater than two non-mindless mages

calcbestspell

Spell attribute 745/0x2e9 (found on most vanilla battle wide spells such as Doom, Wind of Death, Arcane Domination, Master Enslave, Army of Rats…) is some kind of checker for requiring a certain number of targets:

  • Check all hostile units on the field. Add 1 for each unit, and 3 for each commander. This is the hostile unit threshold.
  • If conservative gem usage is on: Fatigue component = fatigue cost / 50, random component = closed d8
  • Otherwise, fatigue component = fatiguecost / 200, random component = closed d3
  • Spell is rejected if (1 + random + fatigue) ⇐ hostile unit threshold

Evaluate spell score.

Evaluate spell score

  • Invalid spells (effect >9999) get nothing.
  • Spells that can't be cast due to underwater/land/specific terrain restrictions/lack of sun get nothing.
  • If you don't have the secondary path requirement, you get nothing.
  • Apply communion path boost. Check to see if you have the path requirement to cast the spell, including the use of one gem to boost if applicable. If not, you get nothing.
  • If the spell costs gems and you aren't allowed to spend (or you don't have enough gems to cast the spell, including the 1 gem levelboost), you get nothing.
  • If the spell is some kind of summoning spell (effects 1, 21, 43, 126):
    • Run the unit summoned through resolvemontag, which resolves montags as well as doing a few other replacements such as making ice elementals
    • The spell's score is (unit attack + unit defence + unit strength + unit max hitpoints) * 2.
    • If the unit is ethereal, add max hitpoints * 4.
    • If the unit is a trampler or has an innate fire shield, add max hitpoints * 4.
    • If the unit has a secondshape, evaluate the score of the secondshape and add that too.
    • Multiply the score by the spell's number of effects at the caster's level.
    • If the spell is more than lingering 4, multiply the score by 3. If it is lingering 2 or 3, multiply by 2 instead.
    • If the score is greater than zero:
      • Calculate a new score: ((closed d120 + 40) * old score) / 100, rounded down. If this value is less than 10, set it to be 10.
      • Some stuff I don't understand that cares about the spell range
      • If the spell effect was 126 (call horror), the score is set to d10 exploding or the actual score, whichever is lower.
  • If the spell is undocumented effect 31, do some stuff that looks very similar to the stuff I don't understand for the above summon group
  • If the spell is a battle enchantment or time stop effect:
    • If the enchantment is already active, you get nothing.
    • If the effect is rigor mortis and the caster is undead, the score is exploding d1000 + 150. If the caster is not undead it is 1.
    • If the effect is wailing winds and, the score is exploding d1000 + 100.
    • If the effect is foul air (10), the score is exploding d1000 + 75.
    • If the effect is soul drain, the score is exploding d1000 + 200.
    • If the effect is heat from hell and some unknown criteria, the score is exploding d1000 + 100. If the criteria are not met the score is 0.
    • If the effect is foul vapours, and the same kind of criteria as heat from hell, the score is exploding d1000 + 75.
    • If the effect is fire storm, and yet more of the unknown criteria, score is exploding d1000 + 200.
    • If grip of winter, and yet more unknown criteria, exploding d1000 + 100.
    • If wrathful skies and yet more more unknown criteria, exploding d1500 + 75.
    • If growing fury, exploding d1000 + 75
    • If rain of stones, exploding d5.
    • If astral tempest, exploding d5.
    • If friendly currents, exploding d1000 + 50.
    • If quagmire, exploding d5.
    • If rain and it is raining, nothing. Otherwise, exploding d5.
    • If blood rain, some significantly longer and more complex criteria
    • If relief, exploding d100.
    • If solar brilliance, exploding d5.
    • If ravenous swarm, exploding d5.
    • If acid storm, exploding d5.
    • Any other enchantment, only 1.
  • Other types of spells:
    • If the spell is self target only, just consider the caster.
    • Work out how many units the effect could usefully target (check every square, add up the number of targets in them), depending on whether it is offensive (look at enemies) or nonoffensive (look at friends). Make a copy of this value called the "reduced number of targets"
    • If the effect is NOT a damaging or buff effect (these are 1 and 0 on the offensive effects lists), the reduced number of squares is half this value.
    • If magic duel effects, the reduced number of squares is divided by 5.
    • Start considering every potential square in turn.
    • If reduced squares is 12+: if min(300, reduced squares) ⇐ closed d300 + 9, check this square. [there is a (squares-9)/300 chance to skip any given square]
    • If the square being considered is out of range, skip it.
    • Calc some values based on range, aoe, and precision
  • Calculate a final score: (score * 100) / (fatigue from cast, not including encumbrance + 90) and round down.
  • If over 75 fatigue and casting a reinvigoration spell (effect 8 only):
    • Work out <spell's damage> or (caster's current fatigue - fatigue from cast). Add 5x the value of whichever one is less to the final score.
  • If the fatigue from casting would put the caster over 100, and the spell is not a drain life or reinvigoration spell, divide the final score by 3 and round down.

When you actually are about to cast a spell...

  • If you can't cast the spell you're asking to due to missing ability or being mindless (and the spell requires some of these), set the score to some negative value. Otherwise it's 0.
  • Randomspell has a x% chance to set Random favchance to 100 / max(2, number of spell choices)
  • If you have no scripted spell, there is a random favchance% probability to
    • do something I don't understand that governs how randomspell operates (but this isn't as big a question anyway)
  • Scripted spells gain 1000000 to their score
  • If you have more than 50 spell choices and the spell being considered is not scripted, there is a chance to not consider the spell. This is 1% per spell choice available over 50, to a max of 50% at 100+ choices.
  • If the spell costs a game AND it's not scripted AND gem usage is not allowed, set score to negative because you're not allowed to spend gems.
  • Check #aibadlvl and set score to negative if it fails
  • If the spell wasn't scripted, check for #ainocast and set score to negative if it exists
  • If the spell wasn't scripted, check for stupidity (as per above) and set to score to negative if stupid
  • Run evalspell and use that as the spell score
  • After this, evaluate item spells separately.
  • Then do the actual casting of whatever you decided to cast, wherever you decided to cast it
user/loggy/castingai.1623351247.txt.gz · Last modified: 2021/06/10 18:54 by loggy