mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
merge latest trunk
This commit is contained in:
274
CHANGES.txt
274
CHANGES.txt
@@ -1,7 +1,7 @@
|
||||
Forge Beta: 0#-##-2013 ver 1.3.9
|
||||
Forge Beta: 03-01-2013 ver 1.3.9
|
||||
|
||||
|
||||
12### cards in total.
|
||||
12193 cards in total.
|
||||
|
||||
|
||||
Release Notes:
|
||||
@@ -23,7 +23,7 @@ Work was also done on making the UI more keyboard-friendly. For example, the OK
|
||||
Gatecrash Guild Sealed game mode has been added. To use it, start a new Sealed Mode Game, select "Block / Set" and "Gatecrash Guild Sealed". Select the first (default) configuration in the "Choose Set Combination" dialog, and when asked to pick your boosters, choose the guild you want twice (once for the guild-specific booster, and then for the extra promo cards).
|
||||
The following cards are not included in the guild boosters of this game mode because they are not currently implemented in Forge: Bane Alley Broker, Bioshift, Killing Glare, Simic Manipulator.
|
||||
|
||||
All Traditional sets are now up to 85% complete. Standard Format is supported at 99.19%. We are now at under 900 unsupported cards that are missing from Forge.
|
||||
All Traditional sets are now up to 85% complete. Standard Format is supported at 99.19%. We are now at under 800 unsupported cards that are missing from Forge.
|
||||
|
||||
A person reported "Love the game but I seem to be having a problem using a draft pool to start a quest. It works for sealed for me but when I select the draft deck option it's always blank even if I have one or several drafts completed." This should now be fixed and draft decks should now show up in quest start combobox.
|
||||
|
||||
@@ -34,151 +34,155 @@ Our snapshot and beta releases should now display the correct SVN revision numbe
|
||||
|
||||
New Cards:
|
||||
|
||||
Ghosts of the Innocent
|
||||
Pendrell Flux
|
||||
Disruption Aura
|
||||
Library of Leng
|
||||
Temporal Extortion
|
||||
Archery Training
|
||||
Aurelia's Fury
|
||||
Aven Shrine
|
||||
Barrin's Spite
|
||||
Battletide Alchemist
|
||||
Bioshift
|
||||
Blind Seer
|
||||
Blinding Powder
|
||||
Bloom Tender
|
||||
Bomb Squad
|
||||
Bounty of the Hunt
|
||||
Builder's Bane
|
||||
Cabal Shrine
|
||||
Cannibalize
|
||||
Cephalid Shrine
|
||||
Chant of Vitu-Ghazi
|
||||
Chaoslace
|
||||
Charm Peddler
|
||||
Circle of Despair
|
||||
Cleansing Meditation
|
||||
Common Cause
|
||||
Conflagrate
|
||||
Conjurer's Ban
|
||||
Cornered Market
|
||||
Covenant of Minds
|
||||
Crashing Boars
|
||||
Crush Underfoot
|
||||
Cryptic Gateway
|
||||
Deathlace
|
||||
Deepwood Elder
|
||||
Desecrator Hag
|
||||
Disruption Aura
|
||||
Duplicity
|
||||
Dwarven Shrine
|
||||
Eight-and-a-Half-Tails
|
||||
Embolden
|
||||
Endemic Plague
|
||||
Epochrasite
|
||||
Ersatz Gnomes
|
||||
Eye for an Eye
|
||||
Eye of Singularity
|
||||
Eye of Yawgmoth
|
||||
Feint
|
||||
Fiery Bombardment
|
||||
Fiery Justice
|
||||
Fire and Brimstone
|
||||
Fire Covenant
|
||||
Flash
|
||||
Flickerform
|
||||
Forbidden Crypt
|
||||
Forked Lightning
|
||||
Frostwielder
|
||||
Game Preserve
|
||||
Gargantuan Gorilla
|
||||
Ghosts of the Innocent
|
||||
Glamer Spinners
|
||||
Guard Dogs
|
||||
Hail of Arrows
|
||||
Heartseeker
|
||||
Heroic Defiance
|
||||
Hint of Insanity
|
||||
Holistic Wisdom
|
||||
Infectious Rage
|
||||
Knowledge Exploitation
|
||||
Lightning Dart
|
||||
Memory Crystal
|
||||
Mist of Stagnation
|
||||
Moonring Mirror
|
||||
Nantuko Shrine
|
||||
Phyrexian Purge
|
||||
Planeswalker's Mischief
|
||||
Protean Hulk
|
||||
Purgatory
|
||||
Quenchable Fire
|
||||
Retribution
|
||||
Reviving Vapors
|
||||
Reweave
|
||||
Sapphire Drake
|
||||
Searing Rays
|
||||
Sphinx Ambassador
|
||||
Talara's Bane
|
||||
Thelon of Havenwood
|
||||
Mist of Stagnation
|
||||
Unforge
|
||||
Warren Weirding
|
||||
Worldpurge
|
||||
Flash
|
||||
Forked Lightning
|
||||
Embolden
|
||||
Infernal Harvest
|
||||
Invoke Prejudice
|
||||
Jaded Response
|
||||
Jaws of Stone
|
||||
Killing Glare
|
||||
Knollspine Invocation
|
||||
Knowledge Exploitation
|
||||
Kumano's Blessing
|
||||
Kumano's Pupils
|
||||
Kumano, Master Yamabushi
|
||||
Leonin Bola
|
||||
Library of Leng
|
||||
Lifelace
|
||||
Light from Within
|
||||
Lightning Dart
|
||||
Living Inferno
|
||||
Magmatic Core
|
||||
Remedy
|
||||
Rolling Thunder
|
||||
Aurelia's Fury
|
||||
Pollen Remedy
|
||||
Conflagrate
|
||||
Hail of Arrows
|
||||
Fire Covenant
|
||||
Meteor Shower
|
||||
Infernal Harvest
|
||||
Rock Slide
|
||||
Serra's Hymn
|
||||
Volcanic Wind
|
||||
Spoils of War
|
||||
Fiery Justice
|
||||
Bounty of the Hunt
|
||||
Shambling Swarm
|
||||
Fire and Brimstone
|
||||
Marble Priest
|
||||
Talruum Piper
|
||||
Endemic Plague
|
||||
Feint
|
||||
Reincarnation
|
||||
Killing Glare
|
||||
Gargantuan Gorilla
|
||||
Psychic Allergy
|
||||
Invoke Prejudice
|
||||
Conjurer's Ban
|
||||
Cephalid Shrine
|
||||
Bioshift
|
||||
Glamer Spinners
|
||||
Mark of Eviction
|
||||
Plague Boiler
|
||||
Razia's Purification
|
||||
Reins of the Vinesteed
|
||||
Shared Animosity
|
||||
Simic Guildmage
|
||||
Rite of Ruin
|
||||
Common Cause
|
||||
Sabertooth Cobra
|
||||
Archery Training
|
||||
Barrin's Spite
|
||||
Cryptic Gateway
|
||||
Deepwood Elder
|
||||
Knollspine Invocation
|
||||
Eye of Yawgmoth
|
||||
Spike Cannibal
|
||||
Flickerform
|
||||
Epochrasite
|
||||
Eye of Singularity
|
||||
Heroic Defiance
|
||||
Forbidden Crypt
|
||||
Charm Peddler
|
||||
Heartseeker
|
||||
Blinding Powder
|
||||
Leonin Bola
|
||||
Razor Boomerang
|
||||
Surestrike Trident
|
||||
Sunforger
|
||||
Circle of Despair
|
||||
Martyr's Cause
|
||||
Cannibalize
|
||||
Shuriken
|
||||
Rally the Horde
|
||||
Deathlace
|
||||
Mana Vapors
|
||||
Samite Elder
|
||||
Struggle for Sanity
|
||||
Takeno, Samurai General
|
||||
Thran Tome
|
||||
Chaoslace
|
||||
Lifelace
|
||||
Moonlace
|
||||
Purelace
|
||||
Thoughtlace
|
||||
Eight-and-a-Half-Tails
|
||||
Pious Kitsune
|
||||
Blind Seer
|
||||
Ersatz Gnomes
|
||||
Vodalian Mystic
|
||||
Light from Within
|
||||
Fiery Bombardment
|
||||
Phosphorescent Feast
|
||||
Guard Dogs
|
||||
Jaded Response
|
||||
Tainted Pact
|
||||
Pledge of Loyalty
|
||||
Marble Priest
|
||||
Mark of Eviction
|
||||
Martyr's Cause
|
||||
Memory Crystal
|
||||
Meteor Shower
|
||||
Mirror Golem
|
||||
Reverent Mantra
|
||||
Frostwielder
|
||||
Kumano, Master Yamabushi
|
||||
Kumano's Pupils
|
||||
Kumano's Blessing
|
||||
Winnow
|
||||
Cornered Market
|
||||
Mist of Stagnation
|
||||
Mist of Stagnation
|
||||
Moonlace
|
||||
Moonring Mirror
|
||||
Nantuko Shrine
|
||||
Not of This World
|
||||
Duplicity
|
||||
Pendrell Flux
|
||||
Phosphorescent Feast
|
||||
Phyrexian Purge
|
||||
Pious Kitsune
|
||||
Plague Boiler
|
||||
Planeswalker's Mischief
|
||||
Pledge of Loyalty
|
||||
Pollen Remedy
|
||||
Protean Hulk
|
||||
Psychic Allergy
|
||||
Purelace
|
||||
Purgatory
|
||||
Quenchable Fire
|
||||
Rally the Horde
|
||||
Razia's Purification
|
||||
Razor Boomerang
|
||||
Reincarnation
|
||||
Reins of the Vinesteed
|
||||
Remedy
|
||||
Retribution
|
||||
Reverent Mantra
|
||||
Reviving Vapors
|
||||
Reweave
|
||||
Rite of Ruin
|
||||
Rock Slide
|
||||
Rolling Thunder
|
||||
Sabertooth Cobra
|
||||
Samite Elder
|
||||
Sapphire Drake
|
||||
Searing Rays
|
||||
Serra's Hymn
|
||||
Shambling Swarm
|
||||
Shared Animosity
|
||||
Shuriken
|
||||
Simic Guildmage
|
||||
Sphinx Ambassador
|
||||
Spike Cannibal
|
||||
Spoils of War
|
||||
Struggle for Sanity
|
||||
Sunforger
|
||||
Surestrike Trident
|
||||
Tainted Pact
|
||||
Takeno, Samurai General
|
||||
Talara's Bane
|
||||
Talruum Piper
|
||||
Temporal Extortion
|
||||
Thelon of Havenwood
|
||||
Thought Gorger
|
||||
Thoughtlace
|
||||
Thran Tome
|
||||
Unforge
|
||||
Vodalian Mystic
|
||||
Volcanic Wind
|
||||
Warren Weirding
|
||||
Winnow
|
||||
Worldpurge
|
||||
|
||||
|
||||
New Phenomenons:
|
||||
@@ -189,23 +193,25 @@ Planewide Disaster
|
||||
|
||||
New Planes:
|
||||
|
||||
Undercity Reaches
|
||||
Aretopolis
|
||||
Undercity Reaches
|
||||
|
||||
|
||||
New Vanguard Avatars:
|
||||
|
||||
Arcanis the Omnipotent Avatar
|
||||
Bosh, Iron Golem Avatar
|
||||
Figure of Destiny Avatar
|
||||
Haakon Stromgald Scourge Avatar
|
||||
Jaya Ballard Avatar
|
||||
Maro Avatar
|
||||
Master of the Wild Hunt Avatar
|
||||
Necropotence Avatar
|
||||
Sisters of Stone Death Avatar
|
||||
Stuffy Doll Avatar
|
||||
Two Headed Giant of Foriys Avatar
|
||||
Viridian Zealot Avatar
|
||||
Bosh, Iron Golem Avatar
|
||||
Maro Avatar
|
||||
Necropotence Avatar
|
||||
Vampire Nocturnus Avatar
|
||||
Arcanis the Omnipotent Avatar
|
||||
Master of the Wild Hunt Avatar
|
||||
Viridian Zealot Avatar
|
||||
|
||||
|
||||
Known Issues:
|
||||
|
||||
12
pom.xml
12
pom.xml
@@ -5,7 +5,7 @@
|
||||
<artifactId>forge</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Forge</name>
|
||||
<version>1.3.9-SNAPSHOT</version>
|
||||
<version>1.3.10-SNAPSHOT</version>
|
||||
<description>
|
||||
Forge lets you play the card game Magic: The Gathering against a computer opponent
|
||||
using all of the rules.
|
||||
@@ -211,7 +211,7 @@
|
||||
<exportAntProperties>true</exportAntProperties>
|
||||
<target>
|
||||
<condition property="fullversionstring" value="${project.version}-r${forge.revision}${forge.specialStatus}" else="${project.version}-r${forge.revision}${forge.specialStatus} (mixed revisions detected; please update from the root directory)">
|
||||
<contains string="${forge.mixedRevisions}" substring="false"/>
|
||||
<contains string="${forge.mixedRevisions}" substring="false" />
|
||||
</condition>
|
||||
</target>
|
||||
</configuration>
|
||||
@@ -464,7 +464,7 @@
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
<ignore />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
@@ -478,7 +478,7 @@
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute/>
|
||||
<execute />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
@@ -491,7 +491,7 @@
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute/>
|
||||
<execute />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
@@ -504,7 +504,7 @@
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<execute/>
|
||||
<execute />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
|
||||
@@ -186,13 +186,13 @@ while inputName != 'quit' :
|
||||
if text.find("When CARDNAME enters the battlefield") != -1 :
|
||||
print "\n"+text
|
||||
print "<Trigger Script Start>"
|
||||
print 'T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ <TriggerFunc> | TriggerDescription$ '+text
|
||||
print 'T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ <TriggerFunc> | TriggerDescription$ '+text
|
||||
print 'SVar:<TriggerFunc>:AB$ <Added Triggered Ability HERE>'
|
||||
print "<Trigger Script End>\n"
|
||||
elif text.find("When CARDNAME leaves the battlefield") != -1 :
|
||||
print "\n"+text
|
||||
print "<Trigger Script Start>"
|
||||
print 'T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Creature.Self | Execute$ <TriggerFunc> | TriggerDescription$ '+text
|
||||
print 'T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ <TriggerFunc> | TriggerDescription$ '+text
|
||||
print 'SVar:<TriggerFunc>:AB$ <Added Triggered Ability HERE>'
|
||||
print "<Trigger Script End>\n"
|
||||
elif text.find("Unleash") != -1 :
|
||||
|
||||
@@ -2,9 +2,12 @@ Name:Astral Slide
|
||||
ManaCost:2 W
|
||||
Types:Enchantment
|
||||
T:Mode$ Cycled | ValidCard$ Card | Execute$ TrigExile | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever a player cycles a card, you may exile target creature. If you do, return the exiled card to the battlefield under its owner's control at the beginning of the next end step.
|
||||
SVar:TrigExile:AB$ ChangeZone | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DelTrig
|
||||
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigBounce | TriggerDescription$ Return exiled creature to the battlefield.
|
||||
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered
|
||||
SVar:TrigExile:AB$ ChangeZone | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DelTrigEffect
|
||||
SVar:DelTrigEffect:DB$ Effect | Triggers$ EOTTrig | SVars$ TrigBounce,RemoveEffect | RememberObjects$ Remembered | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1
|
||||
SVar:EOTTrig:Mode$ Phase | Phase$ End of Turn | Execute$ TrigBounce | TriggerZones$ Command | TriggerDescription$ Return exiled creature to the battlefield.
|
||||
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered | SubAbility$ RemoveEffect
|
||||
SVar:RemoveEffect:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:RemAIDeck:True
|
||||
SVar:Rarity:Uncommon
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/astral_slide.jpg
|
||||
|
||||
@@ -4,8 +4,9 @@ Types:Creature Insect
|
||||
PT:0/1
|
||||
K:Flying
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigEffect | TriggerDescription$ When CARDNAME attacks, defending player can't cast spells this turn.
|
||||
SVar:TrigEffect:AB$ Effect | Cost$ 0 | Name$ Xantid Swarm Effect | StaticAbilities$ CantBeCast
|
||||
SVar:CantBeCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card | Caster$ DefendingPlayer | Description$ Defending player can't cast spells.
|
||||
SVar:TrigEffect:AB$ Effect | Cost$ 0 | Name$ Xantid Swarm Effect | RememberObjects$ DefendingPlayer | StaticAbilities$ CantBeCast | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:CantBeCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card | Caster$ Player.IsRemembered | Description$ Defending player can't cast spells.
|
||||
SVar:RemRandomDeck:True
|
||||
SVar:HasAttackEffect:TRUE
|
||||
SVar:Rarity:Rare
|
||||
|
||||
@@ -293,3 +293,37 @@ http://www.cardforge.org/fpics/questAvatars/WereHyena.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/WitchDoctor.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Yemaya.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Yewa.jpg
|
||||
#RAVNICA WORLD ICONS
|
||||
http://www.cardforge.org/fpics/questAvatars/Agrus.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Aurelia.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Azorius-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Bep.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Borborygmos.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Boros-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Caprio.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Ghost%20Council.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Golgari-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Gruul-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Hameln.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Isperia.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Izzet-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Jarad.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Kraj.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Lazav.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Lyzolda.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Momir.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Niv-Mizzet.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Orzhov-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Rakdos.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Savra.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Selesnya-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Simic-precon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Sisters%20of%20Stone%20Death.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Sus Antigoon.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Szadek.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Teysa.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Token.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Tolsimir.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Trostani.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Ulasht.jpg
|
||||
http://www.cardforge.org/fpics/questAvatars/Zegana.jpg
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.deck;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import forge.Card;
|
||||
|
||||
@@ -139,7 +140,7 @@ public class CardPool extends ItemPool<CardPrinted> {
|
||||
if ( cp != null)
|
||||
this.add(cp);
|
||||
else
|
||||
throw new RuntimeException(String.format("Card %s is not supported by Forge, as it's neither a known common card nor one of casual variants' card.", cardName));
|
||||
throw new NoSuchElementException(String.format("Card %s is not supported by Forge, as it's neither a known common card nor one of casual variants' card.", cardName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class PlayerController {
|
||||
*/
|
||||
public void passPriority() {
|
||||
PhaseHandler handler = game.getPhaseHandler();
|
||||
// may pass only priority is has
|
||||
|
||||
if ( handler.getPriorityPlayer() == getPlayer() )
|
||||
game.getPhaseHandler().passPriority();
|
||||
}
|
||||
@@ -95,5 +95,6 @@ public abstract class PlayerController {
|
||||
public Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title, false); }
|
||||
public abstract Card chooseSingleCardForEffect(List<Card> sourceList, SpellAbility sa, String title, boolean isOptional);
|
||||
public abstract boolean confirmAction(SpellAbility sa, String mode, String message);
|
||||
public abstract boolean getWillPlayOnFirstTurn(String message);
|
||||
public abstract boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message);
|
||||
}
|
||||
|
||||
@@ -198,6 +198,10 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return brains.confirmAction(sa, mode, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getWillPlayOnFirstTurn(String message) {
|
||||
return true; // AI is brave :)
|
||||
}
|
||||
@Override
|
||||
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
||||
return brains.confirmStaticApplication(hostCard, affected, logic, message);
|
||||
|
||||
@@ -250,5 +250,14 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return GuiDialog.confirm(hostCard, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getWillPlayOnFirstTurn(String message) {
|
||||
final String[] possibleValues = { "Play", "Draw" };
|
||||
|
||||
final Object playDraw = JOptionPane.showOptionDialog(null, message + "\n\nWould you like to play or draw?",
|
||||
"Play or Draw?", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null,
|
||||
possibleValues, possibleValues[0]);
|
||||
|
||||
return !playDraw.equals(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ public class QuestEventManager {
|
||||
outList.add(duel);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
targetIdx -= opponents.size();
|
||||
|
||||
@@ -23,11 +23,9 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import forge.Card;
|
||||
import forge.view.arcane.util.CardPanelMouseListener;
|
||||
|
||||
@@ -76,6 +74,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
* a {@link javax.swing.JScrollPane} object.
|
||||
* @param mirror
|
||||
* a boolean.
|
||||
* @param modelRef
|
||||
*/
|
||||
public PlayArea(final JScrollPane scrollPane, final boolean mirror) {
|
||||
super(scrollPane);
|
||||
@@ -196,46 +195,40 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
this.playAreaWidth = rect.width;
|
||||
this.playAreaHeight = rect.height;
|
||||
|
||||
final CardStackRow allLands = collectAllLands();
|
||||
final CardStackRow allTokens = collectAllTokens();
|
||||
final CardStackRow allCreatures = new CardStackRow(this.getCardPanels(), RowType.creatureNonToken);
|
||||
final CardStackRow allOthers = new CardStackRow(this.getCardPanels(), RowType.other);
|
||||
final CardStackRow lands = collectAllLands();
|
||||
final CardStackRow tokens = collectAllTokens();
|
||||
final CardStackRow creatures = new CardStackRow(this.getCardPanels(), RowType.CreatureNonToken);
|
||||
final CardStackRow others = new CardStackRow(this.getCardPanels(), RowType.Other);
|
||||
|
||||
// should find an appropriate width of card
|
||||
this.cardWidth = this.getCardWidthMax();
|
||||
int maxCardWidth = this.getCardWidthMax();
|
||||
setCardWidth(maxCardWidth);
|
||||
int minCardWidth = this.getCardWidthMin();
|
||||
int lastGoodCardWidth = minCardWidth;
|
||||
int deltaCardWidth = (maxCardWidth - minCardWidth) / 2;
|
||||
boolean workedLastTime = false;
|
||||
//boolean isFirstRun = true;
|
||||
List<CardStackRow> lastTemplate = null;
|
||||
|
||||
while (deltaCardWidth > 0) {
|
||||
final CardStackRow creatures = (CardStackRow) allCreatures.clone();
|
||||
final CardStackRow tokens = (CardStackRow) allTokens.clone();
|
||||
final CardStackRow lands = (CardStackRow) allLands.clone();
|
||||
CardStackRow others = (CardStackRow) allOthers.clone();
|
||||
workedLastTime = canAdjustWidth(lands, tokens, creatures, others);
|
||||
|
||||
deltaCardWidth = (cardWidth - lastGoodCardWidth) / 2;
|
||||
if (workedLastTime) {
|
||||
lastGoodCardWidth = cardWidth;
|
||||
cardWidth += deltaCardWidth;
|
||||
List<CardStackRow> template = tryArrangePilesOfWidth(lands, tokens, creatures, others);
|
||||
|
||||
deltaCardWidth = (getCardWidth() - lastGoodCardWidth) / 2;
|
||||
if (template != null) {
|
||||
lastTemplate = template;
|
||||
lastGoodCardWidth = getCardWidth();
|
||||
setCardWidth(getCardWidth() + deltaCardWidth);
|
||||
if (lastGoodCardWidth == maxCardWidth) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cardWidth -= deltaCardWidth;
|
||||
setCardWidth(getCardWidth() - deltaCardWidth);
|
||||
}
|
||||
}
|
||||
cardWidth = lastGoodCardWidth;
|
||||
final CardStackRow creatures = (CardStackRow) allCreatures.clone();
|
||||
final CardStackRow tokens = (CardStackRow) allTokens.clone();
|
||||
final CardStackRow lands = (CardStackRow) allLands.clone();
|
||||
CardStackRow others = (CardStackRow) allOthers.clone();
|
||||
workedLastTime = canAdjustWidth(lands, tokens, creatures, others);
|
||||
setCardWidth(lastGoodCardWidth);
|
||||
if ( null == lastTemplate )
|
||||
lastTemplate = tryArrangePilesOfWidth(lands, tokens, creatures, others);
|
||||
|
||||
this.rows = lastTemplate;
|
||||
// Get size of all the rows.
|
||||
int x, y = PlayArea.GUTTER_Y;
|
||||
int maxRowWidth = 0;
|
||||
@@ -252,25 +245,26 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
}
|
||||
this.setPreferredSize(new Dimension(maxRowWidth - this.cardSpacingX, y - this.cardSpacingY));
|
||||
this.revalidate();
|
||||
positionAllCards();
|
||||
positionAllCards(lastTemplate);
|
||||
}
|
||||
|
||||
private void positionAllCards() {
|
||||
private void positionAllCards(List<CardStackRow> template) {
|
||||
|
||||
// Position all card panels.
|
||||
int x = 0;
|
||||
int y = PlayArea.GUTTER_Y;
|
||||
|
||||
for (final CardStackRow row : this.rows) {
|
||||
for (final CardStackRow row : template) {
|
||||
int rowBottom = 0;
|
||||
x = PlayArea.GUTTER_X;
|
||||
for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) {
|
||||
final CardStack stack = row.get(stackIndex);
|
||||
// Align others to the right.
|
||||
if (RowType.other.isType(stack.get(0).getGameCard())) {
|
||||
if (RowType.Other.isGoodFor(stack.get(0).getGameCard())) {
|
||||
x = (this.playAreaWidth - PlayArea.GUTTER_X) + this.extraCardSpacingX;
|
||||
for (int i = stackIndex, n = row.size(); i < n; i++) {
|
||||
x -= row.get(i).getWidth();
|
||||
CardStack r = row.get(i);
|
||||
x -= r.getWidth();
|
||||
}
|
||||
}
|
||||
for (int panelIndex = 0, panelCount = stack.size(); panelIndex < panelCount; panelIndex++) {
|
||||
@@ -279,68 +273,62 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
this.setComponentZOrder(panel, panelIndex);
|
||||
final int panelX = x + (stackPosition * this.stackSpacingX);
|
||||
final int panelY = y + (stackPosition * this.stackSpacingY);
|
||||
panel.setCardBounds(panelX, panelY, this.cardWidth, this.cardHeight);
|
||||
panel.setCardBounds(panelX, panelY, this.getCardWidth(), this.cardHeight);
|
||||
}
|
||||
rowBottom = Math.max(rowBottom, y + stack.getHeight());
|
||||
x += stack.getWidth();
|
||||
x += stack.getWidth() + cardSpacingX;
|
||||
}
|
||||
y = rowBottom;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canAdjustWidth(final CardStackRow lands, final CardStackRow tokens, final CardStackRow creatures, CardStackRow others) {
|
||||
this.rows.clear();
|
||||
this.cardHeight = Math.round(this.cardWidth * CardPanel.ASPECT_RATIO);
|
||||
this.extraCardSpacingX = Math.round(this.cardWidth * PlayArea.EXTRA_CARD_SPACING_X);
|
||||
this.cardSpacingX = (this.cardHeight - this.cardWidth) + this.extraCardSpacingX;
|
||||
this.cardSpacingY = Math.round(this.cardHeight * PlayArea.CARD_SPACING_Y);
|
||||
this.stackSpacingX = Math.round(this.cardWidth * PlayArea.STACK_SPACING_X);
|
||||
this.stackSpacingY = Math.round(this.cardHeight * PlayArea.STACK_SPACING_Y);
|
||||
|
||||
private List<CardStackRow> tryArrangePilesOfWidth(final CardStackRow lands, final CardStackRow tokens, final CardStackRow creatures, CardStackRow others) {
|
||||
List<CardStackRow> template = new ArrayList<PlayArea.CardStackRow>();
|
||||
|
||||
int afterFirstRow;
|
||||
|
||||
boolean landsFit, tokensFit, creaturesFit;
|
||||
if (this.mirror) {
|
||||
// Wrap all creatures and lands.
|
||||
this.wrap(lands, this.rows, -1);
|
||||
afterFirstRow = this.rows.size();
|
||||
this.wrap(tokens, this.rows, afterFirstRow);
|
||||
this.wrap(creatures, this.rows, this.rows.size());
|
||||
landsFit = this.planRow(lands, template, -1);
|
||||
afterFirstRow = template.size();
|
||||
tokensFit = this.planRow(tokens, template, afterFirstRow);
|
||||
creaturesFit = this.planRow(creatures, template, template.size());
|
||||
} else {
|
||||
// Wrap all creatures and lands.
|
||||
this.wrap(creatures, this.rows, -1);
|
||||
afterFirstRow = this.rows.size();
|
||||
this.wrap(tokens, this.rows, afterFirstRow);
|
||||
this.wrap(lands, this.rows, this.rows.size());
|
||||
creaturesFit = this.planRow(creatures, template, -1);
|
||||
afterFirstRow = template.size();
|
||||
tokensFit = this.planRow(tokens, template, afterFirstRow);
|
||||
landsFit = this.planRow(lands, template, template.size());
|
||||
}
|
||||
// Store the current rows and others.
|
||||
final List<CardStackRow> storedRows = new ArrayList<CardStackRow>(this.rows.size());
|
||||
for (final CardStackRow row : this.rows) {
|
||||
try {
|
||||
storedRows.add((CardStackRow) row.clone());
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
System.out.println("Null pointer exception in Row Spacing. Possibly also part of the issue.");
|
||||
}
|
||||
|
||||
if ( !landsFit || !creaturesFit || !tokensFit )
|
||||
return null;
|
||||
|
||||
// Other cards may be stored at end of usual rows or on their own row.
|
||||
int cntOthers = others.size();
|
||||
|
||||
// Copy the template for the case 1st approach won't work
|
||||
final List<CardStackRow> templateCopy = new ArrayList<CardStackRow>(template.size());
|
||||
for (final CardStackRow row : template) {
|
||||
templateCopy.add((CardStackRow) row.clone());
|
||||
}
|
||||
final CardStackRow storedOthers = (CardStackRow) others.clone();
|
||||
|
||||
// Fill in all rows with others.
|
||||
for (final CardStackRow row : this.rows) {
|
||||
this.fillRow(others, this.rows, row);
|
||||
int nextOther = 0;
|
||||
for (final CardStackRow row : template) {
|
||||
nextOther = this.planOthersRow(others, nextOther, template, row);
|
||||
if ( nextOther == cntOthers )
|
||||
return template; // everything was successfully placed
|
||||
}
|
||||
// Stop if everything fits, otherwise revert back to the stored
|
||||
// values.
|
||||
if (creatures.isEmpty() && tokens.isEmpty() && lands.isEmpty() && others.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
this.rows = storedRows;
|
||||
others = storedOthers;
|
||||
// Try to put others on their own row(s) and fill in the rest.
|
||||
this.wrap(others, this.rows, afterFirstRow);
|
||||
for (final CardStackRow row : this.rows) {
|
||||
this.fillRow(others, this.rows, row);
|
||||
}
|
||||
// If that still doesn't fit, scale down.
|
||||
return creatures.isEmpty() && tokens.isEmpty() && lands.isEmpty() && others.isEmpty();
|
||||
|
||||
template = templateCopy;
|
||||
// Try to put others on their own row(s)
|
||||
if ( this.planRow(others, template, afterFirstRow) )
|
||||
return template;
|
||||
|
||||
|
||||
return null; // Cannot fit everything with that width;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,69 +338,53 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
*
|
||||
* @param sourceRow
|
||||
* a {@link forge.view.arcane.PlayArea.CardStackRow} object.
|
||||
* @param rows
|
||||
* @param template
|
||||
* a {@link java.util.List} object.
|
||||
* @param insertIndex
|
||||
* a int.
|
||||
* @return a int.
|
||||
*/
|
||||
// private int cntRepaints = 0;
|
||||
private int wrap(final CardStackRow sourceRow, final List<CardStackRow> rows, final int insertIndex) {
|
||||
// Won't modify the first parameter
|
||||
private boolean planRow(final CardStackRow sourceRow, final List<CardStackRow> template, final int insertIndex) {
|
||||
// The cards are sure to fit (with vertical scrolling) at the minimum
|
||||
// card width.
|
||||
final boolean allowHeightOverflow = this.cardWidth == this.getCardWidthMin();
|
||||
final boolean isMinimalSize = this.getCardWidth() == this.getCardWidthMin();
|
||||
|
||||
// System.err.format("[%d] @ %d - Repaint playarea - %s %n", new Date().getTime(), cntRepaints++, mirror ? "MIRROR" : "DIRECT");
|
||||
|
||||
CardStackRow currentRow = new CardStackRow();
|
||||
for (int i = 0, n = sourceRow.size() - 1; i <= n; i++) {
|
||||
final CardStack stack = sourceRow.get(i);
|
||||
// If the row is not empty and this stack doesn't fit, add the row.
|
||||
for (final CardStack stack : sourceRow) {
|
||||
final int rowWidth = currentRow.getWidth();
|
||||
if (!currentRow.isEmpty() && ((rowWidth + stack.getWidth()) > this.playAreaWidth)) {
|
||||
// If the row is not empty and this stack doesn't fit, add the row.
|
||||
if (rowWidth + stack.getWidth() > this.playAreaWidth && !currentRow.isEmpty() ) {
|
||||
|
||||
// Stop processing if the row is too wide or tall.
|
||||
if (!allowHeightOverflow && (rowWidth > this.playAreaWidth)) {
|
||||
break;
|
||||
}
|
||||
if (!allowHeightOverflow && ((this.getRowsHeight(rows) + sourceRow.getHeight()) > this.playAreaHeight)) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow);
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println("ArrayIndex Out of Bounds when trying to add row in PlayArea. Someone fix this logic, "
|
||||
+ " I believe it causes the no cards loading in issue we've noticed.");
|
||||
// TODO: There's a crash here, maybe when rows == [null] and currentRow == [[Plant Wall]] and insertIndex is 0
|
||||
if (rowWidth > this.playAreaWidth || this.getRowsHeight(template) + sourceRow.getHeight() > this.playAreaHeight) {
|
||||
if ( !isMinimalSize )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( insertIndex == -1)
|
||||
template.add(currentRow);
|
||||
else
|
||||
template.add(insertIndex, currentRow);
|
||||
|
||||
currentRow = new CardStackRow();
|
||||
}
|
||||
|
||||
currentRow.add(stack);
|
||||
}
|
||||
// Add the last row if it is not empty and it fits.
|
||||
if (!currentRow.isEmpty()) {
|
||||
final int rowWidth = currentRow.getWidth();
|
||||
if (allowHeightOverflow
|
||||
|| (rowWidth <= this.playAreaWidth)
|
||||
&& (allowHeightOverflow || ((this.getRowsHeight(rows) + sourceRow.getHeight()) <= this.playAreaHeight))) {
|
||||
try {
|
||||
rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow);
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.out.println("ArrayIndex Out of Bounds when trying to add row in PlayArea. Someone fix this logic, "
|
||||
+ " I believe it causes the no cards loading in issue we've noticed.");
|
||||
// TODO: There's a crash here, maybe when rows == [null] and currentRow == [[Plant Wall]] and insertIndex is 0
|
||||
}
|
||||
}
|
||||
if (isMinimalSize || rowWidth <= this.playAreaWidth && this.getRowsHeight(template) + sourceRow.getHeight() <= this.playAreaHeight) {
|
||||
if ( insertIndex == -1)
|
||||
template.add(currentRow);
|
||||
else
|
||||
template.add(insertIndex, currentRow);
|
||||
} else return false;
|
||||
}
|
||||
// Remove the wrapped stacks from the source row.
|
||||
for (int iRow = 0; iRow < rows.size(); iRow++) {
|
||||
CardStackRow row = rows.get(iRow);
|
||||
if (row != null) {
|
||||
sourceRow.removeAll(row);
|
||||
}
|
||||
}
|
||||
return insertIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -423,32 +395,30 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
*
|
||||
* @param sourceRow
|
||||
* a {@link forge.view.arcane.PlayArea.CardStackRow} object.
|
||||
* @param rows
|
||||
* @param template
|
||||
* a {@link java.util.List} object.
|
||||
* @param rows
|
||||
* @param template
|
||||
* a {@link java.util.List} object.
|
||||
* @param row
|
||||
* @param rowToFill
|
||||
* a {@link forge.view.arcane.PlayArea.CardStackRow} object.
|
||||
*/
|
||||
private void fillRow(final CardStackRow sourceRow, final List<CardStackRow> rows, final CardStackRow row) {
|
||||
int rowWidth = row.getWidth();
|
||||
private int planOthersRow(final List<CardStack> sourceRow, final int firstPile, final List<CardStackRow> template, final CardStackRow rowToFill) {
|
||||
int rowWidth = rowToFill.getWidth();
|
||||
|
||||
final Iterator<CardStack> itr = sourceRow.iterator();
|
||||
|
||||
while (itr.hasNext()) {
|
||||
final CardStack stack = itr.next();
|
||||
for (int i = firstPile; i < sourceRow.size(); i++ ) {
|
||||
CardStack stack = sourceRow.get(i);
|
||||
|
||||
rowWidth += stack.getWidth();
|
||||
if (rowWidth > this.playAreaWidth) {
|
||||
break;
|
||||
if (rowWidth > this.playAreaWidth) return i; // cannot add any more piles in a row
|
||||
|
||||
if (stack.getHeight() > rowToFill.getHeight()) { // if row becomes taller
|
||||
int newAllRowsHeight = this.getRowsHeight(template) - rowToFill.getHeight() + stack.getHeight();
|
||||
if ( newAllRowsHeight > this.playAreaHeight)
|
||||
return i; // refuse to add here because it won't fit in height
|
||||
}
|
||||
if (stack.getHeight() > row.getHeight()
|
||||
&& (((this.getRowsHeight(rows) - row.getHeight()) + stack.getHeight()) > this.playAreaHeight)) {
|
||||
break;
|
||||
}
|
||||
row.add(stack);
|
||||
itr.remove();
|
||||
rowToFill.add(stack);
|
||||
}
|
||||
return sourceRow.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,20 +479,18 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
}
|
||||
|
||||
private static enum RowType {
|
||||
land, creature, creatureNonToken, other;
|
||||
Land,
|
||||
Creature,
|
||||
CreatureNonToken,
|
||||
Other;
|
||||
|
||||
public boolean isType(final Card card) {
|
||||
public boolean isGoodFor(final Card card) {
|
||||
switch (this) {
|
||||
case land:
|
||||
return card.isLand();
|
||||
case creature:
|
||||
return card.isCreature();
|
||||
case creatureNonToken:
|
||||
return card.isCreature() && !card.isToken();
|
||||
case other:
|
||||
return !card.isLand() && !card.isCreature();
|
||||
default:
|
||||
throw new RuntimeException("Unhandled type: " + this);
|
||||
case Land: return card.isLand();
|
||||
case Creature: return card.isCreature();
|
||||
case CreatureNonToken: return card.isCreature() && !card.isToken();
|
||||
case Other: return !card.isLand() && !card.isCreature();
|
||||
default: throw new RuntimeException("Unhandled type: " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,7 +509,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
|
||||
private void addAll(final List<CardPanel> cardPanels, final RowType type) {
|
||||
for (final CardPanel panel : cardPanels) {
|
||||
if (!type.isType(panel.getGameCard()) || (panel.getAttachedToPanel() != null)) {
|
||||
if (!type.isGoodFor(panel.getGameCard()) || (panel.getAttachedToPanel() != null)) {
|
||||
continue;
|
||||
}
|
||||
final CardStack stack = new CardStack();
|
||||
@@ -606,4 +574,17 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
+ PlayArea.this.cardSpacingY;
|
||||
}
|
||||
}
|
||||
private int getCardWidth() {
|
||||
return cardWidth;
|
||||
}
|
||||
|
||||
private void setCardWidth(int cardWidth0) {
|
||||
this.cardWidth = cardWidth0;
|
||||
this.cardHeight = Math.round(this.cardWidth * CardPanel.ASPECT_RATIO);
|
||||
this.extraCardSpacingX = Math.round(this.cardWidth * PlayArea.EXTRA_CARD_SPACING_X);
|
||||
this.cardSpacingX = (this.cardHeight - this.cardWidth) + this.extraCardSpacingX;
|
||||
this.cardSpacingY = Math.round(this.cardHeight * PlayArea.CARD_SPACING_Y);
|
||||
this.stackSpacingX = Math.round(this.cardWidth * PlayArea.STACK_SPACING_X);
|
||||
this.stackSpacingY = Math.round(this.cardHeight * PlayArea.STACK_SPACING_Y);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user