It is currently 15 May 2025, 20:14
   
Text Size

[fixed]Collective Brutality escalate issue

Moderators: BAgate, drool66, Aswan jaguar, gmzombie, stassy, CCGHQ Admins

[fixed]Collective Brutality escalate issue

Postby Aswan jaguar » 23 Aug 2020, 16:29

Describe the Bug:
Collective Brutality has an issue when you escalate for second time in a raw to select all 3 modes. When the submenu with cards in your hand appears there is still with the same number of cards there was when you escalated the first time (the previous selected card is not there but in it's place there is a card not even in deck) and that card can be chosen again as a result you can discard only one card if you select the substitute card. If you don't then correctly it will discard the two chosen cards.

Which card did behave improperly?
Collective Brutality

Which update are you using? (date, name)Which type? (duel, gauntlet, sealed deck)
dev

What exactly should be the correct behavior/interaction?
Collective Brutality should either mark the selected card so it can't be chosen again if you escalate it again or remove the first selected card to be discarded from 2nd selection submenu.

Are any other cards possibly affected by this bug?
-
Last edited by Aswan jaguar on 28 Sep 2020, 12:11, edited 2 times in total.
Reason: fixed
---
Trying to squash some bugs and playtesting.
User avatar
Aswan jaguar
Super Tester Elite
 
Posts: 8129
Joined: 13 May 2010, 12:17
Has thanked: 748 times
Been thanked: 477 times

Re: Collective Brutality escalate issue

Postby FastEddie » 20 Sep 2020, 15:37

I think that fixes it. This card had other issues beyond the escalate mechanism, namely that discard would end in a hanging game, same for choosing a creature for -2/-2.

I tested the following cases:
    Opponent has instant or sorcery in hand
    Opponent has no instant or sorcery in hand (no save game for this attached)
    At least one creature in play
    No creature in play
    Player has no hand after casting Collective Brutality
    Opponent has shroud
Save games for all cases except the one mentioned are attached. The base save game works for most of them.

Code: Select all
int card_collective_brutality(int player, int card, event_t event){
 /* Collective Brutality   |1|B   0x200ef6c
  * Sorcery
  * Escalate-Discard a card.
  * Choose one or more -
  * * Target opponent reveals his or her hand. You choose an instant or sorcery card from it. That player discards that card.
  * * Target creature gets -2/-2 until end of turn.
  * * Target opponent loses 2 life and you gain 2 life. */

   if( ! IS_GS_EVENT(player, card, event) ){
      return 0;
   }

   enum
   {
      CHOICE_DURESS       = 1<<0,
      CHOICE_WEAKEN       = 1<<1,
      CHOICE_SUCK_LIFE    = 1<<2,
      CHOICE_MASK = CHOICE_DURESS | CHOICE_WEAKEN | CHOICE_SUCK_LIFE,
   };

   target_definition_t td_creature;
   default_target_definition(player, card, &td_creature, TYPE_CREATURE );
   td_creature.preferred_controller = player;

   target_definition_t td_opp;
   default_target_definition(player, card, &td_opp, 0);
   td_opp.zone = TARGET_ZONE_PLAYERS;

   card_instance_t *instance = get_card_instance(player, card);

   if( event == EVENT_CAN_CAST ){
      if( basic_spell(player, card, event) ){
         return would_validate_arbitrary_target(&td_opp, 1-player, -1) || can_target(&td_creature);
      }
   }

   if( event == EVENT_CAST_SPELL && affect_me(player, card) ){
      int i;
      int to_discard[2];
      int td_count = 0;
      if( ! check_special_flags2(player, card, SF2_COPIED_FROM_STACK) ){
         instance->info_slot = 0;
         int remaining_choices = 3;
         if ( !would_validate_arbitrary_target(&td_opp, 1-player, -1) ) {
            // Opponent can't be targeted
            remaining_choices -= 2;
         }
         if ( !can_target(&td_creature) ) {
            // No creatures in play
            remaining_choices--;
         }
         int hand_backup[2][hand_count[player]];
         int hand_backup_count = 0;
         for(i=0; i<active_cards_count[player]; i++){
            if( in_hand(player, i) ){
               hand_backup[0][hand_backup_count] = get_original_internal_card_id(player, i);
               hand_backup[1][hand_backup_count] = i;
               hand_backup_count++;
            }
         }
         while( ((instance->info_slot & CHOICE_MASK) != CHOICE_MASK) && (remaining_choices > 0) ){
               int can_discard = !(instance->info_slot & CHOICE_DURESS) && would_validate_arbitrary_target(&td_opp, 1-player, -1);
               int can_target_crit = !(instance->info_slot & CHOICE_WEAKEN) && can_target(&td_creature);
               int can_suck = !(instance->info_slot & CHOICE_SUCK_LIFE) && would_validate_arbitrary_target(&td_opp, 1-player, -1);
               int choice = DIALOG(player, card, event, DLG_NO_STORAGE, DLG_RANDOM,
                              "Opponent discards", can_discard, 15,
                              "Target creature gets -2/-2", can_target_crit, 10,
                              "Drain opponent 2 life", can_suck, life[1-player] <= 2 ? 20 : 5);

               if( ! choice ){
                  spell_fizzled = 1;
                  return 0;
               }
               remaining_choices--;
                     // Convert choice number 1, 2, 3 in choice bits 001, 010, 100
                     instance->info_slot |= 1<<(choice-1);
               if( (hand_count[player] > td_count) && (remaining_choices > 0) ){
                  int choice2 = DIALOG(player, card, event, DLG_NO_STORAGE, DLG_NO_CANCEL,
                                 "Escalate", 1, 10,
                                 "Decline", 1, 1);
                  if( choice2 == 1 ){
                     test_definition_t test;
                     new_default_test_definition(&test, TYPE_ANY, "Select a card to discard.");
                     test.id_flag = DOESNT_MATCH;
                     int selected = select_card_from_zone(player, player, hand_backup[0], hand_backup_count, 0, AI_MIN_VALUE, -1, &test);
                     if( selected != -1 ){
                        // Store selected card, will discard later
                        to_discard[td_count] = hand_backup[1][selected];
                        td_count++;
                        // Move cards right of selected one left to overwrite selected
                        for ( i=selected; i<hand_backup_count-1; i++ ) {
                           hand_backup[0][i] = hand_backup[0][i+1];
                           hand_backup[1][i] = hand_backup[1][i+1];
                        }
                        hand_backup_count--;
                     }
                     else{
                        break;
                     }
                  }
                  else{
                     break;
                  }
               }
               else{
                  break;
               }
         }
      }
      instance->number_of_targets = 0;
      if( instance->info_slot & CHOICE_DURESS ){
         instance->targets[0].player = 1-player;
         instance->targets[0].card = -1;
         instance->number_of_targets++;
      }
      if( instance->info_slot & CHOICE_WEAKEN ){
         // new_pick_target stores the result in targets[] and increments number_of_targets
         new_pick_target(&td_creature, "Select target creature (-2/-2).", -1, 1 | GS_LITERAL_PROMPT);
      }
      if( instance->info_slot & CHOICE_SUCK_LIFE ){
         instance->targets[instance->number_of_targets].player = 1-player;
         instance->targets[instance->number_of_targets].card = -1;
         instance->number_of_targets++;
      }
      if( spell_fizzled != 1 ){
         for(i=0; i<td_count; i++){
            new_discard_card(player, to_discard[i], 0, player);
         }
      }
      if (ai_is_speculating == 0) {
         LOG_DEBUG("EVENT_CAST")
         for (i=0; i<instance->number_of_targets; i++) {
            LOG_DEBUG("targets[%d].player=%d, targets[%d].card=%d", i, instance->targets[i].player, i, instance->targets[i].card)
         }
      }
   }

   if( event == EVENT_RESOLVE_SPELL ){
      if (ai_is_speculating == 0) {
         LOG_DEBUG("EVENT_RESOLVE")
      }
      int targets_found = 0;
      if( instance->info_slot & CHOICE_DURESS ){
         if (ai_is_speculating == 0) {
            LOG_DEBUG("CHOICE_DURESS")
         }
         if( validate_target(player, card, &td_opp, targets_found) ){
            ec_definition_t ec;
            // If duress has been chosen the player id is by definition in targets[0]
            default_ec_definition(instance->targets[0].player, player, &ec);
   
            test_definition_t this_test;
            new_default_test_definition(&this_test, TYPE_INSTANT | TYPE_SORCERY, "Select an instant or sorcery card.");
            this_test.type_flag = MATCH;
            new_effect_coercion(&ec, &this_test);
         }
         targets_found++;
      }
      if( instance->info_slot & CHOICE_WEAKEN ){
         if (ai_is_speculating == 0) {
            LOG_DEBUG("CHOICE_WEAKEN")
         }
         if( validate_target(player, card, &td_creature, targets_found) ){
            if (ai_is_speculating == 0) {
               LOG_DEBUG("targets_found=%d, targets[targets_found].player=%d, targets[targets_found].card=%d", \
                  targets_found, instance->targets[targets_found].player, instance->targets[targets_found].card)
            }
            pump_until_eot(player, card, instance->targets[targets_found].player, instance->targets[targets_found].card, -2, -2);
         }
         targets_found++;
      }
      if( instance->info_slot & CHOICE_SUCK_LIFE ){
         if (ai_is_speculating == 0) {
            LOG_DEBUG("CHOICE_SUCK_LIFE")
         }
         if( validate_target(player, card, &td_opp, targets_found) ){
            if (ai_is_speculating == 0) {
               LOG_DEBUG("targets_found=%d, targets[targets_found].player=%d", targets_found, instance->targets[targets_found].player)
            }
            lose_life(instance->targets[targets_found].player, 2);
            gain_life(player, 2);
         }
      }
      kill_card(player, card, KILL_DESTROY);
   }

   return 0;
}
---
Argivian Archaeologist in the Library of Leng studying the Spells of the Ancients
User avatar
FastEddie
 
Posts: 246
Joined: 24 Dec 2019, 10:59
Has thanked: 15 times
Been thanked: 19 times

Re: [confirmed]Collective Brutality escalate issue

Postby FastEddie » 28 Sep 2020, 10:22

Committed in "[fasteddie 703385ba0] Fixed Collective Brutality."
---
Argivian Archaeologist in the Library of Leng studying the Spells of the Ancients
User avatar
FastEddie
 
Posts: 246
Joined: 24 Dec 2019, 10:59
Has thanked: 15 times
Been thanked: 19 times


Return to Archived Reports

Who is online

Users browsing this forum: Google [Bot] and 23 guests


Who is online

In total there are 24 users online :: 1 registered, 0 hidden and 23 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: Google [Bot] and 23 guests

Login Form