Let me search that for you.
---
What I've been working on:
The good:
I've got a mostly-working system in place to make triggers use the stack. This both cleanly separates their announcement from resolution (so, say, cards like
Man-o'-War interact properly with cards like
Skulking Ghost) and - since they're now distinct objects - lets triggers be selected by things like
Stifle and
Strionic Resonator. (But see below.) Almost as an afterthought, I can delay triggers getting put onto the stack until a player gets priority (so untap triggers like
Wake Thrasher's work right, i.e. not during the untap step), and properly allowing the order of multiple "simultaneous" triggers from the same source (as recently reported
here for Manalink) is no more complex than any other card that has multiple unrelated triggers.
Mostly, though, I did it to simplify programming other cards - delayed resolution of triggers is much, much easier to program for than the immediate model used in the fourth-edition era. The reason is that nothing is really "simultaneous" like it's meant to be: cast an
Evacuation or
Wrath of God and the program has to move the creatures off the battlefield one at a time. This gets complicated very, very quickly when one of them is something like
Faceless Butcher, and even more so if the creature returning to the battlefield has an enters-the-battlefield trigger too.
For most triggers, everything just happened immediately. Destruction and damage triggers had to support the 4th-edition regeneration and damage prevention steps, so they already got delayed; unfortunately, if the trigger has to remember anything besides the mere fact that it's triggering for a particular card - most damage triggers need to know what was damaged or how much damage was dealt, for example - all the queued-up triggers have to share storage space somewhere in the original card, since there aren't separate trigger objects to put the data into. Now I can just create a trigger card for each damage event, store just the data for that particular trigger event, and not have to worry about whether or what else the same card is damaging. And when the triggers move onto the stack, it's now
correct that they do so one at a time in a well-defined order.
Plus, it's a pretty good excuse to make purple cards.
- Most of the cards since my last post have untap or target triggers, to test aspects of this | Open
- Limited Edition Alpha
Basalt Monolith (MicroProse rewrite)
Mirage
Forsaken Wastes
Skulking Ghost
Visions
Tar Pit Warrior
Tempest
Angelic Protector
Fugitive Druid
Segmented Wurm
Spinal Graft
Exodus
Mirozel
Urza's Saga
Retromancer
Urza's Legacy
Tethered Skirge
Mercadian Masques
Cowardice
Lava Runner
Skulking Fugitive
Task Force
Nemesis
Mossdog
Planeshift
Cloud Cover
Sleeping Potion
Odyssey
Cursed Monstrosity
Torment
Boneshard Slasher
Cephalid Aristocrat
Cephalid Illusionist
Scourge
Daru Spiritualist
Mirrodin
Fractured Loyalty
Mesmeric Orb
Champions of Kamigawa
Horobi, Death's Wail
Guildpact
Petrahydrox
Time Spiral
Skulking Knight
Planar Chaos
Gossamer Phantasm
Shadowmoor
Ashenmoor Liege
Hollowsage
Eventide
Wake Thrasher
Alara Reborn
Crystallization
Magic 2010
Ice Cage
Illusionary Servant
Rise of the Eldrazi
Dormant Gomazoa
Phantasmal Abomination
Magic 2011
Phantom Beast
Magic 2012
Phantasmal Bear
Phantasmal Dragon
Avacyn Restored
Spectral Prison
Wild Defiance
Magic 2014
Illusionary Armor
Born of the Gods
Aerie Worshippers
Deepwater Hypnotist
Forlorn Pseudamma
God-Favored General
Kragma Butcher
Oreskos Sun Guide
Pain Seer
Pheres-Band Raiders
Pheres-Band Tromper
Satyr Nyx-Smith
Servant of Tymaret
Siren of the Silent Song
Sphinx's Disciple
Warchanter of Mogis
Journey into Nyx
King Macar, the Gold-Cursed
Fate Reforged
Frost Walker
Dragons of Tarkir
Thunderbreak Regent
Magic Origins
Willbreaker
Oath of the Gatewatch
Reality Smasher
Shadows over Innistrad
Silverfur Partisan
Conspiracy: Take the Crown
Leovold, Emissary of Trest
Kaladesh
Key to the City
Commander 2016
Akiri, Line-Slinger
Ancient Excavation
Armory Automaton
Ash Barrens
Boompile
Breya, Etherium Shaper
Bruse Tarl, Boorish Herder
Charging Cinderhorn
Coastal Breach
Conqueror's Flail
Crystalline Crawler
Curtains' Call
Deepglow Skate
Divergent Transformations
Duelist's Heritage
Entrapment Maneuver
Faerie Artisans
Frenzied Fugue
Goblin Spymaster
Grave Upheaval
Grip of Phyresis
Ishai, Ojutai Dragonspeaker
Kraum, Ludevic's Opus
Kydele, Chosen of Kruphix
Ludevic, Necro-Alchemist
Manifold Insights
Migratory Route
Orzhov Advokist
Parting Thoughts
Primeval Protector
Prismatic Geoscope
Ravos, Soultender
Saskia the Unyielding
Seeds of Renewal
Sidar Kondo of Jamuraa
Sublime Exhalation
Sylvan Reclamation
Tana, the Bloodsower
Thrasios, Triton Hero
Treacherous Terrain
Tymna the Weaver
Vial Smasher the Fierce
The bad:
I'd gone to some trouble to make the triggers in cards I've programmed go through a uniform series of macros, rather than directly responding to events from the engine. The idea was that, once I'd written a stack-based trigger system, I'd be able to just change the macros, rather than deal with every individual card.
I wasn't careful enough, though: while the triggers already in the engine always execute in the context of the triggering card, stack-based ones under modern rules have to refer both to the triggering card and the trigger object on the stack. When
Cloudchaser Kestrel's trigger resolves, it has to destroy the enchantment targeted at announcement of the trigger and stored on the trigger object, not whatever permanent it's currently targeting with its activated ability; conversely, when
Skulking Ghost's trigger resolves, it has to be the
Skulking Ghost that gets sacrificed, not the trigger object.
So I've ended up having to individually update all the existing triggers anyway, and there's something more than two thousand to deal with. At least it was going fairly rapidly, at about 150 day, since the existing macros were pretty close to what I need in most respects. On the other hand, the motherboard of the machine I'd been developing on died on Tuesday, so I'm back in recovery mode instead of actively working on the game for a while more yet. At least I didn't lose any hard drives this time.
(I
am still reasonably confident that the similar macros I've been using for spells and activated abilities will be sufficient for
Deflection/
Rings of Brighthearth/etc.)
The ugly:
A couple things.
The stack in this engine isn't really self-contained. Each function that puts a spell or activation onto the stack is also responsible both for allowing a response to it, and for making sure it gets resolved; they all assume that the same object they put on the stack is still on top of it at that point. Activation is reasonably well-behaved, in that most of the work of resolution is done by a general function we've long labelled as "resolve_top_card_of_stack()", which in turn only does activation-specific stuff if the top object's an activation. Normal spell-casting, though, does most of the spell-specific stuff in the calling function, and it completely ignores whatever's on the stack - it calls the function of the spell it put on the stack and passes it the information of the object that's actually currently on top of the stack. So I have to jump through a lot of hoops to make sure that exactly the right number of trigger objects get popped off the stack and in the right place, and that's dreadfully easy to get wrong.
I haven't yet figured out how to stop resolution of everything on the stack once anything starts to resolve. So not only are you still unable to do something like activate
Mangara of Corondor,
Twiddle it, let the
Twiddle resolve, and then activate Mangara again; if something triggers during resolution, then you can't respond to that trigger, even if I call the function that usually allows response. (If something triggers as a result of
announcing a spell or activation, though, it goes onto the stack and then you can respond, just like you should be able to.)
Players still don't get priority at all the right times, sometimes get it at times they shouldn't, and generally don't get it in the right order. Out of scope for this feature.
---
On the Manalink side, the Great Rewrite-the-World for
Panharmonicon project is midway through dragons_maze.c. That's 21% done, counting by lines of code, and the first commit was on October 14; at that rate, even if nothing else at all gets worked on, there won't be a new version until late February. That's much longer than I'm willing to put off Shandalar for, so I'll do a release in the meantime, but installation will be messier than usual.