mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -375,7 +375,7 @@ public class GameAction {
|
||||
// the LKI needs to be the Card itself,
|
||||
// or it might not updated correctly
|
||||
// TODO be reworked when ZoneTrigger Update is done
|
||||
if (toBattlefield) {
|
||||
if (toBattlefield || zoneTo.is(ZoneType.Stack)) {
|
||||
lastKnownInfo = c;
|
||||
}
|
||||
|
||||
@@ -565,16 +565,31 @@ public class GameAction {
|
||||
public final void controllerChangeZoneCorrection(final Card c) {
|
||||
System.out.println("Correcting zone for " + c.toString());
|
||||
final Zone oldBattlefield = game.getZoneOf(c);
|
||||
if (oldBattlefield == null || oldBattlefield.getZoneType() == ZoneType.Stack) {
|
||||
|
||||
if (oldBattlefield == null || oldBattlefield.is(ZoneType.Stack)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Player original = oldBattlefield.getPlayer();
|
||||
final PlayerZone newBattlefield = c.getController().getZone(oldBattlefield.getZoneType());
|
||||
final Player controller = c.getController();
|
||||
if (original == null || controller == null || original.equals(controller)) {
|
||||
return;
|
||||
}
|
||||
final PlayerZone newBattlefield = controller.getZone(oldBattlefield.getZoneType());
|
||||
|
||||
if (newBattlefield == null || oldBattlefield.equals(newBattlefield)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 702.94e A paired creature becomes unpaired if any of the following occur:
|
||||
// another player gains control of it or the creature it’s paired with
|
||||
if (c.isPaired()) {
|
||||
Card partner = c.getPairedWith();
|
||||
c.setPairedWith(null);
|
||||
partner.setPairedWith(null);
|
||||
partner.updateStateForView();
|
||||
}
|
||||
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
for (Player p : game.getPlayers()) {
|
||||
((PlayerZoneBattlefield) p.getZone(ZoneType.Battlefield)).setTriggers(false);
|
||||
|
||||
@@ -62,7 +62,9 @@ public class AttachEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ChooseAnObject")) {
|
||||
Card c = p.getController().chooseSingleEntityForEffect(attachments, sa, sa.getParam("ChooseAnObject"));
|
||||
attachments.clear();
|
||||
attachments.add(c);
|
||||
if (c != null) {
|
||||
attachments.add(c);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
attachments = new CardCollection(source);
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -18,7 +17,6 @@ import forge.game.combat.Combat;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.Ability;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.collect.FCollectionView;
|
||||
@@ -26,9 +24,7 @@ import forge.util.Localizer;
|
||||
import forge.util.CardTranslation;
|
||||
|
||||
public class ControlGainEffect extends SpellAbilityEffect {
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
@@ -67,15 +63,17 @@ public class ControlGainEffect extends SpellAbilityEffect {
|
||||
if (null == c || c.hasKeyword("Other players can't gain control of CARDNAME.")) {
|
||||
return;
|
||||
}
|
||||
final Game game = host.getGame();
|
||||
if (c.isInPlay()) {
|
||||
c.removeTempController(tStamp);
|
||||
|
||||
game.getAction().controllerChangeZoneCorrection(c);
|
||||
|
||||
if (tapOnLose) {
|
||||
c.tap();
|
||||
}
|
||||
} // if
|
||||
host.removeGainControlTargets(c);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,11 +82,9 @@ public class ControlGainEffect extends SpellAbilityEffect {
|
||||
|
||||
final boolean bUntap = sa.hasParam("Untap");
|
||||
final boolean bTapOnLose = sa.hasParam("TapOnLose");
|
||||
final boolean bNoRegen = sa.hasParam("NoRegen");
|
||||
final boolean remember = sa.hasParam("RememberControlled");
|
||||
final boolean forget = sa.hasParam("ForgetControlled");
|
||||
final boolean attacking = sa.hasParam("Attacking");
|
||||
final List<String> destroyOn = sa.hasParam("DestroyTgt") ? Arrays.asList(sa.getParam("DestroyTgt").split(",")) : null;
|
||||
final List<String> keywords = sa.hasParam("AddKWs") ? Arrays.asList(sa.getParam("AddKWs").split(" & ")) : null;
|
||||
final List<String> lose = sa.hasParam("LoseControl") ? Arrays.asList(sa.getParam("LoseControl").split(",")) : null;
|
||||
|
||||
@@ -189,18 +185,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
if (destroyOn != null) {
|
||||
if (destroyOn.contains("LeavesPlay")) {
|
||||
sa.getHostCard().addLeavesPlayCommand(getDestroyCommand(tgtC, source, bNoRegen));
|
||||
}
|
||||
if (destroyOn.contains("Untap")) {
|
||||
sa.getHostCard().addUntapCommand(getDestroyCommand(tgtC, source, bNoRegen));
|
||||
}
|
||||
if (destroyOn.contains("LoseControl")) {
|
||||
sa.getHostCard().addChangeControllerCommand(getDestroyCommand(tgtC, source, bNoRegen));
|
||||
}
|
||||
}
|
||||
|
||||
if (keywords != null) {
|
||||
// Add keywords only until end of turn
|
||||
final GameCommand untilKeywordEOT = new GameCommand() {
|
||||
@@ -241,43 +225,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
|
||||
} // end foreach target
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getDestroyCommand.
|
||||
* </p>
|
||||
*
|
||||
* @param i
|
||||
* a int.
|
||||
* @return a {@link forge.GameCommand} object.
|
||||
*/
|
||||
private static GameCommand getDestroyCommand(final Card c, final Card hostCard, final boolean bNoRegen) {
|
||||
final GameCommand destroy = new GameCommand() {
|
||||
private static final long serialVersionUID = 878543373519872418L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final Game game = hostCard.getGame();
|
||||
final Ability ability = new Ability(hostCard, ManaCost.ZERO) {
|
||||
@Override
|
||||
public void resolve() {
|
||||
game.getAction().destroy(c, null, !bNoRegen, null);
|
||||
}
|
||||
};
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(hostCard).append(" - destroy ").append(c.getName()).append(".");
|
||||
if (bNoRegen) {
|
||||
sb.append(" It can't be regenerated.");
|
||||
}
|
||||
ability.setStackDescription(sb.toString());
|
||||
ability.setTrigger(true);
|
||||
|
||||
game.getStack().addSimultaneousStackEntry(ability);
|
||||
}
|
||||
|
||||
};
|
||||
return destroy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getLoseControlCommand.
|
||||
|
||||
@@ -1,34 +1,62 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class MustBlockEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Game game = activator.getGame();
|
||||
|
||||
List<Card> tgtCards = Lists.newArrayList();
|
||||
if (sa.hasParam("Choices")) {
|
||||
Player chooser = activator;
|
||||
if (sa.hasParam("Chooser")) {
|
||||
final String choose = sa.getParam("Chooser");
|
||||
chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0);
|
||||
}
|
||||
|
||||
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
|
||||
if (!choices.isEmpty()) {
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") +" ";
|
||||
|
||||
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false);
|
||||
|
||||
if (choosen != null) {
|
||||
tgtCards.add(choosen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tgtCards = getTargetCards(sa);
|
||||
}
|
||||
|
||||
List<Card> tgtCards = getTargetCards(sa);
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final boolean mustBlockAll = sa.hasParam("BlockAllDefined");
|
||||
|
||||
List<Card> cards;
|
||||
if (sa.hasParam("DefinedAttacker")) {
|
||||
cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa);
|
||||
} else {
|
||||
cards = new ArrayList<>();
|
||||
cards.add(host);
|
||||
cards = Lists.newArrayList(host);
|
||||
}
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
if ((tgt == null) || c.canBeTargetedBy(sa)) {
|
||||
if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) {
|
||||
if (mustBlockAll) {
|
||||
c.addMustBlockCards(cards);
|
||||
} else {
|
||||
@@ -48,8 +76,6 @@ public class MustBlockEffect extends SpellAbilityEffect {
|
||||
|
||||
// end standard pre-
|
||||
|
||||
final List<Card> tgtCards = getTargetCards(sa);
|
||||
|
||||
String attacker = null;
|
||||
if (sa.hasParam("DefinedAttacker")) {
|
||||
final List<Card> cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa);
|
||||
@@ -58,10 +84,13 @@ public class MustBlockEffect extends SpellAbilityEffect {
|
||||
attacker = host.toString();
|
||||
}
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
sb.append(c).append(" must block ").append(attacker).append(" if able.");
|
||||
if (sa.hasParam("Choices")) {
|
||||
sb.append("Choosen creature ").append(" must block ").append(attacker).append(" if able.");
|
||||
} else {
|
||||
for (final Card c : getTargetCards(sa)) {
|
||||
sb.append(c).append(" must block ").append(attacker).append(" if able.");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1518,27 +1518,38 @@ public class CardProperty {
|
||||
} else if (property.startsWith("blockedByThisTurn")) {
|
||||
return !card.getBlockedByThisTurn().isEmpty();
|
||||
} else if (property.startsWith("blockedValidThisTurn ")) {
|
||||
if (card.getBlockedThisTurn() == null) {
|
||||
CardCollectionView blocked = card.getBlockedThisTurn();
|
||||
if (blocked == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String valid = property.split(" ")[1];
|
||||
for(Card c : card.getBlockedThisTurn()) {
|
||||
for(Card c : blocked) {
|
||||
if (c.isValid(valid, card.getController(), source, spellAbility)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(Card c : AbilityUtils.getDefinedCards(source, valid, spellAbility)) {
|
||||
if (blocked.contains(c)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return false;
|
||||
} else if (property.startsWith("blockedByValidThisTurn ")) {
|
||||
if (card.getBlockedByThisTurn() == null) {
|
||||
CardCollectionView blocked = card.getBlockedByThisTurn();
|
||||
if (blocked == null) {
|
||||
return false;
|
||||
}
|
||||
String valid = property.split(" ")[1];
|
||||
for(Card c : card.getBlockedByThisTurn()) {
|
||||
for(Card c : blocked) {
|
||||
if (c.isValid(valid, card.getController(), source, spellAbility)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(Card c : AbilityUtils.getDefinedCards(source, valid, spellAbility)) {
|
||||
if (blocked.contains(c)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return false;
|
||||
} else if (property.startsWith("blockedBySourceThisTurn")) {
|
||||
return source.getBlockedByThisTurn().contains(card);
|
||||
@@ -1779,4 +1790,4 @@ public class CardProperty {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,17 +100,21 @@ public class TrackableTypes {
|
||||
if (newCollection != null) {
|
||||
//swap in objects in old collection for objects in new collection
|
||||
for (int i = 0; i < newCollection.size(); i++) {
|
||||
T newObj = newCollection.get(i);
|
||||
if (newObj != null) {
|
||||
T existingObj = from.getTracker().getObj(itemType, newObj.getId());
|
||||
if (existingObj != null) { //if object exists already, update its changed properties
|
||||
existingObj.copyChangedProps(newObj);
|
||||
newCollection.remove(i);
|
||||
newCollection.add(i, existingObj);
|
||||
}
|
||||
else { //if object is new, cache in object lookup
|
||||
from.getTracker().putObj(itemType, newObj.getId(), newObj);
|
||||
try {
|
||||
T newObj = newCollection.get(i);
|
||||
if (newObj != null) {
|
||||
T existingObj = from.getTracker().getObj(itemType, newObj.getId());
|
||||
if (existingObj != null) { //if object exists already, update its changed properties
|
||||
existingObj.copyChangedProps(newObj);
|
||||
newCollection.remove(i);
|
||||
newCollection.add(i, existingObj);
|
||||
}
|
||||
else { //if object is new, cache in object lookup
|
||||
from.getTracker().putObj(itemType, newObj.getId(), newObj);
|
||||
}
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
System.err.println("got an IndexOutOfBoundsException, trying to continue ...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user