mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch 'master' into Attractions
This commit is contained in:
@@ -485,7 +485,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return damageChoosingTargets(ai, saMe, tgt, dmg, false, immediately);
|
return damageChoosingTargets(ai, saMe, tgt, dmg, saMe.isMandatory(), immediately);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -174,6 +174,21 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
|||||||
return cp != null && !cp.isEmpty();
|
return cp != null && !cp.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaperCard removeCardName(String name) {
|
||||||
|
PaperCard paperCard;
|
||||||
|
for (Entry<DeckSection, CardPool> kv : parts.entrySet()) {
|
||||||
|
CardPool pool = kv.getValue();
|
||||||
|
for (Entry<PaperCard, Integer> pc : pool) {
|
||||||
|
if (pc.getKey().getName().equalsIgnoreCase(name)) {
|
||||||
|
paperCard = pc.getKey();
|
||||||
|
pool.remove(paperCard);
|
||||||
|
return paperCard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// will return new if it was absent
|
// will return new if it was absent
|
||||||
public CardPool getOrCreate(DeckSection deckSection) {
|
public CardPool getOrCreate(DeckSection deckSection) {
|
||||||
CardPool p = get(deckSection);
|
CardPool p = get(deckSection);
|
||||||
|
|||||||
@@ -22,10 +22,7 @@ package forge.game;
|
|||||||
*/
|
*/
|
||||||
public enum GlobalRuleChange {
|
public enum GlobalRuleChange {
|
||||||
|
|
||||||
attackerChoosesBlockers ("The attacking player chooses how each creature blocks each combat."),
|
attackerChoosesBlockers ("The attacking player chooses how each creature blocks each combat.");
|
||||||
onlyOneBlocker ("No more than one creature can block each combat."),
|
|
||||||
onlyOneBlockerPerOpponent ("Each opponent can't block with more than one creature."),
|
|
||||||
onlyTwoBlockers ("No more than two creatures can block each combat.");
|
|
||||||
|
|
||||||
private final String ruleText;
|
private final String ruleText;
|
||||||
|
|
||||||
|
|||||||
@@ -2133,6 +2133,9 @@ public class CardProperty {
|
|||||||
List<String> nameList = Lists.newArrayList(names.split(";"));
|
List<String> nameList = Lists.newArrayList(names.split(";"));
|
||||||
|
|
||||||
return nameList.contains(card.getName());
|
return nameList.contains(card.getName());
|
||||||
|
} else if (property.equals("NotedGuessPhantasm")) {
|
||||||
|
String names = sourceController.getDraftNotes().get("Spire Phantasm");
|
||||||
|
return names != null && !names.isEmpty();
|
||||||
} else if (property.equals("NotedTypes")) {
|
} else if (property.equals("NotedTypes")) {
|
||||||
// Should Paliano Vanguard be hardcoded here or part of the property?
|
// Should Paliano Vanguard be hardcoded here or part of the property?
|
||||||
String types = sourceController.getDraftNotes().get("Paliano Vanguard");
|
String types = sourceController.getDraftNotes().get("Paliano Vanguard");
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.google.common.collect.Lists;
|
|||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
import forge.game.GlobalRuleChange;
|
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
@@ -36,6 +35,7 @@ import forge.game.player.Player;
|
|||||||
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
|
import forge.game.staticability.StaticAbilityBlockRestrict;
|
||||||
import forge.game.staticability.StaticAbilityCantAttackBlock;
|
import forge.game.staticability.StaticAbilityCantAttackBlock;
|
||||||
import forge.game.staticability.StaticAbilityMustBlock;
|
import forge.game.staticability.StaticAbilityMustBlock;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
@@ -457,21 +457,11 @@ public class CombatUtil {
|
|||||||
if (!canBlockMoreCreatures(blocker, combat.getAttackersBlockedBy(blocker))) {
|
if (!canBlockMoreCreatures(blocker, combat.getAttackersBlockedBy(blocker))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Game game = blocker.getGame();
|
|
||||||
final int blockers = combat.getAllBlockers().size();
|
|
||||||
|
|
||||||
if (blockers > 1 && game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.onlyTwoBlockers)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockers > 0 && game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.onlyOneBlocker)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CardCollection allOtherBlockers = combat.getAllBlockers();
|
CardCollection allOtherBlockers = combat.getAllBlockers();
|
||||||
allOtherBlockers.remove(blocker);
|
allOtherBlockers.remove(blocker);
|
||||||
final int blockersFromOnePlayer = CardLists.count(allOtherBlockers, CardPredicates.isController(blocker.getController()));
|
final int blockersFromOnePlayer = CardLists.count(allOtherBlockers, CardPredicates.isController(blocker.getController()));
|
||||||
if (blockersFromOnePlayer > 0 && game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.onlyOneBlockerPerOpponent)) {
|
if (blockersFromOnePlayer >= StaticAbilityBlockRestrict.blockRestrictNum(blocker.getController())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2134,12 +2134,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return lost;
|
return lost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasProwl(final Set<String> types) {
|
public final boolean hasProwl(final SpellAbility sa) {
|
||||||
StringBuilder sb = new StringBuilder();
|
return !game.getDamageDoneThisTurn(true, true, "Card.YouCtrl+sharesCreatureTypeWith", "Player", sa.getHostCard(), this, sa).isEmpty();
|
||||||
for (String type : types) {
|
|
||||||
sb.append("Card.YouCtrl+").append(type).append(",");
|
|
||||||
}
|
|
||||||
return !game.getDamageDoneThisTurn(true, true, sb.toString(), "Player", null, this, null).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasFreerunning() {
|
public final boolean hasFreerunning() {
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sa.isProwl()) {
|
if (sa.isProwl()) {
|
||||||
if (!activator.hasProwl(c.getType().getCreatureTypes())) {
|
if (!activator.hasProwl(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package forge.game.staticability;
|
||||||
|
|
||||||
|
import forge.game.Game;
|
||||||
|
import forge.game.ability.AbilityUtils;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
|
public class StaticAbilityBlockRestrict {
|
||||||
|
static String MODE = "BlockRestrict";
|
||||||
|
|
||||||
|
static public int blockRestrictNum(Player defender) {
|
||||||
|
final Game game = defender.getGame();
|
||||||
|
int num = Integer.MAX_VALUE;
|
||||||
|
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
||||||
|
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||||
|
if (!stAb.checkConditions(MODE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (blockRestrict(stAb, defender)) {
|
||||||
|
int stNum = AbilityUtils.calculateAmount(stAb.getHostCard(),
|
||||||
|
stAb.getParamOrDefault("MaxBlockers", "1"), stAb);
|
||||||
|
if (stNum < num) {
|
||||||
|
num = stNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public boolean blockRestrict(StaticAbility stAb, Player defender) {
|
||||||
|
if (!stAb.matchesValidParam("ValidDefender", defender)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -116,12 +116,21 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
|
|||||||
// can only draft one at a time, regardless of the requested quantity
|
// can only draft one at a time, regardless of the requested quantity
|
||||||
PaperCard card = items.iterator().next().getKey();
|
PaperCard card = items.iterator().next().getKey();
|
||||||
|
|
||||||
|
if (boosterDraft.getHumanPlayer().shouldSkipThisPick()) {
|
||||||
|
System.out.println(card + " not drafted because we're skipping this pick");
|
||||||
|
showPackToDraft();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify if card is in the activate pack?
|
// Verify if card is in the activate pack?
|
||||||
this.getDeckManager().addItem(card, 1);
|
this.getDeckManager().addItem(card, 1);
|
||||||
|
|
||||||
// get next booster pack
|
// get next booster pack if we aren't picking again from this pack
|
||||||
this.boosterDraft.setChoice(card);
|
this.boosterDraft.setChoice(card);
|
||||||
|
showPackToDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void showPackToDraft() {
|
||||||
boolean nextChoice = this.boosterDraft.hasNextChoice();
|
boolean nextChoice = this.boosterDraft.hasNextChoice();
|
||||||
ItemPool<PaperCard> pool = null;
|
ItemPool<PaperCard> pool = null;
|
||||||
if (nextChoice) {
|
if (nextChoice) {
|
||||||
|
|||||||
@@ -58,10 +58,15 @@ public class BoosterDraftTest implements IBoosterDraft {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setChoice(final PaperCard c) {
|
public boolean setChoice(final PaperCard c) {
|
||||||
System.out.println(c.getName());
|
System.out.println(c.getName());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -132,3 +132,4 @@ Alchemy: Ixalan, 3/6/LCI, YLCI
|
|||||||
Ravnica Remastered, 3/6/RAV, RVR
|
Ravnica Remastered, 3/6/RAV, RVR
|
||||||
Murders at Karlov Manor, 3/6/MKM, MKM
|
Murders at Karlov Manor, 3/6/MKM, MKM
|
||||||
Outlaws of Thunder Junction, 3/6/OTJ, OTJ
|
Outlaws of Thunder Junction, 3/6/OTJ, OTJ
|
||||||
|
Modern Horizons 3, 3/6/MH3, MH3
|
||||||
7
forge-gui/res/cardsfolder/a/agent_of_acquisitions.txt
Normal file
7
forge-gui/res/cardsfolder/a/agent_of_acquisitions.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Agent of Acquisitions
|
||||||
|
ManaCost:2
|
||||||
|
Types:Artifact Creature Construct
|
||||||
|
PT:2/1
|
||||||
|
Draft:Draft CARDNAME face up.
|
||||||
|
Draft:Instead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn CARDNAME face down and you can’t draft cards for the rest of this draft round. (You may look at booster packs passed to you.)
|
||||||
|
Oracle:Draft Agent of Acquisitions face up.\nInstead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn Agent of Acquisitions face down and you can’t draft cards for the rest of this draft round. (You may look at booster packs passed to you.)
|
||||||
@@ -4,6 +4,6 @@ Types:Creature Human
|
|||||||
PT:3/1
|
PT:3/1
|
||||||
K:Squad:2
|
K:Squad:2
|
||||||
K:CARDNAME can't block.
|
K:CARDNAME can't block.
|
||||||
A:AB$ Pump | PrecostDesc$ Endurant — | Cost$ PayLife<3> | KW$ Indestructible | SpellDescription$ CARDNAME gains indestructible until end of turn.
|
A:AB$ Pump | PrecostDesc$ Endurant — | Cost$ PayLife<3> | KW$ Indestructible | Defined$ Self | SpellDescription$ CARDNAME gains indestructible until end of turn.
|
||||||
DeckHas:Ability$Token
|
DeckHas:Ability$Token
|
||||||
Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nArco-Flagellant can't block.\nEndurant — Pay 3 life: Arco-Flagellant gains indestructible until end of turn.
|
Oracle:Squad {2} (As an additional cost to cast this spell, you may pay {2} any number of times. When this creature enters the battlefield, create that many tokens that are copies of it.)\nArco-Flagellant can't block.\nEndurant — Pay 3 life: Arco-Flagellant gains indestructible until end of turn.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Astral Arena
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Plane Kolbahan
|
Types:Plane Kolbahan
|
||||||
S:Mode$ AttackRestrict | EffectZone$ Command | MaxAttackers$ 1 | Description$ No more than one creature can attack each combat.
|
S:Mode$ AttackRestrict | EffectZone$ Command | MaxAttackers$ 1 | Description$ No more than one creature can attack each combat.
|
||||||
S:Mode$ Continuous | EffectZone$ Command | GlobalRule$ No more than one creature can block each combat. | Description$ No more than one creature can block each combat.
|
S:Mode$ BlockRestrict | EffectZone$ Command | MaxBlockers$ 1 | Description$ No more than one creature can block each combat.
|
||||||
T:Mode$ ChaosEnsues | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever chaos ensues, CARDNAME deals 2 damage to each creature.
|
T:Mode$ ChaosEnsues | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever chaos ensues, CARDNAME deals 2 damage to each creature.
|
||||||
SVar:RolledChaos:DB$ DamageAll | NumDmg$ 2 | ValidCards$ Creature
|
SVar:RolledChaos:DB$ DamageAll | NumDmg$ 2 | ValidCards$ Creature
|
||||||
SVar:AIRollPlanarDieParams:Mode$ Random | MinTurn$ 5
|
SVar:AIRollPlanarDieParams:Mode$ Random | MinTurn$ 5
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Creature Elemental Knight
|
|||||||
PT:5/6
|
PT:5/6
|
||||||
K:Reach
|
K:Reach
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | TriggerDescription$ When CARDNAME enters the battlefield, reveal the top five cards of your library. Put a land card from among them onto the battlefield and the rest into your graveyard.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | TriggerDescription$ When CARDNAME enters the battlefield, reveal the top five cards of your library. Put a land card from among them onto the battlefield and the rest into your graveyard.
|
||||||
SVar:TrigDig:DB$ Dig | DigNum$ 5 | ChangeNum$ 1 | ChangeValid$ Land | Optional$ True | DestinationZone$ Battlefield | DestinationZone2$ Graveyard
|
SVar:TrigDig:DB$ Dig | DigNum$ 5 | ChangeNum$ 1 | ChangeValid$ Land | DestinationZone$ Battlefield | DestinationZone2$ Graveyard
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME dies, you may exile it. If you do, put another target card from your graveyard on top of your library.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME dies, you may exile it. If you do, put another target card from your graveyard on top of your library.
|
||||||
SVar:TrigExile:AB$ ChangeZone | Cost$ ExileAnyGrave<1/Card.TriggeredNewCard> | Origin$ Graveyard | Destination$ Library | ValidTgts$ Card.YouOwn+Other | TgtPrompt$ Select another target card from your graveyard | AITgts$ Card.Other
|
SVar:TrigExile:AB$ ChangeZone | Cost$ ExileAnyGrave<1/Card.TriggeredNewCard> | Origin$ Graveyard | Destination$ Library | ValidTgts$ Card.YouOwn+Other | TgtPrompt$ Select another target card from your graveyard | AITgts$ Card.Other
|
||||||
DeckHas:Ability$Graveyard
|
DeckHas:Ability$Graveyard
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Caverns of Despair
|
|||||||
ManaCost:2 R R
|
ManaCost:2 R R
|
||||||
Types:World Enchantment
|
Types:World Enchantment
|
||||||
S:Mode$ AttackRestrict | MaxAttackers$ 2 | Description$ No more than two creatures can attack each combat.
|
S:Mode$ AttackRestrict | MaxAttackers$ 2 | Description$ No more than two creatures can attack each combat.
|
||||||
S:Mode$ Continuous | GlobalRule$ No more than two creatures can block each combat. | Description$ No more than two creatures can block each combat.
|
S:Mode$ BlockRestrict | MaxBlockers$ 2 | Description$ No more than two creatures can block each combat.
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
DeckHints:Type$Planeswalker|Artifact|Enchantment|Aura|Equipment
|
DeckHints:Type$Planeswalker|Artifact|Enchantment|Aura|Equipment
|
||||||
|
|||||||
7
forge-gui/res/cardsfolder/c/cogwork_librarian.txt
Normal file
7
forge-gui/res/cardsfolder/c/cogwork_librarian.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Cogwork Librarian
|
||||||
|
ManaCost:4
|
||||||
|
Types:Artifact Creature Construct
|
||||||
|
PT:3/3
|
||||||
|
Draft:Draft CARDNAME face up.
|
||||||
|
Draft:As you draft a card, you may draft an additional card from that booster pack. If you do, put CARDNAME into that booster pack.
|
||||||
|
Oracle:Draft Cogwork Librarian face up.\nAs you draft a card, you may draft an additional card from that booster pack. If you do, put Cogwork Librarian into that booster pack.
|
||||||
@@ -2,6 +2,6 @@ Name:Dueling Grounds
|
|||||||
ManaCost:1 G W
|
ManaCost:1 G W
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
S:Mode$ AttackRestrict | MaxAttackers$ 1 | Description$ No more than one creature can attack each combat.
|
S:Mode$ AttackRestrict | MaxAttackers$ 1 | Description$ No more than one creature can attack each combat.
|
||||||
S:Mode$ Continuous | GlobalRule$ No more than one creature can block each combat. | Description$ No more than one creature can block each combat.
|
S:Mode$ BlockRestrict | MaxBlockers$ 1 | Description$ No more than one creature can block each combat.
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
Oracle:No more than one creature can attack each combat.\nNo more than one creature can block each combat.
|
Oracle:No more than one creature can attack each combat.\nNo more than one creature can block each combat.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user