Re: Adding new cards with Groovy
Posted: 23 Sep 2014, 12:51
Agree, running untrusted code safely is tough. In that case, does it still make sense to merge the changeset in your repo for running card scripts?
High Quality Resources for Collectible Card Games and Home of the CCGHQ Team
https://www.slightlymagic.net/forum/
https://www.slightlymagic.net/forum/viewtopic.php?f=82&t=10323
name=Gorgon Recluse
image=http://mtgimage.com/card/gorgon%20recluse.jpg
value=2.500
rarity=C
type=Creature
subtype=Gorgon
cost={3}{B}{B}
pt=2/4
ability=Madness {B}{B}
timing=main
requires_groovy_code=Deathgazer
oracle=Whenever Gorgon Recluse blocks or becomes blocked by a nonblack creature, destroy that creature at end of combat. Madness {B}{B}
name=Siege Rhino
image=http://magiccards.info/scans/en/ktk/200.jpg
value=2.500
rarity=R
type=Creature
subtype=Rhino
cost={1}{W}{B}{G}
pt=4/5
ability=Trample; When SN enters the battlefield, each opponent loses 3 life and you gain 3 life.
timing=main
oracle=Trample. When Siege Rhino enters the battlefield, each opponent loses 3 life and you gain 3 life.
[
new MagicIfDamageWouldBeDealtTrigger(MagicTrigger.INCREASE_DAMAGE) {
@Override
public MagicEvent executeTrigger(final MagicGame game,final MagicPermanent permanent,final MagicDamage damage) {
final MagicSource source = damage.getSource();
if (damage.isCombat() && source.isCreature()) {
// Generates no event or action.
damage.setAmount(source.getCardDefinition().getCardToughness());
}
return MagicEvent.NONE;
}
}
]
I took this as an opportunity to explore the magarena source a little.someone can help me with this one? I don't see what I'm doing wrong...
if (power>0 && !attacker.hasState(MagicPermanentState.NoCombatDamage))
I took a quick glance myself after reading this, and also on line 61 the same check is done for blockers.mike wrote:
In MagicCombatDamageAction.java on line 74 I found thisWhich means a MagicDealDamageAction is never created and hence no MagicIfDamageWouldBeDealtTrigger will ever be invoked.
- Code: Select all
if (power>0 && !attacker.hasState(MagicPermanentState.NoCombatDamage))
If I might propose a solution for this: How about replacing power=attacker.getPower() with power=attacker.getCombatPower() which is by default getPower but may be overrwritten for cases like this? This is assuming that attacker.getPower may be overwritten from within the groovy script.
Adding getCombatPower and a MagicStatic to modify the combat power value is one possible way, but introduces additional complexity such as additional state in MagicPermanent for combat power which would have to be initialized and managed properly. What others cards would be enabled from such a feature besides Doran?119.8. If a source would deal 0 damage, it does not deal damage at all. That means abilities that trigger on damage being dealt won’t trigger. It also means that replacement effects that would increase the damage dealt by that source, or would have that source deal that damage to a different object or player, have no event to replace, so they have no effect.
I fear the answer is: "none". That's a shame, I really love Doran, but it doesn't make sense to add all this code for a single card.melvin wrote:The checks are there for rule 119.8Adding getCombatPower and a MagicStatic to modify the combat power value is one possible way, but introduces additional complexity such as additional state in MagicPermanent for combat power which would have to be initialized and managed properly. What others cards would be enabled from such a feature besides Doran?119.8. If a source would deal 0 damage, it does not deal damage at all. That means abilities that trigger on damage being dealt won’t trigger. It also means that replacement effects that would increase the damage dealt by that source, or would have that source deal that damage to a different object or player, have no event to replace, so they have no effect.
it does make sense if we want to achieve 100% playable cards in MtG. Just put it at lower priority.I fear the answer is: "none". That's a shame, I really love Doran, but it doesn't make sense to add all this code for a single card.
name=Gargantuan Gorilla
image=http://mtgimage.com/card/gargantuan%20gorilla.jpg
value=2.500
rarity=R
type=Creature
subtype=Ape
cost={4}{G}{G}{G}
pt=7/7
timing=main
requires_groovy_code
oracle=At the beginning of your upkeep, you may sacrifice a Forest. If you sacrifice a snow Forest this way, Gargantuan Gorilla gains trample until end of turn. If you don't sacrifice a Forest, sacrifice Gargantuan Gorilla and it deals 7 damage to you. {T}: Gargantuan Gorilla deals damage equal to its power to another target creature. That creature deals damage equal to its power to Gargantuan Gorilla.
def SAC_ACTION = {
final MagicGame game, final MagicEvent event ->
event.processTargetPermanent(game, {
game.doAction(new MagicSacrificeAction(it));
if (it.hasType(MagicType.Snow)) {
game.doAction(new MagicGainAbilityAction(event.getPermanent(),MagicAbility.Trample));
}
})
}
[
new MagicAtYourUpkeepTrigger() {
@Override
public MagicEvent executeTrigger(final MagicGame game,final MagicPermanent permanent,final MagicPlayer upkeepPlayer) {
return new MagicEvent(
permanent,
new MagicMayChoice("Sacrifice a Forest?"),
this,
"PN may\$ sacrifice a Forest. " +
"If PN sacrifices a snow Forest this way, SN gains trample until end of turn. " +
"If PN doesn't sacrifice a Forest, sacrifice SN and it deals 7 damage to you."
);
}
@Override
public void executeEvent(final MagicGame game, final MagicEvent event) {
final MagicPermanent SN = event.getPermanent();
final MagicPlayer PN = event.getPlayer();
final MagicEvent sac = new MagicEvent(
SN,
PN,
MagicTargetChoice.SACRIFICE_FOREST,
MagicSacrificeTargetPicker.create(),
SAC_ACTION,
"Choose a Forest to sacrifice\$."
);
if (event.isYes() && PN.controlsPermanent(MagicSubType.Forest)) {
game.addEvent(sac);
} else {
game.doAction(new MagicSacrificeAction(SN));
game.doAction(new MagicDealDamageAction(SN, PN, 7));
}
}
},
new MagicPermanentActivation(
new MagicActivationHints(MagicTiming.Removal),
"Damage"
) {
@Override
public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
return [
new MagicTapEvent(source)
];
}
@Override
public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
return new MagicEvent(
source,
MagicTargetChoice.NegOther("target creature", source),
new MagicDamageTargetPicker(source.getPower()),
this,
"SN deals damage equal to its power to another target creature. " +
"That creature deals damage equal to its power to SN."
);
}
@Override
public void executeEvent(final MagicGame game, final MagicEvent event) {
event.processTargetPermanent(game, {
game.doAction(new MagicDealDamageAction(
event.getPermanent(),
it,
event.getPermanent().getPower()
));
game.doAction(new MagicDealDamageAction(
it,
event.getPermanent(),
it.getPower()
));
});
}
}
]
[
new MagicPermanentActivation(
[MagicCondition.YOUR_UPKEEP_CONDITION, MagicCondition.NO_MORE_THAN_ONCE_CONDITION],
new MagicActivationHints(MagicTiming.Pump),
"Sacrifice"
) {
@Override
public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
return [new MagicSacrificePermanentEvent(source,MagicTargetChoice.SACRIFICE_CREATURE)];
}
@Override
public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
return new MagicEvent(
source,
payedCost.getTarget(),
this,
"Remove a -2/-2 counter from SN. " +
"If the sacrificed creature was a Thrull, put a +1/+0 counter on SN."
);
}
@Override
public void executeEvent(final MagicGame game, final MagicEvent event) {
final MagicPermanent sacrificed = event.getRefPermanent();
new MagicRemoveCounterEvent(
event.getPermanent(),
MagicCounterType.MinusTwo,
1
);
if (sacrificed.hasSubType(MagicSubType.Thrull)) {
game.doAction(new MagicChangeCountersAction(
event.getPermanent(),
MagicCounterType.PlusOnePlusZero,
1
));
}
}
}
]
@Override
public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
return [
new MagicSacrificePermanentEvent(source,MagicTargetChoice.SACRIFICE_CREATURE),
new MagicPlayAbilityEvent(source)
];
}