diff --git a/res/cards.txt b/res/cards.txt index 61dcac5f648..8fff92e3ac3 100644 --- a/res/cards.txt +++ b/res/cards.txt @@ -1,3 +1,47 @@ +Bituminous Blast +3 B R +Instant +Cascade. +spDamageTgtC:4 + +Enlisted Wurm +4 G W +Creature Wurm +no text +5/5 +Cascade + +Kathari Remnant +2 U B +Creature Bird Skeleton +no text +0/1 +Flying +RegenerateMe:B +Cascade + +Ardent Plea +1 W U +Enchantment +no text +Exalted +Cascade + +Kor Skyfisher +1 W +Creature Kor Soldier +When Kor Skyfisher enters the battlefield, return a permanent you control to its owner's hand. +2/3 +Flying + +Bloodbraid Elf +2 R G +Creature Elf +no text +3/2 +Haste +Cascade + Bloodghast B B Creature Vampire Spirit @@ -120,7 +164,7 @@ Upkeep:1 W Arctic Nishoba 5 G -Creature Cat Warrior +Creature Cat When Arctic Nishoba is put into a graveyard from the battlefield, you gain 2 life for each age counter on it. 6/6 Trample @@ -6317,7 +6361,7 @@ TgtKPump B B:Shadow Ember Shot 6 R Instant -no text +Draw a card. spDamageTgtCP:3 Draw a card. @@ -6330,7 +6374,7 @@ TgtKPump 1 W:First Strike Zap 2 R Instant -no text +no text spDamageTgtCP:1 Draw a card. diff --git a/src/forge/Card.java b/src/forge/Card.java index 452e455727d..7ff45d31e59 100644 --- a/src/forge/Card.java +++ b/src/forge/Card.java @@ -371,7 +371,6 @@ public class Card extends MyObservable manaAbility.remove((Ability_Mana)a); else spellAbility.remove(a); - } @@ -411,6 +410,33 @@ public class Card extends MyObservable res.toArray(s); return s; } + + public ArrayList getSpells() + { + ArrayList s = new ArrayList(spellAbility); + ArrayList res = new ArrayList(); + + for (SpellAbility sa : s) + { + if (sa.isSpell() ) + res.add(sa); + } + return res; + } + + public ArrayList getBasicSpells() + { + ArrayList s = new ArrayList(spellAbility); + ArrayList res = new ArrayList(); + + for (SpellAbility sa : s) + { + if (sa.isSpell() && !sa.isFlashBackAbility() && !sa.isBuyBackAbility()) + res.add(sa); + } + return res; + } + //shield = regeneration public void setShield(int n) {nShield = n;} diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java index 0222eb96b32..9e43c663e65 100644 --- a/src/forge/CardFactory.java +++ b/src/forge/CardFactory.java @@ -1694,7 +1694,7 @@ public class CardFactory implements NewConstants { DamageTgt.setStackDescription(card.getName() + " - deals " + NumDmg[0] + " damage."); if (TgtCP[0]) - DamageTgt.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(DamageTgt, true)); + DamageTgt.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(DamageTgt, true, false)); else if (TgtCreature[0]) DamageTgt.setBeforePayMana(CardFactoryUtil.input_targetCreature(DamageTgt)); else if (TgtPlayer[0]) @@ -1836,7 +1836,7 @@ public class CardFactory implements NewConstants { };//Ability_Activated ability.setDescription(manaCost + ": " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); card.addSpellAbility(ability); }//!tapCost @@ -1896,7 +1896,7 @@ public class CardFactory implements NewConstants { };//Ability_Tap ability.setDescription("tap: " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); card.addSpellAbility(ability); }//tapOnlyCost @@ -1954,7 +1954,7 @@ public class CardFactory implements NewConstants { };//Ability_Tap ability.setDescription(manaCost + ", tap: " + Desc); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); card.addSpellAbility(ability); }//!tapOnlyCost && tapCost }//n @@ -2600,9 +2600,7 @@ public class CardFactory implements NewConstants { } }//flashback - - if (hasKeyword(card, "Devour") != -1) { int n = hasKeyword(card, "Devour"); @@ -6147,7 +6145,7 @@ public class CardFactory implements NewConstants { }; spell.setChooseTargetAI(CardFactoryUtil.AI_targetHumanCreatureOrPlayer()); - spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell, true)); + spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell, true, false)); card.clearSpellAbility(); card.addSpellAbility(spell); }//*************** END ************ END ************************** @@ -8366,15 +8364,16 @@ public class CardFactory implements NewConstants { } };//flashback + flashback.setFlashBackAbility(true); flashback.setManaCost("4 R"); - flashback.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(flashback,true)); + flashback.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(flashback, true, false)); flashback.setDescription("Flashback: 4R"); card.clearSpellAbility(); card.addSpellAbility(spell); card.addSpellAbility(flashback); - spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell,true)); + spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell, true, false)); card.setFlashback(true); }//*************** END ************ END ************************** @@ -8511,7 +8510,7 @@ public class CardFactory implements NewConstants { card.addSpellAbility(spell); - spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell, true)); + spell.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(spell, true, false)); }//*************** END ************ END ************************** //*************** START *********** START ************************** @@ -11191,6 +11190,7 @@ public class CardFactory implements NewConstants { } };//Input + flashback.setFlashBackAbility(true); flashback.setManaCost("5 R"); flashback.setBeforePayMana(targetFB); flashback.setDescription("Flashback: 5 R"); @@ -12190,16 +12190,23 @@ public class CardFactory implements NewConstants { Card c1 = list.get(0); list.remove(c1); + /* AllZone.Computer_Graveyard.add(c1); AllZone.Computer_Hand.remove(c1); + */ + AllZone.GameAction.discard(c1); if (list.size()== 0) return; Card c2 = list.get(0); list.remove(c2); + + /* AllZone.Computer_Graveyard.add(c2); AllZone.Computer_Hand.remove(c2); + */ + AllZone.GameAction.discard(c2); if (c1.getType().contains("Land")) { PlayerLife life = AllZone.GameAction.getPlayerLife(Constant.Player.Human); @@ -12216,7 +12223,6 @@ public class CardFactory implements NewConstants { public void computerResolve() { PlayerZone hand = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Human); - PlayerZone grave = AllZone.getZone(Constant.Zone.Graveyard, Constant.Player.Human); CardList list = new CardList(hand.getCards()); if (list.size() > 0){ @@ -12225,9 +12231,12 @@ public class CardFactory implements NewConstants { Card c = (Card)o; list.remove(c); - + + /* hand.remove(c); grave.add(c); + */ + AllZone.GameAction.discard(c); if(c.getType().contains("Land")) { PlayerLife life = AllZone.GameAction.getPlayerLife(Constant.Player.Computer); @@ -12241,8 +12250,11 @@ public class CardFactory implements NewConstants { Card c2 = (Card)o2; list.remove(c2); + /* hand.remove(c2); grave.add(c2); + */ + AllZone.GameAction.discard(c2); if(c2.getType().contains("Land")) { PlayerLife life = AllZone.GameAction.getPlayerLife(Constant.Player.Computer); @@ -13560,7 +13572,7 @@ public class CardFactory implements NewConstants { }//resolve() };//Ability_Activated - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); ability.setDescription("R, Sacrifice Pyrite Spellbomb: Pyrite Spellbomb deals 2 damage to target creature or player."); card.addSpellAbility(ability); }//*************** END ************ END ************************** @@ -16273,7 +16285,7 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); { AllZone.GameAction.sacrifice(card); } - }, true)); + }, true, false)); }//*************** END ************ END ************************** //*************** START *********** START ************************** @@ -16633,7 +16645,7 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase(); }; ability.setDescription("3, tap: Reveal cards from the top of your library until you reveal a land card. Goblin Charbelcher deals damage equal to the number of nonland cards revealed this way to target creature or player. If the revealed land card was a Mountain, Goblin Charbelcher deals double that damage instead. Put the revealed cards on the bottom of your library in any order."); ability.setChooseTargetAI(CardFactoryUtil.AI_targetHuman()); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); card.addSpellAbility(ability); diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index fc8c632c33d..f58561211aa 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -330,12 +330,12 @@ public class CardFactoryUtil } return biggest; } - public static Input input_targetCreaturePlayer(final SpellAbility spell, boolean targeted) + public static Input input_targetCreaturePlayer(final SpellAbility spell, boolean targeted, boolean free) { - return input_targetCreaturePlayer(spell, Command.Blank, targeted); + return input_targetCreaturePlayer(spell, Command.Blank, targeted, free); } - public static Input input_targetCreaturePlayer(final SpellAbility spell, final Command paid, final boolean targeted) + public static Input input_targetCreaturePlayer(final SpellAbility spell, final Command paid, final boolean targeted, final boolean free) { Input target = new Input() { @@ -366,8 +366,9 @@ public class CardFactoryUtil if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility((Ability_Tap)spell)); - else if(spell.getManaCost().equals("0")) + else if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -405,8 +406,9 @@ public class CardFactoryUtil if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility((Ability_Tap)spell)); - else if(spell.getManaCost().equals("0")) + else if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -442,8 +444,9 @@ public class CardFactoryUtil if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility((Ability_Tap)spell)); - else if(spell.getManaCost().equals("0")) + else if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -476,8 +479,9 @@ public class CardFactoryUtil AllZone.getZone(card).remove(card); AllZone.GameAction.moveToGraveyard(card); - if(spell.getManaCost().equals("0")) + if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -657,7 +661,7 @@ public class CardFactoryUtil if (loss != 0) lifecost = ", pay " + lifeloss + " life"; - + flashback.setFlashBackAbility(true); flashback.setManaCost(manaCost); flashback.setDescription("Flashback: " + manaCost + lifecost); flashback.setStackDescription("Flashback: " + sourceCard.getName()); @@ -1591,8 +1595,9 @@ public class CardFactoryUtil spell.setTargetCard(card); if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility((Ability_Tap)spell)); - else if(spell.getManaCost().equals("0")) + else if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -1749,8 +1754,9 @@ public class CardFactoryUtil { if(spell instanceof Ability_Tap && spell.getManaCost().equals("0")) stopSetNext(new Input_NoCost_TapAbility((Ability_Tap)spell)); - else if(spell.getManaCost().equals("0"))//for "sacrifice this card" abilities + else if(spell.getManaCost().equals("0") || this.isFree())//for "sacrifice this card" abilities { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -1835,8 +1841,9 @@ public class CardFactoryUtil public void selectPlayer(String player) { spell.setTargetPlayer(player); - if(spell.getManaCost().equals("0")) + if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } @@ -1864,8 +1871,9 @@ public class CardFactoryUtil command.execute(); spell.setTargetPlayer(player); - if(spell.getManaCost().equals("0")) + if(spell.getManaCost().equals("0") || this.isFree()) { + this.setFree(false); AllZone.Stack.add(spell); stop(); } diff --git a/src/forge/CardFactory_Creatures.java b/src/forge/CardFactory_Creatures.java index e8dafd4e1a3..e3af0a870c3 100644 --- a/src/forge/CardFactory_Creatures.java +++ b/src/forge/CardFactory_Creatures.java @@ -328,7 +328,7 @@ public class CardFactory_Creatures { a2.setBeforePayMana(CardFactoryUtil.input_targetPlayer(a2)); }//*************** END ************ END ************************** - + /* //*************** START *********** START ************************** else if(cardName.equals("Street Wraith")) { @@ -375,6 +375,7 @@ public class CardFactory_Creatures { a1.setStackDescription(card +" Cycling: Draw a card"); }//*************** END ************ END ************************** + */ //*************** START *********** START ************************** else if(cardName.equals("Street Wraith")) @@ -498,7 +499,7 @@ public class CardFactory_Creatures { if (c.getKeyword().contains("Lifelink")) GameActionUtil.executeLifeLinkEffects(c,n); - CardList cl = CardFactoryUtil.getAurasEnchanting(card, "Guilty Conscience"); + CardList cl = CardFactoryUtil.getAurasEnchanting(c, "Guilty Conscience"); for (Card crd : cl) { GameActionUtil.executeGuiltyConscienceEffects(c, crd, n); @@ -2275,7 +2276,7 @@ public class CardFactory_Creatures { public void execute() { if(card.getController().equals(Constant.Player.Human)) - AllZone.InputControl.setInput(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + AllZone.InputControl.setInput(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); else { CardList list = CardFactoryUtil.AI_getHumanCreature(3, card, true); @@ -6727,7 +6728,7 @@ public class CardFactory_Creatures { card.addSpellAbility(ability); ability.setDescription("tap: "+ cardName +" deals 1 damage to target creature or player."); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); }//*************** END ************ END ************************** @@ -6796,7 +6797,7 @@ public class CardFactory_Creatures { card.addSpellAbility(ability); ability.setDescription("tap: " +cardName + " deals 2 damage to target creature or player and 3 damage to you."); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability,true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability,true,false)); }//*************** END ************ END ************************** @@ -7331,7 +7332,7 @@ public class CardFactory_Creatures { } }); - stopSetNext(CardFactoryUtil.input_targetSpecific(ability, all, "Destroy target creature or enchantment.", true)); + stopSetNext(CardFactoryUtil.input_targetSpecific(ability, all, "Choose target creature or enchantment.", true)); } }; ability.setBeforePayMana(runtime); @@ -9269,7 +9270,7 @@ public class CardFactory_Creatures { { AllZone.GameAction.sacrifice(card); } - }, true)); + }, true, false)); }//*************** END ************ END ************************** //*************** START *********** START ************************** @@ -11572,7 +11573,7 @@ public class CardFactory_Creatures { card.addSpellAbility(ability); ability.setDescription("1 R, Sacrifice a goblin: Siege-Gang Commander deals 2 damage to target creature or player ."); ability.setStackDescription("Siege-Gang Commander deals 2 damage to target creature or player"); - ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true)); + ability.setBeforePayMana(CardFactoryUtil.input_targetCreaturePlayer(ability, true, false)); }//*************** END ************ END ************************** @@ -13399,7 +13400,7 @@ public class CardFactory_Creatures { }//*************** END ************ END ************************** //*************** START *********** START ************************** - else if(cardName.equals("Dream Stalker")) + else if(cardName.equals("Dream Stalker") || cardName.equals("Kor Skyfisher")) { final SpellAbility ability = new Ability(card, "0") { @@ -18219,7 +18220,7 @@ public class CardFactory_Creatures { { AllZone.GameAction.sacrifice(card); } - }, true)); + }, true, false)); }//*************** END ************ END ************************** //*************** START *********** START ************************** diff --git a/src/forge/ComputerUtil.java b/src/forge/ComputerUtil.java index cb5f7ddd517..ed03d6de439 100644 --- a/src/forge/ComputerUtil.java +++ b/src/forge/ComputerUtil.java @@ -64,6 +64,20 @@ private static Random random = new Random(); } + final static public void playStackFree(SpellAbility sa) + { + if (AllZone.GameAction.isCardInZone(sa.getSourceCard(),AllZone.Computer_Hand)) + AllZone.Computer_Hand.remove(sa.getSourceCard()); + + + if (sa.getSourceCard().getKeyword().contains("Draw a card.")) + AllZone.GameAction.drawCard(sa.getSourceCard().getController()); + + AllZone.Stack.add(sa); + + + } + final static public void playNoStack(SpellAbility sa) { if(canPayCost(sa)) diff --git a/src/forge/GameAction.java b/src/forge/GameAction.java index ff2498e45cd..f205c31a61d 100644 --- a/src/forge/GameAction.java +++ b/src/forge/GameAction.java @@ -1239,19 +1239,20 @@ private int getDifferentLand(CardList list, String land) public void playCardNoCost(Card c) { - SpellAbility[] choices = canPlaySpellAbility(c.getSpellAbility()); + //SpellAbility[] choices = (SpellAbility[]) c.getSpells().toArray(); + ArrayList choices = c.getBasicSpells(); SpellAbility sa; /* System.out.println(choices.length); for(int i = 0; i < choices.length; i++) System.out.println(choices[i]); */ - if(choices.length == 0) + if(choices.size() == 0) return; - else if(choices.length == 1) - sa = choices[0]; + else if(choices.size() == 1) + sa = (SpellAbility)choices.get(0); else - sa = (SpellAbility) AllZone.Display.getChoiceOptional("Choose", choices); + sa = (SpellAbility) AllZone.Display.getChoiceOptional("Choose", choices.toArray()); if(sa == null) return; @@ -1263,11 +1264,21 @@ private int getDifferentLand(CardList list, String land) { if (sa.getBeforePayMana() == null){ AllZone.Stack.add(sa); - if (sa.isTapAbility()) - sa.getSourceCard().tap(); + + /* + if (sa.getAfterPayMana() != null) + AllZone.InputControl.setInput(sa.getAfterPayMana()); + else + { + AllZone.Stack.add(sa); + AllZone.InputControl.setInput(new ComputerAI_StackNotEmpty()); + } + */ } - else + else { + sa.getBeforePayMana().setFree(true); AllZone.InputControl.setInput(sa.getBeforePayMana()); + } } public void playSpellAbility(SpellAbility sa) diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java index 5b8ee3c9f82..d0ba2e7f4bd 100644 --- a/src/forge/GameActionUtil.java +++ b/src/forge/GameActionUtil.java @@ -139,8 +139,82 @@ public class GameActionUtil playCard_Enchantress_Draw(c); playCard_Mold_Adder(c); playCard_Fable_of_Wolf_and_Owl(c); + + playCard_Cascade(c); + } + public static void playCard_Cascade(Card c) + { + + if (c.getKeyword().contains("Cascade") || c.getName().equals("Bituminous Blast")) + { + final String controller = c.getController(); + final PlayerZone lib = AllZone.getZone(Constant.Zone.Library, controller); + final Card cascCard = c; + + final Ability ability = new Ability(c, "0") + { + public void resolve() + { + CardList topOfLibrary = new CardList(lib.getCards()); + CardList revealed = new CardList(); + + if (topOfLibrary.size() == 0) + return; + + Card cascadedCard = null; + Card crd; + int count = 0; + while (cascadedCard == null) + { + crd = topOfLibrary.get(count++); + revealed.add(crd); + lib.remove(crd); + if ((!crd.isLand() && CardUtil.getConvertedManaCost(crd.getManaCost()) < CardUtil.getConvertedManaCost(cascCard.getManaCost()) )) + cascadedCard = crd; + + if (count == topOfLibrary.size() ) + break; + + }//while + AllZone.Display.getChoiceOptional("Revealed cards:", revealed.toArray()); + + if (cascadedCard != null) { + revealed.remove(cascadedCard); + + if (cascadedCard.getController().equals(Constant.Player.Human)) + { + AllZone.GameAction.playCardNoCost(cascadedCard); + } + else + { + ArrayList choices = cascadedCard.getBasicSpells(); + + for (SpellAbility sa : choices ) + { + if (sa.canPlayAI()) + { + ComputerUtil.playStackFree(sa); + break; + } + } + } + + } + revealed.shuffle(); + for (Card bottom : revealed) + { + lib.add(bottom); + } + } + }; + ability.setStackDescription(c + " - Cascade."); + AllZone.Stack.add(ability); + + } + } + public static void playCard_Emberstrike_Duo(Card c) { final String controller = c.getController(); diff --git a/src/forge/Input.java b/src/forge/Input.java index ff6461c884a..db9240d4c43 100644 --- a/src/forge/Input.java +++ b/src/forge/Input.java @@ -3,6 +3,8 @@ public abstract class Input implements java.io.Serializable { private static final long serialVersionUID = -6539552513871194081L; + private boolean isFree = false; + //showMessage() is always the first method called public void showMessage() {AllZone.Display.showMessage("Blank Input");} @@ -37,4 +39,12 @@ public abstract class Input implements java.io.Serializable final public void stopSetNext(Input in) {stop(); AllZone.InputControl.setInput(in);} public String toString() {return "blank";}//returns the Input name like "EmptyStack" + + public void setFree(boolean isFree) { + this.isFree = isFree; + } + + public boolean isFree() { + return isFree; + } } \ No newline at end of file diff --git a/src/forge/SpellAbility.java b/src/forge/SpellAbility.java index 82aeac47ee2..c5656c98fc7 100644 --- a/src/forge/SpellAbility.java +++ b/src/forge/SpellAbility.java @@ -23,6 +23,7 @@ public abstract class SpellAbility private boolean spell; private boolean tapAbility; private boolean buyBackAbility = false; //false by default + private boolean flashBackAbility = false; private Input beforePayMana; private Input afterResolve; @@ -169,4 +170,10 @@ public void execute(Object o) {}}; public void setCancelCommand(Command cancelCommand) { this.cancelCommand = cancelCommand; } + public void setFlashBackAbility(boolean flashBackAbility) { + this.flashBackAbility = flashBackAbility; + } + public boolean isFlashBackAbility() { + return flashBackAbility; + } } \ No newline at end of file