Compare commits

..

698 Commits

Author SHA1 Message Date
Chris
fe9ff2f4f9 [maven-release-plugin] prepare release forge-1.5.8 2013-12-27 17:42:15 +00:00
Chris
bf05d850fb Preparing the changes.txt file for the next beta build and release. 2013-12-27 17:29:36 +00:00
Chris
266cbd5dde Added new card names to changes.txt. 2013-12-27 17:26:08 +00:00
swordshine
e222c0f7a9 - Added Pools of Becoming 2013-12-27 12:59:31 +00:00
swordshine
12e80be6d1 - Fix NewGame trigger not working 2013-12-27 12:31:21 +00:00
swordshine
5efb2c2e40 - Fixed DigEffect 2013-12-27 11:34:05 +00:00
swordshine
2e574caac6 - Another fix to avoid overriding 2013-12-27 10:32:07 +00:00
swordshine
74b7a40763 -Fixed Selesnya Loft Gardens 2013-12-27 10:30:32 +00:00
Maxmtg
1ede72b64a ai cost decisions now use visitors 2013-12-27 09:26:39 +00:00
Maxmtg
c45fe42129 prerequisites to pay costs using visitor pattern (to remove AI decision-making and gui-specific inputs from the concrete cost classes) 2013-12-27 08:42:44 +00:00
drdev
ddaffcf7a5 Prevent glitchy dialog on Linux
Transition more message/confirm dialogs to skinned look
2013-12-27 05:59:29 +00:00
swordshine
0d28620ee3 - Fixed a typo in Journey of Discovery 2013-12-27 00:28:23 +00:00
Chris
bbab149d3c Added new card names to changes.txt. 2013-12-26 14:36:00 +00:00
Maxmtg
d4e193f39a ensure that limited games won't pop the AI cannot play cards window 2013-12-26 07:25:16 +00:00
swordshine
bd4dd064be - BNG: Added Kiora, the Crashing Wave 2013-12-26 05:47:19 +00:00
Agetian
2efb70e3b5 - Stupid NetBeans space/tab settings were broken again, fixing. 2013-12-26 05:33:47 +00:00
Agetian
92668c3a2a - Adding an AI profile property for cheat shuffling (to be used soon). 2013-12-26 05:31:31 +00:00
Agetian
3915c3ac2c - Fix the dialog window popping up about unplayable cards in the AI deck in Sealed Deck, Booster Draft, and Quest modes. 2013-12-26 05:22:46 +00:00
Chris
51e521fbb3 Added new card names to changes.txt. 2013-12-25 15:03:12 +00:00
Maxmtg
a81a666b81 move haunt Ai to a separate file
remove isComputer method
2013-12-25 08:21:25 +00:00
swordshine
69a9f0fe43 - Added Plunge into Darkness 2013-12-25 08:14:19 +00:00
Maxmtg
9262ad4d82 make newGame method private, non-static 2013-12-25 08:07:33 +00:00
Maxmtg
b6270a71bb dissolve gameNew, move ai cheating to that very class, improve ante messages
remove lose by milling option
2013-12-25 08:03:20 +00:00
Maxmtg
e31d2ae0d1 fix proliferate not working on creatures 2013-12-25 05:49:00 +00:00
Maxmtg
77510ac6e3 arrange inputs hierarchy 2013-12-25 05:42:49 +00:00
swordshine
0f1e88bb25 - Converted Amplify to replacement effects 2013-12-25 04:50:26 +00:00
swordshine
c5a42f03e6 - Update more scripts 2013-12-25 04:07:37 +00:00
swordshine
de1124c19e - Update 3 scripts 2013-12-25 00:33:58 +00:00
drdev
60ba4bfec6 Add back FDialog custom paint code 2013-12-24 19:06:10 +00:00
drdev
6372242b0b Temporarily comment out FDialog custom paint code 2013-12-24 19:05:17 +00:00
drdev
9a8c4a1c8c Make Left/Right/Home/End keys shift focus as expected between buttons in FOptionPanes 2013-12-24 18:50:09 +00:00
drdev
891db98700 Close FDialogs when Escape key pressed 2013-12-24 18:38:11 +00:00
drdev
f7d1b73a6c Move setShape call from paint to resize listener rather to hopefully fix Linux issue
Make FDialog border non-rounded if setShape isn't supported (Mac)
2013-12-24 18:11:09 +00:00
swordshine
7a906fdc03 - Update more scripts 2013-12-24 13:21:40 +00:00
swordshine
e7046c9bf5 - Update more scripts 2013-12-24 10:54:44 +00:00
swordshine
8d87b0256b - Update more scripts 2013-12-24 10:30:26 +00:00
Maxmtg
802aa167a9 Added input to select both players and cards for tokens created by Hero of Bladehold 2013-12-24 09:23:14 +00:00
swordshine
b83bd41716 - Update more scripts 2013-12-24 07:06:01 +00:00
swordshine
7c8cb3053a - Update more scripts 2013-12-24 06:24:29 +00:00
swordshine
7c9fb9f6b4 - Update some scripts 2013-12-24 05:21:11 +00:00
swordshine
68989d3e31 - Cleanup 2013-12-24 02:08:18 +00:00
swordshine
51a0745348 - Refactored Entwine ability 2013-12-24 02:06:22 +00:00
drdev
3505a2bcd5 Add FOptionPane
Make FDialog title use skinned font
2013-12-23 23:05:17 +00:00
drdev
0581a5e42b Fix Mac FDialog crash properly 2013-12-23 21:16:40 +00:00
drdev
7ea839334c Fix setShape issue without try/catch block 2013-12-23 17:06:39 +00:00
drdev
be7cce4300 Prevent FDialog crashing on Mac. 2013-12-23 16:46:03 +00:00
drdev
c78251a90e Improve appearance of FDialogs
Make CardListViewer use FDialog and display on screen
2013-12-23 10:45:31 +00:00
Maxmtg
c3c8fd7186 improve random choice of N cards
remove gui calls from choosePile effect
2013-12-23 09:05:50 +00:00
drdev
3d97768f71 Code cleanup 2013-12-23 04:52:08 +00:00
swordshine
f2c93cb5dd - Fixed Maelstrom Nexus and similar cards 2013-12-23 04:37:59 +00:00
drdev
689ef0cf8a Make selection after adding/removing cards from deck behave as expected and improve performance of adding multiple cards at once
Support Ctrl+F in Current Deck pane
Prevent losing multi-selection when using Left/Right arrow keys to switch focus between Catalog and Deck
2013-12-23 03:03:33 +00:00
swordshine
77de4abfd1 - Fixed Battalion Triggers check requirements when resolving 2013-12-23 02:58:10 +00:00
Maxmtg
dc16b75c94 minimize need to player type checks 2013-12-22 23:13:07 +00:00
Maxmtg
3a0fdb4d4f remove gui calls from untap 2013-12-22 22:50:01 +00:00
Maxmtg
32b0f8333d remove calls to gui from game code 2013-12-22 22:36:36 +00:00
drdev
446dfd2257 Add +/- buttons to Deck Editor Quantity column 2013-12-22 20:43:11 +00:00
drdev
faa9947974 Fix so tooltips don't always appear for all columns of table 2013-12-22 19:09:33 +00:00
drdev
c75971e8c5 Get favorites feature working again 2013-12-22 18:20:36 +00:00
Maxmtg
2c850cbe53 clash - gui call replaced by gameAction.notifyOfValue
proliferate - single executor for human and AI, chooseProliferation method added to PlayerController
2013-12-22 18:04:00 +00:00
Chris
a060f5f322 Added new card names to changes.txt. 2013-12-22 15:00:26 +00:00
Maxmtg
5367811a33 moved card prefrences to gui 2013-12-22 13:08:28 +00:00
Maxmtg
7d41ae1331 revert unwanted "preferences" from game-core.
remove gui calls
2013-12-22 13:06:27 +00:00
swordshine
f55abfa576 - Added Tariff 2013-12-22 13:03:31 +00:00
drdev
79b8340b80 Fix bug with sort priorities getting messed up 2013-12-22 10:21:53 +00:00
drdev
e0b7034f97 Fix so favorites appear on top by default when column first clicked 2013-12-22 10:03:57 +00:00
drdev
b79876c959 Support hiding Favorite column from Editor Preferences pane 2013-12-22 09:39:00 +00:00
drdev
e159c25f6d Improve appearance of star icons 2013-12-22 09:07:47 +00:00
drdev
d16eedd1b3 Update CHANGES.txt to mention Deck Editor usability improvements 2013-12-22 08:41:08 +00:00
drdev
a062d61c8d Support marking cards as favorites in catalog 2013-12-22 08:39:20 +00:00
drdev
471e5b5399 Support mana icons 13, 14, 17, 18, 19
Reorganize a couple mana symbols in skin
2013-12-21 22:29:27 +00:00
drdev
577f94a67f Fix firebloom and simpsons mana icons 2013-12-21 22:01:29 +00:00
drdev
f7e05491da Prevent 16/17 mana cost icons being cut off 2013-12-21 21:56:09 +00:00
drdev
2771b4fe1f Fix mana cost rendering in table
Start favorites column
2013-12-21 19:43:52 +00:00
Sol
b5830fac6e - Command Tower taps for Controller Commander's CI, not the owners. 2013-12-21 17:34:25 +00:00
drdev
d8511c92c0 Fix so Pack and Multicolor filter buttons work correctly when only they are toggled off 2013-12-21 17:33:30 +00:00
Sloth
1ea41edd6a - Added the hard quest opponent Abe Sapien 3. 2013-12-21 07:28:38 +00:00
swordshine
4f79f92940 - Converted Sphinx of Jwar Isle to script 2013-12-21 03:16:16 +00:00
swordshine
e13865a966 - Converted "You may discard CARDNAME any time you could cast an instant." to script 2013-12-21 01:08:36 +00:00
Maxmtg
05e1161632 this should prevent some NPE 2013-12-20 20:40:33 +00:00
Sloth
feae947742 - Fixed Tsabo's Decree. 2013-12-20 16:13:44 +00:00
Sloth
9ef69149ee - Fixed preventRunAwayActivations to work with temporary abilities.
- AI updates and code cleanup.
2013-12-20 15:45:27 +00:00
Chris
04ca668807 dded new card names to changes.txt. 2013-12-20 14:46:42 +00:00
Sloth
489af75669 - Updated the quest deck Optimus Prime 3. 2013-12-20 14:44:19 +00:00
swordshine
c8e1aff861 - Update mana replacements in ComputerUtilMana 2013-12-20 08:49:00 +00:00
Maxmtg
373bcd0351 commit 24000 FTW! (remove gui calls from untap) 2013-12-20 08:40:08 +00:00
swordshine
c08e984e35 - Added Hall of Gemstone 2013-12-20 08:06:33 +00:00
drdev
5dee59e8e5 Make Pack stat label appear in color and cmc filters too so each toggle button filter has the same button count and works the same way when left clicking other filters. 2013-12-20 04:57:04 +00:00
drdev
350dbeb12f Add back Pack filter button to Spell Shop 2013-12-20 03:35:32 +00:00
swordshine
fdc2eb66aa - Added Scrambleverse 2013-12-20 00:33:16 +00:00
Maxmtg
ef332e4568 move HumanPlay, PlayerControllerHuman to forge.gui.player package 2013-12-20 00:22:20 +00:00
Maxmtg
93c7d28714 moved limited play to a different package (since they don't belong to game module) 2013-12-19 23:17:04 +00:00
Maxmtg
5d8225f041 eliminate gui calls 2013-12-19 23:15:32 +00:00
Maxmtg
b501c76f7c some more gui calls gone 2013-12-19 23:03:28 +00:00
Maxmtg
97526110d0 removing direct references from game to gui 2013-12-19 22:20:28 +00:00
drdev
f8a4c5db92 Fix Statistics tooltips 2013-12-19 06:22:00 +00:00
drdev
2093d23e24 Add Card CMC toggle button filters
Enhance Filters menu to support adding Color and Type filters
2013-12-19 06:14:49 +00:00
drdev
7e32b752a0 Refactor ItemTable into ItemListView and ItemView base class
Add combo box for selecting view
2013-12-19 04:29:59 +00:00
Sloth
4b02708bb0 - Updated the Sherlock Holmes quest decks. 2013-12-18 15:47:50 +00:00
Chris
9684d69bd1 Added new card names to changes.txt. 2013-12-18 15:07:57 +00:00
swordshine
f6d07944d8 - Converted TokenDoubler to script 2013-12-18 11:38:07 +00:00
swordshine
46796041c7 - Added Primal Vigor 2013-12-18 10:33:44 +00:00
swordshine
196a782f8c - Update 3 scripts 2013-12-18 05:25:41 +00:00
swordshine
4839d05b70 - Update two scripts 2013-12-18 04:27:09 +00:00
drdev
d8b6140692 Refactor previous fix 2013-12-17 22:14:17 +00:00
Sloth
040e51f124 - Fixed two scripts missing a nonToken restriction. 2013-12-17 22:11:07 +00:00
drdev
a24161db2b Support search for non-card items in SpellShop 2013-12-17 21:42:21 +00:00
drdev
117501c511 Fix SpellShop item manager to not crash and support filtering 2013-12-17 21:21:35 +00:00
moomarc
1c122b99e9 - Fixed Rotted Ones Lay Siege 2013-12-17 10:24:15 +00:00
drdev
6970c1e7cf Fix ratio in Current Deck item manager
Add captions before ratios in item managers
Fix padding around header in Current Deck pane
2013-12-16 19:28:33 +00:00
drdev
d56cecdba4 Integrate filters into ItemManager 2013-12-16 09:10:40 +00:00
Sloth
8ebf514dab - Fixed possible NPE in ChooseSourceAi. 2013-12-15 22:36:14 +00:00
Sol
1376f0dde2 - Fixing mana symbols for a few devotion cards 2013-12-15 16:50:42 +00:00
Sloth
dbacf597da - Updated some quest decks. 2013-12-15 11:17:58 +00:00
Sloth
87eaf96fa1 - Fixed Reparations triggering on creatures not on the battlefield. 2013-12-14 21:21:09 +00:00
Sloth
13db59aac8 - Fixed possible source for NPE's in RemoveFromCombatEffect. 2013-12-14 20:56:21 +00:00
Sol
9a46768de6 - Starke is already removed from combat by the GainControl code, and whatever he's destroying should be removed by the destruction code. 2013-12-14 19:02:50 +00:00
Chris
3c5010cebf Cleared out the changes.txt file, now ready for new material. 2013-12-14 15:35:37 +00:00
Sloth
d25b197c09 - Fixed Legion's Initiative. 2013-12-14 07:52:54 +00:00
Chris
b892cfa029 [maven-release-plugin] prepare for next development iteration 2013-12-13 15:54:18 +00:00
Chris
23a012364b [maven-release-plugin] prepare release forge-1.5.7 2013-12-13 15:54:07 +00:00
Chris
ed0f3600f5 Preparing the changes.txt file for the next beta build and release. 2013-12-13 15:39:28 +00:00
drdev
dd4e250432 Fix compilation problem 2013-12-13 08:05:42 +00:00
drdev
2ffb71e053 Code cleanup 2013-12-13 08:04:36 +00:00
Maxmtg
be25cf699c removed input play or draw (for being a special case of InputConfirm)
added optional param to chooseCreatureType
2013-12-13 07:51:27 +00:00
drdev
1cc15fe50c Update CHANGES.txt 2013-12-13 07:40:21 +00:00
drdev
a04e5c1da2 Skin FDialog 2013-12-13 07:29:55 +00:00
Maxmtg
5b18ba9058 Cost.chooseXValue moved to member of CostPart 2013-12-13 07:10:23 +00:00
Maxmtg
753f4d989b renamed InputYesOrNo, removed static methods from it, added a method to confirmPayment to PlayerController 2013-12-13 07:01:30 +00:00
Maxmtg
8960fa20c3 added showAndWait method to InputSyncronizedBase - it holds the long chain of calls to reach Control's input queue. 2013-12-13 06:25:55 +00:00
drdev
38344027ca Show cost payment prompts during ability resolve using Prompt pane instead of a dialog 2013-12-13 06:17:03 +00:00
drdev
90ff1abab8 Code cleanup 2013-12-13 05:48:35 +00:00
drdev
7fe3799ea6 Code cleanup 2013-12-13 05:19:09 +00:00
drdev
5ed6fba085 Code cleanup 2013-12-13 05:04:27 +00:00
drdev
6c3573d854 Use Prompt pane instead of dialogs for cost-related questions 2013-12-13 04:48:31 +00:00
drdev
d00aeffbda Add static "ask" API to InputYesOrNo 2013-12-13 03:07:15 +00:00
drdev
e247b8e368 Update CHANGES.txt 2013-12-13 02:40:36 +00:00
drdev
3d54fd3b7b Prompt Yes or No for optional triggered abilities using Prompt pane rather than dialog 2013-12-13 02:37:09 +00:00
drdev
b19b5daf48 Refactor confirmTrigger into controller class 2013-12-13 02:02:54 +00:00
drdev
f48952aa94 Added notes to CHANGES.txt 2013-12-13 01:06:37 +00:00
drdev
e8d4433bb3 Tweak follow up logic after auto payment 2013-12-13 00:59:45 +00:00
drdev
84b0e17572 Fix so you're still prompted for a color when paying cards that care what colors are spent to cast them 2013-12-12 14:53:17 +00:00
drdev
e4ba6f56dd Fix so GUI thread not locked while waiting for Auto payment 2013-12-12 12:57:08 +00:00
drdev
bdfd2e9adf Avoid prompting for color when using "Add one mana of any color" effect to pay for a colorless cost 2013-12-12 12:43:50 +00:00
drdev
849655cb2f Fix so Auto payment occurs in Game thread 2013-12-12 11:49:50 +00:00
swordshine
1c391a7c7e - Fixed Varolz 2013-12-12 11:36:41 +00:00
Sloth
cf1990ddf7 - Fixed Ragged Veins. 2013-12-11 15:04:35 +00:00
drdev
fad3ea497d Code cleanup 2013-12-11 04:05:17 +00:00
drdev
f586525a61 Ensure index in hand zone updated when card drag dropped into new position 2013-12-10 16:27:11 +00:00
Chris
832a290778 Added new card names to changes.txt. 2013-12-10 13:26:11 +00:00
swordshine
ecbba9f1c0 - Added Sheltering Ancient 2013-12-10 13:10:32 +00:00
drdev
afeb4eb815 Fix so canceled spells return to same place in your hand as they were cast from 2013-12-10 02:50:24 +00:00
drdev
d0b5e78f7a Code cleanup 2013-12-10 01:13:34 +00:00
drdev
1837234650 Revert change that prevented a spell moving on the stack until after prerequisites were met 2013-12-10 00:24:21 +00:00
drdev
c65031ea31 Avoid removing source card from lists 2013-12-10 00:17:46 +00:00
Chris
14a7176325 Added a new piece to the Known Issues section. 2013-12-09 19:23:32 +00:00
swordshine
a0c3a1eb05 - Clones are able to copy LevelUp abilities 2013-12-09 04:03:02 +00:00
drdev
f7af3865b7 Allow canceling discarding cards to pay cost 2013-12-09 00:03:18 +00:00
drdev
51a0c08042 Prevent card exiled to pay its own additional cost 2013-12-08 23:47:53 +00:00
drdev
abc2118a77 Code cleanup 2013-12-08 23:18:40 +00:00
drdev
776ac3ee2b Prevent card discarded to pay its own additional cost 2013-12-08 23:12:07 +00:00
drdev
63eaec8348 Code cleanup 2013-12-08 22:50:59 +00:00
drdev
ddb8464c1c Code cleanup 2013-12-08 22:22:44 +00:00
drdev
29ef7a7d3b Code cleanup 2013-12-08 22:14:19 +00:00
drdev
49aa0cc459 Code cleanup 2013-12-08 22:10:03 +00:00
drdev
cdf1b44cb0 Check static abilities when adding card to zone from nowhere (such as using Dev tools) 2013-12-08 18:47:31 +00:00
drdev
61fe9f2282 Code cleanup 2013-12-08 17:49:49 +00:00
Maxmtg
0b9d254e12 fix NPE caused by null predicate 2013-12-07 23:12:37 +00:00
Maxmtg
77b241eb68 remove another toString method from manacost, update references to use better ways 2013-12-07 22:18:52 +00:00
Sloth
b98ae5844c - Fixed type of Stern Judge. 2013-12-07 21:28:45 +00:00
drdev
507ce6f220 Ensure OK button gets initial focus in DualListBox if remainingSources matches source list count 2013-12-07 20:08:03 +00:00
drdev
4d2a27f7e8 Prevent adding cards in DualListBox using spacebar if add button disabled
Prevent selecting cards to discard with Abandon Hope if 0 cards should have been allowed
2013-12-07 19:54:57 +00:00
drdev
a90841a6b6 Fix conditions under which Auto button enabled on DualListBox 2013-12-07 19:39:33 +00:00
drdev
e9bb6e42f6 Prevent adding cards in DualListBox once specific target reached 2013-12-07 19:30:42 +00:00
drdev
ed4b11d9ef Prevent focusing OK button if DualListBox has no specified count needed 2013-12-07 19:10:16 +00:00
drdev
c115f01edf Fix so OK button in DualListBox gets focus when it becomes enabled 2013-12-07 18:52:10 +00:00
drdev
8fd6bbef3b Code cleanup 2013-12-07 18:29:49 +00:00
drdev
8fa68731d1 Fix so mana refunded when using Auto to pay non-X cost then canceling at X prompt 2013-12-07 18:25:29 +00:00
drdev
b6b586a865 Make {X} appear before generic on card overlays 2013-12-07 17:38:52 +00:00
Chris
457ba444f1 Added new card names to changes.txt. 2013-12-07 14:36:10 +00:00
Sloth
31a367c434 - Added Praetor creature type. 2013-12-07 09:43:13 +00:00
swordshine
e83eb92948 - Added Fight or Flight 2013-12-07 01:50:02 +00:00
Sloth
5ee779846d - Fixed 2 more LKI problems. 2013-12-06 17:11:54 +00:00
Sloth
7a3ecf8e38 - Fixed LKI problems with Mercy Killing and similar cards. 2013-12-06 17:06:12 +00:00
Chris
9e2c96a18e Minor change to the changes.txt file. 2013-12-06 15:23:43 +00:00
Sloth
6550fa28ca - Fixed a bug in DamagePreventAi. 2013-12-06 14:47:30 +00:00
drdev
de9ce7ebb9 Mention recent game play usability improvements in CHANGES.txt 2013-12-06 07:26:54 +00:00
drdev
caae78b6ee Add basic Undo support for untapping mana sources that were tapped when not paying an active mana cost 2013-12-06 07:16:04 +00:00
Maxmtg
495701c46c tap-untap effect is indifferent to playertype 2013-12-06 06:46:24 +00:00
Maxmtg
ed99ce1694 remove gui calls from add/remove counters effects 2013-12-06 06:26:49 +00:00
Maxmtg
51a37e896d move counters no longer uses gui 2013-12-06 06:10:51 +00:00
Maxmtg
b431315e88 removed some gui calls 2013-12-06 05:49:11 +00:00
drdev
ea59f120da Prevent cards disappearing from your hand while paying for them or picking targets 2013-12-06 05:11:36 +00:00
drdev
9bd30e8d5d Code cleanup 2013-12-06 04:37:39 +00:00
drdev
39d1ef7e13 Add Escape as shortcut for Cancel in Prompt even if OK button has focus 2013-12-06 04:24:49 +00:00
drdev
83a1b70efe Ensure game ends if you concede while in the middle of playing a spell/ability 2013-12-05 02:26:06 +00:00
drdev
01b4f803a8 Code cleanup 2013-12-05 02:25:19 +00:00
drdev
5c31890066 Code cleanup 2013-12-05 02:02:34 +00:00
drdev
be7f4e5192 Code cleanup 2013-12-05 01:37:35 +00:00
drdev
4124c45875 Code cleanup 2013-12-05 01:18:28 +00:00
drdev
06e785c75a Code cleanup 2013-12-05 01:10:32 +00:00
drdev
2f384c079c Code cleanup 2013-12-05 00:56:57 +00:00
drdev
e4adada542 Code cleanup 2013-12-05 00:50:42 +00:00
drdev
efa86891cc Code cleanup 2013-12-05 00:38:04 +00:00
drdev
bcc20bb774 Return focus to OK button when returning to match screen 2013-12-05 00:31:41 +00:00
drdev
937a095209 Make runAsAi private 2013-12-05 00:14:06 +00:00
Maxmtg
1661228168 fix npe in PlayerControllerHuman 2013-12-04 21:28:11 +00:00
Chris
b17b9eb4e1 Added new card names to changes.txt. 2013-12-04 13:31:37 +00:00
Maxmtg
2ffa1510ed Player belongs to game, it cannot have references to any concrete PlayerController 2013-12-04 07:46:30 +00:00
swordshine
d1ef107b48 - Added Chorus of the Conclave 2013-12-04 07:05:50 +00:00
drdev
aa48e9cacc Fix so Ok button in DualListBox dialog receives focus as soon as it's been enabled so spacebar will activate it 2013-12-04 03:44:32 +00:00
drdev
3c0bfa7843 Remove extra blank line before "Pay Mana Cost" with optional payment prompt 2013-12-04 02:58:54 +00:00
drdev
803b6331f4 Fix so abilities using InputPayManaExecuteCommands work with Auto button 2013-12-04 02:49:26 +00:00
drdev
fe8af8705d Fix crash when determining if mana costs can be paid for SpellAbilities with no source card 2013-12-04 01:51:44 +00:00
drdev
624365cda3 Prevent AI taking over if exception thrown while AI controller temporarily set 2013-12-04 01:33:42 +00:00
Maxmtg
4fb59b6071 give spelldescriptions to card that offer 'generic' choices 2013-12-03 09:04:09 +00:00
Maxmtg
d15948e44b remove refs to gui and playertype in ChooseGenericEffect 2013-12-03 08:48:19 +00:00
Maxmtg
bf629ff518 choose color now uses player controller to decide.
removed calls to gui from ability executing classes
adjust visibility of CardFace methods
2013-12-03 08:27:44 +00:00
Maxmtg
ee9ee7f207 moved evaluator away from core 2013-12-03 06:56:13 +00:00
Maxmtg
311d4091ff remove runAsAi from playercontroller (it's meant to be indifferent to playercontrollers, and PlayerControllers descendants don't know of thier siblings' existance) 2013-12-03 06:34:29 +00:00
Sol
4e79f508c0 - Fixed issue with formatted mana being used for level up cost 2013-12-03 04:19:31 +00:00
swordshine
90828e6eab - Fixed a bug related to Commander games 2013-12-03 00:58:35 +00:00
Chris
7d3afc35cc Added a fluff piece to the changes.txt file.
Added new card names to changes.txt.
2013-12-02 14:58:46 +00:00
swordshine
6f4c046732 - Added Mana braces for three cards 2013-12-02 13:05:56 +00:00
swordshine
503a8da70f - Added Caller of the Hunt 2013-12-02 12:24:43 +00:00
drdev
1cf9a005d9 Fix places that assumed old format of ManaCost.toString() to either call new getCostString() function or assume {G} formatting
This fixes bugs with Rout ("may cast as instance if you pay 2 more" cards)
This also fixes bugs with Rune Snag ("unless player pays X" cards)
2013-12-02 08:52:30 +00:00
drdev
fe04d56568 Code cleanup 2013-12-02 07:31:12 +00:00
drdev
93b6ac15dd Ensure enters the battlefield triggered abilities are visible on stack 2013-12-02 07:06:50 +00:00
drdev
500632515c Mention Auto button and other game usability improvements in CHANGES.txt 2013-12-02 06:15:26 +00:00
drdev
598d2da9d6 Prevent mana not deducting from pool when manually paying mana costs 2013-12-02 05:56:18 +00:00
drdev
05f7a9b30a Prevent being prompted to decide how to pay mana when clicking Auto by temporarily using AI controller 2013-12-02 05:33:44 +00:00
drdev
0b6be04428 Add "Auto" button for automatically paying a mana cost
Code cleanup
2013-12-02 03:07:19 +00:00
Sol
dcb9553807 - Added Mana braces for Level up Ability and Insidious Bookworms 2013-12-02 01:03:38 +00:00
Chris
c9c9be68b1 Added new card names to changes.txt. 2013-12-01 13:50:11 +00:00
swordshine
53e6671143 - Added Call to Arms 2013-12-01 05:34:21 +00:00
drdev
3d063d8188 Code cleanup and refactoring 2013-12-01 03:50:47 +00:00
drdev
8d3633fe63 Code cleanup 2013-12-01 03:27:17 +00:00
drdev
ee7d64c533 Code cleanup 2013-12-01 03:24:22 +00:00
drdev
5009ebe0ab Code cleanup 2013-12-01 03:21:51 +00:00
drdev
9b2f3f3108 Tweak fix for not prompting if can't attack 2013-12-01 03:14:19 +00:00
drdev
9ca9dc797e Don't prompt to declare blockers if no creatures can block 2013-11-30 22:01:04 +00:00
drdev
2ffc18cc89 Skip combat phases if player has no creatures that can attack 2013-11-30 20:57:30 +00:00
drdev
cfeeda3c93 Cleanup whitespace 2013-11-30 18:50:17 +00:00
drdev
a2277bc2d4 Cleanup whitespace 2013-11-30 18:40:40 +00:00
drdev
694e4e7988 Fix misspelling 2013-11-30 18:39:28 +00:00
drdev
1c0e786489 Code cleanup 2013-11-30 18:31:18 +00:00
drdev
7420e94876 Rename CMessage to CPrompt to better match tab caption 2013-11-30 18:19:22 +00:00
drdev
73c921bb95 Increase contrast between Inactive color and background texture in Journeyman theme 2013-11-30 18:00:13 +00:00
Chris
7a22f4f74a - Added a fluff piece to the changes.txt file.
- Cleared out the changes.txt file, now ready for new material.
2013-11-30 15:15:56 +00:00
drdev
cdb76d344e Fix display of 0 loyalty planeswalker abilities 2013-11-30 07:26:10 +00:00
drdev
6cbded92cb if colorless filtered out ensure phyrexian cards don't appear unless at least one of their colors is selected 2013-11-30 07:04:21 +00:00
drdev
bc032a074c Optimize logic for no cost cards 2013-11-30 06:46:20 +00:00
drdev
89a4afdc08 Prevent cards with no mana cost showing up if they're color is filtered 2013-11-30 06:28:36 +00:00
drdev
be6266d633 Improve filter logic to support showing playable hybrid and phyrexian cards even if filtering out colors present in the card's mana cost that aren't needed to cast it 2013-11-30 05:45:30 +00:00
drdev
705264ba9a Ensure multicolor filter selected after right-clicking a color filter 2013-11-30 00:56:05 +00:00
drdev
a0b181e6fe Don't filter out multicolor cards after right-clicking a color filter 2013-11-30 00:51:09 +00:00
drdev
df50a0a38d Support showing only colorless or multicolor cards 2013-11-30 00:27:47 +00:00
Chris
abd182e17f [maven-release-plugin] prepare for next development iteration 2013-11-29 15:06:44 +00:00
Chris
312c15d824 [maven-release-plugin] prepare release forge-1.5.6 2013-11-29 15:06:32 +00:00
Chris
3f0cdc9b19 - Preparing the changes.txt file for the next beta build and release. 2013-11-29 14:52:38 +00:00
drdev
5d5c42c843 Mention Compact Prompt in CHANGES.txt 2013-11-29 06:57:36 +00:00
drdev
1a8fe19c88 Fix so multi-color cards containing a filtered color no longer show up in catalogs 2013-11-29 06:52:51 +00:00
drdev
7e37495b49 Hide checkbox to enable "Stack Card View" setting which isn't ready yet 2013-11-29 06:23:29 +00:00
drdev
3210f06931 Revert so command zone shown for all game types 2013-11-29 05:08:25 +00:00
drdev
a457ff539d Convert hide prompt header setting into compact prompt setting that also controls font size 2013-11-29 04:51:51 +00:00
drdev
afbcd90ffc Don't switch to Combat pane unless an attacker is declared 2013-11-29 04:37:35 +00:00
Maxmtg
8acdc6c458 fix name card effect 2013-11-29 04:37:23 +00:00
drdev
4ed8f69da1 If switched to Combat pane when combat begins, switch back to previous pane when combat ends 2013-11-29 04:28:05 +00:00
Maxmtg
90fe657da6 refactor: move isCommandZoneNeeded to gameType (java enums are far better than c#'s ones :) 2013-11-29 04:03:20 +00:00
drdev
91fe7b516c Show turn number in prompt message 2013-11-29 03:54:04 +00:00
drdev
e3851e3f1d Reduce padding around Prompt buttons 2013-11-29 03:39:34 +00:00
drdev
301014285f Reduce font size of prompt
Add setting to hide prompt header
2013-11-29 03:33:09 +00:00
drdev
e467f44bf2 Fix so Save and Open dialogs appear over main window 2013-11-29 02:59:22 +00:00
drdev
e8e5ac2ca7 Don't show command zone if game type doesn't need it 2013-11-29 02:51:55 +00:00
drdev
ebb0a4b2bc Mention change to show tabs if multiple on pane in CHANGES.txt 2013-11-28 18:01:50 +00:00
drdev
d21e2666ec Don't hide drag tabs if drag cell has multiple tabs 2013-11-28 17:58:46 +00:00
moomarc
43140b2db3 - Small fix for multiplayer tab labels 2013-11-28 09:02:39 +00:00
Maxmtg
c898e1321f cardreader fix 2013-11-27 07:46:21 +00:00
Maxmtg
4f04cbbcc8 fix hangs when both textfiles and zip are present in cardsfolder 2013-11-26 17:40:30 +00:00
asepetci
f17e857710 updated rankings.txt 2013-11-26 09:01:22 +00:00
drdev
2401b9b1ff Fix display issue with switching away from Game screen then back 2013-11-26 03:31:03 +00:00
drdev
e646ff1d1f Add checkbox to control whether list view or card view for Stack 2013-11-26 01:55:46 +00:00
drdev
9bb800ce43 Start adding card view to Stack, with preference to use current list view 2013-11-26 01:36:42 +00:00
ptx
6859ad2ad9 Some initial game simulation tests 2013-11-25 21:33:24 +00:00
drdev
19152790b2 Prevent dividing by zero when laying out cards 2013-11-24 23:03:51 +00:00
drdev
05751dbe1b Break up files in nonsingleton folder into existing controller and view folders 2013-11-24 21:16:23 +00:00
drdev
f35f6b3edd Cleanup whitespace 2013-11-24 20:56:11 +00:00
Maxmtg
8af7fadbf6 another 2 calls to gui removed 2013-11-24 19:21:30 +00:00
Maxmtg
9190ce038f remove imports of forge.gui from where they are not supposed to be (part 2 of many) 2013-11-24 11:14:51 +00:00
Maxmtg
bda47748f2 remove imports of forge.gui from where they are not supposed to be (part 1 of many) 2013-11-24 10:53:58 +00:00
Maxmtg
96084d7b26 disband forge.card package in gui module 2013-11-24 10:34:45 +00:00
Maxmtg
e96ff73b50 modified spells' canPlayAi, doTrigger and playFromEffect methods used by AI to include aiPlayer as 1st parameter 2013-11-24 10:02:58 +00:00
Hellfish
fcb8c4bdd6 *Fixed Charm of Vigor not having to be bought to be available 2013-11-24 09:44:28 +00:00
Maxmtg
c7c1d2d302 arrange Predicates for CardEdition 2013-11-24 09:35:43 +00:00
Maxmtg
21ea8e377c move card/CardCharacteristics.java to forge.game.card 2013-11-24 09:24:50 +00:00
Maxmtg
e9409d01a6 merged cardfactory into forge.game.card package 2013-11-24 07:17:43 +00:00
Maxmtg
a8c70a903f arrange packages 2013-11-24 07:09:23 +00:00
Maxmtg
c66ca97dfc move game Card class to forge.game.card package to ease further translation to game module 2013-11-24 06:59:42 +00:00
Maxmtg
5b5517ad29 replace TreeMapOfLists with Guava Multimap 2013-11-24 06:45:30 +00:00
drdev
c8de886967 Fix Flash of Insight reminder text 2013-11-23 23:13:54 +00:00
drdev
2ef19583a6 Fix displayed equip cost for M13 ring cycle 2013-11-23 23:06:01 +00:00
drdev
9e0ff5e635 Fix Civic Saber descriptions 2013-11-23 22:54:07 +00:00
drdev
427cef758f Fix Card Detail for Equip and Fortify cards 2013-11-23 22:49:54 +00:00
drdev
1cc1516feb Mention preference to hide reminder text in CHANGES.txt 2013-11-23 21:56:11 +00:00
drdev
daafa3f5c2 Add preference to Hide Reminder Text 2013-11-23 21:55:12 +00:00
drdev
9e20af7603 Cleanup whitespace 2013-11-23 21:37:37 +00:00
Chris
306a160df0 - Added a fluff piece to the changes.txt file. 2013-11-23 14:57:58 +00:00
Hellfish
b5686bcd2f *Removed first attempt code Charm of Vigor code. 2013-11-23 09:43:57 +00:00
Maxmtg
33dd245131 commit empty folders (otherwise eclipse refuses to move files) 2013-11-23 08:46:17 +00:00
Maxmtg
25334c27f1 (minor) remove IZone, rename gameAge to gameStage, remove unused imports 2013-11-23 08:34:14 +00:00
Maxmtg
3f20ebb15b prevent NPE for cases when new card is added 2013-11-23 08:21:49 +00:00
Maxmtg
37849b88e2 clean up core classes 2013-11-23 08:12:40 +00:00
drdev
800b3f8272 Tweak logic for formatting reminder text in italics 2013-11-23 06:39:42 +00:00
drdev
b2ecb3cb52 Mention reminder text formatting in CHANGES.txt 2013-11-23 06:25:27 +00:00
drdev
8a794f2e02 Display reminder text in italics 2013-11-23 06:21:26 +00:00
drdev
3c05e1674f Only show Workshop tab if running in Developer mode (for now) 2013-11-23 06:06:19 +00:00
drdev
a15b3c2a69 More card format fixes 2013-11-23 05:54:25 +00:00
drdev
10c138d64e Format mana batteries and a few other cards 2013-11-23 05:39:42 +00:00
drdev
99d1718498 Tweak formatting on Musician 2013-11-23 05:25:00 +00:00
drdev
515985dead Fix formatting of Volvers and Planar cards 2013-11-23 05:12:53 +00:00
drdev
e30c4532b8 Show regular and variant cards in Workshop 2013-11-23 05:03:07 +00:00
drdev
2ab5f19f79 Fix formatting of a couple cumulative upkeep cards 2013-11-23 04:55:17 +00:00
drdev
f5054558c2 Fix formating of Forecast and other cards 2013-11-23 04:50:31 +00:00
drdev
b726053164 Auto-select first card after doing search if no card otherwise selected 2013-11-23 04:38:34 +00:00
drdev
cc433b6708 Fix so PaperCard for card name doesn't change unless card renamed 2013-11-23 04:19:05 +00:00
drdev
e95e251161 Format mana costs for card scripts 2013-11-23 04:15:06 +00:00
drdev
75edc751f3 Format bestow costs 2013-11-23 03:45:47 +00:00
drdev
b4ba84a0d1 Fix Flash of Insight cost formatting and display {X} before generic cost 2013-11-23 03:29:14 +00:00
drdev
38074a1660 Fix so Card Detail updated when card script saved 2013-11-23 03:11:11 +00:00
drdev
ca5e20b1a9 Fix so rules not replaced when updated 2013-11-23 03:05:28 +00:00
drdev
c4db463338 Support saving script changes again 2013-11-23 02:54:52 +00:00
Maxmtg
34c2cb604f carddb editor will detect cases when rules are changed without rename 2013-11-23 00:11:07 +00:00
Maxmtg
f058e38004 CardRules.reinitializeFromScript 2013-11-23 00:03:51 +00:00
drdev
b38a8b5830 Format flashback cost on Firecat Blitz 2013-11-22 23:46:30 +00:00
drdev
8e76829a27 Format mana costs for Madness, Recover, and Miracle on instants/sorceries 2013-11-22 23:42:38 +00:00
Hellfish
f3bf092898 *Added Quest Item - Charm of Vigor: Let's you play best of 5 games rather than 3. 2013-11-22 23:03:49 +00:00
drdev
4dd2b87538 Rename allScripts hash map 2013-11-22 22:47:24 +00:00
Maxmtg
4d6930e903 prioritize text files over whatever found in zip 2013-11-22 18:10:06 +00:00
Maxmtg
3fecd16efd Have cardStorageReader read both zip and the files folder. There remains a task to replace duplicate cards 2013-11-22 17:09:07 +00:00
Maxmtg
29a535c71a moved CardStorageReader to core project 2013-11-22 16:51:38 +00:00
Maxmtg
3fd72f35df use concurrent map 2013-11-22 16:36:07 +00:00
Maxmtg
bb3d637738 adjust dependencies for CardScriptInfo 2013-11-22 16:32:56 +00:00
jendave
02fe620360 update guava 2013-11-22 09:25:24 +00:00
Hellfish
ebe0e350ff *Constructed defaults to 2 players to match previous behaviour 2013-11-22 05:41:52 +00:00
Sol
6dbe638a59 - Merfolk Seer wasn't displaying mana symbols in trigger cost 2013-11-22 04:42:22 +00:00
drdev
31b5f4181a Support displaying scripts in Workshop again 2013-11-22 03:21:37 +00:00
drdev
72d0cfdbbc Whitespace cleanup 2013-11-22 02:23:53 +00:00
drdev
f934764290 Prevent forge.profile.properties being accidentally committed to SVN 2013-11-22 01:38:33 +00:00
drdev
e28f809a58 Remove forge.profile.properties from SVN 2013-11-22 01:34:41 +00:00
Maxmtg
a88dd00a0d interface to edit cards 2013-11-21 23:37:34 +00:00
Hellfish
5d9de47fd5 *Expanded Constructed to up to 8 players, any amount AI or Human, to match up with the Variant update. 2013-11-21 22:54:30 +00:00
Maxmtg
7add28ad7d propper delete 2013-11-21 22:54:15 +00:00
Maxmtg
17b97aca28 hide some readers, collections and simple enums as nested classes, 2013-11-21 22:53:20 +00:00
Maxmtg
86b422230e added module 'game' 2013-11-21 21:32:49 +00:00
Hellfish
0193671453 *Fixed extra Field/Command/Hand views sticking around when for instance playing a game with 2 players after playing a game with 8 players. 2013-11-21 21:27:27 +00:00
Maxmtg
c4be1b8697 inlined type casts 2013-11-21 21:27:27 +00:00
Maxmtg
52f8880627 minor rearrangements in util package 2013-11-21 21:23:04 +00:00
Hellfish
f537e8cf78 *Prettyfied my previous addition. 2013-11-21 21:10:41 +00:00
Maxmtg
482af12b67 deck generation moved to core 2013-11-21 20:59:18 +00:00
Hellfish
2f85d50778 *Added the ability to specify multiple human (hotseat, of course) players or all AI for all variants 2013-11-21 20:25:14 +00:00
Hellfish
b51663c130 *Undoing Subclipse's mess 2013-11-21 19:46:05 +00:00
Hellfish
7ebc54352e Initial import. 2013-11-21 19:40:06 +00:00
jendave
6703e62823 minor doc fixes 2013-11-21 16:54:34 +00:00
Hellfish
e860e9e1af *"Remove All Counters" in a way that interacts other systems. Fixes Chronozoa + AEther Snap 2013-11-21 07:04:22 +00:00
Sloth
de3303abc9 - More use of activateForCost function. 2013-11-20 22:51:22 +00:00
Hellfish
a0695c08cc *Remove Inbound Tokens at appropriate places if the etb of the same token was replaced. Fixes Chronozoa. 2013-11-20 20:05:02 +00:00
Chris
c5aeb0785e - Cleared out the changes.txt file, now ready for new material.
- Added new card names to changes.txt.
2013-11-20 15:05:11 +00:00
Sloth
21b376848f - More use of activateForCost function. 2013-11-20 14:55:33 +00:00
swordshine
f8fe7e41b4 - Added Liar's Pendulum 2013-11-20 13:00:06 +00:00
Maxmtg
22caa0a408 updated references to org.apache.commons.lang version 2.6 to use version 3 ('cause forge used to import both 2.6 and 3.x versions of the named artifact) 2013-11-20 08:47:06 +00:00
Maxmtg
4d3945f5a4 moved all items to core, decks were included too. 2013-11-20 08:34:37 +00:00
Maxmtg
0786012ed8 rm ColorChanger.java (unused)
mv2core BoosterGenerator and UnOpenedProduct
2013-11-19 22:54:04 +00:00
Maxmtg
6e9a316460 remove UI references from CardStorageReader 2013-11-19 21:53:01 +00:00
Maxmtg
fd7d0e1d99 cleaned CardStorageReader of experimental code 2013-11-19 20:56:59 +00:00
Maxmtg
65199c7a81 moved cardFace and rules reader to core 2013-11-19 20:38:51 +00:00
Sloth
851094c523 - Added a doTriggerAINoCost function to RepeatAI. 2013-11-19 13:15:01 +00:00
Maxmtg
9b31032016 Moved cardDb and most of static data to core project. Had to rollback some incompatible changes. Sorry, drdev! 2013-11-19 07:40:58 +00:00
Sloth
a7fa173e52 - Content downloader will now show the number of item skipped. 2013-11-18 22:11:42 +00:00
Sloth
de4d83372c - Added 2 precons by Erazmus. 2013-11-18 20:59:32 +00:00
Sloth
c7f24490f3 - Some more work on the activateForCost function. 2013-11-18 20:57:25 +00:00
drdev
fabc7a3a27 Support updating card rules and display when saving script changes 2013-11-18 14:35:19 +00:00
swordshine
e830527f74 - Fixed other cards with optional decisions in ChangeZone effect 2013-11-18 12:48:02 +00:00
swordshine
5fc5feb636 - Fixed Cloudstone Curio 2013-11-18 12:41:19 +00:00
drdev
384af0001c Fix cursor positioning after undoing delete 2013-11-17 21:44:02 +00:00
drdev
2abc9b3f7c Create FUndoManager to encapsulate making undo/redo logic smarter and lumping typing changes together 2013-11-17 21:38:27 +00:00
drdev
9242f3439c Create FTextEditor to encapsulate a plain text editor with undo/redo support 2013-11-17 21:17:14 +00:00
drdev
b1ba8f0aa2 Add File menu and support Ctrl+S to save card in Workshop 2013-11-17 20:36:44 +00:00
drdev
20b3775280 Prompt to save card when switching to another card or another screen 2013-11-17 17:57:55 +00:00
drdev
c2bb321e17 Optimize determination of card script text being dirty 2013-11-17 08:33:00 +00:00
drdev
b0160287ba Add Workshop screen 2013-11-17 08:02:40 +00:00
drdev
284e2257f3 Fix Cascade 2013-11-16 21:43:57 +00:00
drdev
ec06d07f35 Breakup PrecostDesc$ of certain Entwine cards so mana cost part in CostDesc$
Make "Choose one" syntax consistent
2013-11-16 20:11:41 +00:00
drdev
5eca8807d8 Format mana costs for Echo, Cumulative Upkeep, and Unearth 2013-11-16 19:25:43 +00:00
drdev
5b3ee63299 Ignore forge-*/target directories for SVN 2013-11-16 19:22:41 +00:00
drdev
a6ffa3ae36 Update card scripts with CostDesc$ so its formatted 2013-11-16 19:17:44 +00:00
Sol
e021e66387 - Fixed Spell Description of MorphDown 2013-11-16 16:02:23 +00:00
Sol
eb70985551 - Fix Viridian Joiner description 2013-11-16 01:23:00 +00:00
Chris
cd6dc5158e [maven-release-plugin] prepare for next development iteration 2013-11-15 14:14:27 +00:00
Chris
942f30557c [maven-release-plugin] prepare release forge-1.5.5 2013-11-15 14:14:16 +00:00
Chris
1486d61e65 - Preparing the changes.txt file for the next beta build and release. 2013-11-15 13:57:23 +00:00
drdev
eb082d2f49 Fix abilities that used "tap" 2013-11-15 12:57:47 +00:00
drdev
7e6e691771 Ensure top of card text visible when first viewed in Card Detail 2013-11-15 12:14:03 +00:00
drdev
8e4962ceb1 Eliminate Card Detail flicker 2013-11-15 12:11:31 +00:00
drdev
414d82bd37 Fix The Tabernacle at Pendrell Vale mana format 2013-11-15 11:38:31 +00:00
drdev
4091f1d1d9 Fix Fleshwriter reminder cost format 2013-11-15 11:36:58 +00:00
drdev
fe0f4ddf99 Format Ninjutsu mana cost in reminder text 2013-11-15 11:34:27 +00:00
drdev
b0845c5795 Commit commented out imperfect code used for parsing ability in quotes 2013-11-15 11:24:44 +00:00
drdev
aeddb37d9d Format ability costs in quotes 2013-11-15 11:22:51 +00:00
drdev
1ff1c35486 Remove bullet in CHANGES.txt that no longer applies 2013-11-15 09:48:11 +00:00
drdev
6e585a7afa For now, if card only has 1 activated ability, don't show menu even if cost is automatic and undoable 2013-11-15 09:47:24 +00:00
Sloth
e0df16ee17 - Fixed AI using Exhume. 2013-11-15 09:42:15 +00:00
drdev
ae5cb7a17a Make ability menu items consistent regardless of containing mana symbol icons and make them respect menu item height 2013-11-15 09:40:47 +00:00
Sloth
8d79ed527f - Fixed a bug in ChooseCardEffect. 2013-11-15 09:37:08 +00:00
Sloth
d4bc84c6bd - Fixed Stormfront Riders. 2013-11-15 09:11:52 +00:00
drdev
9743a7d1b7 Mention fixing WUBRG order in CHANGES.txt 2013-11-15 09:03:48 +00:00
drdev
e5cffc623a Support updating colored mana order, phyrexian and hybrid mana format, and mana production abilities with multiple choices 2013-11-15 06:59:23 +00:00
drdev
9c0a559bce Update hybrid costs in abilities 2013-11-15 06:56:52 +00:00
drdev
b794bc5ee0 Update card ability descriptions containing choice of dual mana production 2013-11-15 06:26:33 +00:00
drdev
55c71d77e1 Fix colored mana order for card scripts 2013-11-15 06:04:12 +00:00
drdev
6914e30443 Fix colored mana order for card scripts 2013-11-15 05:48:47 +00:00
drdev
1c52e8e38a Update card ability descriptions containing choice of mana production 2013-11-15 03:00:09 +00:00
drdev
c38f169d1d Add space between ability description mana cost and reminder text 2013-11-15 00:58:24 +00:00
drdev
8f4b8dbf88 Prevent trimming spaces 2013-11-15 00:51:34 +00:00
drdev
b68f28b621 Update earwig_squad.txt prowl cost 2013-11-15 00:51:01 +00:00
drdev
a23eb2f869 Support outputting results from parse utility 2013-11-15 00:45:49 +00:00
drdev
8dfbf2b3b6 Update more card ability descriptions 2013-11-15 00:14:31 +00:00
drdev
70b0fab66a Use try/catch block to avoid crash from bad pattern 2013-11-14 23:27:08 +00:00
drdev
082e2ff2cd Add parse command line argument to allow performing function on all parsed cards 2013-11-14 23:16:28 +00:00
Sloth
12af50d473 - Update more card ability descriptions. 2013-11-14 22:54:50 +00:00
Sloth
b1cde02dd4 - Update more card ability descriptions with {T} symbol. 2013-11-14 22:22:19 +00:00
jendave
2d737ab092 a little progress on the Mac app bundle 2013-11-14 21:59:44 +00:00
jendave
8cd9220f36 update release plugin. Update site urls for new maven structure. 2013-11-14 17:08:54 +00:00
swordshine
838d4a98aa - Update more scripts 2013-11-14 13:50:40 +00:00
swordshine
d32bfea94e - Fixed Braid of Fire 2013-11-14 13:25:28 +00:00
swordshine
181a7f5b9c - Updated basic land abilities to display mana symbol icons 2013-11-14 10:57:51 +00:00
drdev
ee00b544f7 Support displaying Chaos icon in details 2013-11-14 09:20:29 +00:00
drdev
5548c71bda Update more card ability descriptions 2013-11-14 08:46:01 +00:00
drdev
ae7a6b79b7 Update more card ability descriptions 2013-11-14 08:27:50 +00:00
drdev
96d2338bea Update card ability descriptions so mana symbols are displayed as icons 2013-11-14 07:48:31 +00:00
drdev
21217e030b Code cleanup 2013-11-14 04:42:59 +00:00
drdev
1d63f4b4a1 Update CHANGES.txt 2013-11-14 04:19:34 +00:00
drdev
8843e5bfe7 Properly translate only mana costs to icons
Make snow and certain hybrid mana symbols display correctly
Show mana symbols in game prompt
2013-11-14 04:08:24 +00:00
Sloth
48b97f8632 - Fixed Balduvian Frostwaker. 2013-11-13 22:51:29 +00:00
jendave
20184fb4c0 ignore IntelliJ files 2013-11-12 08:46:35 +00:00
drdev
76000a90fb Update CHANGES.txt 2013-11-12 07:08:52 +00:00
drdev
4aebd350ee Support showing mana symbols in ability menu and card detail pane 2013-11-12 07:06:09 +00:00
Sol
13f4a0abb4 - Adding Enchant opponent line to Psychic Posssesion 2013-11-12 02:19:51 +00:00
drdev
35ea297090 Make target arrows appear in correct place in window mode 2013-11-12 02:15:55 +00:00
drdev
f11909d6da Prevent repeating shortcuts for abilities 2013-11-12 01:57:24 +00:00
jendave
5df82652b6 clean ups 2013-11-11 16:07:37 +00:00
Chris
8fde8ebe5f - Added new card names to changes.txt. 2013-11-11 13:43:52 +00:00
drdev
6bc20a8830 Update CHANGES.txt 2013-11-11 12:48:18 +00:00
drdev
0bbd9c103a Make menu items easier to click
Mention context menu ability select in CHANGES.txt
2013-11-11 12:39:18 +00:00
jendave
0b68e2ade6 re-org 2013-11-11 08:27:14 +00:00
jendave
1ca79539b6 update deps and re-org a few things 2013-11-11 08:27:00 +00:00
drdev
1c2c3d6d51 Ensure first ability selected in menu by default 2013-11-11 02:55:18 +00:00
drdev
bdb1243409 Prevent showing menu if no ability can be played 2013-11-11 02:36:44 +00:00
drdev
812d4ca519 Prevent returning ability that can't be played 2013-11-11 02:22:27 +00:00
swordshine
4e7e14cbf3 - Added Invasion Plans 2013-11-11 00:29:43 +00:00
swordshine
2064b6517e - Temporarily removed Arboria
- Fixed Quicksilver Dragon
2013-11-11 00:22:11 +00:00
drdev
c9f491a483 Show unplayable activated abilities disabled unless activator or zone restriction
Prompt for single activated ability unless mana ability
Show mana abilities before other abilities to match card order
2013-11-10 21:48:55 +00:00
Maxmtg
be2ec80f0c redirect dependency between Card and IPaperCard 2013-11-10 21:37:07 +00:00
drdev
1c13e8dc10 Show context menu to select ability instead of dialog 2013-11-10 20:25:25 +00:00
drdev
4748aa2262 Fix typo in function name 2013-11-10 18:56:41 +00:00
swordshine
a3376b0502 - Added Arboria, Premature Burial, and Sacred Ground 2013-11-10 05:14:26 +00:00
swordshine
c073d39cd6 - Updated scripts 2013-11-10 04:51:16 +00:00
Chris
b508f78f04 Moved the CHANGES.txt, LICENSE.txt, forge.profile.properties.example and README.txt files to forge-gui folder. 2013-11-09 15:33:38 +00:00
Chris
8424da8311 - Added new card names to changes.txt. 2013-11-09 15:17:05 +00:00
swordshine
cfd9d55668 - Added Quicksilver Dragon 2013-11-09 10:01:48 +00:00
swordshine
417e3bb104 - Added Reflecting Mirror 2013-11-09 09:36:45 +00:00
swordshine
320d4f62d9 2013-11-09 08:24:47 +00:00
Maxmtg
6c712d86fb moved a few classes to core module 2013-11-09 02:27:38 +00:00
jendave
a0479f9610 Test run of moving files to modules. 2013-11-08 23:21:11 +00:00
Maxmtg
374a744a44 added java nature to forge-gui project, set up classpath (copied it from former project) 2013-11-08 21:57:20 +00:00
Maxmtg
81416d49de added reference from core to guava, set runtime version of ai and core to 1.7 2013-11-08 21:35:14 +00:00
Sloth
31ebd62c83 - Added more precons by Erazmus. 2013-11-08 20:18:39 +00:00
jendave
93dd4af6ed fix eclipse issues 2013-11-08 18:39:59 +00:00
jendave
9f0308dd66 Start of re-org into modules 2013-11-08 10:05:52 +00:00
Sloth
f9298703d4 - Added some precons by Erazmus. 2013-11-08 08:52:31 +00:00
Sloth
3992032e8e - Added Rebound. 2013-11-07 23:08:44 +00:00
Sloth
58dacc0789 - Added Silver Wyvern. 2013-11-07 22:54:17 +00:00
Chris
b3280923d9 - Added new card names to changes.txt. 2013-11-07 14:49:02 +00:00
Sloth
e83da9ff9c - Some safety fixes for Muck Drubb. 2013-11-07 09:17:48 +00:00
Sloth
8b1d0fc759 - Added Muck Drubb. 2013-11-06 22:45:35 +00:00
Sloth
ff869933be - Cleanup. 2013-11-06 22:15:51 +00:00
Sloth
fb0af4dc18 - Start of using isValid function for SpellAbilities. 2013-11-06 19:39:34 +00:00
Sloth
6f5551d78d - Fixed Razia's Purification. 2013-11-05 22:32:40 +00:00
swordshine
a90efe4939 - Fixed Mirror Strike 2013-11-05 02:37:33 +00:00
Sloth
46c37b9d82 - Updated mtg-data.txt.
- Added Oracle texts to C13 cards.
2013-11-04 21:10:55 +00:00
drdev
3e23eb517b Use FMouseAdapter to make catalog and deck tables more responsive 2013-11-04 03:17:28 +00:00
Sloth
9cf75ea844 - Script fixes and updates. 2013-11-03 22:02:28 +00:00
drdev
5565b4a4d0 Retain column sort direction between sessions 2013-11-03 18:44:14 +00:00
drdev
bde5967ef4 Remember column order in Deck Editor 2013-11-03 17:47:57 +00:00
Chris
f3560238fe - Added new card names to changes.txt. 2013-11-03 13:52:06 +00:00
swordshine
f97f489aba - Added Juxtapose 2013-11-03 13:28:12 +00:00
swordshine
454b7715c0 - Added Scheme: Your Inescapable Doom 2013-11-03 11:46:46 +00:00
swordshine
ac1e279235 - Fixed LibraryPosition 2013-11-03 07:50:02 +00:00
swordshine
5950162663 - Added Johan
- Updated mtgdata
2013-11-03 07:32:08 +00:00
Chris
6a52b46192 - Added a fluff piece to the changes.txt file. 2013-11-02 12:42:27 +00:00
Sloth
f5558eec7f - Updated and fixed some C13 cards. 2013-11-02 07:37:33 +00:00
Chris
0c39f596a3 - Cleared out the changes.txt file, now ready for new material. 2013-11-01 23:09:20 +00:00
Sloth
ba3c544484 - Fixed Saltskitter. 2013-11-01 19:42:54 +00:00
jendave
e0063727a9 update to latest deps and plugins. Did not update to latest jetty and guava since they may cause issues 2013-11-01 16:27:50 +00:00
swordshine
7b68821a8c - Merged C13 Branch
- Fixed Curse of Chaos, Curse of the Forsaken, Fell Shepherd
2013-11-01 14:19:28 +00:00
Chris
4a84b408d4 [maven-release-plugin] prepare for next development iteration 2013-11-01 13:06:01 +00:00
Chris
b9aec4ffb8 [maven-release-plugin] prepare release forge-1.5.4 2013-11-01 13:05:50 +00:00
Chris
1a958e758f - Preparing the changes.txt file for the next beta build and release. 2013-11-01 12:55:46 +00:00
RumbleBBU
74527319aa Relabeled the starting pool color distribution options to make them more intuitive. Merged the randomization option to the pulldown menu. 2013-10-31 09:48:35 +00:00
drdev
a66e7ad14f Add click effect to opague and selectable FLabels to make them feel more like buttons 2013-10-30 14:40:36 +00:00
drdev
e4b91416dd Update DeckLister to use FMouseAdapter 2013-10-30 14:00:37 +00:00
drdev
7735c705c0 Fix so right-clicking stat label that's the only selected one in group will re-select all other labels in group 2013-10-30 13:15:56 +00:00
drdev
31ab48d0d4 Let FMouseAdapter raise click if mouse moved outside component then back inside before releasing mouse 2013-10-30 13:02:44 +00:00
drdev
e5cf9da31d Update FLabel to use new FMouseAdapter 2013-10-30 12:39:10 +00:00
drdev
9eac64ab7b Create FMouseAdapter to facilitate more reliable and responsive click handling
Improve responsiveness of table sorting in ItemManagers
Prevent events on editor tables being duplicated, resulting in poor performance and inverting sort sometimes not working
2013-10-30 12:29:30 +00:00
swordshine
7131cebf7d - Fixed last commit 2013-10-30 04:49:55 +00:00
swordshine
bfb4a5ee57 - Commander 2013 edition file 2013-10-30 03:04:38 +00:00
drdev
21e250bf36 Prevent auto-inverting sort direction when switching away from editor and back 2013-10-28 14:04:31 +00:00
swordshine
f5b1ac970b - Fixed Scroll Thief and Stealer of Secrets 2013-10-28 03:04:36 +00:00
drdev
c85f14f27c Fix crash when taking over another player's turn 2013-10-27 19:14:00 +00:00
drdev
c0cf6198a4 Mention addition of concede confirmation in CHANGES.txt 2013-10-27 06:53:39 +00:00
drdev
4d3012fee7 Ensure Match screen active before showing concede prompt 2013-10-27 06:52:17 +00:00
drdev
75726dc272 Make user confirm that they want to concede the current game 2013-10-27 06:47:20 +00:00
drdev
260724af80 Fix so Match screen uses the correct controller (so correct menus built for example) 2013-10-27 06:33:26 +00:00
drdev
2b37cf217f Updated CHANGES.txt for combo box visual tweaks 2013-10-27 06:23:03 +00:00
drdev
669ff579c5 Fix so combo boxes on Constructed home screen update when skin switched 2013-10-27 06:17:23 +00:00
drdev
d0e65fe1bc Use FComboBox in place of JComboBox 2013-10-27 05:54:22 +00:00
drdev
4485e46801 Remove unused FComboBox properties 2013-10-27 05:27:51 +00:00
drdev
2265687c75 Make combo box be all one piece 2013-10-27 05:12:57 +00:00
drdev
f70523bf14 Update CHANGES.txt for Draft fixes 2013-10-27 03:56:13 +00:00
drdev
48013b9339 Fix a couple more issues with drafting 2013-10-27 03:46:20 +00:00
drdev
e9e1caf9d1 Prevent losing draft picks when switching away and back
Prevent canceling naming draft pool which caused a crash
2013-10-27 03:29:20 +00:00
drdev
5b17e2beda Make it so Draft screen closes when draft process finished and Draft Deck Editor immediately opens 2013-10-27 03:17:45 +00:00
drdev
19bc74f88d Fix a few remaining places that would show prompts outside main window 2013-10-27 02:52:14 +00:00
drdev
ae0069652a Fix switching between Editors 2013-10-26 21:49:26 +00:00
Sloth
5ec7f01b7a - Added the new quest deck Robot Santa 3. 2013-10-26 20:55:39 +00:00
Sloth
691f798f90 - Replaced the interface ITargetable with the class GameObject (which reflects the term used in the rules for players, cards and spell/abilities).
- Preparations for extending isValid and hasProperty functions for spell/abilities.
2013-10-25 21:41:38 +00:00
Chris
d5bef0861b - Added new card names to changes.txt. 2013-10-24 13:27:07 +00:00
swordshine
87dd938cde - Added Graxiplon 2013-10-24 08:54:27 +00:00
Sloth
c4e0d3e7ce - Added Glarecaster. 2013-10-23 21:52:06 +00:00
Sloth
c705722bdc - Updated some AI SVars. 2013-10-23 15:53:08 +00:00
Sloth
6424fa151a - Added a hard version of the Leela quest deck. 2013-10-23 14:04:44 +00:00
swordshine
0646e49359 - Added Scheme: Only Blood Ends Your Nightmares
- Added Cyclopean Tomb
2013-10-23 00:24:38 +00:00
Sloth
6ddae9e9da - Updated some Shandalar world quest decks. 2013-10-22 20:34:41 +00:00
Sloth
efc7be1637 - Fixed face-down cards moving to Hand or Library not being turned face up. 2013-10-22 13:41:16 +00:00
Chris
1de80be872 - Added new card names to changes.txt. 2013-10-22 13:02:54 +00:00
swordshine
f8740f1268 - Updated scripts (Psychogenic Probe should trigger only once for these cards) 2013-10-22 12:19:08 +00:00
swordshine
d6f30c9220 - Added Dichotomancy 2013-10-22 12:02:28 +00:00
swordshine
f2d7004b02 - C13: Added From the Ashes 2013-10-22 11:08:14 +00:00
swordshine
6ecf800bab - Added Seeds of Innocence 2013-10-22 10:23:24 +00:00
Sloth
6f92a834da - Some deck updates. 2013-10-21 21:06:56 +00:00
Sloth
a7a85d22d5 - Added some card specific AI for Serene Master and Shape Stealer. 2013-10-21 20:18:05 +00:00
Sloth
178024e248 - Fixed AI freeze caused by Fireball. 2013-10-21 19:53:04 +00:00
swordshine
798e93af46 - Fixed Opal Palace (using an etbCounter replacement now) 2013-10-21 13:40:36 +00:00
swordshine
3cb125ae4a - C13: Added Opal Palace 2013-10-21 12:12:01 +00:00
swordshine
30aed49e87 - C13: Added Serene Master (please improve AiAttackController.declareAttackers and AiBlockController for this card) 2013-10-21 06:27:48 +00:00
swordshine
d0173a2341 - Fixed r23523 LibraryPosition 2013-10-21 02:56:07 +00:00
drdev
fb7a61ab30 Fix crash when purchasing items in the Bazaar 2013-10-20 23:07:37 +00:00
Sloth
13e09c73bc - Fixed text of Force of Nature. 2013-10-20 07:34:25 +00:00
swordshine
6fdaf4fda4 - C13: Added Tempt with Glory, Tempt with Reflections and Unexpectedly Absent 2013-10-20 05:24:56 +00:00
Chris
ba79089bed - Cleared out the changes.txt file, now ready for new material.
- Added new card names to changes.txt.
2013-10-19 16:22:03 +00:00
Sloth
a8670467be - Fixed Tangle Wire. 2013-10-19 11:26:31 +00:00
swordshine
4dd84cdb2e - C13: Added Naya Soulbeast and Tempt with Discovery 2013-10-19 04:09:38 +00:00
Sol
028d6c0a1f - Using CARDNAME instead of Seasinger for ability stealing cards 2013-10-19 03:36:39 +00:00
swordshine
ca2584f598 - C13: Added Sudden Demise, Tempt with Vengeance, Terra Ravager, Toxic Deluge, Widespread Panic and Witch Hunt 2013-10-19 00:49:33 +00:00
Sol
17e96250f7 - Fix issue with a few Avatars that spawn cards outside of the game not knowing what game they are apart of 2013-10-18 21:48:38 +00:00
Chris
79fdd21817 [maven-release-plugin] prepare for next development iteration 2013-10-18 14:33:15 +00:00
Chris
a0daa7c4be [maven-release-plugin] prepare release forge-1.5.3 2013-10-18 14:33:05 +00:00
Chris
000d0d3119 - Preparing the changes.txt file for the next beta build and release. 2013-10-18 14:21:49 +00:00
Chris
3b01b4f3dd - Added new card names to changes.txt. 2013-10-18 12:54:11 +00:00
swordshine
f0613e9660 - C13: Added Act of Authority and Angel of Finality 2013-10-18 05:43:51 +00:00
Sloth
1c51ed37c2 - Fixed an issue with the "May be played by your opponent" keyword. 2013-10-17 21:18:24 +00:00
Chris
2bfcd92da9 - Added new card names to changes.txt. 2013-10-17 12:50:02 +00:00
RumbleBBU
0bf676448b Fixed a bug that caused the Quest starting pool reduction incorrectly affect randomized starting pools. 2013-10-17 12:43:46 +00:00
RumbleBBU
5bceff414e Bias steepness now reduces the total amount of cards in your Quest starting pool. Effect of steepness slightly increased to compensate for this in your chosen color.
Slightly tweaked and relabeled the UI components for color preference selection, to make them slightly more intuitive.
2013-10-17 10:11:31 +00:00
swordshine
1b65231e30 - C13: Added Illusionist's Gambit and True-Name Nemesis 2013-10-17 05:23:38 +00:00
drdev
8b39b69bb7 Move/rename FControl.Screens to FScreen and make that define the Navigation tab data instead of INavigationTabData
Make it so each Deck Editor type appears in its own tab
Make Bazaar screen act more like other screens
2013-10-17 04:23:48 +00:00
Chris
4dfab45544 - Added new card names to changes.txt. 2013-10-16 12:53:43 +00:00
swordshine
f046dbf3cc - C13: Added Surveyor's Scope 2013-10-16 06:34:58 +00:00
swordshine
2e5f9350eb - Replicate is a trigger now 2013-10-16 00:35:36 +00:00
Sloth
938784d6e8 - Fixed Kiki-Jiki, Mirror Breaker not granting haste to transformed cards. 2013-10-15 13:59:43 +00:00
Chris
02c582a695 - Added new card names to changes.txt. 2013-10-15 13:05:01 +00:00
swordshine
2851d49c3b - C13: Added Eye of Doom 2013-10-15 12:15:33 +00:00
swordshine
e88af1f6ba - Converted Madness 2013-10-15 10:48:32 +00:00
swordshine
da3b6bf19e - Converted Persist/Undying to script (these triggers can be stifled and copied now) 2013-10-15 00:21:23 +00:00
Chris
da28e10ac7 - Added new card names to changes.txt. 2013-10-14 13:42:37 +00:00
swordshine
e6b260cc60 - C13: Added Curse of Chaos 2013-10-14 04:12:40 +00:00
Sloth
2cea9debcf - Added Carom. 2013-10-13 19:26:17 +00:00
swordshine
768a26a5d4 - Converted Tangle Wire to script 2013-10-13 08:33:38 +00:00
swordshine
0e251ffb6a - Converted Drop of Honey and Porphyry Nodes to script 2013-10-13 08:00:44 +00:00
swordshine
74c04ea561 - Cleanup 2013-10-13 07:20:08 +00:00
swordshine
e92cc2735b - Converted Braid of Fire to script 2013-10-13 07:15:59 +00:00
swordshine
6a94535b78 - Converted Intruder Alarm, Smoke and Stoic Angel to script 2013-10-13 05:24:17 +00:00
swordshine
17ad490f97 - Converted Damping Field and Imi Statue to script 2013-10-13 05:07:07 +00:00
swordshine
704e4c4ef7 - Converted Winter Orb and Mungha Wurm to script 2013-10-13 04:57:08 +00:00
Chris
36a301275e - Added new card names to changes.txt. 2013-10-12 20:20:15 +00:00
drdev
bb2a01512e Make disabled close buttons appear disabled
Fix contrast skin colors
2013-10-12 20:17:52 +00:00
Sloth
ad73c9391d - Added the WU Heroic deck Bilbo Baggins 2 with help from Nordos. 2013-10-12 17:13:07 +00:00
swordshine
ce33d146d0 - Converted Land Equilibrium to script 2013-10-12 13:06:37 +00:00
Sloth
055695890e - Cleanup. 2013-10-12 13:02:12 +00:00
swordshine
028579eed4 - Added Protective Sphere 2013-10-12 11:20:54 +00:00
swordshine
5c836228f7 - Added Spellweaver Volute 2013-10-12 05:48:07 +00:00
swordshine
0663eee49a - Added Takklemaggot 2013-10-12 02:38:30 +00:00
dripton
4d9205699b Fix typo in comment 2013-10-11 15:12:52 +00:00
drdev
d8a5993a28 Ensure close buttons disabled along with navigation tabs 2013-10-11 06:11:31 +00:00
drdev
6e7e19fd34 Disable navigation tabs while overlay open 2013-10-11 05:56:22 +00:00
drdev
9e55ee9be1 Improve animation of navigation bar reveal and prevent it being stuck open with auto-hiding 2013-10-11 05:41:06 +00:00
drdev
ae93665645 Fix so remaining dialogs show up on top of Forge, such as sideboard 2013-10-11 01:52:50 +00:00
drdev
7eb84bb6a3 Update tooltip for X button based on current screen and close action 2013-10-11 01:18:39 +00:00
drdev
3006cc9431 Ensure previous game ended when continuing Guantlet 2013-10-11 00:32:22 +00:00
Sloth
480629953b - Fixed Ghoulcaller's Chant. 2013-10-10 21:59:30 +00:00
dripton
c54ed09d38 Add try/catch to hiddenOriginCanPlayAi
If a SpellAbility's origin is something like "Graveyard,Library",
ZoneType.smartValueOf throws an IllegalArgumentException.  Catch
this exception and return false.  This prevents the crash, but
means that the AI still can't play cards like Doomsday.

Fixes bug 745
2013-10-10 14:29:53 +00:00
drdev
a098b56339 Fix typos 2013-10-10 03:19:28 +00:00
drdev
7a9f8d9788 Add setting to control behavior of X button in upper right (Close Screen vs. Exit Forge) 2013-10-10 03:06:05 +00:00
Sloth
7bd822b96a - Fixed human player not being able to activate mana abilities as a spell/ability is played when Mana produced replacement effects are around. 2013-10-09 13:57:59 +00:00
swordshine
d20e9d5629 - Fixed Dark Betrayal 2013-10-09 10:34:20 +00:00
RumbleBBU
9b61a99dc3 Added a preference to adjust color bias steepness when using color-biased Quest starting pools. 2013-10-09 09:49:38 +00:00
drdev
4c1f670147 Set dialog default to Yes when exiting Forge without game active
Ensure Deck Editor visible if and when "Save Changes?" dialog would appear
2013-10-09 05:10:59 +00:00
drdev
c05d299fe4 Always prompt user before exiting or restarting Forge 2013-10-09 04:45:44 +00:00
drdev
0ba8b530fe Fix so quitting Quest games works with tabs
Prevent adding multiple game tabs
2013-10-09 04:33:45 +00:00
drdev
0a6f7afeff Add navigation tab for Bazaar
Prevent arrow button remaining visible when switching to Bazaar from Home screen
2013-10-09 01:56:03 +00:00
Sloth
483f274bac - Fixed my commit r23388. 2013-10-08 21:15:03 +00:00
Chris
1fd36a4623 - Added new card names to changes.txt. 2013-10-08 13:55:52 +00:00
drdev
3b1ab80c1c Add navigation tabs for switching between Home, Deck Editor, and Match screens
Remove Deck Editor and Exit Forge buttons home screen
Exit Forge when X button in upper right clicked
Add safety checks before exit or restart
Show warning if you try to Start a game while one is already active (at least for now)
2013-10-08 13:07:33 +00:00
RumbleBBU
abe0cec346 - Added an experimental UI that allows you to choose a preferred color in new Quest games. Also added a "Balanced color distribution" checkbox that can be unchecked to completely randomize the color distribution in new Quest games.
- Minor checkstyle fixes to old issues in VSubmenuQuestData and CSubmenuQuestData.
2013-10-08 12:32:42 +00:00
spr
6e1e22d6cb - Refactor GamePlayerUtil. 2013-10-08 10:04:32 +00:00
drdev
7650ec9323 Minimize if switching from Full Screen Forge to outside application window 2013-10-08 09:20:47 +00:00
spr
fe3fedaf64 - Renamed "Themed ComboBox" setting to "Enable Themes" to better reflect its purpose. 2013-10-08 07:16:52 +00:00
spr
f21f187890 - Removed redundant Visual Themes section from Game Settings -> Preferences. 2013-10-08 07:10:59 +00:00
spr
41e164d131 - Removed redundant Card Overlay Options section from Game Settings -> Preferences. 2013-10-08 07:04:28 +00:00
drdev
adb6a0b7f0 Fix so Deck Importer and other JDialogs display centered over main Forge window 2013-10-08 02:11:50 +00:00
drdev
31618c1611 Mention dialog fix in CHANGES.txt 2013-10-08 01:25:28 +00:00
drdev
6eba60638b Prevent Full Screen Forge being minimized when deactivated (such as by opening JOptionPane dialog) 2013-10-08 01:15:29 +00:00
drdev
e4040d4a47 Fix so JOptionPane dialogs always display at center of main window by default 2013-10-08 00:43:34 +00:00
drdev
c53cd32291 Fix so, when maximized, Forge doesn't extend below top of taskbar if screen has a top inset 2013-10-07 23:07:42 +00:00
drdev
172ca340ae Disable Forge button and Forge menu shortcut keys while overlay open 2013-10-07 22:53:14 +00:00
drdev
a8451abea4 Delay hiding titlebar a half second after becoming full-screen 2013-10-07 22:26:02 +00:00
drdev
cdf67a3865 Mention fix to Mac minimize crash 2013-10-07 22:05:31 +00:00
Sloth
e2f2fc4804 - Added a medium version of the Hugo Drax deck. 2013-10-07 20:41:08 +00:00
spr
db9a451e32 - Added option to replace default "Human" with custom name during gameplay. (http://www.slightlymagic.net/forum/viewtopic.php?f=52&t=11553). 2013-10-07 19:56:00 +00:00
spr
a8cf682f71 - Added very simple About box to display Forge version. 2013-10-07 19:46:05 +00:00
spr
0c721f1776 - FNavBar tweak - Revealspeed = 200, revealDelay = 100. 2013-10-07 19:39:48 +00:00
Chris
f8194aac7a - Added new card names to changes.txt. 2013-10-07 13:14:57 +00:00
swordshine
15dd60ff3e - Update the script for Chained to the Rocks 2013-10-07 12:45:55 +00:00
drdev
d54441a9b2 Update CHANGES.txt for Full Screen support 2013-10-07 06:59:19 +00:00
drdev
4e75bfb4d0 Remove status bar, instead using tooltips for menu hints
Prevent overlays showing on top of titlebar
2013-10-07 06:52:41 +00:00
drdev
3e350d03c6 If titlebar unlocked or window made full-screen, delay hiding titlebar until mouse moves away 2013-10-07 05:42:10 +00:00
drdev
2fa44e1ae2 Always show Full Screen button right of Minimize button 2013-10-07 05:23:43 +00:00
drdev
1e5244cee0 Only allow titlebar being hidden when in Full Screen mode
Ensure Full Screen window appears on correct monitor
Add buttons to toggle Full Screen and lock/unlock titlebar
Make clock appear in titlebar when Full Screen and hiding status bar
Prevent moving window or double-click restore down when Full Screen
2013-10-07 05:17:27 +00:00
swordshine
6043c2738d - Added Snowblind 2013-10-07 05:09:55 +00:00
drdev
013cf5eb13 Disable Direct3D to improve rendering performance 2013-10-07 02:37:03 +00:00
drdev
a413fe2dc1 Ensure full-screen still works after using Set Window Size when in in Full Screen mode 2013-10-06 16:14:02 +00:00
drdev
a2bf02eb82 Support toggling Full Screen with F11 on all platforms
Fix way window state is updated (minimized/normal/maximized/full screen)
2013-10-06 16:08:29 +00:00
swordshine
229485494a - Update scripts 2013-10-06 11:40:05 +00:00
Hellfish
4ea3439667 *Updated Kederekt Parasite for multiplayer 2013-10-06 09:07:17 +00:00
Sloth
4154d31143 - Fixed possible NPE caused by Haunt. 2013-10-06 08:44:18 +00:00
Hellfish
30b660f802 *Missed a vital piece of the AI commander pay fail fix. 2013-10-06 08:08:39 +00:00
drdev
b79cf45778 Prevent Forge covering up taskbar when maximized 2013-10-05 22:53:47 +00:00
drdev
c6e9cbd69b Skin tooltips 2013-10-05 22:12:51 +00:00
drdev
7e493ed129 Change constants to static 2013-10-05 21:53:40 +00:00
drdev
c3ed6ebe79 Make reveal speed easier to tweak 2013-10-05 21:47:32 +00:00
Hellfish
27e33ec1b1 *Fixed AI failing to pay for recasting commander. 2013-10-05 18:02:42 +00:00
Chris
7601d5a2bd - Cleared out the changes.txt file, now ready for new material.
- Added new card names to changes.txt.
2013-10-05 13:24:12 +00:00
swordshine
a9fb42eb15 - Added Excavator 2013-10-05 11:38:53 +00:00
Sloth
cd9cdbf1be - Added AEtherplasm. 2013-10-05 11:38:33 +00:00
swordshine
e68a716587 - Added Elemental Resonance 2013-10-05 06:49:09 +00:00
swordshine
bab5672669 - Added Charmed Pendant 2013-10-05 06:31:54 +00:00
drdev
80f083e141 Increase speed and responsiveness of titlebar reveal 2013-10-05 00:23:08 +00:00
Sloth
91d37b38cc - Fixed Ghazban Ogre. 2013-10-04 19:55:21 +00:00
Chris
9349fa9217 [maven-release-plugin] prepare for next development iteration 2013-10-04 16:25:23 +00:00
Chris
748523f9cf [maven-release-plugin] prepare release forge-1.5.2 2013-10-04 16:25:13 +00:00
Chris
e64336abe9 - Preparing the changes.txt file for the next beta build and release. 2013-10-04 16:14:56 +00:00
RumbleBBU
15450a7fba - Added supporting infrastructure for manipulating the initial card distribution in new Quest games. The user interface components that actually enable this feature will be added after the next beta.
- Lots of checkstyle fixes to old issues.
2013-10-04 11:52:56 +00:00
drdev
ad2f63cd8f Fix so Forge menu items update from skin change properly 2013-10-04 06:43:41 +00:00
drdev
dbd3d956fb Avoid losing hidden title bar setting when switching to window mode and back to full screen 2013-10-04 06:12:15 +00:00
drdev
aabb4399ed Support temporarily revealing hidden title bar by moving mouse to top of screen 2013-10-04 05:27:18 +00:00
drdev
a99386ac1d Show clock in titlebar if maximized and status bar hidden 2013-10-04 02:43:14 +00:00
Sloth
b400f22d15 - Fixed description of Nest Invader. 2013-10-03 18:12:03 +00:00
moomarc
8843054b89 - New skin added 2013-10-03 16:34:14 +00:00
Sloth
8c8bde0799 - Fixed cost lists not using LKI's (once again). 2013-10-03 11:23:21 +00:00
drdev
109a990b28 Dim status bar text color and fix padding right of clock 2013-10-03 09:26:31 +00:00
drdev
8e9ac2e3e7 Make status bar text look better aligned 2013-10-03 09:05:44 +00:00
drdev
c0ad9b1b71 Update CHANGES.txt for Forge button changes 2013-10-03 08:37:11 +00:00
Maxmtg
01609a1f29 adjusted visibility of listInSync, removed unused import, removed test that does not test draft rankings anyway 2013-10-03 08:26:30 +00:00
drdev
2f5219615d Create Forge button which, when clicked, displays popup menu containing items from old menu bar
Support hiding status bar (F12) and saving title bar and status bar visibility between sessions
Changed F1 to be a shortcut for launching the Forge wiki
2013-10-03 08:26:11 +00:00
spr
91cd93783f - Fix: Constructed home screen "Game" menu was not being cleared from MenuBar when switching to other home screens; Menubar was not being repainted properly; 2013-10-03 08:17:44 +00:00
Maxmtg
2d8e4e9053 removed some (not all) slowdonws in quest card shop when owner of a big collection purchases a fatpack. (there were N redraws of owned card list instead of just one) 2013-10-03 08:06:10 +00:00
swordshine
9500b3a5ae - Updated scripts 2013-10-03 07:37:00 +00:00
swordshine
84e124bbf5 - Updated Cube by Juzamjedi 2013-10-03 07:28:58 +00:00
drdev
0d0377ae4a Remove clock from titlebar 2013-10-03 02:14:25 +00:00
drdev
9e1ec67253 Move version and clock to new status bar 2013-10-03 02:11:03 +00:00
drdev
4f8ee5ea52 Increase height of titlebar and size of minimize, maximize, and close icons
Fix so minimize, maximize, and close buttons allow clicking very top of screen and allow canceling click by moving mouse away before releasing
2013-10-03 00:50:31 +00:00
drdev
56654ffcb1 Cache time formatter 2013-10-03 00:28:55 +00:00
Chris
ac48d3634b fixed 2 broken pic URLs. 2013-10-02 13:45:03 +00:00
spr
934e4cbb2c - Constructed game now remembers the last deck played (both left and right decks) and restores at next startup.
- Default human deck type is Preconstructed decks.
2013-10-02 13:35:09 +00:00
Chris
53e631d65f - Cleared out the changes.txt file, now ready for new material. 2013-10-02 12:47:46 +00:00
swordshine
1483d7c969 - update some SVars 2013-10-02 08:29:48 +00:00
spr
71ddee1033 - Constructed screen updates based on feedback. 2013-10-02 06:54:59 +00:00
Maxmtg
480bba7a8c making multimaps in combat class synchronized 2013-10-01 20:40:28 +00:00
Chris
9c4c529c62 [maven-release-plugin] prepare for next development iteration 2013-10-01 14:22:19 +00:00
15974 changed files with 58686 additions and 45107 deletions

View File

@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>

31264
.gitattributes vendored

File diff suppressed because it is too large Load Diff

26
.gitignore vendored
View File

@@ -2,20 +2,28 @@
/*.iml
/*.tmp
/.metadata
forge-ai/forge-ai.iml
forge-ai/target
forge-core/forge-core.iml
forge-core/target
forge-game/target
forge-gui/forge-gui.iml
forge-gui/forge.profile.properties
forge-gui/res/*.log
forge-gui/res/PerSetTrackingResults
forge-gui/res/cardsfolder/*.bat
forge-gui/res/decks
forge-gui/res/layouts
forge-gui/res/pics*
forge-gui/res/pics_product
forge-gui/target
forge-gui/tools/PerSetTrackingResults
forge-gui/tools/oracleScript.log
/forge.profile.properties
/nbactions.xml
/pom.xml.next
/pom.xml.releaseBackup
/pom.xml.tag
/release.properties
res/*.log
res/PerSetTrackingResults
res/cardsfolder/*.bat
res/decks
res/layouts
res/pics*
res/pics_product
/target
/test-output
tools/PerSetTrackingResults
tools/oracleScript.log

View File

@@ -4,36 +4,7 @@
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
</natures>
</projectDescription>

View File

@@ -1,101 +0,0 @@
Forge Beta: 10-01-2013 ver 1.5.1
13328 cards in total.
-------------
Release Notes
-------------
- Forge freezing during a match bug -
A number of people have reported this bug and we now feel that it may have been fixed in this version. Please play test this version and let us know.
- Skinned titlebar for main window -
Titlebar is now skinned instead of displaying using standard OS window titlebar
Maximizing window now displays full-screen
Can use Layout > View > Titlebar (F11) to toggle visibility of titlebar (will also open full-screen if hiding titlebar)
- Forge now requires Java 7 -
Please update your Java runtime environment. At this point Forge versions 1.4.2 and above will no longer run under Java 6. Those who are using Mac OS should install the JDK version rather than the JRE version.
- The Mac OS X application -
At this time Forge now requires Java 7 and will no longer run under Java 6.
Unfortunately, the Mac OS X builder that we were using does not support Java 7. We hope to find and to use a different Mac OS X builder in order to continue releasing a Mac OS bundled application like we have in the past.
Currently, the windows/unix release of Forge includes a launcher file named "forge.command". Double click on the "forge.command" launcher command file and this will in turn launch the Forge jar file via the terminal application while increasing the Java heap space. This should be a temporary inconvenience.
---------
New Cards
---------
Chaos Moon
Deep Water
Infernal Darkness
Mana Reflection
Mausoleum Turnkey
Naked Singularity
Pale Moon
Pulse of Llanowar
Reality Twist
Ritual of Subdual
-----------
New Schemes
-----------
Nature Demands an Offering
--------------------
New Vanguard Avatars
--------------------
Mirri
------------
Known Issues
------------
Several people have noticed that the cards displayed on the battlefield will fail to be displayed when the number of cards on the battlefield increases. Maximizing the human panel can help to re-display the cards.
Some time was spent turning the static ETB triggers into the proper ETB replacement effects they should be, mainly to interact correctly with each other. This work is not yet finished. As a result there is currently some inconsistencies with "Enters the battlefield with counters" (Not incredibly noticeable).
A recent contribution to the code base should fix some of the bugs that people noticed with cloning type abilities. At this time there is one remaining issue that we hope will be addressed in the near future:
Copies of cards that setup Zone Change triggers via addComesIntoPlayCommand and addLeavesPlayCommand will not function correctly.
The Forge archive includes a readme.txt file and we ask that you spend a few minutes reading this file as it contains some information that may prove useful. We do tend to update this file at times and you should quickly read this file and look for new information for each and every new release. Thank you.
The archive format used for the Forge distribution is ".tar.bz2". There are utilities for Windows, Mac OS and the various *nix's that can be used to extract/decompress these ".tar.bz2" archives. We recommend that you extract/decompress the Forge archive into a new and unused folder.
Some people use the Windows application 7zip. This utility can be found at http://www.7-zip.org/download.html. Mac users can double click on the archive and the application Archive Utility will launch and extract the archive. Mac users do not need to download a separate utility.
----------------------------
Contributors to This Release
----------------------------
DrDev
Dripton
Gos
Hellfish
Max
Sloth
spr
Swordshine
Chris H
(Quest icons used created by Teekatas, from his Legendora set http://raindropmemory.deviantart.com)
(Thanks to the MAGE team for permission to use their targeting arrows.)
(Thanks to http://www.freesound.org/browse/ for providing some sound files.)
end

9
forge-ai/.classpath Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

23
forge-ai/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>forge-ai</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=ISO-8859-1
encoding//src/test/java=ISO-8859-1
encoding/<project>=ISO-8859-1

View File

@@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7

View File

@@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

28
forge-ai/pom.xml Normal file
View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.5.8</version>
</parent>
<artifactId>forge-ai</artifactId>
<name>Forge AI</name>
<dependencies>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>forge</groupId>
<artifactId>forge-game</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -28,7 +28,8 @@ public enum AiProps { /** */
DEFAULT_MIN_TURN_TO_ROLL_PLANAR_DIE ("3"), /** */
DEFAULT_PLANAR_DIE_ROLL_CHANCE ("50"), /** */
MULLIGAN_THRESHOLD ("5"), /** */
PLANAR_DIE_ROLL_HESITATION_CHANCE ("10"); /** */
PLANAR_DIE_ROLL_HESITATION_CHANCE ("10"),
CHEAT_WITH_MANA_ON_SHUFFLE ("FALSE"); /** */
private final String strDefaultVal;

9
forge-core/.classpath Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

23
forge-core/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>forge-core</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=ISO-8859-1
encoding//src/test/java=ISO-8859-1
encoding/<project>=ISO-8859-1

View File

@@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7

View File

@@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

27
forge-core/pom.xml Normal file
View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.5.8</version>
</parent>
<artifactId>forge-core</artifactId>
<name>Forge Core</name>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,375 +1,375 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card.cardfactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.swing.SwingUtilities;
import org.apache.commons.lang.time.StopWatch;
import forge.FThreads;
import forge.card.CardRules;
import forge.card.CardRulesReader;
import forge.error.BugReporter;
import forge.gui.toolbox.FProgressBar;
import forge.util.FileUtil;
/**
* <p>
* CardReader class.
* </p>
*
* @author Forge
* @version $Id$
*/
public class CardStorageReader {
private static final String CARD_FILE_DOT_EXTENSION = ".txt";
/** Default charset when loading from files. */
public static final String DEFAULT_CHARSET_NAME = "US-ASCII";
final private boolean useThreadPool = FThreads.isMultiCoreSystem();
final private int NUMBER_OF_PARTS = 25;
final private CountDownLatch cdl = new CountDownLatch(NUMBER_OF_PARTS);
final private FProgressBar barProgress;
private transient File cardsfolder;
private transient ZipFile zip;
private transient Charset charset;
// 8/18/11 10:56 PM
/**
* <p>
* Constructor for CardReader.
* </p>
*
* @param theCardsFolder
* indicates location of the cardsFolder
* @param useZip
* if true, attempts to load cards from a zip file, if one
* exists.
*/
public CardStorageReader(String cardDataDir, final boolean useZip, FProgressBar barProgress) {
this.barProgress = barProgress;
// These read data for lightweight classes.
File theCardsFolder = new File(cardDataDir);
if (!theCardsFolder.exists()) {
throw new RuntimeException("CardReader : constructor error -- file not found -- filename is "
+ theCardsFolder.getAbsolutePath());
}
if (!theCardsFolder.isDirectory()) {
throw new RuntimeException("CardReader : constructor error -- not a directory -- "
+ theCardsFolder.getAbsolutePath());
}
this.cardsfolder = theCardsFolder;
final File zipFile = new File(theCardsFolder, "cardsfolder.zip");
if (useZip && zipFile.exists()) {
try {
this.zip = new ZipFile(zipFile);
} catch (final Exception exn) {
System.err.printf("Error reading zip file \"%s\": %s. Defaulting to txt files in \"%s\".%n", zipFile.getAbsolutePath(), exn, theCardsFolder.getAbsolutePath());
}
}
this.charset = Charset.forName(CardStorageReader.DEFAULT_CHARSET_NAME);
} // CardReader()
private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) {
CardRulesReader rulesReader = new CardRulesReader();
List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) {
File cardTxtFile = files.get(i);
result.add(this.loadCard(rulesReader, cardTxtFile));
}
return result;
}
private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) {
CardRulesReader rulesReader = new CardRulesReader();
List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) {
ZipEntry ze = files.get(i);
// if (ze.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) // already filtered!
result.add(this.loadCard(rulesReader, ze));
}
return result;
}
/**
* Starts reading cards into memory until the given card is found.
*
* After that, we save our place in the list of cards (on disk) in case we
* need to load more.
*
* @return the Card or null if it was not found.
*/
public final List<CardRules> loadCards() {
if (barProgress != null) {
barProgress.setMaximum(NUMBER_OF_PARTS);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
barProgress.setPercentMode(true);
barProgress.setDescription("Loading card data: ");
}
});
}
final List<Callable<List<CardRules>>> tasks;
long estimatedFilesRemaining;
// Iterate through txt files or zip archive.
// Report relevant numbers to progress monitor model.
if (this.zip == null) {
final List<File> allFiles = new ArrayList<File>();
fillFilesArray(allFiles, this.cardsfolder);
estimatedFilesRemaining = allFiles.size();
tasks = makeTaskListForFiles(allFiles);
} else {
estimatedFilesRemaining = this.zip.size();
ZipEntry entry;
List<ZipEntry> entries = new ArrayList<ZipEntry>();
// zipEnum was initialized in the constructor.
Enumeration<? extends ZipEntry> zipEnum = this.zip.entries();
while (zipEnum.hasMoreElements()) {
entry = zipEnum.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
continue;
entries.add(entry);
}
tasks = makeTaskListForZip(entries);
} // endif
StopWatch sw = new StopWatch();
sw.start();
List<CardRules> res = executeLoadTask(tasks);
sw.stop();
final long timeOnParse = sw.getTime();
System.out.printf("Read cards: %s %s in %d ms (%d parts) %s%n", estimatedFilesRemaining, zip == null? "files" : "archived files", timeOnParse, NUMBER_OF_PARTS, useThreadPool ? "using thread pool" : "in same thread");
if ( null != barProgress )
barProgress.setPercentMode(false);
return res;
} // loadCardsUntilYouFind(String)
private List<CardRules> executeLoadTask(final List<Callable<List<CardRules>>> tasks) {
List<CardRules> result = new ArrayList<CardRules>();
try {
if ( useThreadPool ) {
final ExecutorService executor = FThreads.getComputingPool(0.5f);
final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks);
executor.shutdown();
cdl.await();
for(Future<List<CardRules>> pp : parts) {
result.addAll(pp.get());
}
} else {
for(Callable<List<CardRules>> c : tasks) {
result.addAll(c.call());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) { // this clause comes from non-threaded branch
throw new RuntimeException(e);
}
return result;
}
private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries) {
int totalFiles = entries.size();
int filesPerPart = totalFiles / NUMBER_OF_PARTS;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
if ( null != barProgress )
barProgress.increment();
cdl.countDown();
return res;
}
});
}
return tasks;
}
private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles) {
int totalFiles = allFiles.size();
int filesPerPart = totalFiles / NUMBER_OF_PARTS;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRange(allFiles, from, till);
if ( null != barProgress )
barProgress.increment();
cdl.countDown();
return res;
}
});
}
return tasks;
}
/**
* TODO: Write javadoc for this method.
* @param allFiles
* @param cardsfolder2
*/
private void fillFilesArray(List<File> allFiles, File startDir) {
String[] list = startDir.list();
for (String filename : list) {
File entry = new File(startDir, filename);
if (!entry.isDirectory()) {
if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
allFiles.add(entry);
continue;
}
if (filename.startsWith(".")) {
continue;
}
fillFilesArray(allFiles, entry);
}
}
/**
* <p>
* load a card.
* </p>
*
* @param inputStream
* the stream from which to load the card's information
*
* @return the card loaded from the stream
*/
protected final CardRules loadCard(CardRulesReader reader, final InputStream inputStream) {
reader.reset();
InputStreamReader isr = new InputStreamReader(inputStream, this.charset);
List<String> allLines = FileUtil.readAllLines(isr, true);
return reader.readCard(allLines);
}
/**
* Load a card from a txt file.
*
* @param pathToTxtFile
* the full or relative path to the file to load
*
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRulesReader reader, final File pathToTxtFile) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(pathToTxtFile);
return this.loadCard(reader, fileInputStream);
} catch (final FileNotFoundException ex) {
BugReporter.reportException(ex, "File \"%s\" exception", pathToTxtFile.getAbsolutePath());
throw new RuntimeException("CardReader : run error -- file exception -- filename is "
+ pathToTxtFile.getPath(), ex);
} finally {
try {
fileInputStream.close();
} catch (final IOException ignored) {
// 11:08
// PM
}
}
}
/**
* Load a card from an entry in a zip file.
*
* @param entry
* to load from
*
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRulesReader rulesReader, final ZipEntry entry) {
InputStream zipInputStream = null;
try {
zipInputStream = this.zip.getInputStream(entry);
return this.loadCard(rulesReader, zipInputStream);
} catch (final IOException exn) {
throw new RuntimeException(exn);
// PM
} finally {
try {
if (zipInputStream != null) {
zipInputStream.close();
}
} catch (final IOException ignored) {
// 11:08
// PM
}
}
}
}
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.lang3.time.StopWatch;
import forge.card.CardRules;
import forge.util.FileUtil;
import forge.util.ThreadUtil;
/**
* <p>
* CardReader class.
* </p>
*
* @author Forge
* @version $Id: CardStorageReader.java 23742 2013-11-22 16:32:56Z Max mtg $
*/
public class CardStorageReader {
public interface Observer {
public void cardLoaded(CardRules rules, List<String> lines, File fileOnDisk);
}
public interface ProgressObserver{
void setOperationName(String name, boolean usePercents);
void report(int current, int total);
// does nothing, used when they pass null instead of an instance
public final static ProgressObserver emptyObserver = new ProgressObserver() {
@Override public void setOperationName(String name, boolean usePercents) {}
@Override public void report(int current, int total) {}
};
}
private static final String CARD_FILE_DOT_EXTENSION = ".txt";
/** Default charset when loading from files. */
public static final String DEFAULT_CHARSET_NAME = "US-ASCII";
private final boolean useThreadPool = ThreadUtil.isMultiCoreSystem();
private final static int NUMBER_OF_PARTS = 25;
private final ProgressObserver progressObserver;
private transient File cardsfolder;
private transient ZipFile zip;
private final transient Charset charset;
private final Observer observer;
// 8/18/11 10:56 PM
/**
* <p>
* Constructor for CardReader.
* </p>
*
* @param theCardsFolder
* indicates location of the cardsFolder
* @param useZip
* if true, attempts to load cards from a zip file, if one
* exists.
*/
public CardStorageReader(String cardDataDir, CardStorageReader.ProgressObserver progressObserver, Observer observer) {
this.progressObserver = progressObserver != null ? progressObserver : CardStorageReader.ProgressObserver.emptyObserver;
this.cardsfolder = new File(cardDataDir);
this.observer = observer;
// These read data for lightweight classes.
if (!cardsfolder.exists()) {
throw new RuntimeException("CardReader : constructor error -- " + cardsfolder.getAbsolutePath() + " file/folder not found.");
}
if (!cardsfolder.isDirectory()) {
throw new RuntimeException("CardReader : constructor error -- not a directory -- " + cardsfolder.getAbsolutePath());
}
final File zipFile = new File(cardsfolder, "cardsfolder.zip");
if (zipFile.exists()) {
try {
this.zip = new ZipFile(zipFile);
} catch (final Exception exn) {
System.err.printf("Error reading zip file \"%s\": %s. Defaulting to txt files in \"%s\".%n", zipFile.getAbsolutePath(), exn, cardsfolder.getAbsolutePath());
}
}
this.charset = Charset.forName(CardStorageReader.DEFAULT_CHARSET_NAME);
} // CardReader()
private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader();
List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) {
File cardTxtFile = files.get(i);
result.add(this.loadCard(rulesReader, cardTxtFile));
}
return result;
}
private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader();
List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) {
ZipEntry ze = files.get(i);
// if (ze.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) // already filtered!
result.add(this.loadCard(rulesReader, ze));
}
return result;
}
/**
* Starts reading cards into memory until the given card is found.
*
* After that, we save our place in the list of cards (on disk) in case we
* need to load more.
*
* @return the Card or null if it was not found.
*/
public final Iterable<CardRules> loadCards() {
progressObserver.setOperationName("Loading cards, examining folder", true);
// Iterate through txt files or zip archive.
// Report relevant numbers to progress monitor model.
Set<CardRules> result = new TreeSet<CardRules>(new Comparator<CardRules>() {
@Override
public int compare(CardRules o1, CardRules o2) {
return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName());
}
});
final List<File> allFiles = collectCardFiles(new ArrayList<File>(), this.cardsfolder);
if(!allFiles.isEmpty()) {
int fileParts = zip == null ? NUMBER_OF_PARTS : 1 + NUMBER_OF_PARTS / 3;
if( allFiles.size() < fileParts * 100)
fileParts = allFiles.size() / 100; // to avoid creation of many threads for a dozen of files
final CountDownLatch cdlFiles = new CountDownLatch(fileParts);
List<Callable<List<CardRules>>> taskFiles = makeTaskListForFiles(allFiles, cdlFiles);
progressObserver.setOperationName("Loading cards from folders", true);
progressObserver.report(0, taskFiles.size());
StopWatch sw = new StopWatch();
sw.start();
executeLoadTask(result, taskFiles, cdlFiles);
sw.stop();
final long timeOnParse = sw.getTime();
System.out.printf("Read cards: %s files in %d ms (%d parts) %s%n", allFiles.size(), timeOnParse, taskFiles.size(), useThreadPool ? "using thread pool" : "in same thread");
}
if( this.zip != null ) {
final CountDownLatch cdlZip = new CountDownLatch(NUMBER_OF_PARTS);
List<Callable<List<CardRules>>> taskZip = new ArrayList<>();
ZipEntry entry;
List<ZipEntry> entries = new ArrayList<ZipEntry>();
// zipEnum was initialized in the constructor.
Enumeration<? extends ZipEntry> zipEnum = this.zip.entries();
while (zipEnum.hasMoreElements()) {
entry = zipEnum.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
continue;
entries.add(entry);
}
taskZip = makeTaskListForZip(entries, cdlZip);
progressObserver.setOperationName("Loading cards from archive", true);
progressObserver.report(0, taskZip.size());
StopWatch sw = new StopWatch();
sw.start();
executeLoadTask(result, taskZip, cdlZip);
sw.stop();
final long timeOnParse = sw.getTime();
System.out.printf("Read cards: %s archived files in %d ms (%d parts) %s%n", this.zip.size(), timeOnParse, taskZip.size(), useThreadPool ? "using thread pool" : "in same thread");
}
return result;
} // loadCardsUntilYouFind(String)
private void executeLoadTask(Collection<CardRules> result, final List<Callable<List<CardRules>>> tasks, CountDownLatch cdl) {
try {
if ( useThreadPool ) {
final ExecutorService executor = ThreadUtil.getComputingPool(0.5f);
final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks);
executor.shutdown();
cdl.await();
for(Future<List<CardRules>> pp : parts) {
result.addAll(pp.get());
}
} else {
for(Callable<List<CardRules>> c : tasks) {
result.addAll(c.call());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) { // this clause comes from non-threaded branch
throw new RuntimeException(e);
}
}
private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries, final CountDownLatch cdl) {
int totalFiles = entries.size();
final int maxParts = (int) cdl.getCount();
int filesPerPart = totalFiles / maxParts;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res;
}
});
}
return tasks;
}
private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles, final CountDownLatch cdl) {
int totalFiles = allFiles.size();
final int maxParts = (int) cdl.getCount();
int filesPerPart = totalFiles / maxParts;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart;
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
@Override
public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRange(allFiles, from, till);
cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res;
}
});
}
return tasks;
}
public static List<File> collectCardFiles(List<File> accumulator, File startDir) {
String[] list = startDir.list();
for (String filename : list) {
File entry = new File(startDir, filename);
if (!entry.isDirectory()) {
if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
accumulator.add(entry);
continue;
}
if (filename.startsWith(".")) {
continue;
}
collectCardFiles(accumulator, entry);
}
return accumulator;
}
private List<String> readScript(final InputStream inputStream) {
return FileUtil.readAllLines(new InputStreamReader(inputStream, this.charset), true);
}
/**
* Load a card from a txt file.
*
* @param pathToTxtFile
* the full or relative path to the file to load
*
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRules.Reader reader, final File file) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
reader.reset();
List<String> lines = readScript(fileInputStream);
CardRules rules = reader.readCard(lines);
if ( null != observer )
observer.cardLoaded(rules, lines, file);
return rules;
} catch (final FileNotFoundException ex) {
throw new RuntimeException("CardReader : run error -- file not found: " + file.getPath(), ex);
} finally {
try {
fileInputStream.close();
} catch (final IOException ignored) {
// 11:08
// PM
}
}
}
/**
* Load a card from an entry in a zip file.
*
* @param entry
* to load from
*
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRules.Reader rulesReader, final ZipEntry entry) {
InputStream zipInputStream = null;
try {
zipInputStream = this.zip.getInputStream(entry);
rulesReader.reset();
CardRules rules = rulesReader.readCard(readScript(zipInputStream));
return rules;
} catch (final IOException exn) {
throw new RuntimeException(exn);
// PM
} finally {
try {
if (zipInputStream != null) {
zipInputStream.close();
}
} catch (final IOException ignored) {
// 11:08
// PM
}
}
}
}

View File

@@ -0,0 +1,102 @@
package forge;
import java.io.File;
import java.util.Map;
import java.util.TreeMap;
import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.CardRules;
import forge.card.PrintSheet;
import forge.item.FatPack;
import forge.item.SealedProduct;
import forge.util.storage.IStorage;
import forge.util.storage.StorageBase;
/**
* The class holding game invariants, such as cards, editions, game formats. All that data, which is not supposed to be changed by player
*
* @author Max
*/
public class StaticData {
private final CardDb commonCards;
private final CardDb variantCards;
private final CardEdition.Collection editions;
private final IStorage<SealedProduct.Template> boosters;
private final IStorage<SealedProduct.Template> specialBoosters;
private final IStorage<SealedProduct.Template> tournaments;
private final IStorage<FatPack.Template> fatPacks;
private final IStorage<PrintSheet> printSheets;
private static StaticData lastInstance = null;
public StaticData(CardStorageReader reader, String editionFolder, String blockDataFolder) {
this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder)));
lastInstance = this;
final Map<String, CardRules> regularCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
final Map<String, CardRules> variantsCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
for (CardRules card : reader.loadCards()) {
if (null == card) continue;
final String cardName = card.getName();
if ( card.isVariant() ) {
variantsCards.put(cardName, card);
}
else {
regularCards.put(cardName, card);
}
}
commonCards = new CardDb(regularCards, editions, false);
variantCards = new CardDb(variantsCards, editions, false);
this.boosters = new StorageBase<SealedProduct.Template>("Boosters", editions.getBoosterGenerator());
this.specialBoosters = new StorageBase<SealedProduct.Template>("Special boosters", new SealedProduct.Template.Reader(new File(blockDataFolder, "boosters-special.txt")));
this.tournaments = new StorageBase<SealedProduct.Template>("Starter sets", new SealedProduct.Template.Reader(new File(blockDataFolder, "starters.txt")));
this.fatPacks = new StorageBase<FatPack.Template>("Fat packs", new FatPack.Template.Reader("res/blockdata/fatpacks.txt"));
this.printSheets = new StorageBase<PrintSheet>("Special print runs", new PrintSheet.Reader(new File(blockDataFolder, "printsheets.txt")));
}
public final static StaticData instance() {
return lastInstance;
}
public final CardEdition.Collection getEditions() {
return this.editions;
}
/** @return {@link forge.util.storage.IStorageView}<{@link forge.item.FatPackTemplate}> */
public IStorage<FatPack.Template> getFatPacks() {
return fatPacks;
}
/** @return {@link forge.util.storage.IStorageView}<{@link forge.card.BoosterTemplate}> */
public final IStorage<SealedProduct.Template> getTournamentPacks() {
return tournaments;
}
/** @return {@link forge.util.storage.IStorageView}<{@link forge.card.BoosterTemplate}> */
public final IStorage<SealedProduct.Template> getBoosters() {
return boosters;
}
public final IStorage<SealedProduct.Template> getSpecialBoosters() {
return specialBoosters;
}
public IStorage<PrintSheet> getPrintSheets() {
return printSheets;
}
public CardDb getCommonCards() {
return commonCards;
}
public CardDb getVariantCards() {
return variantCards;
}
}

View File

@@ -34,10 +34,10 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.Singletons;
import forge.StaticData;
import forge.item.PaperCard;
import forge.item.IPaperCard;
import forge.item.PrintSheet;
import forge.item.SealedProduct;
import forge.util.TextUtil;
/**
@@ -50,26 +50,15 @@ import forge.util.TextUtil;
*/
public class BoosterGenerator {
private static final String LAND = "Land";
public static final String ANY = "Any";
public static final String COMMON = "Common";
public static final String UNCOMMON = "Uncommon";
public static final String UNCOMMON_RARE = "UncommonRare";
public static final String RARE = "Rare";
public static final String RARE_MYTHIC = "RareMythic";
public static final String MYTHIC = "Mythic";
public static final String BASIC_LAND = "BasicLand";
public static final String TIME_SHIFTED = "TimeShifted";
private final static Map<String, PrintSheet> cachedSheets = new TreeMap<String, PrintSheet>(String.CASE_INSENSITIVE_ORDER);
private static final synchronized PrintSheet getPrintSheet(String key) {
if( !cachedSheets.containsKey(key) )
cachedSheets.put(key, makeSheet(key, CardDb.instance().getAllCards()));
cachedSheets.put(key, makeSheet(key, StaticData.instance().getCommonCards().getAllCards()));
return cachedSheets.get(key);
}
public static final List<PaperCard> getBoosterPack(SealedProductTemplate booster) {
public static final List<PaperCard> getBoosterPack(SealedProduct.Template booster) {
List<PaperCard> result = new ArrayList<PaperCard>();
for(Pair<String, Integer> slot : booster.getSlots()) {
String slotType = slot.getLeft(); // add expansion symbol here?
@@ -77,7 +66,7 @@ public class BoosterGenerator {
String[] sType = TextUtil.splitWithParenthesis(slotType, ' ');
String setCode = sType.length == 1 && booster.getEdition() != null ? booster.getEdition() : null;
String sheetKey = Singletons.getModel().getEditions().contains(setCode) ? slotType.trim() + " " + setCode: slotType.trim();
String sheetKey = StaticData.instance().getEditions().contains(setCode) ? slotType.trim() + " " + setCode: slotType.trim();
PrintSheet ps = getPrintSheet(sheetKey);
result.addAll(ps.random(numCards, true));
@@ -100,7 +89,7 @@ public class BoosterGenerator {
String mainCode = itMod.next();
if ( mainCode.regionMatches(true, 0, "fromSheet", 0, 9)) { // custom print sheet
String sheetName = StringUtils.strip(mainCode.substring(9), "()\" ");
src = Singletons.getModel().getPrintSheets().get(sheetName).toFlatList();
src = StaticData.instance().getPrintSheets().get(sheetName).toFlatList();
setPred = Predicates.alwaysTrue();
} else if (mainCode.startsWith("promo")) { // get exactly the named cards, that's a tiny inlined print sheet
@@ -108,7 +97,7 @@ public class BoosterGenerator {
String[] cardNames = TextUtil.splitWithParenthesis(list, ',', '"', '"');
List<PaperCard> srcList = new ArrayList<PaperCard>();
for(String cardName: cardNames)
srcList.add(CardDb.instance().getCard(cardName));
srcList.add(StaticData.instance().getCommonCards().getCard(cardName));
src = srcList;
setPred = Predicates.alwaysTrue();
@@ -121,18 +110,18 @@ public class BoosterGenerator {
// only special operators should remain by now - the ones that could not be turned into one predicate
String mainCode = operators.isEmpty() ? null : operators.get(0).trim();
if( null == mainCode || mainCode.equalsIgnoreCase(ANY) ) { // no restriction on rarity
if( null == mainCode || mainCode.equalsIgnoreCase(BoosterSlots.ANY) ) { // no restriction on rarity
Predicate<PaperCard> predicate = Predicates.and(setPred, extraPred);
ps.addAll(Iterables.filter(src, predicate));
} else if ( mainCode.equalsIgnoreCase(UNCOMMON_RARE) ) { // for sets like ARN, where U1 cards are considered rare and U3 are uncommon
} else if ( mainCode.equalsIgnoreCase(BoosterSlots.UNCOMMON_RARE) ) { // for sets like ARN, where U1 cards are considered rare and U3 are uncommon
Predicate<PaperCard> predicateRares = Predicates.and(setPred, IPaperCard.Predicates.Presets.IS_RARE, extraPred);
ps.addAll(Iterables.filter(src, predicateRares));
Predicate<PaperCard> predicateUncommon = Predicates.and( setPred, IPaperCard.Predicates.Presets.IS_UNCOMMON, extraPred);
ps.addAll(Iterables.filter(src, predicateUncommon), 3);
} else if ( mainCode.equalsIgnoreCase(RARE_MYTHIC) ) {
} else if ( mainCode.equalsIgnoreCase(BoosterSlots.RARE_MYTHIC) ) {
// Typical ratio of rares to mythics is 53:15, changing to 35:10 in smaller sets.
// To achieve the desired 1:8 are all mythics are added once, and all rares added twice per print sheet.
@@ -168,13 +157,13 @@ public class BoosterGenerator {
Predicate<PaperCard> toAdd = null;
if( operator.equalsIgnoreCase("dfc") ) { toAdd = Predicates.compose(CardRulesPredicates.splitType(CardSplitType.Transform), PaperCard.FN_GET_RULES);
} else if ( operator.equalsIgnoreCase(LAND) ) { toAdd = Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES);
} else if ( operator.equalsIgnoreCase(BASIC_LAND)) { toAdd = IPaperCard.Predicates.Presets.IS_BASIC_LAND;
} else if ( operator.equalsIgnoreCase(TIME_SHIFTED)) { toAdd = IPaperCard.Predicates.Presets.IS_SPECIAL;
} else if ( operator.equalsIgnoreCase(MYTHIC)) { toAdd = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE;
} else if ( operator.equalsIgnoreCase(RARE)) { toAdd = IPaperCard.Predicates.Presets.IS_RARE;
} else if ( operator.equalsIgnoreCase(UNCOMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_UNCOMMON;
} else if ( operator.equalsIgnoreCase(COMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_COMMON;
} else if ( operator.equalsIgnoreCase(BoosterSlots.LAND) ) { toAdd = Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES);
} else if ( operator.equalsIgnoreCase(BoosterSlots.BASIC_LAND)) { toAdd = IPaperCard.Predicates.Presets.IS_BASIC_LAND;
} else if ( operator.equalsIgnoreCase(BoosterSlots.TIME_SHIFTED)) { toAdd = IPaperCard.Predicates.Presets.IS_SPECIAL;
} else if ( operator.equalsIgnoreCase(BoosterSlots.MYTHIC)) { toAdd = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE;
} else if ( operator.equalsIgnoreCase(BoosterSlots.RARE)) { toAdd = IPaperCard.Predicates.Presets.IS_RARE;
} else if ( operator.equalsIgnoreCase(BoosterSlots.UNCOMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_UNCOMMON;
} else if ( operator.equalsIgnoreCase(BoosterSlots.COMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_COMMON;
} else if ( operator.startsWith("name(") ) {
operator = StringUtils.strip(operator.substring(4), "() ");
String[] cardNames = TextUtil.splitWithParenthesis(operator, ',', '"', '"');

View File

@@ -0,0 +1,14 @@
package forge.card;
public class BoosterSlots {
public static final String LAND = "Land";
public static final String ANY = "Any";
public static final String COMMON = "Common";
public static final String UNCOMMON = "Uncommon";
public static final String UNCOMMON_RARE = "UncommonRare";
public static final String RARE = "Rare";
public static final String RARE_MYTHIC = "RareMythic";
public static final String MYTHIC = "Mythic";
public static final String BASIC_LAND = "BasicLand";
public static final String TIME_SHIFTED = "TimeShifted";
}

View File

@@ -1,4 +1,4 @@
package forge;
package forge.card;
/**
* TODO: Write javadoc for this type.

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -29,6 +30,7 @@ import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -36,77 +38,46 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import forge.Card;
import forge.card.CardEdition.Type;
import forge.card.CardEdition.CardInSet;
import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.CollectionSuppliers;
import forge.util.Lang;
import forge.util.MyRandom;
import forge.util.maps.CollectionSuppliers;
public final class CardDb implements ICardDatabase {
private static volatile CardDb commonCards = null; // 'volatile' keyword makes this working
private static volatile CardDb variantCards = null; // 'volatile' keyword makes this working
public final static String foilSuffix = "+";
private final static int foilSuffixLength = foilSuffix.length();
public static ICardDatabase instance() {
if (CardDb.commonCards == null) {
throw new NullPointerException("CardDb has not yet been initialized, run setup() first");
}
return CardDb.commonCards;
}
public static ICardDatabase variants() {
if (CardDb.variantCards == null) {
throw new NullPointerException("CardDb has not yet been initialized, run setup() first");
}
return CardDb.variantCards;
}
public static void setup(final Iterable<CardRules> rules, EditionCollection editions) {
if (CardDb.commonCards != null) {
throw new RuntimeException("CardDb has already been initialized, don't do it twice please");
}
synchronized (CardDb.class) {
if (CardDb.commonCards == null) { // It's broken under 1.4 and below, on 1.5+ works again!
CardSorter cs = new CardSorter(rules);
commonCards = new CardDb(cs.regularCards, editions, false);
variantCards = new CardDb(cs.variantsCards, editions, false);
}
}
}
// need this to obtain cardReference by name+set+artindex
private final Multimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.<PaperCard>arrayLists());
private final Multimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.<PaperCard>arrayLists());
private final Map<String, PaperCard> uniqueCardsByName = new TreeMap<String, PaperCard>(String.CASE_INSENSITIVE_ORDER);
private final Map<String, CardRules> rulesByName;
private final List<PaperCard> allCards = new ArrayList<PaperCard>();
private final List<PaperCard> roAllCards = Collections.unmodifiableList(allCards);
private final Collection<PaperCard> roUniqueCards = Collections.unmodifiableCollection(uniqueCardsByName.values());
private final EditionCollection editions;
private CardDb(Map<String, CardRules> rules, EditionCollection editions0, boolean logMissingCards) {
private final List<PaperCard> allCards = new ArrayList<PaperCard>();
private final List<PaperCard> roAllCards = Collections.unmodifiableList(allCards);
private final Collection<PaperCard> roUniqueCards = Collections.unmodifiableCollection(uniqueCardsByName.values());
private final CardEdition.Collection editions;
public CardDb(Map<String, CardRules> rules, CardEdition.Collection editions0, boolean logMissingCards) {
this.rulesByName = rules;
this.editions = editions0;
List<String> missingCards = new ArrayList<String>();
for(CardEdition e : editions.getOrderedEditions()) {
boolean worthLogging = logMissingCards && ( e.getType() == Type.CORE || e.getType() == Type.EXPANSION || e.getType() == Type.REPRINT );
boolean worthLogging = logMissingCards && ( e.getType() == CardEdition.Type.CORE || e.getType() == CardEdition.Type.EXPANSION || e.getType() == CardEdition.Type.REPRINT );
if(worthLogging)
System.out.print(e.getName() + " (" + e.getCards().length + " cards)");
String lastCardName = null;
int artIdx = 0;
for(CardEdition.CardInSet cis : e.getCards()) {
if ( cis.name.equals(lastCardName) )
if ( cis.name.equals(lastCardName) )
artIdx++;
else {
artIdx = 0;
lastCardName = cis.name;
}
CardRules cr = rulesByName.get(lastCardName);
if( cr != null )
if( cr != null )
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx));
else if (worthLogging)
missingCards.add(cis.name);
@@ -121,7 +92,7 @@ public final class CardDb implements ICardDatabase {
missingCards.clear();
}
}
for(CardRules cr : rulesByName.values()) {
if( !allCardsByName.containsKey(cr.getName()) )
{
@@ -129,7 +100,7 @@ public final class CardDb implements ICardDatabase {
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 0));
}
}
reIndex();
}
@@ -182,7 +153,7 @@ public final class CardDb implements ICardDatabase {
public PaperCard tryGetCard(final String cardName0) {
return tryGetCard(cardName0, true);
}
@Override
public PaperCard tryGetCard(final String cardName0, boolean fromLastSet) {
if (null == cardName0) {
@@ -191,23 +162,23 @@ public final class CardDb implements ICardDatabase {
final boolean isFoil = this.isFoil(cardName0);
final String cardName = isFoil ? this.removeFoilSuffix(cardName0) : cardName0;
final ImmutablePair<String, String> nameWithSet = CardDb.splitCardName(cardName);
final PaperCard res = nameWithSet.right == null
? ( fromLastSet ? this.uniqueCardsByName.get(nameWithSet.left) : Aggregates.random(this.allCardsByName.get(nameWithSet.left)) )
final PaperCard res = nameWithSet.right == null
? ( fromLastSet ? this.uniqueCardsByName.get(nameWithSet.left) : Aggregates.random(this.allCardsByName.get(nameWithSet.left)) )
: tryGetCard(nameWithSet.left, nameWithSet.right);
return null != res && isFoil ? getFoiled(res) : res;
}
@Override
public PaperCard tryGetCardPrintedByDate(final String name0, final boolean fromLatestSet, final Date printedBefore) {
final boolean isFoil = this.isFoil(name0);
final String cardName = isFoil ? this.removeFoilSuffix(name0) : name0;
final ImmutablePair<String, String> nameWithSet = CardDb.splitCardName(cardName);
PaperCard res = null;
if (null != nameWithSet.right) // set explicitly requested, should return card from it and disregard the date
if (null != nameWithSet.right) // set explicitly requested, should return card from it and disregard the date
res = tryGetCard(nameWithSet.left, nameWithSet.right);
else {
Collection<PaperCard> cards = this.allCardsByName.get(nameWithSet.left); // cards are sorted by datetime desc
@@ -223,13 +194,12 @@ public final class CardDb implements ICardDatabase {
return null != res && isFoil ? getFoiled(res) : res;
}
@Override
public PaperCard tryGetCard(final String cardName, String setName) {
return tryGetCard(cardName, setName, -1);
}
@Override
public PaperCard tryGetCard(final String cardName0, String setName, int index) {
final boolean isFoil = this.isFoil(cardName0);
@@ -239,7 +209,7 @@ public final class CardDb implements ICardDatabase {
if ( null == cards ) return null;
CardEdition edition = editions.get(setName);
if ( null == edition )
if ( null == edition )
return tryGetCard(cardName, true); // set not found, try to get the same card from just any set.
String effectiveSet = edition.getCode();
@@ -254,7 +224,7 @@ public final class CardDb implements ICardDatabase {
if (cnt == 0 ) return null;
result = cnt == 1 ? candidates[0] : candidates[MyRandom.getRandom().nextInt(cnt)];
} else
} else
for( PaperCard pc : cards ) {
if( pc.getEdition().equalsIgnoreCase(effectiveSet) && index == pc.getArtIndex() ) {
result = pc;
@@ -264,7 +234,7 @@ public final class CardDb implements ICardDatabase {
if ( result == null ) return null;
return isFoil ? getFoiled(result) : result;
}
public PaperCard getFoiled(PaperCard card0) {
// Here - I am still unsure if there should be a cache Card->Card from unfoiled to foiled, to avoid creation of N instances of single plains
return new PaperCard(card0.getRules(), card0.getEdition(), card0.getRarity(), card0.getArtIndex(), true);
@@ -279,17 +249,17 @@ public final class CardDb implements ICardDatabase {
}
return cnt;
}
@Override
public int getMaxPrintCount(String cardName) {
int max = -1;
for( PaperCard pc : allCardsByName.get(cardName) ) {
if ( max < pc.getArtIndex() )
if ( max < pc.getArtIndex() )
max = pc.getArtIndex();
}
return max + 1;
}
}
// Single fetch
@Override
public PaperCard getCard(final String name) {
@@ -306,8 +276,7 @@ public final class CardDb implements ICardDatabase {
}
return result;
}
@Override
public PaperCard getCardPrintedByDate(final String name0, final boolean fromLatestSet, Date printedBefore ) {
// Sometimes they read from decks things like "CardName|Set" - but we
@@ -317,8 +286,8 @@ public final class CardDb implements ICardDatabase {
throw new NoSuchElementException(String.format("Card '%s' released before %s not found in our database.", name0, printedBefore.toString()));
}
return result;
}
}
// Advanced fetch by name+set
@Override
public PaperCard getCard(final String name, final String set) {
@@ -327,7 +296,6 @@ public final class CardDb implements ICardDatabase {
@Override
public PaperCard getCard(final String name, final String set, final int artIndex) {
final PaperCard result = tryGetCard(name, set, artIndex);
if (null == result) {
final String message = String.format("Asked for '%s' from '%s' #%d: db didn't find that copy.", name, set, artIndex);
@@ -336,21 +304,6 @@ public final class CardDb implements ICardDatabase {
return result;
}
// Fetch from Forge's Card instance. Well, there should be no errors, but
// we'll still check
public static PaperCard getCard(final Card forgeCard) {
final String name = forgeCard.getName();
final String set = forgeCard.getCurSetCode();
if (StringUtils.isNotBlank(set)) {
PaperCard cp = variants().tryGetCard(name, set);
return cp == null ? instance().getCard(name, set) : cp;
}
PaperCard cp = variants().tryGetCard(name, true);
return cp == null ? instance().getCard(name) : cp;
}
// returns a list of all cards from their respective latest editions
@Override
public Collection<PaperCard> getUniqueCards() {
@@ -368,29 +321,15 @@ public final class CardDb implements ICardDatabase {
return Lists.newArrayList(Iterables.filter(this.roAllCards, predicate));
}
private static class CardSorter{
// Here are refs, get them by name
public final Map<String, CardRules> regularCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
public final Map<String, CardRules> variantsCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER);
CardSorter(final Iterable<CardRules> parser) {
for (CardRules card : parser) {
if (null == card) continue;
final String cardName = card.getName();
if ( card.isVariant() )
variantsCards.put(cardName, card);
else
regularCards.put(cardName, card);
}
}
@Override
public Iterator<PaperCard> iterator() {
return this.roAllCards.iterator();
}
public Predicate<? super PaperCard> wasPrintedInSets(List<String> setCodes) {
return new PredicateExistsInSets(setCodes);
}
private class PredicateExistsInSets implements Predicate<PaperCard> {
private final List<String> sets;
@@ -401,9 +340,84 @@ public final class CardDb implements ICardDatabase {
@Override
public boolean apply(final PaperCard subject) {
Collection<PaperCard> cc = allCardsByName.get(subject.getName());
for(PaperCard c : cc) if (sets.contains(c.getEdition())) return true;
for(PaperCard c : cc)
if (sets.contains(c.getEdition()))
return true;
return false;
}
}
private final Editor editor = new Editor();
public Editor getEditor() { return editor; }
public class Editor {
private boolean immediateReindex = true;
public CardRules putCard(CardRules rules) { return putCard(rules, null); /* will use data from editions folder */ }
public CardRules putCard(CardRules rules, List<Pair<String, CardRarity>> whenItWasPrinted){ // works similarly to Map<K,V>, returning prev. value
String cardName = rules.getName();
CardRules result = rulesByName.get(cardName);
if (result != null && result.getName().equals(cardName)){ // change properties only
result.reinitializeFromRules(rules);
return result;
}
result = rulesByName.put(cardName, rules);
// 1. generate all paper cards from edition data we have (either explicit, or found in res/editions, or add to unknown edition)
List<PaperCard> paperCards = new ArrayList<PaperCard>();
if (null == whenItWasPrinted || whenItWasPrinted.isEmpty()) {
for(CardEdition e : editions.getOrderedEditions()) {
int artIdx = 0;
for(CardInSet cis : e.getCards()) {
if( !cis.name.equals(cardName) )
continue;
paperCards.add(new PaperCard(rules, e.getCode(), cis.rarity, artIdx++));
}
}
} else {
String lastEdition = null;
int artIdx = 0;
for(Pair<String, CardRarity> tuple : whenItWasPrinted){
if(!tuple.getKey().equals(lastEdition)) {
artIdx = 0;
lastEdition = tuple.getKey();
}
CardEdition ed = editions.get(lastEdition);
if(null == ed)
continue;
paperCards.add(new PaperCard(rules, lastEdition, tuple.getValue(), artIdx++));
}
}
if(paperCards.isEmpty())
paperCards.add(new PaperCard(rules, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 0));
// 2. add them to db
for (PaperCard paperCard : paperCards)
addCard(paperCard);
// 3. reindex can be temporary disabled and run after the whole batch of rules is added to db.
if(immediateReindex)
reIndex();
return result;
}
public void removeCard(String name) {
allCardsByName.removeAll(name);
uniqueCardsByName.remove(name);
rulesByName.remove(name);
Iterator<PaperCard> it = allCards.iterator();
while(it.hasNext()) {
PaperCard pc = it.next();
if( pc.getName().equalsIgnoreCase(name))
it.remove();
}
}
public void rebuildIndex() { reIndex(); }
public boolean isImmediateReindex() {
return immediateReindex;
}
public void setImmediateReindex(boolean immediateReindex) {
this.immediateReindex = immediateReindex;
}
}
}

View File

@@ -22,23 +22,29 @@ import java.io.FilenameFilter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.Constant;
import forge.Singletons;
import forge.game.GameFormat;
import forge.StaticData;
import forge.item.SealedProduct;
import forge.util.Aggregates;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.IItemReader;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderBase;
import forge.util.storage.StorageReaderFolder;
@@ -104,7 +110,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
private int boosterArts = 1;
private SealedProductTemplate boosterTpl = null;
private SealedProduct.Template boosterTpl = null;
private CardEdition(CardInSet[] cards) {
this.cards = cards;
@@ -204,76 +210,20 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
return whiteBorder;
}
/**
* The Class Predicates.
*/
public abstract static class Predicates {
/** The Constant canMakeBooster. */
public static final Predicate<CardEdition> CAN_MAKE_BOOSTER = new CanMakeBooster();
private static class CanMakeBooster implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return subject.boosterTpl != null;
}
}
public static final Predicate<CardEdition> HAS_TOURNAMENT_PACK = new CanMakeStarter();
private static class CanMakeStarter implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return Singletons.getModel().getTournamentPacks().contains(subject.getCode());
}
}
public static final Predicate<CardEdition> HAS_FAT_PACK = new CanMakeFatPack();
private static class CanMakeFatPack implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return Singletons.getModel().getFatPacks().contains(subject.getCode());
}
}
/**
* Checks if is legal in format.
*
* @param format the format
* @return the predicate
*/
public static final Predicate<CardEdition> isLegalInFormat(final GameFormat format) {
return new LegalInFormat(format);
}
private static class LegalInFormat implements Predicate<CardEdition> {
private final GameFormat format;
public LegalInFormat(final GameFormat fmt) {
this.format = fmt;
}
@Override
public boolean apply(final CardEdition subject) {
return this.format.isSetLegal(subject.getCode());
}
}
public static final Predicate<CardEdition> hasBasicLands = new Predicate<CardEdition>() {
@Override
public boolean apply(CardEdition ed) {
for(String landName : Constant.Color.BASIC_LANDS) {
if (null == CardDb.instance().tryGetCard(landName, ed.getCode(), 0))
return false;
}
return true;
};
};
public int getCntBoosterPictures() {
return boosterArts;
}
public static class EditionReader extends StorageReaderFolder<CardEdition> {
public EditionReader(File path) {
public SealedProduct.Template getBoosterTemplate() {
return boosterTpl;
}
public boolean hasBoosterTemplate() {
return boosterTpl != null;
}
public static class Reader extends StorageReaderFolder<CardEdition> {
public Reader(File path) {
super(path, CardEdition.FN_GET_CODE);
}
@@ -309,7 +259,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
res.boosterArts = section.getInt("BoosterCovers", 1);
String boosterDesc = section.get("Booster");
res.boosterTpl = boosterDesc == null ? null : new SealedProductTemplate(res.code, SealedProductTemplate.Reader.parseSlots(boosterDesc));
res.boosterTpl = boosterDesc == null ? null : new SealedProduct.Template(res.code, SealedProduct.Template.Reader.parseSlots(boosterDesc));
res.alias = section.get("alias");
res.whiteBorder = "white".equalsIgnoreCase(section.get("border"));
@@ -360,16 +310,146 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
}
};
}
public final static CardEdition getRandomSetWithAllBasicLands(Iterable<CardEdition> allEditions) {
return Aggregates.random(Iterables.filter(allEditions, CardEdition.Predicates.hasBasicLands));
}
public int getCntBoosterPictures() {
return boosterArts;
}
public static class Collection extends StorageBase<CardEdition> {
public SealedProductTemplate getBoosterTemplate() {
return boosterTpl;
private final Map<String, CardEdition> aliasToEdition = new TreeMap<String, CardEdition>(String.CASE_INSENSITIVE_ORDER);
public Collection(IItemReader<CardEdition> reader) {
super("Card editions", reader);
for (CardEdition ee : this) {
String alias = ee.getAlias();
if (null != alias) {
aliasToEdition.put(alias, ee);
}
aliasToEdition.put(ee.getCode2(), ee);
}
}
/**
* Gets a sets by code. It will search first by three letter codes, then by aliases and two-letter codes.
*
* @param code
* the code
* @return the sets the by code
*/
@Override
public CardEdition get(final String code) {
CardEdition baseResult = super.get(code);
return baseResult == null ? aliasToEdition.get(code) : baseResult;
}
public Iterable<CardEdition> getOrderedEditions() {
List<CardEdition> res = Lists.newArrayList(this);
Collections.sort(res);
Collections.reverse(res);
return res;
}
/**
* Gets the sets by code or throw.
*
* @param code
* the code
* @return the sets the by code or throw
*/
public CardEdition getEditionByCodeOrThrow(final String code) {
final CardEdition set = this.get(code);
if (null == set) {
throw new RuntimeException(String.format("Edition with code '%s' not found", code));
}
return set;
}
// used by image generating code
/**
* Gets the code2 by code.
*
* @param code
* the code
* @return the code2 by code
*/
public String getCode2ByCode(final String code) {
final CardEdition set = this.get(code);
return set == null ? "" : set.getCode2();
}
public final Function<String, CardEdition> FN_EDITION_BY_CODE = new Function<String, CardEdition>() {
@Override
public CardEdition apply(String code) {
return Collection.this.get(code);
};
};
/**
* TODO: Write javadoc for this method.
* @return
*/
public IItemReader<SealedProduct.Template> getBoosterGenerator() {
// TODO Auto-generated method stub
return new StorageReaderBase<SealedProduct.Template>(null) {
@Override
public Map<String, SealedProduct.Template> readAll() {
Map<String, SealedProduct.Template> map = new TreeMap<String, SealedProduct.Template>(String.CASE_INSENSITIVE_ORDER);
for(CardEdition ce : Collection.this) {
map.put(ce.getCode(), ce.getBoosterTemplate());
}
return map;
}
@Override
public String getItemKey(SealedProduct.Template item) {
return item.getEdition();
}
};
}
}
public static class Predicates {
/** The Constant canMakeBooster. */
public static final Predicate<CardEdition> CAN_MAKE_BOOSTER = new CanMakeBooster();
private static class CanMakeBooster implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return subject.hasBoosterTemplate();
}
}
public final static CardEdition getRandomSetWithAllBasicLands(Iterable<CardEdition> allEditions) {
return Aggregates.random(Iterables.filter(allEditions, hasBasicLands));
}
public static final Predicate<CardEdition> HAS_TOURNAMENT_PACK = new CanMakeStarter();
private static class CanMakeStarter implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return StaticData.instance().getTournamentPacks().contains(subject.getCode());
}
}
public static final Predicate<CardEdition> HAS_FAT_PACK = new CanMakeFatPack();
private static class CanMakeFatPack implements Predicate<CardEdition> {
@Override
public boolean apply(final CardEdition subject) {
return StaticData.instance().getFatPacks().contains(subject.getCode());
}
}
public static final Predicate<CardEdition> hasBasicLands = new Predicate<CardEdition>() {
@Override
public boolean apply(CardEdition ed) {
for(String landName : MagicColor.Constant.BASIC_LANDS) {
if (null == StaticData.instance().getCommonCards().tryGetCard(landName, ed.getCode(), 0))
return false;
}
return true;
};
};
}
}

View File

@@ -22,6 +22,13 @@ import forge.card.mana.ManaCost;
*/
final class CardFace implements ICardFace {
public enum FaceSelectionMethod { //
USE_ACTIVE_FACE,
USE_PRIMARY_FACE,
COMBINE;
}
private final static List<String> emptyList = Collections.unmodifiableList(new ArrayList<String>());
private final static Map<String, String> emptyMap = Collections.unmodifiableMap(new TreeMap<String, String>());
@@ -74,13 +81,13 @@ final class CardFace implements ICardFace {
throw new RuntimeException("Card name is empty");
}
// Here come setters to allow parser supply values
public void setType(CardType type0) { this.type = type0; }
public void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
public void setColor(ColorSet color0) { this.color = color0; }
public void setOracleText(String text) { this.oracleText = text; }
public void setInitialLoyalty(int value) { this.initialLoyalty = value; }
void setType(CardType type0) { this.type = type0; }
void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
void setColor(ColorSet color0) { this.color = color0; }
void setOracleText(String text) { this.oracleText = text; }
void setInitialLoyalty(int value) { this.initialLoyalty = value; }
public void setPtText(String value) {
void setPtText(String value) {
final int slashPos = value.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Creature '%s' has bad p/t stats", this.getName()));
@@ -92,16 +99,16 @@ final class CardFace implements ICardFace {
}
// Raw fields used for Card creation
public void setNonAbilityText(String value) { this.nonAbilityText = value; }
public void addKeyword(String value) { if (null == this.keywords) { this.keywords = new ArrayList<String>(); } this.keywords.add(value); }
public void addAbility(String value) { if (null == this.abilities) { this.abilities = new ArrayList<String>(); } this.abilities.add(value);}
public void addTrigger(String value) { if (null == this.triggers) { this.triggers = new ArrayList<String>(); } this.triggers.add(value);}
public void addStaticAbility(String value) { if (null == this.staticAbilities) { this.staticAbilities = new ArrayList<String>(); } this.staticAbilities.add(value);}
public void addReplacementEffect(String value) { if (null == this.replacements) { this.replacements = new ArrayList<String>(); } this.replacements.add(value);}
public void addSVar(String key, String value) { if (null == this.variables) { this.variables = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); } this.variables.put(key, value); }
void setNonAbilityText(String value) { this.nonAbilityText = value; }
void addKeyword(String value) { if (null == this.keywords) { this.keywords = new ArrayList<String>(); } this.keywords.add(value); }
void addAbility(String value) { if (null == this.abilities) { this.abilities = new ArrayList<String>(); } this.abilities.add(value);}
void addTrigger(String value) { if (null == this.triggers) { this.triggers = new ArrayList<String>(); } this.triggers.add(value);}
void addStaticAbility(String value) { if (null == this.staticAbilities) { this.staticAbilities = new ArrayList<String>(); } this.staticAbilities.add(value);}
void addReplacementEffect(String value) { if (null == this.replacements) { this.replacements = new ArrayList<String>(); } this.replacements.add(value);}
void addSVar(String key, String value) { if (null == this.variables) { this.variables = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); } this.variables.put(key, value); }
public void assignMissingFields() { // Most scripts do not specify color explicitly
void assignMissingFields() { // Most scripts do not specify color explicitly
if ( null == oracleText ) { System.err.println(name + " has no Oracle text."); oracleText = ""; }
if ( manaCost == null && color == null ) System.err.println(name + " has neither ManaCost nor Color");
if ( color == null ) color = ColorSet.fromManaCost(manaCost);

View File

@@ -0,0 +1,493 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.lang3.StringUtils;
import forge.card.mana.IParserManaCost;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
/**
* A collection of methods containing full
* meta and gameplay properties of a card.
*
* @author Forge
* @version $Id: CardRules.java 9708 2011-08-09 19:34:12Z jendave $
*/
public final class CardRules implements ICardCharacteristics {
private CardSplitType splitType;
private ICardFace mainPart;
private ICardFace otherPart;
private CardAiHints aiHints;
private ColorSet colorIdentity;
private CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
splitType = altMode;
mainPart = faces[0];
otherPart = faces[1];
aiHints = cah;
//calculate color identity
byte colMask = calculateColorIdentity(mainPart);
if (otherPart != null) {
colMask |= calculateColorIdentity(otherPart);
}
colorIdentity = ColorSet.fromMask(colMask);
}
void reinitializeFromRules(CardRules newRules) {
if(!newRules.getName().equals(this.getName()))
throw new UnsupportedOperationException("You cannot rename the card using the same CardRules object");
splitType = newRules.splitType;
mainPart = newRules.mainPart;
otherPart = newRules.otherPart;
aiHints = newRules.aiHints;
colorIdentity = newRules.colorIdentity;
}
private byte calculateColorIdentity(ICardFace face) {
byte res = face.getColor().getColor();
boolean isReminder = false;
boolean isSymbol = false;
String oracleText = face.getOracleText();
int len = oracleText.length();
for(int i = 0; i < len; i++) {
char c = oracleText.charAt(i); // This is to avoid needless allocations performed by toCharArray()
switch(c) {
case('('): isReminder = i > 0; break; // if oracle has only reminder, consider it valid rules (basic and true lands need this)
case(')'): isReminder = false; break;
case('{'): isSymbol = true; break;
case('}'): isSymbol = false; break;
default:
if(isSymbol && !isReminder) {
switch(c) {
case('W'): res |= MagicColor.WHITE; break;
case('U'): res |= MagicColor.BLUE; break;
case('B'): res |= MagicColor.BLACK; break;
case('R'): res |= MagicColor.RED; break;
case('G'): res |= MagicColor.GREEN; break;
}
}
break;
}
}
return res;
}
public boolean isVariant() {
CardType t = getType();
return t.isVanguard() || t.isScheme() || t.isPlane() || t.isPhenomenon();
}
public CardSplitType getSplitType() {
return splitType;
}
public ICardFace getMainPart() {
return mainPart;
}
public ICardFace getOtherPart() {
return otherPart;
}
public String getName() {
switch(splitType.getAggregationMethod()) {
case COMBINE:
return mainPart.getName() + " // " + otherPart.getName();
default:
return mainPart.getName();
}
}
public CardAiHints getAiHints() {
return aiHints;
}
@Override
public CardType getType() {
switch(splitType.getAggregationMethod()) {
case COMBINE: // no cards currently have different types
return CardType.combine(mainPart.getType(), otherPart.getType());
default:
return mainPart.getType();
}
}
@Override
public ManaCost getManaCost() {
switch(splitType.getAggregationMethod()) {
case COMBINE:
return ManaCost.combine(mainPart.getManaCost(), otherPart.getManaCost());
default:
return mainPart.getManaCost();
}
}
@Override
public ColorSet getColor() {
switch(splitType.getAggregationMethod()) {
case COMBINE:
return ColorSet.fromMask(mainPart.getColor().getColor() | otherPart.getColor().getColor());
default:
return mainPart.getColor();
}
}
private boolean canCastFace(ICardFace face, byte colorCode) {
if (face.getManaCost().isNoCost()) {
//if card face has no cost, assume castable only by mana of its defined color
return face.getColor().hasNoColorsExcept(colorCode);
}
return face.getManaCost().canBePaidWithAvaliable(colorCode);
}
public boolean canCastWithAvailable(byte colorCode) {
switch(splitType.getAggregationMethod()) {
case COMBINE:
return canCastFace(mainPart, colorCode) || canCastFace(otherPart, colorCode);
default:
return canCastFace(mainPart, colorCode);
}
}
@Override public int getIntPower() { return mainPart.getIntPower(); }
@Override public int getIntToughness() { return mainPart.getIntToughness(); }
@Override public String getPower() { return mainPart.getPower(); }
@Override public String getToughness() { return mainPart.getToughness(); }
@Override public int getInitialLoyalty() { return mainPart.getInitialLoyalty(); }
@Override
public String getOracleText() {
switch(splitType.getAggregationMethod()) {
case COMBINE:
return mainPart.getOracleText() + "\r\n\r\n" + otherPart.getOracleText();
default:
return mainPart.getOracleText();
}
}
// public Set<String> getSets() { return this.setsPrinted.keySet(); }
// public CardInSet getEditionInfo(final String setCode) {
// final CardInSet result = this.setsPrinted.get(setCode);
// return result; // if returns null, String.format("Card '%s' was never printed in set '%s'", this.getName(), setCode);
// }
// vanguard card fields, they don't use sides.
private int deltaHand;
private int deltaLife;
public int getHand() { return deltaHand; }
public int getLife() { return deltaLife; }
public void setVanguardProperties(String pt) {
final int slashPos = pt == null ? -1 : pt.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Vanguard '%s' has bad hand/life stats", this.getName()));
}
this.deltaHand = Integer.parseInt(pt.substring(0, slashPos).replace("+", ""));
this.deltaLife = Integer.parseInt(pt.substring(slashPos+1).replace("+", ""));
}
// Downloadable image
private String dlUrl;
private String dlUrlOtherSide;
public String getPictureUrl(boolean backface ) { return backface ? dlUrlOtherSide : dlUrl; }
public void setDlUrls(String[] dlUrls) { this.dlUrl = dlUrls[0]; this.dlUrlOtherSide = dlUrls[1]; }
public final List<String> getReplacements() {
return null;
}
public final List<String> getTriggers() {
return null;
}
public final List<String> getStaticAbilities() {
return null;
}
public final List<String> getAbilities() {
return null;
}
public ColorSet getColorIdentity() {
return colorIdentity;
}
/** Instantiates class, reads a card. For batch operations better create you own reader instance. */
public static CardRules fromScript(Iterable<String> script) {
Reader crr = new Reader();
for(String line : script) {
crr.parseLine(line);
}
return crr.getCard();
}
// Reads cardname.txt
public static class Reader {
// fields to build
private CardFace[] faces = new CardFace[] { null, null };
private String[] pictureUrl = new String[] { null, null };
private int curFace = 0;
private CardSplitType altMode = CardSplitType.None;
private String handLife = null;
// fields to build CardAiHints
private boolean removedFromAIDecks = false;
private boolean removedFromRandomDecks = false;
private DeckHints hints = null;
private DeckHints needs = null;
/**
* Reset all fields to parse next card (to avoid allocating new CardRulesReader N times)
*/
public final void reset() {
this.curFace = 0;
this.faces[0] = null;
this.faces[1] = null;
this.pictureUrl[0] = null;
this.pictureUrl[1] = null;
this.handLife = null;
this.altMode = CardSplitType.None;
this.removedFromAIDecks = false;
this.removedFromRandomDecks = false;
this.needs = null;
this.hints = null;
}
/**
* Gets the card.
*
* @return the card
*/
public final CardRules getCard() {
CardAiHints cah = new CardAiHints(removedFromAIDecks, removedFromRandomDecks, hints, needs );
faces[0].assignMissingFields();
if (null != faces[1]) faces[1].assignMissingFields();
final CardRules result = new CardRules(faces, altMode, cah);
result.setDlUrls(pictureUrl);
if (StringUtils.isNotBlank(handLife))
result.setVanguardProperties(handLife);
return result;
}
public final CardRules readCard(final Iterable<String> script) {
this.reset();
for (String line : script) {
if (line.isEmpty() || line.charAt(0) == '#') {
continue;
}
this.parseLine(line);
}
return this.getCard();
}
/**
* Parses the line.
*
* @param line
* the line
*/
public final void parseLine(final String line) {
int colonPos = line.indexOf(':');
String key = colonPos > 0 ? line.substring(0, colonPos) : line;
String value = colonPos > 0 ? line.substring(1+colonPos).trim() : null;
switch(key.charAt(0)) {
case 'A':
if ("A".equals(key))
this.faces[curFace].addAbility(value);
else if ("AlternateMode".equals(key)) {
//System.out.println(faces[curFace].getName());
this.altMode = CardSplitType.smartValueOf(value);
} else if ("ALTERNATE".equals(key)) {
this.curFace = 1;
}
break;
case 'C':
if ("Colors".equals(key)) {
// This is forge.card.CardColor not forge.CardColor.
// Why do we have two classes with the same name?
ColorSet newCol = ColorSet.fromNames(value.split(","));
this.faces[this.curFace].setColor(newCol);
}
break;
case 'D':
if ("DeckHints".equals(key)) {
hints = new DeckHints(value);
} else if ("DeckNeeds".equals(key)) {
needs = new DeckHints(value);
}
break;
case 'H':
if ("HandLifeModifier".equals(key)) {
handLife = value;
}
break;
case 'K':
if ("K".equals(key)) {
this.faces[this.curFace].addKeyword(value);
}
break;
case 'L':
if ("Loyalty".equals(key)) {
this.faces[this.curFace].setInitialLoyalty(Integer.valueOf(value));
}
break;
case 'M':
if ("ManaCost".equals(key)) {
this.faces[this.curFace].setManaCost("no cost".equals(value) ? ManaCost.NO_COST
: new ManaCost(new ManaCostParser(value)));
}
break;
case 'N':
if ("Name".equals(key)) {
this.faces[this.curFace] = new CardFace(value);
}
break;
case 'O':
if ("Oracle".equals(key)) {
this.faces[this.curFace].setOracleText(value);
}
break;
case 'P':
if ("PT".equals(key)) {
this.faces[this.curFace].setPtText(value);
}
break;
case 'R':
if ("R".equals(key)) {
this.faces[this.curFace].addReplacementEffect(value);
}
break;
case 'S':
if ("S".equals(key)) {
this.faces[this.curFace].addStaticAbility(value);
} else if ( "SVar".equals(key) ) {
if ( null == value ) throw new IllegalArgumentException("SVar has no variable name");
colonPos = value.indexOf(':');
String variable = colonPos > 0 ? value.substring(0, colonPos) : value;
value = colonPos > 0 ? value.substring(1+colonPos) : null;
if ( "RemAIDeck".equals(variable) ) {
this.removedFromAIDecks = "True".equalsIgnoreCase(value);
} else if ( "RemRandomDeck".equals(variable) ) {
this.removedFromRandomDecks = "True".equalsIgnoreCase(value);
} else if ( "Picture".equals(variable) ) {
this.pictureUrl[this.curFace] = value;
} else if ( "Rarity".equals(variable) ) {
// discard that, they should supply it in SetInfo
} else
this.faces[curFace].addSVar(variable, value);
} else if ("SetInfo".equals(key)) {
// deprecated
}
break;
case 'T':
if ("T".equals(key)) {
this.faces[this.curFace].addTrigger(value);
} else if ("Types".equals(key)) {
this.faces[this.curFace].setType(CardType.parse(value));
} else if ("Text".equals(key) && !"no text".equals(value) && StringUtils.isNotBlank(value)) {
this.faces[this.curFace].setNonAbilityText(value);
}
break;
}
}
/**
* The Class ParserCardnameTxtManaCost.
*/
private static class ManaCostParser implements IParserManaCost {
private final StringTokenizer st;
private int colorlessCost;
public ManaCostParser(final String cost) {
st = new StringTokenizer(cost, " ");
this.colorlessCost = 0;
}
@Override
public final int getTotalColorlessCost() {
if (this.hasNext()) {
throw new RuntimeException("Colorless cost should be obtained after iteration is complete");
}
return this.colorlessCost;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#hasNext()
*/
@Override
public final boolean hasNext() {
return st.hasMoreTokens();
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#next()
*/
@Override
public final ManaCostShard next() {
final String unparsed = st.nextToken();
// System.out.println(unparsed);
try {
int iVal = Integer.parseInt(unparsed);
this.colorlessCost += iVal;
return null;
}
catch (NumberFormatException nex) { }
return ManaCostShard.parseNonGeneric(unparsed);
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
} // unsuported
}
}
}

View File

@@ -6,6 +6,7 @@ import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.util.ComparableOp;
import forge.util.PredicateString;
@@ -170,7 +171,7 @@ public final class CardRulesPredicates {
*/
public static Predicate<CardRules> coreType(final boolean isEqual, final String what) {
try {
return CardRulesPredicates.coreType(isEqual, Enum.valueOf(CardCoreType.class, what));
return CardRulesPredicates.coreType(isEqual, Enum.valueOf(CardType.CoreType.class, what));
} catch (final Exception e) {
return com.google.common.base.Predicates.alwaysFalse();
}
@@ -185,7 +186,7 @@ public final class CardRulesPredicates {
* the type
* @return the predicate
*/
public static Predicate<CardRules> coreType(final boolean isEqual, final CardCoreType type) {
public static Predicate<CardRules> coreType(final boolean isEqual, final CardType.CoreType type) {
return new PredicateCoreType(type, isEqual);
}
@@ -200,7 +201,7 @@ public final class CardRulesPredicates {
*/
public static Predicate<CardRules> superType(final boolean isEqual, final String what) {
try {
return CardRulesPredicates.superType(isEqual, Enum.valueOf(CardSuperType.class, what));
return CardRulesPredicates.superType(isEqual, Enum.valueOf(CardType.SuperType.class, what));
} catch (final Exception e) {
return com.google.common.base.Predicates.alwaysFalse();
}
@@ -215,7 +216,7 @@ public final class CardRulesPredicates {
* the type
* @return the predicate
*/
public static Predicate<CardRules> superType(final boolean isEqual, final CardSuperType type) {
public static Predicate<CardRules> superType(final boolean isEqual, final CardType.SuperType type) {
return new PredicateSuperType(type, isEqual);
}
@@ -224,7 +225,7 @@ public final class CardRulesPredicates {
* Checks for color.
*
* @param thatColor
* the that color
* color to check
* @return the predicate
*/
public static Predicate<CardRules> hasColor(final byte thatColor) {
@@ -235,13 +236,24 @@ public final class CardRulesPredicates {
* Checks if is color.
*
* @param thatColor
* the that color
* color to check
* @return the predicate
*/
public static Predicate<CardRules> isColor(final byte thatColor) {
return new LeafColor(LeafColor.ColorOperator.HasAnyOf, thatColor);
}
/**
* Checks if card can be cast with unlimited mana of given color set.
*
* @param thatColor
* color to check
* @return the predicate
*/
public static Predicate<CardRules> canCastWithAvailable(final byte thatColor) {
return new LeafColor(LeafColor.ColorOperator.CanCast, thatColor);
}
/**
* Checks if is exactly that color.
*
@@ -310,7 +322,7 @@ public final class CardRulesPredicates {
private static class LeafColor implements Predicate<CardRules> {
public enum ColorOperator {
CountColors, CountColorsGreaterOrEqual, HasAnyOf, HasAllOf, Equals
CountColors, CountColorsGreaterOrEqual, HasAnyOf, HasAllOf, Equals, CanCast
}
private final LeafColor.ColorOperator op;
@@ -337,6 +349,8 @@ public final class CardRulesPredicates {
return subject.getColor().hasAllColors(this.color);
case HasAnyOf:
return subject.getColor().hasAnyColor(this.color);
case CanCast:
return subject.canCastWithAvailable(this.color);
default:
return false;
}
@@ -396,7 +410,7 @@ public final class CardRulesPredicates {
}
private static class PredicateCoreType implements Predicate<CardRules> {
private final CardCoreType operand;
private final CardType.CoreType operand;
private final boolean shouldBeEqual;
@Override
@@ -407,14 +421,14 @@ public final class CardRulesPredicates {
return this.shouldBeEqual == card.getType().typeContains(this.operand);
}
public PredicateCoreType(final CardCoreType type, final boolean wantEqual) {
public PredicateCoreType(final CardType.CoreType type, final boolean wantEqual) {
this.operand = type;
this.shouldBeEqual = wantEqual;
}
}
private static class PredicateSuperType implements Predicate<CardRules> {
private final CardSuperType operand;
private final CardType.SuperType operand;
private final boolean shouldBeEqual;
@Override
@@ -422,7 +436,7 @@ public final class CardRulesPredicates {
return this.shouldBeEqual == card.getType().superTypeContains(this.operand);
}
public PredicateSuperType(final CardSuperType type, final boolean wantEqual) {
public PredicateSuperType(final CardType.SuperType type, final boolean wantEqual) {
this.operand = type;
this.shouldBeEqual = wantEqual;
}
@@ -448,21 +462,21 @@ public final class CardRulesPredicates {
/** The Constant isCreature. */
public static final Predicate<CardRules> IS_CREATURE = CardRulesPredicates
.coreType(true, CardCoreType.Creature);
.coreType(true, CardType.CoreType.Creature);
public static final Predicate<CardRules> IS_LEGENDARY = CardRulesPredicates
.superType(true, CardSuperType.Legendary);
.superType(true, CardType.SuperType.Legendary);
/** The Constant isArtifact. */
public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates
.coreType(true, CardCoreType.Artifact);
.coreType(true, CardType.CoreType.Artifact);
/** The Constant isEquipment. */
public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates
.subType("Equipment");
/** The Constant isLand. */
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardCoreType.Land);
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
/** The Constant isBasicLand. */
public static final Predicate<CardRules> IS_BASIC_LAND = new Predicate<CardRules>() {
@@ -480,31 +494,17 @@ public final class CardRulesPredicates {
}
};
/** The Constant isPlaneswalker. */
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true,
CardCoreType.Planeswalker);
/** The Constant isInstant. */
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardCoreType.Instant);
/** The Constant isSorcery. */
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardCoreType.Sorcery);
/** The Constant isEnchantment. */
public static final Predicate<CardRules> IS_ENCHANTMENT = CardRulesPredicates.coreType(true, CardCoreType.Enchantment);
public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardCoreType.Plane);
public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardCoreType.Phenomenon);
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant);
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery);
public static final Predicate<CardRules> IS_ENCHANTMENT = CardRulesPredicates.coreType(true, CardType.CoreType.Enchantment);
public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardType.CoreType.Plane);
public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardType.CoreType.Phenomenon);
public static final Predicate<CardRules> IS_PLANE_OR_PHENOMENON = Predicates.or(IS_PLANE, IS_PHENOMENON);
public static final Predicate<CardRules> IS_SCHEME = CardRulesPredicates.coreType(true, CardCoreType.Scheme);
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardCoreType.Vanguard);
/** The Constant isNonLand. */
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardCoreType.Land);
/** The Constant isNonCreatureSpell. */
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = Predicates.not(Predicates.or(
Presets.IS_CREATURE, Presets.IS_LAND));
public static final Predicate<CardRules> IS_SCHEME = CardRulesPredicates.coreType(true, CardType.CoreType.Scheme);
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = Predicates.not(Predicates.or(Presets.IS_CREATURE, Presets.IS_LAND));
/** The Constant IS_NONCREATURE_SPELL_FOR_GENERATOR. **/
@SuppressWarnings("unchecked")
@@ -532,7 +532,8 @@ public final class CardRulesPredicates {
/** The Constant isMulticolor. */
public static final Predicate<CardRules> IS_MULTICOLOR = CardRulesPredicates.hasAtLeastCntColors((byte) 2);
/** The Constant isMonocolor. */
public static final Predicate<CardRules> IS_MONOCOLOR = CardRulesPredicates.hasCntColors((byte) 1);
/** The Constant colors. */

View File

@@ -1,26 +1,26 @@
package forge.card;
import forge.CardCharacteristicName;
import forge.card.CardFace.FaceSelectionMethod;
public enum CardSplitType
{
None(AggregationMethod.USE_PRIMARY_FACE, null),
Transform(AggregationMethod.USE_ACTIVE_FACE, CardCharacteristicName.Transformed),
Split(AggregationMethod.AGGREGATE, CardCharacteristicName.RightSplit),
Flip(AggregationMethod.USE_PRIMARY_FACE, CardCharacteristicName.Flipped),
None(FaceSelectionMethod.USE_PRIMARY_FACE, null),
Transform(FaceSelectionMethod.USE_ACTIVE_FACE, CardCharacteristicName.Transformed),
Split(FaceSelectionMethod.COMBINE, CardCharacteristicName.RightSplit),
Flip(FaceSelectionMethod.USE_PRIMARY_FACE, CardCharacteristicName.Flipped),
// used by 12 licid creatures to switch type into enchantment aura
Licid(AggregationMethod.USE_PRIMARY_FACE, CardCharacteristicName.Licid);
Licid(FaceSelectionMethod.USE_PRIMARY_FACE, CardCharacteristicName.Licid);
private CardSplitType(AggregationMethod calcMode, CardCharacteristicName stateName) {
private CardSplitType(FaceSelectionMethod calcMode, CardCharacteristicName stateName) {
method = calcMode;
this.changedStateName = stateName;
}
public AggregationMethod getAggregationMethod() {
public FaceSelectionMethod getAggregationMethod() {
return method;
}
private final AggregationMethod method;
private final FaceSelectionMethod method;
private final CardCharacteristicName changedStateName;
public static CardSplitType smartValueOf(String text) {

View File

@@ -24,8 +24,6 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import forge.Constant;
/**
* <p>
* Immutable Card type. Can be build only from parsing a string.
@@ -36,20 +34,64 @@ import forge.Constant;
*/
public final class CardType implements Comparable<CardType> {
public enum CoreType {
/** The Artifact. */
Artifact,
/** The Creature. */
Creature,
/** The Enchantment. */
Enchantment,
/** The Instant. */
Instant,
/** The Land. */
Land,
/** The Plane. */
Plane,
/** The Planeswalker. */
Planeswalker,
/** The Scheme. */
Scheme,
/** The Sorcery. */
Sorcery,
/** The Tribal. */
Tribal,
/** The Vanguard. */
Vanguard,
/** The Phenomenon. */
Phenomenon
}
public enum SuperType {
/** The Basic. */
Basic,
/** The Legendary. */
Legendary,
/** The Snow. */
Snow,
/** The Ongoing. */
Ongoing,
/** The World. */
World
}
private final List<String> subType = new ArrayList<String>();
private final EnumSet<CardCoreType> coreType = EnumSet.noneOf(CardCoreType.class);
private final EnumSet<CardSuperType> superType = EnumSet.noneOf(CardSuperType.class);
private final EnumSet<CardType.CoreType> coreType = EnumSet.noneOf(CardType.CoreType.class);
private final EnumSet<CardType.SuperType> superType = EnumSet.noneOf(CardType.SuperType.class);
private String calculatedType = null; // since obj is immutable, this is
// calc'd once
// This will be useful for faster parses
private static HashMap<String, CardCoreType> stringToCoreType = new HashMap<String, CardCoreType>();
private static HashMap<String, CardSuperType> stringToSuperType = new HashMap<String, CardSuperType>();
private static HashMap<String, CardType.CoreType> stringToCoreType = new HashMap<String, CardType.CoreType>();
private static HashMap<String, CardType.SuperType> stringToSuperType = new HashMap<String, CardType.SuperType>();
static {
for (final CardSuperType st : CardSuperType.values()) {
for (final CardType.SuperType st : CardType.SuperType.values()) {
CardType.stringToSuperType.put(st.name(), st);
}
for (final CardCoreType ct : CardCoreType.values()) {
for (final CardType.CoreType ct : CardType.CoreType.values()) {
CardType.stringToCoreType.put(ct.name(), ct);
}
}
@@ -106,13 +148,13 @@ public final class CardType implements Comparable<CardType> {
return;
}
final CardCoreType ct = CardType.stringToCoreType.get(type);
final CardType.CoreType ct = CardType.stringToCoreType.get(type);
if (ct != null) {
this.coreType.add(ct);
return;
}
final CardSuperType st = CardType.stringToSuperType.get(type);
final CardType.SuperType st = CardType.stringToSuperType.get(type);
if (st != null) {
this.superType.add(st);
return;
@@ -126,56 +168,56 @@ public final class CardType implements Comparable<CardType> {
return this.subType.contains(operand);
}
public boolean typeContains(final CardCoreType operand) {
public boolean typeContains(final CardType.CoreType operand) {
return this.coreType.contains(operand);
}
public boolean superTypeContains(final CardSuperType operand) {
public boolean superTypeContains(final CardType.SuperType operand) {
return this.superType.contains(operand);
}
public boolean isCreature() {
return this.coreType.contains(CardCoreType.Creature);
return this.coreType.contains(CardType.CoreType.Creature);
}
public boolean isPlaneswalker() {
return this.coreType.contains(CardCoreType.Planeswalker);
return this.coreType.contains(CardType.CoreType.Planeswalker);
}
public boolean isLand() {
return this.coreType.contains(CardCoreType.Land);
return this.coreType.contains(CardType.CoreType.Land);
}
public boolean isArtifact() {
return this.coreType.contains(CardCoreType.Artifact);
return this.coreType.contains(CardType.CoreType.Artifact);
}
public boolean isInstant() {
return this.coreType.contains(CardCoreType.Instant);
return this.coreType.contains(CardType.CoreType.Instant);
}
public boolean isSorcery() {
return this.coreType.contains(CardCoreType.Sorcery);
return this.coreType.contains(CardType.CoreType.Sorcery);
}
public boolean isVanguard() {
return this.coreType.contains(CardCoreType.Vanguard);
return this.coreType.contains(CardType.CoreType.Vanguard);
}
public boolean isScheme() {
return this.coreType.contains(CardCoreType.Scheme);
return this.coreType.contains(CardType.CoreType.Scheme);
}
public boolean isEnchantment() {
return this.coreType.contains(CardCoreType.Enchantment);
return this.coreType.contains(CardType.CoreType.Enchantment);
}
public boolean isBasic() {
return this.superType.contains(CardSuperType.Basic);
return this.superType.contains(CardType.SuperType.Basic);
}
public boolean isLegendary() {
return this.superType.contains(CardSuperType.Legendary);
return this.superType.contains(CardType.SuperType.Legendary);
}
public boolean isBasicLand() {
@@ -200,10 +242,10 @@ public final class CardType implements Comparable<CardType> {
public List<String> getTypesBeforeDash() {
final ArrayList<String> types = new ArrayList<String>();
for (final CardSuperType st : this.superType) {
for (final CardType.SuperType st : this.superType) {
types.add(st.name());
}
for (final CardCoreType ct : this.coreType) {
for (final CardType.CoreType ct : this.coreType) {
types.add(ct.name());
}
return types;
@@ -229,13 +271,54 @@ public final class CardType implements Comparable<CardType> {
}
public boolean isPlane() {
return this.coreType.contains(CardCoreType.Plane);
return this.coreType.contains(CardType.CoreType.Plane);
}
public boolean isPhenomenon() {
return this.coreType.contains(CardCoreType.Phenomenon);
return this.coreType.contains(CardType.CoreType.Phenomenon);
}
/**
* The Interface CardTypes.
*/
public static class Constant {
/** The loaded. */
public static final boolean[] LOADED = { false };
/** The card types. */
public static final List<String> CARD_TYPES = new ArrayList<String>();
/** The super types. */
public static final List<String> SUPER_TYPES = new ArrayList<String>();
/** The basic types. */
public static final List<String> BASIC_TYPES = new ArrayList<String>();
/** The land types. */
public static final List<String> LAND_TYPES = new ArrayList<String>();
/** The creature types. */
public static final List<String> CREATURE_TYPES = new ArrayList<String>();
/** The instant types. */
public static final List<String> INSTANT_TYPES = new ArrayList<String>();
/** The sorcery types. */
public static final List<String> SORCERY_TYPES = new ArrayList<String>();
/** The enchantment types. */
public static final List<String> ENCHANTMENT_TYPES = new ArrayList<String>();
/** The artifact types. */
public static final List<String> ARTIFACT_TYPES = new ArrayList<String>();
/** The walker types. */
public static final List<String> WALKER_TYPES = new ArrayList<String>();
}
///////// Utility methods
public static boolean isACardType(final String cardType) {
return CardType.getAllCardTypes().contains(cardType);
@@ -245,7 +328,7 @@ public final class CardType implements Comparable<CardType> {
final ArrayList<String> types = new ArrayList<String>();
// types.addAll(getCardTypes());
types.addAll(Constant.CardTypes.CARD_TYPES);
types.addAll(Constant.CARD_TYPES);
// not currently used by Forge
types.add("Plane");
@@ -258,7 +341,7 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getBasicTypes() {
final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.BASIC_TYPES);
types.addAll(Constant.BASIC_TYPES);
return types;
}
@@ -266,8 +349,8 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getLandTypes() {
final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.BASIC_TYPES);
types.addAll(Constant.CardTypes.LAND_TYPES);
types.addAll(Constant.BASIC_TYPES);
types.addAll(Constant.LAND_TYPES);
return types;
}
@@ -275,13 +358,13 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getCreatureTypes() {
final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.CREATURE_TYPES);
types.addAll(Constant.CREATURE_TYPES);
return types;
}
public static boolean isASuperType(final String cardType) {
return (Constant.CardTypes.SUPER_TYPES.contains(cardType));
return (Constant.SUPER_TYPES.contains(cardType));
}
public static boolean isASubType(final String cardType) {
@@ -289,18 +372,18 @@ public final class CardType implements Comparable<CardType> {
}
public static boolean isACreatureType(final String cardType) {
return (Constant.CardTypes.CREATURE_TYPES.contains(cardType));
return (Constant.CREATURE_TYPES.contains(cardType));
}
public static boolean isALandType(final String cardType) {
return (Constant.CardTypes.LAND_TYPES.contains(cardType));
return (Constant.LAND_TYPES.contains(cardType));
}
public static boolean isAPlaneswalkerType(final String cardType) {
return (Constant.CardTypes.WALKER_TYPES.contains(cardType));
return (Constant.WALKER_TYPES.contains(cardType));
}
public static boolean isABasicLandType(final String cardType) {
return (Constant.CardTypes.BASIC_TYPES.contains(cardType));
return (Constant.BASIC_TYPES.contains(cardType));
}
}

View File

@@ -17,7 +17,11 @@
*/
package forge.card;
import forge.Constant;
import java.util.Iterator;
import java.util.NoSuchElementException;
import com.google.common.collect.UnmodifiableIterator;
import forge.card.mana.ManaCost;
import forge.util.BinaryUtil;
@@ -31,7 +35,7 @@ import forge.util.BinaryUtil;
*
*
*/
public final class ColorSet implements Comparable<ColorSet> {
public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte> {
private final byte myColor;
private final int orderWeight;
@@ -55,7 +59,6 @@ public final class ColorSet implements Comparable<ColorSet> {
private ColorSet(final byte mask) {
this.myColor = mask;
this.orderWeight = this.getOrderWeight();
}
public static ColorSet fromMask(final int mask) {
@@ -253,7 +256,7 @@ public final class ColorSet implements Comparable<ColorSet> {
return "n/a";
}
String toReturn = MagicColor.toLongString(myColor);
if (toReturn == Constant.Color.COLORLESS && myColor != 0) {
if (toReturn == MagicColor.Constant.COLORLESS && myColor != 0) {
return "multi";
}
return toReturn;
@@ -281,4 +284,37 @@ public final class ColorSet implements Comparable<ColorSet> {
public ColorSet getOffColors(ColorSet ccOther) {
return ColorSet.fromMask(~this.myColor & ccOther.myColor);
}
@Override
public Iterator<Byte> iterator() {
return new ColorIterator();
}
private class ColorIterator extends UnmodifiableIterator<Byte> {
int currentBit = -1;
private int getIndexOfNextColor(){
int nextBit = currentBit + 1;
while(nextBit < MagicColor.NUMBER_OR_COLORS) {
if((myColor & MagicColor.WUBRG[nextBit]) != 0)
break;
nextBit++;
}
return nextBit;
}
@Override
public boolean hasNext() {
return getIndexOfNextColor() < MagicColor.NUMBER_OR_COLORS;
}
@Override
public Byte next() {
currentBit = getIndexOfNextColor();
if (currentBit >= MagicColor.NUMBER_OR_COLORS)
throw new NoSuchElementException();
return MagicColor.WUBRG[currentBit];
}
}
}

View File

@@ -8,7 +8,7 @@ import com.google.common.base.Predicate;
import forge.item.PaperCard;
public interface ICardDatabase {
public interface ICardDatabase extends Iterable<PaperCard> {
PaperCard tryGetCard(String cardName);
PaperCard tryGetCard(String cardName, boolean fromLastSet);
PaperCard tryGetCard(String cardName, String edition);

View File

@@ -0,0 +1,111 @@
package forge.card;
import java.util.List;
import com.google.common.collect.ImmutableList;
/**
* Holds byte values for each color magic has.
*
*/
public class MagicColor {
public static final byte COLORLESS = 0;
public static final byte WHITE = 1 << 1;
public static final byte BLUE = 1 << 2;
public static final byte BLACK = 1 << 3;
public static final byte RED = 1 << 4;
public static final byte GREEN = 1 << 5;
public static final byte ALL_COLORS = BLACK | BLUE | WHITE | RED | GREEN;
public static final int NUMBER_OR_COLORS = 5;
public static final byte[] WUBRG = new byte[] { WHITE, BLUE, BLACK, RED, GREEN };
public static byte fromName(String s) {
if( s == null ) return 0;
if (s.equalsIgnoreCase(Constant.WHITE) || s.equalsIgnoreCase("w")) {
return MagicColor.WHITE;
}
if (s.equalsIgnoreCase(Constant.BLUE) || s.equalsIgnoreCase("u")) {
return MagicColor.BLUE;
}
if (s.equalsIgnoreCase(Constant.BLACK) || s.equalsIgnoreCase("b")) {
return MagicColor.BLACK;
}
if (s.equalsIgnoreCase(Constant.RED) || s.equalsIgnoreCase("r")) {
return MagicColor.RED;
}
if (s.equalsIgnoreCase(Constant.GREEN) || s.equalsIgnoreCase("g")) {
return MagicColor.GREEN;
}
return 0; // colorless
}
public static String toShortString(String color) {
if (color.equalsIgnoreCase(Constant.SNOW)) return "S"; // compatibility
return toShortString(fromName(color));
}
public static String toLongString(String color) {
if (color.equalsIgnoreCase("s")) return Constant.SNOW; // compatibility
return toLongString(fromName(color));
}
public static String toShortString(byte color) {
switch(color){
case GREEN: return "G";
case RED: return "R";
case BLUE: return "U";
case BLACK: return "B";
case WHITE: return "W";
default: return "1";
}
}
public static String toLongString(byte color) {
switch(color){
case GREEN: return Constant.GREEN ;
case RED: return Constant.RED;
case BLUE: return Constant.BLUE;
case BLACK: return Constant.BLACK;
case WHITE: return Constant.WHITE;
default: return Constant.COLORLESS;
}
}
/**
* The Interface Color.
*/
public static class Constant {
/** The Black. */
public static final String BLACK = "black";
/** The Blue. */
public static final String BLUE = "blue";
/** The Green. */
public static final String GREEN = "green";
/** The Red. */
public static final String RED = "red";
/** The White. */
public static final String WHITE = "white";
/** The Colorless. */
public static final String COLORLESS = "colorless";
// color order "wubrg"
/** The only colors. */
public static final ImmutableList<String> ONLY_COLORS = ImmutableList.of(WHITE, BLUE, BLACK, RED, GREEN);
/** The Snow. */
public static final String SNOW = "snow";
/** The Basic lands. */
public static final List<String> BASIC_LANDS = ImmutableList.of("Plains", "Island", "Swamp", "Mountain", "Forest");
public static final List<String> SNOW_LANDS = ImmutableList.of("Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest");
}
}

View File

@@ -1,5 +1,6 @@
package forge.item;
package forge.card;
import java.io.File;
import java.util.List;
import java.util.Map.Entry;
import java.util.ArrayList;
@@ -7,7 +8,9 @@ import java.util.Collection;
import com.google.common.base.Function;
import forge.util.ItemPool;
import forge.deck.CardPool;
import forge.item.PaperCard;
import forge.util.MyRandom;
import forge.util.storage.StorageReaderFileSections;
@@ -30,7 +33,7 @@ public class PrintSheet {
this(name0, null);
}
private PrintSheet(String name0, ItemPool<PaperCard> pool) {
public PrintSheet(String name0, ItemPool<PaperCard> pool) {
name = name0;
cardsWithWeights = pool != null ? pool : new ItemPool<PaperCard>(PaperCard.class);
}
@@ -105,18 +108,6 @@ public class PrintSheet {
return result;
}
public static class Reader extends StorageReaderFileSections<PrintSheet> {
public Reader(String fileName) {
super(fileName, PrintSheet.FN_GET_KEY);
}
@Override
protected PrintSheet read(String title, Iterable<String> body, int idx) {
return new PrintSheet(title, CardPool.fromCardList(body));
}
}
public boolean isEmpty() {
return cardsWithWeights.isEmpty();
}
@@ -125,5 +116,16 @@ public class PrintSheet {
return cardsWithWeights.toFlatList();
}
public static class Reader extends StorageReaderFileSections<PrintSheet> {
public Reader(File file) {
super(file, PrintSheet.FN_GET_KEY);
}
@Override
protected PrintSheet read(String title, Iterable<String> body, int idx) {
return new PrintSheet(title, CardPool.fromCardList(body));
}
}
}

View File

@@ -10,13 +10,15 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.item.PaperCard;
import forge.item.ItemPoolView;
import forge.item.PrintSheet;
import forge.item.SealedProduct;
import forge.util.ItemPoolView;
public class UnOpenedProduct implements IUnOpenedProduct {
private final SealedProductTemplate tpl;
private final SealedProduct.Template tpl;
private final Map<String, PrintSheet> sheets;
private boolean poolLimited = false; // if true after successful generation cards are removed from printsheets.
@@ -30,24 +32,24 @@ public class UnOpenedProduct implements IUnOpenedProduct {
// Means to select from all unique cards (from base game, ie. no schemes or avatars)
public UnOpenedProduct(SealedProductTemplate template) {
public UnOpenedProduct(SealedProduct.Template template) {
tpl = template;
sheets = null;
}
// Invoke this constructor only if you are sure that the pool is not equal to deafult carddb
public UnOpenedProduct(SealedProductTemplate template, ItemPoolView<PaperCard> pool) {
public UnOpenedProduct(SealedProduct.Template template, ItemPoolView<PaperCard> pool) {
this(template, pool.toFlatList());
}
public UnOpenedProduct(SealedProductTemplate template, Iterable<PaperCard> cards) {
public UnOpenedProduct(SealedProduct.Template template, Iterable<PaperCard> cards) {
tpl = template;
sheets = new TreeMap<String, PrintSheet>();
prebuildSheets(cards);
}
public UnOpenedProduct(SealedProductTemplate sealedProductTemplate, Predicate<PaperCard> filterPrinted) {
this(sealedProductTemplate, Iterables.filter(CardDb.instance().getAllCards(), filterPrinted));
public UnOpenedProduct(SealedProduct.Template sealedProductTemplate, Predicate<PaperCard> filterPrinted) {
this(sealedProductTemplate, Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), filterPrinted));
}
private void prebuildSheets(Iterable<PaperCard> sourceList) {

View File

@@ -19,10 +19,9 @@ package forge.card.mana;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import forge.card.ColorSet;
/**
* <p>
* CardManaCost class.
@@ -32,7 +31,7 @@ import forge.card.ColorSet;
* @version $Id: CardManaCost.java 9708 2011-08-09 19:34:12Z jendave $
*/
public final class ManaCost implements Comparable<ManaCost> {
public final class ManaCost implements Comparable<ManaCost>, Iterable<ManaCostShard> {
private List<ManaCostShard> shards;
private final int genericCost;
private final boolean hasNoCost; // lands cost
@@ -49,7 +48,7 @@ public final class ManaCost implements Comparable<ManaCost> {
public static final ManaCost FOUR = new ManaCost(4);
public static ManaCost get(int cntColorless) {
switch (cntColorless) {
switch (cntColorless) {
case 0: return ZERO;
case 1: return ONE;
case 2: return TWO;
@@ -58,14 +57,14 @@ public final class ManaCost implements Comparable<ManaCost> {
}
return cntColorless > 0 ? new ManaCost(cntColorless) : NO_COST;
}
// pass mana cost parser here
private ManaCost(int cmc) {
this.hasNoCost = cmc < 0;
this.genericCost = cmc < 0 ? 0 : cmc;
sealClass(new ArrayList<ManaCostShard>());
}
private void sealClass(List<ManaCostShard> shards0) {
this.shards = Collections.unmodifiableList(shards0);
this.stringValue = this.getSimpleString();
@@ -97,22 +96,19 @@ public final class ManaCost implements Comparable<ManaCost> {
return "no cost";
}
if (this.shards.isEmpty()) {
return Integer.toString(this.genericCost);
return "{" + this.genericCost + "}";
}
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
if (this.genericCost > 0) {
sb.append(this.genericCost);
isFirst = false;
sb.append("{" + this.genericCost + "}");
}
for (final ManaCostShard s : this.shards) {
if (!isFirst) {
sb.append(' ');
if (s == ManaCostShard.X) {
sb.insert(0, s.toString());
} else {
isFirst = false;
sb.append(s.toString());
}
sb.append(s.toString());
}
return sb.toString();
}
@@ -143,15 +139,6 @@ public final class ManaCost implements Comparable<ManaCost> {
return result;
}
/**
* Gets the shards.
*
* @return the shards
*/
public List<ManaCostShard> getShards() {
return this.shards;
}
public int getShardCount(ManaCostShard which) {
if (which == ManaCostShard.COLORLESS) {
return genericCost;
@@ -196,7 +183,7 @@ public final class ManaCost implements Comparable<ManaCost> {
public boolean isZero() {
return genericCost == 0 && isPureGeneric();
}
/*
* (non-Javadoc)
*
@@ -260,13 +247,12 @@ public final class ManaCost implements Comparable<ManaCost> {
/**
* Can this mana cost be paid with unlimited mana of given color set.
* @param color
* @param colorCode
* @return
*/
public boolean canBePaidWithAvaliable(ColorSet color) {
public boolean canBePaidWithAvaliable(byte colorCode) {
for (ManaCostShard shard : shards) {
if (!shard.isPhyrexian() && !shard.canBePaidWithManaOfColor(color.getColor())) {
if (!shard.isPhyrexian() && !shard.canBePaidWithManaOfColor(colorCode)) {
return false;
}
}
@@ -288,4 +274,16 @@ public final class ManaCost implements Comparable<ManaCost> {
return res;
}
@Override
public Iterator<ManaCostShard> iterator() {
return this.shards.iterator();
}
public int getGlyphCount() { // counts all colored shards or 1 for {0} costs
int width = shards.size();
if (genericCost > 0 || (genericCost == 0 && width == 0)) {
width++;
}
return width;
}
}

View File

@@ -11,6 +11,17 @@ public class ManaCostParser implements IParserManaCost {
private int nextToken;
private int colorlessCost;
/**
* Parse the given cost and output formatted cost string
*
* @param cost
*/
public static String parse(final String cost) {
final ManaCostParser parser = new ManaCostParser(cost);
final ManaCost manaCost = new ManaCost(parser);
return manaCost.toString();
}
/**
* Instantiates a new parser cardname txt mana cost.
*
@@ -54,7 +65,6 @@ public class ManaCostParser implements IParserManaCost {
*/
@Override
public final ManaCostShard next() {
final String unparsed = this.cost[this.nextToken++];
// System.out.println(unparsed);
if (StringUtils.isNumeric(unparsed)) {

View File

@@ -23,7 +23,7 @@ import forge.util.BinaryUtil;
* The Class CardManaCostShard.
*/
public enum ManaCostShard implements Comparable<ManaCostShard> {
// declaration order matters! Place the shards that offer least ways to be paid for first
// declaration order matters! Place the shards that offer least ways to be paid for first
/* Pure colors */
WHITE(ManaAtom.WHITE, "W"),
@@ -35,14 +35,14 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
/* Hybrid */
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"),
WB(ManaAtom.WHITE | ManaAtom.BLACK, "W/B", "WB"),
WR(ManaAtom.WHITE | ManaAtom.RED, "W/R", "RW"),
WG(ManaAtom.WHITE | ManaAtom.GREEN, "W/G", "GW"),
UB(ManaAtom.BLUE | ManaAtom.BLACK, "U/B", "UB"),
UR(ManaAtom.BLUE | ManaAtom.RED, "U/R", "UR"),
UG(ManaAtom.BLUE | ManaAtom.GREEN, "U/G", "GU"),
BR(ManaAtom.BLACK | ManaAtom.RED, "B/R", "BR"),
BG(ManaAtom.BLACK | ManaAtom.GREEN, "B/G", "BG"),
RW(ManaAtom.RED | ManaAtom.WHITE, "R/W", "RW"),
RG(ManaAtom.RED | ManaAtom.GREEN, "R/G", "RG"),
GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W", "GW"),
GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U", "GU"),
/* Or 2 colorless */
W2(ManaAtom.WHITE | ManaAtom.OR_2_COLORLESS, "2/W", "2W"),
@@ -55,7 +55,7 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
S(ManaAtom.IS_SNOW, "S"),
COLORLESS(ManaAtom.COLORLESS, "1"),
/* Phyrexian */
/* Phyrexian */
PW(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "W/P", "PW"),
PU(ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "U/P", "PU"),
PB(ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "B/P", "PB"),
@@ -102,15 +102,12 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
this.shard = value;
this.cmc = this.getCMC();
this.cmpc = this.getCmpCost();
this.stringValue = sValue;
this.stringValue = "{" + sValue + "}";
this.imageKey = imgKey;
}
public static final int COLORS_SUPERPOSITION = ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.RED | ManaAtom.GREEN;
private int getCMC() {
if (0 != (this.shard & ManaAtom.IS_X)) {
return 0;
@@ -267,7 +264,6 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
public boolean isMonoColor() {
return BinaryUtil.bitCount(this.shard & COLORS_SUPERPOSITION) == 1;
}
public boolean isOr2Colorless() {

View File

@@ -18,7 +18,6 @@
package forge.deck;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -26,10 +25,9 @@ import java.util.NoSuchElementException;
import org.apache.commons.lang3.StringUtils;
import forge.Card;
import forge.card.CardDb;
import forge.StaticData;
import forge.item.PaperCard;
import forge.item.ItemPool;
import forge.util.ItemPool;
/**
* Deck section.
@@ -54,15 +52,6 @@ public class CardPool extends ItemPool<PaperCard> {
this.addAll(cards);
}
/**
* Adds the.
*
* @param card
* the card
*/
public void add(final Card card) {
this.add(CardDb.getCard(card));
}
/**
* Adds the.
@@ -84,9 +73,9 @@ public class CardPool extends ItemPool<PaperCard> {
* @param amount the amount
*/
public void add(final String cardName, final String setCode, final int amount) {
PaperCard cp = CardDb.instance().tryGetCard(cardName, setCode);
PaperCard cp = StaticData.instance().getCommonCards().tryGetCard(cardName, setCode);
if ( cp == null )
cp = CardDb.variants().tryGetCard(cardName, setCode);
cp = StaticData.instance().getVariantCards().tryGetCard(cardName, setCode);
if ( cp != null)
this.add(cp, amount);
@@ -94,18 +83,6 @@ public class CardPool extends ItemPool<PaperCard> {
throw new RuntimeException(String.format("Card %s from %s is not supported by Forge, as it's neither a known common card nor one of casual variants' card.", cardName, setCode ));
}
/**
* Adds the.
*
* @param cardList
* the card list
*/
public void add(final List<Card> cardList) {
for (final Card c : cardList) {
this.add(c);
}
}
/**
* Add all from a List of CardPrinted.
*
@@ -124,9 +101,9 @@ public class CardPool extends ItemPool<PaperCard> {
* @param cardName the card name
*/
public void add(final String cardName, int cnt) {
PaperCard cp = CardDb.instance().tryGetCard(cardName);
PaperCard cp = StaticData.instance().getCommonCards().tryGetCard(cardName);
if ( cp == null )
cp = CardDb.variants().tryGetCard(cardName);
cp = StaticData.instance().getVariantCards().tryGetCard(cardName);
if ( cp != null)
this.add(cp, cnt);

View File

@@ -35,12 +35,12 @@ import com.google.common.base.Function;
import forge.card.CardDb;
import forge.deck.io.DeckFileHeader;
import forge.deck.io.DeckSerializer;
import forge.item.ItemPoolSorter;
import forge.item.PaperCard;
import forge.item.IPaperCard;
import forge.item.ItemPoolView;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.ItemPoolSorter;
import forge.util.ItemPoolView;
/**

View File

@@ -52,8 +52,8 @@ public abstract class DeckBase implements Serializable, Comparable<DeckBase>, IH
/** {@inheritDoc} */
@Override
public boolean equals(final Object o) {
if (o instanceof Deck) {
final Deck d = (Deck) o;
if (o instanceof DeckBase) {
final DeckBase d = (DeckBase) o;
return this.getName().equals(d.getName());
}
return false;

View File

@@ -22,43 +22,37 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.lang.math.IntRange;
import forge.Singletons;
import forge.card.CardCoreType;
import forge.card.CardDb;
import org.apache.commons.lang3.Range;
import forge.StaticData;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.item.PaperCard;
import forge.item.IPaperCard;
import forge.properties.ForgePreferences.FPref;
import forge.util.Aggregates;
/**
* GameType is an enum to determine the type of current game. :)
*/
public enum DeckFormat {
// Main board: allowed size SB: restriction Max distinct non basic cards
Constructed ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0, 15), 4),
QuestDeck ( new IntRange(40, Integer.MAX_VALUE), new IntRange(0, 15), 4),
Limited ( new IntRange(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
Commander ( new IntRange(99), new IntRange(0, 10), 1),
Vanguard ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
Planechase ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
Archenemy ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4);
Constructed ( Range.between(60, Integer.MAX_VALUE), Range.between(0, 15), 4),
QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4),
Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
Commander ( Range.is(99), Range.between(0, 10), 1),
Vanguard ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
Planechase ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
Archenemy ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4);
private final IntRange mainRange;
private final IntRange sideRange; // null => no check
private final Range<Integer> mainRange;
private final Range<Integer> sideRange; // null => no check
private final int maxCardCopies;
/**
* Instantiates a new game type.
*
* @param isLimited
* the is limited
*/
DeckFormat(IntRange main, IntRange side, int maxCopies) {
DeckFormat(Range<Integer> main, Range<Integer> side, int maxCopies) {
mainRange = main;
sideRange = side;
maxCardCopies = maxCopies;
@@ -90,7 +84,7 @@ public enum DeckFormat {
/**
* @return the sideRange
*/
public IntRange getSideRange() {
public Range<Integer> getSideRange() {
return sideRange;
}
@@ -98,7 +92,7 @@ public enum DeckFormat {
/**
* @return the mainRange
*/
public IntRange getMainRange() {
public Range<Integer> getMainRange() {
return mainRange;
}
@@ -118,15 +112,10 @@ public enum DeckFormat {
return "is not selected";
}
// That's really a bad dependence
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
return null;
}
int deckSize = deck.getMain().countAll();
int min = getMainRange().getMinimumInteger();
int max = getMainRange().getMaximumInteger();
int min = getMainRange().getMinimum();
int max = getMainRange().getMaximum();
if (deckSize < min) {
return String.format("should have a minimum of %d cards", min);
@@ -189,7 +178,7 @@ public enum DeckFormat {
int phenoms = 0;
for (Entry<PaperCard, Integer> cp : planes) {
if (cp.getKey().getRules().getType().typeContains(CardCoreType.Phenomenon)) {
if (cp.getKey().getRules().getType().typeContains(CardType.CoreType.Phenomenon)) {
phenoms++;
}
if (cp.getValue() > 1) {
@@ -233,7 +222,7 @@ public enum DeckFormat {
// should group all cards by name, so that different editions of same card are really counted as the same card
for (Entry<String, Integer> cp : Aggregates.groupSumBy(tmp, PaperCard.FN_GET_NAME)) {
IPaperCard simpleCard = CardDb.instance().getCard(cp.getKey());
IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
boolean canHaveMultiple = simpleCard.getRules().getType().isBasicLand() || limitExceptions.contains(cp.getKey());
if (!canHaveMultiple && cp.getValue() > maxCopies) {
@@ -244,11 +233,11 @@ public enum DeckFormat {
// The sideboard must contain either 0 or 15 cards
int sideboardSize = deck.has(DeckSection.Sideboard) ? deck.get(DeckSection.Sideboard).countAll() : 0;
IntRange sbRange = getSideRange();
if (sbRange != null && sideboardSize > 0 && !sbRange.containsInteger(sideboardSize)) {
return sbRange.getMinimumInteger() == sbRange.getMaximumInteger()
? String.format("must have a sideboard of %d cards or no sideboard at all", sbRange.getMaximumInteger())
: String.format("must have a sideboard of %d to %d cards or no sideboard at all", sbRange.getMinimumInteger(), sbRange.getMaximumInteger());
Range<Integer> sbRange = getSideRange();
if (sbRange != null && sideboardSize > 0 && !sbRange.contains(sideboardSize)) {
return sbRange.getMinimum() == sbRange.getMaximum()
? String.format("must have a sideboard of %d cards or no sideboard at all", sbRange.getMaximum())
: String.format("must have a sideboard of %d to %d cards or no sideboard at all", sbRange.getMinimum(), sbRange.getMaximum());
}
return null;

View File

@@ -167,9 +167,9 @@ public class DeckRecognizer {
private final ICardDatabase db;
private Date recognizeCardsPrintedBefore = null;
public DeckRecognizer(boolean fromLatestSet) {
public DeckRecognizer(boolean fromLatestSet, CardDb db) {
useLastSet = fromLatestSet;
db = CardDb.instance();
this.db = db;
}
public Token recognizeLine(final String rawLine) {

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.generate;
package forge.deck.generation;
import java.util.Arrays;
import java.util.List;
@@ -24,10 +24,10 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.item.PaperCard;
import forge.item.ItemPoolView;
import forge.util.ItemPoolView;
/**
* <p>
@@ -37,17 +37,17 @@ import forge.item.ItemPoolView;
* @author Forge
* @version $Id$
*/
public class Generate2ColorDeck extends GenerateColoredDeckBase {
public class DeckGenerator2Color extends DeckGeneratorBase {
@Override protected final float getLandsPercentage() { return 0.39f; }
@Override protected final float getCreatPercentage() { return 0.36f; }
@Override protected final float getSpellPercentage() { return 0.25f; }
@SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcRelativeWeights = Lists.newArrayList(
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(0, 2), 6),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(3, 4), 4),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(5, 6), 2),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(7, 20), 1)
ImmutablePair.of(new FilterCMC(0, 2), 6),
ImmutablePair.of(new FilterCMC(3, 4), 4),
ImmutablePair.of(new FilterCMC(5, 6), 2),
ImmutablePair.of(new FilterCMC(7, 20), 1)
);
// mana curve of the card pool
@@ -67,7 +67,8 @@ public class Generate2ColorDeck extends GenerateColoredDeckBase {
* @param clr2
* a {@link java.lang.String} object.
*/
public Generate2ColorDeck(final String clr1, final String clr2) {
public DeckGenerator2Color(ICardDatabase cardDb, final String clr1, final String clr2) {
super(cardDb);
int c1 = MagicColor.fromName(clr1);
int c2 = MagicColor.fromName(clr2);
@@ -96,7 +97,7 @@ public class Generate2ColorDeck extends GenerateColoredDeckBase {
tmpDeck.append(String.format("Adjusted deck size to: %d, should add %d land(s)%n", size - numLands, numLands));
// Add dual lands
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
List<String> duals = getDualLandList();
for (String s : duals) {
this.cardCounts.put(s, 0);
}

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.generate;
package forge.deck.generation;
import java.util.List;
@@ -24,10 +24,10 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.item.PaperCard;
import forge.item.ItemPoolView;
import forge.util.ItemPoolView;
import forge.util.MyRandom;
/**
@@ -38,12 +38,12 @@ import forge.util.MyRandom;
* @author Forge
* @version $Id$
*/
public class Generate3ColorDeck extends GenerateColoredDeckBase {
public class DeckGenerator3Color extends DeckGeneratorBase {
@SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(0, 2), 12),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(3, 5), 9),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(6, 20), 3)
ImmutablePair.of(new FilterCMC(0, 2), 12),
ImmutablePair.of(new FilterCMC(3, 5), 9),
ImmutablePair.of(new FilterCMC(6, 20), 3)
);
/**
@@ -58,7 +58,8 @@ public class Generate3ColorDeck extends GenerateColoredDeckBase {
* @param clr3
* a {@link java.lang.String} object.
*/
public Generate3ColorDeck(final String clr1, final String clr2, final String clr3) {
public DeckGenerator3Color(ICardDatabase cardDb, final String clr1, final String clr2, final String clr3) {
super(cardDb);
int c1 = MagicColor.fromName(clr1);
int c2 = MagicColor.fromName(clr2);
int c3 = MagicColor.fromName(clr3);
@@ -105,7 +106,7 @@ public class Generate3ColorDeck extends GenerateColoredDeckBase {
tmpDeck.append("numLands:").append(numLands).append("\n");
// Add dual lands
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
List<String> duals = getDualLandList();
for (String s : duals) {
this.cardCounts.put(s, 0);
}

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.generate;
package forge.deck.generation;
import java.util.List;
@@ -24,9 +24,9 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.card.ICardDatabase;
import forge.item.PaperCard;
import forge.item.ItemPoolView;
import forge.util.ItemPoolView;
/**
* <p>
@@ -36,12 +36,12 @@ import forge.item.ItemPoolView;
* @author Forge
* @version $Id$
*/
public class Generate5ColorDeck extends GenerateColoredDeckBase {
public class DeckGenerator5Color extends DeckGeneratorBase {
@SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(0, 2), 3),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(3, 5), 2),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(6, 20), 1)
ImmutablePair.of(new FilterCMC(0, 2), 3),
ImmutablePair.of(new FilterCMC(3, 5), 2),
ImmutablePair.of(new FilterCMC(6, 20), 1)
);
// resulting mana curve of the card pool
@@ -53,7 +53,8 @@ public class Generate5ColorDeck extends GenerateColoredDeckBase {
/**
* Instantiates a new generate5 color deck.
*/
public Generate5ColorDeck() {
public DeckGenerator5Color(ICardDatabase cardDb) {
super(cardDb);
colors = ColorSet.fromMask(0).inverse();
}
@@ -68,7 +69,7 @@ public class Generate5ColorDeck extends GenerateColoredDeckBase {
tmpDeck.append("numLands:").append(numLands).append("\n");
// Add dual lands
List<String> duals = GenerateDeckUtil.getDualLandList(colors);
List<String> duals = getDualLandList();
for (String s : duals) {
this.cardCounts.put(s, 0);
}

View File

@@ -15,8 +15,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.generate;
package forge.deck.generation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,19 +32,16 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.Constant;
import forge.Singletons;
import forge.card.CardDb;
import forge.card.CardRules;
import forge.card.CardRulesPredicates;
import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.card.mana.ManaCost;
import forge.item.PaperCard;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.properties.ForgePreferences.FPref;
import forge.util.Aggregates;
import forge.util.ItemPool;
import forge.util.ItemPoolView;
import forge.util.MyRandom;
/**
@@ -54,13 +52,15 @@ import forge.util.MyRandom;
* @author Forge
* @version $Id: Generate2ColorDeck.java 14959 2012-03-28 14:03:43Z Chris H. $
*/
public abstract class GenerateColoredDeckBase {
public abstract class DeckGeneratorBase {
protected final Random r = MyRandom.getRandom();
protected final Map<String, Integer> cardCounts = new HashMap<String, Integer>();
protected int maxDuplicates;
protected int maxDuplicates = 4;
protected boolean useArtifacts = true;
protected ColorSet colors;
protected final ItemPool<PaperCard> tDeck;
protected final ItemPool<PaperCard> tDeck = new ItemPool<PaperCard>(PaperCard.class);
protected final ICardDatabase cardDb;
// 2-colored deck generator has its own constants. The rest works fine with these ones
protected float getLandsPercentage() { return 0.44f; }
@@ -69,9 +69,15 @@ public abstract class GenerateColoredDeckBase {
StringBuilder tmpDeck = new StringBuilder();
public GenerateColoredDeckBase() {
this.maxDuplicates = Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS) ? 1 : 4;
tDeck = new ItemPool<PaperCard>(PaperCard.class);
public DeckGeneratorBase(ICardDatabase cardDb) {
this.cardDb = cardDb;
}
public void setSingleton(boolean singleton){
this.maxDuplicates = singleton ? 1 : 4;
}
public void setUseArtifacts(boolean value) {
this.useArtifacts = value;
}
protected void addCreaturesAndSpells(int size, List<ImmutablePair<FilterCMC, Integer>> cmcLevels, boolean forAi) {
@@ -132,8 +138,7 @@ public abstract class GenerateColoredDeckBase {
} while ((this.cardCounts.get(s) > 3) && (lc <= 20));
// not an error if looped too much - could play singleton mode, with 6 slots for 3 non-basic lands.
PaperCard cp = CardDb.instance().getCard(s);
tDeck.add(CardDb.instance().getCard(cp.getName(), false));
tDeck.add(cardDb.getCard(s, false));
final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1);
@@ -159,20 +164,20 @@ public abstract class GenerateColoredDeckBase {
int landsLeft = cnt;
for (Entry<String, Integer> c : clrCnts.entrySet()) {
String color = c.getKey();
String basicLandName = c.getKey();
// calculate number of lands for each color
final int nLand = Math.min(landsLeft, Math.round(cnt * c.getValue() / totalColor));
tmpDeck.append("nLand-").append(color).append(":").append(nLand).append("\n");
tmpDeck.append("nLand-").append(basicLandName).append(":").append(nLand).append("\n");
// just to prevent a null exception by the deck size fixing code
this.cardCounts.put(color, nLand);
this.cardCounts.put(basicLandName, nLand);
PaperCard cp = CardDb.instance().getCard(color);
PaperCard cp = cardDb.getCard(basicLandName);
String basicLandSet = cp.getEdition();
tDeck.add(CardDb.instance().getCard(cp.getName(), basicLandSet), nLand);
tDeck.add(cardDb.getCard(cp.getName(), basicLandSet), nLand);
landsLeft -= nLand;
}
}
@@ -222,7 +227,7 @@ public abstract class GenerateColoredDeckBase {
final List<PaperCard> curvedRandomized = Lists.newArrayList();
for (PaperCard c : curved) {
this.cardCounts.put(c.getName(), 0);
curvedRandomized.add(CardDb.instance().getCard(c.getName(), false));
curvedRandomized.add(cardDb.getCard(c.getName(), false));
}
addSome(addOfThisCmc, curvedRandomized);
@@ -233,13 +238,13 @@ public abstract class GenerateColoredDeckBase {
// start with all cards
// remove cards that generated decks don't like
Predicate<CardRules> canPlay = forAi ? GenerateDeckUtil.AI_CAN_PLAY : GenerateDeckUtil.HUMAN_CAN_PLAY;
Predicate<CardRules> hasColor = new GenerateDeckUtil.MatchColorIdentity(colors);
Predicate<CardRules> canPlay = forAi ? AI_CAN_PLAY : HUMAN_CAN_PLAY;
Predicate<CardRules> hasColor = new MatchColorIdentity(colors);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) {
hasColor = Predicates.or(hasColor, GenerateDeckUtil.COLORLESS_CARDS);
if (useArtifacts) {
hasColor = Predicates.or(hasColor, COLORLESS_CARDS);
}
return Iterables.filter(CardDb.instance().getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor), PaperCard.FN_GET_RULES));
return Iterables.filter(cardDb.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor), PaperCard.FN_GET_RULES));
}
protected static Map<String, Integer> countLands(ItemPool<PaperCard> outList) {
@@ -254,15 +259,15 @@ public abstract class GenerateColoredDeckBase {
int profile = cpe.getKey().getRules().getManaCost().getColorProfile();
if ((profile & MagicColor.WHITE) != 0) {
increment(res, Constant.Color.BASIC_LANDS.get(0), cpe.getValue());
increment(res, MagicColor.Constant.BASIC_LANDS.get(0), cpe.getValue());
} else if ((profile & MagicColor.BLUE) != 0) {
increment(res, Constant.Color.BASIC_LANDS.get(1), cpe.getValue());
increment(res, MagicColor.Constant.BASIC_LANDS.get(1), cpe.getValue());
} else if ((profile & MagicColor.BLACK) != 0) {
increment(res, Constant.Color.BASIC_LANDS.get(2), cpe.getValue());
increment(res, MagicColor.Constant.BASIC_LANDS.get(2), cpe.getValue());
} else if ((profile & MagicColor.RED) != 0) {
increment(res, Constant.Color.BASIC_LANDS.get(3), cpe.getValue());
increment(res, MagicColor.Constant.BASIC_LANDS.get(3), cpe.getValue());
} else if ((profile & MagicColor.GREEN) != 0) {
increment(res, Constant.Color.BASIC_LANDS.get(4), cpe.getValue());
increment(res, MagicColor.Constant.BASIC_LANDS.get(4), cpe.getValue());
}
}
@@ -274,4 +279,127 @@ public abstract class GenerateColoredDeckBase {
final Integer boxed = map.get(key);
map.put(key, boxed == null ? delta : boxed.intValue() + delta);
}
public static final Predicate<CardRules> AI_CAN_PLAY = new Predicate<CardRules>() {
@Override
public boolean apply(CardRules c) {
return !c.getAiHints().getRemAIDecks() && !c.getAiHints().getRemRandomDecks();
}
};
public static final Predicate<CardRules> HUMAN_CAN_PLAY = new Predicate<CardRules>() {
@Override
public boolean apply(CardRules c) {
return !c.getAiHints().getRemRandomDecks();
}
};
public static final Predicate<CardRules> COLORLESS_CARDS = new Predicate<CardRules>() {
@Override
public boolean apply(CardRules c) {
ManaCost mc = c.getManaCost();
return c.getColorIdentity().isColorless() && !mc.isNoCost();
}
};
public static class MatchColorIdentity implements Predicate<CardRules> {
private final ColorSet allowedColor;
public MatchColorIdentity(ColorSet color) {
allowedColor = color;
}
@Override
public boolean apply(CardRules subject) {
ManaCost mc = subject.getManaCost();
return !mc.isPureGeneric() && allowedColor.containsAllColorsFrom(subject.getColorIdentity().getColor());
//return mc.canBePaidWithAvaliable(allowedColor);
// return allowedColor.containsAllColorsFrom(mc.getColorProfile());
}
}
public static class FilterCMC implements Predicate<CardRules> {
private final int min;
private final int max;
public FilterCMC(int from, int to) {
min = from;
max = to;
}
@Override
public boolean apply(CardRules c) {
ManaCost mc = c.getManaCost();
int cmc = mc.getCMC();
return cmc >= min && cmc <= max && !mc.isNoCost();
}
}
private static Map<Integer, String[]> dualLands = new HashMap<Integer, String[]>();
static {
dualLands.put(MagicColor.WHITE | MagicColor.BLUE, new String[] { "Tundra", "Hallowed Fountain", "Flooded Strand" });
dualLands.put(MagicColor.BLACK | MagicColor.BLUE, new String[] { "Underground Sea", "Watery Grave", "Polluted Delta" });
dualLands.put(MagicColor.BLACK | MagicColor.RED, new String[] { "Badlands", "Blood Crypt", "Bloodstained Mire" });
dualLands.put(MagicColor.GREEN | MagicColor.RED, new String[] { "Taiga", "Stomping Ground", "Wooded Foothills" });
dualLands.put(MagicColor.GREEN | MagicColor.WHITE, new String[] { "Savannah", "Temple Garden", "Windswept Heath" });
dualLands.put(MagicColor.WHITE | MagicColor.BLACK, new String[] { "Scrubland", "Godless Shrine", "Marsh Flats" });
dualLands.put(MagicColor.BLUE | MagicColor.RED, new String[] { "Volcanic Island", "Steam Vents", "Scalding Tarn" });
dualLands.put(MagicColor.BLACK | MagicColor.GREEN, new String[] { "Bayou", "Overgrown Tomb", "Verdant Catacombs" });
dualLands.put(MagicColor.WHITE | MagicColor.RED, new String[] { "Plateau", "Sacred Foundry", "Arid Mesa" });
dualLands.put(MagicColor.GREEN | MagicColor.BLUE, new String[] { "Tropical Island", "Breeding Pool", "Misty Rainforest" });
}
/**
* Get list of dual lands for this color combo.
*
* @param color
* the color
* @return dual land names
*/
protected List<String> getDualLandList() {
final List<String> dLands = new ArrayList<String>();
if (colors.countColors() > 3) {
dLands.add("Rupture Spire");
dLands.add("Undiscovered Paradise");
}
if (colors.countColors() > 2) {
dLands.add("Evolving Wilds");
dLands.add("Terramorphic Expanse");
}
for (Entry<Integer, String[]> dual : dualLands.entrySet()) {
if (colors.hasAllColors(dual.getKey())) {
for (String s : dual.getValue()) {
dLands.add(s);
}
}
}
return dLands;
}
/**
* Get all dual lands that do not match this color combo.
*
* @param color
* the color
* @return dual land names
*/
protected List<String> getInverseDualLandList() {
final List<String> dLands = new ArrayList<String>();
for (Entry<Integer, String[]> dual : dualLands.entrySet()) {
if (!colors.hasAllColors(dual.getKey())) {
for (String s : dual.getValue()) {
dLands.add(s);
}
}
}
return dLands;
}
}

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.generate;
package forge.deck.generation;
import java.util.List;
@@ -24,10 +24,10 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.Lists;
import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.item.PaperCard;
import forge.item.ItemPoolView;
import forge.util.ItemPoolView;
/**
* <p>
@@ -37,17 +37,17 @@ import forge.item.ItemPoolView;
* @author Forge
* @version $Id: Generate2ColorDeck.java 19765 2013-02-20 03:01:37Z myk $
*/
public class GenerateMonoColorDeck extends GenerateColoredDeckBase {
public class DeckGeneratorMonoColor extends DeckGeneratorBase {
@Override protected final float getLandsPercentage() { return 0.39f; }
@Override protected final float getCreatPercentage() { return 0.36f; }
@Override protected final float getSpellPercentage() { return 0.25f; }
@SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(0, 2), 10),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(3, 4), 8),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(5, 6), 5),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(7, 20), 3)
ImmutablePair.of(new FilterCMC(0, 2), 10),
ImmutablePair.of(new FilterCMC(3, 4), 8),
ImmutablePair.of(new FilterCMC(5, 6), 5),
ImmutablePair.of(new FilterCMC(7, 20), 3)
);
// mana curve of the card pool
@@ -67,7 +67,8 @@ public class GenerateMonoColorDeck extends GenerateColoredDeckBase {
* @param clr2
* a {@link java.lang.String} object.
*/
public GenerateMonoColorDeck(final String clr1) {
public DeckGeneratorMonoColor(ICardDatabase cardDb, final String clr1) {
super(cardDb);
if (MagicColor.fromName(clr1) == 0) {
int color1 = r.nextInt(5);
colors = ColorSet.fromMask(MagicColor.WHITE << color1);

View File

@@ -0,0 +1,3 @@
/** Forge Card Game. */
package forge.deck.generation;

View File

@@ -23,7 +23,6 @@ import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import forge.deck.DeckFormat;
import forge.game.player.PlayerType;
import forge.util.FileSection;
/**
@@ -48,7 +47,6 @@ public class DeckFileHeader {
private static final String PLAYER_TYPE = "PlayerType";
private final DeckFormat deckType;
private final PlayerType playerType;
private final boolean customPool;
private final String name;
@@ -56,6 +54,15 @@ public class DeckFileHeader {
private final Set<String> tags;
private final boolean intendedForAi;
/**
* @return the intendedForAi
*/
public boolean isIntendedForAi() {
return intendedForAi;
}
/**
* TODO: Write javadoc for Constructor.
*
@@ -67,8 +74,7 @@ public class DeckFileHeader {
this.comment = kvPairs.get(DeckFileHeader.COMMENT);
this.deckType = DeckFormat.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), DeckFormat.Constructed);
this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL);
boolean isForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
this.playerType = isForAi ? PlayerType.COMPUTER : PlayerType.HUMAN;
this.intendedForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
this.tags = new TreeSet<String>();
String rawTags = kvPairs.get(DeckFileHeader.TAGS);
@@ -81,15 +87,6 @@ public class DeckFileHeader {
}
/**
* Gets the player type.
*
* @return the player type
*/
public final PlayerType getPlayerType() {
return this.playerType;
}
/**
* Checks if is custom pool.
*

View File

@@ -0,0 +1,135 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.deck.io;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import forge.deck.Deck;
import forge.util.FileSection;
import forge.util.FileSectionManual;
import forge.util.FileUtil;
import forge.util.IItemReader;
import forge.util.IItemSerializer;
import forge.util.storage.StorageReaderFolder;
/**
* This class knows how to make a file out of a deck object and vice versa.
*/
public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSerializer<Deck> {
private final boolean moveWronglyNamedDecks;
public static final String FILE_EXTENSION = ".dck";
public DeckSerializer(final File deckDir0) {
this(deckDir0, false);
}
public DeckSerializer(final File deckDir0, boolean moveWrongDecks) {
super(deckDir0, Deck.FN_NAME_SELECTOR);
moveWronglyNamedDecks = moveWrongDecks;
}
/** Constant <code>DCKFileFilter</code>. */
public static final FilenameFilter DCK_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(FILE_EXTENSION);
}
};
public static void writeDeck(final Deck d, final File f) {
FileUtil.writeFile(f, d.save());
}
@Override
public void save(final Deck unit) {
FileUtil.writeFile(this.makeFileFor(unit), unit.save());
}
@Override
public void erase(final Deck unit) {
this.makeFileFor(unit).delete();
}
public File makeFileFor(final Deck deck) {
return new File(this.directory, deck.getBestFileName() + FILE_EXTENSION);
}
@Override
protected Deck read(final File file) {
final Map<String, List<String>> sections = FileSection.parseSections(FileUtil.readFile(file));
Deck result = Deck.fromSections(sections, true);
if (moveWronglyNamedDecks) {
adjustFileLocation(file, result);
}
return result;
}
private void adjustFileLocation(final File file, final Deck result) {
if (result == null) {
file.delete();
} else {
String destFilename = result.getBestFileName() + FILE_EXTENSION;
if (!file.getName().equals(destFilename)) {
file.renameTo(new File(file.getParentFile().getParentFile(), destFilename));
}
}
}
@Override
protected FilenameFilter getFileFilter() {
return DeckSerializer.DCK_FILE_FILTER;
}
public static DeckFileHeader readDeckMetadata(final Map<String, List<String>> map, final boolean canThrow) {
if (map == null) {
return null;
}
final List<String> metadata = map.get("metadata");
if (metadata != null) {
return new DeckFileHeader(FileSection.parse(metadata, "="));
}
final List<String> general = map.get("general");
if (general != null) {
if (canThrow) {
throw new OldDeckFileFormatException();
}
final FileSectionManual fs = new FileSectionManual();
fs.put(DeckFileHeader.NAME, StringUtils.join(map.get(""), " "));
fs.put(DeckFileHeader.DECK_TYPE, StringUtils.join(general, " "));
return new DeckFileHeader(fs);
}
return null;
}
/* (non-Javadoc)
* @see forge.util.storage.StorageReaderBase#getReaderForFolder(java.io.File)
*/
@Override
public IItemReader<Deck> getReaderForFolder(File subfolder) {
if ( !subfolder.getParentFile().equals(directory) )
throw new UnsupportedOperationException("Only child folders of " + directory + " may be processed");
return new DeckSerializer(subfolder, false);
}
}

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge.deck.io;

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge.deck;

View File

@@ -20,26 +20,25 @@ package forge.item;
import com.google.common.base.Function;
import forge.Singletons;
import forge.StaticData;
import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
import forge.util.MyRandom;
public class BoosterPack extends OpenablePack {
public class BoosterPack extends SealedProduct {
private final int artIndex;
private final int hash;
public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() {
@Override
public BoosterPack apply(final CardEdition arg1) {
SealedProductTemplate d = Singletons.getModel().getBoosters().get(arg1.getCode());
Template d = StaticData.instance().getBoosters().get(arg1.getCode());
return new BoosterPack(arg1.getName(), d);
}
};
public BoosterPack(final String name0, final SealedProductTemplate boosterData) {
public BoosterPack(final String name0, final Template boosterData) {
super(name0, boosterData);
int maxIdx = Singletons.getModel().getEditions().get(boosterData.getEdition()).getCntBoosterPictures();
int maxIdx = StaticData.instance().getEditions().get(boosterData.getEdition()).getCntBoosterPictures();
artIndex = MyRandom.getRandom().nextInt(maxIdx) + 1;
hash = super.hashCode() ^ artIndex;
}
@@ -58,7 +57,7 @@ public class BoosterPack extends OpenablePack {
return new BoosterPack(name, contents);
}
public SealedProductTemplate getBoosterData() {
public Template getBoosterData() {
return contents;
}

View File

@@ -0,0 +1,141 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.item;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.CardEdition;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFile;
public class FatPack extends SealedProduct {
public static final Function<CardEdition, FatPack> FN_FROM_SET = new Function<CardEdition, FatPack>() {
@Override
public FatPack apply(final CardEdition arg1) {
FatPack.Template d = StaticData.instance().getFatPacks().get(arg1.getCode());
return new FatPack(arg1.getName(), d);
}
};
private final FatPack.Template fpData;
public FatPack(final String name0, final FatPack.Template fpData0) {
super(name0, StaticData.instance().getBoosters().get(fpData0.getEdition()));
fpData = fpData0;
}
@Override
public String getDescription() {
return fpData.toString() + contents.toString();
}
@Override
public final String getItemType() {
return "Fat Pack";
}
@Override
protected List<PaperCard> generate() {
List<PaperCard> result = new ArrayList<PaperCard>();
for (int i = 0; i < fpData.getCntBoosters(); i++) {
result.addAll(super.generate());
}
result.addAll(BoosterGenerator.getBoosterPack(fpData));
return result;
}
@Override
public final Object clone() {
return new FatPack(name, fpData);
}
@Override
public int getTotalCards() {
return super.getTotalCards() * fpData.getCntBoosters() + fpData.getNumberOfCardsExpected();
}
public static class Template extends SealedProduct.Template {
private final int cntBoosters;
public int getCntBoosters() { return cntBoosters; }
private Template(String edition, int boosters, Iterable<Pair<String, Integer>> itrSlots)
{
super(edition, itrSlots);
cntBoosters = boosters;
}
public static final class Reader extends StorageReaderFile<Template> {
public Reader(String pathname) {
super(pathname, Template.FN_GET_NAME);
}
@Override
protected Template read(String line, int i) {
String[] headAndData = TextUtil.split(line, ':', 2);
final String edition = headAndData[0];
final String[] data = TextUtil.splitWithParenthesis(headAndData[1], ',');
int nBoosters = 6;
List<Pair<String, Integer>> slots = new ArrayList<Pair<String,Integer>>();
for(String slotDesc : data) {
String[] kv = TextUtil.split(slotDesc, ' ', 2);
if (kv[1].startsWith("Booster"))
nBoosters = Integer.parseInt(kv[0]);
else
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
}
return new FatPack.Template(edition, nBoosters, slots);
}
}
@Override
public String toString() {
if (0 >= cntBoosters) {
return "no cards";
}
StringBuilder s = new StringBuilder();
for(Pair<String, Integer> p : slots) {
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
}
// trim the last comma and space
if( s.length() > 0 )
s.replace(s.length() - 2, s.length(), "");
if (0 < cntBoosters) {
if( s.length() > 0 )
s.append(" and ");
s.append(cntBoosters).append(" booster packs ");
}
return s.toString();
}
}
}

View File

@@ -9,10 +9,9 @@ import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.Card;
//import forge.Card;
import forge.card.CardRarity;
import forge.card.CardRules;
import forge.game.player.Player;
import forge.util.PredicateString;
public interface IPaperCard extends InventoryItem {
@@ -161,7 +160,4 @@ public interface IPaperCard extends InventoryItem {
public abstract String getItemType();
public abstract Card getMatchingForgeCard();
public abstract Card toForgeCard(Player owner);
}

View File

@@ -57,9 +57,6 @@ public abstract class ItemPredicate {
public static class Presets {
/** The Item IsPack. */
@SuppressWarnings("unchecked")
public static final Predicate<InventoryItem> IS_PACK = Predicates.or(IsBoosterPack, IsFatPack, IsTournamentPack);
/** The Item IsDeck. */
public static final Predicate<InventoryItem> IS_DECK = Predicates.or(IsStarterDeck, IsPrebuiltDeck);
public static final Predicate<InventoryItem> IS_PACK_OR_DECK = Predicates.or(IsBoosterPack, IsFatPack, IsTournamentPack, IsStarterDeck, IsPrebuiltDeck);
}
}

View File

@@ -17,30 +17,22 @@
*/
package forge.item;
import java.util.HashMap;
import java.util.Map;
import com.google.common.base.Function;
import forge.Card;
import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.cardfactory.CardFactory;
import forge.game.player.Player;
/**
* A viciously lightweight version of a card, for instances
* where a full set of meta and rules is not needed.
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
* <br><br>
* The full set of rules is in the CardRules class.
*
* @author Forge
* @version $Id: CardReference.java 9708 2011-08-09 19:34:12Z jendave $
*/
public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
// Reference to rules
private final transient CardRules card;
private final transient CardRules rules;
// These fields are kinda PK for PrintedCard
public final String name;
@@ -55,7 +47,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public String getName() {
return this.name;
}
@Override
public String getEdition() {
return this.edition;
@@ -78,7 +70,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
@Override
public CardRules getRules() {
return this.card;
return this.rules;
}
@Override
@@ -86,15 +78,11 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
return this.rarity;
}
// @Override
// public String getImageKey() {
// return getImageLocator(getImageName(), getArtIndex(), true, false);
// }
@Override
public String getItemType() {
return "Card";
@@ -106,7 +94,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() {
@Override
public CardRules apply(final PaperCard from) {
return from.card;
return from.rules;
}
};
public static final Function<PaperCard, String> FN_GET_NAME = new Function<PaperCard, String>() {
@@ -114,16 +102,16 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public String apply(final PaperCard from) {
return from.getName();
}
};
};
public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index) {
this(c, edition0, rare, index, false);
}
public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index, final boolean foil) {
if ( edition0 == null || c == null || rare == null )
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
this.card = c;
this.rules = c;
this.name = c.getName();
this.edition = edition0;
this.artIndex = index;
@@ -184,34 +172,6 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
// return String.format("%s|%s", name, cardSet);
}
/**
* To forge card.
*
* @return the card
*/
private static final Map<PaperCard, Card> cp2card = new HashMap<PaperCard, Card>();
/* (non-Javadoc)
* @see forge.item.ICardPrinted#getMatchingForgeCard()
*/
@Override
public Card getMatchingForgeCard() {
Card res = cp2card.get(this);
if (null == res) {
res = toForgeCard(null);
cp2card.put(this, res);
}
return res;
}
/* (non-Javadoc)
* @see forge.item.ICardPrinted#toForgeCard(forge.game.player.Player)
*/
@Override
public Card toForgeCard(Player owner) {
final Card c = CardFactory.getCard(this, owner);
return c;
}
/*
* (non-Javadoc)
*

View File

@@ -2,12 +2,10 @@ package forge.item;
import java.util.Locale;
import forge.Card;
import forge.card.CardEdition;
import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.cardfactory.CardFactory;
import forge.game.player.Player;
public class PaperToken implements InventoryItemFromSet, IPaperCard {
private String name;
@@ -61,13 +59,6 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
public String getImageFilename() { return imageFileName; }
@Override public String getItemType() { return "Token"; }
@Override public Card getMatchingForgeCard() { return toForgeCard(null); } // hope this won't be queried too frequently, so no cache
@Override
public Card toForgeCard(Player owner) {
final Card c = CardFactory.getCard(this, owner);
return c;
}
@Override public boolean isToken() { return true; }
}

View File

@@ -18,29 +18,30 @@
package forge.item;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
import forge.Singletons;
import forge.StaticData;
import forge.deck.Deck;
import forge.quest.SellRules;
import forge.deck.io.DeckSerializer;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.storage.StorageReaderFolder;
/**
* TODO: Write javadoc for this type.
*
*/
public class PreconDeck implements InventoryItemFromSet {
private final Deck deck;
private final String imageFilename;
private final String set;
private final String description;
private final SellRules recommendedDeals;
private String imageFilename;
// private final SellRules recommendedDeals;
/*
* (non-Javadoc)
@@ -62,34 +63,12 @@ public class PreconDeck implements InventoryItemFromSet {
return "Prebuilt Deck";
}
/**
* Instantiates a new precon deck.
*
* @param f
* the f
*/
public PreconDeck(final File f) {
final List<String> deckLines = FileUtil.readFile(f);
final Map<String, List<String>> sections = FileSection.parseSections(deckLines);
this.deck = Deck.fromSections(sections);
FileSection kv = FileSection.parse(sections.get("metadata"), "=");
imageFilename = kv.get("Image");
description = kv.get("Description");
String deckEdition = kv.get("set");
this.set = deckEdition == null || Singletons.getModel().getEditions().get(deckEdition.toUpperCase()) == null ? "n/a" : deckEdition;
this.recommendedDeals = new SellRules(sections.get("shop"));
public PreconDeck(final Deck d, String set, String description) {
deck = d;
this.set = set;
this.description = description;
}
/**
* Gets the deck.
*
* @return the deck
*/
public final Deck getDeck() {
return this.deck;
}
@@ -99,9 +78,9 @@ public class PreconDeck implements InventoryItemFromSet {
*
* @return the recommended deals
*/
public final SellRules getRecommendedDeals() {
return this.recommendedDeals;
}
// public final SellRules getRecommendedDeals() {
// return this.recommendedDeals;
// }
public final String getImageFilename() {
return imageFilename;
@@ -133,4 +112,31 @@ public class PreconDeck implements InventoryItemFromSet {
}
};
public static class Reader extends StorageReaderFolder<PreconDeck> {
public Reader(final File deckDir0) {
super(deckDir0, PreconDeck.FN_NAME_SELECTOR);
}
@Override
protected PreconDeck read(final File file) {
return getPreconDeckFromSections(FileSection.parseSections(FileUtil.readFile(file)));
}
// To be able to read "shops" section in overloads
protected PreconDeck getPreconDeckFromSections(final Map<String, List<String>> sections) {
FileSection kv = FileSection.parse(sections.get("metadata"), "=");
String imageFilename = kv.get("Image");
String description = kv.get("Description");
String deckEdition = kv.get("set");
String set = deckEdition == null || StaticData.instance().getEditions().get(deckEdition.toUpperCase()) == null ? "n/a" : deckEdition;
PreconDeck result = new PreconDeck(Deck.fromSections(sections), set, description);
result.imageFilename = imageFilename;
return result;
}
@Override
protected FilenameFilter getFileFilter() {
return DeckSerializer.DCK_FILE_FILTER;
}
}
}

View File

@@ -0,0 +1,213 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.item;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.BoosterSlots;
import forge.card.CardRulesPredicates;
import forge.util.Aggregates;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFile;
public abstract class SealedProduct implements InventoryItemFromSet {
protected final Template contents;
protected final String name;
private final int hash;
private List<PaperCard> cards = null;
public SealedProduct(String name0, Template boosterData) {
if (null == name0) { throw new IllegalArgumentException("name0 must not be null"); }
if (null == boosterData) { throw new IllegalArgumentException("boosterData must not be null"); }
contents = boosterData;
name = name0;
hash = name.hashCode() ^ getClass().hashCode() ^ contents.hashCode();
}
@Override
public final String getName() {
return name + " " + getItemType();
}
public String getDescription() {
return contents.toString();
}
@Override
public final String getEdition() {
return contents.getEdition();
}
public final List<PaperCard> getCards() {
if (null == cards) {
cards = generate();
}
return cards;
}
public int getTotalCards() {
return contents.getNumberOfCardsExpected();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
SealedProduct other = (SealedProduct)obj;
return name.equals(other.name) && contents.equals(other.contents);
}
@Override
public int hashCode() {
return hash;
}
protected List<PaperCard> generate() {
return BoosterGenerator.getBoosterPack(contents);
}
protected PaperCard getRandomBasicLand(final String setCode) {
return this.getRandomBasicLands(setCode, 1).get(0);
}
protected List<PaperCard> getRandomBasicLands(final String setCode, final int count) {
Predicate<PaperCard> cardsRule = Predicates.and(
IPaperCard.Predicates.printedInSet(setCode),
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count);
}
public static class Template {
@SuppressWarnings("unchecked")
public final static Template genericBooster = new Template(null, Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, 10), Pair.of(BoosterSlots.UNCOMMON, 3),
Pair.of(BoosterSlots.RARE_MYTHIC, 1), Pair.of(BoosterSlots.BASIC_LAND, 1)
));
protected final List<Pair<String, Integer>> slots;
protected final String name;
public final List<Pair<String, Integer>> getSlots() {
return slots;
}
public final String getEdition() {
return name;
}
public Template(Iterable<Pair<String, Integer>> itrSlots)
{
this(null, itrSlots);
}
public Template(String name0, Iterable<Pair<String, Integer>> itrSlots)
{
slots = Lists.newArrayList(itrSlots);
name = name0;
}
public Template(String code, String boosterDesc) {
this(code, Reader.parseSlots(boosterDesc));
}
public int getNumberOfCardsExpected() {
int sum = 0;
for(Pair<String, Integer> p : slots) {
sum += p.getRight().intValue();
}
return sum;
}
public static final Function<? super Template, String> FN_GET_NAME = new Function<Template, String>() {
@Override
public String apply(Template arg1) {
return arg1.name;
}
};
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("consisting of ");
for(Pair<String, Integer> p : slots) {
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
}
// trim the last comma and space
s.replace(s.length() - 2, s.length(), "");
// put an 'and' before the previous comma
int lastCommaIdx = s.lastIndexOf(",");
if (0 < lastCommaIdx) {
s.replace(lastCommaIdx+1, lastCommaIdx+1, " and");
}
return s.toString();
}
public final static class Reader extends StorageReaderFile<Template> {
public Reader(File file) {
super(file, Template.FN_GET_NAME);
}
public static List<Pair<String, Integer>> parseSlots(String data) {
final String[] dataz = TextUtil.splitWithParenthesis(data, ',');
List<Pair<String, Integer>> slots = new ArrayList<Pair<String,Integer>>();
for(String slotDesc : dataz) {
String[] kv = TextUtil.splitWithParenthesis(slotDesc, ' ', 2);
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
}
return slots;
}
@Override
protected Template read(String line, int i) {
String[] headAndData = TextUtil.split(line, ':', 2);
return new Template(headAndData[0], parseSlots(headAndData[1]));
}
}
}
}

View File

@@ -21,23 +21,22 @@ import java.util.List;
import com.google.common.base.Function;
import forge.Singletons;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
public class TournamentPack extends OpenablePack {
public class TournamentPack extends SealedProduct {
/** The Constant fnFromSet. */
public static final Function<CardEdition, TournamentPack> FN_FROM_SET = new Function<CardEdition, TournamentPack>() {
@Override
public TournamentPack apply(final CardEdition arg1) {
SealedProductTemplate d = Singletons.getModel().getTournamentPacks().get(arg1.getCode());
Template d = StaticData.instance().getTournamentPacks().get(arg1.getCode());
return new TournamentPack(arg1.getName(), d);
}
};
public TournamentPack(final String name0, final SealedProductTemplate boosterData) {
public TournamentPack(final String name0, final Template boosterData) {
super(name0, boosterData);
}

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge.item;

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge;

View File

@@ -79,8 +79,7 @@ public class Aggregates {
if( null == source )
return null;
Random rnd = MyRandom.getRandom();
if ( source instanceof List<?> )
{
if ( source instanceof List<?> ) {
List<T> src = (List<T>)source;
int len = src.size();
switch(len) {
@@ -88,33 +87,43 @@ public class Aggregates {
case 1: return src.get(0);
default: return src.get(rnd.nextInt(len));
}
}
int n = 0;
T candidate = null;
int lowest = Integer.MAX_VALUE;
for (final T item : source) {
if ((rnd.nextDouble() * ++n) < 1) {
int next = rnd.nextInt();
if(next < lowest) {
lowest = next;
candidate = item;
}
}
return candidate;
}
// Get several random values
// should improve to make 1 pass over source and track N candidates at once
public static final <T> List<T> random(final Iterable<T> source, final int count) {
final List<T> result = new ArrayList<T>();
for (int i = 0; i < count; ++i) {
final T toAdd = Aggregates.random(source);
if (toAdd == null) {
break;
final int[] randoms = new int[count];
for(int i = 0; i < count; i++) {
randoms[i] = Integer.MAX_VALUE;
result.add(null);
}
Random rnd = MyRandom.getRandom();
for(T item : source) {
int next = rnd.nextInt();
for(int i = 0; i < count; i++) {
if(next < randoms[i]) {
randoms[i] = next;
result.set(i, item);
break;
}
}
result.add(toAdd);
}
return result;
}
public static final <K, U> Iterable<U> uniqueByLast(final Iterable<U> source, final Function<U, K> fnUniqueKey) { // this might be exotic
final Map<K, U> uniques = new Hashtable<K, U>();
for (final U c : source) {
@@ -123,7 +132,6 @@ public class Aggregates {
return uniques.values();
}
public static <T> T itemWithMin(final Iterable<T> source, final Function<T, Integer> valueAccessor) {
if (source == null) { return null; }
int max = Integer.MAX_VALUE;

View File

@@ -1,4 +1,4 @@
package forge.util.maps;
package forge.util;
import java.util.ArrayList;
import java.util.HashSet;

View File

@@ -31,8 +31,6 @@ import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import forge.error.BugReporter;
/**
* <p>
* FileUtil class.
@@ -109,17 +107,12 @@ public final class FileUtil {
}
p.close();
} catch (final Exception ex) {
BugReporter.reportException(ex);
throw new RuntimeException("FileUtil : writeFile() error, problem writing file - " + file + " : " + ex);
}
} // writeAllDecks()
public static String readFileToString(String filename) {
StringBuilder s = new StringBuilder();
for (String line : readFile(filename)) {
s.append(line).append('\n');
}
return s.toString();
return TextUtil.join(readFile(filename), "\n");
}
public static List<String> readFile(final String filename) {
@@ -145,7 +138,6 @@ public final class FileUtil {
}
return FileUtil.readAllLines(new FileReader(file), false);
} catch (final Exception ex) {
BugReporter.reportException(ex);
throw new RuntimeException("FileUtil : readFile() error, " + ex);
}
} // readFile()
@@ -180,7 +172,6 @@ public final class FileUtil {
}
in.close();
} catch (final IOException ex) {
BugReporter.reportException(ex);
throw new RuntimeException("FileUtil : readAllLines() error, " + ex);
}
return list;

View File

@@ -15,11 +15,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.item;
package forge.util;
import java.util.Collections;
import java.util.Map.Entry;
import forge.item.InventoryItem;
/**
* <p>
* ItemPool class.
@@ -111,12 +113,12 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
return;
}
this.getItems().put(item, Integer.valueOf(this.count(item) + amount));
this.setListInSync(false);
this.isListInSync = false;
}
private void put(final T item, final int amount) {
this.getItems().put(item, amount);
this.setListInSync(false);
this.isListInSync = false;
}
/**
@@ -134,7 +136,7 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
this.add((T) cr);
}
}
this.setListInSync(false);
this.isListInSync = false;
}
/**
@@ -153,7 +155,7 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
this.add((T) e.getKey(), e.getValue());
}
}
this.setListInSync(false);
this.isListInSync = false;
}
/**
@@ -186,10 +188,14 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
} else {
this.getItems().put(item, count - amount);
}
this.setListInSync(false);
this.isListInSync = false;
return true;
}
public boolean removeAll(final T item) {
return this.getItems().remove(item) != null;
}
/**
*
* RemoveAll.
@@ -222,6 +228,6 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
*/
public void clear() {
this.getItems().clear();
this.setListInSync(false);
this.isListInSync = false;
}
}

View File

@@ -15,13 +15,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.item;
package forge.util;
import java.util.Comparator;
import java.util.Map.Entry;
import com.google.common.base.Function;
import forge.item.PaperCard;
/**
* <p>

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.item;
package forge.util;
import java.util.ArrayList;
import java.util.Hashtable;
@@ -27,6 +27,8 @@ import java.util.Map.Entry;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import forge.item.InventoryItem;
/**
* <p>
@@ -88,7 +90,7 @@ public class ItemPoolView<T extends InventoryItem> implements Iterable<Entry<T,
private final transient List<Entry<T, Integer>> itemsOrdered = new ArrayList<Map.Entry<T, Integer>>();
/** Whether list is in sync. */
private transient boolean isListInSync = false;
protected transient boolean isListInSync = false;
/**
* iterator.
@@ -188,7 +190,7 @@ public class ItemPoolView<T extends InventoryItem> implements Iterable<Entry<T,
* @return List<Entry<T, Integer>>
*/
public final List<Entry<T, Integer>> getOrderedList() {
if (!this.isListInSync()) {
if (!this.isListInSync) {
this.rebuildOrderedList();
}
return this.itemsOrdered;
@@ -201,7 +203,7 @@ public class ItemPoolView<T extends InventoryItem> implements Iterable<Entry<T,
this.itemsOrdered.add(e);
}
}
this.setListInSync(true);
this.isListInSync = true;
}
/**
@@ -238,24 +240,6 @@ public class ItemPoolView<T extends InventoryItem> implements Iterable<Entry<T,
return this.myClass;
}
/**
* Checks if is list in sync.
*
* @return the isListInSync
*/
public boolean isListInSync() {
return this.isListInSync;
}
/**
* Sets the list in sync.
*
* @param isListInSync0
* the isListInSync to set
*/
protected void setListInSync(final boolean isListInSync0) {
this.isListInSync = isListInSync0;
}
/**
* To item list string.

View File

@@ -31,13 +31,13 @@ public class Lang {
return position + sufixes[position % 10];
}
}
public static <T> String joinHomogenous(String s1, String s2) {
public static <T> String joinHomogenous(String s1, String s2) {
boolean has1 = StringUtils.isNotBlank(s1);
boolean has2 = StringUtils.isNotBlank(s2);
return has1 ? (has2 ? s1 + " and " + s2 : s1) : (has2 ? s2 : "");
}
public static <T> String joinHomogenous(Iterable<T> objects) { return joinHomogenous(Lists.newArrayList(objects)); }
public static <T> String joinHomogenous(Collection<T> objects) { return joinHomogenous(objects, null, "and"); }
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor) {
@@ -46,85 +46,92 @@ public class Lang {
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor, String lastUnion) {
int remaining = objects.size();
StringBuilder sb = new StringBuilder();
for(T obj : objects) {
for (T obj : objects) {
remaining--;
if( accessor != null )
if (accessor != null) {
sb.append(accessor.apply(obj));
else
}
else {
sb.append(obj);
if( remaining > 1 ) sb.append(", ");
if( remaining == 1 ) sb.append(" ").append(lastUnion).append(" ");
}
if (remaining > 1) {
sb.append(", ");
}
else if (remaining == 1) {
sb.append(" ").append(lastUnion).append(" ");
}
}
return sb.toString();
}
public static <T> String joinVerb(List<T> subjects, String verb) {
return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb);
}
public static String joinVerb(String subject, String verb) {
return !Lang.subjectIsSingle3rdPerson(subject) ? verb : verbs3rdPersonSingular(verb);
}
public static boolean subjectIsSingle3rdPerson(String subject) {
// Will be most simple
return !"You".equalsIgnoreCase(subject);
}
public static String verbs3rdPersonSingular(String verb) {
// English is simple - just add (s) for multiple objects.
return verb + "s";
// English is simple - just add (s) for multiple objects.
return verb + "s";
}
public static String getPlural(String noun) {
return noun + ( noun.endsWith("s") || noun.endsWith("x") ? "es" : "s");
return noun + (noun.endsWith("s") || noun.endsWith("x") ? "es" : "s");
}
public static <T> String nounWithAmount(int cnt, String noun) {
String countedForm = cnt <= 1 ? noun : getPlural(noun);
String countedForm = cnt == 1 ? noun : getPlural(noun);
final String strCount;
if( cnt == 1 )
if (cnt == 1) {
strCount = startsWithVowel(noun) ? "an " : "a ";
else
strCount = String.valueOf(cnt) + " ";
}
else {
strCount = String.valueOf(cnt) + " ";
}
return strCount + countedForm;
}
public static <T> String nounWithNumeral(int cnt, String noun) {
String countedForm = cnt <= 1 ? noun : getPlural(noun);
return getNumeral(cnt) + " " + countedForm;
}
}
public static String getPossesive(String name) {
if ("You".equalsIgnoreCase(name)) return name + "r"; // to get "your"
return name.endsWith("s") ? name + "'" : name + "'s";
}
public static boolean startsWithVowel(String word) {
return isVowel(word.trim().charAt(0));
}
private static final char[] vowels = { 'a', 'i', 'e', 'o', 'u' };
private static final char[] vowels = { 'a', 'i', 'e', 'o', 'u' };
public static boolean isVowel(char letter) {
char l = Character.toLowerCase(letter);
for(char c : vowels)
if ( c == l ) return true;
for (char c : vowels) {
if (c == l) return true;
}
return false;
}
public final static String[] numbers0 = new String[] {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen", "nineteen" };
public final static String[] numbers20 = new String[] {"twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
public static String getNumeral(int n) {
String prefix = n < 0 ? "minus " : "";
n = Math.abs(n);
if ( n >= 0 && n < 20 )
if (n >= 0 && n < 20)
return prefix + numbers0[n];
if ( n < 100 ) {
if (n < 100) {
int n1 = n % 10;
String ones = n1 == 0 ? "" : numbers0[n1];
return prefix + numbers20[(n / 10) - 2] + " " + ones;

View File

@@ -1,5 +1,6 @@
package forge.util;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -43,7 +44,7 @@ public class TextUtil {
return mapAsString.toString();
}
public static String[] split(CharSequence input, char delimiter) {
public static String[] split(CharSequence input, char delimiter) {
return splitWithParenthesis(input, delimiter, Integer.MAX_VALUE, '\0', '\0', true);
}
@@ -68,7 +69,7 @@ public class TextUtil {
/**
* Split string separated by a single char delimiter, can take parenthesis in account
* It's faster than String.split, and allows parenthesis
* It's faster than String.split, and allows parenthesis
*/
public static String[] splitWithParenthesis(CharSequence input, char delimiter, int maxEntries, char openPar, char closePar, boolean skipEmpty) {
List<String> result = new ArrayList<String>();
@@ -78,13 +79,13 @@ public class TextUtil {
int len = input.length();
int start = 0;
int idx = 1;
for (int iC = 0; iC < len; iC++ ) {
for (int iC = 0; iC < len; iC++) {
char c = input.charAt(iC);
if( closePar > 0 && c == closePar && nPar > 0 ) { nPar--; }
else if( openPar > 0 && c == openPar ) nPar++;
if (closePar > 0 && c == closePar && nPar > 0) { nPar--; }
else if (openPar > 0 && c == openPar) nPar++;
if( c == delimiter && nPar == 0 && idx < maxEntries) {
if( iC > start || !skipEmpty ) {
if (c == delimiter && nPar == 0 && idx < maxEntries) {
if (iC > start || !skipEmpty) {
result.add(input.subSequence(start, iC).toString());
idx++;
}
@@ -92,13 +93,24 @@ public class TextUtil {
}
}
if( len > start || !skipEmpty )
if (len > start || !skipEmpty)
result.add(input.subSequence(start, len).toString());
String[] toReturn = result.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
return trimParenthesis ? StringUtils.stripAll(toReturn, String.valueOf(openPar)) : toReturn;
}
public static String join(Iterable<String> strs, String delim) {
StringBuilder sb = new StringBuilder();
for (String str : strs) {
if (sb.length() > 0) {
sb.append(delim);
}
sb.append(str);
}
return sb.toString();
}
/**
* Converts an enum value to a printable label but upcasing the first letter
* and lcasing all subsequent letters
@@ -111,12 +123,20 @@ public class TextUtil {
public static String buildFourColumnList(String firstLine, Iterable<PaperCard> cAnteRemoved) {
StringBuilder sb = new StringBuilder(firstLine);
int i = 0;
for(PaperCard cp: cAnteRemoved) {
if ( i != 0 ) sb.append(", ");
if ( i % 4 == 0 ) sb.append("\n");
for (PaperCard cp: cAnteRemoved) {
if (i != 0) { sb.append(", "); }
if (i % 4 == 0) { sb.append("\n"); }
sb.append(cp);
i++;
}
return sb.toString();
}
public static boolean isPrintableChar(char c) {
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
return (!Character.isISOControl(c)) &&
c != KeyEvent.CHAR_UNDEFINED &&
block != null &&
block != Character.UnicodeBlock.SPECIALS;
}
}

View File

@@ -0,0 +1,52 @@
package forge.util;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class ThreadUtil {
static {
System.out.printf("(ThreadUtil first call): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() );
}
private static class WorkerThreadFactory implements ThreadFactory {
private int countr = 0;
private String prefix = "";
public WorkerThreadFactory(String prefix) {
this.prefix = prefix;
}
public Thread newThread(Runnable r) {
return new Thread(r, prefix + "-" + countr++);
}
}
private final static ExecutorService gameThreadPool = Executors.newCachedThreadPool(new WorkerThreadFactory("Game"));
private static ExecutorService getGameThreadPool() { return gameThreadPool; }
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2, new WorkerThreadFactory("Delayed"));
private static ScheduledExecutorService getScheduledPool() { return scheduledPool; }
// This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5
public final static ExecutorService getComputingPool(float loadFactor) {
return Executors.newFixedThreadPool((int)(Runtime.getRuntime().availableProcessors() / (1-loadFactor)));
}
public static boolean isMultiCoreSystem() {
return Runtime.getRuntime().availableProcessors() > 1;
}
public static void invokeInGameThread(Runnable toRun) {
getGameThreadPool().execute(toRun);
}
public static void delay(int milliseconds, Runnable inputUpdater) {
getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS);
}
public static boolean isGameThread() {
return Thread.currentThread().getName().startsWith("Game");
}
}

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge.util;

Some files were not shown because too many files have changed in this diff Show More