It is currently 25 Apr 2024, 15:05
   
Text Size

[conf]Karn Liberated restart game ability not begining turn

Report wrong Card behavior to get it fixed.
PLEASE ADD SAVEGAMES TO YOUR TOPIC !

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

[conf]Karn Liberated restart game ability not begining turn

Postby Aswan jaguar » 15 Mar 2021, 15:52

Describe the Bug:
Karn Liberated 's restart game ability doesn't begin the turn from the beginning but from the step it was activated so creatures or lands that were exiled by it's abilities like Akum Refuge don't untap and creatures have summoning sickness while they shouldn't.

Which card did behave improperly?
Karn Liberated

Which update are you using? (date, name)Which type? (duel, gauntlet, sealed deck)
March 2021 - Allegiances and Alliances, duel

What exactly should be the correct behavior/interaction?
Relevant rules:
8/7/2020 Permanents put onto the battlefield due to Karn’s ability will have been under the starting controller’s control continuously since the beginning of that player’s first turn. Creatures among them can attack and their activated abilities with Tap in the cost can be activated.
8/7/2020 Any permanents put onto the battlefield with Karn’s ability that entered the battlefield tapped will untap during their controller’s first untap step.

Are any other cards possibly affected by this bug?
-
Last edited by Aswan jaguar on 16 Mar 2021, 13:14, edited 2 times in total.
Reason: confirmed by drool66
---
Trying to squash some bugs and playtesting.
User avatar
Aswan jaguar
Super Tester Elite
 
Posts: 8078
Joined: 13 May 2010, 12:17
Has thanked: 730 times
Been thanked: 458 times

Re: Karn Liberated restart game ability not begining turn

Postby drool66 » 16 Mar 2021, 05:27

It was also shuffling the Rules Engine into the deck - I've now fixed that and reset some global variables to their initial values, but not the current_phase.
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: [conf]Karn Liberated restart game ability not begining t

Postby drool66 » 27 Mar 2021, 22:02

I managed to find a way to do it, albeit weirdly. I can only get the card to take the player to the precombat main phase, but I can automate everything (I think) before that. Weird thing is that all of the decisions are made for them - if they have mana to pay upkeep costs they are paid automatically, for example. There's probably more code that can be inserted, but this is still an upgrade from what we have:
Code: Select all
void clear_all_traps(int player);
int untap_phase(int player);
int upkeep_phase(int player);
void phase_changed(int player, int new_phase);
int card_karn_liberated(int player, int card, event_t event){

   /* Karn Liberated
    * |7
    * Planeswalker - Karn (6)
    * +4: Target player exiles a card from his or her hand.
    * -3: Exile target permanent.
    * -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with ~. Then put those cards onto the battlefield under your control. */

   check_legend_rule(player, card, event);

   if (IS_ACTIVATING(event)){

      card_instance_t* instance = get_card_instance(player, card);

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

      target_definition_t td1;
      default_target_definition(player, card, &td1, TYPE_PERMANENT);

      enum{
         CHOICE_EXILE_CARD_IN_HAND = 1,
         CHOICE_EXILE_PERMANENT,
         CHOICE_RESTART_GAME,
      };

      int choice = DIALOG(player, card, event, DLG_RANDOM, DLG_PLANESWALKER,
                     "Exile a card in target's hand", can_target(&td), would_validate_arbitrary_target(&td, 1-player, -1) && hand_count[1-player] ? 15 : 0, 4,
                     "Exile a permanent", can_target(&td1), 10, -3,
                     "Restart the game", 1, 20, -14);

     if (event == EVENT_CAN_ACTIVATE)
      {
        if (!choice)
         return 0;
      }
     else if (event == EVENT_ACTIVATE)
      {
        instance->number_of_targets = 0;
        switch (choice)
         {
            case CHOICE_EXILE_CARD_IN_HAND:
               pick_target(&td, "TARGET_PLAYER");
               break;

            case CHOICE_EXILE_PERMANENT:
               pick_target(&td1, "TARGET_PERMANENT");
               break;

            case CHOICE_RESTART_GAME:
            {
               instance->targets[1].card = -1;
               if( count_counters(player, card, COUNTER_LOYALTY) <= 14 || instance->kill_code ){
                  instance->targets[1].card = exiledby_detach(player, card);
               }
               break;
            }
         }
      }
     else   // event == EVENT_RESOLVE_ACTIVATION
      switch (choice)
        {
         case CHOICE_EXILE_CARD_IN_HAND:
            {
               if( valid_target(&td)){
                  if( hand_count[instance->targets[0].player] ){
                     int selected = -1;
                     test_definition_t this_test;
                     if( instance->targets[0].player == HUMAN ){
                        default_test_definition(&this_test, TYPE_ANY);
                        selected = new_select_a_card(instance->targets[0].player, instance->targets[0].player, TUTOR_FROM_HAND, 1, AI_MIN_VALUE, -1, &this_test);
                     }
                     else{
                        default_test_definition(&this_test, TYPE_PERMANENT);
                        this_test.type_flag = DOESNT_MATCH;
                        selected = new_select_a_card(instance->targets[0].player, instance->targets[0].player, TUTOR_FROM_HAND, 1, AI_MIN_VALUE, -1, &this_test);
                        if( selected == -1 ){
                           default_test_definition(&this_test, TYPE_ANY);
                           selected = new_select_a_card(instance->targets[0].player, instance->targets[0].player, TUTOR_FROM_HAND, 1, AI_MIN_VALUE, -1, &this_test);
                        }
                     }
                     if( in_play(instance->parent_controller, instance->parent_card) ){
                        exile_card_and_remember_it_on_exiledby(instance->parent_controller, instance->parent_card,
                                                      instance->targets[0].player, selected);
                     }
                     else{
                        rfg_card_in_hand(instance->targets[0].player, instance->targets[0].card);
                     }
                  }
               }
            }
            break;

         case CHOICE_EXILE_PERMANENT:
            {
               if( valid_target(&td1)){
                  if( ! is_token(instance->targets[0].player, instance->targets[0].card) &&
                     in_play(instance->parent_controller, instance->parent_card) )
                  {
                     exile_card_and_remember_it_on_exiledby(instance->parent_controller, instance->parent_card,
                                                   instance->targets[0].player, instance->targets[0].card);
                  }
                  else{
                     kill_card(instance->targets[0].player, instance->targets[0].card, KILL_EXILE);
                  }
               }
            }
            break;

         case CHOICE_RESTART_GAME:
            {
               int exby_player = instance->targets[1].card > -1 ? player-2 : instance->parent_controller;
               int exby_card = instance->targets[1].card > -1 ? instance->targets[1].card : instance->parent_card;
               int dead = instance->targets[1].card > -1;
               int exiled_by_karn[2][18];
               memset(exiled_by_karn, -1, sizeof(exiled_by_karn));
               int exc[2] = {0, 0};
               int leg = 0;
               int idx = 0;
               int* loc;
               while ((loc = exiledby_find_any(exby_player, exby_card, &leg, &idx)) != NULL){
                     int owner = (*loc & 0x80000000) ? 1 : 0;
                     int iid = *loc & ~0x80000000;
                     *loc = -1;
                     exiled_by_karn[owner][exc[owner]] = iid;
                     exc[owner]++;
               }
               // approximation for "restart the game"
               APNAP(p,{
                        int c;
                        for(c=active_cards_count[p]-1; c>-1; c--){
                           if( in_play(p, c) && is_what(p, c, TYPE_ENCHANTMENT) && has_subtype(p, c, SUBTYPE_AURA) ){
                              put_on_top_of_deck(p, c);
                           }
                        }
                     };
               );
               APNAP(p,{
                        int c;
                        for(c=active_cards_count[p]-1; c>-1; c--){
                           if( in_hand(p, c) ){
                              put_on_top_of_deck(p, c);
                           }
                           if( in_play(p, c) ){
                              int id = get_id(p, c), iid = get_original_internal_card_id(p, c);
                              if( is_what(p, c, TYPE_EFFECT) && iid != activation_card &&
                                    cards_data[iid].cc[2] != 99 && cards_data[iid].cc[2] != 3 &&
                                    id != 916 && id != CARD_ID_RULES_ENGINE && id != CARD_ID_DEADBOX
                              ){
                                 kill_card(p, c, KILL_EXILE);
                              }
                              if( is_what(p, c, TYPE_PERMANENT) ){
                                 put_on_top_of_deck(p, c);
                              }
                           }
                        }
                     };
               );
               APNAP(p,{
                          reshuffle_grave_into_deck(p, 1);
                      };
               );
               APNAP(p,{
                        life[p] = get_starting_life_total(p);
                        raw_set_poison(p, 0);
                        raw_set_experience(p, 0);
                        player_counters[player].energy_ = 0;
                     };
               );
               APNAP(p,{
                        int i;
                        for(i=0; i<exc[p]; i++){
                           if( ! is_what(-1, exiled_by_karn[p][i], TYPE_PERMANENT) || has_subtype_by_id(cards_data[exiled_by_karn[p][i]].id, SUBTYPE_AURA) ){
                              remove_card_from_rfg(p, cards_data[exiled_by_karn[p][i]].id);
                              raw_put_iid_on_top_of_deck(p, exiled_by_karn[p][i]);
                              exiled_by_karn[p][i] = -1;
                           }
                        }
                     };
               );
               APNAP(p,{
                        shuffle(p);
                        draw_cards(p, 7);
                     };
               );
               APNAP(p,{
                        int i;
                        for(i=0; i<exc[p]; i++){
                           if( exiled_by_karn[p][i] > -1 ){
                              int card_added = add_card_to_hand(player, exiled_by_karn[p][i]);
                              if( p != player ){
                                 if( player == AI ){
                                    remove_state(player, card_added, STATE_OWNED_BY_OPPONENT);
                                 }
                                 else{
                                    add_state(player, card_added, STATE_OWNED_BY_OPPONENT);
                                 }
                              }
                              remove_card_from_rfg(p, cards_data[exiled_by_karn[p][i]].id);
                              exiled_by_karn[p][i] = -1;
                              put_into_play(player, card_added);
                              /* 8/7/2020 Permanents put onto the battlefield due to Karn's ability will have been under the starting controller's control continuously since the beginning of that player's first turn. Creatures among them can attack and their activated abilities with Tap in the cost can be activated.
                              *  8/7/2020 Any permanents put onto the battlefield with Karn's ability that entered the battlefield tapped will untap during their controller's first untap step. */
                              if(is_what(player, card_added, TYPE_PERMANENT)){
                                 remove_summoning_sickness(player, card_added);
                                 remove_state(player, card_added, STATE_TAPPED);
                              }
                           }
                        }
                     };
               );
               if( dead )
                  exiledby_destroy_detached(player, instance->targets[1].card);

               memset(cards_drawn_this_turn, 0, sizeof(cards_drawn_this_turn));
               memset(mana_pool, 0, sizeof(mana_pool));
               turn_count = 0;
               lands_played = 0;
               APNAP(p, {clear_all_traps(p);};);
               land_can_be_played = 0;
               recalculate_all_cards_in_play();
               current_turn = player;
               untap_phase(player);
               upkeep_phase(player);
               phase_changed(player, PHASE_DRAW);
               dispatch_event(player, card, EVENT_DRAW_PHASE);
               phase_changed(player, PHASE_MAIN1);
               current_phase = PHASE_MAIN1;
            }
            break;
        }
   }

   return planeswalker(player, card, event, 6);
}
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: [conf]Karn Liberated restart game ability not begining t

Postby Aswan jaguar » 31 Mar 2021, 05:35

I have run few tests and I agree this is better from what we have now.
---
Trying to squash some bugs and playtesting.
User avatar
Aswan jaguar
Super Tester Elite
 
Posts: 8078
Joined: 13 May 2010, 12:17
Has thanked: 730 times
Been thanked: 458 times

Re: [conf]Karn Liberated restart game ability not begining t

Postby Korath » 01 Apr 2021, 20:21

I haven't looked at what kind of hackery you added to implement Time Stop, but maybe reuse that as an alternative?
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times

Re: [conf]Karn Liberated restart game ability not begining t

Postby drool66 » 01 Apr 2021, 22:11

Oh there's plenty of hackery there, but at its heart it just empties the stack and moves to PHASE_DISCARD, disabling everything until it can get there. I was thinking about that - a special end the turn legacy that also includes a time walk (if current_turn == player), and does everything Karn does at PHASE_START, or failing that, PHASE_UNTAP. I'll give it a shot.
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times


Return to Bug Reports

Who is online

Users browsing this forum: No registered users and 56 guests


Who is online

In total there are 56 users online :: 0 registered, 0 hidden and 56 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: No registered users and 56 guests

Login Form