Card Development - talk about cards code here
Discuss Upcoming Releases, Coding New Cards, Etc.
PLEASE DO NOT REPORT BUGS HERE!
PLEASE DO NOT REPORT BUGS HERE!
Moderators: BAgate, drool66, Aswan jaguar, gmzombie, stassy, CCGHQ Admins
Re: Card Development - talk about cards code here
by Aswan jaguar » 24 Jun 2021, 07:32
Hipparion seems to have issue only with Blaze of Glory which is quite fine by me, I will submit the code. Thanks for the help drool66.
---
Trying to squash some bugs and playtesting.
Trying to squash some bugs and playtesting.
-
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
by Aswan jaguar » 06 Jul 2021, 14:06
I tried this but I can't do it, if you find some time please do it.drool66 wrote:From untap_phasing(), it looks like EVENT_PHASING won't be sent to Teferi's Curse because "player" is the player controlling it, and EVENT_PHASING is only sent to the cards of the player whose turn it is - so if played on another player's creature, it won't see Teferi's Curse at all. I'm pretty sure you'd have to special-case these cards into mirage.c::untap_phasing() and maybe even engine.c::untap_phase(). See how Shimmer is handled for reference - these would probably be less complicated than that card.
---
Trying to squash some bugs and playtesting.
Trying to squash some bugs and playtesting.
-
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
by drool66 » 09 Jul 2021, 23:53
I have a working concept for Kaervek's Torch. What it does is modify the cost of interrupts cast when the Torch is (card_on_stack_controller, card_on_stack), and indeed, any interrupts I can throw at it cost more. Question is can a card be targeted on the stack in Manalink when these conditions are not true?
Code is as follows:
Code is as follows:
- Code: Select all
int card_kaerveks_torch(int player, int card, event_t event){
/* CARD_ID_KAERVEKS_TORCH 2522 //remain impossible???
Kaervek's Torch |X|R
Sorcery
As long as ~ is on the stack, spells that target it cost |2 more to cast.
~ deals X damage to any target. */
if( ! IS_GS_EVENT(player, card, event) ){
return 0;
}
target_definition_t td;
default_target_definition(player, card, &td, TYPE_CREATURE|TARGET_TYPE_PLANESWALKER);
td.zone = TARGET_ZONE_CREATURE_OR_PLAYER;
card_instance_t* instance = get_card_instance(player, card);
if( event == EVENT_CAST_SPELL && affect_me(player, card) ){
int card_added = generate_reserved_token_by_id(player, CARD_ID_SPECIAL_EFFECT);
card_instance_t *inst = get_card_instance(player, card_added);
inst->targets[0].card = SE_MOD_SPELLS_TARGETING_ME;
inst->targets[1].player = player;
inst->targets[1].card = card;
inst->targets[2].card = 2;
put_into_play(player, card_added);
}
if( event == EVENT_RESOLVE_SPELL ){
if( valid_target(&td) ){
damage_target0(player, card, instance->info_slot);
}
kill_card(player, card, KILL_DESTROY);
}
return generic_spell(player, card, event, GS_CAN_TARGET | GS_X_SPELL, &td, "TARGET_ANY", 1, NULL);
}
- Code: Select all
if( event == EVENT_MODIFY_COST_GLOBAL ){
...
if( flags & SE_MOD_SPELLS_TARGETING_ME ){
if(card_on_stack_controller == instance->targets[1].player && card_on_stack == instance->targets[1].card && is_what(affected_card_controller, affected_card, TYPE_INTERRUPT))
COST_COLORLESS += instance->targets[2].card;
}
}
The latest images for Manalink will be here.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
-
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
by Korath » 11 Jul 2021, 23:15
Do the Manalink versions of Brutal Expulsion or Unsubstantiate or similar effects that bounce spells on the stack only let you target the most recently-cast one?
In any case, this'll tie your hands when you eventually let bog-standard Counterspell and Fork effects target any spell on the stack instead of the top one.
This also looks like it'll change the casting cost of any interrupt while this is on top of the stack, even if it doesn't target anything. Manalink doesn't yet have Counterflux (in overload mode), Summary Dismissal, Swift Silence, or Whirlwind Denial, but I'd expect they'd all be implemented as interrupts.
In any case, this'll tie your hands when you eventually let bog-standard Counterspell and Fork effects target any spell on the stack instead of the top one.
This also looks like it'll change the casting cost of any interrupt while this is on top of the stack, even if it doesn't target anything. Manalink doesn't yet have Counterflux (in overload mode), Summary Dismissal, Swift Silence, or Whirlwind Denial, but I'd expect they'd all be implemented as interrupts.
-
Korath - DEVELOPER
- Posts: 3707
- Joined: 02 Jun 2013, 05:57
- Has thanked: 496 times
- Been thanked: 1106 times
Brood of Cockroaches is fine see edit
by Aswan jaguar » 18 Aug 2021, 08:53
I tried a lot but can't make Brood of Cockroaches effect to work when Brood of Cockroaches is controlled by the opponent, it triggers with no effect at all if it triggers at opponent's turn and make owner lose life if it is it's owners turn but doesn't return to hand.
My current code:
My current code:
- Code: Select all
static int brood_of_cockroaches_legacy(int player, int card, event_t event){
if( eot_trigger(player, card, event) ){
//card_instance_t *instance = get_card_instance(player, card);
int owner, position;
if( find_in_owners_graveyard(player, card, &owner, &position) ){
lose_life(player, 1);
int iid = get_grave(owner)[position];
remove_card_from_grave(owner, position);
add_card_to_hand(owner, iid);
}
kill_card(player, card, KILL_EXILE);
}
return 0;
}
int card_brood_of_cockroaches(int player, int card, event_t event){
/* CARD_ID_BROOD_OF_COCKROACHES 2678
Brood of Cockroaches |1|B
Creature - Insect 1/1
When ~ is put into your graveyard from the battlefield, at the beginning of the next end step, you lose 1 life and return ~ to your hand. */
if( this_dies_trigger_for_owner(player, card, event, RESOLVE_TRIGGER_MANDATORY) ){
create_legacy_effect(player, card, &brood_of_cockroaches_legacy);
}
return 0;
}
Last edited by Aswan jaguar on 02 Sep 2021, 14:54, edited 1 time in total.
Reason: add edit
Reason: add edit
---
Trying to squash some bugs and playtesting.
Trying to squash some bugs and playtesting.
-
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
by drool66 » 20 Oct 2021, 16:59
I'm finally getting close to finishing my changes to auras. Before I commit & push, does anyone know what this code does? Right now it's in generic_aura_impl()
- Code: Select all
if( event == EVENT_LEAVES_PLAY_ABILITY &&
(instance->targets[0].card != -1 ||
(instance->damage_target_player != instance->targets[2].player && instance->damage_target_card != instance->targets[2].card))
){
instance->targets[2].player = instance->damage_target_player;
instance->targets[2].card = instance->damage_target_card;
}
The latest images for Manalink will be here.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
-
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
by Korath » 20 Oct 2021, 19:13
It's the metastasized remnants of an attempt to detect the aura having been attached to a different object, and disable all the things on the old object like removing abilities or subtypes or vigilance (!) that get permanently added or removed from cards as the game state changes instead of being continuously recalculated.
It might make more sense in a less-mangled form. git show 5363b395f:src/functions/functions.c starting at line 8015.
It might make more sense in a less-mangled form. git show 5363b395f:src/functions/functions.c starting at line 8015.
-
Korath - DEVELOPER
- Posts: 3707
- Joined: 02 Jun 2013, 05:57
- Has thanked: 496 times
- Been thanked: 1106 times
Re: Card Development - talk about cards code here
by drool66 » 21 Oct 2021, 00:10
Oh wow. Do you happen to know of anything else in the larger scope that would examine targets[2] in that context? I can't find anything.
On the bright side it looks like everything there recalcs continuously now that I've got subtypes to do so.
On the bright side it looks like everything there recalcs continuously now that I've got subtypes to do so.
The latest images for Manalink will be here.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
-
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
by Korath » 21 Oct 2021, 00:19
I haven't looked. It was first kept in the non-disably version of the function because there were auras around that were breaking because they looked for their attachment in targets[2] instead of damage_target_player/damage_target_card (or even targets[0], as was mostly the practice then). The similar case for equipment looking in targets[8] is still widespread and easily-greppable.
-
Korath - DEVELOPER
- Posts: 3707
- Joined: 02 Jun 2013, 05:57
- Has thanked: 496 times
- Been thanked: 1106 times
Re: Card Development - talk about cards code here
by Aswan jaguar » 02 Nov 2021, 16:06
Korath, do you know why when I check for deathtouch ability in EVENT_CHECK_ABILITIES AI takes it into account only when considering to block but not when attacking? AI doesn't do that with creatures that have deathtouch continually.
e.g for Narnam Cobra:
e.g for Narnam Cobra:
- Code: Select all
if( event == EVENT_CHECK_ABILITIES && affect_me(player, card) && generic_activated_ability(player, card, EVENT_CAN_ACTIVATE, 0, MANACOST_G(1), 0, NULL, NULL) ){
check_abilities_keywords |= SP_KEYWORD_DEATHTOUCH;
}
---
Trying to squash some bugs and playtesting.
Trying to squash some bugs and playtesting.
-
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
by Korath » 03 Nov 2021, 02:20
You're not telling the AI that {player,card} can get deathtouch. You're saying it can get regeneration. check_abilities_keywords is a keyword_t.
It won't help you for other sp_keyword_t's, but check_destroys_if_blocked() (evolved from the original ai for Thicket Basilisk, Cockatrice, Infernal Medusa, Abomination, and Battering Ram) is what lets the combat AI know that deathtouch kills cards dead despite insufficient power. get_abilities(...EVENT_ABILITIES...) sets DIFB_DESTROYS_UNPROTECTED to tell it deathtouch is present.
It won't help you for other sp_keyword_t's, but check_destroys_if_blocked() (evolved from the original ai for Thicket Basilisk, Cockatrice, Infernal Medusa, Abomination, and Battering Ram) is what lets the combat AI know that deathtouch kills cards dead despite insufficient power. get_abilities(...EVENT_ABILITIES...) sets DIFB_DESTROYS_UNPROTECTED to tell it deathtouch is present.
-
Korath - DEVELOPER
- Posts: 3707
- Joined: 02 Jun 2013, 05:57
- Has thanked: 496 times
- Been thanked: 1106 times
Re: Card Development - talk about cards code here
by drool66 » 26 Nov 2021, 23:39
I'm having a lot of trouble taking can_autotap() out of exe. I cannot get any autotapping behavior to change no matter what I do, including having can_autotap() return 0 unconditionally. What I've done is added:
can_autotap() is declared in manalink.h and looks like this:
patch_move_into_c.pl has added to it:
I did run into a problem in /src/patches/Manalink/patch.pm at line 100 - I changed "$filename's" to "$filename s"
Human autotapping still taps things like Academy Ruins at the same priority of something like Plateau. Did I miss something?
- Code: Select all
manalink.h::
#define QUERYING(val) (event == EVENT_QUERY && attacking_card == (val))
produce_mana.c::
int plain_mana_producer(int player, int card, event_t event){
if( QUERYING(QUERY_IS_PLAIN_MANA_PRODUCER) )
return 1;
return mana_producer(player, card, event);
}
can_autotap() is declared in manalink.h and looks like this:
- Code: Select all
int can_autotap(int player, int card, autotap_t autotap_flags){
// 0x42fda0
card_instance_t* inst = in_play(player, card);
if( !inst )
return 0;
iid_t iid = inst->internal_card_id;
color_test_t colors = (inst->card_color & (COLOR_TEST_ANY | COLOR_TEST_ARTIFACT));
if( is_what(player, card, TYPE_LAND) )
colors |= mana_colors_added[player];
if ( !(colors & COLOR_TEST_ANY)
|| !((cards_data[iid].extra_ability & EA_MANA_SOURCE) || (is_what(player, card, TYPE_LAND) && (mana_colors_added[player] & COLOR_TEST_ANY)))
|| cards_data[iid].extra_ability & EA_PAID_MANASOURCE
|| !can_produce_mana(player, card) )
return 0;
if ( (autotap_flags & AUTOTAP_NO_BASIC_LANDS) && (is_basic_land(player, card) || query(player, card, -1, QUERY_IS_PLAIN_MANA_PRODUCER)) )
return 0;
if ( (autotap_flags & AUTOTAP_NO_NONBASIC_LANDS) && is_what(player, card, TYPE_LAND) && !is_basic_land(player, card) && !query(player, card, -1, QUERY_IS_PLAIN_MANA_PRODUCER) )
return 0;
if ( (autotap_flags & AUTOTAP_NO_DONT_AUTO_TAP) && (inst->state & STATE_NO_AUTO_TAPPING) )
return 0;
if ( (autotap_flags & AUTOTAP_NO_ARTIFACTS) && (is_what(player, card, TYPE_ARTIFACT) && !query(player, card, -1, QUERY_IS_PLAIN_MANA_PRODUCER)) )
return 0;
if ( (autotap_flags & AUTOTAP_NO_CREATURES) && (is_what(player, card, TYPE_CREATURE) && !query(player, card, -1, QUERY_IS_PLAIN_MANA_PRODUCER)) )
return 0;
return 1;
}
patch_move_into_c.pl has added to it:
- Code: Select all
###############
# can_autotap #
###############
#42fda0: 55 push ebp
#42fda1: 8b ec mov ebp,esp
#42fda3: 83 ec 0c sub esp,0c
jmp_to(0x42fda0 => 0x2007884);
I did run into a problem in /src/patches/Manalink/patch.pm at line 100 - I changed "$filename's" to "$filename s"
Human autotapping still taps things like Academy Ruins at the same priority of something like Plateau. Did I miss something?
The latest images for Manalink will be here.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
-
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
by Korath » 26 Nov 2021, 23:53
Are you executing "make data" in between patching and running? If so, it'll restore magic.exe from HEAD. I generally make an extra commit immediately after running the perl patch to deal with that, then squash before pushing.
Try checking that the Magic.exe in the directory you're running the game from to be sure your changes are sticking.
It's also a good practice to do a full disassembly before and after patching (the same objdump arguments as above, except omit --start-address and --stop-address), then diff the results, to be sure you didn't change anything else. In particular, I pushed a commit a few hours ago that patches out the last usage of mana_to_untap[] and mana_upkeep[], and things will break very badly if that patch is accidentally undone and we start reusing that data.
Edit after a reread:
Try checking that the Magic.exe in the directory you're running the game from to be sure your changes are sticking.
- Code: Select all
objdump -M intel -d Magic.exe --start-address=0x42fda0 --stop-address=0x42fdff
It's also a good practice to do a full disassembly before and after patching (the same objdump arguments as above, except omit --start-address and --stop-address), then diff the results, to be sure you didn't change anything else. In particular, I pushed a commit a few hours ago that patches out the last usage of mana_to_untap[] and mana_upkeep[], and things will break very badly if that patch is accidentally undone and we start reusing that data.
Edit after a reread:
This will definitely be a problem if you're using make data, or the Makefile in magic_updater/ at all, to build data files - the first thing it does is "cp ../Magic.exe .".drool66 wrote:and then moved magic.exe (which had a new filestamp) from /src/patches to /magic_updater and built as normal
-
Korath - DEVELOPER
- Posts: 3707
- Joined: 02 Jun 2013, 05:57
- Has thanked: 496 times
- Been thanked: 1106 times
Re: Card Development - talk about cards code here
by drool66 » 27 Nov 2021, 01:57
I had no idea, I'm glad I asked. Thank you, everything is working. I also forgot about doing the diff, so thanks also for the reminder.
The latest images for Manalink will be here.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
The latest Manalink installation directory will be here. Well, not quite, anymore. Check the latest patches.
-
drool66 - Programmer
- Posts: 1163
- Joined: 25 Nov 2010, 22:38
- Has thanked: 186 times
- Been thanked: 267 times
[DONE]Scrying Glass
by Aswan jaguar » 06 Mar 2022, 13:43
I am trying to do this very bad card Scrying Glass and after several tries I can't find how to make the chosen number be taken into account only the chosen color is taken into account when the activated ability resolves.
- Code: Select all
int card_scrying_glass(int player, int card, event_t event){ // remain
/* CARD_ID_SCRYING_GLASS 4189
Scrying Glass |2
Artifact
|3, |T: Choose a number greater than 0 and a color. Target opponent reveals their hand.
If that opponent reveals exactly the chosen number of cards of the chosen color, you draw a card. */
if( ! IS_GAA_EVENT(event) ){
return 0;
}
target_definition_t td;
default_target_definition(player, card, &td, 0);
td.zone = TARGET_ZONE_PLAYERS;
card_instance_t *instance = get_card_instance( player, card );
if( event == EVENT_RESOLVE_ACTIVATION ){
if( valid_target(&td) ){
int result = 0;
if( player == HUMAN ){
while( result == 0 ){
result = choose_a_number(player, "Choose a number greater than 0.", hand_count[1-player]);
if( result < 1 ){
result = 0;
}
}
}
int color_res = 1<<choose_a_color(player, get_deck_color(player, 1-player));
if( player == IS_AI(player) ){
result = recorded_rand(player, hand_count[1-player]) + 1;
}
reveal_target_player_hand(instance->targets[0].player);
test_definition_t this_test;
default_test_definition(&this_test, TYPE_ANY);
this_test.color = color_res;
this_test.qty = result;
this_test.zone = TARGET_ZONE_HAND;
if( check_battlefield_for_special_card(player, card, player, 0, &this_test) ){
draw_cards(player, 1);
}
}
}
return generic_activated_ability(player, card, event, GAA_UNTAPPED | GAA_CAN_ONLY_TARGET_OPPONENT, MANACOST_X(3), 0, &td, NULL);
}
Last edited by Aswan jaguar on 10 Mar 2022, 14:04, edited 1 time in total.
Reason: retitle
Reason: retitle
---
Trying to squash some bugs and playtesting.
Trying to squash some bugs and playtesting.
-
Aswan jaguar - Super Tester Elite
- Posts: 8078
- Joined: 13 May 2010, 12:17
- Has thanked: 730 times
- Been thanked: 458 times
Who is online
Users browsing this forum: No registered users and 35 guests