It is currently 16 Apr 2024, 14:13
   
Text Size

Card Development - talk about cards code here

Discuss Upcoming Releases, Coding New Cards, Etc.
PLEASE DO NOT REPORT BUGS HERE!

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

Re: Card Development - talk about cards code here

Postby Aswan jaguar » 03 Jan 2023, 10:17

It needed store_attackers() to trigger, now fixed.
---
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

Need Help to exile Planeswalkers when died

Postby etphonehome » 14 Jan 2023, 23:30

Hi

This card works fine but it doesn't exile a planeswalker when it dies. There's no other card with similar effect already coded to guide me.



Code: Select all
   int card_scorching_dragonfire(int player, int card, event_t event) {
   /*CARD_ID_SCORCHING_DRAGONFIRE   20722
   Scorching Dragonfire   |1|R
   Instant
   ~ deals 3 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead.
   */

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

   target_definition_t td;
      default_target_definition(player, card, &td, TYPE_CREATURE | TYPE_PLANESWALKER);


   if (event == EVENT_RESOLVE_SPELL) {
      if (valid_target(&td)) {
         card_instance_t* instance = get_card_instance(player, card);
         exile_if_would_be_put_into_graveyard(player, card, instance->targets[0].player, instance->targets[0].card, 1);
         damage_target0(player, card, 3);
      }
      kill_card(player, card, KILL_DESTROY);
   }

   return generic_spell(player, card, event, GS_CAN_TARGET, &td, "TARGET_CREATURE_OR_PLANESWALKER", 1, NULL);

}
THX
Attachments
m21-158-scorching-dragonfire.jpg
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

Re: Card Development - talk about cards code here

Postby drool66 » 15 Jan 2023, 01:57

It's not your card's fault - planeswalkers just don't have a way to handle this. Probably belongs in kill_card(), but I'm not sure if there are corner cases that break something

EDIT: Ok, it's working; your code is good to go
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: Card Development - talk about cards code here

Postby etphonehome » 15 Jan 2023, 15:57

Hi

Need some help here! Can't make this card to reduce cost. Used "Angel's Mercy" to reduce cost but it doesn't happen.

Code: Select all
int card_sanguine_indulgence(int player, int card, event_t event) {
   /* CARD_ID_SANGUINE_INDULGENCE   21659
   Sanguine Indulgence   |3|B
   Sorcery
   This spell costs |3 less to cast if you've gained 3 or more life this turn.
   Return up to two target creature cards from your graveyard to your hand. */

   if (event == EVENT_MODIFY_COST) {
      if (get_trap_condition(player, TRAP_LIFE_GAINED) >= 3) {
         COST_COLORLESS -= 3;
      }
   }

      test_definition_t test;
      new_default_test_definition(&test, TYPE_CREATURE, "Select up to two target creature cards.");
      return spell_return_up_to_n_target_cards_from_your_graveyard_to_your_hand(player, card, event, 2, &test, 0);
}
THX
Attachments
m21-121-sanguine-indulgence.jpg
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

Re: Card Development - talk about cards code here

Postby drool66 » 15 Jan 2023, 16:57

Its another csv flag, this time "Modifies Casting Cost"
btw, if you want to modify the casting cost of something else, like with Sapphire Medallion eg., you use "Flags:Play Cost" in csv and EVENT_MODIFY_COST_GLOBAL on the card.
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: Card Development - talk about cards code here

Postby etphonehome » 16 Jan 2023, 16:39

HI

I set the flag "Modifies Casting Cost" in ct_all.csv to 1, but it still doesn't work.
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

Re: Card Development - talk about cards code here

Postby Aswan jaguar » 16 Jan 2023, 17:44

Add 13 which is for traps to cc2 flag in ct_all.csv.
---
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: Card Development - talk about cards code here

Postby drool66 » 16 Jan 2023, 18:10

Right, here is a somewhat outdated, but still useful reference to cc[2] values
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Riddleform not ending effect at EOT

Postby etphonehome » 16 Jan 2023, 18:49

It works fine if it me who activate effect, if it's AI, on it's turn, the effect only ends at the end of my turn and not at the end of AI turn.

Code: Select all
int card_riddleform(int player, int card, event_t event) {
   /* Riddleform   |1|U
    * Enchantment
    * Whenever you cast a noncreature spell, you may have ~ become a 3/3 Sphinx creature with flying in addition to its other types until end of turn.
    * |2|U: Scry 1. */

   if (trigger_condition == TRIGGER_SPELL_CAST && affect_me(player, card)) {
      test_definition_t test;
      default_test_definition(&test, TYPE_CREATURE);
      test.type_flag = DOESNT_MATCH;
      sp_ability_trigger(player, event, RESOLVE_TRIGGER_MANDATORY, 0, &test, player, card);
   }

   if (event == EVENT_SP_ABILITY) {
      int choice = 0;
      choice = do_dialog(player, player, card, -1, -1, " Animate Riddleform\n Pass", 0);
      if (choice == 0) {
         int legacy = turn_into_creature(player, card, player, card, 1, 3, 3);
         card_instance_t* instance = get_card_instance(player, legacy);
         instance->targets[8].player = KEYWORD_FLYING;
         instance->targets[9].player = instance->targets[9].player & 1;
         instance->targets[9].card = SUBTYPE_SPHINX;
      }
   }

   if (event == EVENT_RESOLVE_ACTIVATION) {
      scry(player, 1);
   }

   return generic_activated_ability(player, card, event, 0, MANACOST_XU(2, 1), 0, NULL, NULL);
}
Attachments
m21-64-riddleform.jpg
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

Re: Card Development - talk about cards code here

Postby Aswan jaguar » 16 Jan 2023, 19:05

When did AI cast the non-creature spell to trigger Riddleform? If AI did it in eot then correctly the effect lasts till your eot.
---
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: Card Development - talk about cards code here

Postby etphonehome » 16 Jan 2023, 19:54

OK!

I think it did. Although it was a bad play. It should have played Lightning Strike during first main and then attack with Riddleform.| [-X

That's why AI will never rule the world! :mrgreen:
Attachments
Captura de ecrã 2023-01-16 192029.jpg
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

fixed - Zombie Boa

Postby Aswan jaguar » 19 Jan 2023, 19:50

I have tried many 3 different ways to code Zombie Boa with no success. I can't find how to store correctly the chosen color to use it in function
for_each_creature_blocking_me() or mark_each_creature_blocking_me()

Code: Select all
static void destroy_creature_of_chosen_color_when_blocked(int player, int color, int blocking_controller, int blocking_card)
{
   
   int color = get_card_instance(player, card)->targets[3].card;
   if( get_color(blocking_controller, blocking_card) & color )
      kill_card(blocking_controller, blocking_card, KILL_DESTROY);
      
}

int card_zombie_boa(int player, int card, event_t event){// see death charmer and treefolk mystic, Hedron Blade,
   /* CARD_ID_ZOMBIE_BOA   5459 // in progress
   Zombie Boa   |4|B
   Creature - Zombie Snake 3/3
   |1|B: Choose a color. Whenever ~ becomes blocked by a creature of that color this turn, destroy that creature. Activate only as a sorcery. */

   if( IS_GAA_EVENT(event) ){
      if( event == EVENT_RESOLVE_ACTIVATION ){
         card_instance_t *instance = get_card_instance(player, card);
         instance->targets[3].card = 1<<choose_a_color_and_show_legacy(instance->parent_controller, instance->parent_card, 1-player, -1);
      }
   }

   if( event == EVENT_DECLARE_BLOCKERS && !is_humiliated(player, card, AL_TRIG) ){
      card_instance_t *instance = get_card_instance(player, card);
      //int col = instance->targets[3].card;
      if( current_turn == player && is_attacking(player, card) ){
         for_each_creature_blocking_me(player, instance->targets[3].card, destroy_creature_of_chosen_color_when_blocked, player, card);
      }
   }
   //kills all blocking
   /*if( event == EVENT_DECLARE_BLOCKERS && is_attacking(player, card) && current_turn == player && !is_humiliated(player, card, AL_TRIG) ){
      card_instance_t *instance = get_card_instance(player, card);
      int clr = instance->targets[3].card;
      char marked[2][151] = {{0}};
      mark_each_creature_blocking_me(player, card, marked);
      int c;
      for( c = 0; c < active_cards_count[1-current_turn]; ++c )
         if( marked[1-current_turn][c] && in_play(1-current_turn, c) && get_color(1-current_turn, c) & clr ){
            kill_card(1-current_turn, c, KILL_DESTROY);
         }
   }*/
   if( event == EVENT_CLEANUP )
      get_card_instance(player, card)->targets[3].card = 0;

   return generic_activated_ability(player, card, event, GAA_CAN_SORCERY_BE_PLAYED, MANACOST_XB(1,1), 0, NULL, NULL);
}
Last edited by Aswan jaguar on 20 Jan 2023, 15:39, edited 1 time in total.
Reason: fixed
---
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: Card Development - talk about cards code here

Postby drool66 » 19 Jan 2023, 23:05

Try this?
Code: Select all
static void destroy_creature_of_chosen_color_when_blocked(int color, int unused, int blocking_controller, int blocking_card)
{
   if( get_color(blocking_controller, blocking_card) & color )
      kill_card(blocking_controller, blocking_card, KILL_DESTROY);
}

int card_zombie_boa(int player, int card, event_t event){// see death charmer and treefolk mystic, Hedron Blade,
   /* CARD_ID_ZOMBIE_BOA   5459 // in progress
   Zombie Boa   |4|B
   Creature - Zombie Snake 3/3
   |1|B: Choose a color. Whenever ~ becomes blocked by a creature of that color this turn, destroy that creature. Activate only as a sorcery. */

   if( IS_GAA_EVENT(event) ){
      if( event == EVENT_RESOLVE_ACTIVATION ){
         DECL_INST();
       DECL_PARENT();
       int colors = inst_info(parent, CARD_ID_ZOMBIE_BOA).data | 1<<choose_a_color_and_show_legacy(inst->parent_controller, inst->parent_card, 1-player, -1);
         set_inst_info(parent, CARD_ID_ZOMBIE_BOA, colors, 0);
      }
   }

   if( event == EVENT_DECLARE_BLOCKERS && !is_humiliated(player, card, AL_TRIG) ){
      DECL_INST();
      //int col = instance->targets[3].card;
      if( current_turn == player && is_attacking(player, card) ){
         for_each_creature_blocking_me(player, card, destroy_creature_of_chosen_color_when_blocked, inst_info(inst, CARD_ID_ZOMBIE_BOA).data, 0);
      }
   }
   //kills all blocking
   /*if( event == EVENT_DECLARE_BLOCKERS && is_attacking(player, card) && current_turn == player && !is_humiliated(player, card, AL_TRIG) ){
      card_instance_t *instance = get_card_instance(player, card);
      int clr = instance->targets[3].card;
      char marked[2][151] = {{0}};
      mark_each_creature_blocking_me(player, card, marked);
      int c;
      for( c = 0; c < active_cards_count[1-current_turn]; ++c )
         if( marked[1-current_turn][c] && in_play(1-current_turn, c) && get_color(1-current_turn, c) & clr ){
            kill_card(1-current_turn, c, KILL_DESTROY);
         }
   }*/
   if( event == EVENT_CLEANUP )
      clear_info(get_card_instance(player, card), CARD_ID_ZOMBIE_BOA);

   return generic_activated_ability(player, card, event, GAA_CAN_SORCERY_BE_PLAYED, MANACOST_XB(1,1), 0, NULL, NULL);
}
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

Re: Card Development - talk about cards code here

Postby etphonehome » 01 Feb 2023, 00:15

Tried to code Silversmote Ghoul, but after gaining 7 life the trigger effect doesn't happen, Added 13 to CC[2] but it probably needs a 2 as it is a triggered ability in the graveyard.

Code: Select all
int card_silversmote_ghoul(int player, int card, event_t event) {
   /* CARD_ID_SILVERSMOTE_GHOUL   21668
   Silversmote Ghoul   |2|B
   Creature - Zombie Vampire 3/1
   At the beginning of your end step, if you gained 3 or more life this turn, return ~ from your graveyard to the battlefield tapped.
   |1|B, Sacrifice ~: Draw a card. */

      if (get_trap_condition(player, TRAP_LIFE_GAINED) > 4 && eot_trigger(player, card, event)){
      return GA_RETURN_TO_PLAY_MODIFIED;
      }

      if (event == EVENT_RETURN_TO_PLAY_FROM_GRAVE_MODIFIED) {
         add_state(player, card, STATE_TAPPED);
      }

      if (!IS_GAA_EVENT(event)) {
         return 0;
      }

      if (event == EVENT_RESOLVE_ACTIVATION) {
         draw_a_card(player);
      }

      return generic_activated_ability(player, card, event, GAA_SACRIFICE_ME, MANACOST_XB(1, 1), 0, NULL, NULL);
   }
Attachments
c21-154-silversmote-ghoul.jpg
etphonehome
 
Posts: 300
Joined: 21 May 2020, 12:50
Has thanked: 270 times
Been thanked: 39 times

Re: Card Development - talk about cards code here

Postby drool66 » 01 Feb 2023, 07:06

So you need to use two cc[2] values - 13 for the trap and 28 for the eot trigger from the grave. The way to do this is to special case the id in the rules engine. Go to rules_engine.c and search for "check_card_for_rules_engine" and add CARD_ID_SILVERSMOTE_GHOUL under either the cc[2] == 13 section, or the cc[2] == 28 section, then set the other cc[2] value to the card in ct_all. I recommend adding the id to the 13 section (so under CARD_ID_SWEET_GUM_RECLUSE), and giving the Silversmote Ghoul a cc[2] value of 28. I say do it that way because 13 already has several special cases and so far 28 has none.

Also, GAA_ means "Graveyard Activated Ability" and this is a triggered ability. The two work differently. You can track what happens in rules_engine.c::resolve_graveyard_eot_triggers(), but the gist is you'll have an invisible copy of the card in your hand, and you have the card put itself into play while responding to EVENT_GRAVEYARD_ABILITY_EOT. See jumpstart.c::card_lightning_phoenix() for how it works, but it'll look like this:
Code: Select all
   if( event == EVENT_GRAVEYARD_ABILITY_EOT ){
      if( get_trap_condition(player, TRAP_LIFE_GAINED) >= 5 ){
         if( ! grafdiggers_cages(player, TYPE_CREATURE, TUTOR_FROM_GRAVE) ){
            add_state(player, card, STATE_TAPPED);
            remove_state(player, card, STATE_INVISIBLE);
            put_into_play(player, card);
            return -1;
         }
      }
   }
Not sure right now why upkeep and eot triggers have their own functions outside of static_graveyard_abilities()
User avatar
drool66
Programmer
 
Posts: 1163
Joined: 25 Nov 2010, 22:38
Has thanked: 186 times
Been thanked: 267 times

PreviousNext

Return to Development

Who is online

Users browsing this forum: No registered users and 19 guests


Who is online

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

Login Form