Merge pull request #5527 from magefree/coinFlips

Fixing coin flip implementation (WIP - Do Not Merge)
This commit is contained in:
Evan Kranzler 2019-01-16 11:44:01 -05:00 committed by GitHub
commit 63fb5964d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 275 additions and 161 deletions

View file

@ -67,7 +67,7 @@ class AleatoryEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source);
return true;
}

View file

@ -61,7 +61,7 @@ class BottleOfSuleimanEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player you = game.getPlayer(source.getControllerId());
if (you != null) {
if (you.flipCoin(game)) {
if (you.flipCoin(source, game, true)) {
DjinnToken token = new DjinnToken();
token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId());
return true;

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -16,27 +15,29 @@ import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.CoinFlippedEvent;
import mage.game.events.GameEvent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class ChanceEncounter extends CardImpl {
public ChanceEncounter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}");
// Whenever you win a coin flip, put a luck counter on Chance Encounter.
this.addAbility(new ChanceEncounterTriggeredAbility());
// At the beginning of your upkeep, if Chance Encounter has ten or more luck counters on it, you win the game.
TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new WinGameSourceControllerEffect(), TargetController.YOU, false);
TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new WinGameSourceControllerEffect(), TargetController.YOU, false);
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceHasCounterCondition(CounterType.LUCK, 10, Integer.MAX_VALUE),
"At the beginning of your upkeep, if {this} has ten or more luck counters on it, you win the game"));
}
public ChanceEncounter(final ChanceEncounter card) {
private ChanceEncounter(final ChanceEncounter card) {
super(card);
}
@ -47,30 +48,33 @@ public final class ChanceEncounter extends CardImpl {
}
class ChanceEncounterTriggeredAbility extends TriggeredAbilityImpl {
public ChanceEncounterTriggeredAbility() {
ChanceEncounterTriggeredAbility() {
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.LUCK.createInstance()), false);
}
public ChanceEncounterTriggeredAbility(final ChanceEncounterTriggeredAbility ability) {
private ChanceEncounterTriggeredAbility(final ChanceEncounterTriggeredAbility ability) {
super(ability);
}
@Override
public ChanceEncounterTriggeredAbility copy() {
return new ChanceEncounterTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.COIN_FLIPPED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return this.isControlledBy(event.getPlayerId()) && event.getFlag();
CoinFlippedEvent flipEvent = (CoinFlippedEvent) event;
return flipEvent.getPlayerId().equals(controllerId)
&& flipEvent.isWinnable()
&& (flipEvent.getChosen() == flipEvent.getResult());
}
@Override
public String getRule() {
return "Whenever you win a coin flip, " + super.getRule();

View file

@ -67,7 +67,7 @@ class ChaoticGooEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.informPlayers("Chaotic Goo: Won flip. Put a +1/+1 counter on Chaotic Goo.");
new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)).apply(game, source);
return true;

View file

@ -65,7 +65,7 @@ class ChaoticStrikeEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source);
return true;
}

View file

@ -66,7 +66,7 @@ class CrazedFirecatEffect extends OneShotEffect {
Permanent sourceObject = game.getPermanent(source.getSourceId());
if (controller != null && sourceObject != null) {
int flipsWon = 0;
while (controller.flipCoin(game)) {
while (controller.flipCoin(source, game, true)) {
flipsWon++;
}
sourceObject.addCounters(CounterType.P1P1.createInstance(flipsWon), source, game);

View file

@ -100,7 +100,7 @@ class CreepyDollEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (player.flipCoin(game)) {
if (player.flipCoin(source, game, true)) {
UUID targetId = getTargetPointer().getFirst(game, source);
Permanent permanent = game.getPermanent(targetId);
if (permanent != null) {

View file

@ -72,7 +72,7 @@ class CrookedScalesEffect extends OneShotEffect {
Cost cost;
String message = "You lost the flip. Pay {3} to prevent your creature from being destroyed?";
do {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
if (theirGuy != null) {
theirGuy.destroy(controller.getId(), game, false);
}

View file

@ -8,7 +8,6 @@ import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.PreventDamageBySourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -21,7 +20,6 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.StackObject;
import mage.filter.FilterObject;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.players.Player;
import mage.target.TargetSource;
import mage.util.CardUtil;
@ -70,7 +68,7 @@ class DesperateGambitEffect extends PreventionEffectImpl {
this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game);
Player you = game.getPlayer(source.getControllerId());
if(you != null) {
wonFlip = you.flipCoin(game);
wonFlip = you.flipCoin(source, game, true);
super.init(source, game);
}
}

View file

@ -71,7 +71,7 @@ class FickleEfreetChangeControlEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (controller != null) {
if (!controller.flipCoin(game)) {
if (!controller.flipCoin(source, game, true)) {
if (sourcePermanent != null) {
Target target = new TargetOpponent(true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {

View file

@ -64,7 +64,7 @@ class FieryGambitEffect extends OneShotEffect {
if (controller != null && sourceObject != null) {
int flipsWon = 0;
boolean controllerStopped = false;
while (controller.flipCoin(game)) {
while (controller.flipCoin(source, game, true)) {
++flipsWon;
if (!controller.chooseUse(outcome, "You won " + flipsWon + (flipsWon == 1 ? " flip." : " flips.") +
" Flip another coin?", source, game)) {

View file

@ -61,7 +61,7 @@ class FightingChanceEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
for (UUID blocker : game.getCombat().getBlockers()) {
if (player.flipCoin(game)) {
if (player.flipCoin(source, game, true)) {
PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true);
effect.setTargetPointer(new FixedTarget(blocker));
game.addEffect(effect, source);

View file

@ -59,7 +59,7 @@ class FlockOfRabidSheepEffect extends OneShotEffect {
int repeat = source.getManaCostsToPay().getX();
int wonCount = 0;
for (int i = 1; i <= repeat; i++) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
wonCount++;
}
}

View file

@ -69,7 +69,7 @@ class FreneticEfreetEffect extends OneShotEffect {
if (controller == null) {
return false;
}
boolean flip = controller.flipCoin(game);
boolean flip = controller.flipCoin(source, game, true);
if (permanent == null) {
return false;
}

View file

@ -76,7 +76,7 @@ class FreneticSliverEffect extends OneShotEffect {
if (player == null || perm == null) {
return false;
}
if (player.flipCoin(game)) {
if (player.flipCoin(source, game, true)) {
return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true).apply(game, source);
} else {
return perm.sacrifice(source.getSourceId(), game);

View file

@ -63,7 +63,7 @@ class GameOfChaosEffect extends OneShotEffect {
if (you != null && targetOpponent != null) {
boolean continueFlipping = true;
boolean youWonFlip = you.flipCoin(game); // controller flips first
boolean youWonFlip = you.flipCoin(source, game, true); // controller flips first
boolean youWonLastFlip = false; // tracks if you won the flip last, negation of it means opponent won last
int lifeAmount = 1; // starts stakes with 1 life
@ -88,7 +88,7 @@ class GameOfChaosEffect extends OneShotEffect {
if (continueFlipping) {
lifeAmount *= 2; // double the life each time
youWonFlip = youWonLastFlip ? you.flipCoin(game) : !targetOpponent.flipCoin(game); // negate the opponent's results for proper evaluation of if you won in next iteration
youWonFlip = youWonLastFlip ? you.flipCoin(source, game, true) : !targetOpponent.flipCoin(source, game, true); // negate the opponent's results for proper evaluation of if you won in next iteration
}
}

View file

@ -75,7 +75,7 @@ class GoblinArchaeologistEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (player != null && permanent != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
permanent.sacrifice(source.getSourceId(), game);
}else{
Permanent targetArtifact = game.getPermanent(source.getFirstTarget());

View file

@ -78,7 +78,7 @@ class GoblinArtisansEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
controller.drawCards(1, game);
} else {
List<Permanent> artifacts = game.getBattlefield().getActivePermanents(new FilterControlledArtifactPermanent(), source.getControllerId(), game);

View file

@ -99,7 +99,7 @@ class GoblinAssassinTriggeredEffect extends OneShotEffect {
if (controller != null) {
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null && !player.flipCoin(game)) {
if (player != null && !player.flipCoin(source, game, false)) {
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent();
target.setNotTarget(true);
if (target.canChoose(player.getId(), game)) {

View file

@ -63,7 +63,7 @@ class GoblinBangchuckersEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
permanent.damage(2, source.getSourceId(), game, false, true);

View file

@ -72,7 +72,7 @@ class GoblinBombEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.informPlayers("Goblin Bomb: Won flip. Put a fuse counter on Goblin Bomb.");
new AddCountersSourceEffect(CounterType.FUSE.createInstance(1)).apply(game, source);
return true;

View file

@ -68,7 +68,7 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (controller != null) {
if (!controller.flipCoin(game)) {
if (!controller.flipCoin(source, game, true)) {
if (sourcePermanent != null) {
Target target = new TargetOpponent(true);
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {

View file

@ -70,7 +70,7 @@ class GoblinKaboomistFlipCoinEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (player != null && permanent != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
String message = permanent.getLogName() + " deals 2 damage to itself";
game.informPlayers(message);
permanent.damage(2, source.getSourceId(), game, false, true);

View file

@ -69,7 +69,7 @@ class GoblinKitesEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
return true;
} else {
new SacrificeSourceEffect().apply(game, source);

View file

@ -65,7 +65,7 @@ class GoblinLyreEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Player opponent = game.getPlayerOrPlaneswalkerController(getTargetPointer().getFirst(game, source));
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
int damage = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()).calculate(game, source, this);
if (opponent != null) {
return game.damagePlayerOrPlaneswalker(source.getFirstTarget(), damage, source.getSourceId(), game, false, true) > 0;

View file

@ -60,7 +60,7 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game);
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true);
super.init(source, game);
}

View file

@ -6,8 +6,6 @@ import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAllTriggeredAbility;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.PreventDamageBySourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -16,9 +14,7 @@ import mage.constants.SetTargetPointer;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.filter.StaticFilters;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.players.Player;
import mage.util.CardUtil;
@ -61,7 +57,7 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game);
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true);
super.init(source, game);
}

View file

@ -15,6 +15,7 @@ import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.CoinFlippedEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.Target;
@ -56,30 +57,6 @@ public final class KarplusanMinotaur extends CardImpl {
}
}
enum KarplusanMinotaurAdjuster implements TargetAdjuster {
instance;
@Override
public void adjustTargets(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) {
return;
}
UUID opponentId = null;
if (game.getOpponents(controller.getId()).size() > 1) {
Target target = new TargetOpponent(true);
if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) {
opponentId = target.getFirstTarget();
}
} else {
opponentId = game.getOpponents(controller.getId()).iterator().next();
}
if (opponentId != null) {
ability.getTargets().get(0).setTargetController(opponentId);
}
}
}
class KarplusanMinotaurFlipWinTriggeredAbility extends TriggeredAbilityImpl {
public KarplusanMinotaurFlipWinTriggeredAbility() {
@ -103,7 +80,10 @@ class KarplusanMinotaurFlipWinTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return this.isControlledBy(event.getPlayerId()) && event.getFlag();
CoinFlippedEvent flipEvent = (CoinFlippedEvent) event;
return flipEvent.getPlayerId().equals(controllerId)
&& flipEvent.isWinnable()
&& (flipEvent.getChosen() == flipEvent.getResult());
}
@Override
@ -136,7 +116,10 @@ class KarplusanMinotaurFlipLoseTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return this.isControlledBy(event.getPlayerId()) && !event.getFlag();
CoinFlippedEvent flipEvent = (CoinFlippedEvent) event;
return flipEvent.getPlayerId().equals(controllerId)
&& flipEvent.isWinnable()
&& (flipEvent.getChosen() != flipEvent.getResult());
}
@Override
@ -155,7 +138,7 @@ class KarplusanMinotaurCost extends CostImpl {
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
if (controller != null) {
controller.flipCoin(game);
controller.flipCoin(ability, game, true);
this.paid = true;
return true;
}
@ -178,3 +161,27 @@ class KarplusanMinotaurCost extends CostImpl {
return new KarplusanMinotaurCost();
}
}
enum KarplusanMinotaurAdjuster implements TargetAdjuster {
instance;
@Override
public void adjustTargets(Ability ability, Game game) {
Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) {
return;
}
UUID opponentId = null;
if (game.getOpponents(controller.getId()).size() > 1) {
Target target = new TargetOpponent(true);
if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) {
opponentId = target.getFirstTarget();
}
} else {
opponentId = game.getOpponents(controller.getId()).iterator().next();
}
if (opponentId != null) {
ability.getTargets().get(0).setTargetController(opponentId);
}
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.k;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
@ -9,25 +8,28 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.FlipCoinEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.util.CardUtil;
import mage.util.RandomUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class KrarksThumb extends CardImpl {
public KrarksThumb(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
addSuperType(SuperType.LEGENDARY);
// If you would flip a coin, instead flip two coins and ignore one.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KrarksThumbEffect()));
}
public KrarksThumb(final KrarksThumb card) {
private KrarksThumb(final KrarksThumb card) {
super(card);
}
@ -44,26 +46,30 @@ class KrarksThumbEffect extends ReplacementEffectImpl {
staticText = "If you would flip a coin, instead flip two coins and ignore one";
}
KrarksThumbEffect(final KrarksThumbEffect effect) {
private KrarksThumbEffect(final KrarksThumbEffect effect) {
super(effect);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null) {
// because second flip is ignored it may not be done by the player method
boolean secondCoinFlip = RandomUtil.nextBoolean();
if (!game.isSimulation()) {
game.informPlayers("[Flip a coin] " + player.getLogName() + (secondCoinFlip ? " won (head)." : " lost (tail)."));
}
if (player.chooseUse(outcome, "Ignore the first coin flip?", source, game)) {
event.setFlag(secondCoinFlip);
game.informPlayers(player.getLogName() + " ignores the first coin flip.");
} else {
game.informPlayers(player.getLogName() + " ignores the second coin flip.");
}
if (player == null || !player.getId().equals(source.getControllerId())) {
return false;
}
FlipCoinEvent flipEvent = (FlipCoinEvent) event;
boolean secondFlip = RandomUtil.nextBoolean();
game.informPlayers(player.getLogName() + " flipped a " + flipEvent.getResultName()
+ " and a " + CardUtil.booleanToFlipName(secondFlip)
);
boolean chosenFlip = player.chooseUse(
Outcome.Benefit, "Choose which coin you want",
"(You chose " + flipEvent.getChosenName() + ")",
flipEvent.getResultName(), CardUtil.booleanToFlipName(secondFlip), source, game
);
if (!chosenFlip) {
flipEvent.setResult(secondFlip);
}
game.informPlayers(player.getLogName() + " chooses to keep " + flipEvent.getResultName());
return false;
}

View file

@ -62,8 +62,8 @@ class ManaClashEffect extends OneShotEffect {
if (!targetOpponent.canRespond() || !controller.canRespond()) {
return false;
}
boolean controllerFlip = controller.flipCoin(game);
boolean opponentFlip = targetOpponent.flipCoin(game);
boolean controllerFlip = controller.flipCoin(source, game, false);
boolean opponentFlip = targetOpponent.flipCoin(source, game, false);
if (controllerFlip && opponentFlip) {
bothHeads = true;
}

View file

@ -58,7 +58,7 @@ class ManaCryptEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
player.damage(3, source.getSourceId(), game, false, true);
}
return true;

View file

@ -88,7 +88,7 @@ class ManaScrewEffect extends BasicManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null && player.flipCoin(game)) {
if (player != null && player.flipCoin(source, game, true)) {
player.getManaPool().addMana(getMana(game, source), game, source);
}
return true;

View file

@ -57,7 +57,7 @@ class MijaeDjinnEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent creature = game.getPermanent(source.getSourceId());
if (controller != null && creature != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
return true;
} else {
creature.removeFromCombat(game);

View file

@ -77,7 +77,7 @@ class MirrorMarchEffect extends OneShotEffect {
int counter = 0;
boolean wonFlip = false;
do {
wonFlip = player.flipCoin(game);
wonFlip = player.flipCoin(source, game, true);
if (wonFlip) {
counter++;
}

View file

@ -110,7 +110,7 @@ class MoggAssassinEffect extends OneShotEffect {
}
Permanent chosenPermanent = game.getPermanent(source.getTargets().get(0).getFirstTarget());
Permanent opponentsPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
if (chosenPermanent != null) {
chosenPermanent.destroy(source.getSourceId(), game, false);
return true;

View file

@ -59,7 +59,7 @@ class MoltenBirthEffect extends OneShotEffect {
if (controller != null) {
MoltenBirthElementalToken token = new MoltenBirthElementalToken();
token.putOntoBattlefield(2, game, source.getSourceId(), source.getControllerId());
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
Card molten = game.getCard(source.getSourceId());
if (molten != null) {
molten.moveToZone(Zone.HAND, source.getSourceId(), game, true);

View file

@ -64,7 +64,7 @@ class MoltenSentryEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanentEntering(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, false)) {
game.informPlayers("Heads: " + permanent.getLogName() + " enters the battlefield as a 5/2 creature with haste");
permanent.getPower().modifyBaseValue(5);
permanent.getToughness().modifyBaseValue(2);

View file

@ -65,7 +65,7 @@ class OddsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, false)) {
game.informPlayers("Odds: Spell countered");
return game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game);

View file

@ -1,7 +1,6 @@
package mage.cards.o;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
import mage.abilities.common.WinsCoinFlipTriggeredAbility;
@ -13,18 +12,18 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.constants.*;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class OkaunEyeOfChaos extends CardImpl {
private static final DynamicValue sourcePower = new SourcePermanentPowerCount();
private static final DynamicValue sourceToughness = new SourcePermanentToughnessValue();
public OkaunEyeOfChaos(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
@ -41,8 +40,6 @@ public final class OkaunEyeOfChaos extends CardImpl {
this.addAbility(new BeginningOfCombatTriggeredAbility(new FlipUntilLoseEffect(), TargetController.YOU, false));
// Whenever a player wins a coin flip, double Okaun's power and toughness until end of turn.
DynamicValue sourcePower = new SourcePermanentPowerCount();
DynamicValue sourceToughness = new SourcePermanentToughnessValue();
this.addAbility(new WinsCoinFlipTriggeredAbility(
new BoostSourceEffect(
sourcePower,

View file

@ -69,7 +69,7 @@ class OrcishCaptainEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.informPlayers("Orcish Captain: Won flip. Target Orc creature gets +2/+0 until end of turn.");
game.addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn), source);
return true;

View file

@ -61,7 +61,7 @@ class PlanarChaosUpkeepEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
Permanent perm = game.getPermanent(source.getSourceId());
if (perm != null) {
perm.sacrifice(source.getSourceId(), game);
@ -104,7 +104,7 @@ class PlanarChaosCastAllEffect extends OneShotEffect {
if (sourceObject != null && spell != null) {
Player caster = game.getPlayer(spell.getControllerId());
if (caster != null) {
if (!caster.flipCoin(game)) {
if (!caster.flipCoin(source, game, true)) {
game.informPlayers(sourceObject.getLogName() + ": " + spell.getLogName() + " countered");
game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game);
}

View file

@ -54,7 +54,7 @@ class PuppetsVerdictEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
FilterCreaturePermanent filterPower2OrLess = new FilterCreaturePermanent("all creatures power 2 or less");
filterPower2OrLess.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3));

View file

@ -80,7 +80,7 @@ class RakdosTheShowstopperEffect extends OneShotEffect {
&& !permanent.hasSubtype(SubType.DEMON, game)
&& !permanent.hasSubtype(SubType.DEVIL, game)
&& !permanent.hasSubtype(SubType.IMP, game)
&& !player.flipCoin(game)) {
&& !player.flipCoin(source, game, false)) {
permanent.destroy(source.getSourceId(), game, false);
}
}

View file

@ -99,7 +99,7 @@ class RalZarekExtraTurnsEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (int i = 0; i < 5; i++) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, false)) {
game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false));
}
}

View file

@ -162,7 +162,7 @@ class RiskyMoveFlipCoinEffect extends OneShotEffect {
}
Permanent permanent = game.getPermanent(target1.getFirstTarget());
Player chosenOpponent = game.getPlayer(target2.getFirstTarget());
if (!controller.flipCoin(game)) {
if (!controller.flipCoin(source, game, true)) {
if (permanent != null && chosenOpponent != null) {
ContinuousEffect effect = new RiskyMoveCreatureGainControlEffect(Duration.Custom, chosenOpponent.getId());
effect.setTargetPointer(new FixedTarget(permanent.getId()));

View file

@ -88,7 +88,7 @@ class SabaccGameEffect extends OneShotEffect {
if (target.chooseTarget(outcome, opponent.getId(), source, game)) {
chosenPermanent = game.getPermanent(target.getFirstTarget());
}
boolean flipWin = controller.flipCoin(game);
boolean flipWin = controller.flipCoin(source, game, true);
if (flipWin) {
ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true, controller.getId());
effect.setTargetPointer(new FixedTarget(targetPermanent, game));

View file

@ -60,7 +60,7 @@ class ScoriaWurmEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
return true;
} else {
new ReturnToHandSourceEffect().apply(game, source);

View file

@ -63,7 +63,7 @@ class SkittishValeskEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null && !controller.flipCoin(game)) {
if (controller != null && permanent != null && !controller.flipCoin(source, game, true)) {
return permanent.turnFaceDown(game, source.getControllerId());
}
return false;

View file

@ -70,7 +70,7 @@ class SkyclawThrashEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (controller.flipCoin(game) && sourcePermanent != null) {
if (controller.flipCoin(source, game, true) && sourcePermanent != null) {
ContinuousEffect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);

View file

@ -56,7 +56,7 @@ class SqueesRevengeEffect extends OneShotEffect {
int number = player.announceXMana(0, Integer.MAX_VALUE, "Choose how many times to flip a coin", game, source);
game.informPlayers(player.getLogName() + " chooses " + number + '.');
for(int i = 0; i < number; i++) {
if(!player.flipCoin(game)) {
if(!player.flipCoin(source, game, true)) {
return true;
}
}

View file

@ -52,7 +52,7 @@ class StitchInTimeEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (player.flipCoin(game)) {
if (player.flipCoin(source, game, true)) {
game.getState().getTurnMods().add(new TurnMod(player.getId(), false));
return true;
}

View file

@ -62,7 +62,7 @@ class TavernSwindlerEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
game.informPlayers(controller.getLogName() + " got " + controller.gainLife(6, game, source)+ " live");
}
}

View file

@ -101,7 +101,7 @@ class TideOfWarEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Set<UUID> toSacrifice = new HashSet<>();
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
// each blocking creature is sacrificed by its controller
for (CombatGroup combatGroup: game.getCombat().getGroups()) {
for (UUID blockerId: combatGroup.getBlockers()) {

View file

@ -69,8 +69,8 @@ class TwoHeadedGiantEffect extends OneShotEffect {
if (player == null) {
return false;
}
boolean head1 = player.flipCoin(game);
boolean head2 = player.flipCoin(game);
boolean head1 = player.flipCoin(source, game, false);
boolean head2 = player.flipCoin(source, game, false);
if (head1 == head2) {
if (head1) {
game.addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), source);

View file

@ -61,7 +61,7 @@ class ViashinoSandswimmerEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
new ReturnToHandSourceEffect().apply(game, source);
return true;
} else {

View file

@ -130,7 +130,7 @@ class VolatileRigEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
return permanent.sacrifice(source.getSourceId(), game);
@ -161,7 +161,7 @@ class VolatileRigEffect2 extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
List<Permanent> permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game);
for (Permanent permanent : permanents) {

View file

@ -58,7 +58,7 @@ class WildWurmEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller != null && permanent != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
return true;
} else {
new ReturnToHandSourceEffect().apply(game, source);

View file

@ -52,7 +52,7 @@ class WinterSkyEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller.flipCoin(game)) {
if (controller.flipCoin(source, game, true)) {
new DamageEverythingEffect(1).apply(game, source);
return true;
} else {

View file

@ -60,7 +60,7 @@ class YdwenEfreetEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Permanent creature = game.getPermanent(source.getSourceId());
if (controller != null && creature != null) {
if (!controller.flipCoin(game)) {
if (!controller.flipCoin(source, game, true)) {
creature.removeFromCombat(game);
creature.setMaxBlocks(0);

View file

@ -2609,13 +2609,13 @@ public class TestPlayer implements Player {
}
@Override
public boolean flipCoin(Game game) {
return computerPlayer.flipCoin(game);
public boolean flipCoin(Ability source, Game game, boolean winnable) {
return computerPlayer.flipCoin(source, game, true);
}
@Override
public boolean flipCoin(Game game, ArrayList<UUID> appliedEffects) {
return computerPlayer.flipCoin(game, appliedEffects);
public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList<UUID> appliedEffects) {
return computerPlayer.flipCoin(source, game, true, appliedEffects);
}
@Override

View file

@ -642,12 +642,12 @@ public class PlayerStub implements Player {
}
@Override
public boolean flipCoin(Game game) {
public boolean flipCoin(Ability source, Game game, boolean winnable) {
return false;
}
@Override
public boolean flipCoin(Game game, ArrayList<UUID> appliedEffects) {
public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList<UUID> appliedEffects) {
return false;
}

View file

@ -5,10 +5,10 @@ import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.CoinFlippedEvent;
import mage.game.events.GameEvent;
/**
*
* @author TheElk801
*/
public class WinsCoinFlipTriggeredAbility extends TriggeredAbilityImpl {
@ -33,7 +33,8 @@ public class WinsCoinFlipTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getFlag();
CoinFlippedEvent flipEvent = (CoinFlippedEvent) event;
return flipEvent.isWinnable() && (flipEvent.getChosen() == flipEvent.getResult());
}
@Override

View file

@ -60,7 +60,7 @@ public class FlipCoinEffect extends OneShotEffect {
MageObject mageObject = game.getObject(source.getSourceId());
if (controller != null && mageObject != null) {
boolean result = true;
for (Effect effect : controller.flipCoin(game) ? executingEffectsWon : executingEffectsLost) {
for (Effect effect : controller.flipCoin(source, game, true) ? executingEffectsWon : executingEffectsLost) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
result &= effect.apply(game, source);

View file

@ -34,7 +34,7 @@ public class FlipUntilLoseEffect extends OneShotEffect {
return false;
}
while (true) {
if (!player.flipCoin(game)) {
if (!player.flipCoin(source, game, true)) {
return true;
}
}

View file

@ -0,0 +1,41 @@
package mage.game.events;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
**/
public class CoinFlippedEvent extends GameEvent {
private final boolean result;
private final boolean chosen;
private final boolean winnable;
CoinFlippedEvent(UUID playerId, UUID sourceId, boolean result, boolean chosen, boolean winnable) {
super(EventType.COIN_FLIPPED, playerId, sourceId, playerId);
this.result = result;
this.chosen = chosen;
this.winnable = winnable;
}
public boolean getResult() {
return result;
}
public String getResultName() {
return CardUtil.booleanToFlipName(result);
}
public boolean getChosen() {
return chosen;
}
public String getChosenName() {
return CardUtil.booleanToFlipName(chosen);
}
public boolean isWinnable() {
return winnable;
}
}

View file

@ -0,0 +1,49 @@
package mage.game.events;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author TheElk801
**/
public class FlipCoinEvent extends GameEvent {
private boolean result;
private final boolean chosen;
private final boolean winnable;
public FlipCoinEvent(UUID playerId, UUID sourceId, boolean result, boolean chosen, boolean winnable) {
super(EventType.FLIP_COIN, playerId, sourceId, playerId);
this.result = result;
this.chosen = chosen;
this.winnable = winnable;
}
public boolean getResult() {
return result;
}
public String getResultName() {
return CardUtil.booleanToFlipName(result);
}
public void setResult(boolean result) {
this.result = result;
}
public boolean getChosen() {
return chosen;
}
public String getChosenName() {
return CardUtil.booleanToFlipName(chosen);
}
public boolean isWinnable() {
return winnable;
}
public CoinFlippedEvent getFlippedEvent() {
return new CoinFlippedEvent(playerId, sourceId, result, chosen, winnable);
}
}

View file

@ -395,9 +395,9 @@ public interface Player extends MageItem, Copyable<Player> {
boolean hasProtectionFrom(MageObject source, Game game);
boolean flipCoin(Game game);
boolean flipCoin(Ability source, Game game, boolean winnable);
boolean flipCoin(Game game, ArrayList<UUID> appliedEffects);
boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList<UUID> appliedEffects);
int rollDice(Game game, int numSides);

View file

@ -42,11 +42,8 @@ import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.*;
import mage.game.combat.CombatGroup;
import mage.game.command.CommandObject;
import mage.game.events.DamagePlayerEvent;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.game.events.*;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.game.match.MatchPlayer;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
@ -2560,27 +2557,38 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean flipCoin(Game game) {
return this.flipCoin(game, null);
public boolean flipCoin(Ability source, Game game, boolean winnable) {
return this.flipCoin(source, game, winnable, null);
}
/**
* @param source
* @param game
* @param winnable
* @param appliedEffects
* @return true if player won the toss
* @return if winnable, true if player won the toss, if not winnable, true for heads and false for tails
*/
@Override
public boolean flipCoin(Game game, ArrayList<UUID> appliedEffects) {
public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList<UUID> appliedEffects) {
boolean chosen = false;
if (winnable) {
chosen = this.chooseUse(Outcome.Benefit, "Heads or tails?", "", "Heads", "Tails", source, game);
game.informPlayers(getLogName() + " chose " + (chosen ? "heads." : "tails."));
}
boolean result = RandomUtil.nextBoolean();
if (!game.isSimulation()) {
game.informPlayers("[Flip a coin] " + getLogName() + (result ? " won (head)." : " lost (tail)."));
FlipCoinEvent event = new FlipCoinEvent(playerId, source.getSourceId(), result, chosen, winnable);
event.addAppliedEffects(appliedEffects);
game.replaceEvent(event);
game.informPlayers(getLogName() + " got " + (event.getResult() ? "heads" : "tails"));
if (event.isWinnable()) {
game.informPlayers(getLogName() + " " + (event.getResult() == event.getChosen() ? "won" : "lost") + " the flip");
}
GameEvent event = new GameEvent(GameEvent.EventType.FLIP_COIN, playerId, null, playerId, 0, result);
event.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) {
game.fireEvent(new GameEvent(GameEvent.EventType.COIN_FLIPPED, playerId, null, playerId, 0, event.getFlag()));
game.fireEvent(event.getFlippedEvent());
if (event.isWinnable()) {
return event.getResult() == event.getChosen();
}
return event.getFlag();
return event.getResult();
}
@Override
@ -2598,7 +2606,7 @@ public abstract class PlayerImpl implements Player, Serializable {
public int rollDice(Game game, ArrayList<UUID> appliedEffects, int numSides) {
int result = RandomUtil.nextInt(numSides) + 1;
if (!game.isSimulation()) {
game.informPlayers("[Roll a die] " + getLogName() + " rolled a " + result + " on a " + numSides + " sided dice");
game.informPlayers("[Roll a die] " + getLogName() + " rolled a " + result + " on a " + numSides + " sided die");
}
GameEvent event = new GameEvent(GameEvent.EventType.ROLL_DICE, playerId, null, playerId, result, true);
event.setAppliedEffects(appliedEffects);

View file

@ -354,6 +354,13 @@ public final class CardUtil {
return message;
}
public static String booleanToFlipName(boolean flip) {
if (flip) {
return "Heads";
}
return "Tails";
}
public static boolean checkNumeric(String s) {
return s.chars().allMatch(Character::isDigit);