It is currently 16 Apr 2024, 10:12
   
Text Size

Oracle of Mul Daya or Courser of Kruphix in the game?

MicroProse's Shandalar Campaign Game, now with new cards & a new look!

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

Oracle of Mul Daya or Courser of Kruphix in the game?

Postby doenerchef » 03 Jul 2018, 19:20

Does anyone know, if either Oracle of Mul Daya or Courser of Kruphix are in the game (i.e. in any version of the game that you are aware of)?
doenerchef
 
Posts: 75
Joined: 09 Dec 2011, 15:18
Has thanked: 10 times
Been thanked: 6 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby Korath » 06 Jul 2018, 03:30

They're not.
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby doenerchef » 09 Jul 2018, 08:33

Thank you! Are those cards where the game engine would have made it very hard to bring them into play or is it simply a case of "not yet"?
doenerchef
 
Posts: 75
Joined: 09 Dec 2011, 15:18
Has thanked: 10 times
Been thanked: 6 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby Korath » 09 Jul 2018, 20:56

It's mostly a matter of the interface. There's entirely too many steps to get this engine to do it right - to acknowledge clicks on the library at all, to interpret those clicks as an attempt to cast (whether at sorcery speed, when the stack is empty but not during the main phase, in response to something on the stack, and for the AI to do it in each of those three situations - it's done in a different place, in a slightly different way, for each of those six cases), and to add or remove the yellow border to the card when it becomes castable or no-longer-castable - and I didn't do a good enough job of documenting them all when I added it for cards in the graveyard and exile. Manalink sidesteps the problem by making it an activated ability of the Oracle or Courser or Future Sight or whatever, which sort of works most of the time but gets the corner cases wrong.

(For that matter, the graveyard/exile implementation is still badly incomplete; it only allows activation or playing cards in the graveyard or exile if it's an ability the card itself has, for the single special case of Crucible of Worlds / Ramunap Excavator, and for casting a single card during the resolution of another spell or ability. So nothing like Yawgmoth's Will or Haakon, Stromgald Scourge or Snapcaster Mage or Mind's Desire.)

In contrast, getting spells to actually be playable from the library isn't all that hard (even considering that you might cancel during targeting after paying the mana cost with something like Millikin, and there's no provision in this engine to "roll the game state back" as the rules require, nor any easy way to add such a provision). I actually did that recently, for Djinn of Wishes, Aetherworks Marvel, and seven other cards that do the casting during their resolutions, where the interface isn't at issue.
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby doenerchef » 16 Jul 2018, 18:31

Thank you for that thorough answer! I figured that was the reason and while reading your explanation the solution that Manalink uses also came to my mind, to make the "play the top card"-ability accessible via Oracle/Courser. But since those are significant cards, I figure if it was possible, you would already have added those.

Since we're talking about significant cards that aren't in the game, I assume it was the same reason (i.e. incompatibility with the interface) that Force of Will and Fireblast were never added?
doenerchef
 
Posts: 75
Joined: 09 Dec 2011, 15:18
Has thanked: 10 times
Been thanked: 6 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby Korath » 16 Jul 2018, 18:58

Nope. Cards in hand or on the stack are treated only a little differently from cards on the battlefield, so alternative casting costs are fairly easy. Activating abilities of cards in hands, such as cycling, is only a little more difficult than that, without even resorting to Manalink's workaround of activating a fake Rules Engine card on the battlefield instead. The only real problem here was working out a proper internal interface so activations and alternative/additional costs could be expressed concisely instead of in pages of boilerplate code. Force of Will (only) made it into the last public release, IIRC, by resorting to the boilerplate.
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby doenerchef » 16 Jul 2018, 19:36

Aw, cool! I have to look into that. Boilerplate is those big popups, like the one you get for Nettle Sentinel where you can click "Trigger" or "Decline"?
doenerchef
 
Posts: 75
Joined: 09 Dec 2011, 15:18
Has thanked: 10 times
Been thanked: 6 times

Re: Oracle of Mul Daya or Courser of Kruphix in the game?

Postby Korath » 16 Jul 2018, 20:39

Completely different. (Wikipedia article.) The idea is to have Force of Will's implementation itself only have to say "I can be cast for exiling a blue card and paying 1 life" and "counter target spell", instead of having it deal with the low-level mechanics of prompting for which card to exile, exiling it, making sure the player can pay life, suppressing the normal mana cost, disallowing the alternative payment if it's already being paid by a different alternative cost like Fist of Suns, etc.

As a concrete example, Manalink's implementation of Fireblast looks like:
Code: Select all
{
    if( event == EVENT_MODIFY_COST ){
        test_definition_t test;
        default_test_definition(&test, TYPE_LAND);
        test.subtype = SUBTYPE_MOUNTAIN;
        test.qty = 2;
        if( new_can_sacrifice_as_cost(player, card, &test) ){
            get_card_instance(player, card)->info_slot = 1;
            null_casting_cost(player, card);
        }
        else{
            get_card_instance(player, card)->info_slot = 0;
        }
    }

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

    target_definition_t td;
    default_target_definition(player, card, &td, TYPE_CREATURE );
    td.zone = TARGET_ZONE_CREATURE_OR_PLAYER;

    card_instance_t *instance = get_card_instance(player, card);

    if( event == EVENT_CAN_CAST ){
        return generic_spell(player, card, event, GS_CAN_TARGET, &td, NULL, 1, NULL);
    }

    if( event == EVENT_CAST_SPELL && affect_me(player, card) ){
        if( ! played_for_free(player, card) && ! is_token(player, card) && instance->info_slot == 1 ){
            int choice = 1;
            if( has_mana_to_cast_iid(player, event, get_card_instance(player, card)->internal_card_id) ){
                choice = DIALOG(player, card, event, DLG_RANDOM, DLG_NO_STORAGE,
                                "Sacrifice two mountains", 1, count_subtype(player, TYPE_LAND, -1) * 2,
                                "Cast normally", 1, 5);
                if( ! choice ){
                    spell_fizzled = 1;
                    return 0;
                }
            }

            if( choice == 1 ){
                test_definition_t test;
                new_default_test_definition(&test, TYPE_LAND, "Select a Mountain to sacrifice.");
                test.subtype = SUBTYPE_MOUNTAIN;    // not hacked; it's a cost, so there's no opportunity to cast Magical Hack

                int sacced[2] = {-1};
                int i;
                for(i=0; i<2; i++){
                    sacced[i] = new_sacrifice(player, card, player, SAC_JUST_MARK|SAC_AS_COST|SAC_RETURN_CHOICE, &test);
                    if( sacced[i] == -1 ){
                        spell_fizzled = 1;
                        break;
                    }
                }
                for(i=0; i<2; i++){
                    if( sacced[i] != -1 ){
                        state_untargettable(BYTE2(sacced[i]), BYTE3(sacced[i]), 0);
                        if( spell_fizzled != 1 ){
                            kill_card(BYTE2(sacced[i]), BYTE3(sacced[i]), KILL_SACRIFICE);
                        }
                    }
                }
                if( spell_fizzled == 1 ){
                    return 0;
                }
                td.allow_cancel = 0;
            }

            if( choice == 1 ){
                charge_mana_from_id(player, -1, event, get_id(player, card));
            }
        }
        return generic_spell(player, card, event, GS_CAN_TARGET, &td, "TARGET_CREATURE_OR_PLAYER", 1, NULL);
    }

    if( event == EVENT_RESOLVE_SPELL ){
        if( valid_target(&td) ){
            damage_target0(player, card, 4);
        }
        kill_card(player, card, KILL_DESTROY);
    }

    return 0;
}
Shandalar's is
Code: Select all
{
  if (ALTERNATIVE_COST_EVENT())
    return alternative_cost_sac(player, card, event, SELECT_LANDTYPE(player, SUBTYPE_MOUNTAIN), 2);

  return SPELL_TARGET_ANY(1-player,
                          deal_damage({player, card}, 4, inst->targets[0]));
}
The former's not so bad if there's only one card that lets you cast it by sacrificing stuff instead, and no chance of another ever being printed. But that's not the case, and so much of it gets copied and pasted over and over and over again into every card that needs it, and if there's something wrong, it only gets fixed in one of the cards that uses it.
User avatar
Korath
DEVELOPER
 
Posts: 3707
Joined: 02 Jun 2013, 05:57
Has thanked: 496 times
Been thanked: 1106 times


Return to Shandalar

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