Compare commits

..

579 Commits

Author SHA1 Message Date
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
15851 changed files with 49547 additions and 37202 deletions

View File

@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <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.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.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/> <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>

31247
.gitattributes vendored

File diff suppressed because it is too large Load Diff

26
.gitignore vendored
View File

@@ -2,20 +2,28 @@
/*.iml /*.iml
/*.tmp /*.tmp
/.metadata /.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 /forge.profile.properties
/nbactions.xml /nbactions.xml
/pom.xml.next /pom.xml.next
/pom.xml.releaseBackup /pom.xml.releaseBackup
/pom.xml.tag /pom.xml.tag
/release.properties /release.properties
res/*.log
res/PerSetTrackingResults
res/cardsfolder/*.bat
res/decks
res/layouts
res/pics*
res/pics_product
/target /target
/test-output /test-output
tools/PerSetTrackingResults
tools/oracleScript.log

View File

@@ -4,36 +4,7 @@
<comment></comment> <comment></comment>
<projects> <projects>
</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> <natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature> <nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
</natures> </natures>
</projectDescription> </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.7</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>

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.7</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

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package forge.card.cardfactory; package forge;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -25,8 +25,12 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@@ -35,16 +39,11 @@ import java.util.concurrent.Future;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.swing.SwingUtilities; import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.lang.time.StopWatch;
import forge.FThreads;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardRulesReader;
import forge.error.BugReporter;
import forge.gui.toolbox.FProgressBar;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.ThreadUtil;
/** /**
* <p> * <p>
@@ -52,25 +51,41 @@ import forge.util.FileUtil;
* </p> * </p>
* *
* @author Forge * @author Forge
* @version $Id$ * @version $Id: CardStorageReader.java 23742 2013-11-22 16:32:56Z Max mtg $
*/ */
public class CardStorageReader { 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"; private static final String CARD_FILE_DOT_EXTENSION = ".txt";
/** Default charset when loading from files. */ /** Default charset when loading from files. */
public static final String DEFAULT_CHARSET_NAME = "US-ASCII"; public static final String DEFAULT_CHARSET_NAME = "US-ASCII";
final private boolean useThreadPool = FThreads.isMultiCoreSystem(); private final boolean useThreadPool = ThreadUtil.isMultiCoreSystem();
final private int NUMBER_OF_PARTS = 25; private final static int NUMBER_OF_PARTS = 25;
final private CountDownLatch cdl = new CountDownLatch(NUMBER_OF_PARTS); private final ProgressObserver progressObserver;
final private FProgressBar barProgress;
private transient File cardsfolder; private transient File cardsfolder;
private transient ZipFile zip; private transient ZipFile zip;
private transient Charset charset; private final transient Charset charset;
private final Observer observer;
// 8/18/11 10:56 PM // 8/18/11 10:56 PM
@@ -87,31 +102,27 @@ public class CardStorageReader {
* if true, attempts to load cards from a zip file, if one * if true, attempts to load cards from a zip file, if one
* exists. * exists.
*/ */
public CardStorageReader(String cardDataDir, final boolean useZip, FProgressBar barProgress) { public CardStorageReader(String cardDataDir, CardStorageReader.ProgressObserver progressObserver, Observer observer) {
this.barProgress = barProgress; this.progressObserver = progressObserver != null ? progressObserver : CardStorageReader.ProgressObserver.emptyObserver;
this.cardsfolder = new File(cardDataDir);
this.observer = observer;
// These read data for lightweight classes. // These read data for lightweight classes.
File theCardsFolder = new File(cardDataDir); if (!cardsfolder.exists()) {
throw new RuntimeException("CardReader : constructor error -- " + cardsfolder.getAbsolutePath() + " file/folder not found.");
if (!theCardsFolder.exists()) {
throw new RuntimeException("CardReader : constructor error -- file not found -- filename is "
+ theCardsFolder.getAbsolutePath());
} }
if (!theCardsFolder.isDirectory()) { if (!cardsfolder.isDirectory()) {
throw new RuntimeException("CardReader : constructor error -- not a directory -- " throw new RuntimeException("CardReader : constructor error -- not a directory -- " + cardsfolder.getAbsolutePath());
+ theCardsFolder.getAbsolutePath());
} }
this.cardsfolder = theCardsFolder; final File zipFile = new File(cardsfolder, "cardsfolder.zip");
final File zipFile = new File(theCardsFolder, "cardsfolder.zip"); if (zipFile.exists()) {
if (useZip && zipFile.exists()) {
try { try {
this.zip = new ZipFile(zipFile); this.zip = new ZipFile(zipFile);
} catch (final Exception exn) { } 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()); System.err.printf("Error reading zip file \"%s\": %s. Defaulting to txt files in \"%s\".%n", zipFile.getAbsolutePath(), exn, cardsfolder.getAbsolutePath());
} }
} }
@@ -120,20 +131,18 @@ public class CardStorageReader {
} // CardReader() } // CardReader()
private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) { private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader();
CardRulesReader rulesReader = new CardRulesReader();
List<CardRules> result = new ArrayList<CardRules>(); List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) { for(int i = from; i < to; i++) {
File cardTxtFile = files.get(i); File cardTxtFile = files.get(i);
result.add(this.loadCard(rulesReader, cardTxtFile)); result.add(this.loadCard(rulesReader, cardTxtFile));
} }
return result; return result;
} }
private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) { private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader();
CardRulesReader rulesReader = new CardRulesReader();
List<CardRules> result = new ArrayList<CardRules>(); List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) { for(int i = from; i < to; i++) {
@@ -144,7 +153,6 @@ public class CardStorageReader {
return result; return result;
} }
/** /**
* Starts reading cards into memory until the given card is found. * Starts reading cards into memory until the given card is found.
* *
@@ -153,31 +161,41 @@ public class CardStorageReader {
* *
* @return the Card or null if it was not found. * @return the Card or null if it was not found.
*/ */
public final List<CardRules> loadCards() { public final Iterable<CardRules> loadCards() {
if (barProgress != null) { progressObserver.setOperationName("Loading cards, examining folder", true);
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. // Iterate through txt files or zip archive.
// Report relevant numbers to progress monitor model. // 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();
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; ZipEntry entry;
List<ZipEntry> entries = new ArrayList<ZipEntry>(); List<ZipEntry> entries = new ArrayList<ZipEntry>();
// zipEnum was initialized in the constructor. // zipEnum was initialized in the constructor.
@@ -189,28 +207,24 @@ public class CardStorageReader {
entries.add(entry); entries.add(entry);
} }
tasks = makeTaskListForZip(entries); taskZip = makeTaskListForZip(entries, cdlZip);
} // endif 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");
}
StopWatch sw = new StopWatch(); return result;
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) } // loadCardsUntilYouFind(String)
private List<CardRules> executeLoadTask(final List<Callable<List<CardRules>>> tasks) { private void executeLoadTask(Collection<CardRules> result, final List<Callable<List<CardRules>>> tasks, CountDownLatch cdl) {
List<CardRules> result = new ArrayList<CardRules>();
try { try {
if ( useThreadPool ) { if ( useThreadPool ) {
final ExecutorService executor = FThreads.getComputingPool(0.5f); final ExecutorService executor = ThreadUtil.getComputingPool(0.5f);
final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks); final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks);
executor.shutdown(); executor.shutdown();
cdl.await(); cdl.await();
@@ -229,24 +243,22 @@ public class CardStorageReader {
} catch (Exception e) { // this clause comes from non-threaded branch } catch (Exception e) { // this clause comes from non-threaded branch
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return result;
} }
private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries) { private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries, final CountDownLatch cdl) {
int totalFiles = entries.size(); int totalFiles = entries.size();
int filesPerPart = totalFiles / NUMBER_OF_PARTS; final int maxParts = (int) cdl.getCount();
int filesPerPart = totalFiles / maxParts;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>(); final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) { for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart; final int from = iPart * filesPerPart;
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart; final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() { tasks.add(new Callable<List<CardRules>>() {
@Override @Override
public List<CardRules> call() throws Exception{ public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRangeFromZip(entries, from, till); List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
if ( null != barProgress )
barProgress.increment();
cdl.countDown(); cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res; return res;
} }
}); });
@@ -254,68 +266,49 @@ public class CardStorageReader {
return tasks; return tasks;
} }
private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles) { private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles, final CountDownLatch cdl) {
int totalFiles = allFiles.size(); int totalFiles = allFiles.size();
int filesPerPart = totalFiles / NUMBER_OF_PARTS; final int maxParts = (int) cdl.getCount();
int filesPerPart = totalFiles / maxParts;
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>(); final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) { for (int iPart = 0; iPart < maxParts; iPart++) {
final int from = iPart * filesPerPart; final int from = iPart * filesPerPart;
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart; final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() { tasks.add(new Callable<List<CardRules>>() {
@Override @Override
public List<CardRules> call() throws Exception{ public List<CardRules> call() throws Exception{
List<CardRules> res = loadCardsInRange(allFiles, from, till); List<CardRules> res = loadCardsInRange(allFiles, from, till);
if ( null != barProgress )
barProgress.increment();
cdl.countDown(); cdl.countDown();
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
return res; return res;
} }
}); });
} }
return tasks; return tasks;
} }
/** public static List<File> collectCardFiles(List<File> accumulator, File startDir) {
* TODO: Write javadoc for this method.
* @param allFiles
* @param cardsfolder2
*/
private void fillFilesArray(List<File> allFiles, File startDir) {
String[] list = startDir.list(); String[] list = startDir.list();
for (String filename : list) { for (String filename : list) {
File entry = new File(startDir, filename); File entry = new File(startDir, filename);
if (!entry.isDirectory()) { if (!entry.isDirectory()) {
if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
allFiles.add(entry); accumulator.add(entry);
continue; continue;
}
if (filename.startsWith(".")) {
continue;
}
fillFilesArray(allFiles, entry);
} }
if (filename.startsWith(".")) {
continue;
}
collectCardFiles(accumulator, entry);
}
return accumulator;
} }
/** private List<String> readScript(final InputStream inputStream) {
* <p> return FileUtil.readAllLines(new InputStreamReader(inputStream, this.charset), true);
* 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);
} }
/** /**
@@ -326,15 +319,18 @@ public class CardStorageReader {
* *
* @return a new Card instance * @return a new Card instance
*/ */
protected final CardRules loadCard(final CardRulesReader reader, final File pathToTxtFile) { protected final CardRules loadCard(final CardRules.Reader reader, final File file) {
FileInputStream fileInputStream = null; FileInputStream fileInputStream = null;
try { try {
fileInputStream = new FileInputStream(pathToTxtFile); fileInputStream = new FileInputStream(file);
return this.loadCard(reader, fileInputStream); 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) { } catch (final FileNotFoundException ex) {
BugReporter.reportException(ex, "File \"%s\" exception", pathToTxtFile.getAbsolutePath()); throw new RuntimeException("CardReader : run error -- file not found: " + file.getPath(), ex);
throw new RuntimeException("CardReader : run error -- file exception -- filename is "
+ pathToTxtFile.getPath(), ex);
} finally { } finally {
try { try {
fileInputStream.close(); fileInputStream.close();
@@ -353,11 +349,14 @@ public class CardStorageReader {
* *
* @return a new Card instance * @return a new Card instance
*/ */
protected final CardRules loadCard(final CardRulesReader rulesReader, final ZipEntry entry) { protected final CardRules loadCard(final CardRules.Reader rulesReader, final ZipEntry entry) {
InputStream zipInputStream = null; InputStream zipInputStream = null;
try { try {
zipInputStream = this.zip.getInputStream(entry); zipInputStream = this.zip.getInputStream(entry);
return this.loadCard(rulesReader, zipInputStream); rulesReader.reset();
CardRules rules = rulesReader.readCard(readScript(zipInputStream));
return rules;
} catch (final IOException exn) { } catch (final IOException exn) {
throw new RuntimeException(exn); throw new RuntimeException(exn);
// PM // PM
@@ -372,4 +371,5 @@ public class CardStorageReader {
} }
} }
} }
} }

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.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Singletons; import forge.StaticData;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PrintSheet; import forge.item.SealedProduct;
import forge.util.TextUtil; import forge.util.TextUtil;
/** /**
@@ -50,26 +50,15 @@ import forge.util.TextUtil;
*/ */
public class BoosterGenerator { 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 final static Map<String, PrintSheet> cachedSheets = new TreeMap<String, PrintSheet>(String.CASE_INSENSITIVE_ORDER);
private static final synchronized PrintSheet getPrintSheet(String key) { private static final synchronized PrintSheet getPrintSheet(String key) {
if( !cachedSheets.containsKey(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); 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>(); List<PaperCard> result = new ArrayList<PaperCard>();
for(Pair<String, Integer> slot : booster.getSlots()) { for(Pair<String, Integer> slot : booster.getSlots()) {
String slotType = slot.getLeft(); // add expansion symbol here? String slotType = slot.getLeft(); // add expansion symbol here?
@@ -77,7 +66,7 @@ public class BoosterGenerator {
String[] sType = TextUtil.splitWithParenthesis(slotType, ' '); String[] sType = TextUtil.splitWithParenthesis(slotType, ' ');
String setCode = sType.length == 1 && booster.getEdition() != null ? booster.getEdition() : null; 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); PrintSheet ps = getPrintSheet(sheetKey);
result.addAll(ps.random(numCards, true)); result.addAll(ps.random(numCards, true));
@@ -100,7 +89,7 @@ public class BoosterGenerator {
String mainCode = itMod.next(); String mainCode = itMod.next();
if ( mainCode.regionMatches(true, 0, "fromSheet", 0, 9)) { // custom print sheet if ( mainCode.regionMatches(true, 0, "fromSheet", 0, 9)) { // custom print sheet
String sheetName = StringUtils.strip(mainCode.substring(9), "()\" "); String sheetName = StringUtils.strip(mainCode.substring(9), "()\" ");
src = Singletons.getModel().getPrintSheets().get(sheetName).toFlatList(); src = StaticData.instance().getPrintSheets().get(sheetName).toFlatList();
setPred = Predicates.alwaysTrue(); setPred = Predicates.alwaysTrue();
} else if (mainCode.startsWith("promo")) { // get exactly the named cards, that's a tiny inlined print sheet } 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, ',', '"', '"'); String[] cardNames = TextUtil.splitWithParenthesis(list, ',', '"', '"');
List<PaperCard> srcList = new ArrayList<PaperCard>(); List<PaperCard> srcList = new ArrayList<PaperCard>();
for(String cardName: cardNames) for(String cardName: cardNames)
srcList.add(CardDb.instance().getCard(cardName)); srcList.add(StaticData.instance().getCommonCards().getCard(cardName));
src = srcList; src = srcList;
setPred = Predicates.alwaysTrue(); 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 // 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(); 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); Predicate<PaperCard> predicate = Predicates.and(setPred, extraPred);
ps.addAll(Iterables.filter(src, predicate)); 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); Predicate<PaperCard> predicateRares = Predicates.and(setPred, IPaperCard.Predicates.Presets.IS_RARE, extraPred);
ps.addAll(Iterables.filter(src, predicateRares)); ps.addAll(Iterables.filter(src, predicateRares));
Predicate<PaperCard> predicateUncommon = Predicates.and( setPred, IPaperCard.Predicates.Presets.IS_UNCOMMON, extraPred); Predicate<PaperCard> predicateUncommon = Predicates.and( setPred, IPaperCard.Predicates.Presets.IS_UNCOMMON, extraPred);
ps.addAll(Iterables.filter(src, predicateUncommon), 3); 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. // 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. // 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; Predicate<PaperCard> toAdd = null;
if( operator.equalsIgnoreCase("dfc") ) { toAdd = Predicates.compose(CardRulesPredicates.splitType(CardSplitType.Transform), PaperCard.FN_GET_RULES); 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(BoosterSlots.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(BoosterSlots.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(BoosterSlots.TIME_SHIFTED)) { toAdd = IPaperCard.Predicates.Presets.IS_SPECIAL;
} else if ( operator.equalsIgnoreCase(MYTHIC)) { toAdd = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE; } else if ( operator.equalsIgnoreCase(BoosterSlots.MYTHIC)) { toAdd = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE;
} else if ( operator.equalsIgnoreCase(RARE)) { toAdd = IPaperCard.Predicates.Presets.IS_RARE; } else if ( operator.equalsIgnoreCase(BoosterSlots.RARE)) { toAdd = IPaperCard.Predicates.Presets.IS_RARE;
} else if ( operator.equalsIgnoreCase(UNCOMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_UNCOMMON; } else if ( operator.equalsIgnoreCase(BoosterSlots.UNCOMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_UNCOMMON;
} else if ( operator.equalsIgnoreCase(COMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_COMMON; } else if ( operator.equalsIgnoreCase(BoosterSlots.COMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_COMMON;
} else if ( operator.startsWith("name(") ) { } else if ( operator.startsWith("name(") ) {
operator = StringUtils.strip(operator.substring(4), "() "); operator = StringUtils.strip(operator.substring(4), "() ");
String[] cardNames = TextUtil.splitWithParenthesis(operator, ',', '"', '"'); 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. * TODO: Write javadoc for this type.

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -29,6 +30,7 @@ import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@@ -36,64 +38,33 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import forge.Card; import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.Type;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.CollectionSuppliers;
import forge.util.Lang; import forge.util.Lang;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.maps.CollectionSuppliers;
public final class CardDb implements ICardDatabase { 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 = "+"; public final static String foilSuffix = "+";
private final static int foilSuffixLength = foilSuffix.length(); 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 // 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, PaperCard> uniqueCardsByName = new TreeMap<String, PaperCard>(String.CASE_INSENSITIVE_ORDER);
private final Map<String, CardRules> rulesByName; private final Map<String, CardRules> rulesByName;
private final List<PaperCard> allCards = new ArrayList<PaperCard>(); private final List<PaperCard> allCards = new ArrayList<PaperCard>();
private final List<PaperCard> roAllCards = Collections.unmodifiableList(allCards); private final List<PaperCard> roAllCards = Collections.unmodifiableList(allCards);
private final Collection<PaperCard> roUniqueCards = Collections.unmodifiableCollection(uniqueCardsByName.values()); private final Collection<PaperCard> roUniqueCards = Collections.unmodifiableCollection(uniqueCardsByName.values());
private final EditionCollection editions; private final CardEdition.Collection editions;
public CardDb(Map<String, CardRules> rules, CardEdition.Collection editions0, boolean logMissingCards) {
private CardDb(Map<String, CardRules> rules, EditionCollection editions0, boolean logMissingCards) {
this.rulesByName = rules; this.rulesByName = rules;
this.editions = editions0; this.editions = editions0;
List<String> missingCards = new ArrayList<String>(); List<String> missingCards = new ArrayList<String>();
for(CardEdition e : editions.getOrderedEditions()) { 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) if(worthLogging)
System.out.print(e.getName() + " (" + e.getCards().length + " cards)"); System.out.print(e.getName() + " (" + e.getCards().length + " cards)");
String lastCardName = null; String lastCardName = null;
@@ -224,7 +195,6 @@ public final class CardDb implements ICardDatabase {
return null != res && isFoil ? getFoiled(res) : res; return null != res && isFoil ? getFoiled(res) : res;
} }
@Override @Override
public PaperCard tryGetCard(final String cardName, String setName) { public PaperCard tryGetCard(final String cardName, String setName) {
return tryGetCard(cardName, setName, -1); return tryGetCard(cardName, setName, -1);
@@ -307,7 +277,6 @@ public final class CardDb implements ICardDatabase {
return result; return result;
} }
@Override @Override
public PaperCard getCardPrintedByDate(final String name0, final boolean fromLatestSet, Date printedBefore ) { public PaperCard getCardPrintedByDate(final String name0, final boolean fromLatestSet, Date printedBefore ) {
// Sometimes they read from decks things like "CardName|Set" - but we // Sometimes they read from decks things like "CardName|Set" - but we
@@ -327,7 +296,6 @@ public final class CardDb implements ICardDatabase {
@Override @Override
public PaperCard getCard(final String name, final String set, final int artIndex) { public PaperCard getCard(final String name, final String set, final int artIndex) {
final PaperCard result = tryGetCard(name, set, artIndex); final PaperCard result = tryGetCard(name, set, artIndex);
if (null == result) { if (null == result) {
final String message = String.format("Asked for '%s' from '%s' #%d: db didn't find that copy.", name, set, artIndex); 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; 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 // returns a list of all cards from their respective latest editions
@Override @Override
public Collection<PaperCard> getUniqueCards() { public Collection<PaperCard> getUniqueCards() {
@@ -368,23 +321,9 @@ public final class CardDb implements ICardDatabase {
return Lists.newArrayList(Iterables.filter(this.roAllCards, predicate)); return Lists.newArrayList(Iterables.filter(this.roAllCards, predicate));
} }
private static class CardSorter{ @Override
// Here are refs, get them by name public Iterator<PaperCard> iterator() {
public final Map<String, CardRules> regularCards = new TreeMap<String, CardRules>(String.CASE_INSENSITIVE_ORDER); return this.roAllCards.iterator();
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);
}
}
} }
public Predicate<? super PaperCard> wasPrintedInSets(List<String> setCodes) { public Predicate<? super PaperCard> wasPrintedInSets(List<String> setCodes) {
@@ -401,9 +340,84 @@ public final class CardDb implements ICardDatabase {
@Override @Override
public boolean apply(final PaperCard subject) { public boolean apply(final PaperCard subject) {
Collection<PaperCard> cc = allCardsByName.get(subject.getName()); 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; 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.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.Constant; import forge.StaticData;
import forge.Singletons; import forge.item.SealedProduct;
import forge.game.GameFormat;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.FileSection; import forge.util.FileSection;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.IItemReader;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderBase;
import forge.util.storage.StorageReaderFolder; import forge.util.storage.StorageReaderFolder;
@@ -104,7 +110,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
private int boosterArts = 1; private int boosterArts = 1;
private SealedProductTemplate boosterTpl = null; private SealedProduct.Template boosterTpl = null;
private CardEdition(CardInSet[] cards) { private CardEdition(CardInSet[] cards) {
this.cards = cards; this.cards = cards;
@@ -204,76 +210,20 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
return whiteBorder; return whiteBorder;
} }
public int getCntBoosterPictures() {
/** return boosterArts;
* 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 static class EditionReader extends StorageReaderFolder<CardEdition> { public SealedProduct.Template getBoosterTemplate() {
public EditionReader(File path) { 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); super(path, CardEdition.FN_GET_CODE);
} }
@@ -309,7 +259,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
res.boosterArts = section.getInt("BoosterCovers", 1); res.boosterArts = section.getInt("BoosterCovers", 1);
String boosterDesc = section.get("Booster"); 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.alias = section.get("alias");
res.whiteBorder = "white".equalsIgnoreCase(section.get("border")); res.whiteBorder = "white".equalsIgnoreCase(section.get("border"));
@@ -361,15 +311,145 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
}; };
} }
public final static CardEdition getRandomSetWithAllBasicLands(Iterable<CardEdition> allEditions) { public static class Collection extends StorageBase<CardEdition> {
return Aggregates.random(Iterables.filter(allEditions, CardEdition.Predicates.hasBasicLands));
}
public int getCntBoosterPictures() { private final Map<String, CardEdition> aliasToEdition = new TreeMap<String, CardEdition>(String.CASE_INSENSITIVE_ORDER);
return boosterArts;
}
public SealedProductTemplate getBoosterTemplate() { public Collection(IItemReader<CardEdition> reader) {
return boosterTpl; 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 { 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 List<String> emptyList = Collections.unmodifiableList(new ArrayList<String>());
private final static Map<String, String> emptyMap = Collections.unmodifiableMap(new TreeMap<String, 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"); throw new RuntimeException("Card name is empty");
} }
// Here come setters to allow parser supply values // Here come setters to allow parser supply values
public void setType(CardType type0) { this.type = type0; } void setType(CardType type0) { this.type = type0; }
public void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; } void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
public void setColor(ColorSet color0) { this.color = color0; } void setColor(ColorSet color0) { this.color = color0; }
public void setOracleText(String text) { this.oracleText = text; } void setOracleText(String text) { this.oracleText = text; }
public void setInitialLoyalty(int value) { this.initialLoyalty = value; } void setInitialLoyalty(int value) { this.initialLoyalty = value; }
public void setPtText(String value) { void setPtText(String value) {
final int slashPos = value.indexOf('/'); final int slashPos = value.indexOf('/');
if (slashPos == -1) { if (slashPos == -1) {
throw new RuntimeException(String.format("Creature '%s' has bad p/t stats", this.getName())); 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 // Raw fields used for Card creation
public void setNonAbilityText(String value) { this.nonAbilityText = value; } 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); } 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);} 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);} 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);} 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);} 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 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 ( 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 ( manaCost == null && color == null ) System.err.println(name + " has neither ManaCost nor Color");
if ( color == null ) color = ColorSet.fromManaCost(manaCost); 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.util.ComparableOp; import forge.util.ComparableOp;
import forge.util.PredicateString; import forge.util.PredicateString;
@@ -170,7 +171,7 @@ public final class CardRulesPredicates {
*/ */
public static Predicate<CardRules> coreType(final boolean isEqual, final String what) { public static Predicate<CardRules> coreType(final boolean isEqual, final String what) {
try { try {
return CardRulesPredicates.coreType(isEqual, Enum.valueOf(CardCoreType.class, what)); return CardRulesPredicates.coreType(isEqual, Enum.valueOf(CardType.CoreType.class, what));
} catch (final Exception e) { } catch (final Exception e) {
return com.google.common.base.Predicates.alwaysFalse(); return com.google.common.base.Predicates.alwaysFalse();
} }
@@ -185,7 +186,7 @@ public final class CardRulesPredicates {
* the type * the type
* @return the predicate * @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); return new PredicateCoreType(type, isEqual);
} }
@@ -200,7 +201,7 @@ public final class CardRulesPredicates {
*/ */
public static Predicate<CardRules> superType(final boolean isEqual, final String what) { public static Predicate<CardRules> superType(final boolean isEqual, final String what) {
try { try {
return CardRulesPredicates.superType(isEqual, Enum.valueOf(CardSuperType.class, what)); return CardRulesPredicates.superType(isEqual, Enum.valueOf(CardType.SuperType.class, what));
} catch (final Exception e) { } catch (final Exception e) {
return com.google.common.base.Predicates.alwaysFalse(); return com.google.common.base.Predicates.alwaysFalse();
} }
@@ -215,7 +216,7 @@ public final class CardRulesPredicates {
* the type * the type
* @return the predicate * @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); return new PredicateSuperType(type, isEqual);
} }
@@ -224,7 +225,7 @@ public final class CardRulesPredicates {
* Checks for color. * Checks for color.
* *
* @param thatColor * @param thatColor
* the that color * color to check
* @return the predicate * @return the predicate
*/ */
public static Predicate<CardRules> hasColor(final byte thatColor) { public static Predicate<CardRules> hasColor(final byte thatColor) {
@@ -235,13 +236,24 @@ public final class CardRulesPredicates {
* Checks if is color. * Checks if is color.
* *
* @param thatColor * @param thatColor
* the that color * color to check
* @return the predicate * @return the predicate
*/ */
public static Predicate<CardRules> isColor(final byte thatColor) { public static Predicate<CardRules> isColor(final byte thatColor) {
return new LeafColor(LeafColor.ColorOperator.HasAnyOf, 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. * Checks if is exactly that color.
* *
@@ -310,7 +322,7 @@ public final class CardRulesPredicates {
private static class LeafColor implements Predicate<CardRules> { private static class LeafColor implements Predicate<CardRules> {
public enum ColorOperator { public enum ColorOperator {
CountColors, CountColorsGreaterOrEqual, HasAnyOf, HasAllOf, Equals CountColors, CountColorsGreaterOrEqual, HasAnyOf, HasAllOf, Equals, CanCast
} }
private final LeafColor.ColorOperator op; private final LeafColor.ColorOperator op;
@@ -337,6 +349,8 @@ public final class CardRulesPredicates {
return subject.getColor().hasAllColors(this.color); return subject.getColor().hasAllColors(this.color);
case HasAnyOf: case HasAnyOf:
return subject.getColor().hasAnyColor(this.color); return subject.getColor().hasAnyColor(this.color);
case CanCast:
return subject.canCastWithAvailable(this.color);
default: default:
return false; return false;
} }
@@ -396,7 +410,7 @@ public final class CardRulesPredicates {
} }
private static class PredicateCoreType implements Predicate<CardRules> { private static class PredicateCoreType implements Predicate<CardRules> {
private final CardCoreType operand; private final CardType.CoreType operand;
private final boolean shouldBeEqual; private final boolean shouldBeEqual;
@Override @Override
@@ -407,14 +421,14 @@ public final class CardRulesPredicates {
return this.shouldBeEqual == card.getType().typeContains(this.operand); 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.operand = type;
this.shouldBeEqual = wantEqual; this.shouldBeEqual = wantEqual;
} }
} }
private static class PredicateSuperType implements Predicate<CardRules> { private static class PredicateSuperType implements Predicate<CardRules> {
private final CardSuperType operand; private final CardType.SuperType operand;
private final boolean shouldBeEqual; private final boolean shouldBeEqual;
@Override @Override
@@ -422,7 +436,7 @@ public final class CardRulesPredicates {
return this.shouldBeEqual == card.getType().superTypeContains(this.operand); 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.operand = type;
this.shouldBeEqual = wantEqual; this.shouldBeEqual = wantEqual;
} }
@@ -448,21 +462,21 @@ public final class CardRulesPredicates {
/** The Constant isCreature. */ /** The Constant isCreature. */
public static final Predicate<CardRules> IS_CREATURE = CardRulesPredicates 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 public static final Predicate<CardRules> IS_LEGENDARY = CardRulesPredicates
.superType(true, CardSuperType.Legendary); .superType(true, CardType.SuperType.Legendary);
/** The Constant isArtifact. */ /** The Constant isArtifact. */
public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates
.coreType(true, CardCoreType.Artifact); .coreType(true, CardType.CoreType.Artifact);
/** The Constant isEquipment. */ /** The Constant isEquipment. */
public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates
.subType("Equipment"); .subType("Equipment");
/** The Constant isLand. */ /** 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. */ /** The Constant isBasicLand. */
public static final Predicate<CardRules> IS_BASIC_LAND = new Predicate<CardRules>() { 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, CardType.CoreType.Planeswalker);
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant);
CardCoreType.Planeswalker); 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);
/** The Constant isInstant. */ public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardType.CoreType.Plane);
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardCoreType.Instant); public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardType.CoreType.Phenomenon);
/** 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_PLANE_OR_PHENOMENON = Predicates.or(IS_PLANE, IS_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_SCHEME = CardRulesPredicates.coreType(true, CardType.CoreType.Scheme);
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardCoreType.Vanguard); 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);
/** The Constant isNonLand. */ 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_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));
/** The Constant IS_NONCREATURE_SPELL_FOR_GENERATOR. **/ /** The Constant IS_NONCREATURE_SPELL_FOR_GENERATOR. **/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -533,6 +533,7 @@ public final class CardRulesPredicates {
/** The Constant isMulticolor. */ /** The Constant isMulticolor. */
public static final Predicate<CardRules> IS_MULTICOLOR = CardRulesPredicates.hasAtLeastCntColors((byte) 2); 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); public static final Predicate<CardRules> IS_MONOCOLOR = CardRulesPredicates.hasCntColors((byte) 1);
/** The Constant colors. */ /** The Constant colors. */

View File

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

View File

@@ -24,8 +24,6 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.Constant;
/** /**
* <p> * <p>
* Immutable Card type. Can be build only from parsing a string. * 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 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 List<String> subType = new ArrayList<String>();
private final EnumSet<CardCoreType> coreType = EnumSet.noneOf(CardCoreType.class); private final EnumSet<CardType.CoreType> coreType = EnumSet.noneOf(CardType.CoreType.class);
private final EnumSet<CardSuperType> superType = EnumSet.noneOf(CardSuperType.class); private final EnumSet<CardType.SuperType> superType = EnumSet.noneOf(CardType.SuperType.class);
private String calculatedType = null; // since obj is immutable, this is private String calculatedType = null; // since obj is immutable, this is
// calc'd once // calc'd once
// This will be useful for faster parses // This will be useful for faster parses
private static HashMap<String, CardCoreType> stringToCoreType = new HashMap<String, CardCoreType>(); private static HashMap<String, CardType.CoreType> stringToCoreType = new HashMap<String, CardType.CoreType>();
private static HashMap<String, CardSuperType> stringToSuperType = new HashMap<String, CardSuperType>(); private static HashMap<String, CardType.SuperType> stringToSuperType = new HashMap<String, CardType.SuperType>();
static { static {
for (final CardSuperType st : CardSuperType.values()) { for (final CardType.SuperType st : CardType.SuperType.values()) {
CardType.stringToSuperType.put(st.name(), st); 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); CardType.stringToCoreType.put(ct.name(), ct);
} }
} }
@@ -106,13 +148,13 @@ public final class CardType implements Comparable<CardType> {
return; return;
} }
final CardCoreType ct = CardType.stringToCoreType.get(type); final CardType.CoreType ct = CardType.stringToCoreType.get(type);
if (ct != null) { if (ct != null) {
this.coreType.add(ct); this.coreType.add(ct);
return; return;
} }
final CardSuperType st = CardType.stringToSuperType.get(type); final CardType.SuperType st = CardType.stringToSuperType.get(type);
if (st != null) { if (st != null) {
this.superType.add(st); this.superType.add(st);
return; return;
@@ -126,56 +168,56 @@ public final class CardType implements Comparable<CardType> {
return this.subType.contains(operand); return this.subType.contains(operand);
} }
public boolean typeContains(final CardCoreType operand) { public boolean typeContains(final CardType.CoreType operand) {
return this.coreType.contains(operand); return this.coreType.contains(operand);
} }
public boolean superTypeContains(final CardSuperType operand) { public boolean superTypeContains(final CardType.SuperType operand) {
return this.superType.contains(operand); return this.superType.contains(operand);
} }
public boolean isCreature() { public boolean isCreature() {
return this.coreType.contains(CardCoreType.Creature); return this.coreType.contains(CardType.CoreType.Creature);
} }
public boolean isPlaneswalker() { public boolean isPlaneswalker() {
return this.coreType.contains(CardCoreType.Planeswalker); return this.coreType.contains(CardType.CoreType.Planeswalker);
} }
public boolean isLand() { public boolean isLand() {
return this.coreType.contains(CardCoreType.Land); return this.coreType.contains(CardType.CoreType.Land);
} }
public boolean isArtifact() { public boolean isArtifact() {
return this.coreType.contains(CardCoreType.Artifact); return this.coreType.contains(CardType.CoreType.Artifact);
} }
public boolean isInstant() { public boolean isInstant() {
return this.coreType.contains(CardCoreType.Instant); return this.coreType.contains(CardType.CoreType.Instant);
} }
public boolean isSorcery() { public boolean isSorcery() {
return this.coreType.contains(CardCoreType.Sorcery); return this.coreType.contains(CardType.CoreType.Sorcery);
} }
public boolean isVanguard() { public boolean isVanguard() {
return this.coreType.contains(CardCoreType.Vanguard); return this.coreType.contains(CardType.CoreType.Vanguard);
} }
public boolean isScheme() { public boolean isScheme() {
return this.coreType.contains(CardCoreType.Scheme); return this.coreType.contains(CardType.CoreType.Scheme);
} }
public boolean isEnchantment() { public boolean isEnchantment() {
return this.coreType.contains(CardCoreType.Enchantment); return this.coreType.contains(CardType.CoreType.Enchantment);
} }
public boolean isBasic() { public boolean isBasic() {
return this.superType.contains(CardSuperType.Basic); return this.superType.contains(CardType.SuperType.Basic);
} }
public boolean isLegendary() { public boolean isLegendary() {
return this.superType.contains(CardSuperType.Legendary); return this.superType.contains(CardType.SuperType.Legendary);
} }
public boolean isBasicLand() { public boolean isBasicLand() {
@@ -200,10 +242,10 @@ public final class CardType implements Comparable<CardType> {
public List<String> getTypesBeforeDash() { public List<String> getTypesBeforeDash() {
final ArrayList<String> types = new ArrayList<String>(); final ArrayList<String> types = new ArrayList<String>();
for (final CardSuperType st : this.superType) { for (final CardType.SuperType st : this.superType) {
types.add(st.name()); types.add(st.name());
} }
for (final CardCoreType ct : this.coreType) { for (final CardType.CoreType ct : this.coreType) {
types.add(ct.name()); types.add(ct.name());
} }
return types; return types;
@@ -229,11 +271,52 @@ public final class CardType implements Comparable<CardType> {
} }
public boolean isPlane() { public boolean isPlane() {
return this.coreType.contains(CardCoreType.Plane); return this.coreType.contains(CardType.CoreType.Plane);
} }
public boolean isPhenomenon() { 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 ///////// Utility methods
@@ -245,7 +328,7 @@ public final class CardType implements Comparable<CardType> {
final ArrayList<String> types = new ArrayList<String>(); final ArrayList<String> types = new ArrayList<String>();
// types.addAll(getCardTypes()); // types.addAll(getCardTypes());
types.addAll(Constant.CardTypes.CARD_TYPES); types.addAll(Constant.CARD_TYPES);
// not currently used by Forge // not currently used by Forge
types.add("Plane"); types.add("Plane");
@@ -258,7 +341,7 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getBasicTypes() { public static ArrayList<String> getBasicTypes() {
final ArrayList<String> types = new ArrayList<String>(); final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.BASIC_TYPES); types.addAll(Constant.BASIC_TYPES);
return types; return types;
} }
@@ -266,8 +349,8 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getLandTypes() { public static ArrayList<String> getLandTypes() {
final ArrayList<String> types = new ArrayList<String>(); final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.BASIC_TYPES); types.addAll(Constant.BASIC_TYPES);
types.addAll(Constant.CardTypes.LAND_TYPES); types.addAll(Constant.LAND_TYPES);
return types; return types;
} }
@@ -275,13 +358,13 @@ public final class CardType implements Comparable<CardType> {
public static ArrayList<String> getCreatureTypes() { public static ArrayList<String> getCreatureTypes() {
final ArrayList<String> types = new ArrayList<String>(); final ArrayList<String> types = new ArrayList<String>();
types.addAll(Constant.CardTypes.CREATURE_TYPES); types.addAll(Constant.CREATURE_TYPES);
return types; return types;
} }
public static boolean isASuperType(final String cardType) { 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) { 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) { 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) { 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) { 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) { 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; 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.card.mana.ManaCost;
import forge.util.BinaryUtil; 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 byte myColor;
private final int orderWeight; private final int orderWeight;
@@ -55,7 +59,6 @@ public final class ColorSet implements Comparable<ColorSet> {
private ColorSet(final byte mask) { private ColorSet(final byte mask) {
this.myColor = mask; this.myColor = mask;
this.orderWeight = this.getOrderWeight(); this.orderWeight = this.getOrderWeight();
} }
public static ColorSet fromMask(final int mask) { public static ColorSet fromMask(final int mask) {
@@ -253,7 +256,7 @@ public final class ColorSet implements Comparable<ColorSet> {
return "n/a"; return "n/a";
} }
String toReturn = MagicColor.toLongString(myColor); String toReturn = MagicColor.toLongString(myColor);
if (toReturn == Constant.Color.COLORLESS && myColor != 0) { if (toReturn == MagicColor.Constant.COLORLESS && myColor != 0) {
return "multi"; return "multi";
} }
return toReturn; return toReturn;
@@ -281,4 +284,37 @@ public final class ColorSet implements Comparable<ColorSet> {
public ColorSet getOffColors(ColorSet ccOther) { public ColorSet getOffColors(ColorSet ccOther) {
return ColorSet.fromMask(~this.myColor & ccOther.myColor); 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; import forge.item.PaperCard;
public interface ICardDatabase { public interface ICardDatabase extends Iterable<PaperCard> {
PaperCard tryGetCard(String cardName); PaperCard tryGetCard(String cardName);
PaperCard tryGetCard(String cardName, boolean fromLastSet); PaperCard tryGetCard(String cardName, boolean fromLastSet);
PaperCard tryGetCard(String cardName, String edition); 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.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.ArrayList; import java.util.ArrayList;
@@ -7,7 +8,9 @@ import java.util.Collection;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.util.ItemPool;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.item.PaperCard;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.storage.StorageReaderFileSections; import forge.util.storage.StorageReaderFileSections;
@@ -30,7 +33,7 @@ public class PrintSheet {
this(name0, null); this(name0, null);
} }
private PrintSheet(String name0, ItemPool<PaperCard> pool) { public PrintSheet(String name0, ItemPool<PaperCard> pool) {
name = name0; name = name0;
cardsWithWeights = pool != null ? pool : new ItemPool<PaperCard>(PaperCard.class); cardsWithWeights = pool != null ? pool : new ItemPool<PaperCard>(PaperCard.class);
} }
@@ -105,9 +108,17 @@ public class PrintSheet {
return result; return result;
} }
public boolean isEmpty() {
return cardsWithWeights.isEmpty();
}
public Iterable<PaperCard> toFlatList() {
return cardsWithWeights.toFlatList();
}
public static class Reader extends StorageReaderFileSections<PrintSheet> { public static class Reader extends StorageReaderFileSections<PrintSheet> {
public Reader(String fileName) { public Reader(File file) {
super(fileName, PrintSheet.FN_GET_KEY); super(file, PrintSheet.FN_GET_KEY);
} }
@Override @Override
@@ -117,13 +128,4 @@ public class PrintSheet {
} }
public boolean isEmpty() {
return cardsWithWeights.isEmpty();
}
public Iterable<PaperCard> toFlatList() {
return cardsWithWeights.toFlatList();
}
} }

View File

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

View File

@@ -19,10 +19,9 @@ package forge.card.mana;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import forge.card.ColorSet;
/** /**
* <p> * <p>
* CardManaCost class. * CardManaCost class.
@@ -32,7 +31,7 @@ import forge.card.ColorSet;
* @version $Id: CardManaCost.java 9708 2011-08-09 19:34:12Z jendave $ * @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 List<ManaCostShard> shards;
private final int genericCost; private final int genericCost;
private final boolean hasNoCost; // lands cost private final boolean hasNoCost; // lands cost
@@ -97,22 +96,19 @@ public final class ManaCost implements Comparable<ManaCost> {
return "no cost"; return "no cost";
} }
if (this.shards.isEmpty()) { if (this.shards.isEmpty()) {
return Integer.toString(this.genericCost); return "{" + this.genericCost + "}";
} }
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
if (this.genericCost > 0) { if (this.genericCost > 0) {
sb.append(this.genericCost); sb.append("{" + this.genericCost + "}");
isFirst = false;
} }
for (final ManaCostShard s : this.shards) { for (final ManaCostShard s : this.shards) {
if (!isFirst) { if (s == ManaCostShard.X) {
sb.append(' '); sb.insert(0, s.toString());
} else { } else {
isFirst = false; sb.append(s.toString());
} }
sb.append(s.toString());
} }
return sb.toString(); return sb.toString();
} }
@@ -143,15 +139,6 @@ public final class ManaCost implements Comparable<ManaCost> {
return result; return result;
} }
/**
* Gets the shards.
*
* @return the shards
*/
public List<ManaCostShard> getShards() {
return this.shards;
}
public int getShardCount(ManaCostShard which) { public int getShardCount(ManaCostShard which) {
if (which == ManaCostShard.COLORLESS) { if (which == ManaCostShard.COLORLESS) {
return genericCost; return genericCost;
@@ -260,13 +247,12 @@ public final class ManaCost implements Comparable<ManaCost> {
/** /**
* Can this mana cost be paid with unlimited mana of given color set. * Can this mana cost be paid with unlimited mana of given color set.
* @param color * @param colorCode
* @return * @return
*/ */
public boolean canBePaidWithAvaliable(byte colorCode) {
public boolean canBePaidWithAvaliable(ColorSet color) {
for (ManaCostShard shard : shards) { for (ManaCostShard shard : shards) {
if (!shard.isPhyrexian() && !shard.canBePaidWithManaOfColor(color.getColor())) { if (!shard.isPhyrexian() && !shard.canBePaidWithManaOfColor(colorCode)) {
return false; return false;
} }
} }
@@ -288,4 +274,16 @@ public final class ManaCost implements Comparable<ManaCost> {
return res; 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 nextToken;
private int colorlessCost; 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. * Instantiates a new parser cardname txt mana cost.
* *
@@ -54,7 +65,6 @@ public class ManaCostParser implements IParserManaCost {
*/ */
@Override @Override
public final ManaCostShard next() { public final ManaCostShard next() {
final String unparsed = this.cost[this.nextToken++]; final String unparsed = this.cost[this.nextToken++];
// System.out.println(unparsed); // System.out.println(unparsed);
if (StringUtils.isNumeric(unparsed)) { if (StringUtils.isNumeric(unparsed)) {

View File

@@ -35,14 +35,14 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
/* Hybrid */ /* Hybrid */
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"), WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"),
WB(ManaAtom.WHITE | ManaAtom.BLACK, "W/B", "WB"), 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"), UB(ManaAtom.BLUE | ManaAtom.BLACK, "U/B", "UB"),
UR(ManaAtom.BLUE | ManaAtom.RED, "U/R", "UR"), UR(ManaAtom.BLUE | ManaAtom.RED, "U/R", "UR"),
UG(ManaAtom.BLUE | ManaAtom.GREEN, "U/G", "GU"),
BR(ManaAtom.BLACK | ManaAtom.RED, "B/R", "BR"), BR(ManaAtom.BLACK | ManaAtom.RED, "B/R", "BR"),
BG(ManaAtom.BLACK | ManaAtom.GREEN, "B/G", "BG"), BG(ManaAtom.BLACK | ManaAtom.GREEN, "B/G", "BG"),
RW(ManaAtom.RED | ManaAtom.WHITE, "R/W", "RW"),
RG(ManaAtom.RED | ManaAtom.GREEN, "R/G", "RG"), 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 */ /* Or 2 colorless */
W2(ManaAtom.WHITE | ManaAtom.OR_2_COLORLESS, "2/W", "2W"), W2(ManaAtom.WHITE | ManaAtom.OR_2_COLORLESS, "2/W", "2W"),
@@ -102,15 +102,12 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
this.shard = value; this.shard = value;
this.cmc = this.getCMC(); this.cmc = this.getCMC();
this.cmpc = this.getCmpCost(); this.cmpc = this.getCmpCost();
this.stringValue = sValue; this.stringValue = "{" + sValue + "}";
this.imageKey = imgKey; this.imageKey = imgKey;
} }
public static final int COLORS_SUPERPOSITION = ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.RED | ManaAtom.GREEN; public static final int COLORS_SUPERPOSITION = ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.RED | ManaAtom.GREEN;
private int getCMC() { private int getCMC() {
if (0 != (this.shard & ManaAtom.IS_X)) { if (0 != (this.shard & ManaAtom.IS_X)) {
return 0; return 0;
@@ -267,7 +264,6 @@ public enum ManaCostShard implements Comparable<ManaCostShard> {
public boolean isMonoColor() { public boolean isMonoColor() {
return BinaryUtil.bitCount(this.shard & COLORS_SUPERPOSITION) == 1; return BinaryUtil.bitCount(this.shard & COLORS_SUPERPOSITION) == 1;
} }
public boolean isOr2Colorless() { public boolean isOr2Colorless() {

View File

@@ -18,7 +18,6 @@
package forge.deck; package forge.deck;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -26,10 +25,9 @@ import java.util.NoSuchElementException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.Card; import forge.StaticData;
import forge.card.CardDb;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.ItemPool; import forge.util.ItemPool;
/** /**
* Deck section. * Deck section.
@@ -54,15 +52,6 @@ public class CardPool extends ItemPool<PaperCard> {
this.addAll(cards); this.addAll(cards);
} }
/**
* Adds the.
*
* @param card
* the card
*/
public void add(final Card card) {
this.add(CardDb.getCard(card));
}
/** /**
* Adds the. * Adds the.
@@ -84,9 +73,9 @@ public class CardPool extends ItemPool<PaperCard> {
* @param amount the amount * @param amount the amount
*/ */
public void add(final String cardName, final String setCode, final int 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 ) if ( cp == null )
cp = CardDb.variants().tryGetCard(cardName, setCode); cp = StaticData.instance().getVariantCards().tryGetCard(cardName, setCode);
if ( cp != null) if ( cp != null)
this.add(cp, amount); 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 )); 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. * Add all from a List of CardPrinted.
* *
@@ -124,9 +101,9 @@ public class CardPool extends ItemPool<PaperCard> {
* @param cardName the card name * @param cardName the card name
*/ */
public void add(final String cardName, int cnt) { public void add(final String cardName, int cnt) {
PaperCard cp = CardDb.instance().tryGetCard(cardName); PaperCard cp = StaticData.instance().getCommonCards().tryGetCard(cardName);
if ( cp == null ) if ( cp == null )
cp = CardDb.variants().tryGetCard(cardName); cp = StaticData.instance().getVariantCards().tryGetCard(cardName);
if ( cp != null) if ( cp != null)
this.add(cp, cnt); this.add(cp, cnt);

View File

@@ -35,12 +35,12 @@ import com.google.common.base.Function;
import forge.card.CardDb; import forge.card.CardDb;
import forge.deck.io.DeckFileHeader; import forge.deck.io.DeckFileHeader;
import forge.deck.io.DeckSerializer; import forge.deck.io.DeckSerializer;
import forge.item.ItemPoolSorter;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.ItemPoolView;
import forge.util.FileSection; import forge.util.FileSection;
import forge.util.FileUtil; 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} */ /** {@inheritDoc} */
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (o instanceof Deck) { if (o instanceof DeckBase) {
final Deck d = (Deck) o; final DeckBase d = (DeckBase) o;
return this.getName().equals(d.getName()); return this.getName().equals(d.getName());
} }
return false; return false;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,8 +15,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Constant;
import forge.Singletons;
import forge.card.CardDb;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardRulesPredicates; import forge.card.CardRulesPredicates;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC; import forge.card.mana.ManaCost;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.properties.ForgePreferences.FPref;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.ItemPool;
import forge.util.ItemPoolView;
import forge.util.MyRandom; import forge.util.MyRandom;
/** /**
@@ -54,13 +52,15 @@ import forge.util.MyRandom;
* @author Forge * @author Forge
* @version $Id: Generate2ColorDeck.java 14959 2012-03-28 14:03:43Z Chris H. $ * @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 Random r = MyRandom.getRandom();
protected final Map<String, Integer> cardCounts = new HashMap<String, Integer>(); 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 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 // 2-colored deck generator has its own constants. The rest works fine with these ones
protected float getLandsPercentage() { return 0.44f; } protected float getLandsPercentage() { return 0.44f; }
@@ -69,9 +69,15 @@ public abstract class GenerateColoredDeckBase {
StringBuilder tmpDeck = new StringBuilder(); StringBuilder tmpDeck = new StringBuilder();
public GenerateColoredDeckBase() { public DeckGeneratorBase(ICardDatabase cardDb) {
this.maxDuplicates = Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_SINGLETONS) ? 1 : 4; this.cardDb = cardDb;
tDeck = new ItemPool<PaperCard>(PaperCard.class); }
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) { 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)); } 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. // 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.getCard(s, false));
tDeck.add(CardDb.instance().getCard(cp.getName(), false));
final int n = this.cardCounts.get(s); final int n = this.cardCounts.get(s);
this.cardCounts.put(s, n + 1); this.cardCounts.put(s, n + 1);
@@ -159,20 +164,20 @@ public abstract class GenerateColoredDeckBase {
int landsLeft = cnt; int landsLeft = cnt;
for (Entry<String, Integer> c : clrCnts.entrySet()) { for (Entry<String, Integer> c : clrCnts.entrySet()) {
String color = c.getKey(); String basicLandName = c.getKey();
// calculate number of lands for each color // calculate number of lands for each color
final int nLand = Math.min(landsLeft, Math.round(cnt * c.getValue() / totalColor)); 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 // 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(); String basicLandSet = cp.getEdition();
tDeck.add(CardDb.instance().getCard(cp.getName(), basicLandSet), nLand); tDeck.add(cardDb.getCard(cp.getName(), basicLandSet), nLand);
landsLeft -= nLand; landsLeft -= nLand;
} }
} }
@@ -222,7 +227,7 @@ public abstract class GenerateColoredDeckBase {
final List<PaperCard> curvedRandomized = Lists.newArrayList(); final List<PaperCard> curvedRandomized = Lists.newArrayList();
for (PaperCard c : curved) { for (PaperCard c : curved) {
this.cardCounts.put(c.getName(), 0); this.cardCounts.put(c.getName(), 0);
curvedRandomized.add(CardDb.instance().getCard(c.getName(), false)); curvedRandomized.add(cardDb.getCard(c.getName(), false));
} }
addSome(addOfThisCmc, curvedRandomized); addSome(addOfThisCmc, curvedRandomized);
@@ -233,13 +238,13 @@ public abstract class GenerateColoredDeckBase {
// start with all cards // start with all cards
// remove cards that generated decks don't like // remove cards that generated decks don't like
Predicate<CardRules> canPlay = forAi ? GenerateDeckUtil.AI_CAN_PLAY : GenerateDeckUtil.HUMAN_CAN_PLAY; Predicate<CardRules> canPlay = forAi ? AI_CAN_PLAY : HUMAN_CAN_PLAY;
Predicate<CardRules> hasColor = new GenerateDeckUtil.MatchColorIdentity(colors); Predicate<CardRules> hasColor = new MatchColorIdentity(colors);
if (!Singletons.getModel().getPreferences().getPrefBoolean(FPref.DECKGEN_ARTIFACTS)) { if (useArtifacts) {
hasColor = Predicates.or(hasColor, GenerateDeckUtil.COLORLESS_CARDS); 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) { protected static Map<String, Integer> countLands(ItemPool<PaperCard> outList) {
@@ -254,15 +259,15 @@ public abstract class GenerateColoredDeckBase {
int profile = cpe.getKey().getRules().getManaCost().getColorProfile(); int profile = cpe.getKey().getRules().getManaCost().getColorProfile();
if ((profile & MagicColor.WHITE) != 0) { 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) { } 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) { } 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) { } 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) { } 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); final Integer boxed = map.get(key);
map.put(key, boxed == null ? delta : boxed.intValue() + delta); 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package forge.deck.generate; package forge.deck.generation;
import java.util.List; import java.util.List;
@@ -24,10 +24,10 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.ICardDatabase;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.deck.generate.GenerateDeckUtil.FilterCMC;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.ItemPoolView; import forge.util.ItemPoolView;
/** /**
* <p> * <p>
@@ -37,17 +37,17 @@ import forge.item.ItemPoolView;
* @author Forge * @author Forge
* @version $Id: Generate2ColorDeck.java 19765 2013-02-20 03:01:37Z myk $ * @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 getLandsPercentage() { return 0.39f; }
@Override protected final float getCreatPercentage() { return 0.36f; } @Override protected final float getCreatPercentage() { return 0.36f; }
@Override protected final float getSpellPercentage() { return 0.25f; } @Override protected final float getSpellPercentage() { return 0.25f; }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList( final List<ImmutablePair<FilterCMC, Integer>> cmcLevels = Lists.newArrayList(
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(0, 2), 10), ImmutablePair.of(new FilterCMC(0, 2), 10),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(3, 4), 8), ImmutablePair.of(new FilterCMC(3, 4), 8),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(5, 6), 5), ImmutablePair.of(new FilterCMC(5, 6), 5),
ImmutablePair.of(new GenerateDeckUtil.FilterCMC(7, 20), 3) ImmutablePair.of(new FilterCMC(7, 20), 3)
); );
// mana curve of the card pool // mana curve of the card pool
@@ -67,7 +67,8 @@ public class GenerateMonoColorDeck extends GenerateColoredDeckBase {
* @param clr2 * @param clr2
* a {@link java.lang.String} object. * 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) { if (MagicColor.fromName(clr1) == 0) {
int color1 = r.nextInt(5); int color1 = r.nextInt(5);
colors = ColorSet.fromMask(MagicColor.WHITE << color1); 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 org.apache.commons.lang3.StringUtils;
import forge.deck.DeckFormat; import forge.deck.DeckFormat;
import forge.game.player.PlayerType;
import forge.util.FileSection; import forge.util.FileSection;
/** /**
@@ -48,7 +47,6 @@ public class DeckFileHeader {
private static final String PLAYER_TYPE = "PlayerType"; private static final String PLAYER_TYPE = "PlayerType";
private final DeckFormat deckType; private final DeckFormat deckType;
private final PlayerType playerType;
private final boolean customPool; private final boolean customPool;
private final String name; private final String name;
@@ -56,6 +54,15 @@ public class DeckFileHeader {
private final Set<String> tags; private final Set<String> tags;
private final boolean intendedForAi;
/**
* @return the intendedForAi
*/
public boolean isIntendedForAi() {
return intendedForAi;
}
/** /**
* TODO: Write javadoc for Constructor. * TODO: Write javadoc for Constructor.
* *
@@ -67,8 +74,7 @@ public class DeckFileHeader {
this.comment = kvPairs.get(DeckFileHeader.COMMENT); this.comment = kvPairs.get(DeckFileHeader.COMMENT);
this.deckType = DeckFormat.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), DeckFormat.Constructed); this.deckType = DeckFormat.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), DeckFormat.Constructed);
this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL); this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL);
boolean isForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE)); this.intendedForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
this.playerType = isForAi ? PlayerType.COMPUTER : PlayerType.HUMAN;
this.tags = new TreeSet<String>(); this.tags = new TreeSet<String>();
String rawTags = kvPairs.get(DeckFileHeader.TAGS); 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. * 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 com.google.common.base.Function;
import forge.Singletons; import forge.StaticData;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
import forge.util.MyRandom; import forge.util.MyRandom;
public class BoosterPack extends OpenablePack { public class BoosterPack extends SealedProduct {
private final int artIndex; private final int artIndex;
private final int hash; private final int hash;
public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() { public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() {
@Override @Override
public BoosterPack apply(final CardEdition arg1) { 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); 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); 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; artIndex = MyRandom.getRandom().nextInt(maxIdx) + 1;
hash = super.hashCode() ^ artIndex; hash = super.hashCode() ^ artIndex;
} }
@@ -58,7 +57,7 @@ public class BoosterPack extends OpenablePack {
return new BoosterPack(name, contents); return new BoosterPack(name, contents);
} }
public SealedProductTemplate getBoosterData() { public Template getBoosterData() {
return contents; 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.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Card; //import forge.Card;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardRules; import forge.card.CardRules;
import forge.game.player.Player;
import forge.util.PredicateString; import forge.util.PredicateString;
public interface IPaperCard extends InventoryItem { public interface IPaperCard extends InventoryItem {
@@ -161,7 +160,4 @@ public interface IPaperCard extends InventoryItem {
public abstract String getItemType(); public abstract String getItemType();
public abstract Card getMatchingForgeCard();
public abstract Card toForgeCard(Player owner);
} }

View File

@@ -17,16 +17,10 @@
*/ */
package forge.item; package forge.item;
import java.util.HashMap;
import java.util.Map;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.Card;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.cardfactory.CardFactory;
import forge.game.player.Player;
/** /**
@@ -40,7 +34,7 @@ import forge.game.player.Player;
*/ */
public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard { public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
// Reference to rules // Reference to rules
private final transient CardRules card; private final transient CardRules rules;
// These fields are kinda PK for PrintedCard // These fields are kinda PK for PrintedCard
public final String name; public final String name;
@@ -78,7 +72,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
@Override @Override
public CardRules getRules() { public CardRules getRules() {
return this.card; return this.rules;
} }
@Override @Override
@@ -86,15 +80,11 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
return this.rarity; return this.rarity;
} }
// @Override // @Override
// public String getImageKey() { // public String getImageKey() {
// return getImageLocator(getImageName(), getArtIndex(), true, false); // return getImageLocator(getImageName(), getArtIndex(), true, false);
// } // }
@Override @Override
public String getItemType() { public String getItemType() {
return "Card"; return "Card";
@@ -106,7 +96,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() { public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() {
@Override @Override
public CardRules apply(final PaperCard from) { 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>() { public static final Function<PaperCard, String> FN_GET_NAME = new Function<PaperCard, String>() {
@@ -123,7 +113,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index, final boolean foil) { public PaperCard(final CardRules c, final String edition0, final CardRarity rare, final int index, final boolean foil) {
if ( edition0 == null || c == null || rare == null ) if ( edition0 == null || c == null || rare == null )
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity"); throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
this.card = c; this.rules = c;
this.name = c.getName(); this.name = c.getName();
this.edition = edition0; this.edition = edition0;
this.artIndex = index; this.artIndex = index;
@@ -184,34 +174,6 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
// return String.format("%s|%s", name, cardSet); // 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) * (non-Javadoc)
* *

View File

@@ -2,12 +2,10 @@ package forge.item;
import java.util.Locale; import java.util.Locale;
import forge.Card;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.cardfactory.CardFactory;
import forge.game.player.Player;
public class PaperToken implements InventoryItemFromSet, IPaperCard { public class PaperToken implements InventoryItemFromSet, IPaperCard {
private String name; private String name;
@@ -61,13 +59,6 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
public String getImageFilename() { return imageFileName; } public String getImageFilename() { return imageFileName; }
@Override public String getItemType() { return "Token"; } @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; } @Override public boolean isToken() { return true; }
} }

View File

@@ -18,16 +18,18 @@
package forge.item; package forge.item;
import java.io.File; import java.io.File;
import java.io.FilenameFilter;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.Singletons; import forge.StaticData;
import forge.deck.Deck; import forge.deck.Deck;
import forge.quest.SellRules; import forge.deck.io.DeckSerializer;
import forge.util.FileSection; import forge.util.FileSection;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.storage.StorageReaderFolder;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
@@ -36,11 +38,11 @@ import forge.util.FileUtil;
public class PreconDeck implements InventoryItemFromSet { public class PreconDeck implements InventoryItemFromSet {
private final Deck deck; private final Deck deck;
private final String imageFilename;
private final String set; private final String set;
private final String description; private final String description;
private String imageFilename;
private final SellRules recommendedDeals; // private final SellRules recommendedDeals;
/* /*
* (non-Javadoc) * (non-Javadoc)
@@ -62,34 +64,12 @@ public class PreconDeck implements InventoryItemFromSet {
return "Prebuilt Deck"; return "Prebuilt Deck";
} }
/** public PreconDeck(final Deck d, String set, String description) {
* Instantiates a new precon deck. deck = d;
* this.set = set;
* @param f this.description = description;
* 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"));
} }
/**
* Gets the deck.
*
* @return the deck
*/
public final Deck getDeck() { public final Deck getDeck() {
return this.deck; return this.deck;
} }
@@ -99,9 +79,9 @@ public class PreconDeck implements InventoryItemFromSet {
* *
* @return the recommended deals * @return the recommended deals
*/ */
public final SellRules getRecommendedDeals() { // public final SellRules getRecommendedDeals() {
return this.recommendedDeals; // return this.recommendedDeals;
} // }
public final String getImageFilename() { public final String getImageFilename() {
return imageFilename; return imageFilename;
@@ -133,4 +113,37 @@ 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 com.google.common.base.Function;
import forge.Singletons; import forge.StaticData;
import forge.card.BoosterGenerator; import forge.card.BoosterGenerator;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
public class TournamentPack extends OpenablePack { public class TournamentPack extends SealedProduct {
/** The Constant fnFromSet. */ /** The Constant fnFromSet. */
public static final Function<CardEdition, TournamentPack> FN_FROM_SET = new Function<CardEdition, TournamentPack>() { public static final Function<CardEdition, TournamentPack> FN_FROM_SET = new Function<CardEdition, TournamentPack>() {
@Override @Override
public TournamentPack apply(final CardEdition arg1) { 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); 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); 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

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

View File

@@ -15,11 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.Collections;
import java.util.Map.Entry; import java.util.Map.Entry;
import forge.item.InventoryItem;
/** /**
* <p> * <p>
* ItemPool class. * ItemPool class.
@@ -111,12 +113,12 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
return; return;
} }
this.getItems().put(item, Integer.valueOf(this.count(item) + amount)); 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) { private void put(final T item, final int amount) {
this.getItems().put(item, 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.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.add((T) e.getKey(), e.getValue());
} }
} }
this.setListInSync(false); this.isListInSync = false;
} }
/** /**
@@ -186,7 +188,7 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
} else { } else {
this.getItems().put(item, count - amount); this.getItems().put(item, count - amount);
} }
this.setListInSync(false); this.isListInSync = false;
return true; return true;
} }
@@ -222,6 +224,6 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
*/ */
public void clear() { public void clear() {
this.getItems().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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.Comparator;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.item.PaperCard;
/** /**
* <p> * <p>

View File

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

View File

@@ -46,19 +46,24 @@ public class Lang {
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor, String lastUnion) { public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor, String lastUnion) {
int remaining = objects.size(); int remaining = objects.size();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for(T obj : objects) { for (T obj : objects) {
remaining--; remaining--;
if( accessor != null ) if (accessor != null) {
sb.append(accessor.apply(obj)); sb.append(accessor.apply(obj));
else }
else {
sb.append(obj); 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(); return sb.toString();
} }
public static <T> String joinVerb(List<T> subjects, String verb) { public static <T> String joinVerb(List<T> subjects, String verb) {
return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb); return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb);
} }
@@ -78,16 +83,18 @@ public class Lang {
} }
public static String getPlural(String noun) { 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) { 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; final String strCount;
if( cnt == 1 ) if (cnt == 1) {
strCount = startsWithVowel(noun) ? "an " : "a "; strCount = startsWithVowel(noun) ? "an " : "a ";
else }
else {
strCount = String.valueOf(cnt) + " "; strCount = String.valueOf(cnt) + " ";
}
return strCount + countedForm; return strCount + countedForm;
} }
@@ -108,10 +115,10 @@ public class Lang {
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) { public static boolean isVowel(char letter) {
char l = Character.toLowerCase(letter); char l = Character.toLowerCase(letter);
for(char c : vowels) for (char c : vowels) {
if ( c == l ) return true; if (c == l) return true;
}
return false; return false;
} }
public final static String[] numbers0 = new String[] { public final static String[] numbers0 = new String[] {
@@ -122,9 +129,9 @@ public class Lang {
public static String getNumeral(int n) { public static String getNumeral(int n) {
String prefix = n < 0 ? "minus " : ""; String prefix = n < 0 ? "minus " : "";
n = Math.abs(n); n = Math.abs(n);
if ( n >= 0 && n < 20 ) if (n >= 0 && n < 20)
return prefix + numbers0[n]; return prefix + numbers0[n];
if ( n < 100 ) { if (n < 100) {
int n1 = n % 10; int n1 = n % 10;
String ones = n1 == 0 ? "" : numbers0[n1]; String ones = n1 == 0 ? "" : numbers0[n1];
return prefix + numbers20[(n / 10) - 2] + " " + ones; return prefix + numbers20[(n / 10) - 2] + " " + ones;

View File

@@ -99,6 +99,17 @@ public class TextUtil {
return trimParenthesis ? StringUtils.stripAll(toReturn, String.valueOf(openPar)) : toReturn; 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 * Converts an enum value to a printable label but upcasing the first letter
* and lcasing all subsequent letters * and lcasing all subsequent letters

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