From ac96890f44757b3b27f524ba98821700399eaa0c Mon Sep 17 00:00:00 2001 From: tool4ever Date: Thu, 14 Nov 2024 10:34:05 +0100 Subject: [PATCH] Some fixes (#6575) --- .../src/main/java/forge/game/GameAction.java | 2 +- .../java/forge/game/ability/AbilityUtils.java | 14 ++++++++++--- .../java/forge/game/cost/ICostVisitor.java | 5 ++++- .../game/replacement/ReplacementHandler.java | 1 + .../screens/match/controllers/CCombat.java | 3 +-- .../res/cardsfolder/i/infernal_vessel.txt | 2 +- .../k/king_of_the_oathbreakers.txt | 2 +- .../res/cardsfolder/n/needletooth_pack.txt | 2 +- .../res/cardsfolder/t/the_mindskinner.txt | 2 +- .../java/forge/gamemodes/match/GameLobby.java | 20 +++++++------------ 10 files changed, 29 insertions(+), 24 deletions(-) diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index e1ccedf9df1..a8b6930717c 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -2456,7 +2456,7 @@ public CardCollection mill(final PlayerCollection millers, final int numCards, f game.getAction().reveal(milledPlayer, destination, p, false, message, addSuffix); } game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, p + " milled " + - Lang.joinHomogenous(milled) + toZoneStr + "."); + Lang.joinHomogenous(milledPlayer) + toZoneStr + "."); } } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 6f3475832fe..d0e727a2bed 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1640,9 +1640,15 @@ public static int xCount(Card c, final String s, final CardTraitBase ctb) { return doXMath(calculateAmount(c, sq[v ? 1 : 2], ctb), expr, c, ctb); } + SpellAbility sa = null; if (ctb instanceof SpellAbility) { - final SpellAbility sa = (SpellAbility) ctb; + sa = (SpellAbility) ctb; + } else if (sq[0].contains("xPaid") && ctb instanceof TriggerReplacementBase) { + // try avoid fallback + sa = ((TriggerReplacementBase) ctb).getOverridingAbility(); + } + if (sa != null) { // special logic for xPaid in SpellAbility if (sq[0].contains("xPaid")) { SpellAbility root = sa.getRootAbility(); @@ -1672,7 +1678,8 @@ public static int xCount(Card c, final String s, final CardTraitBase ctb) { // and the spell that became that object as it resolved had a value of X chosen for any of its costs, // the value of X for that ability is the same as the value of X for that spell, although the value of X for that permanent is 0. if (TriggerType.ChangesZone.equals(t.getMode()) && ZoneType.Battlefield.name().equals(t.getParam("Destination"))) { - return doXMath(c.getXManaCostPaid(), expr, c, ctb); + int x = isUnlinkedFromCastSA(ctb, c) ? 0 : c.getXManaCostPaid(); + return doXMath(x, expr, c, ctb); } else if (TriggerType.SpellCast.equals(t.getMode())) { // Cast Trigger like Hydroid Krasis SpellAbilityStackInstance castSI = (SpellAbilityStackInstance) root.getTriggeringObject(AbilityKey.StackInstance); @@ -1696,7 +1703,8 @@ public static int xCount(Card c, final String s, final CardTraitBase ctb) { } if (root.isReplacementAbility() && sa.hasParam("ETB")) { - return doXMath(c.getXManaCostPaid(), expr, c, ctb); + int x = isUnlinkedFromCastSA(ctb, c) ? 0 : c.getXManaCostPaid(); + return doXMath(x, expr, c, ctb); } return doXMath(0, expr, c, ctb); diff --git a/forge-game/src/main/java/forge/game/cost/ICostVisitor.java b/forge-game/src/main/java/forge/game/cost/ICostVisitor.java index 1ee90baa331..190e1c806ce 100644 --- a/forge-game/src/main/java/forge/game/cost/ICostVisitor.java +++ b/forge-game/src/main/java/forge/game/cost/ICostVisitor.java @@ -105,6 +105,7 @@ public T visit(CostEnlist cost) { public T visit(CostFlipCoin cost) { return null; } + @Override public T visit(CostForage cost) { return null; @@ -146,7 +147,9 @@ public T visit(CostPartMana cost) { } @Override - public T visit(CostPromiseGift cost) { return null; } + public T visit(CostPromiseGift cost) { + return null; + } @Override public T visit(CostPutCardToLib cost) { diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index cd28fa4316a..75262669cfe 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -665,6 +665,7 @@ public void runReplaceDamage(final boolean isCombat, final CardDamageMap damageM } List possibleReplacers = new ArrayList<>(replaceCandidateMap.keySet()); + // TODO should be able to choose different order for each entity ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect(possibleReplacers); List> runParamList = replaceCandidateMap.get(chosenRE); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java index 750d7403a42..9ee50bc9fc1 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java @@ -78,9 +78,8 @@ private static String getCombatDescription(final CombatView localCombat, final G } display.append("\n"); - PlayerView controller = null; if (defender instanceof CardView) { - controller = ((CardView) defender).getController(); + PlayerView controller = ((CardView) defender).getController(); if (controller == null) //shouldn't be null but display card's + controller ie Black Knight's controller display.append(Lang.getInstance().getPossesive(defender.getName())).append(" controller"); diff --git a/forge-gui/res/cardsfolder/i/infernal_vessel.txt b/forge-gui/res/cardsfolder/i/infernal_vessel.txt index 8aec8a859df..064ca619fab 100644 --- a/forge-gui/res/cardsfolder/i/infernal_vessel.txt +++ b/forge-gui/res/cardsfolder/i/infernal_vessel.txt @@ -2,7 +2,7 @@ Name:Infernal Vessel ManaCost:2 B Types:Creature Human Cleric PT:2/1 -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self+notDemon | Execute$ TrigReturn | TriggerDescription$ When this creature dies, if it wasn't a Demon, return it to the battlefield under its owner's control with two +1/+1 counters on it. It's a Demon in addition to its other types. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self+nonDemon | Execute$ TrigReturn | TriggerDescription$ When this creature dies, if it wasn't a Demon, return it to the battlefield under its owner's control with two +1/+1 counters on it. It's a Demon in addition to its other types. SVar:TrigReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ TriggeredNewCardLKICopy | WithCountersType$ P1P1 | WithCountersAmount$ 2 | AnimateSubAbility$ DBAnimate SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Demon | Duration$ Permanent Oracle:When this creature dies, if it wasn't a Demon, return it to the battlefield under its owner's control with two +1/+1 counters on it. It's a Demon in addition to its other types. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/k/king_of_the_oathbreakers.txt b/forge-gui/res/cardsfolder/k/king_of_the_oathbreakers.txt index 9e400b406ba..4a93802da32 100644 --- a/forge-gui/res/cardsfolder/k/king_of_the_oathbreakers.txt +++ b/forge-gui/res/cardsfolder/k/king_of_the_oathbreakers.txt @@ -3,7 +3,7 @@ ManaCost:2 W B Types:Legendary Creature Spirit Noble PT:3/3 K:Flying -T:Mode$ BecomesTarget | ValidTarget$ Card.Self,Spirit.YouCtrl+Other | ValidSource$ Spell | TriggerZones$ Battlefield | Execute$ TrigPhaseOut | TriggerDescription$ Whenever CARDNAME or another Spirit you control becomes the target of a spell, it phases out. (Treat it and anything attached to it as though they don't exist until your next turn.) +T:Mode$ BecomesTarget | ValidTarget$ Card.Self,Spirit.YouCtrl+Other+inZoneBattlefield | ValidSource$ Spell | TriggerZones$ Battlefield | Execute$ TrigPhaseOut | TriggerDescription$ Whenever CARDNAME or another Spirit you control becomes the target of a spell, it phases out. (Treat it and anything attached to it as though they don't exist until your next turn.) SVar:TrigPhaseOut:DB$ Phases | Defined$ TriggeredTargetLKICopy T:Mode$ PhaseIn | ValidCard$ Card.Self,Spirit.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another Spirit you control phases in, create a tapped 1/1 white Spirit creature token with flying. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_spirit_flying | TokenOwner$ You | TokenTapped$ True diff --git a/forge-gui/res/cardsfolder/n/needletooth_pack.txt b/forge-gui/res/cardsfolder/n/needletooth_pack.txt index 4c7b222a5c3..81e7abaf07b 100644 --- a/forge-gui/res/cardsfolder/n/needletooth_pack.txt +++ b/forge-gui/res/cardsfolder/n/needletooth_pack.txt @@ -2,7 +2,7 @@ Name:Needletooth Pack ManaCost:3 G G Types:Creature Dinosaur PT:4/5 -T:Mode$ Phase | Phase$ End of Turn | CheckSVar$ Morbid | SVarCompare$ GE1 | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Morbid — At the beginning of your end step, if a creature died this turn, put two +1/+1 counters on target creature you control. +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | CheckSVar$ Morbid | SVarCompare$ GE1 | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Morbid — At the beginning of your end step, if a creature died this turn, put two +1/+1 counters on target creature you control. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 2 SVar:Morbid:Count$Morbid.1.0 Oracle:Morbid — At the beginning of your end step, if a creature died this turn, put two +1/+1 counters on target creature you control. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/t/the_mindskinner.txt b/forge-gui/res/cardsfolder/t/the_mindskinner.txt index fce38f7d439..74bcacb712a 100644 --- a/forge-gui/res/cardsfolder/t/the_mindskinner.txt +++ b/forge-gui/res/cardsfolder/t/the_mindskinner.txt @@ -3,7 +3,7 @@ ManaCost:U U U Types:Legendary Enchantment Creature Nightmare PT:10/1 S:Mode$ CantBlockBy | ValidAttacker$ Creature.Self | Description$ CARDNAME can't be blocked. -R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Opponent | ReplaceWith$ Mill | PreventionEffect$ True | ExecuteMode$ PerTarget | Description$ If a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards. +R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Opponent | ReplaceWith$ Mill | PreventionEffect$ True | ExecuteMode$ PerSource | Description$ If a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards. SVar:Mill:DB$ Mill | Defined$ Opponent | NumCards$ X SVar:X:ReplaceCount$DamageAmount Oracle:The Mindskinner can't be blocked.\nIf a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards. diff --git a/forge-gui/src/main/java/forge/gamemodes/match/GameLobby.java b/forge-gui/src/main/java/forge/gamemodes/match/GameLobby.java index c92bc865263..340a9633b46 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/GameLobby.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/GameLobby.java @@ -443,17 +443,13 @@ public Runnable startGame() { Deck deck = slot.getDeck(); RegisteredPlayer rp = new RegisteredPlayer(deck); - if (variantTypes.isEmpty()) { - rp.setTeamNumber(team); - players.add(rp.setPlayer(lobbyPlayer)); - } - else { + if (!variantTypes.isEmpty()) { if (isCommanderMatch) { final GameType commanderGameType = isOathbreakerMatch ? GameType.Oathbreaker : - isTinyLeadersMatch ? GameType.TinyLeaders : - isBrawlMatch ? GameType.Brawl : - GameType.Commander; + isTinyLeadersMatch ? GameType.TinyLeaders : + isBrawlMatch ? GameType.Brawl : + GameType.Commander; if (checkLegality) { final String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck); if (errMsg != null) { @@ -481,7 +477,6 @@ else if (autoGenerateVariant != null) { Iterable schemes = null; Iterable planes = null; - //Archenemy if (variantTypes.contains(GameType.ArchenemyRumble) || (variantTypes.contains(GameType.Archenemy) && isArchenemy)) { final CardPool schemePool = deck.get(DeckSection.Schemes); @@ -495,7 +490,6 @@ else if (autoGenerateVariant != null) { schemes = schemePool == null ? Collections.emptyList() : schemePool.toFlatList(); } - //Planechase if (variantTypes.contains(GameType.Planechase)) { final CardPool planePool = deck.get(DeckSection.Planes); if (checkLegality) { @@ -508,7 +502,6 @@ else if (autoGenerateVariant != null) { planes = planePool == null ? Collections.emptyList() : planePool.toFlatList(); } - //Vanguard if (variantTypes.contains(GameType.Vanguard)) { if (avatarPool == null || avatarPool.countAll() == 0) { //ERROR! null if avatar deselected on list SOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblNoSelectedVanguardAvatarForPlayer", name)); @@ -517,10 +510,11 @@ else if (autoGenerateVariant != null) { } rp = RegisteredPlayer.forVariants(activeSlots.size(), variantTypes, deck, schemes, isArchenemy, planes, avatarPool); - rp.setTeamNumber(team); - players.add(rp.setPlayer(lobbyPlayer)); } + rp.setTeamNumber(team); + players.add(rp.setPlayer(lobbyPlayer)); + if (!isAI) { guis.put(rp, gui); }