Page 1 of 1

[fixed] Betrayal of Flesh wrong etwine cost & etwine for all

PostPosted: 31 Mar 2018, 10:53
by Aswan jaguar
Describe the Bug:
1- Betrayal of Flesh it asks for etwine cost for all 3 options.
2- Betrayal of Flesh etwine cost is wrong it is sacrifice 3 creatures. It needs you to have more than 6 lands and select all your lands in order to sacrifice 3.
Which card did behave improperly?
Betrayal of Flesh or etwine ability cost.

Which update are you using? (date, name)Which type? (duel, gauntlet, sealed deck)
Manalink dev 778ccb5 version - duel

What exactly should be the correct behavior/interaction?
1- Betrayal of Flesh asks for etwine cost only for etwine ability.
2- Betrayal of Flesh etwine cost (select 3 lands) sacrifice 3 lands.

Are any other cards possibly affected by this bug?
-

Re: Betrayal of Flesh wrong etwine cost & etwine for all

PostPosted: 25 Jul 2020, 10:20
by FastEddie
I just answered to the wrong (archived) post...

Attached is a partial fix. Put it in the cards directory and apply

Code: Select all
patch mirrodin.c mirrodin.diff
The issue was the usage of the & operator. For example

Code: Select all
if (instance->info_slot & CHOICE_ENTWINE)
evaluates the brackets to 1, 2 or 3, depending on the choice stored in instance->info_slot, but this will always be at least 1, i.e. true. Therefore you always had to pay the Entwine cost.

Geek note: applying bitwise and with mask 0b11 (0b says that the following figures will be binary) on 0b01, 0b10 or 0b11 always preserves the input value.

Now the issue is that both kill and reanimate produce a get_card_instance(255,255) dump. Can it be that the stored target is overwritten? :?

As a sidenote, the following also looks fishy to me:

Code: Select all
count_subtype(player, TYPE_LAND, -1) > 6 ? 15 : 1
This counts the number of lands if I understand it correctly (my save game had 7 and I got 7). Since the casting cost if 5B it will be 1 if you have the exact amount of lands needed or less (e.g. if you have a Sol Ring) otherwise 15. But why?

Re: Betrayal of Flesh wrong etwine cost & etwine for all

PostPosted: 30 Jul 2020, 22:16
by drool66
Fixed in 4990ec9dc ("Fix Betrayal of Flesh", 2020-07-30)

Re: [fixed] Betrayal of Flesh wrong etwine cost & etwine for

PostPosted: 31 Jul 2020, 12:21
by FastEddie
Can you quickly elaborate what the issue was? I would like to understand where I went astray.

Re: [fixed] Betrayal of Flesh wrong etwine cost & etwine for

PostPosted: 31 Jul 2020, 15:34
by drool66
Several things. Here's the diff:
Code: Select all
 
    if( event == EVENT_CAST_SPELL && affect_me(player, card) ){
       instance->number_of_targets = 0;
-      int sacced[3] = {-1};
+      char marked_for_sacrifice[151];
       if( ! check_special_flags2(player, card, SF2_COPIED_FROM_STACK) ){
          instance->info_slot = 0;
          test_definition_t test2;
@@ -481,68 +481,58 @@ Entwine
                      generic_spell(player, card, EVENT_CAN_CAST, GS_GRAVE_RECYCLER, NULL, NULL, 1, &test),
                      new_can_sacrifice_as_cost(player, card, &test2)
          };
-         int choice = DIALOG(player, card, event, DLG_RANDOM,
+         int choice = DIALOG(player, card, event, DLG_RANDOM, //DLG_AUTOCHOOSE_IF_1
                         "Kill a creature", abils[1], 10,
                         "Reanimate a creature", abils[2], 5,
-                        "Entwine", abils[1] && abils[2] && abils[3], count_subtype(player, TYPE_LAND, -1) > 6 ? 15 : 1);
+                        "Entwine", abils[1] && abils[2] && abils[3], count_subtype(player, TYPE_LAND, -1)*2);
          if( ! choice ){
             spell_fizzled = 1;
             return 0;
          }
-         if( instance->info_slot & CHOICE_ENTWINE ){
-            int i;
-            for(i=0; i<3; i++){
-               int sac = new_sacrifice(player, card, player, SAC_JUST_MARK | SAC_AS_COST | SAC_RETURN_CHOICE, &test2);
-               if( sac ){
-                  sacced[i] = sac;
-               }
-               else{
-                  spell_fizzled = 1;
-                  break;
-               }
-            }
-            for(i=0; i<3; i++){
-               if( sacced[i] != -1 ){
-                  state_untargettable(BYTE2(sacced[i]), BYTE3(sacced[i]), 0);
-               }
-            }
-            if( spell_fizzled == 1 ){
+         if( choice == CHOICE_ENTWINE ){
+            scnprintf(test2.message, 100, "Select land to sacrifice.");
+            if( mark_sacrifice(player, card, player, SAC_JUST_MARK | SAC_AS_COST | SAC_ALL_OR_NONE, &test2, marked_for_sacrifice) < 3 ){
+               spell_fizzled = 1;
                return 0;
             }
          }
       }
       instance->number_of_targets = 0;
       int base_target = 0;
-      if( instance->info_slot & CHOICE_KILL ){
-         if( pick_target(&td, "TARGET_CREATURE") ){
+      if( (instance->info_slot == CHOICE_KILL) || (instance->info_slot == CHOICE_ENTWINE) ){
+         if( new_pick_target(&td, "TARGET_CREATURE", 0, 1) ){
             base_target++;
          }
          else{
             return 0;
          }
       }
-      if( instance->info_slot & CHOICE_REANIMATE ){
+      if( (instance->info_slot == CHOICE_REANIMATE) || (instance->info_slot == CHOICE_ENTWINE) ){
          if( ! select_target_from_grave_source(player, card, player, 0, AI_MAX_CMC, &test, base_target) ){
             return 0;
          }
       }
-      if( ! check_special_flags2(player, card, SF2_COPIED_FROM_STACK) ){
-         int i;
-         for(i=0; i<3; i++){
-            kill_card(BYTE2(sacced[i]), BYTE3(sacced[i]), KILL_SACRIFICE);
+      if( ! check_special_flags2(player, card, SF2_COPIED_FROM_STACK) && instance->info_slot == CHOICE_ENTWINE ){
+         int c;
+         for (c = 0; c < active_cards_count[player]; ++c){
+            if (marked_for_sacrifice[c]){
+               get_card_instance(player, c)->state &= ~STATE_CANNOT_TARGET;
+               if (cancel != 1 && in_play(player, c))
+                  kill_card(player, c, KILL_SACRIFICE);
+            }
          }
       }
    }
 
    if(event == EVENT_RESOLVE_SPELL ){
       int base_target = 0;
-      if( instance->info_slot & CHOICE_KILL ){
-         if( valid_target(&td) ){
+      if( (instance->info_slot == CHOICE_KILL) || (instance->info_slot == CHOICE_ENTWINE) ){
+         if( validate_target(player, card, &td, 0) ){
             kill_card(instance->targets[0].player, instance->targets[0].card, KILL_DESTROY);
          }
          base_target++;
       }
-      if( instance->info_slot & CHOICE_REANIMATE ){
+      if( (instance->info_slot == CHOICE_REANIMATE) || (instance->info_slot == CHOICE_ENTWINE) ){
          int selected = validate_target_from_grave_source(player, card, player, base_target);
          if( selected != -1 ){
             reanimate_permanent(player, card, player, selected, REANIMATE_DEFAULT);
The biggest problem was that using SAC_JUST_MARK with new_sacrifice() when there is more than one thing to sacrifice will only give you the last card sacrificed in (BYTE2, BYTE3) to use them together you need to use mark_sacrifice() (which is only used on one other card). This is documented at SAC_JUST_MARK in defs.h.
But also, it used "if(valid_target())" instead of validate_target(), its sacced[] array was memset wrong, and the sacrifice prompt was just "select a card" I also made the AI selection a little less binary.
Thank you for the correction on the bitwise operators =D>

Re: [fixed] Betrayal of Flesh wrong etwine cost & etwine for

PostPosted: 31 Jul 2020, 16:16
by FastEddie
Oh my gosh... good that you had a look at it. This would have cost me ages to figure out.