diff --git a/.gitattributes b/.gitattributes index e4eb5dd4fcb..8bd64727cf9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9774,6 +9774,7 @@ src/main/java/forge/gui/ListChooser.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabel.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabelUI.java svneol=native#text/plain src/main/java/forge/gui/MultiPhaseProgressMonitorWithETA.java svneol=native#text/plain +src/main/java/forge/gui/SelectablePanel.java -text src/main/java/forge/gui/deckeditor/CardPanelBase.java -text src/main/java/forge/gui/deckeditor/CardPanelHeavy.java -text src/main/java/forge/gui/deckeditor/CardPanelLite.java -text @@ -9822,6 +9823,10 @@ src/main/java/forge/properties/NewConstants.java svneol=native#text/plain src/main/java/forge/properties/Preferences.java svneol=native#text/plain src/main/java/forge/properties/SavePreferencesListener.java svneol=native#text/plain src/main/java/forge/properties/package-info.java svneol=native#text/plain +src/main/java/forge/quest/data/DeckSingleBattle.java svneol=native#text/plain +src/main/java/forge/quest/data/DeckSingleQuest.java svneol=native#text/plain +src/main/java/forge/quest/data/ManagerBattle.java svneol=native#text/plain +src/main/java/forge/quest/data/ManagerQuest.java -text src/main/java/forge/quest/data/QuestBattleManager.java svneol=native#text/plain src/main/java/forge/quest/data/QuestBoosterPack.java svneol=native#text/plain src/main/java/forge/quest/data/QuestData.java svneol=native#text/plain @@ -9853,8 +9858,11 @@ src/main/java/forge/quest/data/pet/QuestPetManager.java svneol=native#text/plain src/main/java/forge/quest/data/pet/QuestPetPlant.java svneol=native#text/plain src/main/java/forge/quest/data/pet/QuestPetWolf.java svneol=native#text/plain src/main/java/forge/quest/data/pet/package-info.java svneol=native#text/plain +src/main/java/forge/quest/gui/PanelSingleBattle.java -text +src/main/java/forge/quest/gui/PanelSingleQuest.java -text src/main/java/forge/quest/gui/QuestAbstractPanel.java svneol=native#text/plain src/main/java/forge/quest/gui/QuestFrame.java svneol=native#text/plain +src/main/java/forge/quest/gui/QuestMainPanel.java svneol=native#text/plain src/main/java/forge/quest/gui/QuestOptions.java svneol=native#text/plain src/main/java/forge/quest/gui/bazaar/QuestBazaarItem.java svneol=native#text/plain src/main/java/forge/quest/gui/bazaar/QuestBazaarPanel.java svneol=native#text/plain @@ -9923,7 +9931,6 @@ src/test/java/forge/GuiWinLoseTest.java svneol=native#text/plain src/test/java/forge/PanelTest.java svneol=native#text/plain src/test/java/forge/PhaseTest.java svneol=native#text/plain src/test/java/forge/ReadBoosterPackTest.java svneol=native#text/plain -src/test/java/forge/ReadQuestAssignmentTest.java svneol=native#text/plain src/test/java/forge/RunTest.java svneol=native#text/plain src/test/java/forge/TinyTest.java svneol=native#text/plain src/test/java/forge/card/cardFactory/CardFactoryTest.java svneol=native#text/plain diff --git a/res/quest/decks/quest1.dck b/res/quest/decks/quest1.dck index 3bd1e8985c3..2595ae05aca 100644 --- a/res/quest/decks/quest1.dck +++ b/res/quest/decks/quest1.dck @@ -1,6 +1,17 @@ -quest1 -[general] -constructed +[metadata] +ID=1 +Name=quest1 +DisplayName=Dungeon Crawling (White) +Difficulty=Medium +Description=This realm is guarded by a divine entity laying his protecting hand on each living being. +Repeatable=true +NumberWinsRequired=20 +CardReward=3 white rares +CreditsReward=100 +Icon=Dungeon Crawling White.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 24 Plains 1 Abbey Gargoyles @@ -40,3 +51,6 @@ constructed 1 Retribution of the Meek 1 Sunlance [sideboard] +[human_extra_cards] +[ai_extra_cards] +1 Divine Presence \ No newline at end of file diff --git a/res/quest/decks/quest10.dck b/res/quest/decks/quest10.dck index a2363fab55e..47c32055eef 100644 --- a/res/quest/decks/quest10.dck +++ b/res/quest/decks/quest10.dck @@ -1,6 +1,17 @@ -quest10 -[general] -constructed +[metadata] +ID=10 +Name=quest10 +DisplayName=Zombie Attack! +Difficulty=Hard +Description=The village of Haven is getting attacked by the Zombie horde! Protect the village. +Repeatable=false +NumberWinsRequired=40 +CardReward=4 black rares +CreditsReward=200 +Icon=Zombie Attack.jpg +AILife=30 +Deck Type=constructed +Comment= [main] 1 Cadaverous Knight 1 Bog Raiders @@ -27,3 +38,11 @@ constructed 1 Warpath Ghoul 1 Viscera Dragger [sideboard] +[human_extra_cards] +TOKEN|W|1|1|citizen|creature +TOKEN|W|1|1|citizen|creature +TOKEN|W|1|1|citizen|creature +Wall of Spears +[ai_extra_cards] +Scathe Zombies +Mass of Ghouls \ No newline at end of file diff --git a/res/quest/decks/quest11.dck b/res/quest/decks/quest11.dck index 2565a2b4cd9..25c71bc3148 100644 --- a/res/quest/decks/quest11.dck +++ b/res/quest/decks/quest11.dck @@ -1,49 +1,64 @@ -quest11 -[general] -constructed -[main] -1 Isamaru, Hound of Konda -4 Plateau -1 Radiant, Archangel -4 Taiga -1 Zuo Ci, the Mocking Sage -1 Mox Emerald -1 Rakka Mar -1 Concordant Crossroads -1 Meng Huo, Barbarian King -1 Jeska, Warrior Adept -2 Loyal Retainers -1 Jacques le Vert -1 Tolsimir Wolfblood -1 Squee, Goblin Nabob -1 Kaysa -1 Earthcraft -1 Mox Pearl -1 Mikokoro, Center of the Sea -1 Eladamri, Lord of Leaves -1 Eladamri's Call -1 Mirri, Cat Warrior -1 Exploration -4 Savannah -1 Gaddock Teeg -1 Honden of Cleansing Fire -1 Pianna, Nomad Captain -1 Azusa, Lost but Seeking -3 Plains -1 Captain Sisay -1 Okina, Temple to the Grandfathers -1 Honden of Infinite Rage -1 Reki, the History of Kamigawa -1 Goblin Assault -1 Umezawa's Jitte -3 Forest -1 Fecundity -1 Mox Ruby -1 Tuktuk the Explorer -1 Zuberi, Golden Feather -1 Fastbond -1 Honden of Life's Web -1 Kongming, "Sleeping Dragon" -3 Mountain -1 Tuknir Deathlock -[sideboard] +[metadata] +ID=11 +Name=quest11 +DisplayName=The King's Contest +Difficulty=Hard +Description=The king is holding a contest. You are invited to participate and compete against other legends of this era. +Repeatable=false +NumberWinsRequired=40 +CardReward=3 random rares +CreditsReward=150 +Icon=The Kings Contest.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +1 Isamaru, Hound of Konda +4 Plateau +1 Radiant, Archangel +4 Taiga +1 Zuo Ci, the Mocking Sage +1 Mox Emerald +1 Rakka Mar +1 Concordant Crossroads +1 Meng Huo, Barbarian King +1 Jeska, Warrior Adept +2 Loyal Retainers +1 Jacques le Vert +1 Tolsimir Wolfblood +1 Squee, Goblin Nabob +1 Kaysa +1 Earthcraft +1 Mox Pearl +1 Mikokoro, Center of the Sea +1 Eladamri, Lord of Leaves +1 Eladamri's Call +1 Mirri, Cat Warrior +1 Exploration +4 Savannah +1 Gaddock Teeg +1 Honden of Cleansing Fire +1 Pianna, Nomad Captain +1 Azusa, Lost but Seeking +3 Plains +1 Captain Sisay +1 Okina, Temple to the Grandfathers +1 Honden of Infinite Rage +1 Reki, the History of Kamigawa +1 Goblin Assault +1 Umezawa's Jitte +3 Forest +1 Fecundity +1 Mox Ruby +1 Tuktuk the Explorer +1 Zuberi, Golden Feather +1 Fastbond +1 Honden of Life's Web +1 Kongming, "Sleeping Dragon" +3 Mountain +1 Tuknir Deathlock +[sideboard] +[human_extra_cards] +Seal of Cleansing +[ai_extra_cards] +Loyal Retainers \ No newline at end of file diff --git a/res/quest/decks/quest12.dck b/res/quest/decks/quest12.dck index 4c0da6a5ac3..7cfecdba3e9 100644 --- a/res/quest/decks/quest12.dck +++ b/res/quest/decks/quest12.dck @@ -1,26 +1,43 @@ -quest12 -[general] -constructed -[main] -2 Birds of Paradise -4 Knight of the Reliquary -2 Elspeth, Knight-Errant -2 Eternal Witness -1 Progenitus -5 Plains -3 Natural Order -2 Garruk Wildspeaker -1 Umezawa's Jitte -7 Forest -2 Stoneforge Mystic -4 Swords to Plowshares -1 Dryad Arbor -4 Qasali Pridemage -4 Tarmogoyf -1 Loxodon Warhammer -2 Path to Exile -4 Noble Hierarch -1 Quietus Spike -4 Savannah -4 Wasteland -[sideboard] +[metadata] +ID=12 +Name=quest12 +DisplayName=Barroom Brawl +Difficulty=Hard +Description=A drunken giant of a man takes a swing at you, your brew spills and a fight breaks out. +Repeatable=false +NumberWinsRequired=64 +CardReward=4 random rares +CreditsReward=250 +Icon=Barroom Brawl.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +2 Birds of Paradise +4 Knight of the Reliquary +2 Elspeth, Knight-Errant +2 Eternal Witness +1 Progenitus +5 Plains +3 Natural Order +2 Garruk Wildspeaker +1 Umezawa's Jitte +7 Forest +2 Stoneforge Mystic +4 Swords to Plowshares +1 Dryad Arbor +4 Qasali Pridemage +4 Tarmogoyf +1 Loxodon Warhammer +2 Path to Exile +4 Noble Hierarch +1 Quietus Spike +4 Savannah +4 Wasteland +[sideboard] +[human_extra_cards] +TOKEN|W|1|1|soldier ally|creature|soldier|ally +TOKEN|W|1|1|soldier ally|creature|soldier|ally +TOKEN|W|1|1|soldier ally|creature|soldier|ally +[ai_extra_cards] +Lowland Giant \ No newline at end of file diff --git a/res/quest/decks/quest13.dck b/res/quest/decks/quest13.dck index fdc2ba1a02d..4f755357b46 100644 --- a/res/quest/decks/quest13.dck +++ b/res/quest/decks/quest13.dck @@ -1,27 +1,42 @@ -quest13 -[general] -constructed -[main] -4 Underground Sea -4 Spreading Seas -4 Remove Soul -1 Avatar of Fury -1 Mox Sapphire -2 Damnation -4 Crumbling Necropolis -2 Island -1 Ancestral Recall -4 Badlands -4 Fire-Field Ogre -4 Kargan Dragonlord -4 Lightning Bolt -2 Nicol Bolas -1 Mox Ruby -4 Sedraxis Specter -4 Volcanic Island -1 Time Walk -4 Counterspell -2 Cruel Ultimatum -1 Mox Jet -2 Mountain -[sideboard] +[metadata] +ID=13 +Name=quest13 +DisplayName=The Court Jester +Difficulty=Hard +Description=The Court Jester pulls a prank on you. Will you laugh it off or pay him back? +Repeatable=false +NumberWinsRequired=52 +CardReward=4 multi-colored rares +CreditsReward=300 +Icon=The Court Jester.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Underground Sea +4 Spreading Seas +4 Remove Soul +1 Avatar of Fury +1 Mox Sapphire +2 Damnation +4 Crumbling Necropolis +2 Island +1 Ancestral Recall +4 Badlands +4 Fire-Field Ogre +4 Kargan Dragonlord +4 Lightning Bolt +2 Nicol Bolas +1 Mox Ruby +4 Sedraxis Specter +4 Volcanic Island +1 Time Walk +4 Counterspell +2 Cruel Ultimatum +1 Mox Jet +2 Mountain +[sideboard] +[human_extra_cards] +Sensei's Divining Top +[ai_extra_cards] +Teferi's Puzzle Box \ No newline at end of file diff --git a/res/quest/decks/quest14.dck b/res/quest/decks/quest14.dck index 7734d6457dc..622de5daf5d 100644 --- a/res/quest/decks/quest14.dck +++ b/res/quest/decks/quest14.dck @@ -1,6 +1,17 @@ -quest14 -[general] -constructed +[metadata] +ID=14 +Name=quest14 +DisplayName=Ancient Battlefield +Difficulty=Hard +Description=You visit an ancient battlefield at midnight. It is overgrown and dark. You trip on a root, utter a curse and wish that you could see. +Repeatable=false +NumberWinsRequired=64 +CardReward=4 random rares +CreditsReward=250 +Icon=Ancient Battlefield.jpg +AILife=30 +Deck Type=constructed +Comment= [main] 4 Birds of Paradise 1 Plague Wind @@ -21,3 +32,9 @@ constructed 1 Mox Jet 4 Essence Warden [sideboard] +[human_extra_cards] +Glasses of Urza +Blight Sickle +[ai_extra_cards] +Bad Moon +Wall of Brambles \ No newline at end of file diff --git a/res/quest/decks/quest15.dck b/res/quest/decks/quest15.dck index 9a34aac4b1f..234a89f183f 100644 --- a/res/quest/decks/quest15.dck +++ b/res/quest/decks/quest15.dck @@ -1,24 +1,42 @@ -quest15 -[general] -constructed -[main] -4 Plateau -4 Druid of the Anima -4 Taiga -1 Mox Emerald -3 Temple Garden -3 Glorious Anthem -3 Stomping Ground -4 Elvish Champion -4 Lightning Bolt -1 Mox Ruby -1 Mox Pearl -3 Gaea's Anthem -4 Blaze -3 Fireball -4 Savannah -3 Beastmaster Ascension -3 Keen-Eyed Archers -4 Elvish Harbinger -4 Llanowar Elves -[sideboard] +[metadata] +ID=15 +Name=quest15 +DisplayName=Don't Play With Matches +Difficulty=Hard +Description=The goblins are battling the elves. Those pesky elves, will they ever learn. Do not play with fire! +Repeatable=false +NumberWinsRequired=52 +CardReward=4 red rares +CreditsReward=200 +Icon=Dont Play With Matches.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Plateau +4 Druid of the Anima +4 Taiga +1 Mox Emerald +3 Temple Garden +3 Glorious Anthem +3 Stomping Ground +4 Elvish Champion +4 Lightning Bolt +1 Mox Ruby +1 Mox Pearl +3 Gaea's Anthem +4 Blaze +3 Fireball +4 Savannah +3 Beastmaster Ascension +3 Keen-Eyed Archers +4 Elvish Harbinger +4 Llanowar Elves +[sideboard] +[human_extra_cards] +1 Mudbutton Torchrunner +1 Scuzzback Scrapper +[ai_extra_cards] +1 Heedless One +1 Norwood Archers +1 Wildslayer Elves \ No newline at end of file diff --git a/res/quest/decks/quest16.dck b/res/quest/decks/quest16.dck index 91382935c9e..3209425a6f7 100644 --- a/res/quest/decks/quest16.dck +++ b/res/quest/decks/quest16.dck @@ -1,28 +1,50 @@ -quest16 -[general] -constructed -[main] -1 Proper Burial -2 Disenchant -1 Mox Emerald -4 Sporesower Thallid -2 Psychotrope Thallid -5 Plains -4 Graypelt Refuge -2 Mycoloth -4 Sunpetal Grove -2 Rampant Growth -1 Enlightened Tutor -4 Mycologist -2 Kodama's Reach -5 Forest -4 Thallid -1 Mox Pearl -1 Desert Twister -1 Exploration -4 Pallid Mycoderm -2 Defense of the Heart -4 Savannah -1 Doubling Season -3 Thelonite Hermit -[sideboard] +[metadata] +ID=16 +Name=quest16 +DisplayName=Mines of Kazum Durl +Difficulty=Hard +Description=While exploring a mine with a group of dwarves the mine caves in. You start to dig out and then realize that your group is not alone. +Repeatable=false +NumberWinsRequired=52 +CardReward=4 green rares +CreditsReward=250 +Icon=Mines of Kazum Durl.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +1 Proper Burial +2 Disenchant +1 Mox Emerald +4 Sporesower Thallid +2 Psychotrope Thallid +5 Plains +4 Graypelt Refuge +2 Mycoloth +4 Sunpetal Grove +2 Rampant Growth +1 Enlightened Tutor +4 Mycologist +2 Kodama's Reach +5 Forest +4 Thallid +1 Mox Pearl +1 Desert Twister +1 Exploration +4 Pallid Mycoderm +2 Defense of the Heart +4 Savannah +1 Doubling Season +3 Thelonite Hermit +[sideboard] +[human_extra_cards] +Dwarven Demolition Team +Dwarven Pony +Dwarven Trader +[ai_extra_cards] +Wall of Earth +Wall of Air +Wall of Ice +Wall of Light +Carrion Wall +Steel Wall \ No newline at end of file diff --git a/res/quest/decks/quest17.dck b/res/quest/decks/quest17.dck index 9befd406764..9e26a1d950f 100644 --- a/res/quest/decks/quest17.dck +++ b/res/quest/decks/quest17.dck @@ -1,28 +1,46 @@ -quest17 -[general] -constructed -[main] -4 Terminate -4 Taiga -2 Dragonskull Summit -1 Mox Emerald -1 Swamp -4 Putrid Leech -2 Bituminous Blast -2 Siege-Gang Commander -1 Garruk Wildspeaker -3 Savage Lands -1 Forest -4 Badlands -4 Blightning -4 Lightning Bolt -1 Mox Ruby -4 Maelstrom Pulse -2 Rootbound Crag -4 Bayou -4 Bloodbraid Elf -2 Sarkhan the Mad -1 Mox Jet -4 Sprouting Thrinax -1 Mountain -[sideboard] +[metadata] +ID=17 +Name=quest17 +DisplayName=House Party +Difficulty=Hard +Description=Your friends decide to hold a house party at your home tonight. Later that night uninvited guests show up and disrupt the party. +Repeatable=false +NumberWinsRequired=64 +CardReward=4 colorless rares +CreditsReward=250 +Icon=House Party.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Terminate +4 Taiga +2 Dragonskull Summit +1 Mox Emerald +1 Swamp +4 Putrid Leech +2 Bituminous Blast +2 Siege-Gang Commander +1 Garruk Wildspeaker +3 Savage Lands +1 Forest +4 Badlands +4 Blightning +4 Lightning Bolt +1 Mox Ruby +4 Maelstrom Pulse +2 Rootbound Crag +4 Bayou +4 Bloodbraid Elf +2 Sarkhan the Mad +1 Mox Jet +4 Sprouting Thrinax +1 Mountain +[sideboard] +[human_extra_cards] +Hopping Automaton +Honden of Life's Web +Forbidden Orchard +[ai_extra_cards] +Honden of Infinite Rage +Mikokoro, Center of the Sea \ No newline at end of file diff --git a/res/quest/decks/quest18.dck b/res/quest/decks/quest18.dck index 3a5374e9b0f..8ab89db2a5b 100644 --- a/res/quest/decks/quest18.dck +++ b/res/quest/decks/quest18.dck @@ -1,25 +1,45 @@ -quest18 -[general] -constructed -[main] -4 Birds of Paradise -4 Knight of the Reliquary -2 Sejiri Steppe -1 Mox Emerald -4 Tropical Island -2 Elspeth, Knight-Errant -1 Mox Sapphire -2 Plains -2 Island -4 Forest -4 Sovereigns of Lost Alara -3 Jace Beleren -1 Mox Pearl -4 Dauntless Escort -4 Tundra -4 Steppe Lynx -4 Baneslayer Angel -4 Noble Hierarch -4 Savannah -2 Eldrazi Conscription -[sideboard] +[metadata] +ID=18 +Name=quest18 +DisplayName=Crows in the Field +Difficulty=Hard +Description=Crows are eating the seed planted in the local farm fields. The farmers are scared. Those crows are big, you will need some help. +Repeatable=false +NumberWinsRequired=64 +CardReward=5 random rares +CreditsReward=300 +Icon=Crows in the Field.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Birds of Paradise +4 Knight of the Reliquary +2 Sejiri Steppe +1 Mox Emerald +4 Tropical Island +2 Elspeth, Knight-Errant +1 Mox Sapphire +2 Plains +2 Island +4 Forest +4 Sovereigns of Lost Alara +3 Jace Beleren +1 Mox Pearl +4 Dauntless Escort +4 Tundra +4 Steppe Lynx +4 Baneslayer Angel +4 Noble Hierarch +4 Savannah +2 Eldrazi Conscription +[sideboard] +[human_extra_cards] +Straw Soldiers +Femeref Archers +Moonglove Extract +[ai_extra_cards] +Defiant Falcon +Soulcatcher +Storm Crow +Hypnotic Specter \ No newline at end of file diff --git a/res/quest/decks/quest19.dck b/res/quest/decks/quest19.dck index cbde1cde189..ad1d425ec45 100644 --- a/res/quest/decks/quest19.dck +++ b/res/quest/decks/quest19.dck @@ -1,22 +1,39 @@ -quest19 -[general] -constructed -[main] -4 Birds of Paradise -3 Armistice -1 Mox Emerald -6 Plains -4 Temple Garden -4 Utopia Tree -3 Door to Nothingness -4 Darksteel Ingot -3 Harmonize -1 Enlightened Tutor -6 Forest -4 Peacekeeper -4 Gemhide Sliver -4 Magus of the Moat -1 Mox Pearl -4 Eladamri's Call -4 Savannah -[sideboard] +[metadata] +ID=19 +Name=quest19 +DisplayName=The Desert Caravan +Difficulty=Hard +Description=A caravan is transporting silk across the desert. While setting up camp for the night you are attacked by thieves. Defend yourself. +Repeatable=false +NumberWinsRequired=80 +CardReward=5 random rares +CreditsReward=300 +Icon=The Desert Caravan.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Birds of Paradise +3 Armistice +1 Mox Emerald +6 Plains +4 Temple Garden +4 Utopia Tree +3 Door to Nothingness +4 Darksteel Ingot +3 Harmonize +1 Enlightened Tutor +6 Forest +4 Peacekeeper +4 Gemhide Sliver +4 Magus of the Moat +1 Mox Pearl +4 Eladamri's Call +4 Savannah +[sideboard] +[human_extra_cards] +Spidersilk Net +Dromad Purebred +[ai_extra_cards] +4 Ambush Party +Gnat Alley Creeper diff --git a/res/quest/decks/quest2.dck b/res/quest/decks/quest2.dck index 841139a6b30..c441c50006c 100644 --- a/res/quest/decks/quest2.dck +++ b/res/quest/decks/quest2.dck @@ -1,6 +1,17 @@ -quest2 -[general] -constructed +[metadata] +ID=2 +Name=quest2 +DisplayName=Dungeon Crawling (Blue) +Difficulty=Medium +Description=This realm holds knowledge so vast it can overburden the unwary. +Repeatable=true +NumberWinsRequired=20 +CardReward=3 blue rares +CreditsReward=100 +Icon=Dungeon Crawling Blue.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 20 Island 4 Wasteland @@ -27,3 +38,7 @@ constructed 1 Fugitive Wizard 1 Grayscaled Gharial [sideboard] +[human_extra_cards] +1 Quest for Ancient Secrets +[ai_extra_cards] +1 Forced Fruition \ No newline at end of file diff --git a/res/quest/decks/quest20.dck b/res/quest/decks/quest20.dck index d6ddaf27b80..760b796215e 100644 --- a/res/quest/decks/quest20.dck +++ b/res/quest/decks/quest20.dck @@ -1,34 +1,53 @@ -quest20 -[general] -constructed -[main] -4 Underground Sea -4 Tropical Island -1 Mox Emerald -4 Oath of Druids -1 Kozilek, Butcher of Truth -1 Thirst for Knowledge -4 Island -1 Brainstorm -1 Ancestral Recall -4 Spell Pierce -1 Sphinx of the Steel Wind -2 Duress -1 Mox Pearl -1 Iona, Shield of Emeria -1 Mox Jet -1 Balance -1 Ulamog, the Infinite Gyre -1 Mox Sapphire -4 Accumulated Knowledge -1 Tinker -2 Echoing Truth -4 Forbidden Orchard -1 Mox Ruby -3 Serum Visions -4 Volcanic Island -1 Time Walk -4 Counterspell -1 Thoughtseize -1 Emrakul, the Aeons Torn -[sideboard] +[metadata] +ID=20 +Name=quest20 +DisplayName=Blood Oath +Difficulty=Hard +Description=A druid saves your life and the two of you take a blood oath. It is now time to fulfill your oath. +Repeatable=false +NumberWinsRequired=80 +CardReward=5 colorless rares +CreditsReward=300 +Icon=Blood Oath.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +4 Underground Sea +4 Tropical Island +1 Mox Emerald +4 Oath of Druids +1 Kozilek, Butcher of Truth +1 Thirst for Knowledge +4 Island +1 Brainstorm +1 Ancestral Recall +4 Spell Pierce +1 Sphinx of the Steel Wind +2 Duress +1 Mox Pearl +1 Iona, Shield of Emeria +1 Mox Jet +1 Balance +1 Ulamog, the Infinite Gyre +1 Mox Sapphire +4 Accumulated Knowledge +1 Tinker +2 Echoing Truth +4 Forbidden Orchard +1 Mox Ruby +3 Serum Visions +4 Volcanic Island +1 Time Walk +4 Counterspell +1 Thoughtseize +1 Emrakul, the Aeons Torn +[sideboard] +[human_extra_cards] +Counterbalance +Hatching Plans +Ley Druid +[ai_extra_cards] +Ior Ruin Expedition +Oversold Cemetery +Trapjaw Kelpie \ No newline at end of file diff --git a/res/quest/decks/quest21.dck b/res/quest/decks/quest21.dck index 546b00c8bac..ebd53ee54d2 100644 --- a/res/quest/decks/quest21.dck +++ b/res/quest/decks/quest21.dck @@ -1,6 +1,17 @@ -quest21 -[general] -constructed +[metadata] +ID=21 +Name=quest21 +DisplayName=Private Domain +Difficulty=Expert +Description=During your travels, you accidentally stumble upon the domain of an evil, powerful wizard. A fight to the death ensues. +Repeatable=false +NumberWinsRequired=96 +CardReward=6 random rares +CreditsReward=500 +Icon=Private Domain.jpg +AILife=50 +Deck Type=constructed +Comment= [main] 2 Underground Sea 2 Plateau @@ -29,3 +40,11 @@ constructed 1 Mountain 2 Wandering Stream [sideboard] +[human_extra_cards] +Strip Mine +[ai_extra_cards] +Plains +Island +Mountain +Swamp +Forest diff --git a/res/quest/decks/quest22.dck b/res/quest/decks/quest22.dck index 538293a4152..e33e6b1fca7 100644 --- a/res/quest/decks/quest22.dck +++ b/res/quest/decks/quest22.dck @@ -1,6 +1,17 @@ -quest22 -[general] -constructed +[metadata] +ID=22 +Name=quest22 +DisplayName=The Pied Piper +Difficulty=Hard +Description=A mysterious man threatens to flood the land with a relentless stream of hungry rats. Cross his plan before it's too late. +Repeatable=false +NumberWinsRequired=32 +CardReward=3 random rares +CreditsReward=150 +Icon=The Pied Piper.jpg +AILife=30 +Deck Type=constructed +Comment= [main] 6 Swamp 4 Underground Sea @@ -12,3 +23,11 @@ constructed 4 Thrumming Stone 29 Relentless Rats [sideboard] +[human_extra_cards] +1 Volunteer Militia +1 Land Tax +1 Elvish Farmer +1 An-Havva Township +[ai_extra_cards] +1 Darksteel Citadel +1 Relentless Rats \ No newline at end of file diff --git a/res/quest/decks/quest3.dck b/res/quest/decks/quest3.dck index a1245344791..c0d123d1a22 100644 --- a/res/quest/decks/quest3.dck +++ b/res/quest/decks/quest3.dck @@ -1,6 +1,17 @@ -quest3 -[general] -constructed +[metadata] +ID=3 +Name=quest3 +DisplayName=Dungeon Crawling (Black) +Difficulty=Medium +Description=Guarded by black creatures. +Repeatable=true +NumberWinsRequired=20 +CardReward=3 black rares +CreditsReward=100 +Icon=Dungeon Crawling Black.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 20 Swamp 4 Charcoal Diamond @@ -27,3 +38,6 @@ constructed 1 Beacon of Unrest 1 Zombify [sideboard] +[human_extra_cards] +[ai_extra_cards] +Infernal Genesis \ No newline at end of file diff --git a/res/quest/decks/quest4.dck b/res/quest/decks/quest4.dck index 198ca32feef..06a93cc8478 100644 --- a/res/quest/decks/quest4.dck +++ b/res/quest/decks/quest4.dck @@ -1,6 +1,17 @@ -quest4 -[general] -constructed +[metadata] +ID=4 +Name=quest4 +DisplayName=Dungeon Crawling (Red) +Difficulty=Medium +Description=Guarded by red creatures. +Repeatable=true +NumberWinsRequired=20 +CardReward=3 red rares +CreditsReward=100 +Icon=Dungeon Crawling Red.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 49 Mountain 1 Fury Sliver @@ -85,3 +96,6 @@ constructed 1 Tarfire 1 Volcanic Hammer [sideboard] +[human_extra_cards] +[ai_extra_cards] +Furnace of Rath \ No newline at end of file diff --git a/res/quest/decks/quest5.dck b/res/quest/decks/quest5.dck index 9e0bcf69496..81b8e7b65ad 100644 --- a/res/quest/decks/quest5.dck +++ b/res/quest/decks/quest5.dck @@ -1,6 +1,17 @@ -quest5 -[general] -constructed +[metadata] +ID=5 +Name=quest5 +DisplayName=Dungeon Crawling (Green) +Difficulty=Medium +Description=Guarded by green creatures. +Repeatable=true +NumberWinsRequired=20 +CardReward=3 green rares +CreditsReward=100 +Icon=Dungeon Crawling Green.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 33 Forest 1 Alpha Tyrranax @@ -65,3 +76,8 @@ constructed 1 Woodfall Primus 1 Yavimaya Wurm [sideboard] +[human_extra_cards] +Defense of the Heart +[ai_extra_cards] +Eladamri's Vineyard +Upwelling \ No newline at end of file diff --git a/res/quest/decks/quest6.dck b/res/quest/decks/quest6.dck index d1ad5300b39..76242092e62 100644 --- a/res/quest/decks/quest6.dck +++ b/res/quest/decks/quest6.dck @@ -1,76 +1,90 @@ -quest6 -[general] -constructed -[main] -20 Island -20 Swamp -1 Complex Automaton -1 Eldrazi Monument -1 Esperzoa -1 Forethought Amulet -1 Masticore -1 Molten-Tail Masticore -1 Puppet Conjurer -1 Razormane Masticore -1 Rejuvenation Chamber -1 Rusting Golem -1 Soldevi Simulacrum -1 Soultether Golem -1 Thran War Machine -1 Urza's Blueprints -1 Aku Djinn -1 Arnjlot's Ascent -1 Benthic Djinn -1 Binding Grasp -1 Blessing of Leeches -1 Breeding Pit -1 Carnophage -1 Cloudskate -1 Cosmic Horror -1 Demonic Appetite -1 Drifter il-Dal -1 Ebon Praetor -1 Fledgling Djinn -1 Flow of Maggots -1 Greater Harvester -1 Grinning Demon -1 Illusionary Forces -1 Illusionary Wall -1 Illusions of Grandeur -1 Imaginary Pet -1 Junun Efreet -1 Juzam Djinn -1 Kezzerdrix -1 Kuro, Pitlord -1 Liege of the Pit -1 Lord of the Pit -1 Melancholy -1 Minion of Tevesh Szat -1 Molting Harpy -1 Moroii -1 Mystic Remora -1 Oni Possession -4 Pact of Negation -1 Pact of the Titan -1 Phantasmal Forces -1 Phobian Phantasm -1 Pit Raptor -1 Pit Spawn -1 Raven Familiar -1 Sangrophage -1 Sarcomancy -1 School of Piranha -1 Serendib Efreet -1 Shauku, Endbringer -1 Skull Collector -4 Slaughter Pact -1 Spindrift Drake -1 Spiteful Bully -1 Thirst -1 Trusted Advisor -1 Unstable Mutation -1 Vampire Lacerator -1 Waning Wurm -1 Whipstitched Zombie -1 Yawgmoth Demon -[sideboard] +[metadata] +ID=6 +Name=quest6 +DisplayName=Dungeon Crawling (Colorless) +Difficulty=Hard +Description=The inhabitants of this plane tread with a light step. +Repeatable=true +NumberWinsRequired=28 +CardReward=3 colorless rares +CreditsReward=150 +Icon=Dungeon Crawling Colorless.jpg +AILife=30 +Deck Type=constructed +Comment= +[main] +20 Island +20 Swamp +1 Complex Automaton +1 Eldrazi Monument +1 Esperzoa +1 Forethought Amulet +1 Masticore +1 Molten-Tail Masticore +1 Puppet Conjurer +1 Razormane Masticore +1 Rejuvenation Chamber +1 Rusting Golem +1 Soldevi Simulacrum +1 Soultether Golem +1 Thran War Machine +1 Urza's Blueprints +1 Aku Djinn +1 Arnjlot's Ascent +1 Benthic Djinn +1 Binding Grasp +1 Blessing of Leeches +1 Breeding Pit +1 Carnophage +1 Cloudskate +1 Cosmic Horror +1 Demonic Appetite +1 Drifter il-Dal +1 Ebon Praetor +1 Fledgling Djinn +1 Flow of Maggots +1 Greater Harvester +1 Grinning Demon +1 Illusionary Forces +1 Illusionary Wall +1 Illusions of Grandeur +1 Imaginary Pet +1 Junun Efreet +1 Juzam Djinn +1 Kezzerdrix +1 Kuro, Pitlord +1 Liege of the Pit +1 Lord of the Pit +1 Melancholy +1 Minion of Tevesh Szat +1 Molting Harpy +1 Moroii +1 Mystic Remora +1 Oni Possession +4 Pact of Negation +1 Pact of the Titan +1 Phantasmal Forces +1 Phobian Phantasm +1 Pit Raptor +1 Pit Spawn +1 Raven Familiar +1 Sangrophage +1 Sarcomancy +1 School of Piranha +1 Serendib Efreet +1 Shauku, Endbringer +1 Skull Collector +4 Slaughter Pact +1 Spindrift Drake +1 Spiteful Bully +1 Thirst +1 Trusted Advisor +1 Unstable Mutation +1 Vampire Lacerator +1 Waning Wurm +1 Whipstitched Zombie +1 Yawgmoth Demon +[sideboard] +[human_extra_cards] +[ai_extra_cards] +3 Eon Hub \ No newline at end of file diff --git a/res/quest/decks/quest7.dck b/res/quest/decks/quest7.dck index 7a2a715b6d5..2fc207e569e 100644 --- a/res/quest/decks/quest7.dck +++ b/res/quest/decks/quest7.dck @@ -1,6 +1,17 @@ -quest7 -[general] -constructed +[metadata] +ID=7 +Name=quest7 +DisplayName=Dungeon Crawling (Gold) +Difficulty=Hard +Description=Guarded by gold creatures. +Repeatable=true +NumberWinsRequired=28 +CardReward=3 multi-colored rares +CreditsReward=150 +Icon=Dungeon Crawling Gold.jpg +AILife=30 +Deck Type=constructed +Comment= [main] 4 Glimmervoid 4 Reflecting Pool @@ -37,3 +48,6 @@ constructed 1 Conflux 1 Maelstrom Nexus [sideboard] +[human_extra_cards] +[ai_extra_cards] +Darksteel Ingot \ No newline at end of file diff --git a/res/quest/decks/quest8.dck b/res/quest/decks/quest8.dck index b0f07d3d4d7..8bab6103fc9 100644 --- a/res/quest/decks/quest8.dck +++ b/res/quest/decks/quest8.dck @@ -1,6 +1,17 @@ -quest8 -[general] -constructed +[metadata] +ID=8 +Name=quest8 +DisplayName=A Wolf in Sheep's Clothing +Difficulty=Medium +Description=The local sheep farm is under attack by a pack of wolves. Kill the wolves, save the sheep! +Repeatable=false +NumberWinsRequired=28 +CardReward=3 random rares +CreditsReward=200 +Icon=A Wolf in Sheeps Clothing.jpg +AILife=25 +Deck Type=constructed +Comment= [main] 1 Temple Garden 1 Mox Emerald @@ -20,3 +31,8 @@ constructed 4 Tundra Wolves 4 Savannah [sideboard] +[human_extra_cards] +TOKEN|G|0|1|sheep|creature|sheep +TOKEN|G|0|1|sheep|creature|sheep +TOKEN|G|0|1|sheep|creature|sheep +[ai_extra_cards] \ No newline at end of file diff --git a/res/quest/decks/quest9.dck b/res/quest/decks/quest9.dck index 1e609e6fb36..6916e106766 100644 --- a/res/quest/decks/quest9.dck +++ b/res/quest/decks/quest9.dck @@ -1,6 +1,17 @@ -quest9 -[general] -constructed +[metadata] +ID=9 +Name=quest9 +DisplayName=Bushwhacked! +Difficulty=Hard +Description=You find yourself surrounded by carnivorous plants and poisonous vines. Cut your way out of this foresty mess and make it home safe. +Repeatable=false +NumberWinsRequired=40 +CardReward=4 green rares +CreditsReward=225 +Icon=Bushwhacked.jpg +AILife=30 +Deck Type=constructed +Comment= [main] 2 Avenger of Zendikar 1 Sapling of Colfenor @@ -21,3 +32,7 @@ constructed 4 Vine Trellis 1 Overbeing of Myth [sideboard] +[human_extra_cards] +Trusty Machete +[ai_extra_cards] +3 Wall of Wood \ No newline at end of file diff --git a/src/main/java/forge/AllZone.java b/src/main/java/forge/AllZone.java index 41fe213057a..3f7f2ef3ea1 100644 --- a/src/main/java/forge/AllZone.java +++ b/src/main/java/forge/AllZone.java @@ -17,6 +17,7 @@ import forge.properties.ForgeProps; import forge.properties.NewConstants; import forge.quest.data.QuestMatchState; import forge.quest.data.QuestData; +import forge.quest.data.DeckSingleQuest; /** * Please use public getters and setters instead of direct field access. @@ -40,9 +41,9 @@ public final class AllZone implements NewConstants { /** Global questData. */ private static forge.quest.data.QuestData questData = null; - - /** Global QuestAssignment. */ - private static Quest_Assignment questAssignment = null; + + /** Global currentQuest. */ + private static forge.quest.data.DeckSingleQuest currentQuest = null; /** Constant NAME_CHANGER. */ private static final NameChanger NAME_CHANGER = new NameChanger(); @@ -129,25 +130,25 @@ public final class AllZone implements NewConstants { public static void setQuestData(final QuestData questData0) { questData = questData0; } - + /** - *

getQuestAssignment.

+ *

getCurrentQuest.

* - * @return a {@link forge.Quest_Assignment} object. - * @since 1.0.15 + * @return a {@link forge.quest.data.QuestData} object. + * */ - public static Quest_Assignment getQuestAssignment() { - return questAssignment; + public static forge.quest.data.DeckSingleQuest getCurrentQuest() { + return currentQuest; } /** - *

setQuestAssignment.

+ *

setCurrentQuest.

* - * @param assignment a {@link forge.Quest_Assignment} object. - * @since 1.0.15 + * @param a DeckSingleQuest object. + * */ - public static void setQuestAssignment(final Quest_Assignment assignment) { - questAssignment = assignment; + public static void setCurrentQuest(final DeckSingleQuest qq) { + currentQuest = qq; } /** diff --git a/src/main/java/forge/gui/SelectablePanel.java b/src/main/java/forge/gui/SelectablePanel.java new file mode 100644 index 00000000000..5af89c1013c --- /dev/null +++ b/src/main/java/forge/gui/SelectablePanel.java @@ -0,0 +1,43 @@ +package forge.gui; + +import java.awt.Color; + +import javax.swing.JPanel; + + +/** + *

SelectablePanel

+ * VIEW - Standard selectable JPanel used for many places in the GUI. + * + */ +@SuppressWarnings("serial") +public abstract class SelectablePanel extends JPanel { + + private boolean selected = false; + protected Color backgroundColor = this.getBackground(); + + /** + *

Getter for the field selected

+ * + * @return boolean. + */ + public boolean getSelected() { + return selected; + } + + /** + *

Setter for the field selected

+ * Sets selected field and visual effect. + * + * @param boolean. + */ + public void setSelected(boolean selected) { + if (selected) { + this.setBackground(backgroundColor.darker()); + } else { + this.setBackground(backgroundColor); + } + + this.selected = selected; + } +} diff --git a/src/main/java/forge/quest/data/DeckSingleBattle.java b/src/main/java/forge/quest/data/DeckSingleBattle.java new file mode 100644 index 00000000000..ba7dde7ab3f --- /dev/null +++ b/src/main/java/forge/quest/data/DeckSingleBattle.java @@ -0,0 +1,116 @@ +package forge.quest.data; + +import javax.swing.ImageIcon; +import forge.deck.Deck; +import forge.gui.GuiUtils; + +/** + *

DeckSingleBattle

+ * MODEL - Assembles and stores information from a battle deck. + * + * @author Forge + * @version $Id$ + */ +public class DeckSingleBattle { + private String deckName; + private String displayName; + private String diff; + private String desc; + private String iconFilename; + private ImageIcon icon; + private Deck deckObj; + + /** + *

Constructor for DeckSingleBattle.

+ * + * @param {@link java.lang.String} storing name of AI deck for this battle + */ + public DeckSingleBattle(Deck d) { + // Get deck object and properties for this opponent. + this.deckObj = d; + this.deckName = d.getName(); + this.displayName = deckObj.getMetadata("DisplayName"); + this.diff = deckObj.getMetadata("Difficulty"); + this.desc = deckObj.getMetadata("Description"); + this.iconFilename = deckObj.getMetadata("Icon"); + + // Default icon + this.icon = GuiUtils.getIconFromFile(displayName + ".jpg"); + + // If non-default icon defined, use it. Any filetype accepted. + if(!iconFilename.equals("")) { + this.icon = GuiUtils.getIconFromFile(iconFilename); + } + } + + /** + *

getDifficulty()

+ * Retrieve rated difficulty of this battle deck. + * + * @return {@link java.lang.String} + */ + public String getDifficulty() { + return this.diff; + } + + /** + *

getDescription()

+ * Retrieve description of this battle deck. + * + * @return {@link java.lang.String} + */ + public String getDescription() { + return this.desc; + } + + /** + *

getDisplayName()

+ * Retrieve display name of this battle deck. + * + * @return {@link java.lang.String} + */ + public String getDisplayName() { + return this.displayName; + } + + /** + *

getDeckName()

+ * Retrieve file name of this battle deck. + * + * @return {@link java.lang.String} + */ + public String getDeckName() { + return this.deckName; + } + + /** + *

getIconFilename()

+ * Retrieve file name of preferred icon + * + * @return {@link java.lang.String} + */ + public String getIconFilename() { + return this.iconFilename; + } + + /** + *

getDeck()

+ * Retrieve this battle deck. + * + * @return {@link java.lang.String} + */ + public Deck getDeck() { + return this.deckObj; + } + + /** + *

getIcon()

+ * Retrieve the icon used with this battle deck. + * + * @return {@link java.lang.String} + */ + public ImageIcon getIcon() { + return this.icon; + } + +} diff --git a/src/main/java/forge/quest/data/DeckSingleQuest.java b/src/main/java/forge/quest/data/DeckSingleQuest.java new file mode 100644 index 00000000000..7143a1c80d0 --- /dev/null +++ b/src/main/java/forge/quest/data/DeckSingleQuest.java @@ -0,0 +1,270 @@ +package forge.quest.data; + +import java.util.ArrayList; +import javax.swing.ImageIcon; + +import com.google.code.jyield.Generator; +import com.google.code.jyield.YieldUtils; + +import forge.AllZone; +import forge.Card; +import forge.Constant; +import forge.deck.Deck; +import forge.gui.GuiUtils; + +/** + *

DeckSingleQuest

+ * MODEL - Assembles and stores information from a quest deck. + * + * @author Forge + * @version $Id$ + */ +public class DeckSingleQuest { + private String deckName; + private String displayName; + private String diff; + private String desc; + private String iconFilename; + private String cardReward; + + private int creditsReward; + private int numberWinsRequired; + private int AILife; + private int id; + + private boolean repeatable; + private ImageIcon icon; + private Deck deckObj; + + /** + *

Constructor for DeckSingleQuest

+ * + * @param {@link java.lang.String} storing name of AI deck for this quest + */ + public DeckSingleQuest(Deck d) { + // Get deck object and properties for this opponent. + this.deckObj = d; + this.deckName = d.getName(); + this.id = Integer.parseInt(deckObj.getMetadata("ID")); + this.displayName = deckObj.getMetadata("DisplayName"); + this.diff = deckObj.getMetadata("Difficulty"); + this.desc = deckObj.getMetadata("Description"); + this.iconFilename = deckObj.getMetadata("Icon"); + this.cardReward = deckObj.getMetadata("CardReward"); + this.creditsReward = Integer.parseInt(deckObj.getMetadata("CreditsReward")); + this.numberWinsRequired = Integer.parseInt(deckObj.getMetadata("NumberWinsRequired")); + this.AILife = Integer.parseInt(deckObj.getMetadata("AILife")); + + // Default icon + this.icon = GuiUtils.getIconFromFile(displayName + ".jpg"); + + // If non-default icon defined, use it. Any filetype accepted. + if(!iconFilename.equals("")) { + this.icon = GuiUtils.getIconFromFile(iconFilename); + } + + // Repeatability test + if(deckObj.getMetadata("Repeatable").equals("true")) { + this.repeatable = true; + } + else { + this.repeatable = false; + } + + } + + /** + *

getID()

+ * Retrieve ID number of this quest deck for recordkeeping. + * + * @return {@link java.lang.int} + */ + public int getID() { + return this.id; + } + + /** + *

getDifficulty()

+ * Retrieve rated difficulty of this quest deck. + * + * @return {@link java.lang.String} + */ + public String getDifficulty() { + return this.diff; + } + + /** + *

getDescription()

+ * Retrieve description of this quest deck. + * + * @return {@link java.lang.String} + */ + public String getDescription() { + return this.desc; + } + + /** + *

getDisplayName()

+ * Retrieve display name of this quest deck. + * + * @return {@link java.lang.String} + */ + public String getDisplayName() { + return this.displayName; + } + + /** + *

getDeckName()

+ * Retrieve file name of this quest deck. + * + * @return {@link java.lang.String} + */ + public String getDeckName() { + return this.deckName; + } + + /** + *

getCardReward()

+ * Retrieve cards rewarded after a win with this quest deck. + * + * @return {@link java.lang.String} + */ + private String getCardReward() { + return this.cardReward; + } + + /** + *

getCardRewardList()

+ * Retrieve cards rewarded after a win with this quest deck. + * + * @return String[] + */ + public ArrayList getCardRewardList() { + ArrayList cardRewardList = new ArrayList(); + + String[] details = this.getCardReward().split(" "); + + // Set quantity, color and rarity from file meta. + String cardscolor; + Constant.Rarity rarity; + int quantity = Integer.parseInt(details[0]); + + // Color + if(details[1].toLowerCase().equals("random")) { + cardscolor = null; + } + else if(details[1].toLowerCase().equals("blue")) { + cardscolor = Constant.Color.Blue; + } + else if(details[1].toLowerCase().equals("black")) { + cardscolor = Constant.Color.Black; + } + else if(details[1].toLowerCase().equals("green")) { + cardscolor = Constant.Color.Green; + } + else if(details[1].toLowerCase().equals("red")) { + cardscolor = Constant.Color.Red; + } + else if(details[1].toLowerCase().equals("white")) { + cardscolor = Constant.Color.White; + } + else if(details[1].toLowerCase().equals("multi-color") || + details[1].toLowerCase().equals("multi-colored")) { + cardscolor = "Multicolor"; + } + else if(details[1].toLowerCase().equals("colorless")) { + cardscolor = Constant.Color.Colorless; + } + else { + cardscolor = null; + System.err.println("DeckSingleQuest > getCardRewardList() reports "+ + "a badly formed card reward for quest "+ + this.getID()+".\n The color "+details[1]+" is not permitted.\n"+ + "Random colors have been substituted."); + } + + // Rarity + if(details[2].toLowerCase().equals("rares")) { + rarity = Constant.Rarity.Rare; + } + else { + rarity = Constant.Rarity.Common; + } + + // Generate deck list. + QuestBoosterPack pack = new QuestBoosterPack(); + pack.generateCards(quantity, rarity, cardscolor); + + return cardRewardList; + } + + /** + *

getNumberWinsRequired()

+ * Retrieve number of wins required to play against this quest deck. + * + * @return {@link java.lang.int} + */ + public int getNumberWinsRequired() { + return this.numberWinsRequired; + } + + /** + *

getAILife()

+ * Retrieve starting value of life for the AI playing this quest deck. + * + * @return {@link java.lang.int} + */ + public int getAILife() { + return this.AILife; + } + + /** + *

getCreditsReward()

+ * Retrieve number of credits rewarded after a win against this quest deck. + * + * @return {@link java.lang.int} + */ + public int getCreditsReward() { + return this.creditsReward; + } + + /** + *

getDeck()

+ * Retrieve this quest deck. + * + * @return {@link forge.deck.Deck} + */ + public Deck getDeck() { + return this.deckObj; + } + + /** + *

getIconFilename()

+ * Retrieve file name of preferred icon + * + * @return {@link java.lang.String} + */ + public String getIconFilename() { + return this.iconFilename; + } + + /** + *

getIcon()

+ * Retrieve the icon used with this quest deck. + * + * @return {@link javax.swing.ImageIcon} + */ + public ImageIcon getIcon() { + return this.icon; + } + + /** + *

getRepeatable.

+ * Retrieve boolean indicating if this quest is repeatable. + * + */ + public boolean getRepeatable() { + return this.repeatable; + } + +} diff --git a/src/main/java/forge/quest/data/ManagerBattle.java b/src/main/java/forge/quest/data/ManagerBattle.java new file mode 100644 index 00000000000..4cb3579693d --- /dev/null +++ b/src/main/java/forge/quest/data/ManagerBattle.java @@ -0,0 +1,237 @@ +package forge.quest.data; + +import forge.AllZone; +import forge.FileUtil; +import forge.deck.Deck; +import forge.deck.DeckManager; +import forge.error.ErrorViewer; +import forge.properties.ForgeProps; +import forge.properties.NewConstants; + +import java.io.File; +import java.util.*; + +/** + *

QuestBattleManager

+ * MODEL - Provides static methods to accomplish two key tasks: + * 1. Stores various AI difficulty decks and generates opponent list based on quest record. + * + * 2. Can instantiate a DeckSingleBattle for each opponent in the list. + * + * @author Forge + * @version $Id$ + */ + +// This could be combined with BattleManager and moved into QuestUtil. +public class ManagerBattle { + /** Constant aiDecks */ + private static transient Map aiDecks = new HashMap(); + /** Constant easyAIDecks */ + private static transient List easyAIDecks; + /** Constant mediumAIDecks */ + private static transient List mediumAIDecks; + /** Constant hardAIDecks */ + private static transient List hardAIDecks; + /** Constant veryHardAIDecks */ + private static transient List veryHardAIDecks; + + static { + List aiDeckNames = getAIDeckNames(); + easyAIDecks = readFile(ForgeProps.getFile(NewConstants.QUEST.EASY), aiDeckNames); + mediumAIDecks = readFile(ForgeProps.getFile(NewConstants.QUEST.MEDIUM), aiDeckNames); + hardAIDecks = readFile(ForgeProps.getFile(NewConstants.QUEST.HARD), aiDeckNames); + veryHardAIDecks = readFile(ForgeProps.getFile(NewConstants.QUEST.VERYHARD), aiDeckNames); + } + + + /** + *

removeAIDeck.

+ * Removes a deck object stored in the + *{@link forge.quest.gui.main.aiDecks} map. + * + * @param deckName a {@link java.lang.String} object. + */ + public static void removeAIDeck(String deckName) { + aiDecks.remove(deckName); + } + + /** + *

addAIDeck.

+ * Adds a deck object stored in the + *{@link forge.quest.gui.main.aiDecks} map. + * + * @param d a {@link forge.deck.Deck} object. + */ + public static void addAIDeck(Deck d) { + aiDecks.put(d.getName(), d); + } + + /** + *

getAIDeckFromMap.

+ * Returns a deck object stored in the + *{@link forge.quest.gui.main.aiDecks} map. + * + * @param deckName a {@link java.lang.String} object. + * @return a {@link forge.deck.Deck} object. + */ + public static Deck getAIDeckFromMap(String deckName) { + if (!aiDecks.containsKey(deckName)) { + ErrorViewer.showError(new Exception(), + "QuestData : getAIDeckFromMap(String deckName) error, deck name not found - %s", deckName); + } + + return aiDecks.get(deckName); + } + + /** + *

getAIDeckNames.

+ * Returns a list of decks stored in the + * {@link forge.quest.gui.main.aiDecks} map. + * + * @return a {@link java.util.List} object. + */ + public static List getAIDeckNames() { + return new ArrayList(aiDecks.keySet()); + } + + /** + *

getDeckFromFile.

+ * Returns a deck object built from a file name. + * Req'd because NewConstants.QUEST.DECKS must be used. + * + * @param deckName a {@link java.lang.String} object. + * @return a {@link forge.deck.Deck} object. + */ + public static Deck getAIDeckFromFile(String deckName) { + final File file = ForgeProps.getFile(NewConstants.QUEST.DECKS); + final DeckManager manager = new DeckManager(file); + return manager.getDeck(deckName); + } + + /** + *

getOpponent.

+ * + * Poorly named; AllZoneUtil already has a method called getOpponents. + * ????? Mechanics of this still a mystery ????? + * + * @param aiDeck a {@link java.util.List} object. + * @param number a int. + * @return a {@link java.lang.String} object. + */ + public static String getOpponent(List aiDeck, int number) { + //This is to make sure that the opponents do not change when the deck editor is launched. + List deckListCopy = new ArrayList(aiDeck); + Collections.shuffle(deckListCopy, new Random(AllZone.getQuestData().getRandomSeed())); + + return deckListCopy.get(number); + } + + + /** + *

generateBattles.

+ * Generates an array of new opponents based on current win conditions. + * + * @return an array of {@link java.lang.String} objects. + */ + public static String[] generateBattles() { + int index = AllZone.getQuestData().getDifficultyIndex(); + + if (AllZone.getQuestData().getWin() < QuestPreferences.getWinsForMediumAI(index)) { + return new String[]{ + getOpponent(easyAIDecks, 0), + getOpponent(easyAIDecks, 1), + getOpponent(easyAIDecks, 2)}; + } + + if (AllZone.getQuestData().getWin() == QuestPreferences.getWinsForMediumAI(index)) { + return new String[]{ + getOpponent(easyAIDecks, 0), + getOpponent(mediumAIDecks, 0), + getOpponent(mediumAIDecks, 1)}; + } + + if (AllZone.getQuestData().getWin() < QuestPreferences.getWinsForHardAI(index)) { + return new String[]{ + getOpponent(mediumAIDecks, 0), + getOpponent(mediumAIDecks, 1), + getOpponent(mediumAIDecks, 2)}; + } + + if (AllZone.getQuestData().getWin() == QuestPreferences.getWinsForHardAI(index)) { + return new String[]{ + getOpponent(mediumAIDecks, 0), + getOpponent(hardAIDecks, 0), + getOpponent(hardAIDecks, 1)}; + } + + if (AllZone.getQuestData().getWin() >= QuestPreferences.getWinsForVeryHardAI(index)) { + return new String[]{ + getOpponent(hardAIDecks, 0), + getOpponent(hardAIDecks, 1), + getOpponent(veryHardAIDecks, 0)}; + } + + return new String[]{ + getOpponent(hardAIDecks, 0), + getOpponent(hardAIDecks, 1), + getOpponent(hardAIDecks, 2)}; + } // End generateBattles() + + /** + *

readFile.

+ * A reader util for accessing the AI deck list text files. + * + * @param file a {@link java.io.File} object. + * @param aiDecks a {@link java.util.List} object. + * @return a {@link java.util.List} object. + */ + private static List readFile(File file, List aiDecks) { + ArrayList list = FileUtil.readFile(file); + + //remove any blank lines + ArrayList noBlankLines = new ArrayList(); + String s; + for (String aList : list) { + s = aList.trim(); + if (!s.equals("")) { + noBlankLines.add(s); + } + } + list = noBlankLines; + + if (list.size() < 3) { + ErrorViewer.showError(new Exception(), + "QuestData : readFile() error, file %s is too short, it must contain at least 3 ai deck names", + file); + } + + for (String aList : list) { + if (!aiDecks.contains(aList)) { + aiDecks.add(aList); + } + } + + return list; + } + + /** + *

getBattles.

+ * + * Returns list of DeckSingleBattle objects storing data + * of the battles currently available. + * + * @return a {@link java.util.List} object. + */ + public static List getBattles() { + List battlesAvailable = new ArrayList(); + + String[] oppDecks = ManagerBattle.generateBattles(); + + for (String oppDeckName : oppDecks) { + battlesAvailable.add(new DeckSingleBattle(getAIDeckFromFile(oppDeckName))); + } + + return battlesAvailable; + } + +} diff --git a/src/main/java/forge/quest/data/ManagerQuest.java b/src/main/java/forge/quest/data/ManagerQuest.java new file mode 100644 index 00000000000..68c6d45bbbf --- /dev/null +++ b/src/main/java/forge/quest/data/ManagerQuest.java @@ -0,0 +1,104 @@ +package forge.quest.data; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import forge.AllZone; +import forge.deck.Deck; +import forge.deck.DeckManager; +import forge.properties.ForgeProps; +import forge.properties.NewConstants; + + +/** + *

ManagerQuest

+ * MODEL - Provides static methods to work with quest-related tasks. + * + */ + +// This could be combined with BattleManager and moved into QuestUtil? +public class ManagerQuest { + /** + *

getQuests

+ * + * Returns list of DeckSingleQuest objects storing data + * of the quests currently available. + * + * @return a {@link java.util.List} object. + */ + + public static List getQuests() { + QuestData questData = AllZone.getQuestData(); + + List idsCompleted = questData.getCompletedQuests(); + List idsAvailable = new ArrayList(); + List allQuests = new ArrayList(); + List questsAvailable = new ArrayList(); + + // Generate DeckSingleQuest objects for available quest IDs. + // If there are quests IDs available, use them. + if (questData.getAvailableQuests() != null && questData.getAvailableQuests().size() > 0) { + idsAvailable = questData.getAvailableQuests(); + for (int id : idsAvailable) { + questsAvailable.add(new DeckSingleQuest(getAIDeckFromFile("quest"+id))); + } + } + // Otherwise, re-generate list. + // To do this, each quest file must be opened and metadata examined. + // DeckSingleQuest objects are grabbed directly from opened list. + else { + File[] files = ForgeProps.getFile(NewConstants.QUEST.DECKS).listFiles(); + + for(File f : files) { + if(!f.isDirectory() && f.getName().substring(0,5).equals("quest")) { + DeckSingleQuest temp = new DeckSingleQuest(getAIDeckFromFile( + f.getName().substring(0, f.getName().lastIndexOf('.')))); + + idsAvailable.add(temp.getID()); + if (temp.getNumberWinsRequired() <= questData.getWin() && + !idsCompleted.contains(temp.getID())) { + allQuests.add(temp); + } + } + } + + // Limit available IDs. + int maxQuests = questData.getWin() / 10; + if (maxQuests > 5) { + maxQuests = 5; + } + if (idsAvailable.size() < maxQuests) { + maxQuests = idsAvailable.size(); + } + + Collections.shuffle(idsAvailable); + idsAvailable = idsAvailable.subList(0,maxQuests); + + questData.setAvailableQuests(idsAvailable); + questData.saveData(); + + for (int id : idsAvailable) { + questsAvailable.add(allQuests.get(id)); + } + } + + return questsAvailable; + } + + + /** + *

getDeckFromFile.

+ * Returns a deck object built from a file name. + * Req'd because NewConstants.QUEST.DECKS must be used. + * + * @param deckName a {@link java.lang.String} object. + * @return a {@link forge.deck.Deck} object. + */ + public static Deck getAIDeckFromFile(String deckName) { + final File file = ForgeProps.getFile(NewConstants.QUEST.DECKS); + final DeckManager manager = new DeckManager(file); + return manager.getDeck(deckName); + } +} diff --git a/src/main/java/forge/quest/gui/PanelSingleBattle.java b/src/main/java/forge/quest/gui/PanelSingleBattle.java new file mode 100644 index 00000000000..02b8b18ef2b --- /dev/null +++ b/src/main/java/forge/quest/gui/PanelSingleBattle.java @@ -0,0 +1,100 @@ +package forge.quest.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; + +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; + +import forge.gui.GuiUtils; +import forge.gui.SelectablePanel; +import forge.quest.data.DeckSingleBattle; + +/** + *

PanelSingleBattle

+ * VIEW - A selectable panel for battles available in Quest mode. + * + */ +@SuppressWarnings("serial") +public class PanelSingleBattle extends SelectablePanel { + + private final DeckSingleBattle battle; + + public PanelSingleBattle(DeckSingleBattle b) { + battle = b; + final JPanel centerPanel = new JPanel(); + + this.setLayout(new BorderLayout(5, 5)); + + // Icon stuff + JLabel iconLabel; + + if (battle.getIcon() == null) { + iconLabel = new JLabel(GuiUtils.getEmptyIcon(40, 40)); + } else { + iconLabel = new JLabel(GuiUtils.getResizedIcon(battle.getIcon(), 40, 40)); + } + + iconLabel.setBorder(new LineBorder(Color.BLACK)); + iconLabel.setAlignmentY(TOP_ALIGNMENT); + + JPanel iconPanel = new JPanel(new BorderLayout()); + iconPanel.setOpaque(false); + iconPanel.add(iconLabel, BorderLayout.NORTH); + this.add(iconPanel, BorderLayout.WEST); + + centerPanel.setOpaque(false); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); + this.add(centerPanel, BorderLayout.CENTER); + + JPanel centerTopPanel = new JPanel(); + centerTopPanel.setOpaque(false); + centerTopPanel.setAlignmentX(LEFT_ALIGNMENT); + centerTopPanel.setLayout(new BoxLayout(centerTopPanel, BoxLayout.X_AXIS)); + + JLabel nameLabel = new JLabel(battle.getDisplayName()); + GuiUtils.setFontSize(nameLabel, 20); + nameLabel.setAlignmentY(BOTTOM_ALIGNMENT); + centerTopPanel.add(nameLabel); + + GuiUtils.addExpandingHorizontalSpace(centerTopPanel); + + JLabel difficultyLabel = new JLabel(battle.getDifficulty()); + difficultyLabel.setAlignmentY(BOTTOM_ALIGNMENT); + centerTopPanel.add(difficultyLabel); + centerPanel.add(centerTopPanel); + + GuiUtils.addGap(centerPanel); + + JLabel descriptionLabel = new JLabel(battle.getDescription()); + descriptionLabel.setAlignmentX(LEFT_ALIGNMENT); + centerPanel.add(descriptionLabel); + + this.setMaximumSize(new Dimension(Integer.MAX_VALUE, 80)); + this.setBorder(new CompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(5, 5, 5, 5))); + } + + /** + *

getIconFilename()

+ * Retrieves filename of icon used in this panel's display. + * + * @return + */ + public String getIconFilename() { + return this.battle.getIconFilename(); + } + + /** + *

getQuest()

+ * + * @return the DeckSingleBattle model associated with this panel. + */ + public DeckSingleBattle getBattle() { + return this.battle; + } +} diff --git a/src/main/java/forge/quest/gui/PanelSingleQuest.java b/src/main/java/forge/quest/gui/PanelSingleQuest.java new file mode 100644 index 00000000000..b4f119ca457 --- /dev/null +++ b/src/main/java/forge/quest/gui/PanelSingleQuest.java @@ -0,0 +1,110 @@ +package forge.quest.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; + +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; + +import forge.gui.GuiUtils; +import forge.gui.SelectablePanel; +import forge.quest.data.DeckSingleQuest; + +/** + *

PanelSingleQuest

+ * VIEW - A selectable panel for quests available in Quest mode. + * + */ +@SuppressWarnings("serial") +public class PanelSingleQuest extends SelectablePanel { + + private final DeckSingleQuest quest; + + public PanelSingleQuest(DeckSingleQuest q) { + quest = q; + final JPanel centerPanel = new JPanel(); + + this.setLayout(new BorderLayout(5, 5)); + + JLabel iconLabel; + + if (quest.getIcon() == null) { + iconLabel = new JLabel(GuiUtils.getEmptyIcon(40, 40)); + } else { + iconLabel = new JLabel(GuiUtils.getResizedIcon(quest.getIcon(), 40, 40)); + } + + iconLabel.setBorder(new LineBorder(Color.BLACK)); + iconLabel.setAlignmentY(TOP_ALIGNMENT); + + JPanel iconPanel = new JPanel(new BorderLayout()); + iconPanel.setOpaque(false); + iconPanel.add(iconLabel, BorderLayout.NORTH); + this.add(iconPanel, BorderLayout.WEST); + + centerPanel.setOpaque(false); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); + this.add(centerPanel, BorderLayout.CENTER); + + JPanel centerTopPanel = new JPanel(); + centerTopPanel.setOpaque(false); + centerTopPanel.setAlignmentX(LEFT_ALIGNMENT); + centerTopPanel.setLayout(new BoxLayout(centerTopPanel, BoxLayout.X_AXIS)); + + JLabel nameLabel = new JLabel(quest.getDisplayName()); + GuiUtils.setFontSize(nameLabel, 20); + nameLabel.setAlignmentY(BOTTOM_ALIGNMENT); + centerTopPanel.add(nameLabel); + + GuiUtils.addExpandingHorizontalSpace(centerTopPanel); + + JLabel difficultyLabel = new JLabel(quest.getDifficulty()); + difficultyLabel.setAlignmentY(BOTTOM_ALIGNMENT); + centerTopPanel.add(difficultyLabel); + centerPanel.add(centerTopPanel); + + GuiUtils.addGap(centerPanel); + + JLabel descriptionLabel = new JLabel(quest.getDescription()); + descriptionLabel.setAlignmentX(LEFT_ALIGNMENT); + centerPanel.add(descriptionLabel); + + // Temporarily removed; no meaning yet (all quests repeat anyway) + /*JLabel repeatabilityLabel; + if (quest.getRepeatable()) { + repeatabilityLabel = new JLabel("This quest is repeatable"); + } else { + repeatabilityLabel = new JLabel("This quest is not repeatable"); + } + + GuiUtils.addGap(centerPanel); + centerPanel.add(repeatabilityLabel);*/ + + this.setMaximumSize(new Dimension(Integer.MAX_VALUE, 80)); + this.setBorder(new CompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(5, 5, 5, 5))); + } + + /** + *

getIconFilename()

+ * Retrieves filename of icon used in this panel's display. + * + * @return + */ + public String getIconFilename() { + return this.quest.getIconFilename(); + } + + /** + *

getQuest()

+ * + * @return the DeckSingleQuest model associated with this panel. + */ + public DeckSingleQuest getQuest() { + return this.quest; + } +} diff --git a/src/main/java/forge/quest/gui/QuestFrame.java b/src/main/java/forge/quest/gui/QuestFrame.java index d72750139ce..0fad3534028 100644 --- a/src/main/java/forge/quest/gui/QuestFrame.java +++ b/src/main/java/forge/quest/gui/QuestFrame.java @@ -3,7 +3,6 @@ package forge.quest.gui; import forge.AllZone; import forge.gui.GuiUtils; import forge.quest.gui.bazaar.QuestBazaarPanel; -import forge.quest.gui.main.QuestMainPanel; import forge.view.swing.OldGuiNewGame; import javax.swing.*; diff --git a/src/main/java/forge/quest/gui/QuestMainPanel.java b/src/main/java/forge/quest/gui/QuestMainPanel.java new file mode 100644 index 00000000000..a945f8d2897 --- /dev/null +++ b/src/main/java/forge/quest/gui/QuestMainPanel.java @@ -0,0 +1,817 @@ +package forge.quest.gui; + + +import forge.*; +import forge.deck.Deck; +import forge.gui.GuiUtils; +import forge.gui.SelectablePanel; +import forge.quest.data.DeckSingleBattle; +import forge.quest.data.ManagerBattle; +import forge.quest.data.QuestData; +import forge.quest.data.DeckSingleQuest; +import forge.quest.data.ManagerQuest; +import forge.quest.data.item.QuestItemZeppelin; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.border.EtchedBorder; +import javax.swing.border.TitledBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.*; +import java.util.List; + + +/** + *

QuestMainPanel class.

+ * VIEW - handler for main screen of Quest GUI. + * + * @author Forge + * @version $Id$ + */ +public class QuestMainPanel extends QuestAbstractPanel { + /** Constant serialVersionUID=6142934729724012402L */ + private static final long serialVersionUID = 6142934729724012402L; + + private forge.quest.data.QuestData questData; + + JLabel creditsLabel = new JLabel(); + JLabel lifeLabel = new JLabel(); + JLabel statsLabel = new JLabel(); + JLabel titleLabel = new JLabel(); + JLabel nextQuestLabel = new JLabel(); + + JComboBox petComboBox = new JComboBox(); + JComboBox deckComboBox = new JComboBox(); + + JButton questButton = new JButton("Quests"); + JButton playButton = new JButton("Play"); + + private SelectablePanel lastPanelSelected; + + JPanel nextMatchPanel = new JPanel(); + CardLayout nextMatchLayout; + + boolean isShowingQuests = false; + private JCheckBox devModeCheckBox = new JCheckBox("Developer Mode"); + //private JCheckBox newGUICheckbox = new JCheckBox("Use new UI", true); + private JCheckBox smoothLandCheckBox = new JCheckBox("Adjust AI Land"); + private JCheckBox petCheckBox = new JCheckBox("Summon Pet"); + + private JCheckBox plantBox = new JCheckBox("Summon Plant"); + /** Constant NO_DECKS_AVAILABLE="No decks available" */ + private static final String NO_DECKS_AVAILABLE = "No decks available"; + /** Constant BATTLES="Battles" */ + private static final String BATTLES = "Battles"; + /** Constant QUESTS="Quests" */ + private static final String QUESTS = "Quests"; + + //TODO: Make this ordering permanent + /** Constant lastUsedDeck="//TODO: Make this ordering permanent" */ + private static String lastUsedDeck; + private JButton zeppelinButton = new JButton("Launch
Zeppelin", + GuiUtils.getResizedIcon(GuiUtils.getIconFromFile("ZeppelinIcon.png"), 40, 40)); + private JPanel zeppelinPanel = new JPanel(); + + /** + *

Constructor for QuestMainPanel.

+ * + * @param mainFrame a {@link forge.quest.gui.QuestFrame} object. + */ + public QuestMainPanel(QuestFrame mainFrame) { + super(mainFrame); + questData = AllZone.getQuestData(); + + initUI(); + } + + /** + *

initUI.

+ */ + private void initUI() { + refresh(); + this.setLayout(new BorderLayout(5, 5)); + JPanel centerPanel = new JPanel(new BorderLayout()); + this.add(centerPanel, BorderLayout.CENTER); + + JPanel northPanel = createStatusPanel(); + this.add(northPanel, BorderLayout.NORTH); + + JPanel eastPanel = createSidePanel(); + this.add(eastPanel, BorderLayout.EAST); + + JPanel matchSettingsPanel = createMatchSettingsPanel(); + centerPanel.add(matchSettingsPanel, BorderLayout.SOUTH); + + centerPanel.add(nextMatchPanel, BorderLayout.CENTER); + this.setBorder(new EmptyBorder(5, 5, 5, 5)); + + } + + /** + *

createStatusPanel.

+ * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createStatusPanel() { + JPanel northPanel = new JPanel(); + JLabel modeLabel; + JLabel difficultyLabel;//Create labels at the top + titleLabel.setFont(new Font(Font.DIALOG, Font.PLAIN, 28)); + titleLabel.setAlignmentX(LEFT_ALIGNMENT); + northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.Y_AXIS)); + northPanel.add(titleLabel); + + northPanel.add(Box.createVerticalStrut(5)); + + JPanel statusPanel = new JPanel(); + statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.X_AXIS)); + statusPanel.setAlignmentX(LEFT_ALIGNMENT); + + modeLabel = new JLabel(questData.getMode()); + statusPanel.add(modeLabel); + statusPanel.add(Box.createHorizontalGlue()); + + difficultyLabel = new JLabel(questData.getDifficulty()); + statusPanel.add(difficultyLabel); + statusPanel.add(Box.createHorizontalGlue()); + + statusPanel.add(statsLabel); + + northPanel.add(statusPanel); + return northPanel; + } + + /** + *

createSidePanel.

+ * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createSidePanel() { + JPanel panel = new JPanel(); + JPanel optionsPanel; //Create options checkbox list + optionsPanel = createOptionsPanel(); + + List eastComponents = new ArrayList(); + //Create buttons + + JButton mainMenuButton = new JButton("Return to Main Menu"); + mainMenuButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + mainFrame.returnToMainMenu(); + } + }); + eastComponents.add(mainMenuButton); + + JButton cardShopButton = new JButton("Card Shop"); + cardShopButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + QuestMainPanel.this.showCardShop(); + } + }); + eastComponents.add(cardShopButton); + cardShopButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20)); + + JButton bazaarButton = null; + if (questData.getMode().equals(forge.quest.data.QuestData.FANTASY)) { + + bazaarButton = new JButton("Bazaar"); + bazaarButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + QuestMainPanel.this.showBazaar(); + } + }); + eastComponents.add(bazaarButton); + bazaarButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20)); + } + + + questButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + QuestMainPanel.this.toggleBattleQuest(); + } + }); + eastComponents.add(questButton); + questButton.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 18)); + questButton.setPreferredSize(new Dimension(0, 60)); + + + playButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + QuestMainPanel.this.launchGame(); + } + }); + + playButton.setFont(new Font(Font.DIALOG, Font.BOLD, 28)); + playButton.setPreferredSize(new Dimension(0, 100)); + + + eastComponents.add(playButton); + eastComponents.add(optionsPanel); + + GuiUtils.setWidthToMax(eastComponents); + + panel.add(mainMenuButton); + GuiUtils.addGap(panel); + panel.add(optionsPanel); + panel.add(Box.createVerticalGlue()); + panel.add(Box.createVerticalGlue()); + + if (questData.getMode().equals(forge.quest.data.QuestData.FANTASY)) { + panel.add(this.lifeLabel); + this.lifeLabel.setFont(new Font(Font.DIALOG, Font.BOLD, 14)); + this.lifeLabel.setIcon(GuiUtils.getResizedIcon(GuiUtils.getIconFromFile("Life.png"), 30, 30)); + } + + GuiUtils.addGap(panel); + panel.add(this.creditsLabel); + this.creditsLabel.setIcon(GuiUtils.getResizedIcon(GuiUtils.getIconFromFile("CoinStack.png"), 30, 30)); + this.creditsLabel.setFont(new Font(Font.DIALOG, Font.BOLD, 14)); + GuiUtils.addGap(panel, 10); + panel.add(cardShopButton); + + if (questData.getMode().equals(forge.quest.data.QuestData.FANTASY)) { + GuiUtils.addGap(panel); + panel.add(bazaarButton); + } + + panel.add(Box.createVerticalGlue()); + + panel.add(questButton); + this.nextQuestLabel.setFont(new Font(Font.DIALOG, Font.PLAIN, 11)); + panel.add(nextQuestLabel); + GuiUtils.addGap(panel); + + panel.add(playButton); + + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + return panel; + } + + /** + *

createOptionsPanel.

+ * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createOptionsPanel() { + JPanel optionsPanel; + optionsPanel = new JPanel(); + optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS)); + + //optionsPanel.add(this.newGUICheckbox); + optionsPanel.add(Box.createVerticalStrut(5)); + optionsPanel.add(this.smoothLandCheckBox); + optionsPanel.add(Box.createVerticalStrut(5)); + optionsPanel.add(this.devModeCheckBox); + optionsPanel.setBorder(new TitledBorder(new EtchedBorder(), "Options")); + return optionsPanel; + } + + /** + *

createMatchSettingsPanel.

+ * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createMatchSettingsPanel() { + + JPanel matchPanel = new JPanel(); + matchPanel.setLayout(new BoxLayout(matchPanel, BoxLayout.Y_AXIS)); + + JPanel deckPanel = new JPanel(); + deckPanel.setLayout(new BoxLayout(deckPanel, BoxLayout.X_AXIS)); + + JLabel deckLabel = new JLabel("Use Deck"); + deckPanel.add(deckLabel); + GuiUtils.addGap(deckPanel); + + this.deckComboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + playButton.setEnabled(canGameBeLaunched()); + lastUsedDeck = (String) deckComboBox.getSelectedItem(); + } + }); + + deckPanel.add(this.deckComboBox); + GuiUtils.addGap(deckPanel); + + JButton editDeckButton = new JButton("Deck Editor"); + editDeckButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + showDeckEditor(); + } + }); + deckPanel.add(editDeckButton); + deckPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, deckPanel.getPreferredSize().height)); + deckPanel.setAlignmentX(LEFT_ALIGNMENT); + matchPanel.add(deckPanel); + + + GuiUtils.addGap(matchPanel); + + if (questData.getMode().equals(forge.quest.data.QuestData.FANTASY)) { + JPanel fantasyPanel = new JPanel(); + fantasyPanel.setLayout(new BorderLayout()); + + JPanel petPanel = new JPanel(); + petPanel.setLayout(new BoxLayout(petPanel, BoxLayout.X_AXIS)); + + this.petCheckBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + if (petCheckBox.isSelected()) { + questData.getPetManager().setSelectedPet((String) petComboBox.getSelectedItem()); + } else { + questData.getPetManager().setSelectedPet(null); + } + + petComboBox.setEnabled(petCheckBox.isSelected()); + } + }); + + petPanel.add(this.petCheckBox); + GuiUtils.addGap(petPanel); + this.petComboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + if (petCheckBox.isSelected()) { + questData.getPetManager().setSelectedPet((String) petComboBox.getSelectedItem()); + } else { + questData.getPetManager().setSelectedPet(null); + } + } + }); + this.petComboBox.setMaximumSize( + new Dimension(Integer.MAX_VALUE, + (int) this.petCheckBox.getPreferredSize().getHeight())); + petPanel.add(this.petComboBox); + + this.plantBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + questData.getPetManager().usePlant = plantBox.isSelected(); + } + }); + + GuiUtils.addGap(petPanel, 10); + petPanel.add(this.plantBox); + petPanel.setMaximumSize(petPanel.getPreferredSize()); + petPanel.setAlignmentX(LEFT_ALIGNMENT); + + fantasyPanel.add(petPanel, BorderLayout.WEST); + + zeppelinButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + questData.randomizeOpponents(); + refreshNextMatchPanel(); + QuestItemZeppelin zeppelin = (QuestItemZeppelin) questData.getInventory().getItem("Zeppelin"); + zeppelin.setZeppelinUsed(true); + zeppelinButton.setEnabled(false); + } + }); + + zeppelinButton.setMaximumSize(zeppelinButton.getPreferredSize()); + zeppelinPanel.setLayout(new BorderLayout()); + + fantasyPanel.add(zeppelinPanel, BorderLayout.EAST); + fantasyPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + matchPanel.add(fantasyPanel); + } + return matchPanel; + } + + /** + *

createBattlePanel

+ * Returns a JPanel containing PanelSingleBattle instances for each battle. + * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createBattlePanel() { + JPanel pan = new JPanel(); + pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS)); + pan.setBorder(new TitledBorder(new EtchedBorder(), "Available Battles")); + PanelSingleBattle pb; + + List Battles = ManagerBattle.getBattles(); + + for (DeckSingleBattle Battle : Battles) { + pb = new PanelSingleBattle(Battle); + + pan.add(pb); + pb.addMouseListener(new SelectionAdapter(pb)); + + GuiUtils.addGap(pan, 3); + } + + pan.setAlignmentX(LEFT_ALIGNMENT); + + return pan; + } + + /** + *

createQuestPanel.

+ * Returns a JPanel containing PanelSingleQuest instances for each battle. + * + * @return a {@link javax.swing.JPanel} object. + */ + private JPanel createQuestPanel() { + JPanel pan = new JPanel(); + pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS)); + pan.setBorder(new TitledBorder(new EtchedBorder(), "Available Quests")); + PanelSingleQuest pq; + + List Quests = ManagerQuest.getQuests(); + + for (DeckSingleQuest Quest : Quests) { + pq = new PanelSingleQuest(Quest); + + pan.add(pq); + pq.addMouseListener(new SelectionAdapter(pq)); + + GuiUtils.addGap(pan, 3); + } + + pan.setAlignmentX(LEFT_ALIGNMENT); + + return pan; + } + + /** + *

refresh.

+ */ + void refresh() { + AllZone.getQuestData().saveData(); + + devModeCheckBox.setSelected(Constant.Runtime.DevMode[0]); + smoothLandCheckBox.setSelected(Constant.Runtime.Smooth[0]); + //newGUICheckbox.setSelected(OldGuiNewGame.preferences.newGui); + + creditsLabel.setText(" " + questData.getCredits()); + statsLabel.setText(questData.getWin() + " wins / " + questData.getLost() + " losses"); + titleLabel.setText(questData.getRank()); + + //copy lastUsedDeck as removal triggers selection change. + String lastUsedDeck = QuestMainPanel.lastUsedDeck; + deckComboBox.removeAllItems(); + + if (questData.getDeckNames().size() > 0) { + deckComboBox.setEnabled(true); + + List deckNames = new ArrayList(questData.getDeckNames()); + + Collections.sort(deckNames, new Comparator() { + public int compare(String s, String s1) { + return s.compareToIgnoreCase(s1); + } + }); + + if (deckNames.contains(lastUsedDeck)) { + deckNames.remove(lastUsedDeck); + deckNames.add(0, lastUsedDeck); + } + + for (String deckName : deckNames) { + deckComboBox.addItem(deckName); + } + } else { + deckComboBox.addItem(NO_DECKS_AVAILABLE); + deckComboBox.setEnabled(false); + } + deckComboBox.setMinimumSize(new Dimension(150, 0)); + + questButton.setEnabled(nextQuestInWins() == 0); + + playButton.setEnabled(canGameBeLaunched()); + + if (questData.getMode().equals(QuestData.FANTASY)) { + lifeLabel.setText(" " + questData.getLife()); + + petComboBox.removeAllItems(); + + Set petList = questData.getPetManager().getAvailablePetNames(); + + if (petList.size() > 0) { + petComboBox.setEnabled(true); + petCheckBox.setEnabled(true); + for (String aPetList : petList) { + petComboBox.addItem(aPetList); + } + } else { + petComboBox.addItem("No pets available"); + petComboBox.setEnabled(false); + petCheckBox.setEnabled(false); + } + + if (!questData.getPetManager().shouldPetBeUsed()) { + petCheckBox.setSelected(false); + petComboBox.setEnabled(false); + } else { + petCheckBox.setSelected(true); + petComboBox.setSelectedItem(questData.getPetManager().getSelectedPet().getName()); + } + + + this.plantBox.setEnabled(questData.getPetManager().getPlant().getLevel() > 0); + this.plantBox.setSelected(questData.getPetManager().shouldPlantBeUsed()); + + QuestItemZeppelin zeppelin = (QuestItemZeppelin) questData.getInventory().getItem("Zeppelin"); + + if (zeppelin.getLevel() > 0) { + zeppelinPanel.removeAll(); + zeppelinPanel.add(zeppelinButton, BorderLayout.CENTER); + } + + if (!zeppelin.hasBeenUsed()) { + zeppelinButton.setEnabled(true); + } else { + zeppelinButton.setEnabled(false); + } + + + } + + if (nextQuestInWins() > 0) { + nextQuestLabel.setText("Next Quest in " + nextQuestInWins() + " Wins."); + } else { + nextQuestLabel.setText("Next Quest available now."); + } + + nextMatchLayout = new CardLayout(); + + refreshNextMatchPanel(); + } + + /** + *

refreshNextMatchPanel.

+ */ + private void refreshNextMatchPanel() { + nextMatchPanel.removeAll(); + nextMatchLayout = new CardLayout(); + nextMatchPanel.setLayout(nextMatchLayout); + nextMatchPanel.add(createBattlePanel(), BATTLES); + nextMatchPanel.add(createQuestPanel(), QUESTS); + if (isShowingQuests) { + this.nextMatchLayout.show(nextMatchPanel, QUESTS); + } else { + this.nextMatchLayout.show(nextMatchPanel, BATTLES); + } + } + + /** + *

nextQuestInWins.

+ * + * @return a int. + */ + private int nextQuestInWins() { + + // Number of wins was 25, lowereing the number to 20 to help short term questers. + if (questData.getWin() < 20) { + return 20 - questData.getWin(); + } + + // The int mul has been lowered by one, should face special opps more frequently. + int questsPlayed = questData.getQuestsPlayed(); + int mul = 5; + + if (questData.getInventory().hasItem("Zeppelin")) { + mul = 3; + } else if (questData.getInventory().hasItem("Map")) { + mul = 4; + } + + int delta = (questsPlayed * mul) - questData.getWin(); + + return (delta > 0) ? delta : 0; + } + + + /** + *

showDeckEditor.

+ */ + void showDeckEditor() { + Command exit = new Command() { + private static final long serialVersionUID = -5110231879431074581L; + + public void execute() { + //saves all deck data + AllZone.getQuestData().saveData(); + + new QuestFrame(); + } + }; + + Gui_Quest_DeckEditor g = new Gui_Quest_DeckEditor(); + + g.show(exit); + g.setVisible(true); + mainFrame.dispose(); + }//deck editor button + + /** + *

showBazaar.

+ */ + void showBazaar() { + mainFrame.showBazaarPane(); + } + + /** + *

showCardShop.

+ */ + void showCardShop() { + Command exit = new Command() { + private static final long serialVersionUID = 8567193482568076362L; + + public void execute() { + //saves all deck data + AllZone.getQuestData().saveData(); + + new QuestFrame(); + } + }; + + Gui_CardShop g = new Gui_CardShop(questData); + + g.show(exit); + g.setVisible(true); + + this.mainFrame.dispose(); + + }//card shop button + + /** + *

launchGame.

+ */ + private void launchGame() { + //TODO: This is a temporary hack to see if the image cache affects the heap usage significantly. + ImageCache.clear(); + + QuestItemZeppelin zeppelin = (QuestItemZeppelin) questData.getInventory().getItem("Zeppelin"); + zeppelin.setZeppelinUsed(false); + questData.randomizeOpponents(); + + String humanDeckName = (String) deckComboBox.getSelectedItem(); + Deck humanDeck = questData.getDeck(humanDeckName); + Constant.Runtime.HumanDeck[0] = humanDeck; + moveDeckToTop(humanDeckName); + + Constant.Quest.oppIconName[0] = getMatchIcon(); + + // Dev Mode occurs before Display + Constant.Runtime.DevMode[0] = devModeCheckBox.isSelected(); + + //DO NOT CHANGE THIS ORDER, GuiDisplay needs to be created before cards are added + //if (newGUICheckbox.isSelected()) { + AllZone.setDisplay(new GuiDisplay4()); + //} else { + // AllZone.setDisplay(new GuiDisplay3()); + //} + + //OldGuiNewGame.preferences.newGui = newGUICheckbox.isSelected(); + + Constant.Runtime.Smooth[0] = smoothLandCheckBox.isSelected(); + + AllZone.getMatchState().reset(); + if (isShowingQuests) { + setupQuest(humanDeck); + } else { + setupBattle(humanDeck); + } + + AllZone.getQuestData().saveData(); + + AllZone.getDisplay().setVisible(true); + mainFrame.dispose(); + } + + + /** + *

setupBattle.

+ * + * @param humanDeck a {@link forge.deck.Deck} object. + */ + void setupBattle(Deck humanDeck) { + Deck computer = ((PanelSingleBattle) lastPanelSelected).getBattle().getDeck(); + Constant.Runtime.ComputerDeck[0] = computer; + + AllZone.getGameAction().newGame(humanDeck, computer, forge.quest.data.QuestUtil.getHumanExtraCards(questData), + new CardList(), questData.getLife(), 20, null); + } + + /** + *

setupQuest.

+ * + * @param humanDeck a {@link forge.deck.Deck} object. + */ + private void setupQuest(Deck humanDeck) { + DeckSingleQuest selectedQuest = ((PanelSingleQuest) lastPanelSelected).getQuest(); + AllZone.setCurrentQuest(selectedQuest); + + Deck computerDeck = ManagerBattle.getAIDeckFromFile("quest" + selectedQuest.getID()); + Constant.Runtime.ComputerDeck[0] = computerDeck; + + int extraLife = 0; + + if (questData.getInventory().getItemLevel("Gear") == 2) { + extraLife = 3; + } + + AllZone.getGameAction().newGame(humanDeck, computerDeck, + forge.quest.data.QuestUtil.getHumanExtraCards(questData, selectedQuest), new CardList(), + questData.getLife() + extraLife, selectedQuest.getAILife(), selectedQuest); + + } + + /** + *

getMatchIcon.

+ * + * @return a {@link java.lang.String} object. + */ + String getMatchIcon() { + String oppIconName; + + if (isShowingQuests) { + PanelSingleQuest selectedQuest = (PanelSingleQuest) lastPanelSelected; + oppIconName = selectedQuest.getIconFilename(); + } else { + PanelSingleBattle selectedBattle = (PanelSingleBattle) lastPanelSelected; + oppIconName = selectedBattle.getIconFilename(); + } + return oppIconName; + } + + /** + *

toggleBattleQuest.

+ * Toggles view between battle and quest screen. + */ + void toggleBattleQuest() { + if (isShowingQuests) { + isShowingQuests = false; + questButton.setText("Quests"); + } else { + isShowingQuests = true; + questButton.setText("Battles"); + } + + if (lastPanelSelected != null) { + lastPanelSelected.setSelected(false); + } + + lastPanelSelected = null; + + refresh(); + } + + /** + *

SelectionAdapter

+ * Handles (de)selection of various SelectablePanel instances using lastPanelSelected field. + * Also toggles launch button after (de)selection. + * + */ + class SelectionAdapter extends MouseAdapter { + SelectablePanel targetPanel; + + SelectionAdapter(SelectablePanel sp) { + super(); + this.targetPanel = sp; + } + + @Override + public void mouseClicked(MouseEvent mouseEvent) { + // Deselect previous + if (lastPanelSelected != null) { + lastPanelSelected.setSelected(false); + } + + targetPanel.setSelected(true); + + lastPanelSelected = targetPanel; + playButton.setEnabled(canGameBeLaunched()); + } + + } + + /** + *

moveDeckToTop.

+ * + * @param humanDeckName a {@link java.lang.String} object. + */ + private void moveDeckToTop(String humanDeckName) { + QuestMainPanel.lastUsedDeck = humanDeckName; + } + + + /** + *

canGameBeLaunched.

+ * + * @return a boolean. + */ + boolean canGameBeLaunched() { + return !(NO_DECKS_AVAILABLE.equals(deckComboBox.getSelectedItem()) || lastPanelSelected == null); + } + + /** {@inheritDoc} */ + @Override + public void refreshState() { + this.refresh(); + } + +} diff --git a/src/test/java/forge/ReadQuestAssignmentTest.java b/src/test/java/forge/ReadQuestAssignmentTest.java deleted file mode 100644 index 9e426d40bbd..00000000000 --- a/src/test/java/forge/ReadQuestAssignmentTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package forge; - -import forge.error.ErrorViewer; -import forge.properties.ForgeProps; -import forge.properties.NewConstants; -import org.testng.annotations.Test; - -/** - * Created by IntelliJ IDEA. - * User: dhudson - */ -@Test(groups = {"UnitTest"}, timeOut = 1000) -public class ReadQuestAssignmentTest implements NewConstants { - /** - * - * - */ - @Test(groups = {"UnitTest", "fast"}, timeOut = 1000) - public void ReadQuestAssignmentTest1() { - try { - ReadQuest_Assignment read = new ReadQuest_Assignment(ForgeProps.getFile(QUEST.QUESTS), null); - - javax.swing.SwingUtilities.invokeAndWait(read); - // read.run(); - - Quest_Assignment qa[] = new Quest_Assignment[read.allQuests.size()]; - read.allQuests.toArray(qa); - for (int i = 0; i < qa.length; i++) { - System.out.println(qa[i].getId()); - System.out.println(qa[i].getName()); - System.out.println(qa[i].getDesc()); - System.out.println(qa[i].getDifficulty()); - System.out.println(qa[i].isRepeatable()); - System.out.println(qa[i].getRequiredNumberWins()); - } - } catch (Exception ex) { - ErrorViewer.showError(ex); - System.out.println("Error reading file " + ex); - } - } -}