Page 1 of 1

[fixed]Soulflayer doesn't gain all abilities

PostPosted: 16 Sep 2018, 15:59
by Aswan jaguar
Describe the Bug:
I used delve with Soulflayer and exiled Spark Trooper but Soulflayer didn't get haste nor lifelink only trample ability.
I looked at the code and if I am not wrong it will not add also deathtouch, hexproof, indestructible and vigilance.
Which card did behave improperly?
Soulflayer

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?
Soulflayer : If a creature card with flying was exiled with Soulflayer's delve ability, Soulflayer has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, reach, trample, and vigilance.

Are any other cards possibly affected by this bug?
-

Re: Soulflayer doesn't gain all abilities

PostPosted: 25 Oct 2023, 14:31
by Aswan jaguar
Can we now add special_abilities to Soulflayer? I tried but I always ended up with Soulflayer gaining an extra ability for each other keyword or sp_keyword ability.

Re: Soulflayer doesn't gain all abilities

PostPosted: 25 Oct 2023, 18:01
by drool66
Yep. One limitation was getting sp_keywords from an iid (we have since overcome this through has_sp_key_by_iid()). The other is carrying them over and storing them on the instance data. cast_spell_with_delve() is called on EVENT_CAST_SPELL, so we have an instance, and we can write the data directly to the instance rather than reading the return value of cast_spell_with_delve(). This is what Murktide Regent does.
The other issue is where to store it. It should properly be stored in instance_info, but we only have one full int (good for the regular keywords) and one int16_t. We can overcome this one of two ways - I would say we should re-enumerate all of SP_KEYWORD_REAL_KEYWORDS to the first 16 bits of sp_keyword_t (there are exactly 16 of them so huzzah). I doubt this would have unintended consequences, and if it does it means there is a problem elsewhere. The other way would be to store the relevant keywords in arbitrary bits of inst_info_t::data2, and then re-interpret them on every EVENT_ABILITIES. eg. store deathtouch at 1<<0 in data2, and then write SP_KEYWORD_DEATHTOUCH (ie. 1<<9) to ext::sp_keywords on EVENT_ABILITIES, store haste as 1<<1, and so on.

Re: Soulflayer doesn't gain all abilities

PostPosted: 26 Oct 2023, 03:12
by drool66
Here's some code:
future_sight.c::cast_spell_with_delve():
Code: Select all
...
      if( spell_fizzled != 1 ){
         int result = 2;
         int num_spells = 0, num_creatures = 0;
         const int *grave = get_grave(player);
         for(i=0; i<trc; i++){
            if( get_id(player, card) == CARD_ID_SOULFLAYER ){
               int ability_mask = KEYWORD_FIRST_STRIKE | KEYWORD_DOUBLE_STRIKE | KEYWORD_TRAMPLE | KEYWORD_FLYING | KEYWORD_REACH;
               int sp_ability_mask = SP_KEYWORD_DEATHTOUCH | SP_KEYWORD_HASTE | SP_KEYWORD_HEXPROOF | SP_KEYWORD_INDESTRUCTIBLE | SP_KEYWORD_LIFELINK | SP_KEYWORD_VIGILANCE;
               int sp_abilities = has_sp_key_by_iid(grave[targs[i].player, sp_ability_mask);
               int sp_ability_bits = 0;
               if( sp_abilities ){
                  if(sp_abilities & SP_KEYWORD_DEATHTOUCH)
                     sp_ability_bits |= 1<<0;
                  if(sp_abilities & SP_KEYWORD_HASTE)
                     sp_ability_bits |= 1<<1;
                  if(sp_abilities & SP_KEYWORD_HEXPROOF)
                     sp_ability_bits |= 1<<2;
                  if(sp_abilities & SP_KEYWORD_INDESTRUCTIBLE)
                     sp_ability_bits |= 1<<3;
                  if(sp_abilities & SP_KEYWORD_LIFELINK)
                     sp_ability_bits |= 1<<4;
                  if(sp_abilities & SP_KEYWORD_VIGILANCE)
                     sp_ability_bits |= 1<<5;
               }
               set_inst_info(instance, CARD_ID_SOULFLAYER,
                     inst_info(instance, CARD_ID_SOULFLAYER).data | (cards_data[grave[targs[i].player]].static_ability & ability_mask),
                     inst_info(instance, CARD_ID_SOULFLAYER).data2 | sp_ability_bits);
            }
...
fate_reforged.c::card_soulflayer()
Code: Select all
int card_soulflayer(int player, int card, event_t event){
   /*
     Soulflayer |4|B|B
     Creature - Demon
     Delve
     If a creature card with flying was exiled with ~'s delve ability, ~ has flying.
       The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, reach, trample, and vigilance.
     4/4
   */
   delve(player, card, event);

   if( event == EVENT_ABILITIES && affect_me(player, card) && ! is_humiliated(player, card, AL_STATIC) ){
      DECL_INST();
      event_result |= cards_data(inst, CARD_ID_SOULFLAYER).data;
      if( cards_data(inst, CARD_ID_SOULFLAYER).data2 ){
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<0)
            deathtouch(player, card, event);
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<1)
            haste(player, card, event);
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<2)
            hexproof(player, card, event);
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<3)
            indestructible(player, card, event);
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<4)
            lifelink(player, card, event);
         if(cards_data(inst, CARD_ID_SOULFLAYER).data2 & 1<<5)
            vigilance(player, card, event);
      }
   }

   return 0;
}

Re: Soulflayer doesn't gain all abilities

PostPosted: 26 Oct 2023, 08:41
by Aswan jaguar
Fixed in commit c34ea45, thanks drool66.