mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Merge remote-tracking branch 'core/master'
This commit is contained in:
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
|
||||
import forge.util.*;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
@@ -1265,7 +1266,24 @@ public class GameAction {
|
||||
noRegCreats.add(c);
|
||||
checkAgain = true;
|
||||
} else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) {
|
||||
for (final Integer dmg : c.getReceivedDamageFromThisTurn().values()) {
|
||||
// merge entries with same source
|
||||
List<Integer> dmgList = Lists.newArrayList();
|
||||
List<Pair<Card, Integer>> remainingDamaged = Lists.newArrayList(c.getReceivedDamageFromThisTurn());
|
||||
while (!remainingDamaged.isEmpty()) {
|
||||
Pair <Card, Integer> damaged = remainingDamaged.get(0);
|
||||
int sum = damaged.getRight();
|
||||
remainingDamaged.remove(damaged);
|
||||
for (Pair<Card, Integer> other : Lists.newArrayList(remainingDamaged)) {
|
||||
if (other.getLeft().equalsWithTimestamp(damaged.getLeft())) {
|
||||
sum += other.getRight();
|
||||
// once it got counted keep it out
|
||||
remainingDamaged.remove(other);
|
||||
}
|
||||
}
|
||||
dmgList.add(sum);
|
||||
}
|
||||
|
||||
for (final Integer dmg : dmgList) {
|
||||
if (c.getLethal() <= dmg.intValue() || c.hasBeenDealtDeathtouchDamage()) {
|
||||
if (desCreats == null) {
|
||||
desCreats = new CardCollection();
|
||||
|
||||
@@ -255,14 +255,14 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
Player chooser = p;
|
||||
if (mode.endsWith("YouChoose")) {
|
||||
chooser = source.getController();
|
||||
} else if (mode.endsWith("TgtChoose")) {
|
||||
} else if (mode.equals("RevealTgtChoose")) {
|
||||
chooser = firstTarget;
|
||||
}
|
||||
|
||||
if (mode.startsWith("Reveal")) {
|
||||
game.getAction().reveal(dPHand, p);
|
||||
}
|
||||
if (mode.startsWith("Look")) {
|
||||
if (mode.startsWith("Look") && p != chooser) {
|
||||
game.getAction().revealTo(dPHand, chooser);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,8 +174,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
private final Set<Object> rememberedObjects = Sets.newLinkedHashSet();
|
||||
private Map<Player, String> flipResult;
|
||||
|
||||
private Map<GameEntity, Integer> receivedDamageFromThisTurn = Maps.newHashMap();
|
||||
|
||||
private List<Pair<Card, Integer>> receivedDamageFromThisTurn = Lists.newArrayList();
|
||||
private Map<Player, Integer> receivedDamageFromPlayerThisTurn = Maps.newHashMap();
|
||||
|
||||
private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
|
||||
|
||||
private boolean isCommander = false;
|
||||
@@ -5154,46 +5155,48 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
damageHistory = history;
|
||||
}
|
||||
|
||||
public final Map<GameEntity, Integer> getReceivedDamageFromThisTurn() {
|
||||
public final List<Pair<Card, Integer>> getReceivedDamageFromThisTurn() {
|
||||
return receivedDamageFromThisTurn;
|
||||
}
|
||||
public final void setReceivedDamageFromThisTurn(final Map<GameEntity, Integer> receivedDamageList) {
|
||||
receivedDamageFromThisTurn = Maps.newHashMap(receivedDamageList);
|
||||
public final void setReceivedDamageFromThisTurn(final List<Pair<Card, Integer>> receivedDamageList) {
|
||||
receivedDamageFromThisTurn = Lists.newArrayList(receivedDamageList);
|
||||
}
|
||||
public final Map<Player, Integer> getReceivedDamageFromPlayerThisTurn() {
|
||||
return receivedDamageFromPlayerThisTurn;
|
||||
}
|
||||
public final void setReceivedDamageFromPlayerThisTurn(final Map<Player, Integer> receivedDamageMap) {
|
||||
receivedDamageFromPlayerThisTurn = Maps.newHashMap(receivedDamageMap);
|
||||
}
|
||||
|
||||
public int getReceivedDamageByPlayerThisTurn(final Player p) {
|
||||
if (receivedDamageFromThisTurn.containsKey(p)) {
|
||||
return receivedDamageFromThisTurn.get(p);
|
||||
if (receivedDamageFromPlayerThisTurn.containsKey(p)) {
|
||||
return receivedDamageFromPlayerThisTurn.get(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public final void addReceivedDamageFromThisTurn(final Card c, final int damage) {
|
||||
public final void addReceivedDamageFromThisTurn(Card c, final int damage) {
|
||||
int currentDamage = 0;
|
||||
if (receivedDamageFromThisTurn.containsKey(c)) {
|
||||
currentDamage = receivedDamageFromThisTurn.get(c);
|
||||
}
|
||||
receivedDamageFromThisTurn.put(c, damage+currentDamage);
|
||||
// because Aegar cares about the past state we need to keep all LKI instances
|
||||
receivedDamageFromThisTurn.add(Pair.of(c.isLKI() ? c : CardUtil.getLKICopy(c), damage));
|
||||
|
||||
Player p = c.getController();
|
||||
if (p != null) {
|
||||
currentDamage = 0;
|
||||
if (receivedDamageFromThisTurn.containsKey(p)) {
|
||||
currentDamage = receivedDamageFromThisTurn.get(p);
|
||||
if (receivedDamageFromPlayerThisTurn.containsKey(p)) {
|
||||
currentDamage = receivedDamageFromPlayerThisTurn.get(p);
|
||||
}
|
||||
receivedDamageFromThisTurn.put(p, damage+currentDamage);
|
||||
receivedDamageFromPlayerThisTurn.put(p, damage+currentDamage);
|
||||
}
|
||||
}
|
||||
public final void resetReceivedDamageFromThisTurn() {
|
||||
receivedDamageFromThisTurn.clear();
|
||||
receivedDamageFromPlayerThisTurn.clear();
|
||||
}
|
||||
|
||||
public final int getTotalDamageReceivedThisTurn() {
|
||||
int total = 0;
|
||||
for (Entry<GameEntity, Integer> e : receivedDamageFromThisTurn.entrySet()) {
|
||||
if (e.getKey() instanceof Player) {
|
||||
total += e.getValue();
|
||||
}
|
||||
for (Integer i : receivedDamageFromPlayerThisTurn.values()) {
|
||||
total += i;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -633,18 +634,21 @@ public class CardProperty {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("DamagedBy")) {
|
||||
List<Card> damaged = Lists.newArrayList();
|
||||
for (Pair<Card, Integer> pair : card.getReceivedDamageFromThisTurn()) {
|
||||
damaged.add(pair.getLeft());
|
||||
}
|
||||
if (property.endsWith("Source") || property.equals("DamagedBy")) {
|
||||
if (!card.getReceivedDamageFromThisTurn().containsKey(source)) {
|
||||
if (!damaged.contains(source)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
String prop = property.substring("DamagedBy".length());
|
||||
final Iterable<Card> list = Iterables.filter(card.getReceivedDamageFromThisTurn().keySet(), Card.class);
|
||||
boolean found = Iterables.any(list, CardPredicates.restriction(prop, sourceController, source, spellAbility));
|
||||
boolean found = Iterables.any(damaged, CardPredicates.restriction(prop, sourceController, source, spellAbility));
|
||||
|
||||
if (!found) {
|
||||
for (Card d : AbilityUtils.getDefinedCards(source, prop, spellAbility)) {
|
||||
if (card.getReceivedDamageFromThisTurn().containsKey(d)) {
|
||||
if (damaged.contains(d)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1177,7 +1181,7 @@ public class CardProperty {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("wasDealtDamageThisTurn")) {
|
||||
if ((card.getReceivedDamageFromThisTurn().keySet()).isEmpty()) {
|
||||
if (card.getReceivedDamageFromPlayerThisTurn().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("dealtDamageThisTurn")) {
|
||||
|
||||
@@ -250,6 +250,7 @@ public final class CardUtil {
|
||||
newCopy.setPhasedOut(in.isPhasedOut());
|
||||
|
||||
newCopy.setReceivedDamageFromThisTurn(in.getReceivedDamageFromThisTurn());
|
||||
newCopy.setReceivedDamageFromPlayerThisTurn(in.getReceivedDamageFromPlayerThisTurn());
|
||||
newCopy.setDamageHistory(in.getDamageHistory());
|
||||
for (Card c : in.getBlockedThisTurn()) {
|
||||
newCopy.addBlockedThisTurn(c);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Name:Disruption Protocol
|
||||
ManaCost:U U
|
||||
Types:Instant
|
||||
K:AlternateAdditionalCost:tapXType<1/Artifact>:1
|
||||
A:SP$ Counter | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | SpellDescription$ Counter target spell.
|
||||
DeckHints:Type$Artifact
|
||||
Oracle:As an additional cost to cast this spell, tap an untapped artifact you control or pay {1}.\nCounter target spell.
|
||||
6
forge-gui/res/cardsfolder/upcoming/futurist_sentinel.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/futurist_sentinel.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Futurist Sentinel
|
||||
ManaCost:3 U
|
||||
Types:Artifact Vehicle
|
||||
PT:6/6
|
||||
K:Crew:3
|
||||
Oracle:Crew 3 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)
|
||||
@@ -0,0 +1,8 @@
|
||||
Name:Moonfolk Puzzlemaker
|
||||
ManaCost:2 U
|
||||
Types:Artifact Creature Moonfolk Wizard
|
||||
PT:1/4
|
||||
K:Flying
|
||||
T:Mode$ Taps | ValidCard$ Card.Self | Execute$ TrigSry | TriggerDescription$ Whenever CARDNAME becomes tapped, scry 1.
|
||||
SVar:TrigSry:DB$ Scry | ScryNum$ 1
|
||||
Oracle:Flying\nWhenever Moonfolk Puzzlemaker becomes tapped, scry 1.
|
||||
@@ -7,15 +7,15 @@ SVar:DBExile:DB$ Dig | Defined$ You | DigNum$ 1 | ChangeNum$ All | DestinationZo
|
||||
SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ STPlay | SubAbility$ DBCleanup | ForgetOnMoved$ Exile | StackDescription$ SpellDescription | SpellDescription$ You may play that card this turn. Activate only as a sorcery.
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:STPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play the exiled card this turn.
|
||||
T:Mode$ SpellCast | ValidCard$ Card.IsImprinted | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ Whenever you play a card exiled with CARDNAME, transform it.
|
||||
T:Mode$ LandPlayed | ValidCard$ Land.IsImprinted+YouCtrl | Execute$ TrigTransform | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever you play a card exiled with CARDNAME, transform it.
|
||||
T:Mode$ SpellCast | ValidCard$ Card.IsImprinted | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ When you play a card exiled with CARDNAME, transform it.
|
||||
T:Mode$ LandPlayed | ValidCard$ Land.IsImprinted+YouCtrl | Execute$ TrigTransform | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ When you play a card exiled with CARDNAME, transform it.
|
||||
SVar:TrigTransform:DB$ SetState | Defined$ Self | Mode$ Transform
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBClear | Static$ True
|
||||
SVar:DBClear:DB$ Cleanup | ClearImprinted$ True
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
||||
AlternateMode:DoubleFaced
|
||||
Oracle:{T}: Voltaic Visionary deals 2 damage to you. Exile the top card of your library. You may play that card this turn. Activate only as a sorcery.\nWhenever you play a card exiled with Voltaic Visionary, transform it.
|
||||
Oracle:{T}: Voltaic Visionary deals 2 damage to you. Exile the top card of your library. You may play that card this turn. Activate only as a sorcery.\nWhen you play a card exiled with Voltaic Visionary, transform it.
|
||||
|
||||
ALTERNATE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user