Page 1 of 1

APNAP rules question vs our code.

PostPosted: 08 Mar 2020, 13:03
by Aswan jaguar
Do cards like Balefire Dragon that their effect involves only damaged player (and not both players e.g "damage all creatures") need APNAP order for their effect?
Is this correct or by mistake it was used in such cards. Is there a situation where that is needed in such cards that escapes me?

Re: APNAP rules question vs our code.

PostPosted: 20 Sep 2020, 05:19
by FastEddie
As I promised an answer weeks ago it is about time I guess...

No, I don't think so. It is clear who the attacking player is and who the defending player, so APNAP is at least superflous and should probably be taken out. It is not a bug in the sense that something doesn't work as it should (it does) but it is also not correct as it does way to much.
Another example would be the function invasion_dragon in invasion.c. It uses APNAP to provide dialog texts for both players, ignoring the fact that the dialog will never be shown if the AI attacks you... so this could be shortened quite a bit.

My theory is that someone just copy-pasted a legitimate use of APNAP, plugged in his code, it worked, fine, let's move on. And then someone else did and things went downhill from there.

A legitimate use (although not correct either, but this is an engine issue Drool66 is grinding his teeth on) would be Prosperity, where you need to involve both players. But my guess is that there are far less of those than actual uses of APNAP.

Re: APNAP rules question vs our code.

PostPosted: 20 Sep 2020, 17:22
by drool66
Noncombat damage triggers should definitely stay in APNAP - consider targeting Barbed Shocker with Arcbond and then Gut Shot. What I'm not sure of is if there's any way a creature can deal combat damage to its controller. Say you have a Balefire Dragon heading your way, and you target it with a hypothetical instant that says "Whenever target creature deals damage to you this turn, it deals that much damage to its controller". Does Balefire Dragon deal 6 damage to each of its controller's creatures (ie. is the damage it deals to its controller combat damage)? I guess this could be possible in game if instead of the hypothetical instant, the opponent had a Saskia the Unyielding with themselves chosen.

Re: APNAP rules question vs our code.

PostPosted: 20 Sep 2020, 19:04
by Korath
I can't find anything that says redirected combat damage isn't still combat damage, and rulings for other damage-replacement cards like Furnace of Rath support that - if it were no longer combat damage, there'd be no need to mention trample at all. Just part of the damage could be redirected via, say, Captain's Maneuver, so it's possible for Balefire Dragon to be dealing combat damage to both players in the same combat damage step.

Your Balefire Dragon / Saskia the Unyielding example wouldn't be combat damage, since it's a separate damage event as a result of the triggered ability, not as a consequence of combat.

More practically, some order has to be chosen, and if it isn't consistent multiplayer will desync. Player 0 is always the local player, player 1 always the remote one. Handling current_turn first is at least as good an order as any.

Re: APNAP rules question vs our code.

PostPosted: 20 Sep 2020, 20:17
by FastEddie
Korath wrote:More practically, some order has to be chosen
Let's stick with this example. Card A deals combat damage, card B redirects it, amplifies it, transforms it into non-combat damage, whatever. You have an implicit order in there. First comes A, then B. Without A there would be no effect from card B. A cannot possibly know that B is in play. This is the crucial point. Thus I think that it would be wrong to apply APNAP in such a case to A unless A targets both players by definition as Prosperity does.

Happy to discuss.

Re: APNAP rules question vs our code.

PostPosted: 20 Sep 2020, 21:22
by Korath
All the damage in a given iteration of resolve_damage_cards_and_prevent_damage(), roughly the equivalent of a single 4th/5th-edition-era damage prevention phase, results in a single dispatch of TRIGGER_DEAL_DAMAGE. If the Balefire Dragon's been made to be damaging both players by that time - whether because of an instant or activated ability, something handling EVENT_PREVENT_DAMAGE or EVENT_DAMAGE_PREVENTION or TRIGGER_END_DAMAGE_PREV, card_balefire_dragon() is going to see it for both in the same call.

It's true that the damage cards collected by check_damage_test() during EVENT_DEAL_DAMAGE have an actual order. It's not one we can use, though, because A) EVENT_DEAL_DAMAGE isn't dispatched by timestamp, but by player 0->1 card 0->active_cards_count, and so using it would desync; and B) the order has already been thrown away - by design - by the time damage_deal_by_me()'s caller sees it.