mirror of
https://github.com/magefree/mage.git
synced 2025-12-28 06:22:01 -08:00
* Fixed wrong timer handling while other player controlled a player's turn. Attackers now marked with blue frame. Playable cards have a violet frame. If a player has to select cards from hand, the possible cards are marked yellow now. Discard of multiple cards now marks already selected cards and happens in one selection.
This commit is contained in:
parent
194efe6237
commit
67479bb5a4
20 changed files with 205 additions and 163 deletions
|
|
@ -31,13 +31,10 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.Mode;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +45,6 @@ public class DiscardTargetEffect extends OneShotEffect {
|
|||
|
||||
protected DynamicValue amount;
|
||||
protected boolean randomDiscard;
|
||||
protected boolean setTargetPointer;
|
||||
|
||||
public DiscardTargetEffect(DynamicValue amount) {
|
||||
this(amount, false);
|
||||
|
|
@ -64,22 +60,22 @@ public class DiscardTargetEffect extends OneShotEffect {
|
|||
this(new StaticValue(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount amount of cards to discard
|
||||
* @param randomDiscard discard the cards by random
|
||||
*
|
||||
*/
|
||||
public DiscardTargetEffect(int amount, boolean randomDiscard) {
|
||||
this(new StaticValue(amount), randomDiscard);
|
||||
}
|
||||
|
||||
public DiscardTargetEffect(int amount, boolean randomDiscard, boolean setTargetPointer) {
|
||||
super(Outcome.Discard);
|
||||
this.randomDiscard = randomDiscard;
|
||||
this.amount = new StaticValue(amount);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
||||
public DiscardTargetEffect(final DiscardTargetEffect effect) {
|
||||
super(effect);
|
||||
this.amount = effect.amount.copy();
|
||||
this.randomDiscard = effect.randomDiscard;
|
||||
this.setTargetPointer = effect.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -91,23 +87,7 @@ public class DiscardTargetEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(targetPointer.getFirst(game, source));
|
||||
if (player != null) {
|
||||
if (randomDiscard) {
|
||||
int maxAmount = Math.min(amount.calculate(game, source, this), player.getHand().size());
|
||||
for (int i = 0; i < maxAmount; i++) {
|
||||
Card card = player.getHand().getRandom(game);
|
||||
if (card != null) {
|
||||
player.discard(card, source, game);
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : source.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.discard(amount.calculate(game, source, this), source, game);
|
||||
}
|
||||
|
||||
player.discard(amount.calculate(game, source, this), randomDiscard, source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -988,7 +988,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
int deduction = 1;
|
||||
if (freeMulligans > 0) {
|
||||
if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) {
|
||||
int used = usedFreeMulligans.get(player.getId()).intValue();
|
||||
int used = usedFreeMulligans.get(player.getId());
|
||||
if (used < freeMulligans ) {
|
||||
deduction = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ import mage.target.TargetCard;
|
|||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
import mage.target.common.TargetDiscard;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.common.BloodthirstWatcher;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -563,6 +564,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
@Override
|
||||
public void setGameUnderYourControl(boolean value) {
|
||||
this.isGameUnderControl = value;
|
||||
if (isGameUnderControl) {
|
||||
this.turnController = getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -623,12 +627,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
public void discardToMax(Game game) {
|
||||
if (hand.size() > this.maxHandSize) {
|
||||
game.informPlayers(new StringBuilder(getName()).append(" discards down to ").append(this.maxHandSize).append(this.maxHandSize == 1?" hand card":" hand cards").toString());
|
||||
while (isInGame() && hand.size() > this.maxHandSize) {
|
||||
TargetDiscard target = new TargetDiscard(playerId);
|
||||
target.setTargetName(new StringBuilder(" card to discard (").append(hand.size() - this.maxHandSize).append(" in total)").toString());
|
||||
choose(Outcome.Discard, target, null, game);
|
||||
discard(hand.get(target.getFirstTarget(), game), null, game);
|
||||
}
|
||||
discard(hand.size() - this.maxHandSize, null, game);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,21 +681,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
return discardedCards;
|
||||
}
|
||||
int numDiscarded = 0;
|
||||
while (isInGame() && numDiscarded < amount) {
|
||||
if (this.getHand().size() == 0) {
|
||||
break;
|
||||
if (random) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Card card = this.getHand().getRandom(game);
|
||||
discardedCards.add(card);
|
||||
discard(card, source, game);
|
||||
}
|
||||
Card card;
|
||||
if (random) {
|
||||
card = this.getHand().getRandom(game);
|
||||
} else {
|
||||
TargetDiscard target = new TargetDiscard(playerId);
|
||||
choose(Outcome.Discard, target, source.getSourceId(), game);
|
||||
card = this.getHand().get(target.getFirstTarget(), game);
|
||||
}
|
||||
if (card != null) {
|
||||
numDiscarded++;
|
||||
} else {
|
||||
TargetDiscard target = new TargetDiscard(amount, amount, new FilterCard(CardUtil.numberToText(amount, "a") + " card" + (amount > 1 ?"s":"")), playerId);
|
||||
choose(Outcome.Discard, target, source == null?null:source.getSourceId(), game);
|
||||
for (UUID cardId: target.getTargets()) {
|
||||
Card card = this.getHand().get(cardId, game);
|
||||
discardedCards.add(card);
|
||||
discard(card, source, game);
|
||||
}
|
||||
|
|
@ -2253,36 +2248,40 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return playable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of card ids that are currently playable.<br>
|
||||
* Used to mark the playable cards in GameView
|
||||
*
|
||||
* @return A Set of cardIds that are playable
|
||||
* @see mage.server.GameSessionPlayer#getGameView()
|
||||
*
|
||||
* @param game
|
||||
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Set<UUID> getPlayableInHand(Game game) {
|
||||
Set<UUID> playable = new HashSet<>();
|
||||
if (!shouldSkipGettingPlayable(game)) {
|
||||
// for clean_up phase show all cards
|
||||
if (game.getPhase() != null && PhaseStep.CLEANUP.equals(game.getPhase().getStep().getType())) {
|
||||
for (Card card: hand.getCards(game)) {
|
||||
playable.add(card.getId());
|
||||
}
|
||||
} else {
|
||||
ManaOptions available = getManaAvailable(game);
|
||||
available.addMana(manaPool.getMana());
|
||||
ManaOptions available = getManaAvailable(game);
|
||||
available.addMana(manaPool.getMana());
|
||||
|
||||
for (Card card : hand.getCards(game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) {
|
||||
if (ability instanceof PlayLandAbility) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
for (Card card : hand.getCards(game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getPlayableAbilities(Zone.HAND)) {
|
||||
if (ability instanceof PlayLandAbility) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
break;
|
||||
}
|
||||
if (canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
package mage.target;
|
||||
|
||||
import java.io.Serializable;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class TargetDiscard extends TargetCard {
|
|||
super(minNumTargets, maxNumTargets, Zone.HAND, filter);
|
||||
this.filter.add(new OwnerIdPredicate(playerId));
|
||||
this.playerId = playerId;
|
||||
this.targetName = "card to discard";
|
||||
this.targetName = this.filter.getMessage() + " to discard";
|
||||
}
|
||||
|
||||
public TargetDiscard(final TargetDiscard target) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue