OK, OK. I've mostly worked on three things since last post - AI, auras, and tutors.
The AIWe've treated the Microprose MTG AI pretty poorly.
The overall design of the general AI - used for just about everything except playing lands, tapping for mana, and attacker and blocker assignment - is quite good, as evidenced by it being able handle essentially all of the ~10500 non-vanilla cards that we've thrown into it over the years with hardly any specific tuning.
Its basic algorithm is to save the game state, make a random choice (recording all decisions it has to make to do that), play the game through to the end of the turn, and assess how well it's done. If there's something whose effects aren't easily assessed except at the time the decision is made (like casting a
Giant Growth during the AI's main phase instead of waiting until after blockers are declared) or that won't have an effect until the next turn (like casting a
Lord of the Pit with no other creatures on the bf), there's two ways for a card to handle it:
- While responding to a specific event, add to the global variable ai_modifier (if the decision benefits the AI) or subtract from it (if it benefits the player). This is the best way to deal with transitory effects like the Giant Growth example above; typically we adjust ai_modifier during EVENT_CAST_SPELL/EVENT_ACTIVATE while choosing targets.
- Respond to EVENT_SHOULD_AI_PLAY, which is only ever sent to cards while the game state has been saved and the AI is speculating about its choices, by either changing ai_modifier as above, or by changing the conditions on the battlefield. The original Lord of the Pit implementation, for example, responds to this event by dealing 7 damage to its controller unless he controls at least one other creature; while Holy Armor increases ai_modifier up (if the AI controls it) or down (if the human player does) a fixed amount for each
-producing land its controller has. (Cards can also do the same in response to the not-so-well-named EVENT_CAN_COUNTER; the difference is that EVENT_CAN_COUNTER is sent only to the AI's cards either in hand or on the battlefield, and only during the main AI speculation; while EVENT_SHOULD_AI_PLAY is only sent to cards on the battlefield, but gets sent to both players' cards and is also sent by the combat AI.)
While there's some unexpected quirks - for example, the AI would think it a horrible idea to ever cast
Ball Lightning if it weren't special-cased, since the gamestate-assessment function would give it more value while in hand than the 6 damage it would do if it attacked, and doesn't get run until after its end-step trigger - it worked generally ok for the cards available in the original game.
It hasn't held up so well.
Non-aura enchantments, except for cards like
Crusade that alter other things that the assessment function looks for like power and toughness, were apparently assumed to be too complex to assess in the general case; and so they all respond with individually-tuned EVENT_SHOULD_AI_PLAY handlers. Enchantments still in the AI's hand are worth a small, constant amount (3 points; by way of comparison, each point of positive life is worth between 12 and 36). So when folks started making new enchantments and didn't know to account for this, the AI wouldn't cast them - a
Larceny in hand is worth 3 points, and one on the battlefield is worth 0, even before considering that the lands tapped to cast it are worth less than untapped ones. Plenty of the old asm cards that every spare byte of Magic.exe has been overwritten with and that we were still using until relatively recently borrow the AI from completely unrelated cards, just because they happen to convince the AI to cast them instead of letting them sit in hand. These days, most non-auras call global_enchantment() which gives an 8-point bonus to every enchantment; still not so good, and I'd expect the AI to pass them over if it had to tap more than five lands or take even one point of damage from e.g. a
City of Brass to get them into play.
Auras in hand, like non-aura enchantments, are worth exactly 3 points each. Auras in play were originally worth 2 for whoever controls whatever they're enchanting; that worked out ok even in the presence of detrimental auras like
Cursed Land (which has an EVENT_SHOULD_AI_PLAY handler to account for the damage) or
Weakness (whose power/toughness decrease far outstrips the paltry 2 point bonus). Once less-obvious auras started showing up, someone realized that this didn't make sense, and worked out a fairly complex and completely non-obvious set of rules based on the aura's controller, the enchanted permanent's controller, and the values in the aura's Enchant Type OWN and Enchant Type OPP columns in manalink.csv to figure who to give the 2-point bonus to, if anyone... but it's still only 2 points, worth less than it would be if it went uncast and less than a sixth of a point of life, and about half the auras don't have Enchant Type set at all.
Artifacts fare better; they're assessed at 12 times their cmc plus 12. Only the colorless part of a colored artifact's casting cost counts toward its cmc for this purpose, though.
Anything with flash and not on the battlefield gets treated solely like it were a spell, since there was no such thing as an Instant Creature; so the AI's happier to have a
Grizzly Bears in its hand (worth 30) than an
Ashcoat Bear or
Havenwood Wurm (both common "instants", so 12 each).
And most of the new abilities we've added to cards are completely ignored. Creatures get a large bonus to their perceived value if nothing can block them, so ones like shadow and horsemanship and so on matter; but cards with abilities like lifelink and deathtouch and indestructible (!) aren't treated as worth any more than vanilla creatures. (On the other hand, creatures with defender always got a bonus if nothing could block them, too. They also got assessed as if they always had zero power; and while, say, a
Wall of Heat should clearly be worth less than a
Catacomb Slug, it should still be better than a
Wall of Earth.)
We can at least take some comfort in that Microprose didn't always get it right, either. For example,
Lord of the Pit, in addition to the EVENT_SHOULD_AI_PLAY handler mentioned above, decreases ai_modifier by a large amount if it's successfully cast while its controller has fewer than two other creatures in play... no matter who its controller is. So the AI is
less likely to
Counterspell it if you cast it with 2 or more other creatures than if you cast it with 1 or 0. Not enough less to be observable compared to its 7/7 trampling body, but enough if it were only 5/5 or didn't trample.
(Plus, under some conditions that aren't easily detectable from a card's function, positive ai_modifier means that some decision or condition is beneficial to the human, not the AI. I've still got to track these down and make them consistent.)
I've moved the end-of-turn ai assessment function into C and have changed stuff that looks illogical (like most of what I've mentioned above), but it's still going to need a
lot of playtesting and tuning to get right. Besides the playtesting just to know that the cards I've added work correctly; most of them, including large swathes of functionality shared between cards, won't have been played even once before this release.
And while the tap-for-mana AI is robust enough that we've never really felt the need to tweak it, I still don't understand the combat AI at all, and don't understand the play-a-land AI well enough that I'm comfortable fiddling with it just yet.
AurasAuras as implemented in the original game have a number of problems.
- The AI values them inconsistently while on the battlefield, as mentioned above.
- They don't have any way of checking whether a given object can be legally enchanted by them, except while doing everything else they happen to do as they're being cast. (This is a special case of the basic problem keeping us from making a robust Deflection or Misdirection or Spellskite effect.)
- If something tries to put them directly onto the battlefield, they're treated as if their controller were casting them from his hand. They don't stay wherever they were if there's no legal target (contra rule 303.4g); the controller can choose to not enchant anything (contra rule 303.4f); and the caster gets to remake any non-targeting choices (like whether to pay for Gigantiform's kicker) unless we jump through serious hoops to disable them.
The second of these, while it's obviously problematic for cards like
Enchantment Alteration that I'm not dealing with yet, also has a major impact on the game during state-based actions.
704.5n. If an Aura is attached to an illegal object or player, or is not attached to an object or player, that Aura is put into its owner's graveyard.
Previously, this was dealt with (sort of) in two ways:
- Zap off auras with Enchant Creature if a temporarily-animated card (via, say, Animate Artifact or Kormus Bell or Mishra's Factory) stops being a creature
- Make creatures with protection from colors zap off auras of those colors themselves.
The first of these doesn't detect whether an aura has Enchant Creature reliably (for example, it was zapping
Consecrate Land off of animated
Mishra's Factories at end of turn); the second isn't done by anywhere near all creatures with protection (so if you enchanted a
Beasts of Bogardan with
Flight and then
Chaoslace'd the aura, it stayed put); and neither deal with any of the weird variants of the Enchant ability that've shown up over the years like on
Threads of Disloyalty or
Wurmweaver Coil or
Daybreak Coronet, or even on
Relic Bind or
Animate Wall, which are original Microprose cards.
The obvious solution is to make all aura cards responsible for zapping
themselves off while state-based actions are being checked. It's easy enough to make a macro for all aura cards that transparently does both that and targeting during casting if you plan for it from the start; though retrofitting it into all the already-existing auras in Manalink isn't any easier than throwing them all away and reprogramming them from scratch. The number of existing Microprose auras is small enough that I could just write wrappers for them all. (Except
Animate Dead, which is problematic for a number of reasons. So if you animate a
Black Knight with one and then
Purelace it, it'll stay put for now.)
White Ward and its four friends dealt with their "this-doesn't-zap-itself-off" ability by simply not making their granted protection zap
any auras off. They work correctly now, too, though it's a bit of a hack.
I haven't started to deal with problem #3 - putting auras directly into play - yet, though my solution for #2 at least makes it feasible.
TutoringNot much to say about this just yet, and I'm still writing individual cards.
Tinker will be feasible, though the implementation of its additional cost probably won't be in final form before I leave; and I'll likely replace the three other remaining dungeon cards with
Imperial Seal,
Mystical Tutor, and
Vampiric Tutor for now.
- I'm still on track for a release either tomorrow or Thursday, so no updated Rarities.dat this time. | Open
- Abzan Runemark
Agoraphobia
Ajani's Mantra
Ajani's Pridemate
Akroan Hoplite
Alabaster Mage
Alpha Status
Amrou Scout
Ancestral Mask
Ancestral Vengeance
Ancient Hellkite
Annex
Archivist
Arid Mesa
Armadillo Cloak
Armor of Faith
Armored Ascension
Aspect of Gorgon
Aura Gnarlid
Auramancer's Guise
Aurochs
Azure Mage
Bad River
Battle Mastery
Beloved Chaplain
Benalish Heralds
Benalish Veteran
Bifurcate
Binding Grasp
Black Scarab
Blanchwood Armor
Blessing of the Nephilim
Blood Ogre
Bloodcrazed Goblin
Bloodfire Mentor
Bloodrage Vampire
Bloodstained Mire
Blue Scarab
Bond Beetle
Bonded Fetch
Bonds of Faith
Borderland Marauder
Bottle Gnomes
Boundless Realms
Briar Shield
Brindle Boar
Bull Aurochs
Burnished Hart
Cage of Hands
Carnage Wurm
Cast into Darkness
Cateran Brute
Cateran Enforcer
Cateran Kidnappers
Cateran Persuader
Cateran Slaver
Cenn's Heir
Chant of the Skifsang
Charging Griffin
Chasm Drake
Children of Korlis
Chosen by Heliod
Claws of Gix
Commander Eesha
Confiscate
Conquer
Contaminated Ground
Cooperation
Corrupted Conscience
Creeping Corrosion
Crimson Mage
Crippling Blight
Crown of Empires
Crystal Ball
Dark Favor
Dark Heart of the Wood
Dark Tutelage
Dawntreader Elk
Daybreak Coronet
Dead Weight
Death's Approach
Debilitating Injury
Dedicated Martyr
Defense of the Heart
Defensive Stance
Defiant Falcon
Diligent Farmhand
Diplomatic Immunity
Divine Favor
Domestication
Donate
Dream Leash
Dryad Arbor
Dryad's Favor
Dunerider Outlaw
Duskhunter Bat
Earth Servant
Ember Hauler
Embodiment of Spring
Emmessi Tome
Empyrial Armor
Enslave
Epic Proportions
Ethereal Armor
Evolving Wilds
Excommunicate
Explosive Vegetation
Far Wanderings
Farhaven Elf
Farseek
Feral Invocation
Fists of Ironwood
Flood Plain
Flooded Strand
Flowstone Charger
Font of Fertility
Font of Fortunes
Font of Ire
Font of Vigor
Fool's Tome
Forced Worship
Frenzied Tilling
Frontier Guide
Furor of the Bitten
Furyborn Hellkite
Gaea's Embrace
Gamble
Ghostly Possession
Ghoulcaller's Bell
Goblin Fireslinger
Goblin Piledriver
Goblin War Paint
Gorehorn Minotaurs
Grasslands
Green Scarab
Griffin Rider
Grim Tutor
Griptide
Grisly Transformation
Gristleback
Growth Spasm
Gruesome Deformity
Guise of Fire
Gutless Ghoul
Hammerhand
Harbor Serpent
Heartwood Giant
Holy Mantle
Indomitable Will
Inferno Fist
Innocent Blood
Into the North
Ironshell Beetle
Jace's Archivist
Jade Mage
Jeskai Runemark
Kamahl's Desire
Kavu Mauler
Kiln Walker
Kirtar's Desire
Knight of the White Orchid
Knightly Valor
Knotvine Paladin
Kor Cartographer
Lifelink
Lightning Diadem
Lightning Talons
Liliana's Specter
Llanowar Sentinel
Lurking Crocodile
Lurking Nightstalker
Map the Wastes
Marble Chalice
Mardu Roughrider
Mardu Runemark
Mark of the Oni
Mark of the Vampire
Marked by Honor
Marsh Flats
Merfolk Looter
Messenger's Speed
Misty Rainforest
Moggcatcher
Molting Snakeskin
Mountain Valley
Mwonvuli Acid-Moss
Mythic Proportions
Nimbus Wings
Ogre Jailbreaker
Onyx Mage
Overgrown Estate
Overwhelming Stampede
Pacifism
Peace of Mind
Phyresis
Pillar of War
Pillory of the Sleepless
Pin to the Earth
Planar Portal
Polluted Delta
Predator's Gambit
Preordain
Primal Frenzy
Primal Visitation
Primeval Titan
Psychic Venom
Quag Sickness
Rabble-Rouser
Raised by Wolves
Ramosian Captain
Ramosian Commander
Ramosian Lieutenant
Ramosian Sergeant
Ramosian Sky Marshal
Rampant Growth
Ranger's Path
Rathi Fiend
Rathi Intimidator
Ravenous Baloth
Red Scarab
Reflexes
Research Assistant
Returned Phalanx
Reverent Hunter
Righteous Authority
Riptide Director
Rocky Tar Pit
Rolling Stones
Rune-Scarred Demon
Sage's Reverie
Sakura-Tribe Elder
Satyr Grovedancer
Savage Silhouette
Scab-Clan Mauler
Scalding Devil
Scalding Tarn
Scepter of Empires
Scepter of Insight
Scorched Rusalka
Scourgemark
Scute Mob
Sea Gate Loremaster
Seahunter
Seeker of Skybreak
Seismic Shudder
Sensory Deprivation
Serra's Embrace
Shadow Lance
Shiv's Embrace
Siegecraft
Silverglade Elemental
Silverglade Pathfinder
Skarrgan Pit-Skulk
Skeletal Grimace
Skinrender
Skyshroud Claim
Skyshroud Poacher
Slithering Shade
Soltari Trooper
Soul Link
Soul Snuffers
Soulmender
Spectral Cloak
Spectral Flight
Spire Serpent
Spirit Away
Spirit Mantle
Spreading Seas
Stab Wound
Starved Rusalka
Sultai Runemark
Sunbond
Supply-Line Cranes
Tainted Sigil
Taste for Mayhem
Telim'Tor's Darts
Temur Runemark
Terra Ravager
Terramorphic Expanse
Teysa, Envoy of Ghosts
Thought Courier
Threads of Disloyalty
Three Visits
Throne of Empires
Timberland Guide
Timbermaw Larva
Time Ebb
Tivadar's Crusade
Tower of Eons
Tower of Fortunes
Tribute to the Wild
Tricks of the Trade
Trollhide
Twisted Experiment
Uncontrollable Anger
Unflinching Courage
Unquestioned Authority
Vampire Outcasts
Verdant Catacombs
Verdant Embrace
Verdant Force
Vicious Kavu
Volcanic Strength
Volition Reins
Vow of Duty
Vow of Flight
Vow of Lightning
Vow of Malice
Vow of Wildness
Vulshok Replica
Wakestone Gargoyle
Wandering Wolf
Way of the Thief
Wayfarer's Bauble
Wei Ambush Force
Weight of the Underworld
Wellwisher
White Scarab
Wild Beastmaster
Windswept Heath
Wood Elves
Wooded Foothills
Wreath of Geists
Wurmweaver Coil
Xira Arien
Zarichi Tiger
Zephid's Embrace
Zhang He, Wei General
Zuran Orb