Sorry - this may not be the right place to post this. My apologies in advance. I have your base code and was trying to add Mind Over Matter. For some reason, when I add this card, the very next turn the game tries to evaluate DiscardTarget(), even though I haven't even tried to place the ability on the stack. I have added 0 Effects, Costs or Modifiers to the game so I don't believe I have broken anything in that regard.
My Mind Over Matter Implementation:
namespace Grove.CardsLibrary
{
using System.Collections.Generic;
using Grove.Effects;
using Grove.AI.TimingRules;
using Grove.Costs;
using Grove.AI.TargetingRules;
public class MindOverMatter : CardTemplateSource
{
public override IEnumerable<CardTemplate> GetCards()
{
yield return Card
.Named("Mind Over Matter")
.ManaCost("{2}{U}{U}{U}{U}")
.Type("Enchantment")
.Text("Choose and discard a card: Tap or untap target artifact, creature, or land.")
.FlavorText("Lyna turned to the figure beside her.{EOL}\"They're gone. What now?\"{EOL}\"As ever,\" said Urza, \"we wait.\"")
.Cast(p => p.TimingRule(new OnSecondMain()))
.ActivatedAbility(p =>
{
p.Text = "Choose and discard a card: Tap target artifact, creature, or land.";
p.Cost = new DiscardTarget();
p.Effect = () => new TapTargets();
p.TargetSelector.AddCost(
trg => trg.Is.Card().In.OwnersHand(),
trg => trg.Message = "Select a card to discard.");
p.TargetSelector.AddEffect(
trg => trg.Is.Card(card => card.Is().Creature || card.Is().Land || card.Is().Artifact).On.Battlefield(),
trg => trg.Message = "Select a creature, land or artifact to tap.");
p.TimingRule(new OnStep(Step.BeginningOfCombat));
})
.ActivatedAbility(p =>
{
p.Text = "Choose and discard a card: Untap target artifact, creature, or land.";
p.Cost = new DiscardTarget();
p.Effect = () => new UntapTargetPermanents();
p.TargetSelector.AddCost(
trg => trg.Is.Card().In.OwnersHand(),
trg => trg.Message = "Select a card to discard.");
p.TargetSelector.AddEffect(
trg => trg.Is.Card(card => card.Is().Creature || card.Is().Land || card.Is().Artifact).On.Battlefield(),
trg => trg.Message = "Select a creature, land or artifact to untap.");
p.TimingRule(new Any(
new OnFirstMain(),
new AfterOpponentDeclaresAttackers()));
p.TargetingRule(new EffectUntapPermanent());
});
}
}
}
System.NullReferenceException: Object reference not set to an instance of an object.
at Grove.Costs.DiscardTarget.PayPartial(PayCostParameters p) in \grove-master\source\Grove\Core\Costs\DiscardTarget.cs:line 15 is the first raised error in the debug dump, which is also where the debugger points when running it through debug. It happens when evaluating void PayPartial (because card is never set, since I didn't activate the ability, and thus the cost was never selected. What I'm confused about is why PayPartial is even firing at the time, since I didn't activate the ability?
I built a test deck with Necromancer's Stockpile which also features a DiscardTarget cost (admittedly an Aggregate cost so not exactly apples to apples here) and that did not run into the same error, so clearly I'm doing something wrong. I do note further in the error dump, the message of: "Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Trying to modify a locked change tracker. This is a common indication of an incorrect object copy.". In your stack overflow question you link to from the readme in the project, you state how the engine needs a way to copy the game state for AI purposes, though if that is what is happening here and raising the exception, I'm again lost as to why.
I know this is a huge ask, and totally not your responsibility, but if possible, would you please let me know what I'm doing wrong here and why this might be happening? I'm hopeful that this is something that is glaringly obvious to you since you're intimately familiar with the card implementation. Thank you in advance for your time.
Full error dump here: error.txt