mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
- Added very basic AddPhase AF
- Added support in PhaseHandler for Additional phases - Convert Finest Hour to AddPhase
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -12918,6 +12918,7 @@ src/main/java/forge/card/abilityfactory/CommonDrawback.java svneol=native#text/p
|
|||||||
src/main/java/forge/card/abilityfactory/CommonSpell.java -text
|
src/main/java/forge/card/abilityfactory/CommonSpell.java -text
|
||||||
src/main/java/forge/card/abilityfactory/SpellAiLogic.java -text
|
src/main/java/forge/card/abilityfactory/SpellAiLogic.java -text
|
||||||
src/main/java/forge/card/abilityfactory/SpellEffect.java -text
|
src/main/java/forge/card/abilityfactory/SpellEffect.java -text
|
||||||
|
src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java -text
|
||||||
src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java svneol=native#text/plain
|
src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java svneol=native#text/plain
|
||||||
src/main/java/forge/card/abilityfactory/ai/AlwaysPlayAi.java -text
|
src/main/java/forge/card/abilityfactory/ai/AlwaysPlayAi.java -text
|
||||||
src/main/java/forge/card/abilityfactory/ai/AnimateAi.java -text
|
src/main/java/forge/card/abilityfactory/ai/AnimateAi.java -text
|
||||||
@@ -13013,6 +13014,7 @@ src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java -text
|
|||||||
src/main/java/forge/card/abilityfactory/ai/UntapAi.java -text
|
src/main/java/forge/card/abilityfactory/ai/UntapAi.java -text
|
||||||
src/main/java/forge/card/abilityfactory/ai/UntapAllAi.java -text
|
src/main/java/forge/card/abilityfactory/ai/UntapAllAi.java -text
|
||||||
src/main/java/forge/card/abilityfactory/effects/AbandonEffect.java -text
|
src/main/java/forge/card/abilityfactory/effects/AbandonEffect.java -text
|
||||||
|
src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java -text
|
||||||
src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text
|
src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text
|
||||||
src/main/java/forge/card/abilityfactory/effects/AnimateAllEffect.java -text
|
src/main/java/forge/card/abilityfactory/effects/AnimateAllEffect.java -text
|
||||||
src/main/java/forge/card/abilityfactory/effects/AnimateEffect.java -text
|
src/main/java/forge/card/abilityfactory/effects/AnimateEffect.java -text
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
Name:Finest Hour
|
Name:Finest Hour
|
||||||
ManaCost:2 G W U
|
ManaCost:2 G W U
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
Text:Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.
|
Text:no text
|
||||||
K:Exalted
|
K:Exalted
|
||||||
|
T:Mode$ Attacks | ValidCard$ Creature.YouCtrl | Alone$ True | TriggerZones$ Battlefield | Execute$ TrigUntap | FirstCombat$ True | TriggerDescription$ Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.
|
||||||
|
SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttacker | SubAbility$ DBAddCombat
|
||||||
|
SVar:DBAddCombat:DB$ AddPhase | ExtraPhase$ BeginCombat | AfterPhase$ EndCombat
|
||||||
SVar:PlayMain1:TRUE
|
SVar:PlayMain1:TRUE
|
||||||
SVar:Rarity:Rare
|
SVar:Rarity:Rare
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/finest_hour.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/finest_hour.jpg
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import forge.card.abilityfactory.effects.*;
|
|||||||
public enum ApiType {
|
public enum ApiType {
|
||||||
|
|
||||||
Abandon (AbandonEffect.class, AlwaysPlayAi.class),
|
Abandon (AbandonEffect.class, AlwaysPlayAi.class),
|
||||||
|
AddPhase (AddPhaseEffect.class, AddPhaseAi.class),
|
||||||
AddTurn (AddTurnEffect.class, AddTurnAi.class),
|
AddTurn (AddTurnEffect.class, AddTurnAi.class),
|
||||||
Animate (AnimateEffect.class, AnimateAi.class),
|
Animate (AnimateEffect.class, AnimateAi.class),
|
||||||
AnimateAll (AnimateAllEffect.class, AnimateAllAi.class),
|
AnimateAll (AnimateAllEffect.class, AnimateAllAi.class),
|
||||||
|
|||||||
18
src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java
Normal file
18
src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package forge.card.abilityfactory.ai;
|
||||||
|
|
||||||
|
import forge.card.abilityfactory.SpellAiLogic;
|
||||||
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this type.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AddPhaseAi extends SpellAiLogic {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package forge.card.abilityfactory.effects;
|
||||||
|
|
||||||
|
import forge.Singletons;
|
||||||
|
import forge.card.abilityfactory.SpellEffect;
|
||||||
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.phase.PhaseHandler;
|
||||||
|
import forge.game.phase.PhaseType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write javadoc for this type.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AddPhaseEffect extends SpellEffect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve(SpellAbility sa) {
|
||||||
|
PhaseHandler phaseHandler = Singletons.getModel().getGame().getPhaseHandler();
|
||||||
|
PhaseType extra = PhaseType.smartValueOf(sa.getParam("ExtraPhase"));
|
||||||
|
|
||||||
|
PhaseType after;
|
||||||
|
if (sa.hasParam("AfterPhase")) {
|
||||||
|
after = PhaseType.smartValueOf(sa.getParam("AfterPhase"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
after = phaseHandler.getPhase();
|
||||||
|
}
|
||||||
|
|
||||||
|
phaseHandler.addExtraPhase(after, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import forge.card.abilityfactory.AbilityFactory;
|
|||||||
import forge.card.cardfactory.CardFactoryUtil;
|
import forge.card.cardfactory.CardFactoryUtil;
|
||||||
import forge.card.spellability.Ability;
|
import forge.card.spellability.Ability;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.Expressions;
|
import forge.util.Expressions;
|
||||||
@@ -227,20 +228,27 @@ public abstract class Trigger extends TriggerReplacementBase {
|
|||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public final boolean phasesCheck() {
|
public final boolean phasesCheck() {
|
||||||
|
PhaseHandler phaseHandler = Singletons.getModel().getGame().getPhaseHandler();
|
||||||
if (null != validPhases) {
|
if (null != validPhases) {
|
||||||
if (!validPhases.contains(Singletons.getModel().getGame().getPhaseHandler().getPhase())) {
|
if (!validPhases.contains(phaseHandler.getPhase())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getMapParams().containsKey("PlayerTurn")) {
|
if (this.getMapParams().containsKey("PlayerTurn")) {
|
||||||
if (!Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(this.getHostCard().getController())) {
|
if (!phaseHandler.isPlayerTurn(this.getHostCard().getController())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getMapParams().containsKey("OpponentTurn")) {
|
if (this.getMapParams().containsKey("OpponentTurn")) {
|
||||||
if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(this.getHostCard().getController())) {
|
if (phaseHandler.isPlayerTurn(this.getHostCard().getController())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getMapParams().containsKey("FirstCombat")) {
|
||||||
|
if (!phaseHandler.isFirstCombat()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3092,41 +3092,6 @@ public class CombatUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Player phasingPlayer = c.getController();
|
final Player phasingPlayer = c.getController();
|
||||||
// Finest Hour untaps the creature on the first combat phase
|
|
||||||
if ((phasingPlayer.getCardsIn(ZoneType.Battlefield, "Finest Hour").size() > 0)
|
|
||||||
&& Singletons.getModel().getGame().getPhaseHandler().isFirstCombat()) {
|
|
||||||
// Untap the attacking creature
|
|
||||||
final Ability fhUntap = new Ability(c, "0") {
|
|
||||||
@Override
|
|
||||||
public void resolve() {
|
|
||||||
crd.untap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final StringBuilder sbUntap = new StringBuilder();
|
|
||||||
sbUntap.append(c).append(" - (Finest Hour) untap.");
|
|
||||||
fhUntap.setDescription(sbUntap.toString());
|
|
||||||
fhUntap.setStackDescription(sbUntap.toString());
|
|
||||||
|
|
||||||
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(fhUntap);
|
|
||||||
|
|
||||||
// If any Finest Hours, queue up a new combat phase
|
|
||||||
for (int ix = 0; ix < phasingPlayer.getCardsIn(ZoneType.Battlefield, "Finest Hour").size(); ix++) {
|
|
||||||
final Ability fhAddCombat = new Ability(c, "0") {
|
|
||||||
@Override
|
|
||||||
public void resolve() {
|
|
||||||
Singletons.getModel().getGame().getPhaseHandler().addExtraCombat();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final StringBuilder sbACom = new StringBuilder();
|
|
||||||
sbACom.append(c).append(" - (Finest Hour) ").append(phasingPlayer).append(" gets Extra Combat Phase.");
|
|
||||||
fhAddCombat.setDescription(sbACom.toString());
|
|
||||||
fhAddCombat.setStackDescription(sbACom.toString());
|
|
||||||
|
|
||||||
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(fhAddCombat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size() > 0) {
|
if (phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size() > 0) {
|
||||||
for (int i = 0; i < phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size(); i++) {
|
for (int i = 0; i < phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size(); i++) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package forge.game.phase;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import com.esotericsoftware.minlog.Log;
|
import com.esotericsoftware.minlog.Log;
|
||||||
@@ -59,8 +60,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
|||||||
// Start turn at 0, so first untap step will turn it to 1
|
// Start turn at 0, so first untap step will turn it to 1
|
||||||
|
|
||||||
private final transient Stack<ExtraTurn> extraTurns = new Stack<ExtraTurn>();
|
private final transient Stack<ExtraTurn> extraTurns = new Stack<ExtraTurn>();
|
||||||
|
private final transient Map<PhaseType, Stack<PhaseType>> extraPhases = new HashMap<PhaseType, Stack<PhaseType>>();
|
||||||
private int extraCombats = 0;
|
|
||||||
|
|
||||||
private int nCombatsThisTurn = 0;
|
private int nCombatsThisTurn = 0;
|
||||||
private boolean bPreventCombatDamageThisTurn = false;
|
private boolean bPreventCombatDamageThisTurn = false;
|
||||||
@@ -465,17 +465,6 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
|||||||
this.resetAttackedThisCombat(this.getPlayerTurn());
|
this.resetAttackedThisCombat(this.getPlayerTurn());
|
||||||
this.bCombat = false;
|
this.bCombat = false;
|
||||||
|
|
||||||
// TODO: ExtraCombat needs to be changed for other spell/abilities
|
|
||||||
// that give extra combat can do it like ExtraTurn stack ExtraPhases
|
|
||||||
if (this.extraCombats > 0) {
|
|
||||||
final Player player = this.getPlayerTurn();
|
|
||||||
|
|
||||||
this.bCombat = true;
|
|
||||||
this.extraCombats--;
|
|
||||||
game.getCombat().reset();
|
|
||||||
game.getCombat().setAttackingPlayer(player);
|
|
||||||
this.phase = PhaseType.COMBAT_BEGIN;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLEANUP:
|
case CLEANUP:
|
||||||
@@ -489,13 +478,29 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
|||||||
default: // no action
|
default: // no action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
if (this.bRepeat) { // for when Cleanup needs to repeat itself
|
if (this.bRepeat) { // for when Cleanup needs to repeat itself
|
||||||
this.bRepeat = false;
|
this.bRepeat = false;
|
||||||
|
sb.append("Repeat Phase");
|
||||||
} else {
|
} else {
|
||||||
this.phase = phase.getNextPhase();
|
// If the phase that's ending has a stack of additional phases
|
||||||
|
// Take the LIFO one and move to that instead of the normal one
|
||||||
|
if (this.extraPhases.containsKey(phase)) {
|
||||||
|
PhaseType nextPhase = this.extraPhases.get(phase).pop();
|
||||||
|
// If no more additional phases are available, remove it from the map
|
||||||
|
// and let the next add, reput the key
|
||||||
|
if (this.extraPhases.get(phase).isEmpty()) {
|
||||||
|
this.extraPhases.remove(phase);
|
||||||
|
}
|
||||||
|
this.phase = nextPhase;
|
||||||
|
sb.append("Additional Phase");
|
||||||
|
} else {
|
||||||
|
this.phase = phase.getNextPhase();
|
||||||
|
sb.append("Phase");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game.getGameLog().add("Phase", this.getPlayerTurn() + " " + this.getPhase().Name, 6);
|
game.getGameLog().add(sb.toString(), this.getPlayerTurn() + " " + this.getPhase().Name, 6);
|
||||||
|
|
||||||
// **** Anything BELOW Here is actually in the next phase. Maybe move
|
// **** Anything BELOW Here is actually in the next phase. Maybe move
|
||||||
// this to handleBeginPhase
|
// this to handleBeginPhase
|
||||||
@@ -659,15 +664,20 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
|||||||
return this.extraTurns.push(new ExtraTurn(player));
|
return this.extraTurns.push(new ExtraTurn(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* addExtraCombat.
|
* addExtraPhase.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public final void addExtraCombat() {
|
public final void addExtraPhase(final PhaseType afterPhase, final PhaseType extraPhase) {
|
||||||
// Extra combats can only happen
|
// 300.7. Some effects can add phases to a turn. They do this by adding the phases directly after the specified phase.
|
||||||
this.extraCombats++;
|
// If multiple extra phases are created after the same phase, the most recently created phase will occur first.
|
||||||
|
if (!this.extraPhases.containsKey(afterPhase)) {
|
||||||
|
this.extraPhases.put(afterPhase, new Stack<PhaseType>());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.extraPhases.get(afterPhase).push(extraPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public enum PhaseType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Write javadoc for this method.
|
* Get the next PhaseType in turn order.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public PhaseType getNextPhase() {
|
public PhaseType getNextPhase() {
|
||||||
|
|||||||
Reference in New Issue
Block a user