Page 1 of 1

[fix]Whenever...tapped for mana cards affect non-mana, too.

PostPosted: 20 Feb 2021, 14:58
by Aswan jaguar
Describe the Bug:
If I enchant Arena with Wild Growth and activate it I will get {G} from Wild Growth even though I don't tap Arena for mana.

Which card did behave improperly?
tapped_for_mana_color seems to be broken.

Which update are you using? (date, name)Which type? (duel, gauntlet, sealed deck)
Holidays 2020 - Time of Ice, duel

What exactly should be the correct behavior/interaction?
Wild Growth and all cards that have an effect when a land is tapped for mana don't have an effect when a Land is tapped for a non-mana ability, unless there is another card that instructs them to do so.

Are any other cards possibly affected by this bug?
3 cards that I tested and use tapped_for_mana_color all were bugged.

Re: [conf]Whenever...tapped for mana cards affect non-mana,

PostPosted: 11 Mar 2021, 21:52
by drool66
This one is pretty insidious. I'm thinking it has something to do with an uncontrolled return to mana_producer(), or something just returning a tapped_for_mana_color on every EVENT_TAP_CARD if the card is tagged EA_MANA_SOURCE. This bug doesn't appear on Bazaar of Baghdad, for instance.

Re: [conf]Whenever...tapped for mana cards affect non-mana,

PostPosted: 15 Mar 2021, 10:57
by Korath
It's the responsibility of cards that set STATE_TAPPED when not tapping for mana to clear tapped_for_mana_color to -1. It's getting set in Arena during the charge_mana_for_activated_ability() call, and, by design, cmaa can't clear tapped_for_mana_color.

I'm sure you'll find that, if you already have the mana in your pool before activating Arena, Wild Growth won't add mana. Similarly, this is why Bazaar of Baghdad works: you don't ever tap a card for mana in the middle of its activation. If Suppression Field works and properly makes the Bazaar's ability cost mana - it looks like it won't - and tap a land after the Bazaar instead of before it, it would exhibit this bug.

Re: [conf]Whenever...tapped for mana cards affect non-mana,

PostPosted: 15 Mar 2021, 20:34
by drool66
Seems to me few cards handle this responsibly. Before I go through all mana producing cards that also have a non-mana producing activated ability, I think what you're saying is I would change, say, Diamond Kaleidoscope's EVENT_ACTIVATE from:
Code: Select all
   if( event == EVENT_ACTIVATE ){
      int abils[3] = {
                  0,
                  generic_activated_ability(player, card, EVENT_CAN_ACTIVATE, GAA_UNTAPPED, MANACOST_X(3), 0, NULL, NULL),
                  can_produce_mana(player, card) && new_can_sacrifice_as_cost(player, card, &test) ? 1 : 0
      };
      int choice = DIALOG(player, card, event, DLG_RANDOM, DLG_AUTOCHOOSE_IF_1,
                     "Create a Prism", abils[1] && ! paying_mana(), 5,
                     "Sac prism & get mana", abils[2], 1);
      if( ! choice ){
         spell_fizzled = 1;
         return 0;
      }
      if( choice == CHOICE_PRISM ){
         return generic_activated_ability(player, card, event, GAA_UNTAPPED, MANACOST_X(3), 0, NULL, NULL);
      }
      if( choice == CHOICE_MANA ){
         if( new_sacrifice(player, card, player, SAC_AS_COST, &test) ){
            FORCE(produce_mana_all_one_color(player, COLOR_TEST_ANY_COLORED, 1));
         }
         else{
            spell_fizzled = 1;
         }
      }
   }
to
Code: Select all
   if( event == EVENT_ACTIVATE ){
      int abils[3] = {
                  0,
                  generic_activated_ability(player, card, EVENT_CAN_ACTIVATE, GAA_UNTAPPED, MANACOST_X(3), 0, NULL, NULL),
                  can_produce_mana(player, card) && new_can_sacrifice_as_cost(player, card, &test) ? 1 : 0
      };
      int choice = DIALOG(player, card, event, DLG_RANDOM, DLG_AUTOCHOOSE_IF_1,
                     "Create a Prism", abils[1] && ! paying_mana(), 5,
                     "Sac prism & get mana", abils[2], 1);
      if( ! choice ){
         spell_fizzled = 1;
         return 0;
      }
      if( choice == CHOICE_PRISM ){
         int rv = generic_activated_ability(player, card, event, GAA_UNTAPPED, MANACOST_X(3), 0, NULL, NULL);
         tapped_for_mana_color = -1;
         return rv;
      }
      if( choice == CHOICE_MANA ){
         if( new_sacrifice(player, card, player, SAC_AS_COST, &test) ){
            FORCE(produce_mana_all_one_color(player, COLOR_TEST_ANY_COLORED, 1));
         }
         else{
            spell_fizzled = 1;
         }
      }
   }
and Morselhoarder's from:
Code: Select all
   if (event == EVENT_ACTIVATE){
      if (produce_mana_all_one_color(player, COLOR_TEST_ANY_COLORED, 1)){
         remove_counter(player, card, player, card, COUNTER_M1_M1);
      }
   }
to
Code: Select all
   if (event == EVENT_ACTIVATE){
      if (produce_mana_all_one_color(player, COLOR_TEST_ANY_COLORED, 1)){
         tapped_for_mana_color = -2;
         remove_counter(player, card, player, card, COUNTER_M1_M1);
      }
   }
Thanks for your help.

Re: [conf]Whenever...tapped for mana cards affect non-mana,

PostPosted: 20 Mar 2021, 22:01
by Korath
generic_activated_ability(...GAA_UNTAPPED...) is high-enough level that it should be safe to set it there. Unless there are mana producers that use that to activate their mana abilities, anyway, though those should already be setting it themselves. And even then you could add a flag to suppress that behavior.

The real problem is cards like Arena that dive directly into low-level activation behavior. Those should be findable by grepping for \|.*STATE_TAPPED|set_state.*STATE_TAPPED.

Morselhoarder doesn't tap, so it isn't an issue with this bug, but you're correct that it should be setting tapped_for_mana_color to a negative value other than -1 so it can't be responded to. The logic for tapped_for_mana_color in Manalink's assembly activate() is the same as in Shandalar's C++ version (except Manalink can't activate from the graveyard or exile).

Re: [conf]Whenever...tapped for mana cards affect non-mana,

PostPosted: 13 Apr 2021, 02:34
by drool66
Completed in e50890e "missing clear tapped_for_mana_color to -1 or -2; fix spurious instances of tap_card() in EVENT_ACTIVATE"