mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
Compare commits
1 Commits
cardTraitC
...
precalc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f3a9cd22e |
2
.github/workflows/test-build.yaml
vendored
2
.github/workflows/test-build.yaml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
java: ['17', '21']
|
||||
java: [ '17' ]
|
||||
name: Test with Java ${{ matrix.Java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -66,9 +66,6 @@ forge-gui-mobile-dev/testAssets
|
||||
|
||||
forge-gui/res/cardsfolder/*.bat
|
||||
|
||||
# Generated changelog file
|
||||
forge-gui/release-files/CHANGES.txt
|
||||
|
||||
forge-gui/res/PerSetTrackingResults
|
||||
forge-gui/res/decks
|
||||
forge-gui/res/layouts
|
||||
|
||||
33
.gitlab/issue_templates/Bug.md
Normal file
33
.gitlab/issue_templates/Bug.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Summary
|
||||
|
||||
(Summarize the bug encountered concisely)
|
||||
|
||||
|
||||
Steps to reproduce
|
||||
|
||||
(How one can reproduce the issue - this is very important. Specific cards and specific actions especially)
|
||||
|
||||
|
||||
Which version of Forge are you on (Release, Snapshot? Desktop, Android?)
|
||||
|
||||
|
||||
What is the current bug behavior?
|
||||
|
||||
(What actually happens)
|
||||
|
||||
|
||||
What is the expected correct behavior?
|
||||
|
||||
(What you should see instead)
|
||||
|
||||
|
||||
Relevant logs and/or screenshots
|
||||
|
||||
(Paste/Attach your game.log from the crash - please use code blocks (```)) Also, provide screenshots of the current state.
|
||||
|
||||
|
||||
Possible fixes
|
||||
|
||||
(If you can, link to the line of code that might be responsible for the problem)
|
||||
|
||||
/label ~needs-investigation
|
||||
15
.gitlab/issue_templates/Feature.md
Normal file
15
.gitlab/issue_templates/Feature.md
Normal file
@@ -0,0 +1,15 @@
|
||||
Summary
|
||||
|
||||
(Summarize the feature you wish concisely)
|
||||
|
||||
|
||||
Example screenshots
|
||||
|
||||
(If this is a UI change, please provide an example screenshot of how this feature might work)
|
||||
|
||||
|
||||
Feature type
|
||||
|
||||
(Where in Forge does this belong? e.g. Quest Mode, Deck Editor, Limited, Constructed, etc.)
|
||||
|
||||
/label ~feature request
|
||||
@@ -563,7 +563,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
int thisRemove = Math.min(prefCard.getCounters(cType), stillToRemove);
|
||||
if (thisRemove > 0) {
|
||||
removed += thisRemove;
|
||||
table.put(null, prefCard, cType, thisRemove);
|
||||
table.put(null, prefCard, CounterType.get(cType), thisRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,7 +573,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
@Override
|
||||
public PaymentDecision visit(CostRemoveAnyCounter cost) {
|
||||
final int c = cost.getAbilityAmount(ability);
|
||||
final Card originalHost = ObjectUtils.getIfNull(ability.getOriginalHost(), source);
|
||||
final Card originalHost = ObjectUtils.defaultIfNull(ability.getOriginalHost(), source);
|
||||
|
||||
if (c <= 0) {
|
||||
return null;
|
||||
@@ -716,7 +716,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
int over = Math.min(crd.getCounters(CounterEnumType.QUEST) - e, c - toRemove);
|
||||
if (over > 0) {
|
||||
toRemove += over;
|
||||
table.put(null, crd, CounterEnumType.QUEST, over);
|
||||
table.put(null, crd, CounterType.get(CounterEnumType.QUEST), over);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,7 +767,7 @@ public class ComputerUtil {
|
||||
public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) {
|
||||
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
|
||||
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterEnumType.STUN));
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
|
||||
if (untap) {
|
||||
typeList.remove(activate);
|
||||
@@ -2542,7 +2542,7 @@ public class ComputerUtil {
|
||||
|
||||
boolean opponent = controller.isOpponentOf(ai);
|
||||
|
||||
final CounterType p1p1Type = CounterEnumType.P1P1;
|
||||
final CounterType p1p1Type = CounterType.get(CounterEnumType.P1P1);
|
||||
|
||||
if (!sa.hasParam("AILogic")) {
|
||||
return Aggregates.random(options);
|
||||
|
||||
@@ -171,7 +171,7 @@ public class SpecialAiLogic {
|
||||
final boolean isInfect = source.hasKeyword(Keyword.INFECT); // Flesh-Eater Imp
|
||||
int lethalDmg = isInfect ? 10 - defPlayer.getPoisonCounters() : defPlayer.getLife();
|
||||
|
||||
if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterEnumType.POISON)) {
|
||||
if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
lethalDmg = Integer.MAX_VALUE; // won't be able to deal poison damage to kill the opponent
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public class SpecialAiLogic {
|
||||
final boolean isInfect = source.hasKeyword(Keyword.INFECT);
|
||||
int lethalDmg = isInfect ? 10 - defPlayer.getPoisonCounters() : defPlayer.getLife();
|
||||
|
||||
if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterEnumType.POISON)) {
|
||||
if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
lethalDmg = Integer.MAX_VALUE; // won't be able to deal poison damage to kill the opponent
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public abstract class CountersAi extends SpellAbilityAi {
|
||||
} else if (type.equals("DIVINITY")) {
|
||||
final CardCollection boon = CardLists.filter(list, c -> c.getCounters(CounterEnumType.DIVINITY) == 0);
|
||||
choice = ComputerUtilCard.getMostExpensivePermanentAI(boon);
|
||||
} else if (CounterType.getType(type).isKeywordCounter()) {
|
||||
} else if (CounterType.get(type).isKeywordCounter()) {
|
||||
choice = ComputerUtilCard.getBestCreatureAI(CardLists.getNotKeyword(list, type));
|
||||
} else {
|
||||
// The AI really should put counters on cards that can use it.
|
||||
|
||||
@@ -154,7 +154,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
if (counterType == null || counterType.is(type)) {
|
||||
addTargetsByCounterType(ai, sa, aiList, type);
|
||||
addTargetsByCounterType(ai, sa, aiList, CounterType.get(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
if (!oppList.isEmpty()) {
|
||||
// not enough targets
|
||||
if (sa.canAddMoreTarget()) {
|
||||
final CounterType type = CounterEnumType.M1M1;
|
||||
final CounterType type = CounterType.get(CounterEnumType.M1M1);
|
||||
if (counterType == null || counterType == type) {
|
||||
addTargetsByCounterType(ai, sa, oppList, type);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
|
||||
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
// Proliferate is always optional for all, no need to select best
|
||||
|
||||
final CounterType poison = CounterEnumType.POISON;
|
||||
final CounterType poison = CounterType.get(CounterEnumType.POISON);
|
||||
|
||||
boolean aggroAI = (((PlayerControllerAi) ai.getController()).getAi()).getBooleanProperty(AiProps.PLAY_AGGRO);
|
||||
// because countertype can't be chosen anymore, only look for poison counters
|
||||
|
||||
@@ -170,7 +170,7 @@ public class CountersPutAi extends CountersAi {
|
||||
CardCollection oppCreatM1 = CardLists.filter(oppCreat, CardPredicates.hasCounter(CounterEnumType.M1M1));
|
||||
oppCreatM1 = CardLists.getNotKeyword(oppCreatM1, Keyword.UNDYING);
|
||||
|
||||
oppCreatM1 = CardLists.filter(oppCreatM1, input -> input.getNetToughness() <= 1 && input.canReceiveCounters(CounterEnumType.M1M1));
|
||||
oppCreatM1 = CardLists.filter(oppCreatM1, input -> input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1)));
|
||||
|
||||
Card best = ComputerUtilCard.getBestAI(oppCreatM1);
|
||||
if (best != null) {
|
||||
@@ -336,7 +336,7 @@ public class CountersPutAi extends CountersAi {
|
||||
Game game = ai.getGame();
|
||||
Combat combat = game.getCombat();
|
||||
|
||||
if (!source.canReceiveCounters(CounterEnumType.P1P1) || source.getCounters(CounterEnumType.P1P1) > 0) {
|
||||
if (!source.canReceiveCounters(CounterType.get(CounterEnumType.P1P1)) || source.getCounters(CounterEnumType.P1P1) > 0) {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
} else if (combat != null && ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||
return doCombatAdaptLogic(source, amount, combat);
|
||||
@@ -608,7 +608,7 @@ public class CountersPutAi extends CountersAi {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.MissingNeededCards);
|
||||
}
|
||||
|
||||
final int currCounters = cards.get(0).getCounters(CounterType.getType(type));
|
||||
final int currCounters = cards.get(0).getCounters(CounterType.get(type));
|
||||
// each non +1/+1 counter on the card is a 10% chance of not
|
||||
// activating this ability.
|
||||
|
||||
@@ -623,7 +623,7 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
|
||||
// Useless since the card already has the keyword (or for another reason)
|
||||
if (ComputerUtil.isUselessCounter(CounterType.getType(type), cards.get(0))) {
|
||||
if (ComputerUtil.isUselessCounter(CounterType.get(type), cards.get(0))) {
|
||||
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
|
||||
}
|
||||
}
|
||||
@@ -961,8 +961,8 @@ public class CountersPutAi extends CountersAi {
|
||||
protected Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
// Bolster does use this
|
||||
// TODO need more or less logic there?
|
||||
final CounterType m1m1 = CounterEnumType.M1M1;
|
||||
final CounterType p1p1 = CounterEnumType.P1P1;
|
||||
final CounterType m1m1 = CounterType.get(CounterEnumType.M1M1);
|
||||
final CounterType p1p1 = CounterType.get(CounterEnumType.P1P1);
|
||||
|
||||
// no logic if there is no options or no to choice
|
||||
if (!isOptional && Iterables.size(options) <= 1) {
|
||||
@@ -1083,8 +1083,8 @@ public class CountersPutAi extends CountersAi {
|
||||
if (e instanceof Card) {
|
||||
Card c = (Card) e;
|
||||
if (c.getController().isOpponentOf(ai)) {
|
||||
if (options.contains(CounterEnumType.M1M1) && !c.hasKeyword(Keyword.UNDYING)) {
|
||||
return CounterEnumType.M1M1;
|
||||
if (options.contains(CounterType.get(CounterEnumType.M1M1)) && !c.hasKeyword(Keyword.UNDYING)) {
|
||||
return CounterType.get(CounterEnumType.M1M1);
|
||||
}
|
||||
for (CounterType type : options) {
|
||||
if (ComputerUtil.isNegativeCounter(type, c)) {
|
||||
@@ -1101,12 +1101,12 @@ public class CountersPutAi extends CountersAi {
|
||||
} else if (e instanceof Player) {
|
||||
Player p = (Player) e;
|
||||
if (p.isOpponentOf(ai)) {
|
||||
if (options.contains(CounterEnumType.POISON)) {
|
||||
return CounterEnumType.POISON;
|
||||
if (options.contains(CounterType.get(CounterEnumType.POISON))) {
|
||||
return CounterType.get(CounterEnumType.POISON);
|
||||
}
|
||||
} else {
|
||||
if (options.contains(CounterEnumType.EXPERIENCE)) {
|
||||
return CounterEnumType.EXPERIENCE;
|
||||
if (options.contains(CounterType.get(CounterEnumType.EXPERIENCE))) {
|
||||
return CounterType.get(CounterEnumType.EXPERIENCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -218,18 +218,18 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
|
||||
Card tgt = (Card) params.get("Target");
|
||||
|
||||
// planeswalker has high priority for loyalty counters
|
||||
if (tgt.isPlaneswalker() && options.contains(CounterEnumType.LOYALTY)) {
|
||||
return CounterEnumType.LOYALTY;
|
||||
if (tgt.isPlaneswalker() && options.contains(CounterType.get(CounterEnumType.LOYALTY))) {
|
||||
return CounterType.get(CounterEnumType.LOYALTY);
|
||||
}
|
||||
|
||||
if (tgt.getController().isOpponentOf(ai)) {
|
||||
// creatures with BaseToughness below or equal zero might be
|
||||
// killed if their counters are removed
|
||||
if (tgt.isCreature() && tgt.getBaseToughness() <= 0) {
|
||||
if (options.contains(CounterEnumType.P1P1)) {
|
||||
return CounterEnumType.P1P1;
|
||||
} else if (options.contains(CounterEnumType.M1M1)) {
|
||||
return CounterEnumType.M1M1;
|
||||
if (options.contains(CounterType.get(CounterEnumType.P1P1))) {
|
||||
return CounterType.get(CounterEnumType.P1P1);
|
||||
} else if (options.contains(CounterType.get(CounterEnumType.M1M1))) {
|
||||
return CounterType.get(CounterEnumType.M1M1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,17 +241,17 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
|
||||
}
|
||||
} else {
|
||||
// this counters are treat first to be removed
|
||||
if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterEnumType.ICE)) {
|
||||
if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.get(CounterEnumType.ICE))) {
|
||||
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
|
||||
|
||||
if (maritEmpty) {
|
||||
return CounterEnumType.ICE;
|
||||
return CounterType.get(CounterEnumType.ICE);
|
||||
}
|
||||
} else if (tgt.hasKeyword(Keyword.UNDYING) && options.contains(CounterEnumType.P1P1)) {
|
||||
return CounterEnumType.P1P1;
|
||||
} else if (tgt.hasKeyword(Keyword.PERSIST) && options.contains(CounterEnumType.M1M1)) {
|
||||
return CounterEnumType.M1M1;
|
||||
} else if (tgt.hasKeyword(Keyword.UNDYING) && options.contains(CounterType.get(CounterEnumType.P1P1))) {
|
||||
return CounterType.get(CounterEnumType.P1P1);
|
||||
} else if (tgt.hasKeyword(Keyword.PERSIST) && options.contains(CounterType.get(CounterEnumType.M1M1))) {
|
||||
return CounterType.get(CounterEnumType.M1M1);
|
||||
}
|
||||
|
||||
// fallback logic, select positive counter to add more
|
||||
|
||||
@@ -384,7 +384,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
||||
if (targetCard.getController().isOpponentOf(ai)) {
|
||||
// if its a Planeswalker try to remove Loyality first
|
||||
if (targetCard.isPlaneswalker()) {
|
||||
return CounterEnumType.LOYALTY;
|
||||
return CounterType.get(CounterEnumType.LOYALTY);
|
||||
}
|
||||
for (CounterType type : options) {
|
||||
if (!ComputerUtil.isNegativeCounter(type, targetCard)) {
|
||||
@@ -392,10 +392,10 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.contains(CounterEnumType.M1M1) && targetCard.hasKeyword(Keyword.PERSIST)) {
|
||||
return CounterEnumType.M1M1;
|
||||
} else if (options.contains(CounterEnumType.P1P1) && targetCard.hasKeyword(Keyword.UNDYING)) {
|
||||
return CounterEnumType.P1P1;
|
||||
if (options.contains(CounterType.get(CounterEnumType.M1M1)) && targetCard.hasKeyword(Keyword.PERSIST)) {
|
||||
return CounterType.get(CounterEnumType.M1M1);
|
||||
} else if (options.contains(CounterType.get(CounterEnumType.P1P1)) && targetCard.hasKeyword(Keyword.UNDYING)) {
|
||||
return CounterType.get(CounterEnumType.P1P1);
|
||||
}
|
||||
for (CounterType type : options) {
|
||||
if (ComputerUtil.isNegativeCounter(type, targetCard)) {
|
||||
|
||||
@@ -133,9 +133,9 @@ public class DamageAllAi extends SpellAbilityAi {
|
||||
if (ComputerUtilCombat.predictDamageTo(opp, dmg, source, false) > 0) {
|
||||
// When using Pestilence to hurt players, do it at
|
||||
// the end of the opponent's turn only
|
||||
if (!"DmgAllCreaturesAndPlayers".equals(sa.getParam("AILogic"))
|
||||
|| (ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
|
||||
&& !ai.getGame().getPhaseHandler().isPlayerTurn(ai)))
|
||||
if ((!"DmgAllCreaturesAndPlayers".equals(sa.getParam("AILogic")))
|
||||
|| ((ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
|
||||
&& (ai.getGame().getNonactivePlayers().contains(ai)))))
|
||||
// Need further improvement : if able to kill immediately with repeated activations, do not wait
|
||||
// for phases! Will also need to implement considering repeated activations for killed creatures!
|
||||
// || (ai.sa.getPayCosts(). ??? )
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.cost.*;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
@@ -369,7 +370,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
|
||||
// try to make opponent lose to poison
|
||||
// currently only Caress of Phyrexia
|
||||
if (getPoison != null && oppA.canReceiveCounters(CounterEnumType.POISON)) {
|
||||
if (getPoison != null && oppA.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
if (oppA.getPoisonCounters() + numCards > 9) {
|
||||
sa.getTargets().add(oppA);
|
||||
return true;
|
||||
@@ -413,7 +414,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
if (getPoison != null && ai.canReceiveCounters(CounterEnumType.POISON)) {
|
||||
if (getPoison != null && ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
if (numCards + ai.getPoisonCounters() >= 8) {
|
||||
aiTarget = false;
|
||||
}
|
||||
@@ -471,7 +472,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// ally would lose because of poison
|
||||
if (getPoison != null && ally.canReceiveCounters(CounterEnumType.POISON) && ally.getPoisonCounters() + numCards > 9) {
|
||||
if (getPoison != null && ally.canReceiveCounters(CounterType.get(CounterEnumType.POISON)) && ally.getPoisonCounters() + numCards > 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ public class ManaAi extends SpellAbilityAi {
|
||||
int numCounters = 0;
|
||||
int manaSurplus = 0;
|
||||
if ("Count$xPaid".equals(host.getSVar("X")) && sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
|
||||
CounterType ctrType = CounterEnumType.KI; // Petalmane Baku
|
||||
CounterType ctrType = CounterType.get(CounterEnumType.KI); // Petalmane Baku
|
||||
for (CostPart part : sa.getPayCosts().getCostParts()) {
|
||||
if (part instanceof CostRemoveCounter) {
|
||||
ctrType = ((CostRemoveCounter)part).counter;
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.ai.ComputerUtil;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.GameLossReason;
|
||||
@@ -64,7 +65,7 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
boolean result;
|
||||
if (sa.usesTargeting()) {
|
||||
result = tgtPlayer(ai, sa, mandatory);
|
||||
} else if (mandatory || !ai.canReceiveCounters(CounterEnumType.POISON)) {
|
||||
} else if (mandatory || !ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
// mandatory or ai is uneffected
|
||||
result = true;
|
||||
} else {
|
||||
@@ -89,7 +90,7 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
PlayerCollection betterTgts = tgts.filter(input -> {
|
||||
if (input.cantLoseCheck(GameLossReason.Poisoned)) {
|
||||
return false;
|
||||
} else if (!input.canReceiveCounters(CounterEnumType.POISON)) {
|
||||
} else if (!input.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -108,7 +109,7 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
if (tgts.isEmpty()) {
|
||||
if (mandatory) {
|
||||
// AI is uneffected
|
||||
if (ai.canBeTargetedBy(sa) && !ai.canReceiveCounters(CounterEnumType.POISON)) {
|
||||
if (ai.canBeTargetedBy(sa) && !ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
sa.getTargets().add(ai);
|
||||
return true;
|
||||
}
|
||||
@@ -120,7 +121,7 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
if (input.cantLoseCheck(GameLossReason.Poisoned)) {
|
||||
return true;
|
||||
}
|
||||
return !input.canReceiveCounters(CounterEnumType.POISON);
|
||||
return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON));
|
||||
});
|
||||
if (!betterAllies.isEmpty()) {
|
||||
allies = betterAllies;
|
||||
|
||||
@@ -8,6 +8,7 @@ import forge.ai.SpellAbilityAi;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerController;
|
||||
@@ -39,7 +40,7 @@ public class TimeTravelAi extends SpellAbilityAi {
|
||||
// so removing them is good; stuff on the battlefield is usually stuff like Vanishing or As Foretold, which favors adding Time
|
||||
// counters for better effect, but exceptions should be added here).
|
||||
Card target = (Card)params.get("Target");
|
||||
return !ComputerUtil.isNegativeCounter(CounterEnumType.TIME, target);
|
||||
return !ComputerUtil.isNegativeCounter(CounterType.get(CounterEnumType.TIME), target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.util.stream.Collectors;
|
||||
public class StaticData {
|
||||
private final CardStorageReader cardReader;
|
||||
private final CardStorageReader tokenReader;
|
||||
private final CardStorageReader customCardReader;
|
||||
|
||||
private final String blockDataFolder;
|
||||
private final CardDb commonCards;
|
||||
private final CardDb variantCards;
|
||||
@@ -77,6 +79,7 @@ public class StaticData {
|
||||
this.tokenReader = tokenReader;
|
||||
this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder)));
|
||||
this.blockDataFolder = blockDataFolder;
|
||||
this.customCardReader = customCardReader;
|
||||
this.allowCustomCardsInDecksConformance = allowCustomCardsInDecksConformance;
|
||||
this.enableSmartCardArtSelection = enableSmartCardArtSelection;
|
||||
this.loadNonLegalCards = loadNonLegalCards;
|
||||
|
||||
@@ -649,37 +649,31 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sectionName.endsWith("Types")) {
|
||||
CardType.Helper.parseTypes(sectionName, contents.get(sectionName));
|
||||
} else {
|
||||
// Parse cards
|
||||
// parse sections of the format "<collector number> <rarity> <name>"
|
||||
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
|
||||
for(String line : contents.get(sectionName)) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
// parse sections of the format "<collector number> <rarity> <name>"
|
||||
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
|
||||
for(String line : contents.get(sectionName)) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String collectorNumber = matcher.group(2);
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
|
||||
String cardName = matcher.group(5);
|
||||
String artistName = matcher.group(7);
|
||||
String functionalVariantName = matcher.group(9);
|
||||
EditionEntry cis = new EditionEntry(cardName, collectorNumber, r, artistName, functionalVariantName);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
} else if (boosterSlotsToParse.contains(sectionName)) {
|
||||
// parse booster slots of the format "Base=N\n|Replace=<amount> <sheet>"
|
||||
boosterSlots.add(BoosterSlot.parseSlot(sectionName, contents.get(sectionName)));
|
||||
} else {
|
||||
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
|
||||
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
|
||||
customPrintSheetsToParse.put(sectionName, contents.get(sectionName));
|
||||
|
||||
String collectorNumber = matcher.group(2);
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
|
||||
String cardName = matcher.group(5);
|
||||
String artistName = matcher.group(7);
|
||||
String functionalVariantName = matcher.group(9);
|
||||
EditionEntry cis = new EditionEntry(cardName, collectorNumber, r, artistName, functionalVariantName);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
}
|
||||
} else if (boosterSlotsToParse.contains(sectionName)) {
|
||||
// parse booster slots of the format "Base=N\n|Replace=<amount> <sheet>"
|
||||
boosterSlots.add(BoosterSlot.parseSlot(sectionName, contents.get(sectionName)));
|
||||
} else {
|
||||
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
|
||||
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
|
||||
customPrintSheetsToParse.put(sectionName, contents.get(sectionName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,7 +840,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
@Override
|
||||
public void add(CardEdition item) { //Even though we want it to be read only, make an exception for custom content.
|
||||
if(lock) throw new UnsupportedOperationException("This is a read-only storage");
|
||||
else map.put(item.getCode(), item);
|
||||
else map.put(item.getName(), item);
|
||||
}
|
||||
public void append(CardEdition.Collection C){ //Append custom editions
|
||||
if (lock) throw new UnsupportedOperationException("This is a read-only storage");
|
||||
|
||||
@@ -53,7 +53,6 @@ public final class CardRules implements ICardCharacteristics {
|
||||
private boolean addsWildCardColor;
|
||||
private int setColorID;
|
||||
private boolean custom;
|
||||
private boolean unsupported;
|
||||
private String path;
|
||||
|
||||
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
|
||||
@@ -221,9 +220,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
|
||||
public boolean isCustom() { return custom; }
|
||||
public void setCustom() { custom = true; }
|
||||
|
||||
public boolean isUnsupported() { return unsupported; }
|
||||
public void setCustom() { custom = true; }
|
||||
|
||||
@Override
|
||||
public CardType getType() {
|
||||
@@ -376,9 +373,6 @@ public final class CardRules implements ICardCharacteristics {
|
||||
|
||||
public boolean canBeOathbreaker() {
|
||||
CardType type = mainPart.getType();
|
||||
if (mainPart.getOracleText().contains("can be your commander")) {
|
||||
return true;
|
||||
}
|
||||
return type.isPlaneswalker();
|
||||
}
|
||||
|
||||
@@ -831,8 +825,6 @@ public final class CardRules implements ICardCharacteristics {
|
||||
faces[0].assignMissingFields();
|
||||
final CardRules result = new CardRules(faces, CardSplitType.None, cah);
|
||||
|
||||
result.unsupported = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,31 +196,6 @@ public final class CardRulesPredicates {
|
||||
return card -> card.getSplitType().equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Predicate that matches cards that are vanilla.
|
||||
*/
|
||||
public static Predicate<CardRules> isVanilla() {
|
||||
return card -> {
|
||||
if (!(card.getType().isCreature() || card.getType().isLand()) ||
|
||||
card.getSplitType() != CardSplitType.None ||
|
||||
card.hasFunctionalVariants()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ICardFace mainPart = card.getMainPart();
|
||||
|
||||
boolean hasAny =
|
||||
mainPart.getKeywords().iterator().hasNext() ||
|
||||
mainPart.getAbilities().iterator().hasNext() ||
|
||||
mainPart.getStaticAbilities().iterator().hasNext() ||
|
||||
mainPart.getTriggers().iterator().hasNext() ||
|
||||
(mainPart.getDraftActions() != null && mainPart.getDraftActions().iterator().hasNext()) ||
|
||||
mainPart.getReplacements().iterator().hasNext();
|
||||
|
||||
return !hasAny;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for color.
|
||||
*
|
||||
|
||||
@@ -1066,74 +1066,4 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static class Helper {
|
||||
public static final void parseTypes(String sectionName, List<String> content) {
|
||||
Set<String> addToSection = null;
|
||||
|
||||
switch (sectionName) {
|
||||
case "BasicTypes":
|
||||
addToSection = CardType.Constant.BASIC_TYPES;
|
||||
break;
|
||||
case "LandTypes":
|
||||
addToSection = CardType.Constant.LAND_TYPES;
|
||||
break;
|
||||
case "CreatureTypes":
|
||||
addToSection = CardType.Constant.CREATURE_TYPES;
|
||||
break;
|
||||
case "SpellTypes":
|
||||
addToSection = CardType.Constant.SPELL_TYPES;
|
||||
break;
|
||||
case "EnchantmentTypes":
|
||||
addToSection = CardType.Constant.ENCHANTMENT_TYPES;
|
||||
break;
|
||||
case "ArtifactTypes":
|
||||
addToSection = CardType.Constant.ARTIFACT_TYPES;
|
||||
break;
|
||||
case "WalkerTypes":
|
||||
addToSection = CardType.Constant.WALKER_TYPES;
|
||||
break;
|
||||
case "DungeonTypes":
|
||||
addToSection = CardType.Constant.DUNGEON_TYPES;
|
||||
break;
|
||||
case "BattleTypes":
|
||||
addToSection = CardType.Constant.BATTLE_TYPES;
|
||||
break;
|
||||
case "PlanarTypes":
|
||||
addToSection = CardType.Constant.PLANAR_TYPES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (addToSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(String line : content) {
|
||||
if (line.length() == 0) continue;
|
||||
|
||||
if (line.contains(":")) {
|
||||
String[] k = line.split(":");
|
||||
|
||||
if (addToSection.contains(k[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addToSection.add(k[0]);
|
||||
CardType.Constant.pluralTypes.put(k[0], k[1]);
|
||||
|
||||
if (k[0].contains(" ")) {
|
||||
CardType.Constant.MultiwordTypes.add(k[0]);
|
||||
}
|
||||
} else {
|
||||
if (addToSection.contains(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addToSection.add(line);
|
||||
if (line.contains(" ")) {
|
||||
CardType.Constant.MultiwordTypes.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
this.artIndex = Math.max(artIndex, IPaperCard.DEFAULT_ART_INDEX);
|
||||
this.foil = foil;
|
||||
this.rarity = rarity;
|
||||
this.artist = artist;
|
||||
this.artist = TextUtil.normalizeText(artist);
|
||||
this.collectorNumber = (collectorNumber != null && !collectorNumber.isEmpty()) ? collectorNumber : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
// If the user changes the language this will make cards sort by the old language until they restart the game.
|
||||
// This is a good tradeoff
|
||||
@@ -375,8 +375,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
System.out.println("PaperCard: " + name + " not found with set and index " + edition + ", " + artIndex);
|
||||
pc = readObjectAlternate(name, edition);
|
||||
if (pc == null) {
|
||||
pc = StaticData.instance().getCommonCards().createUnsupportedCard(name);
|
||||
//throw new IOException(TextUtil.concatWithSpace("Card", name, "not found with set and index", edition, Integer.toString(artIndex)));
|
||||
throw new IOException(TextUtil.concatWithSpace("Card", name, "not found with set and index", edition, Integer.toString(artIndex)));
|
||||
}
|
||||
System.out.println("Alternate object found: " + pc.getName() + ", " + pc.getEdition() + ", " + pc.getArtIndex());
|
||||
}
|
||||
|
||||
@@ -414,6 +414,19 @@ public class Game {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nonactive players who are still fighting to win, in turn order.
|
||||
*/
|
||||
public final PlayerCollection getNonactivePlayers() {
|
||||
// Don't use getPlayersInTurnOrder to prevent copying the player collection twice
|
||||
final PlayerCollection players = new PlayerCollection(ingamePlayers);
|
||||
players.remove(phaseHandler.getPlayerTurn());
|
||||
if (!getTurnOrder().isDefaultDirection()) {
|
||||
Collections.reverse(players);
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the players who participated in match (regardless of outcome).
|
||||
* <i>Use this in UI and after match calculations</i>
|
||||
|
||||
@@ -1822,8 +1822,8 @@ public class GameAction {
|
||||
|
||||
private boolean stateBasedAction704_5q(Card c) {
|
||||
boolean checkAgain = false;
|
||||
final CounterType p1p1 = CounterEnumType.P1P1;
|
||||
final CounterType m1m1 = CounterEnumType.M1M1;
|
||||
final CounterType p1p1 = CounterType.get(CounterEnumType.P1P1);
|
||||
final CounterType m1m1 = CounterType.get(CounterEnumType.M1M1);
|
||||
int plusOneCounters = c.getCounters(p1p1);
|
||||
int minusOneCounters = c.getCounters(m1m1);
|
||||
if (plusOneCounters > 0 && minusOneCounters > 0) {
|
||||
@@ -1843,7 +1843,7 @@ public class GameAction {
|
||||
return checkAgain;
|
||||
}
|
||||
private boolean stateBasedAction704_5r(Card c) {
|
||||
final CounterType dreamType = CounterEnumType.DREAM;
|
||||
final CounterType dreamType = CounterType.get(CounterEnumType.DREAM);
|
||||
|
||||
int old = c.getCounters(dreamType);
|
||||
if (old <= 0) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.event.GameEventCardAttachment;
|
||||
import forge.game.keyword.Keyword;
|
||||
@@ -304,6 +305,9 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
Integer value = counters.get(counterName);
|
||||
return value == null ? 0 : value;
|
||||
}
|
||||
public final int getCounters(final CounterEnumType counterType) {
|
||||
return getCounters(CounterType.get(counterType));
|
||||
}
|
||||
|
||||
public void setCounters(final CounterType counterType, final Integer num) {
|
||||
if (num <= 0) {
|
||||
@@ -312,6 +316,9 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
counters.put(counterType, num);
|
||||
}
|
||||
}
|
||||
public void setCounters(final CounterEnumType counterType, final Integer num) {
|
||||
setCounters(CounterType.get(counterType), num);
|
||||
}
|
||||
|
||||
abstract public void setCounters(final Map<CounterType, Integer> allCounters);
|
||||
|
||||
@@ -321,6 +328,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
abstract public int subtractCounter(final CounterType counterName, final int n, final Player remover);
|
||||
abstract public void clearCounters();
|
||||
|
||||
public boolean canReceiveCounters(final CounterEnumType type) {
|
||||
return canReceiveCounters(CounterType.get(type));
|
||||
}
|
||||
|
||||
public final void addCounter(final CounterType counterType, int n, final Player source, GameEntityCounterTable table) {
|
||||
if (n <= 0 || !canReceiveCounters(counterType)) {
|
||||
// As per rule 107.1b
|
||||
@@ -340,7 +351,18 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
table.put(source, this, counterType, n);
|
||||
}
|
||||
|
||||
public final void addCounter(final CounterEnumType counterType, final int n, final Player source, GameEntityCounterTable table) {
|
||||
addCounter(CounterType.get(counterType), n, source, table);
|
||||
}
|
||||
|
||||
public int subtractCounter(final CounterEnumType counterName, final int n, final Player remover) {
|
||||
return subtractCounter(CounterType.get(counterName), n, remover);
|
||||
}
|
||||
|
||||
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params);
|
||||
public void addCounterInternal(final CounterEnumType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table, params);
|
||||
}
|
||||
public Integer getCounterMax(final CounterType counterType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -29,25 +29,25 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventGameOutcome ev) {
|
||||
// Turn number counted from the starting player
|
||||
int lastTurn = (int)Math.ceil((float)ev.result().getLastTurnNumber() / 2.0);
|
||||
int lastTurn = (int)Math.ceil((float)ev.result.getLastTurnNumber() / 2.0);
|
||||
log.add(GameLogEntryType.GAME_OUTCOME, localizer.getMessage("lblTurn") + " " + lastTurn);
|
||||
|
||||
for (String outcome : ev.result().getOutcomeStrings()) {
|
||||
for (String outcome : ev.result.getOutcomeStrings()) {
|
||||
log.add(GameLogEntryType.GAME_OUTCOME, outcome);
|
||||
}
|
||||
return generateSummary(ev.history());
|
||||
return generateSummary(ev.history);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventScry ev) {
|
||||
String scryOutcome = "";
|
||||
|
||||
if (ev.toTop() > 0 && ev.toBottom() > 0) {
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopBottomLibrary").replace("%s", ev.player().toString()).replace("%top", String.valueOf(ev.toTop())).replace("%bottom", String.valueOf(ev.toBottom()));
|
||||
} else if (ev.toBottom() == 0) {
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopLibrary").replace("%s", ev.player().toString()).replace("%top", String.valueOf(ev.toTop()));
|
||||
if (ev.toTop > 0 && ev.toBottom > 0) {
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopBottomLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop)).replace("%bottom", String.valueOf(ev.toBottom));
|
||||
} else if (ev.toBottom == 0) {
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop));
|
||||
} else {
|
||||
scryOutcome = localizer.getMessage("lblLogScryBottomLibrary").replace("%s", ev.player().toString()).replace("%bottom", String.valueOf(ev.toBottom()));
|
||||
scryOutcome = localizer.getMessage("lblLogScryBottomLibrary").replace("%s", ev.player.toString()).replace("%bottom", String.valueOf(ev.toBottom));
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, scryOutcome);
|
||||
@@ -57,12 +57,12 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
public GameLogEntry visit(GameEventSurveil ev) {
|
||||
String surveilOutcome = "";
|
||||
|
||||
if (ev.toLibrary() > 0 && ev.toGraveyard() > 0) {
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibraryGraveyard", ev.player().toString(), String.valueOf(ev.toLibrary()), String.valueOf(ev.toGraveyard()));
|
||||
} else if (ev.toGraveyard() == 0) {
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibrary", ev.player().toString(), String.valueOf(ev.toLibrary()));
|
||||
if (ev.toLibrary > 0 && ev.toGraveyard > 0) {
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibraryGraveyard", ev.player.toString(), String.valueOf(ev.toLibrary), String.valueOf(ev.toGraveyard));
|
||||
} else if (ev.toGraveyard == 0) {
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibrary", ev.player.toString(), String.valueOf(ev.toLibrary));
|
||||
} else {
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToGraveyard", ev.player().toString(), String.valueOf(ev.toGraveyard()));
|
||||
surveilOutcome = localizer.getMessage("lblLogSurveiledToGraveyard", ev.player.toString(), String.valueOf(ev.toGraveyard));
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, surveilOutcome);
|
||||
@@ -70,26 +70,26 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventSpellResolved ev) {
|
||||
String messageForLog = ev.hasFizzled() ? localizer.getMessage("lblLogCardAbilityFizzles", ev.spell().getHostCard().toString()) : ev.spell().getStackDescription();
|
||||
String messageForLog = ev.hasFizzled ? localizer.getMessage("lblLogCardAbilityFizzles", ev.spell.getHostCard().toString()) : ev.spell.getStackDescription();
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, messageForLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventSpellAbilityCast event) {
|
||||
String player = event.sa().getActivatingPlayer().getName();
|
||||
String action = event.sa().isSpell() ? localizer.getMessage("lblCast")
|
||||
: event.sa().isTrigger() ? localizer.getMessage("lblTriggered")
|
||||
String player = event.sa.getActivatingPlayer().getName();
|
||||
String action = event.sa.isSpell() ? localizer.getMessage("lblCast")
|
||||
: event.sa.isTrigger() ? localizer.getMessage("lblTriggered")
|
||||
: localizer.getMessage("lblActivated");
|
||||
String object = event.si().getStackDescription().startsWith("Morph ")
|
||||
String object = event.si.getStackDescription().startsWith("Morph ")
|
||||
? localizer.getMessage("lblMorph")
|
||||
: event.sa().getHostCard().toString();
|
||||
: event.sa.getHostCard().toString();
|
||||
|
||||
String messageForLog = "";
|
||||
|
||||
if (event.sa().getTargetRestrictions() != null) {
|
||||
if (event.sa.getTargetRestrictions() != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (TargetChoices ch : event.sa().getAllTargetChoices()) {
|
||||
for (TargetChoices ch : event.sa.getAllTargetChoices()) {
|
||||
if (null != ch) {
|
||||
sb.append(ch);
|
||||
}
|
||||
@@ -104,18 +104,18 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventCardModeChosen ev) {
|
||||
if (!ev.log()) {
|
||||
if (!ev.log) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String modeChoiceOutcome;
|
||||
if (ev.random()) {
|
||||
modeChoiceOutcome = localizer.getMessage("lblLogRandomMode", ev.cardName(), ev.mode());
|
||||
if (ev.random) {
|
||||
modeChoiceOutcome = localizer.getMessage("lblLogRandomMode", ev.cardName, ev.mode);
|
||||
} else {
|
||||
modeChoiceOutcome = localizer.getMessage("lblLogPlayerChosenModeForCard",
|
||||
ev.player().toString(), ev.mode(), ev.cardName());
|
||||
ev.player.toString(), ev.mode, ev.cardName);
|
||||
}
|
||||
String name = CardTranslation.getTranslatedName(ev.cardName());
|
||||
String name = CardTranslation.getTranslatedName(ev.cardName);
|
||||
modeChoiceOutcome = TextUtil.fastReplace(modeChoiceOutcome, "CARDNAME", name);
|
||||
modeChoiceOutcome = TextUtil.fastReplace(modeChoiceOutcome, "NICKNAME",
|
||||
Lang.getInstance().getNickName(name));
|
||||
@@ -124,7 +124,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventRandomLog ev) {
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, ev.message());
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, ev.message);
|
||||
}
|
||||
|
||||
private static GameLogEntry generateSummary(final Collection<GameOutcome> gamesPlayed) {
|
||||
@@ -152,8 +152,8 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(final GameEventPlayerControl event) {
|
||||
final LobbyPlayer newLobbyPlayer = event.newLobbyPlayer();
|
||||
final Player p = event.player();
|
||||
final LobbyPlayer newLobbyPlayer = event.newLobbyPlayer;
|
||||
final Player p = event.player;
|
||||
|
||||
final String message;
|
||||
if (newLobbyPlayer == null) {
|
||||
@@ -166,23 +166,23 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnPhase ev) {
|
||||
Player p = ev.playerTurn();
|
||||
return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc() + Lang.getInstance().getPossessedObject(p.getName(), ev.phase().nameForUi));
|
||||
Player p = ev.playerTurn;
|
||||
return new GameLogEntry(GameLogEntryType.PHASE, ev.phaseDesc + Lang.getInstance().getPossessedObject(p.getName(), ev.phase.nameForUi));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventCardDamaged event) {
|
||||
String additionalLog = "";
|
||||
if (event.type() == DamageType.Deathtouch) {
|
||||
if (event.type == DamageType.Deathtouch) {
|
||||
additionalLog = localizer.getMessage("lblDeathtouch");
|
||||
}
|
||||
if (event.type() == DamageType.M1M1Counters) {
|
||||
if (event.type == DamageType.M1M1Counters) {
|
||||
additionalLog = localizer.getMessage("lblAsM1M1Counters");
|
||||
}
|
||||
if (event.type() == DamageType.LoyaltyLoss) {
|
||||
additionalLog = localizer.getMessage("lblRemovingNLoyaltyCounter", String.valueOf(event.amount()));
|
||||
if (event.type == DamageType.LoyaltyLoss) {
|
||||
additionalLog = localizer.getMessage("lblRemovingNLoyaltyCounter", String.valueOf(event.amount));
|
||||
}
|
||||
String message = localizer.getMessage("lblSourceDealsNDamageToDest", event.source().toString(), String.valueOf(event.amount()), additionalLog, event.card().toString());
|
||||
String message = localizer.getMessage("lblSourceDealsNDamageToDest", event.source.toString(), String.valueOf(event.amount), additionalLog, event.card.toString());
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
@@ -191,43 +191,43 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
*/
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventLandPlayed ev) {
|
||||
String message = localizer.getMessage("lblLogPlayerPlayedLand", ev.player().toString(), ev.land().toString());
|
||||
String message = localizer.getMessage("lblLogPlayerPlayedLand", ev.player.toString(), ev.land.toString());
|
||||
return new GameLogEntry(GameLogEntryType.LAND, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventTurnBegan event) {
|
||||
String message = localizer.getMessage("lblLogTurnNOwnerByPlayer", String.valueOf(event.turnNumber()), event.turnOwner().toString());
|
||||
String message = localizer.getMessage("lblLogTurnNOwnerByPlayer", String.valueOf(event.turnNumber), event.turnOwner.toString());
|
||||
return new GameLogEntry(GameLogEntryType.TURN, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerDamaged ev) {
|
||||
String extra = ev.infect() ? localizer.getMessage("lblLogAsPoisonCounters") : "";
|
||||
String damageType = ev.combat() ? localizer.getMessage("lblCombat") : localizer.getMessage("lblNonCombat");
|
||||
String message = localizer.getMessage("lblLogSourceDealsNDamageOfTypeToDest", ev.source().toString(),
|
||||
String.valueOf(ev.amount()), damageType, ev.target().toString(), extra);
|
||||
String extra = ev.infect ? localizer.getMessage("lblLogAsPoisonCounters") : "";
|
||||
String damageType = ev.combat ? localizer.getMessage("lblCombat") : localizer.getMessage("lblNonCombat");
|
||||
String message = localizer.getMessage("lblLogSourceDealsNDamageOfTypeToDest", ev.source.toString(),
|
||||
String.valueOf(ev.amount), damageType, ev.target.toString(), extra);
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerPoisoned ev) {
|
||||
String message = localizer.getMessage("lblLogPlayerReceivesNPosionCounterFrom",
|
||||
ev.receiver().toString(), String.valueOf(ev.amount()), ev.source().toString());
|
||||
ev.receiver.toString(), String.valueOf(ev.amount), ev.source.toString());
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventPlayerRadiation ev) {
|
||||
String message;
|
||||
final int change = ev.change();
|
||||
final int change = ev.change;
|
||||
String radCtr = CounterEnumType.RAD.getName().toLowerCase() + " " +
|
||||
Localizer.getInstance().getMessage("lblCounter").toLowerCase();
|
||||
if (change >= 0) message = localizer.getMessage("lblLogPlayerRadiation",
|
||||
ev.receiver().toString(), Lang.nounWithNumeralExceptOne(String.valueOf(change), radCtr),
|
||||
ev.source().toString());
|
||||
ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(change), radCtr),
|
||||
ev.source.toString());
|
||||
else message = localizer.getMessage("lblLogPlayerRadRemove",
|
||||
ev.receiver().toString(), Lang.nounWithNumeralExceptOne(String.valueOf(Math.abs(change)), radCtr));
|
||||
ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(Math.abs(change)), radCtr));
|
||||
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
|
||||
}
|
||||
|
||||
@@ -239,16 +239,16 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
// Not a big fan of the triple nested loop here
|
||||
for (GameEntity k : ev.attackersMap().keySet()) {
|
||||
Collection<Card> attackers = ev.attackersMap().get(k);
|
||||
for (GameEntity k : ev.attackersMap.keySet()) {
|
||||
Collection<Card> attackers = ev.attackersMap.get(k);
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (sb.length() > 0) sb.append("\n");
|
||||
sb.append(localizer.getMessage("lblLogPlayerAssignedAttackerToAttackTarget", ev.player(), Lang.joinHomogenous(attackers), k));
|
||||
sb.append(localizer.getMessage("lblLogPlayerAssignedAttackerToAttackTarget", ev.player, Lang.joinHomogenous(attackers), k));
|
||||
}
|
||||
if (sb.length() == 0) {
|
||||
sb.append(localizer.getMessage("lblPlayerDidntAttackThisTurn").replace("%s", ev.player().toString()));
|
||||
sb.append(localizer.getMessage("lblPlayerDidntAttackThisTurn").replace("%s", ev.player.toString()));
|
||||
}
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
Collection<Card> blockers = null;
|
||||
|
||||
for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers().entrySet()) {
|
||||
for (Entry<GameEntity, MapOfLists<Card, Card>> kv : ev.blockers.entrySet()) {
|
||||
GameEntity defender = kv.getKey();
|
||||
MapOfLists<Card, Card> attackers = kv.getValue();
|
||||
if (attackers == null || attackers.isEmpty()) {
|
||||
@@ -298,7 +298,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventMulligan ev) {
|
||||
String message = localizer.getMessage("lblPlayerHasMulliganedDownToNCards").replace("%d", String.valueOf(ev.player().getZone(ZoneType.Hand).size())).replace("%s", ev.player().toString());
|
||||
String message = localizer.getMessage("lblPlayerHasMulliganedDownToNCards").replace("%d", String.valueOf(ev.player.getZone(ZoneType.Hand).size())).replace("%s", ev.player.toString());
|
||||
return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,6 @@ public class GameView extends TrackableObject {
|
||||
}
|
||||
public void setDependencies(Table<StaticAbility, StaticAbility, Set<StaticAbilityLayer>> dependencies) {
|
||||
if (dependencies.isEmpty()) {
|
||||
set(TrackableProperty.Dependencies, "");
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -1328,6 +1328,12 @@ public class AbilityUtils {
|
||||
game.getTriggerHandler().resetActiveTriggers();
|
||||
}
|
||||
|
||||
if (sa.hasParam("Precalc")) {
|
||||
for (String s : sa.getParam("Precalc").split(",")) {
|
||||
sa.setSVar(s, String.valueOf(calculateAmount(sa.getHostCard(), s, sa)));
|
||||
}
|
||||
}
|
||||
|
||||
resolvePreAbilities(sa, game);
|
||||
|
||||
// count times ability resolves this turn
|
||||
|
||||
@@ -39,6 +39,7 @@ public class AirbendEffect extends SpellAbilityEffect {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card hostCard = sa.getHostCard();
|
||||
|
||||
@@ -17,6 +17,7 @@ import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
@@ -85,7 +86,7 @@ public class AmassEffect extends TokenEffectBase {
|
||||
}
|
||||
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("CounterType", CounterEnumType.P1P1);
|
||||
params.put("CounterType", CounterType.get(CounterEnumType.P1P1));
|
||||
params.put("Amount", amount);
|
||||
Card tgt = activator.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), false, params);
|
||||
|
||||
|
||||
@@ -90,16 +90,6 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
|
||||
c.addPerpetual(p);
|
||||
p.applyEffect(c);
|
||||
}
|
||||
if (sa.hasParam("ManaCost")) {
|
||||
final ManaCost manaCost = new ManaCost(new ManaCostParser(sa.getParam("ManaCost")));
|
||||
if (perpetual) {
|
||||
PerpetualManaCost p = new PerpetualManaCost(timestamp, manaCost);
|
||||
c.addPerpetual(p);
|
||||
p.applyEffect(c);
|
||||
} else {
|
||||
c.addChangedManaCost(manaCost, timestamp, (long) 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!addType.isEmpty() || !removeType.isEmpty() || addAllCreatureTypes || !remove.isEmpty()) {
|
||||
if (perpetual) {
|
||||
|
||||
@@ -102,29 +102,24 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
|
||||
int totalRemoved = 0;
|
||||
CardCollectionView srcCards;
|
||||
|
||||
if (sa.hasParam("Choices")) {
|
||||
ZoneType choiceZone = sa.hasParam("ChoiceZone") ? ZoneType.smartValueOf(sa.getParam("ChoiceZone"))
|
||||
: ZoneType.Battlefield;
|
||||
srcCards = CardLists.getValidCards(game.getCardsIn(choiceZone), sa.getParam("Choices"),
|
||||
activator, source, sa);
|
||||
} else {
|
||||
srcCards = getTargetCards(sa);
|
||||
}
|
||||
if (sa.isReplacementAbility()) {
|
||||
srcCards = new CardCollection(srcCards).filter(c -> !c.isInPlay() || sa.getLastStateBattlefield().contains(c));
|
||||
}
|
||||
|
||||
if (sa.hasParam("Choices")) {
|
||||
CardCollection choices = CardLists.getValidCards(game.getCardsIn(choiceZone), sa.getParam("Choices"),
|
||||
activator, source, sa);
|
||||
|
||||
int min = 1;
|
||||
int max = 1;
|
||||
if (sa.hasParam("ChoiceOptional")) {
|
||||
min = 0;
|
||||
max = srcCards.size();
|
||||
max = choices.size();
|
||||
}
|
||||
if (sa.hasParam("ChoiceNum")) {
|
||||
min = max = AbilityUtils.calculateAmount(source, sa.getParam("ChoiceNum"), sa);
|
||||
}
|
||||
if (srcCards.size() < min) {
|
||||
if (choices.size() < min) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,12 +128,13 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
title = title.replace(" ", " ");
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("CounterType", counterType);
|
||||
srcCards = pc.chooseCardsForEffect(srcCards, sa, title, min, max, min == 0, params);
|
||||
srcCards = pc.chooseCardsForEffect(choices, sa, title, min, max, min == 0, params);
|
||||
} else {
|
||||
for (final Player tgtPlayer : getTargetPlayers(sa)) {
|
||||
if (!tgtPlayer.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
// Removing energy
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
|
||||
totalRemoved += tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
@@ -154,6 +150,8 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srcCards = getTargetCards(sa);
|
||||
}
|
||||
|
||||
for (final Card tgtCard : srcCards) {
|
||||
|
||||
@@ -40,7 +40,6 @@ public class EarthbendEffect extends SpellAbilityEffect {
|
||||
TargetRestrictions abTgt = new TargetRestrictions("Select target land you control", "Land.YouCtrl".split(","), "1", "1");
|
||||
sa.setTargetRestrictions(abTgt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card source = sa.getHostCard();
|
||||
|
||||
@@ -369,8 +369,8 @@ public class RollDiceEffect extends SpellAbilityEffect {
|
||||
List<Card> canIncrementDice = new ArrayList<>();
|
||||
for (Card c : xenosquirrels) {
|
||||
// Xenosquirrels must have a P1P1 counter on it to remove in order to modify
|
||||
Integer P1P1Counters = c.getCounters().get(CounterEnumType.P1P1);
|
||||
if (P1P1Counters != null && P1P1Counters > 0 && c.canRemoveCounters(CounterEnumType.P1P1)) {
|
||||
Integer P1P1Counters = c.getCounters().get(CounterType.get(CounterEnumType.P1P1));
|
||||
if (P1P1Counters != null && P1P1Counters > 0 && c.canRemoveCounters(CounterType.get(CounterEnumType.P1P1))) {
|
||||
canIncrementDice.add(c);
|
||||
}
|
||||
}
|
||||
@@ -399,7 +399,6 @@ public class RollDiceEffect extends SpellAbilityEffect {
|
||||
* @param repParams replacement effect parameters
|
||||
* @return list of final roll results after applying ignores and replacements, sorted in ascending order
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Integer> rollAction(int amount, int sides, int ignore, List<Integer> rollsResult, List<Integer> ignored, Map<Player, Integer> ignoreChosenMap, Set<Card> dicePTExchanges, Player player, Map<AbilityKey, Object> repParams) {
|
||||
|
||||
repParams.put(AbilityKey.Sides, sides);
|
||||
@@ -417,8 +416,6 @@ public class RollDiceEffect extends SpellAbilityEffect {
|
||||
ignoreChosenMap = (Map<Player, Integer>) repParams.get(AbilityKey.IgnoreChosen);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
List<Integer> naturalRolls = (rollsResult == null ? new ArrayList<>() : rollsResult);
|
||||
|
||||
@@ -11,7 +11,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
@@ -38,7 +37,7 @@ public class TimeTravelEffect extends SpellAbilityEffect {
|
||||
|
||||
PlayerController pc = activator.getController();
|
||||
|
||||
final CounterType counterType = CounterEnumType.TIME;
|
||||
final CounterEnumType counterType = CounterEnumType.TIME;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
FCollection<Card> list = new FCollection<>();
|
||||
|
||||
@@ -3561,8 +3561,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
if (!getStaticAbilities().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!getReplacementEffects().isEmpty()
|
||||
&& (getReplacementEffects().size() > 1 || !isSaga() || hasKeyword(Keyword.READ_AHEAD))) {
|
||||
if (!getReplacementEffects().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!getTriggers().isEmpty()) {
|
||||
@@ -6442,10 +6441,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
|
||||
DamageType damageType = DamageType.Normal;
|
||||
if (isPlaneswalker()) { // 120.3c
|
||||
subtractCounter(CounterEnumType.LOYALTY, damageIn, null, true);
|
||||
subtractCounter(CounterType.get(CounterEnumType.LOYALTY), damageIn, null, true);
|
||||
}
|
||||
if (isBattle()) {
|
||||
subtractCounter(CounterEnumType.DEFENSE, damageIn, null, true);
|
||||
subtractCounter(CounterType.get(CounterEnumType.DEFENSE), damageIn, null, true);
|
||||
}
|
||||
if (isCreature()) {
|
||||
if (source.isWitherDamage()) { // 120.3d
|
||||
|
||||
@@ -2568,7 +2568,7 @@ public class CardFactoryUtil {
|
||||
} else if (keyword.equals("Sunburst")) {
|
||||
// Rule 702.43a If this object is entering the battlefield as a creature,
|
||||
// ignoring any type-changing effects that would affect it
|
||||
CounterType t = host.isCreature() ? CounterEnumType.P1P1 : CounterEnumType.CHARGE;
|
||||
CounterType t = CounterType.get(host.isCreature() ? CounterEnumType.P1P1 : CounterEnumType.CHARGE);
|
||||
|
||||
StringBuilder sb = new StringBuilder("etbCounter:");
|
||||
sb.append(t).append(":Sunburst:no Condition:");
|
||||
|
||||
@@ -213,10 +213,16 @@ public final class CardPredicates {
|
||||
public static Predicate<Card> hasCounter(final CounterType type) {
|
||||
return hasCounter(type, 1);
|
||||
}
|
||||
public static Predicate<Card> hasCounter(final CounterEnumType type) {
|
||||
return hasCounter(type, 1);
|
||||
}
|
||||
|
||||
public static Predicate<Card> hasCounter(final CounterType type, final int n) {
|
||||
return c -> c.getCounters(type) >= n;
|
||||
}
|
||||
public static Predicate<Card> hasCounter(final CounterEnumType type, final int n) {
|
||||
return hasCounter(CounterType.get(type), n);
|
||||
}
|
||||
|
||||
public static Predicate<Card> hasLessCounter(final CounterType type, final int n) {
|
||||
return c -> {
|
||||
@@ -224,10 +230,16 @@ public final class CardPredicates {
|
||||
return x > 0 && x <= n;
|
||||
};
|
||||
}
|
||||
public static Predicate<Card> hasLessCounter(final CounterEnumType type, final int n) {
|
||||
return hasLessCounter(CounterType.get(type), n);
|
||||
}
|
||||
|
||||
public static Predicate<Card> canReceiveCounters(final CounterType counter) {
|
||||
return c -> c.canReceiveCounters(counter);
|
||||
}
|
||||
public static Predicate<Card> canReceiveCounters(final CounterEnumType counter) {
|
||||
return canReceiveCounters(CounterType.get(counter));
|
||||
}
|
||||
|
||||
public static Predicate<Card> hasGreaterPowerThan(final int minPower) {
|
||||
return c -> c.getNetPower() > minPower;
|
||||
@@ -236,6 +248,9 @@ public final class CardPredicates {
|
||||
public static Comparator<Card> compareByCounterType(final CounterType type) {
|
||||
return Comparator.comparingInt(arg0 -> arg0.getCounters(type));
|
||||
}
|
||||
public static Comparator<Card> compareByCounterType(final CounterEnumType type) {
|
||||
return compareByCounterType(CounterType.get(type));
|
||||
}
|
||||
|
||||
public static Predicate<Card> hasSVar(final String name) {
|
||||
return c -> c.hasSVar(name);
|
||||
|
||||
@@ -605,18 +605,18 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
||||
result.add(loyaltyRep);
|
||||
}
|
||||
if (type.isBattle()) {
|
||||
// TODO This is currently breaking for Battle/Defense
|
||||
// Going to script the cards to work but ideally it would happen here
|
||||
if (defenseRep == null) {
|
||||
defenseRep = CardFactoryUtil.makeEtbCounter("etbCounter:DEFENSE:" + this.baseDefense, this, true);
|
||||
}
|
||||
result.add(defenseRep);
|
||||
|
||||
// TODO add Siege "Choose a player to protect it"
|
||||
}
|
||||
|
||||
card.updateReplacementEffects(result, this);
|
||||
|
||||
// below are global rules
|
||||
if (type.hasSubtype("Saga") && !hasKeyword(Keyword.READ_AHEAD)) {
|
||||
if (sagaRep == null) {
|
||||
sagaRep = CardFactoryUtil.makeEtbCounter("etbCounter:LORE:1", this, false);
|
||||
sagaRep = CardFactoryUtil.makeEtbCounter("etbCounter:LORE:1", this, true);
|
||||
}
|
||||
result.add(sagaRep);
|
||||
}
|
||||
@@ -633,6 +633,7 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
||||
result.add(omenRep);
|
||||
}
|
||||
|
||||
card.updateReplacementEffects(result, this);
|
||||
return result;
|
||||
}
|
||||
public boolean addReplacementEffect(final ReplacementEffect replacementEffect) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.card;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -7,45 +8,74 @@ import forge.game.trigger.Trigger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public record CardTraitChanges(Collection<SpellAbility> abilities, Collection<SpellAbility> removedAbilities,
|
||||
Collection<Trigger> triggers, Collection<ReplacementEffect> replacements, Collection<StaticAbility> staticAbilities,
|
||||
boolean removeAll, boolean removeNonMana) {
|
||||
public class CardTraitChanges implements Cloneable {
|
||||
|
||||
private List<Trigger> triggers = Lists.newArrayList();
|
||||
private List<ReplacementEffect> replacements = Lists.newArrayList();
|
||||
private List<SpellAbility> abilities = Lists.newArrayList();
|
||||
private List<StaticAbility> staticAbilities = Lists.newArrayList();
|
||||
|
||||
private List<SpellAbility> removedAbilities = Lists.newArrayList();
|
||||
|
||||
private boolean removeAll = false;
|
||||
private boolean removeNonMana = false;
|
||||
|
||||
public CardTraitChanges(Collection<SpellAbility> spells, Collection<SpellAbility> removedAbilities,
|
||||
Collection<Trigger> trigger, Collection<ReplacementEffect> res, Collection<StaticAbility> st,
|
||||
boolean removeAll, boolean removeNonMana) {
|
||||
if (spells != null) {
|
||||
this.abilities.addAll(spells);
|
||||
}
|
||||
if (removedAbilities != null) {
|
||||
this.removedAbilities.addAll(removedAbilities);
|
||||
}
|
||||
if (trigger != null) {
|
||||
this.triggers.addAll(trigger);
|
||||
}
|
||||
if (res != null) {
|
||||
this.replacements.addAll(res);
|
||||
}
|
||||
if (st != null) {
|
||||
this.staticAbilities.addAll(st);
|
||||
}
|
||||
|
||||
this.removeAll |= removeAll;
|
||||
this.removeNonMana |= removeNonMana;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the triggers
|
||||
*/
|
||||
public Collection<Trigger> getTriggers() {
|
||||
return Objects.requireNonNullElse(triggers, List.of());
|
||||
return triggers;
|
||||
}
|
||||
/**
|
||||
* @return the replacements
|
||||
*/
|
||||
public Collection<ReplacementEffect> getReplacements() {
|
||||
return Objects.requireNonNullElse(replacements, List.of());
|
||||
return replacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the abilities
|
||||
*/
|
||||
public Collection<SpellAbility> getAbilities() {
|
||||
return Objects.requireNonNullElse(abilities, List.of());
|
||||
return abilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the abilities
|
||||
*/
|
||||
public Collection<SpellAbility> getRemovedAbilities() {
|
||||
return Objects.requireNonNullElse(removedAbilities, List.of());
|
||||
return removedAbilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the staticAbilities
|
||||
*/
|
||||
public Collection<StaticAbility> getStaticAbilities() {
|
||||
return Objects.requireNonNullElse(staticAbilities, List.of());
|
||||
return staticAbilities;
|
||||
}
|
||||
|
||||
public boolean isRemoveAll() {
|
||||
@@ -57,30 +87,53 @@ public record CardTraitChanges(Collection<SpellAbility> abilities, Collection<Sp
|
||||
}
|
||||
|
||||
public CardTraitChanges copy(Card host, boolean lki) {
|
||||
return new CardTraitChanges(
|
||||
this.getAbilities().stream().map(sa -> sa.copy(host, lki)).collect(Collectors.toList()),
|
||||
this.getRemovedAbilities().stream().map(sa -> sa.copy(host, lki)).collect(Collectors.toList()),
|
||||
this.getTriggers().stream().map(tr -> tr.copy(host, lki)).collect(Collectors.toList()),
|
||||
this.getReplacements().stream().map(tr -> tr.copy(host, lki)).collect(Collectors.toList()),
|
||||
this.getStaticAbilities().stream().map(st -> st.copy(host, lki)).collect(Collectors.toList()),
|
||||
removeAll, removeNonMana
|
||||
);
|
||||
try {
|
||||
CardTraitChanges result = (CardTraitChanges) super.clone();
|
||||
|
||||
result.abilities = Lists.newArrayList();
|
||||
for (SpellAbility sa : this.abilities) {
|
||||
result.abilities.add(sa.copy(host, lki));
|
||||
}
|
||||
result.removedAbilities = Lists.newArrayList();
|
||||
for (SpellAbility sa : this.removedAbilities) {
|
||||
result.removedAbilities.add(sa.copy(host, lki));
|
||||
}
|
||||
|
||||
result.triggers = Lists.newArrayList();
|
||||
for (Trigger tr : this.triggers) {
|
||||
result.triggers.add(tr.copy(host, lki));
|
||||
}
|
||||
|
||||
result.replacements = Lists.newArrayList();
|
||||
for (ReplacementEffect re : this.replacements) {
|
||||
result.replacements.add(re.copy(host, lki));
|
||||
}
|
||||
|
||||
result.staticAbilities = Lists.newArrayList();
|
||||
for (StaticAbility sa : this.staticAbilities) {
|
||||
result.staticAbilities.add(sa.copy(host, lki));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("CardTraitChanges : clone() error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void changeText() {
|
||||
for (SpellAbility sa : this.getAbilities()) {
|
||||
for (SpellAbility sa : this.abilities) {
|
||||
sa.changeText();
|
||||
}
|
||||
|
||||
for (Trigger tr : this.getTriggers()) {
|
||||
for (Trigger tr : this.triggers) {
|
||||
tr.changeText();
|
||||
}
|
||||
|
||||
for (ReplacementEffect re : this.getReplacements()) {
|
||||
for (ReplacementEffect re : this.replacements) {
|
||||
re.changeText();
|
||||
}
|
||||
|
||||
for (StaticAbility sa : this.getStaticAbilities()) {
|
||||
for (StaticAbility sa : this.staticAbilities) {
|
||||
sa.changeText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.Locale;
|
||||
* @author Clemens Koza
|
||||
* @version V0.0 17.02.2010
|
||||
*/
|
||||
public enum CounterEnumType implements CounterType {
|
||||
public enum CounterEnumType {
|
||||
|
||||
M1M1("-1/-1", "-1/-1", 255, 110, 106),
|
||||
P1P1("+1/+1", "+1/+1", 96, 226, 23),
|
||||
@@ -555,14 +555,4 @@ public enum CounterEnumType implements CounterType {
|
||||
|
||||
public static final ImmutableList<CounterEnumType> values = ImmutableList.copyOf(values());
|
||||
|
||||
@Override
|
||||
public boolean is(CounterEnumType eType) {
|
||||
return this == eType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeywordCounter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package forge.game.card;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public record CounterKeywordType(String keyword) implements CounterType {
|
||||
|
||||
// Rule 122.1b
|
||||
static ImmutableList<String> keywordCounter = ImmutableList.of(
|
||||
"Flying", "First Strike", "Double Strike", "Deathtouch", "Decayed", "Exalted", "Haste", "Hexproof",
|
||||
"Indestructible", "Lifelink", "Menace", "Reach", "Shadow", "Trample", "Vigilance");
|
||||
private static Map<String, CounterKeywordType> sMap = Maps.newHashMap();
|
||||
|
||||
|
||||
public static CounterKeywordType get(String s) {
|
||||
if (!sMap.containsKey(s)) {
|
||||
sMap.put(s, new CounterKeywordType(s));
|
||||
}
|
||||
return sMap.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getKeywordDescription();
|
||||
}
|
||||
|
||||
public String getCounterOnCardDisplayName() {
|
||||
return getKeywordDescription();
|
||||
}
|
||||
|
||||
private String getKeywordDescription() {
|
||||
if (keyword.startsWith("Hexproof:")) {
|
||||
final String[] k = keyword.split(":");
|
||||
return "Hexproof from " + k[2];
|
||||
}
|
||||
if (keyword.startsWith("Trample:")) {
|
||||
return "Trample over Planeswalkers";
|
||||
}
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public boolean is(CounterEnumType eType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isKeywordCounter() {
|
||||
if (keyword.startsWith("Hexproof:")) {
|
||||
return true;
|
||||
}
|
||||
if (keyword.startsWith("Trample:")) {
|
||||
return true;
|
||||
}
|
||||
return keywordCounter.contains(keyword);
|
||||
}
|
||||
|
||||
|
||||
public int getRed() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
public int getBlue() {
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,141 @@
|
||||
package forge.game.card;
|
||||
|
||||
import java.io.Serializable;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Ordering;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
|
||||
public interface CounterType extends Serializable {
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CounterType implements Comparable<CounterType>, Serializable {
|
||||
private static final long serialVersionUID = -7575835723159144478L;
|
||||
|
||||
private CounterEnumType eVal = null;
|
||||
private String sVal = null;
|
||||
|
||||
// Rule 122.1b
|
||||
static ImmutableList<String> keywordCounter = ImmutableList.of(
|
||||
"Flying", "First Strike", "Double Strike", "Deathtouch", "Decayed", "Exalted", "Haste", "Hexproof",
|
||||
"Indestructible", "Lifelink", "Menace", "Reach", "Shadow", "Trample", "Vigilance");
|
||||
|
||||
private static Map<CounterEnumType, CounterType> eMap = Maps.newEnumMap(CounterEnumType.class);
|
||||
private static Map<String, CounterType> sMap = Maps.newHashMap();
|
||||
|
||||
private CounterType(CounterEnumType e, String s) {
|
||||
this.eVal = e;
|
||||
this.sVal = s;
|
||||
}
|
||||
|
||||
public static CounterType get(CounterEnumType e) {
|
||||
if (!eMap.containsKey(e)) {
|
||||
eMap.put(e, new CounterType(e, null));
|
||||
}
|
||||
return eMap.get(e);
|
||||
}
|
||||
|
||||
public static CounterType get(String s) {
|
||||
if (!sMap.containsKey(s)) {
|
||||
sMap.put(s, new CounterType(null, s));
|
||||
}
|
||||
return sMap.get(s);
|
||||
}
|
||||
|
||||
public static CounterType getType(String name) {
|
||||
if ("Any".equalsIgnoreCase(name)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return CounterEnumType.getType(name);
|
||||
return get(CounterEnumType.getType(name));
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
return CounterKeywordType.get(name);
|
||||
return get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName();
|
||||
|
||||
public String getCounterOnCardDisplayName();
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(eVal, sVal);
|
||||
}
|
||||
|
||||
public boolean is(CounterEnumType eType);
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
CounterType rhs = (CounterType) obj;
|
||||
return new EqualsBuilder()
|
||||
.append(eVal, rhs.eVal)
|
||||
.append(sVal, rhs.sVal)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
public boolean isKeywordCounter();
|
||||
@Override
|
||||
public String toString() {
|
||||
return eVal != null ? eVal.toString() : sVal;
|
||||
}
|
||||
|
||||
public int getRed();
|
||||
public String getName() {
|
||||
return eVal != null ? eVal.getName() : getKeywordDescription();
|
||||
}
|
||||
|
||||
public int getGreen();
|
||||
public String getCounterOnCardDisplayName() {
|
||||
return eVal != null ? eVal.getCounterOnCardDisplayName() : getKeywordDescription();
|
||||
}
|
||||
|
||||
public int getBlue();
|
||||
private String getKeywordDescription() {
|
||||
if (sVal.startsWith("Hexproof:")) {
|
||||
final String[] k = sVal.split(":");
|
||||
return "Hexproof from " + k[2];
|
||||
}
|
||||
if (sVal.startsWith("Trample:")) {
|
||||
return "Trample over Planeswalkers";
|
||||
}
|
||||
return sVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(CounterType o) {
|
||||
return ComparisonChain.start()
|
||||
.compare(eVal, o.eVal, Ordering.natural().nullsLast())
|
||||
.compare(sVal, o.sVal, Ordering.natural().nullsLast())
|
||||
.result();
|
||||
}
|
||||
|
||||
public boolean is(CounterEnumType eType) {
|
||||
return eVal == eType;
|
||||
}
|
||||
|
||||
public boolean isKeywordCounter() {
|
||||
if (eVal != null) {
|
||||
return false;
|
||||
}
|
||||
if (sVal.startsWith("Hexproof:")) {
|
||||
return true;
|
||||
}
|
||||
if (sVal.startsWith("Trample:")) {
|
||||
return true;
|
||||
}
|
||||
return keywordCounter.contains(sVal);
|
||||
}
|
||||
|
||||
public int getRed() {
|
||||
return eVal != null ? eVal.getRed() : 255;
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
return eVal != null ? eVal.getGreen() : 255;
|
||||
}
|
||||
|
||||
public int getBlue() {
|
||||
return eVal != null ? eVal.getBlue() : 255;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package forge.game.card.perpetual;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.cost.Cost;
|
||||
|
||||
public record PerpetualManaCost(long timestamp, ManaCost manaCost) implements PerpetualInterface {
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyEffect(Card c) {
|
||||
c.addChangedManaCost(manaCost, timestamp, (long) 0);
|
||||
|
||||
c.updateManaCostForView();
|
||||
|
||||
if (c.getFirstSpellAbility() != null) {
|
||||
Cost cost = c.getFirstSpellAbility().getPayCosts().copyWithDefinedMana(manaCost);
|
||||
c.getFirstSpellAbility().setPayCosts(cost);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -621,11 +621,8 @@ public class Cost implements Serializable {
|
||||
}
|
||||
|
||||
public final Cost copyWithDefinedMana(String manaCost) {
|
||||
return copyWithDefinedMana(new ManaCost(new ManaCostParser(manaCost)));
|
||||
}
|
||||
public final Cost copyWithDefinedMana(ManaCost manaCost) {
|
||||
Cost toRet = copyWithNoMana();
|
||||
toRet.costParts.add(new CostPartMana(manaCost, null));
|
||||
toRet.costParts.add(new CostPartMana(new ManaCost(new ManaCostParser(manaCost)), null));
|
||||
toRet.cacheTapCost();
|
||||
return toRet;
|
||||
}
|
||||
@@ -997,9 +994,9 @@ public class Cost implements Serializable {
|
||||
Integer counters = otherAmount - part.convertAmount();
|
||||
// the cost can turn positive if multiple Carth raise it
|
||||
if (counters < 0) {
|
||||
costParts.add(new CostPutCounter(String.valueOf(counters *-1), CounterEnumType.LOYALTY, part.getType(), part.getTypeDescription()));
|
||||
costParts.add(new CostPutCounter(String.valueOf(counters *-1), CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription()));
|
||||
} else {
|
||||
costParts.add(new CostRemoveCounter(String.valueOf(counters), CounterEnumType.LOYALTY, part.getType(), part.getTypeDescription(), Lists.newArrayList(ZoneType.Battlefield) , false));
|
||||
costParts.add(new CostRemoveCounter(String.valueOf(counters), CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription(), Lists.newArrayList(ZoneType.Battlefield) , false));
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
|
||||
@@ -22,6 +22,7 @@ import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
@@ -80,7 +81,7 @@ public class CostUntap extends CostPart {
|
||||
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
|
||||
final Card source = ability.getHostCard();
|
||||
return source.isTapped() && !source.isAbilitySick() &&
|
||||
(source.getCounters(CounterEnumType.STUN) == 0 || source.canRemoveCounters(CounterEnumType.STUN));
|
||||
(source.getCounters(CounterEnumType.STUN) == 0 || source.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,7 +86,7 @@ public class CostUntapType extends CostPartWithList {
|
||||
if (!canUntapSource) {
|
||||
typeList.remove(source);
|
||||
}
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterEnumType.STUN));
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
|
||||
final int amount = this.getAbilityAmount(ability);
|
||||
return (typeList.size() != 0) && (typeList.size() >= amount);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package forge.game.event;
|
||||
|
||||
public interface Event {
|
||||
public abstract class Event {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package forge.game.event;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public enum EventValueChangeType {
|
||||
Added,
|
||||
Removed,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package forge.game.event;
|
||||
|
||||
public interface GameEvent extends Event {
|
||||
public abstract class GameEvent extends Event {
|
||||
|
||||
public abstract <T> T visit(IGameEventVisitor<T> visitor);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ import com.google.common.collect.Multimap;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventAnteCardsSelected(Multimap<Player, Card> cards) implements GameEvent {
|
||||
public class GameEventAnteCardsSelected extends GameEvent {
|
||||
public final Multimap<Player, Card> cards;
|
||||
public GameEventAnteCardsSelected(Multimap<Player, Card> list) {
|
||||
cards = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -6,21 +6,27 @@ import forge.game.GameEntity;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventAttackersDeclared(Player player, Multimap<GameEntity, Card> attackersMap) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventAttackersDeclared extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final Multimap<GameEntity, Card> attackersMap;
|
||||
|
||||
public GameEventAttackersDeclared(Player playerTurn, Multimap<GameEntity, Card> attackersMap) {
|
||||
this.player = playerTurn;
|
||||
this.attackersMap = attackersMap;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.GameEvent#visit(forge.game.event.IGameEventVisitor)
|
||||
*/
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + player + " declared attackers: " + attackersMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,23 @@ import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public record GameEventBlockersDeclared(Player defendingPlayer, Map<GameEntity, MapOfLists<Card, Card>> blockers) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventBlockersDeclared extends GameEvent {
|
||||
|
||||
public final Map<GameEntity, MapOfLists<Card, Card>> blockers;
|
||||
public final Player defendingPlayer;
|
||||
|
||||
public GameEventBlockersDeclared(Player who, Map<GameEntity, MapOfLists<Card, Card>> blockers) {
|
||||
this.blockers = blockers;
|
||||
defendingPlayer = who;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,20 @@ package forge.game.event;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCardAttachment(Card equipment, GameEntity newTarget, GameEntity oldEntity) implements GameEvent {
|
||||
public class GameEventCardAttachment extends GameEvent {
|
||||
|
||||
public final Card equipment;
|
||||
public final GameEntity newTarget; // can enchant player, I'm ssaving a class to enchants - it could be incorrect.
|
||||
public final GameEntity oldEntiy;
|
||||
|
||||
public GameEventCardAttachment(Card attachment, GameEntity formerEntity, GameEntity newEntity) {
|
||||
this.equipment = attachment;
|
||||
this.newTarget = newEntity;
|
||||
this.oldEntiy = formerEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return newTarget == null ? "Detached " + equipment + " from " + oldEntity : "Attached " + equipment + (oldEntity == null ? "" : " from " + oldEntity) + " to " + newTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,17 @@ import forge.game.card.Card;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventCardChangeZone(Card card, Zone from, Zone to) implements GameEvent {
|
||||
public class GameEventCardChangeZone extends GameEvent {
|
||||
|
||||
public final Card card;
|
||||
public final Zone from;
|
||||
public final Zone to;
|
||||
|
||||
public GameEventCardChangeZone(Card c, Zone zoneFrom, Zone zoneTo) {
|
||||
card = c;
|
||||
from = zoneFrom;
|
||||
to = zoneTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -3,17 +3,21 @@ package forge.game.event;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CounterType;
|
||||
|
||||
public record GameEventCardCounters(Card card, CounterType type, int oldValue, int newValue) implements GameEvent {
|
||||
public class GameEventCardCounters extends GameEvent {
|
||||
public final Card card;
|
||||
public final CounterType type;
|
||||
public final int oldValue;
|
||||
public final int newValue;
|
||||
|
||||
public GameEventCardCounters(Card card, CounterType counterType, int old, int newValue) {
|
||||
this.card = card;
|
||||
type = counterType;
|
||||
this.oldValue = old;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + card + " " + type + " counters: " + oldValue + " -> " + newValue;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package forge.game.event;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCardDamaged(Card card, Card source, int amount, DamageType type) implements GameEvent {
|
||||
public class GameEventCardDamaged extends GameEvent {
|
||||
|
||||
public enum DamageType {
|
||||
Normal,
|
||||
@@ -11,16 +11,21 @@ public record GameEventCardDamaged(Card card, Card source, int amount, DamageTyp
|
||||
LoyaltyLoss
|
||||
}
|
||||
|
||||
public final Card card;
|
||||
public final Card source;
|
||||
public final int amount;
|
||||
public final DamageType type;
|
||||
|
||||
public GameEventCardDamaged(Card card, Card src, int damageToAdd, DamageType damageType) {
|
||||
this.card = card;
|
||||
source = src;
|
||||
amount = damageToAdd;
|
||||
type = damageType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + source + " dealt " + amount + " " + type + " damage to " + card;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventCardDestroyed() implements GameEvent {
|
||||
public class GameEventCardDestroyed extends GameEvent {
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Card destroyed";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventCardForetold(Player activatingPlayer) implements GameEvent {
|
||||
public class GameEventCardForetold extends GameEvent {
|
||||
public final Player activatingPlayer;
|
||||
|
||||
public GameEventCardForetold(Player player) {
|
||||
activatingPlayer = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -2,7 +2,21 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventCardModeChosen(Player player, String cardName, String mode, boolean log, boolean random) implements GameEvent {
|
||||
public class GameEventCardModeChosen extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final String cardName;
|
||||
public final String mode;
|
||||
public final boolean log;
|
||||
public final boolean random;
|
||||
|
||||
public GameEventCardModeChosen(Player player, String cardName, String mode, boolean log, boolean random) {
|
||||
this.player = player;
|
||||
this.cardName = cardName;
|
||||
this.mode = mode;
|
||||
this.log = log;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -2,7 +2,19 @@ package forge.game.event;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCardPhased(Card card, boolean phaseState) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventCardPhased extends GameEvent {
|
||||
|
||||
public final Card card;
|
||||
public final boolean phaseState;
|
||||
|
||||
public GameEventCardPhased(Card card, boolean state) {
|
||||
this.card = card;
|
||||
phaseState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -3,7 +3,16 @@ package forge.game.event;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventCardPlotted(Card card, Player activatingPlayer) implements GameEvent {
|
||||
public class GameEventCardPlotted extends GameEvent {
|
||||
|
||||
public final Card card;
|
||||
|
||||
public final Player activatingPlayer;
|
||||
|
||||
public GameEventCardPlotted(Card card, Player player) {
|
||||
this.card = card;
|
||||
activatingPlayer = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -5,9 +5,11 @@ import forge.game.card.Card;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public record GameEventCardRegenerated(Collection<Card> cards) implements GameEvent {
|
||||
public class GameEventCardRegenerated extends GameEvent {
|
||||
|
||||
public final Collection<Card> cards;
|
||||
public GameEventCardRegenerated(Card affected) {
|
||||
this(Arrays.asList(affected));
|
||||
cards = Arrays.asList(affected);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
package forge.game.event;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCardSacrificed(Card card) implements GameEvent {
|
||||
public class GameEventCardSacrificed extends GameEvent {
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + card.getController() + " sacrificed " + card;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,20 +11,23 @@ import forge.game.card.Card;
|
||||
/**
|
||||
* This means card's characteristics have changed on server, clients must re-request them
|
||||
*/
|
||||
public record GameEventCardStatsChanged(Collection<Card> cards, boolean transform) implements GameEvent {
|
||||
public class GameEventCardStatsChanged extends GameEvent {
|
||||
|
||||
public final Collection<Card> cards;
|
||||
public boolean transform = false;
|
||||
public GameEventCardStatsChanged(Card affected) {
|
||||
this(affected, false);
|
||||
}
|
||||
|
||||
public GameEventCardStatsChanged(Card affected, boolean isTransform) {
|
||||
this(Arrays.asList(affected), false);
|
||||
cards = Arrays.asList(affected);
|
||||
//the transform should only fire once so the flip effect sound will trigger once every transformation...
|
||||
// disable for now
|
||||
transform = false;
|
||||
}
|
||||
|
||||
public GameEventCardStatsChanged(Collection<Card> affected) {
|
||||
this(affected, false);
|
||||
cards = affected;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -32,6 +35,7 @@ public record GameEventCardStatsChanged(Collection<Card> cards, boolean transfor
|
||||
*/
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@ package forge.game.event;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCardTapped(Card card, boolean tapped) implements GameEvent {
|
||||
public class GameEventCardTapped extends GameEvent {
|
||||
public final boolean tapped;
|
||||
public final Card card;
|
||||
|
||||
public GameEventCardTapped(final Card card, final boolean tapped) {
|
||||
this.tapped = tapped;
|
||||
this.card = card;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + card.getController() + (tapped ? " tapped " : " untapped ") + card;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventCombatChanged() implements GameEvent {
|
||||
public class GameEventCombatChanged extends GameEvent {
|
||||
|
||||
public GameEventCombatChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Combat changed";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,19 @@ import java.util.List;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCombatEnded(List<Card> attackers, List<Card> blockers) implements GameEvent {
|
||||
public class GameEventCombatEnded extends GameEvent {
|
||||
|
||||
public final List<Card> attackers;
|
||||
public final List<Card> blockers;
|
||||
|
||||
public GameEventCombatEnded(List<Card> attackers, List<Card> blockers) {
|
||||
this.attackers = attackers;
|
||||
this.blockers = blockers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Combat ended. Attackers: " + attackers + " Blockers: " + blockers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,15 @@ import java.util.List;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventCombatUpdate(List<Card> attackers, List<Card> blockers) implements GameEvent {
|
||||
public class GameEventCombatUpdate extends GameEvent {
|
||||
|
||||
public final List<Card> attackers;
|
||||
public final List<Card> blockers;
|
||||
|
||||
public GameEventCombatUpdate(List<Card> attackers, List<Card> blockers) {
|
||||
this.attackers = attackers;
|
||||
this.blockers = blockers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventDayTimeChanged(boolean daytime) implements GameEvent {
|
||||
public class GameEventDayTimeChanged extends GameEvent {
|
||||
public final boolean daytime;
|
||||
|
||||
public GameEventDayTimeChanged(final boolean daytime) {
|
||||
this.daytime = daytime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -6,7 +6,18 @@ import forge.game.player.Player;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.Lang;
|
||||
|
||||
public record GameEventDoorChanged(Player activatingPlayer, Card card, CardStateName state, boolean unlock) implements GameEvent {
|
||||
public class GameEventDoorChanged extends GameEvent {
|
||||
public final Player activatingPlayer;
|
||||
public final Card card;
|
||||
public final CardStateName state;
|
||||
public boolean unlock;
|
||||
|
||||
public GameEventDoorChanged(Player player, Card c, CardStateName state, boolean unlock) {
|
||||
activatingPlayer = player;
|
||||
card = c;
|
||||
this.state = state;
|
||||
this.unlock = unlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventFlipCoin() implements GameEvent {
|
||||
public class GameEventFlipCoin extends GameEvent {
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Flipped coin";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventGameFinished() implements GameEvent {
|
||||
|
||||
public class GameEventGameFinished extends GameEvent {
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Game finished";
|
||||
}
|
||||
} // need this class to launch after log was built via previous event
|
||||
@@ -4,18 +4,17 @@ import java.util.Collection;
|
||||
|
||||
import forge.game.GameOutcome;
|
||||
|
||||
public record GameEventGameOutcome(GameOutcome result, Collection<GameOutcome> history) implements GameEvent {
|
||||
public class GameEventGameOutcome extends GameEvent {
|
||||
public final GameOutcome result;
|
||||
public final Collection<GameOutcome> history;
|
||||
|
||||
public GameEventGameOutcome(GameOutcome lastOne, Collection<GameOutcome> history) {
|
||||
this.result = lastOne;
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Game Outcome: " + result.getOutcomeStrings();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,17 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventGameRestarted(Player whoRestarted) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventGameRestarted extends GameEvent {
|
||||
|
||||
public final Player whoRestarted;
|
||||
|
||||
public GameEventGameRestarted(Player playerTurn) {
|
||||
whoRestarted = playerTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -5,7 +5,22 @@ import forge.game.player.Player;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventGameStarted(GameType gameType, Player firstTurn, Iterable<Player> players) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventGameStarted extends GameEvent {
|
||||
|
||||
public final Player firstTurn;
|
||||
public final Iterable<Player> players;
|
||||
public final GameType gameType;
|
||||
|
||||
public GameEventGameStarted(GameType type, Player firstTurn, Iterable<Player> players) {
|
||||
super();
|
||||
this.gameType = type;
|
||||
this.firstTurn = firstTurn;
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -3,17 +3,19 @@ package forge.game.event;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventLandPlayed(Player player, Card land) implements GameEvent {
|
||||
public class GameEventLandPlayed extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final Card land;
|
||||
|
||||
public GameEventLandPlayed(Player player, Card land) {
|
||||
this.player = player;
|
||||
this.land = land;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + player + " played " + land;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,22 @@ package forge.game.event;
|
||||
import forge.game.player.Player;
|
||||
|
||||
// This special event denotes loss of mana due to phase end
|
||||
public record GameEventManaBurn(Player player, boolean causedLifeLoss, int amount) implements GameEvent {
|
||||
public class GameEventManaBurn extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final boolean causedLifeLoss;
|
||||
public final int amount;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param dealDamage
|
||||
* @param burn
|
||||
*/
|
||||
public GameEventManaBurn(Player who, int burn, boolean dealDamage) {
|
||||
player = who;
|
||||
amount = burn;
|
||||
causedLifeLoss = dealDamage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -4,7 +4,20 @@ import forge.game.mana.Mana;
|
||||
import forge.game.player.Player;
|
||||
import forge.util.Lang;
|
||||
|
||||
public record GameEventManaPool(Player player, EventValueChangeType mode, Mana mana) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventManaPool extends GameEvent {
|
||||
public final Player player;
|
||||
public final EventValueChangeType mode;
|
||||
public final Mana mana;
|
||||
|
||||
public GameEventManaPool(Player owner, EventValueChangeType changeMode, Mana mana) {
|
||||
this.mana = mana;
|
||||
player = owner;
|
||||
mode = changeMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -2,18 +2,19 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventMulligan(Player player) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventMulligan extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public GameEventMulligan(Player p) {
|
||||
player = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + player + " mulligans";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,23 @@ import forge.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
|
||||
public record GameEventPlayerControl(Player player, LobbyPlayer oldLobbyPlayer, PlayerController oldController, LobbyPlayer newLobbyPlayer, PlayerController newController) implements GameEvent {
|
||||
public class GameEventPlayerControl extends GameEvent {
|
||||
public final Player player;
|
||||
public final LobbyPlayer oldLobbyPlayer;
|
||||
public final PlayerController oldController;
|
||||
public final LobbyPlayer newLobbyPlayer;
|
||||
public final PlayerController newController;
|
||||
|
||||
public GameEventPlayerControl(final Player p, final LobbyPlayer oldLobbyPlayer, final PlayerController oldController, final LobbyPlayer newLobbyPlayer, final PlayerController newController) {
|
||||
this.player = p;
|
||||
this.oldLobbyPlayer = oldLobbyPlayer;
|
||||
this.oldController = oldController;
|
||||
this.newLobbyPlayer = newLobbyPlayer;
|
||||
this.newController = newController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(final IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + player + " controlled by " + player.getControllingPlayer();
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,21 @@ package forge.game.event;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventPlayerCounters(Player receiver, CounterType type, int oldValue, int amount) implements GameEvent {
|
||||
public class GameEventPlayerCounters extends GameEvent {
|
||||
public final Player receiver;
|
||||
public final CounterType type;
|
||||
public final int oldValue;
|
||||
public final int amount;
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
public GameEventPlayerCounters(Player recv, CounterType t, int old, int num) {
|
||||
receiver = recv;
|
||||
type = t;
|
||||
oldValue = old;
|
||||
amount = num;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + receiver + " got " + oldValue + " plus " + amount + " " + type;
|
||||
}
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,33 @@ package forge.game.event;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventPlayerDamaged(Player target, Card source, int amount, boolean combat, boolean infect) implements GameEvent {
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventPlayerDamaged extends GameEvent {
|
||||
public final Player target;
|
||||
public final Card source;
|
||||
public final int amount;
|
||||
final public boolean infect;
|
||||
public final boolean combat;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param player
|
||||
* @param source
|
||||
* @param amount
|
||||
* @param isCombat
|
||||
* @param infect
|
||||
*/
|
||||
public GameEventPlayerDamaged(Player player, Card source, int amount, boolean isCombat, boolean infect) {
|
||||
target = player;
|
||||
this.source = source;
|
||||
this.amount = amount;
|
||||
combat = isCombat;
|
||||
this.infect = infect;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.GameEvent#visit(forge.game.event.IGameEventVisitor)
|
||||
@@ -13,11 +39,4 @@ public record GameEventPlayerDamaged(Player target, Card source, int amount, boo
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + target + " took " + amount + (infect ? " infect" : combat ? " combat" : "") + " damage from " + source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,16 @@ import forge.game.player.Player;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventPlayerLivesChanged(Player player, int oldLives, int newLives) implements GameEvent {
|
||||
public class GameEventPlayerLivesChanged extends GameEvent {
|
||||
public final Player player;
|
||||
public final int oldLives;
|
||||
public final int newLives;
|
||||
|
||||
public GameEventPlayerLivesChanged(Player who, int oldValue, int newValue) {
|
||||
player = who;
|
||||
oldLives = oldValue;
|
||||
newLives = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -6,7 +6,18 @@ import forge.game.player.Player;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public record GameEventPlayerPoisoned(Player receiver, Player source, int oldValue, int amount) implements GameEvent {
|
||||
public class GameEventPlayerPoisoned extends GameEvent {
|
||||
public final Player receiver;
|
||||
public final Player source;
|
||||
public final int oldValue;
|
||||
public final int amount;
|
||||
|
||||
public GameEventPlayerPoisoned(Player recv, Player src, int old, int num) {
|
||||
receiver = recv;
|
||||
source = src;
|
||||
oldValue = old;
|
||||
amount = num;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -4,7 +4,21 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventPlayerPriority(Player turn, PhaseType phase, Player priority) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventPlayerPriority extends GameEvent {
|
||||
|
||||
public final Player turn;
|
||||
public final PhaseType phase;
|
||||
public final Player priority;
|
||||
|
||||
public GameEventPlayerPriority(Player playerTurn, PhaseType phase, Player priorityPlayer) {
|
||||
turn = playerTurn;
|
||||
this.phase = phase;
|
||||
priority = priorityPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -2,7 +2,16 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventPlayerRadiation(Player receiver, Player source, int change) implements GameEvent {
|
||||
public class GameEventPlayerRadiation extends GameEvent {
|
||||
public final Player receiver;
|
||||
public final Player source;
|
||||
public final int change;
|
||||
|
||||
public GameEventPlayerRadiation(Player recv, Player src, int chng) {
|
||||
receiver = recv;
|
||||
source = src;
|
||||
change = chng;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -4,7 +4,16 @@ import forge.game.player.Player;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventPlayerShardsChanged(Player player, int oldShards, int newShards) implements GameEvent {
|
||||
public class GameEventPlayerShardsChanged extends GameEvent {
|
||||
public final Player player;
|
||||
public final int oldShards;
|
||||
public final int newShards;
|
||||
|
||||
public GameEventPlayerShardsChanged(Player who, int oldValue, int newValue) {
|
||||
player = who;
|
||||
oldShards = oldValue;
|
||||
newShards = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -10,10 +10,18 @@ import forge.util.TextUtil;
|
||||
/**
|
||||
* This means card's characteristics have changed on server, clients must re-request them
|
||||
*/
|
||||
public record GameEventPlayerStatsChanged(Collection<Player> players, boolean updateCards) implements GameEvent {
|
||||
public class GameEventPlayerStatsChanged extends GameEvent {
|
||||
|
||||
public final Collection<Player> players;
|
||||
public final boolean updateCards;
|
||||
public GameEventPlayerStatsChanged(Player affected, boolean updateCards) {
|
||||
this(Arrays.asList(affected), updateCards);
|
||||
players = Arrays.asList(affected);
|
||||
this.updateCards = updateCards;
|
||||
}
|
||||
|
||||
public GameEventPlayerStatsChanged(Collection<Player> affected, boolean updateCards) {
|
||||
players = affected;
|
||||
this.updateCards = updateCards;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -21,6 +29,7 @@ public record GameEventPlayerStatsChanged(Collection<Player> players, boolean up
|
||||
*/
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventRandomLog(String message) implements GameEvent {
|
||||
public class GameEventRandomLog extends GameEvent {
|
||||
|
||||
public final String message;
|
||||
|
||||
public GameEventRandomLog(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package forge.game.event;
|
||||
|
||||
public record GameEventRollDie() implements GameEvent {
|
||||
public class GameEventRollDie extends GameEvent {
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
@@ -2,18 +2,19 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventScry(Player player, int toTop, int toBottom) implements GameEvent {
|
||||
public class GameEventScry extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final int toTop, toBottom;
|
||||
|
||||
public GameEventScry(Player player, int toTop, int toBottom) {
|
||||
this.player = player;
|
||||
this.toTop = toTop;
|
||||
this.toBottom = toBottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + player + " scried " + toTop + " to top, " + toBottom + " to bottom";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,13 @@ import forge.game.player.Player;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public record GameEventShuffle(Player player) implements GameEvent {
|
||||
public class GameEventShuffle extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
|
||||
public GameEventShuffle(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
@@ -16,6 +22,6 @@ public record GameEventShuffle(Player player) implements GameEvent {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return TextUtil.concatWithSpace(player.toString(), Lang.joinVerb(player.getName(), "shuffle"), "their library");
|
||||
return TextUtil.concatWithSpace(player.toString(), Lang.joinVerb(player.getName(), "shuffle"),"his/her/its library");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,18 @@ package forge.game.event;
|
||||
|
||||
import forge.game.player.Player;
|
||||
|
||||
public record GameEventSpeedChanged(Player player, int oldValue, int newValue) implements GameEvent {
|
||||
public class GameEventSpeedChanged extends GameEvent {
|
||||
|
||||
public final Player player;
|
||||
public final int oldValue;
|
||||
public final int newValue;
|
||||
|
||||
public GameEventSpeedChanged(Player affected, int oldValue, int newValue) {
|
||||
player = affected;
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
|
||||
@@ -3,7 +3,21 @@ package forge.game.event;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
|
||||
public record GameEventSpellAbilityCast(SpellAbility sa, SpellAbilityStackInstance si, int stackIndex) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventSpellAbilityCast extends GameEvent {
|
||||
|
||||
public final SpellAbility sa;
|
||||
public final SpellAbilityStackInstance si;
|
||||
public final int stackIndex;
|
||||
|
||||
public GameEventSpellAbilityCast(SpellAbility sp, SpellAbilityStackInstance si, int stackIndex) {
|
||||
sa = sp;
|
||||
this.si = si;
|
||||
this.stackIndex = stackIndex;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.event.GameEvent#visit(forge.game.event.IGameEventVisitor)
|
||||
@@ -13,11 +27,4 @@ public record GameEventSpellAbilityCast(SpellAbility sa, SpellAbilityStackInstan
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + sa.getActivatingPlayer() + (sa.isSpell() ? " cast " : sa.isActivatedAbility() ? " activated " : " triggered ") + sa;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,21 @@ package forge.game.event;
|
||||
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public record GameEventSpellRemovedFromStack(SpellAbility sa) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventSpellRemovedFromStack extends GameEvent {
|
||||
public final SpellAbility sa;
|
||||
|
||||
public GameEventSpellRemovedFromStack(SpellAbility spellAbility) {
|
||||
sa = spellAbility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Stack removed " + sa;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,29 @@ package forge.game.event;
|
||||
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public record GameEventSpellResolved(SpellAbility spell, boolean hasFizzled) implements GameEvent {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventSpellResolved extends GameEvent {
|
||||
|
||||
public final SpellAbility spell;
|
||||
public final boolean hasFizzled;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param source
|
||||
* @param sa
|
||||
* @param hasFizzled
|
||||
*/
|
||||
public GameEventSpellResolved(SpellAbility sa, boolean hasFizzled) {
|
||||
// TODO Auto-generated constructor stub
|
||||
this.spell = sa;
|
||||
this.hasFizzled = hasFizzled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Stack resolved " + spell + (hasFizzled ? " (fizzled)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,18 @@ package forge.game.event;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public record GameEventSprocketUpdate(Card contraption, int oldSprocket, int sprocket) implements GameEvent {
|
||||
public class GameEventSprocketUpdate extends GameEvent {
|
||||
|
||||
public final Card contraption;
|
||||
public final int oldSprocket;
|
||||
public final int sprocket;
|
||||
|
||||
public GameEventSprocketUpdate(Card contraption, int oldSprocket, int sprocket) {
|
||||
this.contraption = contraption;
|
||||
this.oldSprocket = oldSprocket;
|
||||
this.sprocket = sprocket;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user