Merge origin/master

This commit is contained in:
fireshoes 2015-07-19 12:12:31 -05:00
commit 42112622d3
21 changed files with 463 additions and 115 deletions

View file

@ -193,6 +193,7 @@ public class DeckGenerator {
Random random = new Random();
int count = 0;
int reservesAdded = 0;
boolean added;
if (retrievedCount > 0 && retrievedCount >= spellCount) {
int tries = 0;
while (count < spellCount) {
@ -208,9 +209,10 @@ public class DeckGenerator {
count++;
}
} else {
if (reservesAdded < genPool.getDeckSize() / 2) {
genPool.tryAddReserve(card, cardCMC);
reservesAdded++;
if (reservesAdded < (genPool.getDeckSize() / 2)) {
added = genPool.tryAddReserve(card, cardCMC);
if(added)
reservesAdded++;
}
}
}

View file

@ -39,7 +39,8 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.UUID;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
@ -53,10 +54,12 @@ public class DeckGeneratorDialog {
private static JComboBox cbDeckSize;
private static JButton btnGenerate, btnCancel;
private static JCheckBox cArtifacts, cSingleton, cNonBasicLands;
private static SimpleDateFormat dateFormat;
public DeckGeneratorDialog()
{
initDialog();
dateFormat = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss-SSS");
}
private void initDialog() {
@ -172,14 +175,17 @@ public class DeckGeneratorDialog {
for (ActionListener al: btnCancel.getActionListeners()) {
btnCancel.removeActionListener(al);
}
//deck = null;
}
public String saveDeck(Deck deck) {
try {
File tmp = File.createTempFile("tempDeck" + UUID.randomUUID().toString(), ".dck");
// Random directory through the system property to avoid random numeric string attached to temp files.
String tempDir = System.getProperty("java.io.tmpdir");
// Generated deck has a nice unique name which corresponds to the timestamp at which it was created.
String deckName = "Generated-Deck-" + dateFormat.format( new Date());
File tmp = new File(tempDir + File.separator + deckName + ".dck");
tmp.createNewFile();
deck.setName("Generated-Deck-" + UUID.randomUUID());
deck.setName(deckName);
Sets.saveDeck(tmp.getAbsolutePath(), deck.getDeckCardLists());
DeckGeneratorDialog.cleanUp();
return tmp.getAbsolutePath();

View file

@ -176,13 +176,15 @@ public class DeckGeneratorPool
* @param card the card to add
* @param cardCMC the converted mana cost of the card
*/
public void tryAddReserve(Card card, int cardCMC) {
public boolean tryAddReserve(Card card, int cardCMC) {
// Only cards with CMC < 7 and don't already exist in the deck
// can be added to our reserve pool as not to overwhelm the curve
// with high CMC cards and duplicates.
if(cardCMC < 7 && getCardCount(card.getName()) == 0) {
this.reserveSpells.add(card);
return true;
}
return false;
}
/**
@ -386,13 +388,13 @@ public class DeckGeneratorPool
List<Card> spellsToAdd = new ArrayList<>(spellsNeeded);
// Initial reservoir
for(int i = 0; i < spellsNeeded-1; i++)
for(int i = 0; i < spellsNeeded; i++)
spellsToAdd.add(reserveSpells.get(i));
for(int j = spellsNeeded+1; j < reserveSpells.size()-1; j++) {
int index = random.nextInt(j);
Card randomCard = reserveSpells.get(index);
if (index < j && isValidSpellCard(randomCard)) {
for(int i = spellsNeeded+1; i < reserveSpells.size()-1; i++) {
int j = random.nextInt(i);
Card randomCard = reserveSpells.get(j);
if (isValidSpellCard(randomCard) && j < spellsToAdd.size()) {
spellsToAdd.set(j, randomCard);
}
}

View file

@ -138,16 +138,10 @@ public class SimulatedPlayer2 extends ComputerPlayer {
options = optimizeOptions(game, options, ability);
if (options.isEmpty()) {
allActions.add(ability);
// simulateAction(game, previousActions, ability);
} else {
// ExecutorService simulationExecutor = Executors.newFixedThreadPool(4);
for (Ability option : options) {
allActions.add(option);
// SimulationWorker worker = new SimulationWorker(game, this, previousActions, option);
// simulationExecutor.submit(worker);
}
// simulationExecutor.shutdown();
// while(!simulationExecutor.isTerminated()) {}
}
}
}

View file

@ -1,16 +1,16 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,12 +20,11 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.player.ai;
import java.util.ArrayList;
@ -40,9 +39,9 @@ import mage.game.permanent.Permanent;
public class Attackers extends TreeMap<Integer, List<Permanent>> {
public List<Permanent> getAttackers() {
List<Permanent> attackers = new ArrayList<Permanent>();
for (List<Permanent> l: this.values()) {
for (Permanent permanent: l) {
List<Permanent> attackers = new ArrayList<>();
for (List<Permanent> l : this.values()) {
for (Permanent permanent : l) {
attackers.add(permanent);
}
}

View file

@ -47,9 +47,8 @@ public class DeployToTheFront extends CardImpl {
super(ownerId, 6, "Deploy to the Front", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{5}{W}{W}");
this.expansionSetCode = "C14";
// Put X 1/1 white Soldier creature tokens onto the battlefield, where X is the number of creatures on the battlefield.
Effect effect = new CreateTokenEffect(new SoldierToken("C14"), new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("the number of creatures on the battlefield")));
Effect effect = new CreateTokenEffect(new SoldierToken(), new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("the number of creatures on the battlefield")));
effect.setText("Put X 1/1 white Soldier creature tokens onto the battlefield, where X is the number of creatures on the battlefield");
this.getSpellAbility().addEffect(effect);
}

View file

@ -51,7 +51,6 @@ public class FirstResponse extends CardImpl {
super(ownerId, 12, "First Response", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}");
this.expansionSetCode = "M15";
// At the beginning of each upkeep, if you lost life last turn, put a 1/1 white Soldier creature token onto the battlefield.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FirstResponseEffect(), TargetController.ANY, false), new PlayerLostLifeWatcher());
@ -88,7 +87,7 @@ class FirstResponseEffect extends OneShotEffect {
PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get("PlayerLostLifeWatcher");
if (watcher != null) {
if (watcher.getLiveLostLastTurn(source.getControllerId()) > 0) {
return new CreateTokenEffect(new SoldierToken("M15")).apply(game, source);
return new CreateTokenEffect(new SoldierToken()).apply(game, source);
}
return true;
}

View file

@ -102,7 +102,7 @@ class WheelOfSunAndMoonEffect extends ReplacementEffectImpl {
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
@ -110,8 +110,8 @@ class WheelOfSunAndMoonEffect extends ReplacementEffectImpl {
Card card = game.getCard(event.getTargetId());
if (card != null) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null &&
card.getOwnerId().equals(enchantment.getAttachedTo())) {
if (enchantment != null && enchantment.getAttachedTo() != null
&& card.getOwnerId().equals(enchantment.getAttachedTo())) {
return true;
}
}
@ -128,7 +128,7 @@ class WheelOfSunAndMoonEffect extends ReplacementEffectImpl {
if (card != null) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Cards cards = new CardsImpl(card);
controller.revealCards(sourceObject.getName(), cards, game);
controller.revealCards(sourceObject.getIdName(), cards, game);
controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, zEvent.getFromZone(), false, true);
return true;
}

View file

@ -57,7 +57,6 @@ public class SigilOfSleep extends CardImpl {
this.expansionSetCode = "UDS";
this.subtype.add("Aura");
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@ -67,7 +66,7 @@ public class SigilOfSleep extends CardImpl {
// Whenever enchanted creature deals damage to a player, return target creature that player controls to its owner's hand.
Effect effect = new ReturnToHandTargetEffect();
effect.setText("return target creature that player controls to its owner's hand");
ability = new DealsDamageToAPlayerAttachedTriggeredAbility(effect, "enchanted", false, true);
ability = new DealsDamageToAPlayerAttachedTriggeredAbility(effect, "enchanted", false, true, false);
this.addAbility(ability);
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.AI.basic;
import org.mage.test.serverside.base.CardTestPlayerBaseAI;
/**
*
* @author LevelX2
*/
public class CombatTest extends CardTestPlayerBaseAI {
/*
* Combat is not integrated yet in the CardTestPlayerBaseAI
*
* TODO: Modify CardTestPlayerBaseAI to use the AI combat acting
*
* Tests to create:
* AI is not attacking if opponent has a creature that can't block
* AI is not blocking also if able if the damage the attacker will do will kill the AI
* AI is not able to block with two or more creatures one attacking creature to kill it. Even if none of the AI creatures will die
* AI attacks with a flyer even if opponent has a bigger flyer that kills AI
*/
}

View file

@ -29,6 +29,8 @@ package org.mage.test.AI.basic;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.filter.Filter;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseAI;
@ -88,8 +90,10 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI {
// Destroy two target artifacts.
addCard(Zone.HAND, playerA, "Rack and Ruin"); // {2}{R}
addCard(Zone.BATTLEFIELD, playerB, "Mox Emerald", 2);
addCard(Zone.BATTLEFIELD, playerA, "Juggernaut");
addCard(Zone.BATTLEFIELD, playerB, "Mox Emerald", 4);
addCard(Zone.BATTLEFIELD, playerA, "Juggernaut", 1);
addCard(Zone.BATTLEFIELD, playerA, "Composite Golem", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mox Emerald", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
@ -99,4 +103,123 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI {
}
/**
* Target only opponent creatures to tap
*/
@Test
public void testFrostBreath1() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Tap up to two target creatures. Those creatures don't untap during their controller's next untap step.
addCard(Zone.HAND, playerA, "Frost Breath"); // {2}{U}
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1);
addCard(Zone.BATTLEFIELD, playerA, "Juggernaut", 1);
addCard(Zone.BATTLEFIELD, playerA, "Composite Golem", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Frost Breath", 1);
assertTapped("Silvercoat Lion", true);
assertTapped("Pillarfield Ox", true);
assertTapped("Juggernaut", false);
assertTapped("Composite Golem", false);
}
/**
* Target only opponent creatures also if more targets are possible
*/
@Test
public void testFrostBreath2() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Tap up to two target creatures. Those creatures don't untap during their controller's next untap step.
addCard(Zone.HAND, playerA, "Frost Breath"); // {2}{U}
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1);
addCard(Zone.BATTLEFIELD, playerA, "Juggernaut", 1);
addCard(Zone.BATTLEFIELD, playerA, "Composite Golem", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Frost Breath", 1);
assertTapped("Pillarfield Ox", true);
assertTapped("Juggernaut", false);
assertTapped("Composite Golem", false);
}
/**
* Spell is not cast if only own creatures can be targeted
*/
@Test
public void testFrostBreath3() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Tap up to two target creatures. Those creatures don't untap during their controller's next untap step.
addCard(Zone.HAND, playerA, "Frost Breath"); // {2}{U}
addCard(Zone.BATTLEFIELD, playerA, "Juggernaut", 1);
addCard(Zone.BATTLEFIELD, playerA, "Composite Golem", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Frost Breath", 0);
assertTapped("Juggernaut", false);
assertTapped("Composite Golem", false);
}
/**
*
*/
@Test
public void testNefashu() {
// Whenever Nefashu attacks, up to five target creatures each get -1/-1 until end of turn.
addCard(Zone.BATTLEFIELD, playerA, "Nefashu"); // 5/3
addCard(Zone.BATTLEFIELD, playerB, "Bellows Lizard", 5);
// Whenever a creature an opponent controls dies, put a +1/+1 counter on Malakir Cullblade.
addCard(Zone.BATTLEFIELD, playerA, "Malakir Cullblade", 5);
attack(3, playerA, "Nefashu");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerB, "Bellows Lizard", 5);
assertPowerToughness(playerA, "Malakir Cullblade", 6, 6, Filter.ComparisonScope.All);
assertTapped("Nefashu", true);
assertLife(playerB, 15);
}
/**
* Test that AI counters creatire spell
*/
@Test
@Ignore // counter spells don't seem to be cast by AI
public void testRewind() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// Counter target spell. Untap up to four lands.
addCard(Zone.HAND, playerA, "Rewind"); // {2}{U}{U}
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
// Renown 1 (When this creature deals combat damage to a player, if it isn't renowned, put a +1/+1 counter on it and it becomes renowned.)
// {W}{W}: Tap target creature.
addCard(Zone.HAND, playerB, "Kytheon's Irregulars", 1);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Kytheon's Irregulars");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Kytheon's Irregulars", 0);
assertGraveyardCount(playerB, "Kytheon's Irregulars", 1);
assertGraveyardCount(playerA, "Rewind", 1);
assertTappedCount("Island", true, 0);
}
}

View file

@ -1,9 +1,16 @@
package org.mage.test.utils;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.mana.*;
import mage.abilities.mana.BasicManaAbility;
import mage.abilities.mana.BlackManaAbility;
import mage.abilities.mana.ManaAbility;
import mage.abilities.mana.RedManaAbility;
import mage.abilities.mana.WhiteManaAbility;
import mage.cards.Card;
import mage.cards.repository.CardRepository;
import mage.util.ManaUtil;
@ -11,10 +18,6 @@ import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.UUID;
/**
* @author noxx
*/
@ -47,7 +50,7 @@ public class ManaUtilTest extends CardTestPlayerBase {
testManaToPayVsLand("{2}", "Cavern of Souls", 2, 2); // can't auto choose to pay
testManaToPayVsLand("{2}", "Eldrazi Temple", 2, 2); // can't auto choose to pay
// hybrid mana
testManaToPayVsLand("{W/R}{W/R}{W/R}", "Sacred Foundry", 2, 1); // auto choose for hybrid mana: choose any
testManaToPayVsLand("{R}{W/R}", "Sacred Foundry", 2, RedManaAbility.class); // auto choose for hybrid mana: we should choose {R}
@ -79,18 +82,20 @@ public class ManaUtilTest extends CardTestPlayerBase {
Assert.assertEquals("{R}{R}", ManaUtil.condenseManaCostString("{R}{R}"));
Assert.assertEquals("{U}", ManaUtil.condenseManaCostString("{U}"));
Assert.assertEquals("{2}", ManaUtil.condenseManaCostString("{2}"));
Assert.assertEquals("", ManaUtil.condenseManaCostString(""));
Assert.assertEquals("", ManaUtil.condenseManaCostString("{}"));
}
/**
* Common way to test ManaUtil.tryToAutoPay
*
* We get all mana abilities, then try to auto pay and compare to expected1 and expected2 params.
* We get all mana abilities, then try to auto pay and compare to expected1
* and expected2 params.
*
* @param manaToPay Mana that should be paid using land.
* @param landName Land to use as mana producer.
* @param expected1 The amount of mana abilities the land should have.
* @param expected2 The amount of mana abilities that ManaUtil.tryToAutoPay should be returned after optimization.
* @param expected2 The amount of mana abilities that ManaUtil.tryToAutoPay
* should be returned after optimization.
*/
private void testManaToPayVsLand(String manaToPay, String landName, int expected1, int expected2) {
ManaCost unpaid = new ManaCostsImpl(manaToPay);
@ -100,19 +105,20 @@ public class ManaUtilTest extends CardTestPlayerBase {
HashMap<UUID, ManaAbility> useableAbilities = getManaAbilities(card);
Assert.assertEquals(expected1, useableAbilities.size());
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ManaAbility>)useableAbilities);
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ManaAbility>) useableAbilities);
Assert.assertEquals(expected2, useableAbilities.size());
}
/**
* Another way to test ManaUtil.tryToAutoPay
* Here we also check what ability was auto chosen
* Another way to test ManaUtil.tryToAutoPay Here we also check what ability
* was auto chosen
*
* N.B. This method can be used ONLY if we have one ability left that auto choose mode!
* That's why we assert the following:
* Assert.assertEquals(1, useableAbilities.size());
* N.B. This method can be used ONLY if we have one ability left that auto
* choose mode! That's why we assert the following: Assert.assertEquals(1,
* useableAbilities.size());
*
* We get all mana abilities, then try to auto pay and compare to expected1 and expected2 params.
* We get all mana abilities, then try to auto pay and compare to expected1
* and expected2 params.
*
* @param manaToPay Mana that should be paid using land.
* @param landName Land to use as mana producer.
@ -127,7 +133,7 @@ public class ManaUtilTest extends CardTestPlayerBase {
HashMap<UUID, ManaAbility> useableAbilities = getManaAbilities(card);
Assert.assertEquals(expected1, useableAbilities.size());
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ManaAbility>)useableAbilities);
useableAbilities = ManaUtil.tryToAutoPay(unpaid, (LinkedHashMap<UUID, ManaAbility>) useableAbilities);
Assert.assertEquals(1, useableAbilities.size());
ManaAbility ability = useableAbilities.values().iterator().next();
Assert.assertTrue("Wrong mana ability has been chosen", expectedChosen.isInstance(ability));
@ -141,13 +147,13 @@ public class ManaUtilTest extends CardTestPlayerBase {
*/
private HashMap<UUID, ManaAbility> getManaAbilities(Card card) {
HashMap<UUID, ManaAbility> useableAbilities = new LinkedHashMap<>();
for (Ability ability: card.getAbilities()) {
for (Ability ability : card.getAbilities()) {
if (ability instanceof ManaAbility) {
ability.newId(); // we need to assign id manually as we are not in game
useableAbilities.put(ability.getId(), (ManaAbility)ability);
useableAbilities.put(ability.getId(), (ManaAbility) ability);
}
}
return useableAbilities;
}
}

View file

@ -27,7 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import mage.MageInt;
import mage.constants.CardType;
@ -38,9 +40,15 @@ import mage.constants.CardType;
*/
public class BeastToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12"));
}
public BeastToken() {
super("Beast", "3/3 green Beast creature token");
availableImageSetCodes.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12"));
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.CREATURE);
color.setGreen(true);
subtype.add("Beast");
@ -59,4 +67,13 @@ public class BeastToken extends Token {
this.setTokenType(2);
}
}
public BeastToken(final BeastToken token) {
super(token);
}
@Override
public BeastToken copy() {
return new BeastToken(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -27,7 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.MageInt;
import mage.constants.CardType;
@ -37,9 +39,15 @@ import mage.constants.CardType;
*/
public class ElfToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "SHM", "EVG", "LRW", "ORI"));
}
public ElfToken() {
super("Elf Warrior", "1/1 green Elf Warrior creature token");
availableImageSetCodes.addAll(Arrays.asList("C14", "SHM", "EVG", "LRW", "ORI"));
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.CREATURE);
color.setGreen(true);
subtype.add("Elf");
@ -55,4 +63,13 @@ public class ElfToken extends Token {
this.setTokenType(1);
}
}
public ElfToken(final ElfToken token) {
super(token);
}
@Override
public ElfToken copy() {
return new ElfToken(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -39,7 +39,7 @@ public class GoblinToken extends Token {
public GoblinToken() {
super("Goblin", "1/1 red Goblin creature token");
availableImageSetCodes.addAll(Arrays.asList("SOM", "M10", "C14", "KTK", "EVG", "DTK", "ORI"));
availableImageSetCodes.addAll(Arrays.asList("SOM", "M10", "C14", "KTK", "EVG", "DTK", "ORI", "DDG"));
cardType.add(CardType.CREATURE);
subtype.add("Goblin");

View file

@ -1,33 +1,36 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import mage.MageInt;
import mage.constants.CardType;
@ -37,18 +40,38 @@ import mage.constants.CardType;
*/
public class SoldierToken extends Token {
public SoldierToken() {
this("10E");
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("10E", "M15", "C14", "ORI", "ALA", "DDF", "THS", "M12", "M13", "MM2", "MMA", "RTR", "SOM"));
}
public SoldierToken(String setCode) {
public SoldierToken() {
super("Soldier", "1/1 white Soldier creature token");
this.setOriginalExpansionSetCode(setCode);
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.CREATURE);
color.setWhite(true);
subtype.add("Soldier");
power = new MageInt(1);
toughness = new MageInt(1);
}
@Override
public void setExpansionSetCodeForImage(String code) {
super.setExpansionSetCodeForImage(code);
if (getOriginalExpansionSetCode().equals("THS")) {
this.setTokenType(new Random().nextInt(2) + 1);
}
}
public SoldierToken(final SoldierToken token) {
super(token);
}
@Override
public SoldierToken copy() {
return new SoldierToken(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -27,6 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.MageInt;
import mage.constants.CardType;
@ -36,12 +39,15 @@ import mage.constants.CardType;
*/
public class SquirrelToken extends Token {
public SquirrelToken() {
this("CNS");
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("CNS"));
}
public SquirrelToken(String setCode) {
public SquirrelToken() {
super("Squirrel", "1/1 green Squirrel creature token");
setOriginalExpansionSetCode(setCode);
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.CREATURE);
subtype.add("Squirrel");

View file

@ -27,7 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import mage.MageInt;
import mage.abilities.keyword.FlyingAbility;
@ -39,9 +41,15 @@ import mage.constants.CardType;
*/
public class ThopterColorlessToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("EXO", "ORI"));
}
public ThopterColorlessToken() {
super("Thopter", "1/1 colorless Thopter artifact creature token with flying");
availableImageSetCodes.addAll(Arrays.asList("EXO", "ORI"));
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.ARTIFACT);
cardType.add(CardType.CREATURE);
subtype.add("Thopter");
@ -58,4 +66,14 @@ public class ThopterColorlessToken extends Token {
this.setTokenType(new Random().nextInt(2) + 1);
}
}
public ThopterColorlessToken(final ThopterColorlessToken token) {
super(token);
}
@Override
public ThopterColorlessToken copy() {
return new ThopterColorlessToken(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -100,6 +100,7 @@ public class Token extends MageObjectImpl {
this.originalCardNumber = token.originalCardNumber;
this.originalExpansionSetCode = token.originalExpansionSetCode;
this.copySourceCard = token.copySourceCard; // will never be changed
this.availableImageSetCodes = token.availableImageSetCodes;
}
public String getDescription() {
@ -216,6 +217,10 @@ public class Token extends MageObjectImpl {
} else {
setOriginalExpansionSetCode(availableImageSetCodes.get(new Random().nextInt(availableImageSetCodes.size())));
}
} else {
if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty()) {
setOriginalExpansionSetCode(code);
}
}
}
}

View file

@ -27,7 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import mage.MageInt;
import mage.constants.CardType;
@ -38,9 +40,15 @@ import mage.constants.CardType;
*/
public class ZombieToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "CNS", "MMA", "BNG", "KTK", "DTK", "ORI"));
}
public ZombieToken() {
super("Zombie", "2/2 black Zombie creature token");
availableImageSetCodes.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "CNS", "MMA", "BNG", "KTK", "DTK", "ORI"));
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add("Zombie");
@ -56,4 +64,12 @@ public class ZombieToken extends Token {
}
}
public ZombieToken(final ZombieToken token) {
super(token);
}
@Override
public ZombieToken copy() {
return new ZombieToken(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -376,26 +376,94 @@ public abstract class TargetImpl implements Target {
return targets.size() > 0;
}
/**
* Returns all possible different target combinations
*
* @param source
* @param game
* @return
*/
@Override
public List<? extends TargetImpl> getTargetOptions(Ability source, Game game) {
List<TargetImpl> options = new ArrayList<>();
Set<UUID> possibleTargets = possibleTargets(source.getSourceId(), source.getControllerId(), game);
List<UUID> possibleTargets = new ArrayList<>();
possibleTargets.addAll(possibleTargets(source.getSourceId(), source.getControllerId(), game));
possibleTargets.removeAll(getTargets());
Iterator<UUID> it = possibleTargets.iterator();
while (it.hasNext()) {
UUID targetId = it.next();
// get the length of the array
// e.g. for {'A','B','C','D'} => N = 4
int N = possibleTargets.size();
// not enough targets, return no option
if (N < getNumberOfTargets()) {
return options;
}
// not target but that's allowed, return one empty option
if (N == 0) {
TargetImpl target = this.copy();
target.clearChosen();
target.addTarget(targetId, source, game, true);
if (!target.isChosen()) {
Iterator<UUID> it2 = possibleTargets.iterator();
while (it2.hasNext() && !target.isChosen()) {
UUID nextTargetId = it2.next();
target.addTarget(nextTargetId, source, game, true);
}
options.add(target);
return options;
}
int maxK = getMaxNumberOfTargets() - getTargets().size();
if (maxK > 5) { // Prevent endless iteration with targets set to INTEGER.maxvalue
maxK = 5;
if (N > 10) { // not more than 252 combinations
maxK = 4;
}
if (target.isChosen()) {
options.add(target);
if (N > 20) { // not more than 4845 combinations
maxK = 3;
}
}
if (N < maxK) { // less possible targets than the maximum allowed so reduce the max
maxK = N;
}
int minK = getNumberOfTargets();
if (getNumberOfTargets() == 0) { // add option without targets if possible
TargetImpl target = this.copy();
options.add(target);
minK = 1;
}
for (int K = minK; K <= maxK; K++) {
// get the combination by index
// e.g. 01 --> AB , 23 --> CD
int combination[] = new int[K];
// position of current index
// if (r = 1) r*
// index ==> 0 | 1 | 2
// element ==> A | B | C
int r = 0;
int index = 0;
while (r >= 0) {
// possible indexes for 1st position "r=0" are "0,1,2" --> "A,B,C"
// possible indexes for 2nd position "r=1" are "1,2,3" --> "B,C,D"
// for r = 0 ==> index < (4+ (0 - 2)) = 2
if (index <= (N + (r - K))) {
combination[r] = index;
// if we are at the last position print and increase the index
if (r == K - 1) {
//add the new target option
TargetImpl target = this.copy();
for (int i = 0; i < combination.length; i++) {
target.addTarget(possibleTargets.get(combination[i]), source, game, true);
}
options.add(target);
index++;
} else {
// select index for next position
index = combination[r] + 1;
r++;
}
} else {
r--;
if (r > 0) {
index = combination[r] + 1;
} else {
index = combination[0] + 1;
}
}
}
}
return options;