Compare commits

...

1163 Commits

Author SHA1 Message Date
Blacksmith
22dc1a27a0 [maven-release-plugin] prepare release forge-1.6.33 2020-03-20 00:35:52 +00:00
Blacksmith
c374e0ae81 Update README.txt for release 2020-03-20 00:32:15 +00:00
Michael Kamensky
fc1b3547b2 Merge branch 'patch-5' into 'master'
Update DebuffEffect: fix if it doesn't use target

Closes #1325

See merge request core-developers/forge!2625
2020-03-19 06:38:22 +00:00
Hans Mackowiak
b0d3fbe783 Update DebuffEffect: fix if it doesn't use target 2020-03-19 06:38:22 +00:00
Michael Kamensky
3a02a10258 Merge branch 'voteKeywords' into 'master'
Vote: replace hidden keywords with timestamped properties

Closes #57, #1318, and #1258

See merge request core-developers/forge!2510
2020-03-19 06:22:44 +00:00
Hans Mackowiak
33d83dc0c5 Vote: replace hidden keywords with timestamped properties 2020-03-19 06:22:44 +00:00
Sol
d35a2cdead Merge branch 'peltcol' into 'master'
Pelt Collector fixup

See merge request core-developers/forge!2623
2020-03-17 12:40:38 +00:00
Tim Mocny
507c88269b Pelt Collector fixup 2020-03-17 12:40:37 +00:00
Michael Kamensky
2c7dfc0c41 Merge branch 'glyphre' into 'master'
Glyph of Reincarnation fixup

See merge request core-developers/forge!2621
2020-03-16 20:00:15 +00:00
Tim Mocny
a8ab95f321 - closer to "from the graveyard of the player who controlled that creature the last time it became blocked by that Wall" 2020-03-16 20:00:14 +00:00
Michael Kamensky
672cff54ef Merge branch 'krovam2' into 'master'
Krovikan Vampire - a bit more Cleanup

See merge request core-developers/forge!2620
2020-03-16 19:59:34 +00:00
Tim Mocny
44cbd9af3e Krovikan Vampire - a bit more Cleanup 2020-03-16 19:59:34 +00:00
Michael Kamensky
d3bcfea727 Merge branch 'krovam' into 'master'
Krovikan Vampire!

Closes #75

See merge request core-developers/forge!2619
2020-03-15 16:19:09 +00:00
Tim Mocny
20fa72d24e Krovikan Vampire! 2020-03-15 16:19:09 +00:00
Michael Kamensky
10faa20490 Merge branch 'newBranch' into 'master'
Stack display adjustment

See merge request core-developers/forge!2612
2020-03-15 06:06:38 +00:00
Sol
62c9d187eb Merge branch 'respectbanlist' into 'master'
Respect ban list in archetype deck generation and updated deckgen data

See merge request core-developers/forge!2618
2020-03-15 01:12:03 +00:00
austinio7116
a5148e8983 Added draft rankings 2020-03-14 21:19:19 +00:00
maustin
0bb7a84e55 Merge branch 'coremaster' into respectbanlist 2020-03-14 21:18:16 +00:00
Michael Kamensky
1218786b3e Merge branch 'master' into 'master'
A basic AI logic hook for Timmerian Fiends

See merge request core-developers/forge!2617
2020-03-14 16:45:51 +00:00
Agetian
62a1ee6d3d - A basic AI logic hook for Timmerian Fiends 2020-03-14 19:23:37 +03:00
Michael Kamensky
64f17b49fe Merge branch 'timmerian' into 'master'
Timmerian Fiends!

Closes #116

See merge request core-developers/forge!2610
2020-03-14 15:48:57 +00:00
Tim Mocny
0d939da60d Timmerian Fiends! 2020-03-14 15:48:56 +00:00
Michael Kamensky
cc321b1b2e Merge branch 'fixes' into 'master'
Fixes

Closes #1291, #1317, and #1322

See merge request core-developers/forge!2615
2020-03-14 15:42:36 +00:00
Michael Kamensky
71bf43b63a Merge branch 'glyphre' into 'master'
Glyph of Reincarnation!

Closes #64

See merge request core-developers/forge!2616
2020-03-14 15:41:43 +00:00
Tim Mocny
2d7840aa7d Glyph of Reincarnation! 2020-03-14 15:41:43 +00:00
Anthony Calosa
a1be9d0278 Fix Inventory View for Cards without Card Image 2020-03-14 13:34:31 +08:00
Anthony Calosa
8a18f815b4 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-14 10:42:07 +08:00
Sol
2b529a07c2 Merge branch '1323-numberformatexception-for-input-string-2secondary-true' into 'master'
Resolve "NumberFormatException: For input string: "2Secondary$ True""

Closes #1323

See merge request core-developers/forge!2613
2020-03-14 00:55:55 +00:00
Jamin W. Collins
c0349d87fb implement and use new PredicateCard
This fixes the THB and ELD draft, possibly others

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-13 18:45:36 -06:00
Jamin W. Collins
c488ab4772 increase maximal heap size to 4096m
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-13 18:43:06 -06:00
Jamin W. Collins
d83f8deb7a remove vestigial scripts
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-13 18:43:06 -06:00
Jamin W. Collins
f1f480d16a explicitly set the encoding to UTF-8
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-13 18:43:06 -06:00
Hans Mackowiak
a1ffa625e1 CardFactoryUtil: fix Saga 2020-03-13 20:34:34 +00:00
Anthony Calosa
d7e38f7fd8 Format Stack Text
(Should be cleaner)
2020-03-14 03:05:29 +08:00
Anthony Calosa
a5683d4f12 Adjust Card Name & Ability Icons Ordering 2020-03-14 03:02:15 +08:00
Sol
cb1d4b7904 Merge branch 'updatertranslation' into 'master'
Auto Updater: Add missing translation strings

See merge request core-developers/forge!2598
2020-03-13 15:50:09 +00:00
Michael Kamensky
c6def2cc5b Merge branch 'Hanmac-Saga-Trigger' into 'master'
Sage Trigger Combined

See merge request core-developers/forge!2609
2020-03-13 15:11:05 +00:00
Hans Mackowiak
81dc9fecba Sage Trigger Combined 2020-03-13 15:11:05 +00:00
Sol
4629817268 Merge branch '12Mar20' into 'master'
the_triumph_of_anax.txt typo

See merge request core-developers/forge!2607
2020-03-12 22:11:37 +00:00
Tim Mocny
b6bbe3d18b the_triumph_of_anax.txt typo 2020-03-12 22:11:37 +00:00
Hans Mackowiak
b437db8ffa Merge branch 'tinyleadersPWcomm' into 'master'
Make Planeswalkers possible for Tiny Leaders

Closes #1311

See merge request core-developers/forge!2606
2020-03-12 16:00:04 +00:00
Tim Mocny
3be58fee75 Make Planeswalkers poss commander for Tiny Leaders, cleanup Brawl commander syntax
Legendary Planeswalkers only

Clean up Commander syntax for TL and Brawl
2020-03-12 16:00:03 +00:00
Michael Kamensky
fe09671795 Merge branch 'etbCounterManaPaid' into 'master'
ManaPart: use Effect for enter the battlefield when mana was spent

See merge request core-developers/forge!2604
2020-03-12 13:34:27 +00:00
Hans Mackowiak
9f35da4698 ManaPart: use Effect for enter the battlefield when mana was spent 2020-03-12 13:34:27 +00:00
Michael Kamensky
3c5a62056b Merge branch 'edfix9mar' into 'master'
Various fixes

See merge request core-developers/forge!2599
2020-03-12 05:40:05 +00:00
Tim Mocny
43a38e3c6d Various fixes 2020-03-12 05:40:05 +00:00
Michael Kamensky
f5a89afa93 Merge branch 'newBranch' into 'master'
remade border to have thin line edges

See merge request core-developers/forge!2603
2020-03-12 05:38:32 +00:00
Anthony Calosa
7a49dd28e1 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-12 12:16:20 +08:00
Sol
d14f20bc43 Merge branch 'collector_number' into 'master'
handle more complex imageKey parsing

See merge request core-developers/forge!2602
2020-03-12 02:56:33 +00:00
Anthony Calosa
14a40e493f Try first variant art for .fullborder images
(ie WAR variant has alternate art)
2020-03-12 08:54:08 +08:00
Anthony Calosa
9b8e63501a Reduce whiteborder sides 2020-03-11 22:21:48 +08:00
Anthony Calosa
61097e9f80 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-11 22:13:42 +08:00
Sol
404ce34076 Merge branch 'mar9banres' into 'master'
Brawl, Legacy, Modern bans

See merge request core-developers/forge!2605
2020-03-11 13:08:44 +00:00
Northmoc
e546b6a689 Brawl, Legacy, Modern bans 2020-03-11 09:01:11 -04:00
Anthony Calosa
7e31e15ead Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-11 16:52:34 +08:00
Anthony Calosa
62d7824155 remade border to have thin line edges
(simulate card edges)
2020-03-11 14:52:21 +08:00
Jamin W. Collins
8c5a90d6e9 handle more complex imageKey parsing
Should now be able to handle:
c:Town Gossipmonger|SOI|1$alt

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-10 21:23:29 -06:00
Sol
9345ff6725 Merge branch 'cardfixes' into 'master'
Card Fixes: Settle the Wreckage, Cavalier of Dawn

See merge request core-developers/forge!2601
2020-03-11 01:25:13 +00:00
Michael Kamensky
c45573ff2e Merge branch 'newBranch' into 'master'
Minor Visual Improvement & Update Android target SDK

See merge request core-developers/forge!2600
2020-03-10 18:10:14 +00:00
Adam Pantel
55300347ce Fix Settle the Wreckage, Cavalier of Dawn 2020-03-10 12:46:51 -04:00
Anthony Calosa
c85584445e update project.properties 2020-03-10 17:16:08 +08:00
Anthony Calosa
ceeb5d623f Increase Android target SDK so it will work with Android 10.
Need to download SDK 26 to compile.

(Just tested this on Android 6 and Android 9, it works, but need to test the change for Android 5 and Android 10, for Android 10, It needs to turn the storage permission settings manually since the project don't have running permission setup currently)
2020-03-10 16:53:59 +08:00
Anthony Calosa
1f4eff8b1c Adjust CroppedArea for Non Modern Card Frames
(fullborder images)
2020-03-10 16:45:08 +08:00
Anthony Calosa
41af869d3c Update Font 2020-03-10 16:35:39 +08:00
Michael Kamensky
2747d93e4c Merge branch 'fixXonCancel' into 'master'
GameAction: refactor setting CastSA

Closes #1320

See merge request core-developers/forge!2585
2020-03-10 06:35:34 +00:00
Hans Mackowiak
5c9251e295 SpellAbility: adding an Announce needs to be to originalMapParams too 2020-03-10 07:13:04 +01:00
Hans Mackowiak
fa67ee73a5 Card: cleanup multikicker values 2020-03-10 07:13:04 +01:00
Hans Mackowiak
e1659a4539 Combat: use lkiCase only if blocker itself is an lki 2020-03-10 07:13:04 +01:00
Hans Mackowiak
d5b578b306 Card: move reseting xmana paid to clearTemporaryVars 2020-03-10 07:13:04 +01:00
Hans Mackowiak
32b56018a6 GameAction: refactor setting CastSA 2020-03-10 07:13:04 +01:00
Peter
aa12085345 Add new translation strings about the new Auto Updater 2020-03-09 19:54:11 +01:00
Michael Kamensky
3dd20d9d0b Merge branch 'master' into 'master'
Fix AddsCounters

Closes #1264

See merge request core-developers/forge!2597
2020-03-09 18:27:54 +00:00
Agetian
8b922fc8f2 - Fix AddsCounters 2020-03-09 21:13:29 +03:00
Agetian
c88a419e03 - Use ExecuteScript in PS_THB7 for a simpler implementation. 2020-03-09 12:32:06 +03:00
Michael Kamensky
b9618509be Merge branch 'desktop-autoupdate' into 'master'
check for updates button

See merge request core-developers/forge!2537
2020-03-09 03:59:40 +00:00
Sol
1076b1e29f Merge branch 'edition-fixes' into 'master'
improve handling of foil-only Kaya for CN2

See merge request core-developers/forge!2584
2020-03-09 01:10:26 +00:00
Jamin W. Collins
4717955afb improve handling of foil-only Kaya for CN2
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-08 09:43:58 -06:00
Michael Kamensky
af771d0c2c Merge branch 'master' into 'master'
Added puzzles PS_THB6 and PS_THB7 - Possibility Storm - Theros Beyond Death 06 and 07

See merge request core-developers/forge!2595
2020-03-08 12:12:36 +00:00
Michael Kamensky
8fea6b4cc0 Merge branch 'newBranch' into 'master'
Add Cancel Button for Puzzle Screen

See merge request core-developers/forge!2596
2020-03-08 12:12:30 +00:00
Anthony Calosa
9249029dc1 Add Cancel Button for Puzzle Screen
(If you decide not to solve puzzle or accidentally hit start on Puzzle Menu)
2020-03-08 18:37:36 +08:00
Agetian
e5d40554e1 - Error prevention on ID-based precast 2020-03-08 13:16:10 +03:00
Agetian
8b8e39ff41 - Added puzzles PS_THB6 and PS_THB7.
- Added a way to precast a spell from a specific host by ID.
2020-03-08 13:12:28 +03:00
Michael Kamensky
40591b04d2 Merge branch 'newBranch' into 'master'
Update Menu & App Icons

See merge request core-developers/forge!2591
2020-03-08 09:10:44 +00:00
Michael Kamensky
1c1e2416e4 Merge branch 'patch-4' into 'master'
Replace bg_match.jpg in Darkred skin

See merge request core-developers/forge!2593
2020-03-08 09:10:06 +00:00
Anthony Calosa
bdf9d3f88e Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-08 12:34:47 +08:00
Sol
960760a564 Merge branch 'mb1fix' into 'master'
MB1 pool corrections

See merge request core-developers/forge!2590
2020-03-08 02:13:25 +00:00
Tim Mocny
f488cb1d0b MB1 pool corrections 2020-03-08 02:13:25 +00:00
Sol
c4e2004af3 Merge branch 'fixes' into 'master'
simplify regex usage to group numbers, support Android 6

See merge request core-developers/forge!2592
2020-03-08 02:11:07 +00:00
friarsol
dcb151f561 Get the Updater liike 90% of the way there. 2020-03-07 20:37:07 -05:00
Churrufli
4550ee26e3 Replace bg_match.jpg, previous one is a png renamed, I noticed may cause bugs in some Android versions 2020-03-07 18:15:23 +00:00
Jamin W. Collins
ecdea545fc simplify regex usage to group numbers, support Android 6
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-07 09:01:57 -07:00
Anthony Calosa
643c08850b Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-07 13:21:38 +08:00
Anthony Calosa
fed6d788cf Update Menu Icons 2020-03-07 13:21:13 +08:00
Anthony Calosa
3ccd979b63 Update App Icon 2020-03-07 13:20:07 +08:00
Michael Kamensky
be52fb772e Merge branch 'onceupon' into 'master'
Once Upon a Time (lowercase "a" throughout Forge)

See merge request core-developers/forge!2589
2020-03-06 15:30:37 +00:00
Tim Mocny
633c106708 Once Upon a Time (lowercase "a" throughout Forge) 2020-03-06 15:30:36 +00:00
Michael Kamensky
aec62cbffb Merge branch 'mysteryboost' into 'master'
Mystery Booster support!

See merge request core-developers/forge!2588
2020-03-06 15:30:25 +00:00
Tim Mocny
5b61712d70 Mystery Booster support! 2020-03-06 15:30:25 +00:00
Michael Kamensky
7fa248db4c Merge branch 'patch-joust' into 'master'
Update joust: add missing AILogic$ Fight

See merge request core-developers/forge!2586
2020-03-05 14:32:18 +00:00
Hans Mackowiak
33f04148d3 Update joust: add missing AILogic$ Fight 2020-03-05 14:32:17 +00:00
Michael Kamensky
3aa33be214 Merge branch 'patch-collector-number-thb' into 'master'
Update Theros Beyond Death: add missing CollectorNumber

See merge request core-developers/forge!2587
2020-03-05 14:32:11 +00:00
Hans Mackowiak
612045f8c0 Update Theros Beyond Death: add missing CollectorNumber 2020-03-05 14:32:11 +00:00
Michael Kamensky
0bd6b16247 Merge branch 'edition-fixes' into 'master'
Edition fixes

See merge request core-developers/forge!2583
2020-03-05 03:35:42 +00:00
Michael Kamensky
eaa7d296d2 Merge branch 'newBranch' into 'master'
Fix jerky animation on Conquest Reward Dialog

See merge request core-developers/forge!2581
2020-03-05 03:32:26 +00:00
Jamin W. Collins
235162fb84 fixing the collector numbers for Magic 2015
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 20:06:09 -07:00
Jamin W. Collins
fc4a491111 fixing collector numbers for Magic 2014
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 20:04:36 -07:00
Jamin W. Collins
0cd9b1435b fixing collector numbers for Khans of Tarkir
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 20:02:16 -07:00
Sol
61184ade4c Merge branch 'collector_number' into 'master'
change collector number to be a String

See merge request core-developers/forge!2578
2020-03-05 02:55:36 +00:00
Jamin W. Collins
f2e29c9c93 fixing collector numbers for Fate Reforged
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:54:54 -07:00
Sol
e676073548 Merge branch 'network-play-fixes' into 'master'
Network play fixes

See merge request core-developers/forge!2582
2020-03-05 02:51:16 +00:00
Jamin W. Collins
6b315b2571 adding missing card for Conspiracy Take the Crown
Kaya, Ghost Assassin is a foil-only booster card

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:46:40 -07:00
Jamin W. Collins
6e028a1c45 correct the rarities for Beatdown
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:40:27 -07:00
Jamin W. Collins
f07e2bc2ec correct the rarities for Battlebond
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:40:04 -07:00
Jamin W. Collins
3bc4124fe8 correct the rarities for Battle Royale
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:37:55 -07:00
Jamin W. Collins
bb5af6298e correct the collect numbers for Aether Revolt
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:32:28 -07:00
Jamin W. Collins
3c6c0f534d correct the tokens delimeter for Weatherlight
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:29:44 -07:00
Jamin W. Collins
4f3a8590dd semi-ignore non-fatal IndexOutOfBoundsException
Not entirely sure why there are IndexOutOfBoundsException being seen
currently, but they are not fatal and do not appear to result in game
state skew between client and server.  So, logging and moving on.

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:08:02 -07:00
Jamin W. Collins
2a993eb0e0 fixing openZones method signature for network-play
Changes introduced in ef0a1a84 altered the method signature for
openZones, but did not fully update the signature for network-play
calls.

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-04 19:06:07 -07:00
Anthony Calosa
f99e819ff0 Add puzzle improvements to Mobile Forge 2020-03-05 05:45:11 +08:00
Anthony Calosa
0f6b65a9ff Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-04 19:40:09 +08:00
austinio7116
6e94378cc1 Added filter to ensure banlist is respected 2020-03-04 06:05:07 +00:00
Jamin W. Collins
ff31718839 correct how collectorNumber is located
The existing logic will always return the first match for a given card
name, even if there are multiple different printings of the same card
name within a set. This change aligns the collectorNumber with the
alternate art index.

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-03 21:27:05 -07:00
Michael Kamensky
2ab5a286c5 Merge branch '030320' into 'master'
March 3 fixes

See merge request core-developers/forge!2580
2020-03-04 04:07:14 +00:00
Northmoc
e07208e81b dissenters_deliverance.txt correct filename 2020-03-03 14:15:54 -05:00
Hans Mackowiak
1ec9c6cade Merge branch 'glyphofdelusion' into 'master'
Glyph of Delusion

Closes #63

See merge request core-developers/forge!2482
2020-03-03 16:24:42 +00:00
Tim Mocny
04e94f68f5 Glyph of Delusion 2020-03-03 16:24:41 +00:00
Jamin W. Collins
e325f42ca8 change collector number to be a String
This change moves the internal storage of collector number from Integer
to String.

The parsed pattern for valid collector numbers is any number of digits
followed by an optional single non-digit character. This follows the
format used by Scryfall for the alternate art WAR planeswalkers and
cards from older formats sucha as FEM.

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-03 08:59:09 -07:00
Michael Kamensky
f3c078b23c Merge branch 'Hanmac-master-patch-40459' into 'master'
CardProperty: extend blockedValidThisTurn and blockedByValidThisTurn using defined

Closes #1299

See merge request core-developers/forge!2579
2020-03-03 14:30:40 +00:00
Hans Mackowiak
4f0deea15f CardProperty: extend blockedValidThisTurn and blockedByValidThisTurn using defined 2020-03-03 14:30:39 +00:00
Michael Kamensky
db396e6b5c Merge branch '020320' into 'master'
Fixes - 2 Mar 2020

See merge request core-developers/forge!2577
2020-03-03 04:07:39 +00:00
Tim Mocny
dfe7ea0ecc Fixes - 2 Mar 2020 2020-03-03 04:07:39 +00:00
Michael Kamensky
55cba2513f Merge branch 'witchHuntAi' into 'master'
ControlGainAi: fix target logic for Witch Hunt

See merge request core-developers/forge!2576
2020-03-02 06:08:02 +00:00
Hans Mackowiak
9bbc3c8ef2 ControlGainAi: fix target logic for Witch Hunt 2020-03-02 06:59:33 +01:00
Anthony Calosa
c473ecb827 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-02 12:30:51 +08:00
Anthony Calosa
f654982e38 Fix Card Reveal Animation for default display 2020-03-02 12:30:02 +08:00
Michael Kamensky
38394ee263 Merge branch 'fixes' into 'master'
fix message when no cards in opponent's hand

See merge request core-developers/forge!2575
2020-03-02 03:55:12 +00:00
Jamin W. Collins
c9010d4224 fix message when no cards in opponent's hand
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-01 14:04:08 -07:00
Michael Kamensky
cb1b8024b4 Merge branch '1303-control-change-and-cda-not-reset' into 'master'
Resolve "Control Change and CDA not reset?"

Closes #1303

See merge request core-developers/forge!2573
2020-03-01 17:15:39 +00:00
Hans Mackowiak
075a0e99af Merieke Ri Berit: use Effect for Destroy Trigger 2020-03-01 17:37:06 +01:00
Jamin Collins
5f4c86697a Merge branch 'sld37' into 'master'
SLD - Thalia

See merge request core-developers/forge!2574
2020-03-01 15:42:59 +00:00
Tim Mocny
1fee06c843 SLD - Thalia 2020-03-01 15:42:59 +00:00
Hans Mackowiak
23bc7a629b Fix controllerChangeZoneCorrection when ControlGain is undone 2020-03-01 11:47:51 +01:00
Hans Mackowiak
86ec94ca0d Merge branch '1300-crash-on-desktop-1-6-32-snapshot-r123-2020-01-27-1-pm' into 'master'
Resolve "Crash on Desktop 1.6.32 Snapshot r123 (2020-01-27 ~1 PM)"

Closes #1300

See merge request core-developers/forge!2555
2020-03-01 10:30:45 +00:00
Hans Mackowiak
93f0ade107 MustBlockEffect: use Choose Card for Crashing Boars 2020-03-01 10:30:45 +00:00
Michael Kamensky
40bb3d2750 Merge branch 'newBranch' into 'master'
Update Sprite Icons (Default Theme)

See merge request core-developers/forge!2564
2020-03-01 04:16:22 +00:00
Michael Kamensky
86a9cb13d9 Merge branch 'WAR_JP_PW' into 'master'
WAR with Japanese Planeswalkers added (option 2)

Closes #1305

See merge request core-developers/forge!2566
2020-03-01 04:15:18 +00:00
Tim Mocny
e1138ff7b5 WAR with Japanese Planeswalkers added (option 2) 2020-03-01 04:15:17 +00:00
Michael Kamensky
52fe82b834 Merge branch 'sliverfixes' into 'master'
Forum fixes Leap Day

See merge request core-developers/forge!2571
2020-03-01 04:14:47 +00:00
Tim Mocny
15e3c4f5e5 Forum fixes Leap Day 2020-03-01 04:14:47 +00:00
Michael Kamensky
4e5853e29a Merge branch 'triggerFixStack' into 'master'
GameAction: fix Trigger for Stack

Closes #1309

See merge request core-developers/forge!2572
2020-03-01 04:14:44 +00:00
Hans Mackowiak
34d0d143c5 GameAction: fix Trigger for Stack 2020-03-01 04:14:44 +00:00
Michael Kamensky
d37cb22698 Merge branch 'master' into 'master'
Added puzzle PS_THB5 + AI logic improvement for Kenrith, the Returned King

See merge request core-developers/forge!2568
2020-03-01 04:13:57 +00:00
Anthony Calosa
b5787407b6 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-03-01 11:10:55 +08:00
Anthony Calosa
4d1d79098d Better Icon Render 2020-03-01 10:47:48 +08:00
Sol
3fc0c1e20f Merge branch 'fixes' into 'master'
Fixes

See merge request core-developers/forge!2570
2020-03-01 02:44:30 +00:00
Jamin Collins
726b8bfbe5 correct sprite load progress bar to 100% max
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-03-01 02:44:30 +00:00
Anthony Calosa
0306ab97f1 Fix Crash on Desktop, Menu Arrangement, Added some Icons 2020-03-01 07:42:20 +08:00
Jamin Collins
083df572b8 Merge branch 'tinyban' into 'master'
Tiny Leaders ban - Najeela

See merge request core-developers/forge!2569
2020-02-29 21:50:28 +00:00
Tim Mocny
12c705476d Tiny Leaders ban - Najeela 2020-02-29 21:50:28 +00:00
Agetian
4880d70129 - Simple modification for AI PumpAll on Kenrith 2020-02-29 19:33:35 +03:00
Agetian
f49d5e2352 - Better AI targeting for Kenrith, the Returned King's {4}{B} ability. 2020-02-29 19:25:24 +03:00
Agetian
f8b9a31bf2 Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2020-02-29 17:06:04 +03:00
Michael Kamensky
808a43b44d Merge branch 'editions28feb' into 'master'
Editions support for Grand Prix Promos, Unsanctioned

See merge request core-developers/forge!2562
2020-02-29 14:02:09 +00:00
Tim Mocny
f2c523c267 Editions support for Grand Prix Promos, Unsanctioned 2020-02-29 14:02:09 +00:00
Michael Kamensky
b847f7f8c9 Merge branch 'immolation' into 'master'
Mask of Immolation typos fix

See merge request core-developers/forge!2560
2020-02-29 14:01:26 +00:00
Tim Mocny
a9f13ee503 Mask of Immolation typos fix 2020-02-29 14:01:26 +00:00
Agetian
e0b7ea4960 - Added puzzle PS_THB5. 2020-02-29 16:49:53 +03:00
Sol
a41c0454fa Merge branch 'update-modern-banned' into 'master'
updating the Modern banned list

See merge request core-developers/forge!2565
2020-02-29 04:39:58 +00:00
Jamin W. Collins
226716c816 updating Pioneer ban list
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-02-28 19:18:59 -07:00
Jamin W. Collins
3c6f82294b updating the Modern banned list
Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
2020-02-28 19:05:27 -07:00
Anthony Calosa
600d672b4a Update Sprite Icons on Mobile Forge
(Default theme)
2020-02-29 05:05:51 +08:00
Anthony Calosa
48cb11566f Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-02-28 23:16:14 +08:00
Anthony Calosa
c3be51c117 Fix Missing Translation on Planar Conquest 2020-02-28 23:15:29 +08:00
Hans Mackowiak
841808d99a Merge branch 'combo_attack' into 'master'
Band Together / Combo Attack

See merge request core-developers/forge!2551
2020-02-28 15:12:42 +00:00
Tim Mocny
258f0a2072 Band Together / Combo Attack 2020-02-28 15:12:42 +00:00
Michael Kamensky
0b2e60b0c1 Merge branch 'maddening_imp' into 'master'
Maddening Imp round 2

See merge request core-developers/forge!2559
2020-02-28 05:11:31 +00:00
Tim Mocny
669bc9ceaa Maddening Imp round 2 2020-02-28 05:11:31 +00:00
Michael Kamensky
93d9d12879 Merge branch 'maddening_imp' into 'master'
Today's fixes

See merge request core-developers/forge!2558
2020-02-27 04:34:47 +00:00
Tim Mocny
9d0f3f325b Today's fixes 2020-02-27 04:34:47 +00:00
Michael Kamensky
d66b61f0a3 Merge branch 'quenchable_fire' into 'master'
Quenchable Fire - Ready!

Closes #580

See merge request core-developers/forge!2533
2020-02-26 20:01:06 +00:00
Tim Mocny
9d79b6c262 Quenchable Fire - Ready! 2020-02-26 20:01:06 +00:00
Michael Kamensky
7721b227cb Merge branch '24Feb2020' into 'master'
Nahiri, the Lithomancer +2 ability (cosmetic only)

See merge request core-developers/forge!2554
2020-02-26 19:58:08 +00:00
Tim Mocny
d1106f8df7 Nahiri, the Lithomancer +2 ability (cosmetic only) 2020-02-26 19:58:07 +00:00
Michael Kamensky
794fcdafe5 Merge branch 'sld51' into 'master'
SLD - IWD 2020 cards

See merge request core-developers/forge!2557
2020-02-26 19:57:31 +00:00
Tim Mocny
344126d5aa SLD - IWD 2020 cards 2020-02-26 19:57:31 +00:00
Anthony Calosa
2a72a87ef4 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-02-26 23:42:42 +08:00
Michael Kamensky
7b1af4035d Merge branch 'attachNPEfix' into 'master'
AttachEffect: ChooseAnObject if list is empty and chosen is null, don't add to list

See merge request core-developers/forge!2556
2020-02-26 11:05:24 +00:00
Hans Mackowiak
931d08d3ac AttachEffect: ChooseAnObject if list is empty and chosen is null, don't add to list 2020-02-26 11:05:23 +00:00
Michael Kamensky
ea582088a6 Merge branch 'newBranch' into 'master'
Updated Sprite Buttons on Mobile Forge

See merge request core-developers/forge!2552
2020-02-26 04:00:34 +00:00
Sol
468dd46205 Merge branch 'bronzetablet' into 'master'
Bronze Tablet

Closes #37

See merge request core-developers/forge!2493
2020-02-25 16:39:46 +00:00
Tim Mocny
b03f263fce Bronze Tablet 2020-02-25 16:39:45 +00:00
Anthony Calosa
15b69d3d70 Merge remote-tracking branch 'remotes/core/master' into newBranch 2020-02-26 00:07:16 +08:00
Hans Mackowiak
8004892058 Merge branch '1298-wrong-player-controls-etb-trigger-of-clone' into 'master'
Resolve "Wrong player controls ETB trigger of Clone"

Closes #1302 and #1298

See merge request core-developers/forge!2553
2020-02-25 15:03:21 +00:00
Hans Mackowiak
f03e386399 Resolve "Wrong player controls ETB trigger of Clone" 2020-02-25 15:03:20 +00:00
Anthony Calosa
40478a45ac Update Icons 2020-02-25 18:43:57 +08:00
Anthony Calosa
01a17b4b2c Upscaled Zone Icons and FlipCard Icons 2020-02-25 12:23:04 +08:00
friarsol
63f958fa60 Some cleanup 2020-02-24 20:56:59 -05:00
Michael Kamensky
c916c4da31 Merge branch 'tempest_efreet' into 'master'
Tempest Efreet

Closes #115

See merge request core-developers/forge!2550
2020-02-24 09:01:45 +00:00
Tim Mocny
9e79d7810f Tempest Efreet 2020-02-24 09:01:44 +00:00
Michael Kamensky
0dbbcd4edc Merge branch 'newBranch' into 'master'
Upscaled Start Button

See merge request core-developers/forge!2549
2020-02-24 09:00:58 +00:00
Anthony Calosa
eb039b3bdd Update Start Button 2020-02-23 22:38:33 +08:00
Michael Kamensky
9be6a5a6a3 Merge branch 'newBranch' into 'master'
Add Support for HD Buttons on Mobile Forge

See merge request core-developers/forge!2547
2020-02-23 12:44:06 +00:00
Anthony Calosa
81c06f230a Add Support for Upscaling Buttons on Mobile Forge 2020-02-23 19:10:11 +08:00
Michael Kamensky
645a11f9c3 Merge branch 'master' into 'master'
Initial logic implementation for Mercenaries

See merge request core-developers/forge!2546
2020-02-23 05:19:38 +00:00
Agetian
68ca9ec622 - Initial logic implementation for Mercenaries 2020-02-23 08:14:48 +03:00
Michael Kamensky
b4883eb77e Merge branch 'mercenaries' into 'master'
Mercenaries!

See merge request core-developers/forge!2545
2020-02-23 04:39:16 +00:00
Tim Mocny
7e57ffb62d Mercenaries! 2020-02-23 04:39:14 +00:00
Michael Kamensky
820666b278 Merge branch 'fumble' into 'master'
Fumble - Ready!

See merge request core-developers/forge!2535
2020-02-23 04:31:23 +00:00
Tim Mocny
9d0c2968aa Fumble - Ready! 2020-02-23 04:31:23 +00:00
Michael Kamensky
d3f2b07c83 Merge branch 'emergencypowers' into 'master'
Emergency Powers Addendum

See merge request core-developers/forge!2544
2020-02-23 04:31:04 +00:00
Tim Mocny
57ebad948d Emergency Powers Addendum 2020-02-23 04:31:04 +00:00
Michael Kamensky
3f1b9df62a Merge branch '1290-trigger-needs-cleanup-after-cost-is-paid' into 'master'
Resolve "Trigger needs cleanup after cost is paid"

Closes #1290

See merge request core-developers/forge!2543
2020-02-22 14:46:44 +00:00
Hans Mackowiak
f990f19795 Resolve "Trigger needs cleanup after cost is paid" 2020-02-22 14:46:44 +00:00
Michael Kamensky
b2e1855949 Merge branch '1295-runtimeexception-abilityfactory-getability-startled-awake-has-no-svar-trigbounce' into 'master'
Resolve "RuntimeException: AbilityFactory : getAbility -- Startled Awake has no SVar: TrigBounce"

Closes #1295

See merge request core-developers/forge!2540
2020-02-22 11:10:19 +00:00
Hans Mackowiak
850e54fbbc Resolve "RuntimeException: AbilityFactory : getAbility -- Startled Awake has no SVar: TrigBounce" 2020-02-22 11:10:19 +00:00
Michael Kamensky
9931b33be7 Merge branch '1294-anax-hardened-in-the-forge-power-abnormal' into 'master'
Resolve "'Anax, Hardened in the Forge' power abnormal"

Closes #1294

See merge request core-developers/forge!2542
2020-02-22 10:17:40 +00:00
Hans Mackowiak
040518d094 Resolve "'Anax, Hardened in the Forge' power abnormal" 2020-02-22 10:17:40 +00:00
Michael Kamensky
823c651532 Merge branch 'master' into 'master'
Added puzzle PS_THB4 - Possibility Storm - Theros Beyond Death 04

See merge request core-developers/forge!2541
2020-02-22 10:17:32 +00:00
Agetian
b412a361b9 - Added puzzle PS_THB4. 2020-02-22 11:33:32 +03:00
Michael Kamensky
022ea1bb75 Merge branch 'PSLD1292' into 'master'
Secret Lair Promos.txt update

Closes #1292

See merge request core-developers/forge!2538
2020-02-22 06:33:58 +00:00
Tim Mocny
f08f7b09d5 Secret Lair Promos.txt update 2020-02-22 06:33:58 +00:00
Michael Kamensky
16452dd11a Merge branch 'tezzeret21Feb' into 'master'
Forum fixes

See merge request core-developers/forge!2539
2020-02-22 06:33:45 +00:00
Tim Mocny
b0791a0c6a Forum fixes 2020-02-22 06:33:45 +00:00
friarsol
2b8d826209 I think this should be working now! 2020-02-21 22:26:33 -05:00
Michael Kamensky
900ba9ec5b Merge branch '1276-display-divided-value' into 'master'
Display Divided Values in stack description

Closes #1276

See merge request core-developers/forge!2524
2020-02-21 04:08:16 +00:00
Michael Kamensky
8db0281f91 Merge branch '559' into 'master'
Search zones for any number of cards named X and exile (or something else)

Closes #559

See merge request core-developers/forge!2527
2020-02-20 08:43:39 +00:00
Tim Mocny
9637091ab5 Search zones for any number of cards named X and exile (or something else) 2020-02-20 08:43:39 +00:00
Michael Kamensky
45771ec8c0 Merge branch 'mausoleum_wanderer' into 'master'
Mausoleum Wanderer proofread

See merge request core-developers/forge!2532
2020-02-20 08:42:39 +00:00
Tim Mocny
5c3ff8297e Mausoleum Wanderer proofread 2020-02-20 08:42:39 +00:00
Michael Kamensky
722f512e53 Merge branch '504-shared-fate-can-not-cast-spell-queller-via-flash' into 'master'
Resolve "Shared Fate -- can not cast Spell Queller via Flash"

Closes #504

See merge request core-developers/forge!2534
2020-02-20 08:42:33 +00:00
Michael Kamensky
0cceaf0485 Merge branch '1286' into 'master'
Challenger 2020 Precon Decks (Quest Mode)

Closes #1286

See merge request core-developers/forge!2531
2020-02-20 08:40:55 +00:00
Tim Mocny
23d0d70478 Challenger 2020 Precon Decks (Quest Mode) 2020-02-20 08:40:55 +00:00
Hans Mackowiak
2eea49a8e4 Spell: add getAlternateHost for spells that would change the CardState 2020-02-20 07:03:24 +01:00
Michael Kamensky
a7d8a62a69 Merge branch '1288-unstable-shapeshifter-not-unstable' into 'master'
Resolve "Unstable Shapeshifter not unstable"

Closes #1288

See merge request core-developers/forge!2530
2020-02-18 17:03:10 +00:00
Hans Mackowiak
c8fdc6f272 Resolve "Unstable Shapeshifter not unstable" 2020-02-18 17:03:10 +00:00
Sol
9990062ec1 Merge branch '1281-general-ui-display-commander-tax' into 'master'
Resolve "[General / UI] Display Commander Tax"

Closes #1281

See merge request core-developers/forge!2528
2020-02-18 14:23:48 +00:00
Hans Mackowiak
6817b4af66 Resolve "[General / UI] Display Commander Tax" 2020-02-18 14:23:48 +00:00
friarsol
133f1656d8 Some more progress with autoupdate button 2020-02-17 21:51:18 -05:00
friarsol
599d75351c Hook up AutoUpdater to do its thing 2020-02-17 16:51:34 -05:00
Hans Mackowiak
c42202a140 Merge branch 'Hanmac-master-patch-75614' into 'master'
Anax, Hardened in the Forge: updated triggers, need two for itself and other

See merge request core-developers/forge!2496
2020-02-16 15:36:07 +00:00
Hans Mackowiak
d6c0cf6ef8 Anax, Hardened in the Forge: updated triggers, need two for itself and other 2020-02-16 15:36:07 +00:00
MS
72ad7804ca Update CountersPutEffect.java 2020-02-16 07:41:06 +00:00
Michael Kamensky
6bf1af44d8 Merge branch 'master' into 'master'
Added puzzle PS_THB3 - Possibility Storm - Theros Beyond Death 03

See merge request core-developers/forge!2529
2020-02-15 19:13:40 +00:00
Agetian
a74f1a1427 - Added puzzle PS_THB3. 2020-02-15 16:28:36 +03:00
Michael Kamensky
df88cb970f Merge branch '13Feb2020' into 'master'
Quest Shop Precons - Commander 2018

Closes #205

See merge request core-developers/forge!2525
2020-02-15 03:51:04 +00:00
Tim Mocny
452dee7e11 Quest Shop Precons - Commander 2018 2020-02-15 03:51:04 +00:00
Michael Kamensky
f6a6c33193 Merge branch '14Feb2020SLD' into 'master'
SLD - Theros Stargazing

See merge request core-developers/forge!2526
2020-02-15 03:50:36 +00:00
Tim Mocny
6a98c8f371 SLD - Theros Stargazing 2020-02-15 03:50:35 +00:00
Michael Kamensky
9546594e8d Merge branch 'target-other-zones' into 'master'
Show ZoneAreas when targeting non-Stack zones

See merge request core-developers/forge!2492
2020-02-14 15:01:02 +00:00
Michael Kamensky
23f5b7696a Merge branch 'kessCancelFix' into 'master'
HumanPlaySpellAbility: fix CastSA and CastFrom reset when ability is canceld

Closes #1282

See merge request core-developers/forge!2523
2020-02-14 14:01:16 +00:00
Hans Mackowiak
93ae66ad39 HumanPlaySpellAbility: fix CastSA and CastFrom reset when ability is canceld 2020-02-14 14:01:16 +00:00
ESE_Manuel
4d3ce706a5 workaround for divideMap not cleared after canceling ability 2020-02-14 12:50:52 +01:00
ESE_Manuel
5b57ef3531 Revert "fixed bug, dividedMap clear"
This reverts commit eadc0afe1a.
2020-02-14 12:06:02 +01:00
ESE_Manuel
eadc0afe1a fixed bug, dividedMap clear
needs to be cleared when SA was not put on the stack or wrong stack description
2020-02-14 11:38:09 +01:00
ESE_Manuel
687b5f18ef made stack description more clear for DamageDealEffect
changed stack description for distribute parameter (x counter)
2020-02-14 10:54:58 +01:00
ESE_Manuel
25178869ae fallback if there is no targetrestriction on divide damage effects 2020-02-14 10:09:52 +01:00
ESE_Manuel
eedcad8280 removed unused import 2020-02-14 08:32:24 +01:00
ESE_Manuel
50c94755fb Display Divided Values in stack description 2020-02-14 07:58:19 +01:00
friarsol
ec79434759 Improve Android zone restoration 2020-02-13 23:17:26 -05:00
Michael Kamensky
4192d56909 Merge branch 'mana_symbols_vanish' into 'master'
changed hardcoded symbol WIDTH and HEIGHT to constants

See merge request core-developers/forge!2520
2020-02-14 03:26:08 +00:00
Michael Kamensky
2c82aedb74 Merge branch 'bling' into 'master'
Secret Lair Drop Series and Promos

See merge request core-developers/forge!2522
2020-02-13 18:15:02 +00:00
Tim Mocny
049ed5f9c4 Secret Lair Drop Series and Promos 2020-02-13 18:15:02 +00:00
Michael Kamensky
b183862e8d Merge branch 'triggerDamageAll' into 'master'
TriggerDamageAll: add new Trigger for Mindblade Render

See merge request core-developers/forge!2519
2020-02-13 15:12:52 +00:00
Hans Mackowiak
57bc3f930a TriggerDamageAll: add new Trigger for Mindblade Render 2020-02-13 15:12:52 +00:00
Michael Kamensky
48a3b4d652 Merge branch '1272-battle-lands-etb-tap-untap-issue' into 'master'
Resolve "Battle Lands ETB tap/untap issue"

Closes #1272

See merge request core-developers/forge!2521
2020-02-13 15:12:03 +00:00
Hans Mackowiak
bee93cbab3 Player: update LastState when Land is played 2020-02-13 10:29:00 +00:00
Michael Kamensky
9d0a683db8 Merge branch 'release-updates' into 'master'
Update some release files

See merge request core-developers/forge!2516
2020-02-13 05:55:16 +00:00
Michael Kamensky
e163132a1e Merge branch 'bling' into 'master'
Bling cards

See merge request core-developers/forge!2517
2020-02-13 05:54:32 +00:00
Tim Mocny
d35cb8de32 Bling cards 2020-02-13 05:54:31 +00:00
Michael Kamensky
162a27f5a1 Merge branch '12Feb2020' into 'master'
Today's tweaks

See merge request core-developers/forge!2514
2020-02-13 05:53:48 +00:00
Tim Mocny
d1c2096024 Today's tweaks 2020-02-13 05:53:48 +00:00
Zimtente
50c8e129d0 changed hardcoded symbol WIDTH and HEIGHT to constants 2020-02-12 19:07:45 +01:00
Sol
01bd5e5d54 Update CONTRIBUTORS.txt 2020-02-12 18:05:09 +00:00
Sol
562a9e1f8d Update ANNOUNCEMENTS.txt 2020-02-12 18:04:34 +00:00
Sol
548811b370 Merge branch 'mana_symbols_vanish' into 'master'
fixed mana symbols vanishing/not being in the right place in card descriptions

See merge request core-developers/forge!2515
2020-02-12 17:59:25 +00:00
Zimtente
6ae29a311a fixed mana symbols vanishing/not being in the right place in card descriptions 2020-02-12 17:40:50 +01:00
Sol
9934e20f8b Merge branch 'promoarts' into 'master'
Promo arts – correcting a few errors

See merge request core-developers/forge!2513
2020-02-12 14:43:40 +00:00
Tim Mocny
e7a5ee57f1 Promo arts – correcting a few errors 2020-02-12 14:43:40 +00:00
Michael Kamensky
06f2f416e0 Merge branch 'brawl_update' into 'master'
Brawl format update

Closes #1277

See merge request core-developers/forge!2511
2020-02-12 04:24:38 +00:00
Tim Mocny
8bda30179e Brawl format update 2020-02-12 04:24:38 +00:00
Michael Kamensky
9806c2c63c Merge branch 'promoarts' into 'master'
Promo arts update (THB, ELD)

See merge request core-developers/forge!2512
2020-02-12 04:24:23 +00:00
Tim Mocny
9d5d6dd6d2 Promo arts update (THB, ELD) 2020-02-12 04:24:23 +00:00
Michael Kamensky
8fecf07c47 Merge branch '7Feb2020' into 'master'
2/10/2020 tweaks

See merge request core-developers/forge!2508
2020-02-11 03:12:46 +00:00
Tim Mocny
a539d9bf5a 2/10/2020 tweaks 2020-02-11 03:12:46 +00:00
friarsol
ddc531c5f2 Updates for Android 2020-02-10 21:30:19 -05:00
friarsol
ef0a1a843d Pop up other zones during targeting 2020-02-09 21:32:24 -05:00
Michael Kamensky
bf200de73b Merge branch 'triggerFixChangedCopy' into 'master'
Trigger: fix copy need new Map for params

See merge request core-developers/forge!2507
2020-02-09 19:34:03 +00:00
Hans Mackowiak
9a56fb8998 Trigger: fix copy need new Map for params 2020-02-09 19:34:03 +00:00
Michael Kamensky
4a3740dac7 Merge branch 'staticAbilitySuspendedFix' into 'master'
StaticAbility: fix ability is removed by other ability

See merge request core-developers/forge!2505
2020-02-08 17:33:05 +00:00
Hans Mackowiak
31145ef2eb StaticAbility: fix ability is removed by other ability 2020-02-08 17:33:04 +00:00
Michael Kamensky
23ab256f7d Merge branch 'gameActionCloneFix' into 'master'
GameAction: fix Clone working again

See merge request core-developers/forge!2506
2020-02-08 17:33:00 +00:00
Hans Mackowiak
0f435b58a1 GameAction: fix Clone working again 2020-02-08 18:17:21 +01:00
Michael Kamensky
5d1a0421fd Merge branch 'fixAddTypeChosen' into 'master'
StaticAbilityContinuous: fix AddType ChosenType

See merge request core-developers/forge!2504
2020-02-08 04:44:45 +00:00
Hans Mackowiak
55ed4c1bc0 StaticAbilityContinuous: fix AddType ChosenType 2020-02-08 04:44:45 +00:00
Michael Kamensky
22a6a72f12 Merge branch 'master' into 'master'
Added puzzle PS_THB2 - Possibility Storm - Theros Beyond Death 02

See merge request core-developers/forge!2503
2020-02-07 18:14:55 +00:00
Agetian
7c38ac7dfa - Fixed scripted targeting in GameState not remembering targets when necessary.
- Added puzzle PS_THB2.
2020-02-07 20:54:36 +03:00
Michael Kamensky
d29dc72831 Merge branch 'fixesGrafCage' into 'master'
Fixes graf cage

Closes #1195

See merge request core-developers/forge!2377
2020-02-07 17:29:54 +00:00
Hans Mackowiak
e062c83c02 Fixes graf cage 2020-02-07 17:29:54 +00:00
Hans Mackowiak
c25971bba9 Merge branch '6Feb2020' into 'master'
tawnos_urzas_apprentice.txt UI tweaks ONLY

See merge request core-developers/forge!2500
2020-02-07 04:58:58 +00:00
Tim Mocny
92a11d801c tawnos_urzas_apprentice.txt UI tweaks ONLY 2020-02-07 04:58:57 +00:00
Michael Kamensky
87e6b38fa5 Merge branch 'patch-8' into 'master'
Update new translations es-ES.properties

See merge request core-developers/forge!2491
2020-02-07 04:09:34 +00:00
Michael Kamensky
2dcc56934d Merge branch 'ashiok' into 'master'
Improve cleanup on ashiok

See merge request core-developers/forge!2490
2020-02-07 04:07:39 +00:00
Michael Kamensky
f5cb80cec5 Merge branch 'magicStackSpellAbilityFix' into 'master'
Magic stack spell ability fix

See merge request core-developers/forge!2501
2020-02-07 04:06:55 +00:00
Hans Mackowiak
1d71b1efea Magic stack spell ability fix 2020-02-07 04:06:54 +00:00
Michael Kamensky
62e206f8ed Merge branch 'effectUntilCounterRemoved' into 'master'
Refactor: Effects with "For as long" it has CounterType

Closes #1271

See merge request core-developers/forge!2494
2020-02-07 04:06:25 +00:00
Hans Mackowiak
0de140538c Refactor: Effects with "For as long" it has CounterType 2020-02-07 04:06:24 +00:00
Michael Kamensky
55167c5dca Merge branch 'master' into 'master'
Fix AI for Domri's Ambush

Closes #1273

See merge request core-developers/forge!2499
2020-02-06 18:17:56 +00:00
Michael Kamensky
9c78dbfde4 Merge branch 'pioneerdeckgenthb' into 'master'
Updated pioneer and standard data for theros metagame

See merge request core-developers/forge!2498
2020-02-06 17:47:15 +00:00
Agetian
0ca0458656 - Fix AI for Domri's Ambush.
- Don't reset targets on DamageDealAi if it's parented to an ability with valid number of targets set.
2020-02-06 20:33:56 +03:00
austinio7116
1b86738d10 Updated pioneer and standard data for theros metagame
(cherry picked from commit 4b503cb)
2020-02-06 11:27:52 +00:00
swordshine
ccfbaf5b3d Merge branch '5Feb2020' into 'master'
2/5/2020 fixes

See merge request core-developers/forge!2497
2020-02-06 09:37:18 +00:00
Tim Mocny
16ecae29f0 2/5/2020 fixes 2020-02-06 09:37:18 +00:00
Michael Kamensky
7a9fb7a4d8 Merge branch '4Feb2020' into 'master'
Today's tweaks

See merge request core-developers/forge!2495
2020-02-05 03:45:14 +00:00
Tim Mocny
aef84aed51 Today's tweaks 2020-02-05 03:45:14 +00:00
klaxnek
a8b1ce3c32 Update es-ES.properties 2020-02-04 20:39:51 +00:00
klaxnek
7dde40beff Update new translations es-ES.properties 2020-02-03 20:15:15 +00:00
Adam Pantel
ccf39adde4 Improve cleanup on ashiok 2020-02-03 14:24:48 -05:00
Michael Kamensky
5b37a6fb53 Merge branch 'rebirth' into 'master'
Rebirth

See merge request core-developers/forge!2487
2020-02-03 16:00:50 +00:00
Tim Mocny
942225291f Rebirth 2020-02-03 16:00:50 +00:00
Michael Kamensky
4787784d15 Merge branch 'master' into 'master'
translate some text and fix Localizer

Closes #1270

See merge request core-developers/forge!2450
2020-02-03 15:05:28 +00:00
Sol
093f157f77 Merge branch 'master' into 'master'
MillAI logic for Rebirth.

See merge request core-developers/forge!2489
2020-02-03 14:55:17 +00:00
Agetian
78f3614c0a - Smaller life threshold for AILogic Rebirth. 2020-02-03 17:49:01 +03:00
Agetian
ae060a1b76 - MillAI logic for Rebirth. 2020-02-03 17:29:46 +03:00
Michael Kamensky
244b3d6d24 Merge branch 'staticKeywordChangeList' into 'master'
refactor Keywords using Chosen Values

See merge request core-developers/forge!2462
2020-02-03 11:35:28 +00:00
Hans Mackowiak
01bf10c719 refactor Keywords using Chosen Values 2020-02-03 11:35:28 +00:00
CCTV-1
5718072f60 fix miss call Localizer.getInstance().getMessage 2020-02-03 19:31:57 +08:00
CCTV-1
1dfd977238 fix compile error 2020-02-03 18:48:30 +08:00
CCTV-1
9030a39d1d update translation 2020-02-03 18:43:10 +08:00
CCTV-1
d74a4143f3 translate mulligan log 2020-02-03 18:42:35 +08:00
CCTV-1
f6509dd30e Merge remote-tracking branch 'upstream/master' 2020-02-03 18:40:13 +08:00
Michael Kamensky
6c512dd451 Merge branch 'allBasicLandType' into 'master'
All basic land type and AdjustLandPlays

See merge request core-developers/forge!2467
2020-02-03 10:09:45 +00:00
Hans Mackowiak
00c83f1d25 All basic land type and AdjustLandPlays 2020-02-03 10:09:45 +00:00
Michael Kamensky
28615040e8 Merge branch '1269-momir-basic-mode-broken' into 'master'
Resolve "Momir Basic Mode Broken"

Closes #1269

See merge request core-developers/forge!2488
2020-02-03 09:44:42 +00:00
Hans Mackowiak
0482d4636b Resolve "Momir Basic Mode Broken" 2020-02-03 09:44:42 +00:00
Michael Kamensky
86de537fcb Merge branch 'keywordLanguageChange' into 'master'
Keyword: fix problems with other languages

See merge request core-developers/forge!2485
2020-02-03 05:03:29 +00:00
Hans Mackowiak
fb7fdb65f2 Keyword: fix problems with other languages 2020-02-03 05:03:29 +00:00
Sol
15c36118d6 Merge branch '2Feb2020' into 'master'
little Elspeth PW deck edition tweak

See merge request core-developers/forge!2486
2020-02-03 02:26:43 +00:00
Tim Mocny
092eae52fe little Elspeth PW deck edition tweak 2020-02-03 02:26:43 +00:00
CCTV-1
ac58058938 escape single quotes 2020-02-03 09:26:58 +08:00
CCTV-1
64117ad1fc update translation 2020-02-02 19:48:56 +08:00
Michael Kamensky
317833af6d Merge branch 'master' into 'master'
Added puzzle PS_THB1 (both variants A and B)

See merge request core-developers/forge!2484
2020-02-02 10:25:30 +00:00
Agetian
54d367ae8c - Added puzzle PS_THB1 (both variants A and B). 2020-02-02 10:36:01 +03:00
CCTV-1
1381de7d55 add comment 2020-02-02 09:14:43 +08:00
CCTV-1
caacde3aad non creature permanent effect translation 2020-02-02 09:14:12 +08:00
CCTV-1
49e55f1326 update translation 2020-02-02 08:48:53 +08:00
CCTV-1
5082da429f log formatter full translation 2020-02-02 08:48:34 +08:00
CCTV-1
ea4e821f51 Merge remote-tracking branch 'upstream/master' 2020-02-02 08:43:42 +08:00
Sol
83c0195648 Merge branch '31Jan2020' into 'master'
Today's tweaks

See merge request core-developers/forge!2483
2020-02-01 03:58:34 +00:00
Tim Mocny
5c465f8bf0 Today's tweaks 2020-02-01 03:58:34 +00:00
Michael Kamensky
c670d175d9 Merge branch 'master' into 'master'
Check to make sure the cards are targetable by AI in DamageDealAi (mandatory).

See merge request core-developers/forge!2481
2020-01-31 14:38:37 +00:00
Agetian
415e2a1623 - Remove the unneeded mandatory parameter. 2020-01-31 16:54:29 +03:00
Agetian
dff5962b8e - Check to make sure the cards are targetable by AI. 2020-01-31 15:05:56 +03:00
Michael Kamensky
d7febae2e1 Merge branch 'master' into 'master'
Improved DamageDealAi and DrawAi

Closes #1267

See merge request core-developers/forge!2480
2020-01-31 10:20:22 +00:00
Michael Kamensky
a757e033d9 Merge branch 'triggerRunParams' into 'master'
Trigger: remove runParams from Trigger

See merge request core-developers/forge!2479
2020-01-31 10:15:31 +00:00
Hans Mackowiak
c3b05157c5 Trigger: remove runParams from Trigger 2020-01-31 10:15:31 +00:00
Agetian
cb3430b806 - Remove the unneeded mandatory check 2020-01-31 13:08:01 +03:00
Agetian
a86dad40c3 - DamageDealAi: target own indestructible stuff when able (if mandatory and has no better targets) 2020-01-31 12:46:32 +03:00
Agetian
04066b9bc2 - Fix DrawAi not accounting for pay costs on trigger 2020-01-31 12:34:05 +03:00
Agetian
6580883ccc - Improved DamageDealAi for mandatory triggers requiring a choice of planeswalker (e.g. Chandra, Artisan of Fire vs. a Hexproof opponent) 2020-01-31 09:58:51 +03:00
CCTV-1
fa30bbe67c Merge remote-tracking branch 'upstream/master' 2020-01-31 09:10:46 +08:00
CCTV-1
e39b70a5d8 update translation 2020-01-31 09:10:29 +08:00
CCTV-1
45f33106f2 display escape exile card progress 2020-01-31 09:10:01 +08:00
Michael Kamensky
415f911e46 Merge branch 'stupidideas' into 'master'
Soul Echo!

See merge request core-developers/forge!2475
2020-01-30 13:19:27 +00:00
Tim Mocny
7b4b869992 Soul Echo! 2020-01-30 13:19:26 +00:00
Michael Kamensky
3d57759d73 Merge branch 'patch-3' into 'master'
Update net-decks.txt adding Current MTGA Decks

See merge request core-developers/forge!2473
2020-01-30 13:15:26 +00:00
Michael Kamensky
ad0bec318f Merge branch '29Jan2020forumfixes' into 'master'
Various fixes reported on forum

See merge request core-developers/forge!2476
2020-01-30 13:12:24 +00:00
Tim Mocny
9571b2695f Various fixes reported on forum 2020-01-30 13:12:24 +00:00
Michael Kamensky
f09bcc4a66 Merge branch 'master' into 'master'
Fix Garruk, Cursed Huntsman achievement definition.

Closes #1262

See merge request core-developers/forge!2477
2020-01-30 13:09:39 +00:00
Agetian
fc424b1bdd - Fix Garruk, Cursed Huntsman achievement definition. 2020-01-30 14:19:13 +03:00
CCTV-1
8a9b7c562c fix lblReturnForLondon translation 2020-01-30 11:00:45 +08:00
CCTV-1
4d9c730f6f make zh-CN reminder text work(update generate script) 2020-01-29 20:16:14 +08:00
CCTV-1
9a1223c228 fix INVALID PROPERTY: 'Report' 2020-01-29 09:58:21 +08:00
CCTV-1
d7787dc974 update translation 2020-01-29 08:12:55 +08:00
CCTV-1
a3f30d899b fix missing prompt translation 2020-01-29 08:12:38 +08:00
Churrufli
ca48e75a9d Update net-decks.txt adding Current MTGA Decks 2020-01-28 22:16:33 +00:00
CCTV-1
e5051d2635 Merge remote-tracking branch 'upstream/master' 2020-01-28 22:34:10 +08:00
Michael Kamensky
c5a6145ed7 Merge branch 'patch-7' into 'master'
Mobile: AI Personality Translation

See merge request core-developers/forge!2454
2020-01-28 13:23:50 +00:00
Michael Kamensky
b2398ec8e0 Merge branch 'thbtranslation' into 'master'
Updated card translations (Theros: Beyond Death)

See merge request core-developers/forge!2471
2020-01-28 13:22:52 +00:00
Michael Kamensky
1b739ab6e5 Merge branch 'fix-thb-edition' into 'master'
Updating edition file until we have extra art ready to download

See merge request core-developers/forge!2465
2020-01-28 13:22:27 +00:00
Michael Kamensky
2e20a88b3b Merge branch '27jan2020' into 'master'
viviens_grizzly.txt fix

See merge request core-developers/forge!2470
2020-01-28 13:21:53 +00:00
Tim Mocny
9d6798e698 viviens_grizzly.txt fix 2020-01-28 13:21:53 +00:00
klaxnek
f3078059b2 Updated card translations (Theros: Beyond Death). Added Italian to script. 2020-01-28 10:05:23 +01:00
CCTV-1
fe2c3c90d6 Merge remote-tracking branch 'upstream/master' 2020-01-28 08:47:21 +08:00
Michael Kamensky
b994bce116 Merge branch 'master' into 'master'
Added puzzle PS_THB0b - Possibility Storm - Theros Beyond Death 00b (Preseason Puzzle 2)

See merge request core-developers/forge!2466
2020-01-26 16:45:38 +00:00
Agetian
f86d6fc2a8 - Added puzzle PS_THB0b. 2020-01-26 13:55:07 +03:00
CCTV-1
747fa3eb3c update translation 2020-01-26 09:17:09 +08:00
CCTV-1
f723f3347a fix INVALID PROPERTY: 'lblAbleToCastAnytingNiceBeing.' 2020-01-26 09:16:56 +08:00
friarsol
8d1367461d Updating edition file until we have extra art ready to download 2020-01-25 19:44:20 -05:00
CCTV-1
3fd3b2d642 update translation 2020-01-25 20:58:08 +08:00
CCTV-1
0f853983c9 translate some Achievements 2020-01-25 20:57:10 +08:00
CCTV-1
1d20aeddda update translation 2020-01-25 13:57:54 +08:00
CCTV-1
ba10aa935a display localization card name/type 2020-01-25 13:57:34 +08:00
CCTV-1
56c63bc6d1 translate some text 2020-01-25 13:54:32 +08:00
CCTV-1
ef70434277 update translation 2020-01-25 10:51:00 +08:00
CCTV-1
313112a488 translate some text 2020-01-25 10:50:39 +08:00
CCTV-1
9030939938 Merge remote-tracking branch 'upstream/master' 2020-01-25 09:20:03 +08:00
Michael Kamensky
c87fdb820b Merge branch 'issue1253' into 'master'
Number of colors matters cards

Closes #1253

See merge request core-developers/forge!2464
2020-01-24 15:21:09 +00:00
Tim Mocny
fd260af645 Number of colors matters cards 2020-01-24 15:21:08 +00:00
CCTV-1
f7904aac2b Merge remote-tracking branch 'upstream/master' 2020-01-24 09:43:40 +08:00
CCTV-1
c338988650 update translation 2020-01-24 09:42:12 +08:00
CCTV-1
07c4e1b57b fix translation lable typo,incorrect use of symbolLookup. 2020-01-24 09:41:38 +08:00
Michael Kamensky
a5b58aa3ae Merge branch 'patch-3' into 'master'
Update nightcreep, added missing RemoveIntrinsicAbilities

See merge request core-developers/forge!2463
2020-01-23 09:13:11 +00:00
Hans Mackowiak
31fc6e3650 Update nightcreep, added missing RemoveIntrinsicAbilities 2020-01-23 09:13:11 +00:00
CCTV-1
75dc2674d6 update translation 2020-01-23 12:54:10 +08:00
CCTV-1
f212cf1dc8 translate SleeveSelector 2020-01-23 12:53:10 +08:00
CCTV-1
0a3f1bf43c Merge remote-tracking branch 'upstream/master' 2020-01-23 12:52:10 +08:00
Michael Kamensky
1039657a82 Merge branch '22Jan2020' into 'master'
thassa_deep_dwelling.txt fix

Closes #1246

See merge request core-developers/forge!2461
2020-01-23 04:37:59 +00:00
Tim Mocny
43299a5298 thassa_deep_dwelling.txt fix 2020-01-23 04:37:59 +00:00
CCTV-1
5f8f82fc93 update Simplified Chinese characters list 2020-01-23 11:51:50 +08:00
CCTV-1
171cc23dba THB card translation 2020-01-23 11:50:12 +08:00
CCTV-1
9e5e05ae3c add ELD Scryfall missing translation 2020-01-23 11:49:55 +08:00
CCTV-1
e67b63375c update translation 2020-01-22 12:52:07 +08:00
CCTV-1
dda23854a3 translate some text 2020-01-22 12:51:44 +08:00
CCTV-1
625673e167 Merge remote-tracking branch 'upstream/master' 2020-01-22 12:48:25 +08:00
swordshine
d8845a413d Merge branch 'removeNoCyclingRule' into 'master'
Remove no cycling rule

See merge request core-developers/forge!2460
2020-01-22 03:43:53 +00:00
Hans Mackowiak
30f80f75df Remove no cycling rule 2020-01-22 03:43:53 +00:00
swordshine
c4c9d5e042 Merge branch 'master' into 'master'
Improve the AI play logic for Lotus Field.

See merge request core-developers/forge!2459
2020-01-22 03:42:08 +00:00
swordshine
b56de30ea2 Merge branch '21Jan2020' into 'master'
Psychic Possession (issue 1239)

Closes #1239

See merge request core-developers/forge!2458
2020-01-22 03:41:37 +00:00
Tim Mocny
2782046bed Psychic Possession (issue 1239) 2020-01-22 03:41:37 +00:00
Agetian
116fa84b16 - Improve the AI play logic for Lotus Field. 2020-01-21 23:02:24 +03:00
Michael Kamensky
bdb10fe59c Merge branch 'master' into 'master'
Added puzzle PS_THB0a - Possibility Storm - Theros Beyond Death 00a (preseason 1)

See merge request core-developers/forge!2457
2020-01-21 17:50:53 +00:00
Agetian
7aa93d61b3 - Added puzzle PS_THB0a. 2020-01-21 20:31:03 +03:00
CCTV-1
74ed34b6dd Merge remote-tracking branch 'upstream/master' 2020-01-21 17:22:43 +08:00
CCTV-1
faf9ace2ab update translation 2020-01-21 17:22:27 +08:00
Michael Kamensky
1602a1e78a Merge branch 'autodownload-expansion' into 'master'
Auto download from Quest WinLose screen

See merge request core-developers/forge!2456
2020-01-21 06:38:01 +00:00
Michael Kamensky
c6b0a0e072 Merge branch 'fixEnumTypes' into 'master'
Use EnumSet in Conditions/Restrictions

See merge request core-developers/forge!2455
2020-01-21 06:37:53 +00:00
Hans Mackowiak
311eaa70e3 Use EnumSet in Conditions/Restrictions 2020-01-21 06:37:53 +00:00
friarsol
659b1c7a63 Auto download from Quest WinLose screen 2020-01-20 21:55:12 -05:00
CCTV-1
c29432cef2 update translation 2020-01-20 23:46:12 +08:00
CCTV-1
7256cc2f8f translate mobile PlanarConquest and other some text 2020-01-20 23:45:49 +08:00
Sol
a9693495d7 Update mystic_sanctuary.txt 2020-01-20 04:22:24 +00:00
CCTV-1
feae4ebf81 fix:charset detect don't work 2020-01-20 11:24:20 +08:00
CCTV-1
e97ca38cbe fix var name wrong 2020-01-20 09:35:06 +08:00
CCTV-1
eff1be31da fix:in desktop,use chinese,if translation text use placeholder strings, getMessage return a garbled string(a string,the content have two encoding) 2020-01-20 09:26:52 +08:00
CCTV-1
9ee07411d0 Merge remote-tracking branch 'upstream/master' 2020-01-20 09:18:20 +08:00
klaxnek
a0e94f2f51 Mobile: AI Personality Translation 2020-01-19 16:09:47 +00:00
CCTV-1
be99725251 fix missing translation 2020-01-19 18:58:41 +08:00
Michael Kamensky
25e9b942b1 Merge branch 'master' into 'master'
Improve ProtectAi for cards that sacrifice themselves as a part of cost payment.

See merge request core-developers/forge!2453
2020-01-19 07:26:13 +00:00
Agetian
ac041a79f6 - Improve ProtectAi for cards that sacrifice themselves as a part of cost payment. 2020-01-19 10:18:01 +03:00
Michael Kamensky
c59d99b8ae Merge branch 'master' into 'master'
Preparing Forge for Android publish 1.6.32.001 [incremental].

See merge request core-developers/forge!2452
2020-01-19 05:22:28 +00:00
Agetian
3885e02d60 - Preparing Forge for Android publish 1.6.32.001 [incremental]. 2020-01-19 08:11:34 +03:00
CCTV-1
8b432cffd9 update translation 2020-01-19 10:04:25 +08:00
CCTV-1
51e5ce0e17 translate advanced search 2020-01-19 10:04:14 +08:00
CCTV-1
f2f984aff6 Merge remote-tracking branch 'upstream/master' 2020-01-19 10:03:19 +08:00
Blacksmith
a0d8a8a241 Clear out release files in preparation for next release 2020-01-19 00:59:24 +00:00
Blacksmith
b8101d0387 [maven-release-plugin] prepare for next development iteration 2020-01-19 00:54:23 +00:00
Blacksmith
55d02d5adb [maven-release-plugin] prepare release forge-1.6.32 2020-01-19 00:54:18 +00:00
Blacksmith
cf91b69d90 Update README.txt for release 2020-01-19 00:51:26 +00:00
Michael Kamensky
c2fdd86c29 Merge branch 'master' into 'master'
THB basic AI hints, quest precons, achievements, minor fixes + ELD quest precons

See merge request core-developers/forge!2451
2020-01-18 08:10:12 +00:00
Agetian
81af887694 - Enable THB on the Theros plane in Planar Conquest. 2020-01-18 10:47:52 +03:00
Agetian
85ef3aaa23 - Only 3 known booster pack images for ELD 2020-01-18 10:46:00 +03:00
Agetian
c8610da04b - Added quest precons for ELD and THB.
- Fixed a quest precon: Simic Guild Kit.
2020-01-18 10:27:47 +03:00
Agetian
490e204060 - Stylistic correction for an achievement. 2020-01-18 10:27:13 +03:00
Agetian
b2044944ff - THB achievements by Marek14. 2020-01-18 10:26:47 +03:00
Agetian
cbf7cc0b4c - Basic AI hints for THB. Minor card corrections. 2020-01-18 10:26:17 +03:00
CCTV-1
b9dbc14a4d Merge remote-tracking branch 'upstream/master' 2020-01-18 14:06:31 +08:00
CCTV-1
d1364066db update translation 2020-01-18 14:06:02 +08:00
CCTV-1
72d16f0636 translate some text 2020-01-18 14:05:40 +08:00
swordshine
3aa43b8246 Merge branch 'fix-translation' into 'master'
Fix missing translation

See merge request core-developers/forge!2449
2020-01-18 04:59:04 +00:00
Sol
ad288f5303 Merge branch 'thb17janb' into 'master'
THB fixes

See merge request core-developers/forge!2448
2020-01-18 04:21:49 +00:00
Tim Mocny
fcc96cf303 THB fixes 2020-01-18 04:21:48 +00:00
friarsol
ca1504b839 Fix missing translation 2020-01-17 23:20:39 -05:00
Sol
e265cb84cc Merge branch 'thb-formats' into 'master'
Add THB to rotating formats

See merge request core-developers/forge!2447
2020-01-18 03:01:27 +00:00
friarsol
6452189938 Add THB to rotating formats 2020-01-17 21:43:17 -05:00
Sol
3d7bd388e1 Merge branch 'patch-3' into 'master'
Update arena_trickster.txt

See merge request core-developers/forge!2446
2020-01-17 20:56:17 +00:00
Sol
21cfcac0c9 Merge branch 'thb17jan' into 'master'
THB 1/17

See merge request core-developers/forge!2445
2020-01-17 19:34:29 +00:00
Tim Mocny
5eae6acae0 THB 1/17 2020-01-17 19:34:28 +00:00
Sol
1c0cb3a885 Update arena_trickster.txt 2020-01-17 19:33:52 +00:00
Hans Mackowiak
b43fbcfabc Merge branch 'patch-3' into 'master'
Update dreamshaper_shaman.txt

See merge request core-developers/forge!2444
2020-01-17 14:27:07 +00:00
Sol
76146d3c6b Update dreamshaper_shaman.txt 2020-01-17 14:08:36 +00:00
Sol
641a443c82 Merge branch 'migrate-tbd' into 'master'
Migrating Theros Beyond Death

See merge request core-developers/forge!2443
2020-01-17 13:37:39 +00:00
tehdiplomat
e1027ce7ef Migrating Theros Beyond Death 2020-01-17 08:31:28 -05:00
Sol
46422a163b Merge branch 'patch-2' into 'master'
Update ANNOUNCEMENTS.txt

See merge request core-developers/forge!2442
2020-01-17 13:20:30 +00:00
Sol
556d8bfd48 Update ANNOUNCEMENTS.txt 2020-01-17 13:15:15 +00:00
swordshine
5b8e709271 Merge branch 'mana-duplication' into 'master'
Maybe fix Mana Reflection mana duplication

See merge request core-developers/forge!2430
2020-01-17 13:09:25 +00:00
Michael Kamensky
6fce5cc5a4 Merge branch 'patch011520' into 'master'
More Oracle updates, Essence of the Wild fix (issue #1234) and Once and Future QOL

Closes #1234

See merge request core-developers/forge!2439
2020-01-17 04:19:39 +00:00
Tim Mocny
b504b60112 More Oracle updates, Essence of the Wild fix (issue #1234) and Once and Future QOL 2020-01-17 04:19:39 +00:00
Michael Kamensky
c8b4e574b8 Merge branch 'thbdraft' into 'master'
Draft Rankings for THB and other settings to allow drafting

See merge request core-developers/forge!2441
2020-01-17 04:19:29 +00:00
austinio7116
32f117c7ec Added draft block, printsheet and booster details 2020-01-16 21:59:42 +00:00
maustin
95d3642d2e Merge branch 'coremaster' into thbdraft 2020-01-16 21:51:55 +00:00
austinio7116
c2ed631327 Merge branch 'thb15' into 'master'
THB 1/15 tweaks and such

See merge request core-developers/forge!2440
2020-01-16 21:49:58 +00:00
Tim Mocny
1f90f4e470 THB 1/15 tweaks and such 2020-01-16 21:49:58 +00:00
austinio7116
d397db9cfb Added draft rankings 2020-01-16 21:42:42 +00:00
swordshine
b5616362b0 Merge branch 'patch-6' into 'master'
Update es-ES.properties

See merge request core-developers/forge!2438
2020-01-16 01:14:41 +00:00
klaxnek
5d2a32c114 Update es-ES.properties 2020-01-15 15:38:43 +00:00
swordshine
5a64b6c297 Merge branch 'master' into 'master'
translate some text

See merge request core-developers/forge!2436
2020-01-15 13:42:36 +00:00
Michael Kamensky
095e720435 Merge branch 'patch-5' into 'master'
Update StaticAbilityContinuous: for Gain Abilities, only set OriginalHost if it wasn't already set

See merge request core-developers/forge!2437
2020-01-15 13:37:15 +00:00
Hans Mackowiak
6e4908acc3 Update StaticAbilityContinuous: for Gain Abilities, only set OriginalHost if it wasn't already set 2020-01-15 13:37:15 +00:00
CCTV-1
b053f79de3 update translation 2020-01-15 20:20:48 +08:00
CCTV-1
33564d023c translate some text 2020-01-15 20:20:25 +08:00
swordshine
57f445b791 Merge branch 'master' into 'master'
update translation

See merge request core-developers/forge!2433
2020-01-15 11:31:57 +00:00
swordshine
f79e3cad2a Merge branch 'patch-5' into 'master'
Update es-ES.properties

See merge request core-developers/forge!2434
2020-01-15 11:31:27 +00:00
swordshine
0d8a2d4a1d Merge branch 'patch' into 'master'
Add Heliod's Punishment

See merge request core-developers/forge!2435
2020-01-15 11:31:21 +00:00
swordshine
2df1770781 Fix a typo in the oracle text 2020-01-15 18:51:47 +08:00
klaxnek
51ec73bdf9 Update es-ES.properties 2020-01-15 10:42:05 +00:00
klaxnek
4299db4041 Update es-ES.properties 2020-01-15 10:41:09 +00:00
swordshine
c3a95a07a1 Add Heliod's Punishment 2020-01-15 18:39:46 +08:00
CCTV-1
38d614a567 update simplified chinese translation 2020-01-15 16:54:28 +08:00
CCTV-1
c0d77a7fdf fix translation key does not match 2020-01-15 16:53:54 +08:00
swordshine
806d62129b Merge branch 'patch' into 'master'
Add three cards

See merge request core-developers/forge!2432
2020-01-15 08:46:47 +00:00
swordshine
dffd0cd62c Add three cards 2020-01-15 16:33:43 +08:00
swordshine
333a96bb8d Merge branch 'patch' into 'master'
Add Hateful Eidolon

See merge request core-developers/forge!2431
2020-01-15 08:30:41 +00:00
swordshine
1aadc7991f Add Hateful Eidolon 2020-01-15 13:12:47 +08:00
swordshine
a41dc4bbd9 Merge branch 'master' into 'master'
translate some text

See merge request core-developers/forge!2422
2020-01-15 04:00:38 +00:00
friarsol
6529e02c83 Maybe fix Mana Reflection mana duplication 2020-01-14 21:12:47 -05:00
swordshine
476c2e4ce3 Merge branch 'patch' into 'master'
Fix The Birth of Meletis

See merge request core-developers/forge!2429
2020-01-15 02:08:41 +00:00
swordshine
706055f1b5 Fix The Birth of Meletis 2020-01-15 09:21:34 +08:00
swordshine
18c964ee3c Merge branch 'thb14' into 'master'
THB 1/14

See merge request core-developers/forge!2423
2020-01-15 00:48:35 +00:00
Tim Mocny
2a6ba11552 THB 1/14 2020-01-15 00:48:35 +00:00
swordshine
ef9fb6ea68 Merge branch 'temp' into 'master'
Hostage Taker wording

See merge request core-developers/forge!2427
2020-01-15 00:47:59 +00:00
swordshine
7055c11d16 Merge branch 'Jan14Oracle' into 'master'
January 14 Oracle Changes

See merge request core-developers/forge!2426
2020-01-15 00:47:28 +00:00
Tim Mocny
b0bc918bc1 January 14 Oracle Changes 2020-01-15 00:47:28 +00:00
Michael Kamensky
bc030355fc Merge branch 'master' into 'master'
Fix references in Sunbird's Invocation.

See merge request core-developers/forge!2428
2020-01-14 18:06:15 +00:00
Agetian
873c748e76 Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2020-01-14 20:58:45 +03:00
Agetian
9a987ec7a3 - Fix references in Sunbird's Invocation. 2020-01-14 20:55:08 +03:00
Adam Pantel
b7d2790a8b Hostage Taker wording 2020-01-14 12:07:47 -05:00
swordshine
98c7b47681 Merge branch 'patch' into 'master'
Fix Hero of the Games

See merge request core-developers/forge!2425
2020-01-14 15:58:43 +00:00
swordshine
992c81263a Fix Hero of the Games 2020-01-14 23:53:21 +08:00
Hans Mackowiak
d9e9076fb4 Merge branch 'patch-5' into 'master'
Update Throne of Eldraine.txt

See merge request core-developers/forge!2424
2020-01-14 14:21:35 +00:00
Tim Mocny
938d5259a4 Update Throne of Eldraine.txt 2020-01-14 14:21:35 +00:00
CCTV-1
8d64694ac7 update translation 2020-01-14 13:19:20 +08:00
CCTV-1
1a55341dd3 translate some text 2020-01-14 13:18:43 +08:00
swordshine
3f2d70c315 Merge branch 'patch' into 'master'
Add more cards

See merge request core-developers/forge!2421
2020-01-14 01:54:48 +00:00
swordshine
fe005f3232 Add more cards 2020-01-14 09:46:49 +08:00
Hans Mackowiak
38f573bfce Merge branch 'patch' into 'master'
Add more THB cards

See merge request core-developers/forge!2417
2020-01-14 01:15:22 +00:00
swordshine
efc2d3a8e6 Merge branch 'thb13a' into 'master'
THB 1/13

See merge request core-developers/forge!2420
2020-01-14 01:13:09 +00:00
Tim Mocny
b2f0f0ca84 THB 1/13 2020-01-14 01:13:09 +00:00
swordshine
fd347c10d0 Merge branch 'savant' into 'master'
Arcane Savant and friends

See merge request core-developers/forge!2396
2020-01-14 01:12:09 +00:00
swordshine
0aacc3e2da Merge branch 'patch-5' into 'master'
Update rankle_master_of_pranks.txt

See merge request core-developers/forge!2418
2020-01-14 01:03:20 +00:00
Tim Mocny
fea69dfe06 Update rankle_master_of_pranks.txt 2020-01-14 01:03:20 +00:00
swordshine
e8e45cc378 Add Shadowspear 2020-01-13 23:02:49 +08:00
swordshine
5d6047ca7d Merge branch 'patch' into 'master'
Add more THB cards

See merge request core-developers/forge!2416
2020-01-13 14:37:37 +00:00
swordshine
6ad5e6d974 Add more THB cards 2020-01-13 14:37:37 +00:00
swordshine
82ced80a3e Merge branch 'patch' into 'master'
Add more THB cards

See merge request core-developers/forge!2414
2020-01-13 12:47:52 +00:00
swordshine
79347c0f9c Add more THB cards 2020-01-13 12:47:52 +00:00
swordshine
7b060320b5 Merge branch 'patch-4' into 'master'
Update es-ES.properties. Fixed some translations.

See merge request core-developers/forge!2413
2020-01-13 10:38:49 +00:00
klaxnek
38f4d4aa1b Update es-ES.properties. Fixed some translations. 2020-01-13 10:30:30 +00:00
swordshine
3dc80a8342 Merge branch 'master' into 'master'
translate some text

See merge request core-developers/forge!2412
2020-01-13 08:01:55 +00:00
swordshine
8dbfd9050c Merge branch 'thb10b' into 'master'
THB 1/10!

See merge request core-developers/forge!2406
2020-01-13 07:59:46 +00:00
Tim Mocny
c5604bddac THB 1/10! 2020-01-13 07:59:46 +00:00
CCTV-1
789401ed24 fix:some text translate 2020-01-13 13:44:16 +08:00
CCTV-1
c0d967a467 update translation 2020-01-13 13:34:14 +08:00
CCTV-1
75d49554da translate some text 2020-01-13 13:33:55 +08:00
swordshine
d228429b56 Merge branch 'stacktranslation01' into 'master'
StackTranslation01 - Translate PermanentEffect Card Name

See merge request core-developers/forge!2411
2020-01-13 00:44:14 +00:00
swordshine
9630d1a26b Merge branch 'spanishcardsfinal' into 'master'
Spanish Cards Translation (T..Z)

See merge request core-developers/forge!2410
2020-01-13 00:43:35 +00:00
klaxnek
2922f99ae3 Undo changes 2020-01-12 16:41:06 +01:00
klaxnek
cf7a7177c7 Translate PermanentCreatureEffect Card Name 2020-01-12 16:37:06 +01:00
klaxnek
f5dcbf4e6e Wrong commit 2020-01-12 15:02:03 +01:00
klaxnek
60c946a501 Spanish Cards Translation (T..Z). Fixed some untranslated cards. Finished!!! 2020-01-12 14:58:57 +01:00
Peter
28393d4571 Merge branch 'master' of https://git.cardforge.org/core-developers/forge 2020-01-12 14:46:55 +01:00
Michael Kamensky
eacfa96df4 Merge branch 'thb' into 'master'
Whirlwind Denial

See merge request core-developers/forge!2409
2020-01-12 04:40:30 +00:00
Michael Kamensky
576f83b5dc Merge branch 'master' into 'master'
Improve CopyPermanentAi for Bramble Sovereign.

Closes #1231

See merge request core-developers/forge!2408
2020-01-12 04:39:47 +00:00
Adam Pantel
b35ea79083 Whirlwind Denial 2020-01-11 18:20:30 -05:00
Agetian
45f2193e2a - NPE guard. 2020-01-11 16:44:44 +03:00
Agetian
b329786659 - Improve CopyPermanentAi for Bramble Sovereign. 2020-01-11 16:43:20 +03:00
Michael Kamensky
adf181aaec Merge branch 'patch-4' into 'master'
Update seven_dwarves.txt

See merge request core-developers/forge!2407
2020-01-11 04:16:10 +00:00
Sol
a95fff5ae3 Update seven_dwarves.txt 2020-01-11 03:25:58 +00:00
Adam Pantel
f401c3900c Arcane Savant and friends 2020-01-10 18:29:44 -05:00
Michael Kamensky
1f01e2ae16 Merge branch '1228-test-failure-testclonetransform' into 'master'
Resolve "Test failure: testCloneTransform"

Closes #1228

See merge request core-developers/forge!2404
2020-01-10 10:24:07 +00:00
Hans Mackowiak
d5cc3289dc Resolve "Test failure: testCloneTransform" 2020-01-10 10:24:07 +00:00
swordshine
9a0ba159b0 Merge branch 'master' into 'master'
Override getParamOrDefault for the sake of WrappedAbility, fixes Verdurous Gearhulk AI

Closes #1227

See merge request core-developers/forge!2403
2020-01-10 07:47:33 +00:00
Michael Kamensky
71dfe3146b Merge branch 'patch' into 'master'
Add Eidolon of Obstruction

See merge request core-developers/forge!2402
2020-01-10 07:31:00 +00:00
Agetian
9ed01ebbb6 - Override getParamOrDefault for the sake of WrappedAbility, fixes Verdurous Gearhulk AI allocation. 2020-01-10 10:27:30 +03:00
swordshine
0e7af09df3 Add Eidolon of Obstruction 2020-01-10 15:13:26 +08:00
swordshine
3c4844e46d Merge branch 'thb' into 'master'
Fix Dig in Thassas Oracle

See merge request core-developers/forge!2401
2020-01-10 01:11:48 +00:00
swordshine
965b67577a Merge branch 'thb9' into 'master'
THB 1/9

See merge request core-developers/forge!2399
2020-01-10 01:11:28 +00:00
Tim Mocny
8bcb38d4fc THB 1/9 2020-01-10 01:11:28 +00:00
Adam Pantel
071873718e Fix Dig in Thassas Oracle, disallow cancel 2020-01-09 14:16:39 -05:00
Michael Kamensky
7583b67bda Merge branch '1222-exception-with-dfcs-and-copy-effects' into 'master'
Resolve "Exception with DFCs and copy effects"

Closes #1222

See merge request core-developers/forge!2400
2020-01-09 15:32:20 +00:00
Hans Mackowiak
96d3ddf9b5 Resolve "Exception with DFCs and copy effects" 2020-01-09 15:32:20 +00:00
swordshine
dc0ddf542b Merge branch 'temp' into 'master'
Clear controller when leaving battlefield/stack

Closes #619

See merge request core-developers/forge!2397
2020-01-09 14:21:36 +00:00
swordshine
724e483ae3 Merge branch 'patch' into 'master'
Fix Nykthos

See merge request core-developers/forge!2398
2020-01-09 13:06:14 +00:00
swordshine
910fef3ecd Fix Nykthos 2020-01-09 20:59:20 +08:00
Adam Pantel
65288905d0 Clear controller when leaving battlefield/stack 2020-01-08 20:12:13 -05:00
swordshine
82d7171a92 Merge branch 'patch-5' into 'master'
THB 1/8

See merge request core-developers/forge!2395
2020-01-09 00:55:41 +00:00
Tim Mocny
20b51f59b0 Storm Herald - I didn't add AtEOT$ Exile to the animate anticipating some corner case Izzet shenanigans where this card gets flashed in on someone else's turns and the auras last until YOUR next end step. Possible it still can be cleaned up in some way. But this seems correct. 2020-01-09 00:55:41 +00:00
swordshine
16c06c7d7d Merge branch 'thb' into 'master'
Taranika, Thassas Oracle

See merge request core-developers/forge!2393
2020-01-09 00:55:03 +00:00
Adam Pantel
0aa20cb3f4 Taranika, Thassas Oracle 2020-01-08 10:08:59 -05:00
swordshine
71787b7059 Merge branch 'patch' into 'master'
Add Altar of the Pantheon

See merge request core-developers/forge!2392
2020-01-08 10:43:50 +00:00
Michael Kamensky
a9407467a5 Merge branch 'patch-escapeMod' into 'master'
CardFactoryUtil: add Escaped Modifier

See merge request core-developers/forge!2394
2020-01-08 10:18:56 +00:00
Hans Mackowiak
896eb79d2c CardFactoryUtil: add Escaped Modifier 2020-01-08 10:18:56 +00:00
swordshine
fb6f34d67e Merge branch 'spanishcards06' into 'master'
Spanish cards translation (N-O-P-Q-R-S)

See merge request core-developers/forge!2391
2020-01-08 07:33:08 +00:00
Blacksmith
9e9570d191 Clear out release files in preparation for next release 2020-01-08 02:25:33 +00:00
Blacksmith
1b130ab157 [maven-release-plugin] prepare for next development iteration 2020-01-08 02:20:36 +00:00
Blacksmith
74005529f5 [maven-release-plugin] prepare release forge-1.6.31 2020-01-08 02:20:31 +00:00
Blacksmith
4186a365cb Update README.txt for release 2020-01-08 02:18:23 +00:00
swordshine
4366db1acc Add Altar of the Pantheon 2020-01-08 08:42:28 +08:00
klaxnek
4679e00a9e Spanish cards translation (N-O-P-Q-R-S) 2020-01-07 17:32:06 +01:00
Michael Kamensky
51960f0e28 Merge branch 'temp' into 'master'
DigUntil should do nothing on 0

See merge request core-developers/forge!2390
2020-01-07 16:29:43 +00:00
Adam Pantel
a27f69b1c5 DigUntil does nothing on 0 2020-01-07 10:06:33 -05:00
Michael Kamensky
8ab01cce3e Merge branch 'patch' into 'master'
Update Pharika's Spawn using ImmediateTrigger

See merge request core-developers/forge!2388
2020-01-07 11:54:20 +00:00
swordshine
e10235aae9 Remove a cleanup for Atris 2020-01-07 16:48:27 +08:00
swordshine
05591c6bd9 Atris should use targeting 2020-01-07 16:46:16 +08:00
swordshine
a25e469291 Simplify the script of Aphemia, the Cacophony 2020-01-07 14:41:50 +08:00
swordshine
ebd14944c6 Update Pharika's Spawn using ImmediateTrigger 2020-01-07 14:35:23 +08:00
swordshine
1b08fc3592 Merge branch 'patch-5' into 'master'
THB 1/6

See merge request core-developers/forge!2384
2020-01-07 06:29:45 +00:00
Tim Mocny
57457946e5 THB 1/6 2020-01-07 06:29:45 +00:00
Michael Kamensky
918a39ab60 Merge branch 'prerelease-standardization' into 'master'
Prerelease standardization

Closes #520

See merge request core-developers/forge!2379
2020-01-07 05:59:26 +00:00
Sol
2cc39c2580 Prerelease standardization 2020-01-07 05:59:26 +00:00
swordshine
3aca94dc9b Merge branch 'temp' into 'master'
Kiora, Uro

See merge request core-developers/forge!2385
2020-01-07 05:52:40 +00:00
apantel
65ad9d61d9 Kiora, Uro 2020-01-06 23:41:40 -05:00
swordshine
138e3a4661 Merge branch 'bug-fixes' into 'master'
Extracting two bugfixes from Lerio's MR

Closes #1211

See merge request core-developers/forge!2387
2020-01-07 04:12:37 +00:00
Sol
41844ee7e3 Extracting two bugfixes from Lerio's MR 2020-01-07 04:12:37 +00:00
Sol
d4f2594e26 Merge branch 'patch-4' into 'master'
ghireds_belligerence fix damage

See merge request core-developers/forge!2386
2020-01-07 02:02:54 +00:00
Hans Mackowiak
babc9de575 ghireds_belligerence fix damage 2020-01-07 02:02:54 +00:00
Michael Kamensky
11a5683025 Merge branch 'patch-3' into 'master'
Update missing translations in es-ES.properties

See merge request core-developers/forge!2383
2020-01-06 14:42:21 +00:00
Michael Kamensky
b6f8f89c7a Merge branch 'spanishcards05' into 'master'
Spanish cards translation (L and M)

See merge request core-developers/forge!2382
2020-01-06 14:42:16 +00:00
klaxnek
0885fe5898 Update es-ES.properties 2020-01-06 14:14:15 +00:00
klaxnek
8aa1f049ab Update missing translations in es-ES.properties 2020-01-06 11:44:58 +00:00
Peter
f7aa7bf580 Spanish cards translation (L and M) 2020-01-06 11:43:01 +01:00
Michael Kamensky
b74033fe17 Merge branch 'temp' into 'master'
Unneeded SubAbility on Primordial Mist

See merge request core-developers/forge!2380
2020-01-06 06:35:34 +00:00
Michael Kamensky
596296cabf Merge branch 'dashAltFix' into 'master'
Dash: fix keyword after AlternativeCost

See merge request core-developers/forge!2381
2020-01-06 06:35:15 +00:00
Hans Mackowiak
adcd86e7d7 Dash: fix keyword after AlternativeCost 2020-01-06 06:35:14 +00:00
Adam Pantel
308768ae50 Unneeded SubAbility on Primordial Mist 2020-01-05 23:42:31 -05:00
swordshine
235636ca4a Merge branch 'patch' into 'master'
Update more scripts

See merge request core-developers/forge!2376
2020-01-05 08:13:41 +00:00
swordshine
359ce5e39d Update more scripts 2020-01-05 15:54:15 +08:00
swordshine
c6e13e98b3 Merge branch 'patch-9' into 'master'
THB 1/4

See merge request core-developers/forge!2375
2020-01-05 07:52:40 +00:00
Tim Mocny
0cc9687e39 THB 1/4 2020-01-05 07:52:39 +00:00
swordshine
3d59f1832c Allure of the Unknown should reveal first 2020-01-05 14:09:33 +08:00
swordshine
58fdd58e9a Update scripts 2020-01-05 13:29:50 +08:00
swordshine
ea661c4fbb Merge branch 'translation' into 'master'
Keep translation files in sync

See merge request core-developers/forge!2374
2020-01-05 03:08:51 +00:00
Dagin
28abe52106 Keep translation files in sync 2020-01-04 20:23:05 +01:00
swordshine
e689fd8721 Merge branch 'master' into 'master'
fix card name translation

See merge request core-developers/forge!2373
2020-01-04 15:51:00 +00:00
CCTV-1
fea6c85e97 Merge remote-tracking branch 'upstream/master' 2020-01-04 22:25:17 +08:00
CCTV-1
4e80a1b818 get correct localization card name 2020-01-04 22:23:20 +08:00
Michael Kamensky
bdde3520f4 Merge branch 'patch' into 'master'
Update Haktos the Unscarred

See merge request core-developers/forge!2371
2020-01-04 10:21:08 +00:00
swordshine
165ae649b1 Merge branch 'temp' into 'master'
Fix more localization mismatches

See merge request core-developers/forge!2372
2020-01-04 05:57:59 +00:00
Adam Pantel
0536ebf1c8 Fix more localization mismatches 2020-01-03 23:21:13 -05:00
swordshine
fb176abe05 Update Haktos the Unscarred 2020-01-04 12:08:52 +08:00
swordshine
28f0232736 Merge branch 'temp' into 'master'
Mismatched localization labels

See merge request core-developers/forge!2370
2020-01-04 01:18:29 +00:00
swordshine
4c29fd8faf Merge branch 'patch-8' into 'master'
Update the_royal_scions.txt

See merge request core-developers/forge!2368
2020-01-04 01:17:32 +00:00
swordshine
df8d289ee0 Merge branch 'patch-7' into 'master'
Update synthetic_destiny.txt

See merge request core-developers/forge!2367
2020-01-04 01:17:03 +00:00
Tim Mocny
203de48dd4 Update synthetic_destiny.txt 2020-01-04 01:17:03 +00:00
swordshine
97f763b1a0 Merge branch 'patch-6' into 'master'
THB 12/31

See merge request core-developers/forge!2360
2020-01-04 01:15:59 +00:00
Tim Mocny
9fd8969ea5 THB 12/31 2020-01-04 01:15:58 +00:00
Adam Pantel
d70e699c81 Mismatched localization labels 2020-01-03 16:06:01 -05:00
Tim Mocny
39bf8f5313 Update the_royal_scions.txt 2020-01-03 14:58:57 +00:00
swordshine
68eb8e2510 Merge branch 'master' into 'master'
use localization card name in translation text

See merge request core-developers/forge!2357
2020-01-03 13:32:01 +00:00
Michael Kamensky
a20800cfb3 Merge branch 'patch-2' into 'master'
Update es-ES.properties

See merge request core-developers/forge!2366
2020-01-03 13:11:02 +00:00
Michael Kamensky
adce811a3d Merge branch 'devotion-choosecolor' into 'master'
Added a simple logic for ChooseColor based on devotion (Nyx Lotus)

See merge request core-developers/forge!2365
2020-01-03 13:09:27 +00:00
Michael Kamensky
084a7ae73e Added a simple logic for ChooseColor based on devotion (Nyx Lotus) 2020-01-03 13:09:27 +00:00
klaxnek
14a697269b Update es-ES.properties 2020-01-03 11:35:56 +00:00
swordshine
7de8cdee90 Merge branch 'german-translation' into 'master'
Update de-DE.properties from forum

See merge request core-developers/forge!2355
2020-01-03 06:50:43 +00:00
swordshine
20333491f7 Merge branch 'patch-2' into 'master'
it-IT.properties from forum

See merge request core-developers/forge!2363
2020-01-03 06:50:34 +00:00
swordshine
d529c55277 Merge branch 'patch-3' into 'master'
cardnames-it-IT.txt from forum

See merge request core-developers/forge!2364
2020-01-03 06:50:26 +00:00
CCTV-1
9e3bb1ca72 use localization card name 2020-01-03 13:43:17 +08:00
CCTV-1
0caf41f1d6 convert indentation to spaces 2020-01-03 13:33:59 +08:00
CCTV-1
817aadb995 Merge remote-tracking branch 'upstream/master' 2020-01-03 13:32:15 +08:00
Michael Kamensky
c6016c2728 Merge branch 'patch-5' into 'master'
Update visage_of_bolas.txt (typo in line 5)

See merge request core-developers/forge!2359
2020-01-03 04:40:50 +00:00
Tim Mocny
492cab9c06 Update visage_of_bolas.txt (typo in line 5) 2020-01-03 04:40:50 +00:00
Michael Kamensky
64dd84b560 Merge branch 'lbl-error' into 'master'
Fix lblPlayerActivatedCardChooseMode reference

See merge request core-developers/forge!2362
2020-01-03 04:40:30 +00:00
Michael Kamensky
496768b566 Merge branch 'escapeRefactorFlashback' into 'master'
Refactor Escape and AlternativeCost

See merge request core-developers/forge!2361
2020-01-03 04:40:10 +00:00
Hans Mackowiak
b2fcc6e743 Refactor Escape and AlternativeCost 2020-01-03 04:40:09 +00:00
Churrufli
1584fcbb82 cardnames-it-IT.txt 2020-01-02 17:30:29 +00:00
Churrufli
2860111154 it-IT.properties 2020-01-02 17:21:24 +00:00
Dagin Svezek
cfdbb98cf9 Merge branch 'master' into 'german-translation'
# Conflicts:
#   forge-gui/res/languages/de-DE.properties
2020-01-02 12:23:37 +00:00
Dagin Svezek
87ec3a528b Update de-DE.properties from forum 2020-01-02 12:15:17 +00:00
CCTV-1
8ebabd978f add cast check 2020-01-02 12:17:38 +08:00
CCTV-1
51fae70e24 Merge remote-tracking branch 'upstream/master' 2020-01-02 11:51:07 +08:00
CCTV-1
2f0024a8dd rollback unsafe changes 2020-01-02 11:45:38 +08:00
Adam Pantel
cd498e408c Fix lblPlayerActivatedCardChooseMode reference 2020-01-01 21:31:06 -05:00
swordshine
6d193c315e Merge branch 'vs-null' into 'master'
Add null check for Volrath's Shapeshifter

See merge request core-developers/forge!2358
2020-01-01 03:22:26 +00:00
Adam Pantel
c81d9f6bc2 Add null check for Volrath's Shapeshifter 2019-12-31 17:05:29 -05:00
CCTV-1
e13e5d0b16 'reduce the number of words' 2019-12-31 21:37:05 +08:00
CCTV-1
ceb892d610 use localization card name in translation text 2019-12-31 21:16:06 +08:00
swordshine
2690a4d548 Merge branch 'master' into 'master'
update translation text

See merge request core-developers/forge!2351
2019-12-31 06:00:21 +00:00
swordshine
59a8e550d6 Merge branch 'my-branch' into 'master'
3rd try is the charm

See merge request core-developers/forge!2350
2019-12-31 05:59:38 +00:00
CCTV-1
4793425c58 translate ZoneType 2019-12-30 19:08:57 +08:00
CCTV-1
e47ee567bf update translation 2019-12-30 10:35:38 +08:00
CCTV-1
c9f33415e1 translate enum ZoneType 2019-12-30 10:35:16 +08:00
Sol
d1a0c9f1ff Merge branch 'updatedeldstandard' into 'master'
Updated pioneer deckgen data with lots more up-to-date meta data

See merge request core-developers/forge!2353
2019-12-30 01:25:02 +00:00
austinio7116
40b43b00c2 Updated pioneer deckgen data with lots more up-to-date meta data
(cherry picked from commit f490497)

(cherry picked from commit 729dfea)
2019-12-30 01:25:02 +00:00
CCTV-1
cea6d3a9df update simplified chinese translation 2019-12-30 08:48:07 +08:00
CCTV-1
ecda5377a3 Merge remote-tracking branch 'upstream/master' 2019-12-30 08:47:37 +08:00
Northmoc
fb9c7290b2 Tymaret Calls the Dead 2019-12-29 14:05:13 -05:00
Northmoc
5b185d2fe3 fixing Gallia 2019-12-29 12:17:23 -05:00
Northmoc
c4712e705c Gallia the satyr bear :) 2019-12-29 08:31:30 -05:00
Northmoc
d4656b619f Merge branch 'master' of https://git.cardforge.org/core-developers/forge into my-branch 2019-12-29 08:06:37 -05:00
Northmoc
e8c5a58d85 Allure of the Unknown 2019-12-29 08:06:17 -05:00
Dagin Svezek
143cfa04de Update de-DE.properties from forum 2019-12-29 09:45:42 +00:00
austinio7116
ef752c5db6 Pioneer bannings up to Dec 2 2019 2019-12-28 19:23:30 +00:00
CCTV-1
f4ba889c84 update translation 2019-12-28 20:07:03 +08:00
CCTV-1
f20e61520b update translation text to use have placeholder string 2019-12-28 20:06:51 +08:00
CCTV-1
88f082e261 Merge remote-tracking branch 'upstream/master' 2019-12-28 11:18:26 +08:00
Northmoc
6304fa4091 Merge branch 'master' of https://git.cardforge.org/core-developers/forge into my-branch 2019-12-27 18:59:39 -05:00
Northmoc
4b01074d0f Edition update 2019-12-27 09:02:38 -05:00
austinio7116
65c8e47e26 Updated standard deckgen data with lots more up-to-date meta data
(cherry picked from commit f490497)
2019-12-27 14:00:57 +00:00
Northmoc
80c6e30691 The Binding of the Titans 2019-12-27 08:59:54 -05:00
CCTV-1
8cfc922d97 update translation 2019-12-27 15:22:52 +08:00
CCTV-1
92e6c303ad update translation text to use have placeholder string 2019-12-27 15:22:01 +08:00
Northmoc
762dc60600 TBD - card typo fix and card list update 2019-12-26 10:07:18 -05:00
Northmoc
373b81072a Merge branch 'my-branch' of https://git.cardforge.org/Northmoc/forge into my-branch 2019-12-26 09:00:39 -05:00
Northmoc
9bf2d57715 Fix for issue #1219 2019-12-26 13:58:18 +00:00
Northmoc
ef71a7befc Contributor :) 2019-12-26 13:58:18 +00:00
Northmoc
dc34c4e985 Last THB leaks/spoilers 2019-12-26 13:58:18 +00:00
Northmoc
9a495e516a Few more THB 2019-12-26 13:58:18 +00:00
Northmoc
6fcd744132 The Akroan War 2019-12-26 13:58:18 +00:00
Northmoc
70bc280cf1 4 more THB cards 12/20 2019-12-26 13:58:18 +00:00
Northmoc
470fe4b877 Chainweb aracnir - escaping with counters 2019-12-26 13:58:18 +00:00
Northmoc
86f472d29f Chainweb aracnir - escaping with counters 2019-12-26 13:58:18 +00:00
Northmoc
b54ce90df1 S THB cards and some edits 2019-12-26 13:58:18 +00:00
Northmoc
db270d0c7c 3 THB Theme Booster rares 2019-12-26 13:58:18 +00:00
Northmoc
9d5837bb87 3 THB Theme Booster rares 2019-12-26 13:58:18 +00:00
Northmoc
12848af745 3 THB Omens 2019-12-26 13:58:18 +00:00
Northmoc
2d28139ca0 7 THB N creatures (mostly vanilla) 2019-12-26 13:58:18 +00:00
Northmoc
272663dc4a Fixing apostrophes in THB list 2019-12-26 13:58:18 +00:00
Northmoc
d4a47260cb Another round of THB 2019-12-26 13:58:18 +00:00
Northmoc
7023521fb2 Another round of THB 2019-12-26 13:58:18 +00:00
Northmoc
97fe8dc35b Fixing "you may search your library and/or your graveyard" cards so your library isn't auto-searched (and shuffled) 2019-12-26 13:58:18 +00:00
CCTV-1
fb0c0bd807 fix typo 2019-12-26 08:54:20 -05:00
CCTV-1
2285541b6d fix missing translate 2019-12-26 08:54:19 -05:00
CCTV-1
e965b899c0 update translation 2019-12-26 08:54:19 -05:00
CCTV-1
011811d183 translate mobile AssignDamage view 2019-12-26 08:54:19 -05:00
CCTV-1
65efbc57f3 translate dev menu 2019-12-26 08:54:19 -05:00
CCTV-1
437587766b translate pay mana message 2019-12-26 08:54:19 -05:00
CCTV-1
a1fe5c5db1 update interactive message translate 2019-12-26 08:54:19 -05:00
CCTV-1
c44d91281e translate ability/effects all interactive message(in Android because Chinese word wrap doesn't work,do not translate StackDescription for now) 2019-12-26 08:54:19 -05:00
CCTV-1
56fdf15b6f update translation 2019-12-26 08:54:19 -05:00
CCTV-1
19be99d106 translate all confirmPayment message argument 2019-12-26 08:54:19 -05:00
CCTV-1
2e25c83775 translate desktop AddBasicLandDialog.java 2019-12-26 08:54:19 -05:00
CCTV-1
dae91de27e translate "Select Order" 2019-12-26 08:54:19 -05:00
CCTV-1
15424d2fea translate "OK","No" 2019-12-26 08:54:18 -05:00
CCTV-1
cd1d744e1f fix typo 2019-12-26 08:25:06 +08:00
CCTV-1
dc77591571 Merge remote-tracking branch 'upstream/master' 2019-12-26 08:16:43 +08:00
Northmoc
074467e65e Fix for issue #1219 2019-12-25 21:04:50 +00:00
Northmoc
c81f93551e Contributor :) 2019-12-25 21:04:50 +00:00
Northmoc
1f6cbd7d19 Last THB leaks/spoilers 2019-12-25 21:04:50 +00:00
Northmoc
bd35e224a4 Few more THB 2019-12-25 21:04:50 +00:00
Northmoc
ae5986f101 The Akroan War 2019-12-25 21:04:50 +00:00
Northmoc
5cbf5649c0 4 more THB cards 12/20 2019-12-25 21:04:50 +00:00
Northmoc
3da4db3edc Chainweb aracnir - escaping with counters 2019-12-25 21:04:50 +00:00
Northmoc
47121019d4 Chainweb aracnir - escaping with counters 2019-12-25 21:04:50 +00:00
Northmoc
c97b390161 S THB cards and some edits 2019-12-25 21:04:50 +00:00
Northmoc
f97312dcf2 3 THB Theme Booster rares 2019-12-25 21:04:50 +00:00
Northmoc
0eed744018 3 THB Theme Booster rares 2019-12-25 21:04:50 +00:00
Northmoc
655737dcb5 3 THB Omens 2019-12-25 21:04:50 +00:00
Northmoc
488fa4a4dd 7 THB N creatures (mostly vanilla) 2019-12-25 21:04:50 +00:00
Northmoc
8344522e12 Fixing apostrophes in THB list 2019-12-25 21:04:50 +00:00
Northmoc
e1e085d610 Another round of THB 2019-12-25 21:04:50 +00:00
Northmoc
e35904e727 Another round of THB 2019-12-25 21:04:50 +00:00
Northmoc
6dc8d7648a Fixing "you may search your library and/or your graveyard" cards so your library isn't auto-searched (and shuffled) 2019-12-25 21:04:49 +00:00
Agetian
c296b32209 Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2019-12-25 19:36:53 +03:00
Agetian
69f2bb70e8 - Added puzzle PS_ELDS (Superfriends Winter Vacation Puzzle) 2019-12-25 19:35:21 +03:00
Hans Mackowiak
a499e0a551 Combat: copyLastState after damage is applied 2019-12-25 17:25:32 +01:00
Michael Kamensky
bc99962621 Fix a hang in Card.java (e.g. Approach of the Second Sun) 2019-12-25 16:01:26 +00:00
Agetian
bf9b7054b3 - Update the fix. 2019-12-25 18:56:14 +03:00
Agetian
50be973e57 - Fix a hang in Card.java (e.g. Approach of the Second Sun) 2019-12-25 15:34:46 +03:00
CCTV-1
108c39ef7c fix missing translate 2019-12-25 18:42:35 +08:00
CCTV-1
ae6ea42aa9 update translation 2019-12-25 14:07:59 +08:00
CCTV-1
6c4ceccc30 translate mobile AssignDamage view 2019-12-25 14:07:28 +08:00
CCTV-1
fde7d6ff09 translate dev menu 2019-12-25 14:06:59 +08:00
CCTV-1
1af3505d0b translate pay mana message 2019-12-25 14:06:35 +08:00
CCTV-1
047f018da4 update interactive message translate 2019-12-24 11:42:46 +08:00
CCTV-1
a90e9f05e2 translate ability/effects all interactive message(in Android because Chinese word wrap doesn't work,do not translate StackDescription for now) 2019-12-23 22:53:38 +08:00
CCTV-1
7db7e10934 Merge remote-tracking branch 'upstream/master' 2019-12-23 22:39:55 +08:00
Hans Mackowiak
397b340701 Escape: fix Crash when outside of Game 2019-12-21 08:25:42 +00:00
CCTV-1
a050b584ac Merge branch 'master' of https://git.cardforge.org/core-developers/forge 2019-12-21 12:38:06 +08:00
Myrd
d68c740e1d Use FileSection.parseToMap() from TriggerHandler. 2019-12-20 22:18:00 +00:00
Myrd
b807ce30c4 Merge branch 'dump_state_with_owner' into 'master'
Fix dumping state with cards with non-matching owner/controllers.

See merge request core-developers/forge!2342
2019-12-20 17:56:37 +00:00
Myrd
a4bd13d050 Fix dumping state with cards with non-matching owner/controllers. 2019-12-20 17:56:37 +00:00
Myrd
244960d0d7 Merge branch 'avoid_combat_sim' into 'master'
Avoid combat simulation if the current player has no creatures in play.

See merge request core-developers/forge!2341
2019-12-20 16:57:14 +00:00
Myrd
267c8c6b0d Avoid combat simulation if the current player has no creatures in play. 2019-12-20 16:57:14 +00:00
Myrd
06fc409234 Merge branch 'optimize_param_parsing' into 'master'
Optimize FileSection.parse()/parseMap().

See merge request core-developers/forge!2340
2019-12-20 16:37:31 +00:00
Alexei Svitkine
77ed24a203 Revert changes to GameCopier. 2019-12-20 11:28:11 -05:00
Alexei Svitkine
ed3c519404 Remove game copier logging code. 2019-12-20 11:25:43 -05:00
Myrd
9fcf8e82ef Merge branch 'reland_opts' into 'master'
Optimize some code paths in Forge (card type logic and property get with default).

See merge request core-developers/forge!2339
2019-12-20 16:24:11 +00:00
Alexei Svitkine
dd4df9baaa Optimize FileSection.parse()/parseMap().
This was showing up in profiles with simulation AI. The change
makes constants for the patterns used, so they don't have to be
"compiled" each time and also introduces a cache for these.

With this change, a GameCopier operation is sped up by about 30%
from my local measurement (I tried with a modern deck I have).
2019-12-20 11:22:06 -05:00
Alexei Svitkine
4384b1621b Switch card types lists to sets to avoid costly look ups and
optimize getParamOrDefault() to do a single look up, instead of
two. These were showing up in profiles when using simulation AI.
2019-12-20 11:15:38 -05:00
Myrd
0e1c82a31f Merge branch 'revert-b7c47200' into 'master'
Revert "Merge branch 'master' into 'master'"

See merge request core-developers/forge!2338
2019-12-20 15:53:35 +00:00
Hans Mackowiak
b5babd5451 Merge branch 'vanguard-missing-ability-text' into 'master'
Fix Vanguards etc not displaying abilities

See merge request core-developers/forge!2336
2019-12-20 15:52:18 +00:00
Myrd
5cb8502566 Revert "Merge branch 'master' into 'master'"
This reverts merge request !2334
2019-12-20 15:48:04 +00:00
Myrd
b7c4720030 Merge branch 'master' into 'master'
Optimize some code paths in Forge (card type logic and property get with default).

See merge request core-developers/forge!2334
2019-12-20 15:47:44 +00:00
Michael Kamensky
074243891c Merge branch 'sort_flip_results' into 'master'
Sort coing flips for Krark's Thumb

See merge request core-developers/forge!2335
2019-12-20 05:03:43 +00:00
CCTV-1
1117ff1e7c update translation 2019-12-20 12:36:53 +08:00
CCTV-1
5dd24341e1 translate all confirmPayment message argument 2019-12-20 12:36:30 +08:00
CCTV-1
19d4f36faa translate desktop AddBasicLandDialog.java 2019-12-20 12:34:28 +08:00
CCTV-1
ac9f8e3191 translate "Select Order" 2019-12-20 12:31:32 +08:00
CCTV-1
9d193fb3bb translate "OK","No" 2019-12-20 12:30:18 +08:00
friarsol
c20b0c3620 Fix Vanguards etc not displaying abilities 2019-12-19 23:23:39 -05:00
friarsol
8409a7e6d1 Sort coing flips for Krark's Thumb 2019-12-19 22:43:33 -05:00
Alexei Svitkine
3d59118b94 Use Sets instead of Lists for card types to avoid slow lookups. 2019-12-19 20:49:29 -05:00
Alexei Svitkine
e0fb373b3d Use Java 8's getOrDefault() 2019-12-19 20:48:01 -05:00
swordshine
f0c8deb25e Merge branch 'master' into 'master'
some translate fix

See merge request core-developers/forge!2332
2019-12-19 01:16:42 +00:00
Michael Kamensky
b288c9f61a Merge branch 'Hanmac-master-patch-98814' into 'master'
Spell:checkOtherRestrictions check CantBeCast for changed Cardface

Closes #1198

See merge request core-developers/forge!2333
2019-12-18 11:57:26 +00:00
Hans Mackowiak
823c278cd7 Spell:checkOtherRestrictions check CantBeCast for changed Cardface 2019-12-18 11:57:26 +00:00
Michael Kamensky
ba4ba8d051 Merge branch 'keyword-escape' into 'master'
Keyword: add Escape Mechanic

Closes #1199

See merge request core-developers/forge!2331
2019-12-18 10:38:02 +00:00
Hans Mackowiak
467268c451 Keyword: add Escape Mechanic 2019-12-18 10:38:02 +00:00
CCTV-1
3f1f8321d3 do not translate "for {CR}" 2019-12-18 18:04:50 +08:00
CCTV-1
5730a407c3 Merge remote-tracking branch 'upstream/master' 2019-12-18 17:56:47 +08:00
CCTV-1
22974f8bf4 fix typo 2019-12-18 17:52:29 +08:00
CCTV-1
6414347d91 fix:wrong comment 2019-12-18 17:51:59 +08:00
swordshine
113f891348 Merge branch 'master' into 'master'
translate some text

See merge request core-developers/forge!2328
2019-12-18 09:19:40 +00:00
CCTV-1
cbab3e6000 LoadQuestScreen.java "New" should not be use lblNew 2019-12-18 13:21:32 +08:00
CCTV-1
17663bd2c0 translate mobile quest 2019-12-18 12:56:41 +08:00
CCTV-1
c226a4dbd5 Merge remote-tracking branch 'upstream/master' 2019-12-18 12:44:02 +08:00
Michael Kamensky
0c2d0e6cb6 Merge branch 'puzzle-improvements' into 'master'
Puzzle improvements

See merge request core-developers/forge!2330
2019-12-18 04:30:45 +00:00
friarsol
d63106a71a Save completed puzzles, and sort them to the bottom of the screen 2019-12-17 21:16:17 -05:00
Michael Kamensky
2c26e3f509 Merge branch 'master' into 'master'
Added puzzle PS_ELD9 - Possibility Storm - Throne of Eldraine 09

See merge request core-developers/forge!2329
2019-12-17 14:55:42 +00:00
Agetian
50e0387cda - Fix AI persistent mana in PS_ELD9. 2019-12-17 17:52:17 +03:00
Agetian
b05dc40a1c - Added puzzle PS_ELD9. 2019-12-17 17:50:25 +03:00
CCTV-1
3846be2321 translate some text 2019-12-17 19:49:11 +08:00
swordshine
2fa3179a31 Merge branch 'master' into 'master'
translate InputAttack.java and InputBlock.java

See merge request core-developers/forge!2326
2019-12-17 01:30:07 +00:00
CCTV-1
2617ff339d translate InputAttack.java and InputBlock.java 2019-12-16 20:03:28 +08:00
swordshine
e36311db44 Merge branch 'master' into 'master'
More upcoming THB cards

See merge request core-developers/forge!2324
2019-12-16 07:38:06 +00:00
Michael Kamensky
2449166c36 Merge branch 'patch-6' into 'master'
Update enchanted_carriage: fixed trigger

See merge request core-developers/forge!2325
2019-12-15 06:01:35 +00:00
Hans Mackowiak
eb16486ee6 Update enchanted_carriage: fixed trigger 2019-12-15 06:01:35 +00:00
friarsol
e0c858a3d6 Only split the first colon from Puzzle metadata 2019-12-14 22:21:23 -05:00
Northmoc
71749cef3f More upcoming THB 2019-12-14 16:47:25 -05:00
Northmoc
15839e343e More upcoming THB 2019-12-14 12:50:24 -05:00
Northmoc
9a98b39e94 More upcoming THB 2019-12-13 13:58:46 -05:00
Northmoc
9c6c0f1861 More upcoming THB 2019-12-13 12:24:47 -05:00
Northmoc
318d919111 More upcoming THB 2019-12-12 14:03:12 -05:00
Northmoc
c753a1c875 Merge branch 'master' of https://git.cardforge.org/core-developers/forge
 Conflicts:
	forge-gui/res/cardsfolder/upcoming/moss_viper.txt
2019-12-11 10:57:43 -05:00
Northmoc
e304337a62 More upcoming THB 2019-12-11 10:33:10 -05:00
Michael Kamensky
3768ca8f77 Merge branch 'master' into 'master'
Added puzzle PS_ELD8 - Possibility Storm - Throne of Eldraine 08

See merge request core-developers/forge!2322
2019-12-10 17:26:30 +00:00
Agetian
12f76827e9 - Added puzzle PS_ELD8. 2019-12-10 19:51:41 +03:00
Michael Kamensky
3c5f464039 Merge branch 'master' into 'master'
Set ExiledWith for the LKI copies (fixes Colfenor's Plans)

Closes #1215

See merge request core-developers/forge!2321
2019-12-10 16:43:41 +00:00
Agetian
9f2304b1a5 - Set ExiledWith for the LKI copies (fixes Colfenor's Plans) 2019-12-10 19:35:10 +03:00
swordshine
8a0ba4f27a Merge branch 'patch-5' into 'master'
Update iroas_god_of_victory.txt

See merge request core-developers/forge!2320
2019-12-09 03:55:24 +00:00
Sol
43dc6d35c0 Update iroas_god_of_victory.txt 2019-12-09 03:49:50 +00:00
swordshine
d04c593adc Merge branch 'patch' into 'master'
Update scripts

See merge request core-developers/forge!2319
2019-12-07 10:10:53 +00:00
swordshine
4e1b7e886f Update scripts 2019-12-07 17:52:59 +08:00
Michael Kamensky
8544e805bb Merge branch 'master' into 'master'
More THB: Funeral Rites

See merge request core-developers/forge!2318
2019-12-07 04:34:06 +00:00
klaxnek
7e18cbca97 Undo changes 2019-12-06 20:12:05 +01:00
klaxnek
f5734bb626 Merge branch 'master' of https://git.cardforge.org/core-developers/forge 2019-12-06 18:29:31 +01:00
Northmoc
08823bd94c Merge branch 'master' of https://git.cardforge.org/core-developers/forge 2019-12-06 09:24:35 -05:00
Northmoc
04cfc7a81f Furious Rise, some "heroics" and a token (THB leaks) 2019-12-06 09:20:42 -05:00
Northmoc
91656fd7c0 Furious Rise, some "heroics" and a token (THB leaks) 2019-12-06 09:16:17 -05:00
Northmoc
e984bd5708 Funeral Rites 2019-12-05 20:05:45 -05:00
swordshine
eb0c0f3f84 Merge branch 'master' into 'master'
More THB cards and a relevant token

See merge request core-developers/forge!2316
2019-12-05 01:28:05 +00:00
klaxnek
acac0ee5e2 Add personal changes 2019-12-04 23:09:03 +01:00
Michael Kamensky
19b7daeaee Merge branch 'master' into 'master'
Added puzzle PS_ELD7 - Possibility Storm - Throne of Eldraine 07

See merge request core-developers/forge!2317
2019-12-04 16:55:30 +00:00
Agetian
c933e722f3 - Added puzzle PS_ELD7. 2019-12-04 19:03:54 +03:00
Northmoc
1536377eb2 Alirios, Enraptured -putting his token in the right spot 2019-12-04 10:27:38 -05:00
Northmoc
a11640cbc9 Alirios, Enraptured and his token 2019-12-03 23:47:03 -05:00
Northmoc
d51fe454b5 Eidolon of Philosophy and Flicker of Fate THB leaks 2019-12-03 19:36:27 -05:00
Michael Kamensky
550fd937f1 Merge branch 'master' into 'master'
THB leaked cards (in upcoming folder!)

See merge request core-developers/forge!2315
2019-12-03 18:57:41 +00:00
Northmoc
bd1add4d47 Merge branch 'master' of https://git.cardforge.org/core-developers/forge 2019-12-03 13:34:02 -05:00
Tim Mocny
944eb38002 dreamstalker_manticore.txt THB leak 2019-12-03 12:31:07 -05:00
Tim Mocny
ddf481f4fd THB leak (upcoming) 2019-12-03 11:35:58 -05:00
Tim Mocny
2e7d84b58f Upload New File 2019-12-03 14:13:31 +00:00
Tim Mocny
db853cb5ba Upload New File 2019-12-03 14:12:46 +00:00
Tim Mocny
d0d652b427 Upload New File 2019-12-03 14:12:15 +00:00
Tim Mocny
231e048936 Upload New File 2019-12-03 14:11:47 +00:00
Tim Mocny
e95982a043 Upload New File 2019-12-03 14:10:52 +00:00
Tim Mocny
1a7b2677f3 Upload New File 2019-12-03 14:10:24 +00:00
Tim Mocny
b77bb5768d Upload New File 2019-12-03 14:09:52 +00:00
Tim Mocny
2be9fc65b1 Delete moss_viper.txt 2019-12-03 14:08:41 +00:00
Tim Mocny
c4e04fe003 Delete hydras_growth.txt 2019-12-03 14:07:56 +00:00
Tim Mocny
964e06b8cb Delete dreamshaper_shaman.txt 2019-12-03 14:07:26 +00:00
Tim Mocny
78d6847db5 Delete dreadful_apathy.txt 2019-12-03 14:07:11 +00:00
Tim Mocny
25d6ce6763 Delete aspect_of_lamprey.txt 2019-12-03 14:06:39 +00:00
Tim Mocny
fc26b5d3a9 Delete arena_trickster.txt 2019-12-03 14:06:04 +00:00
Tim Mocny
9e4dc631e8 Delete ashioks_erasure.txt 2019-12-03 14:04:49 +00:00
Tim Mocny
b6bff03ad3 Upload New File 2019-12-03 02:24:52 +00:00
Tim Mocny
394a365497 Upload New File 2019-12-03 02:24:12 +00:00
Tim Mocny
d5de2f387b Upload New File 2019-12-03 02:20:54 +00:00
Tim Mocny
5106de0abe Upload New File 2019-12-03 02:20:23 +00:00
Tim Mocny
510c81d251 Upload New File 2019-12-03 02:19:28 +00:00
Tim Mocny
b4437636a8 Upload New File 2019-12-03 02:18:38 +00:00
Tim Mocny
cc64997832 Upload New File 2019-12-03 02:17:39 +00:00
swordshine
c35afecce7 Merge branch 'patch' into 'master'
Update scripts by judotrente

See merge request core-developers/forge!2313
2019-12-02 04:26:41 +00:00
swordshine
2d9e8cc2af Update scripts by judotrente 2019-12-02 09:36:50 +08:00
swordshine
a9c4842b96 Merge branch 'spanishcards04' into 'master'
Translated to spanish previously untranslated first 2.000 cards of about 5.000

See merge request core-developers/forge!2312
2019-12-02 01:35:48 +00:00
Peter
c8b21a12ed Translated to spanish previously untranslated first 2.000 cards of about 5.000. Fixed some accutes in previous translation. 2019-12-01 20:08:12 +01:00
swordshine
d0a75c0943 Merge branch 'spanishcards03' into 'master'
Translated to spanish previously untranslated first 1.000 cards of about 5.000.

See merge request core-developers/forge!2310
2019-12-01 04:38:30 +00:00
swordshine
c75d3b2d04 Merge branch 'updatedspanish01' into 'master'
Updated spanish translations

See merge request core-developers/forge!2311
2019-12-01 04:38:19 +00:00
Peter
50d8c03f8b Commited wrong file 2019-11-30 14:45:08 +01:00
Peter
dde3e08e6a Updated spanish translations 2019-11-30 14:39:46 +01:00
Peter
2dd3385849 Merge branch 'master' of https://git.cardforge.org/core-developers/forge into spanishcards03 2019-11-30 14:23:51 +01:00
Peter
bd6cc759c7 Translated to spanish previously untranslated first 1.000 cards. Improved some translations and some of them translated thanks to DeepL.com. Translations based and fixed from www.rebellion.es 2019-11-30 14:23:22 +01:00
Michael Kamensky
39f695f120 Merge branch 'master' into 'master'
Added puzzle PS_ELD6 - Possibility Storm - Throne of Eldraine 06

See merge request core-developers/forge!2309
2019-11-29 19:44:20 +00:00
Agetian
61839df123 - Added puzzle PS_ELD6. 2019-11-29 21:22:08 +03:00
Michael Kamensky
e6b3ec048a Merge branch 'newBranch' into 'master'
Add Unstable Set to ExtendedArt

See merge request core-developers/forge!2308
2019-11-29 13:40:51 +00:00
Anthony Calosa
4fb5e7d305 Add Unstable Set to ExtendedArt 2019-11-29 13:40:25 +08:00
swordshine
8d4a80089e Merge branch 'patch' into 'master'
Game Night 2019 edition file

See merge request core-developers/forge!2307
2019-11-28 09:50:34 +00:00
swordshine
539e321c53 Removed an unused token 2019-11-28 16:53:40 +08:00
swordshine
737700719a Add Game Night 2019 edition file 2019-11-28 16:50:52 +08:00
swordshine
b2bc26142a Update Thoughtbound Phantasm's description 2019-11-28 16:50:52 +08:00
swordshine
9a125bf4f5 Merge branch 'master' into 'master'
Game Night 2019 Mythics

See merge request core-developers/forge!2306
2019-11-28 08:33:01 +00:00
Tim Mocny
b53135d83a Game Night 2019 Mythics 2019-11-28 08:33:00 +00:00
Tim Mocny
86262f3810 Upload New File 2019-11-28 04:51:27 +00:00
Tim Mocny
9237de38df Upload New File 2019-11-28 04:50:48 +00:00
Tim Mocny
18d5d7da27 Delete fiendish_duo.txt 2019-11-28 04:50:14 +00:00
Tim Mocny
cba653d891 Upload New File 2019-11-28 04:47:34 +00:00
Tim Mocny
9ea265625e Update highcliff_felidar.txt 2019-11-28 04:46:58 +00:00
Tim Mocny
d4aa0ecae4 Upload New File 2019-11-28 04:46:02 +00:00
Tim Mocny
bb5ee52133 Upload New File 2019-11-28 04:44:54 +00:00
Tim Mocny
33d5d45d3c Upload New File 2019-11-28 04:42:51 +00:00
swordshine
87bad70939 Merge branch 'master' into 'master'
translate some controller button

See merge request core-developers/forge!2305
2019-11-27 14:25:51 +00:00
CCTV-1
047bc9c5cd remove duplicate keys 2019-11-27 13:36:07 +08:00
CCTV-1
f098e333d2 translate some controller button 2019-11-27 13:32:05 +08:00
swordshine
785835632d Merge branch 'byebyeoko' into 'master'
Updated standard deckgen data - no more ELKs

See merge request core-developers/forge!2304
2019-11-27 01:43:56 +00:00
austinio7116
360b72fd91 Updated standard deckgen data - no more ELKs
(cherry picked from commit 42eafee)
2019-11-26 20:36:59 +00:00
Michael Kamensky
19082049e7 Merge branch 'master' into 'master'
Better AI logic spec for Heraldic Banner

Closes #1207

See merge request core-developers/forge!2302
2019-11-25 16:26:57 +00:00
Agetian
eacc29672f - Better AI logic spec for Heraldic Banner 2019-11-25 19:19:15 +03:00
Agetian
c7b6ac1670 Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2019-11-25 12:40:04 +03:00
swordshine
0aa54cea23 Merge branch 'master' into 'master'
update simplified chinese translation

See merge request core-developers/forge!2300
2019-11-25 05:57:04 +00:00
Michael Kamensky
9fe50f6c66 Merge branch 'newBranch' into 'master'
Fix path seperator, Fix newdeck editor

See merge request core-developers/forge!2301
2019-11-25 05:27:44 +00:00
Anthony Calosa
2bb84cf79f Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-25 13:04:29 +08:00
Anthony Calosa
8d0ade1eab Fix path seperator
(android now works for filtering download if you have existing fullborder cards)

Fix newdeck editor not loading if a user deleted unwanted edition file
(TODO: Don't include setless cards on deck editor...)
2019-11-25 13:01:19 +08:00
CCTV-1
242c7c3b21 update simplified chinese translation 2019-11-25 12:36:07 +08:00
CCTV-1
ff272b89fd added missing translation label 2019-11-25 12:35:13 +08:00
Michael Kamensky
4e83e73dca Merge branch 'master' into 'master'
Update CHANGES.txt

See merge request core-developers/forge!2299
2019-11-24 05:01:49 +00:00
Michael Kamensky
7d1ffa4e90 Update CHANGES.txt 2019-11-24 05:01:49 +00:00
Agetian
aab83d882a - Updating CHANGES.txt, part 2. 2019-11-24 07:56:59 +03:00
Agetian
4f69b673bf Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2019-11-24 07:54:14 +03:00
Michael Kamensky
7d17e58e1f Merge branch 'newBranch' into 'master'
Update additional check

See merge request core-developers/forge!2298
2019-11-24 04:53:54 +00:00
Agetian
3d6677bbd5 - Update CHANGES.txt. 2019-11-24 07:52:42 +03:00
Anthony Calosa
30d57a5745 Update 2019-11-24 12:35:12 +08:00
Michael Kamensky
2fb2b64d33 Merge branch 'newBranch' into 'master'
Update LQ Downloader

See merge request core-developers/forge!2297
2019-11-24 04:35:01 +00:00
Anthony Calosa
1dc8fed6e8 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-24 12:11:12 +08:00
Anthony Calosa
44c6605804 Update LQ downloader
(dont download full image equivalent to an existing fullborder images)
2019-11-24 12:05:45 +08:00
Michael Kamensky
560f8ac14a Merge branch 'master' into 'master'
Stack Addition Modal Panel

See merge request core-developers/forge!2294
2019-11-23 12:35:48 +00:00
Alessandro Coli
b99dea604d Labels for changes to stack effect notification panel 2019-11-23 12:07:36 +01:00
Alessandro Coli
f3ff419462 Changes for the stack effect notifications - request by Michael Kamensky
@Agetian in merge  request
https://git.cardforge.org/core-developers/forge/merge_requests/2294
2019-11-23 12:05:08 +01:00
Alessandro Coli
d79c2469ec Merge remote-tracking branch 'upstream/master' 2019-11-23 09:44:59 +01:00
swordshine
94de9e7cf2 Merge branch 'fix-broken-start' into 'master'
Fix start crash

See merge request core-developers/forge!2296
2019-11-23 02:40:36 +00:00
Chris H
a9d9c800b8 Fix start crash 2019-11-22 21:02:02 -05:00
swordshine
678d09558c Merge branch 'patch-5' into 'master'
Syr Konrad, the Grim: The Leave the Graveyard Trigger is only for your Graveyard

See merge request core-developers/forge!2295
2019-11-23 01:25:30 +00:00
Hans Mackowiak
831edab34b Syr Konrad, the Grim: The Leave the Graveyard Trigger is only for your Graveyard 2019-11-23 01:25:30 +00:00
Alessandro Coli
5b64b41f21 Merge remote-tracking branch 'upstream/master' 2019-11-22 13:40:18 +01:00
Alessandro Coli
78a5827976 Fixed some code indentations 2019-11-22 08:17:45 +01:00
Michael Kamensky
a9b6faeb7c Merge branch 'remove_some_build_warnings' into 'master'
Remove some build warnings

See merge request core-developers/forge!2219
2019-11-22 04:56:48 +00:00
Ryan1729
bebc58d91d Merge branch 'master' of git.cardforge.org:core-developers/forge into remove_some_build_warnings
# Conflicts:
#	forge-gui-mobile/src/forge/assets/FSkin.java
2019-11-21 10:24:52 -07:00
Alessandro Coli
2c70b8b7e0 End of the stack modal panel implementation, rollback about the Wild
Quests implementation
2019-11-21 16:49:50 +01:00
Alessandro Coli
07d7b7cb58 Merge remote-tracking branch 'upstream/master' 2019-11-21 16:35:45 +01:00
Anthony Calosa
4c80dd3c42 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-20 21:13:35 +08:00
swordshine
0b436479be Merge branch 'spanishcards02' into 'master'
Spanish Cards Translations. Fixed some translations. Translated to Ardent Soldier

See merge request core-developers/forge!2293
2019-11-20 05:11:08 +00:00
swordshine
036cd90516 Merge branch 'master' into 'master'
Update the B&R list (Nov 18, 2019)

See merge request core-developers/forge!2292
2019-11-20 05:10:55 +00:00
Ryan1729
f0076117df respond to code review 2019-11-19 19:38:51 -07:00
klaxnek
f8b4a843c5 Spanish CardS Translations. Fixed some translations. Translated to Ardent Soldier 2019-11-19 22:39:00 +01:00
Agetian
5a24092dc0 - Update the B&R list (Nov 18, 2019) 2019-11-19 16:18:56 +03:00
Michael Kamensky
bf1c32f12a Merge branch 'master' into 'master'
Added puzzle PS_ELD5 - Possibility Storm - Throne of Eldraine 05.

See merge request core-developers/forge!2291
2019-11-19 10:55:15 +00:00
Agetian
f0fb6539ef - Added puzzle PS_ELD5. 2019-11-19 11:59:59 +03:00
swordshine
a85a761bee Merge branch 'spanishcards01' into 'master'
Spanish cards translation: from Abandon Hope to Altar of Bone.

See merge request core-developers/forge!2290
2019-11-19 01:11:05 +00:00
swordshine
2c61dc9a75 Merge branch 'patch-4' into 'master'
Update Deckmasters Garfield vs. Finkel.txt

See merge request core-developers/forge!2289
2019-11-19 01:10:55 +00:00
klaxnek
9516929495 Restore newline at end of file 2019-11-19 01:57:08 +01:00
klaxnek
5350a4c476 Spanish cards translation: from Abandon Hope to Altar of Bone.
Updated spanish card translations from Scryfall.
2019-11-19 01:54:10 +01:00
Alessandro Coli
26dc246c52 Merge remote-tracking branch 'upstream/master' 2019-11-18 13:44:34 +01:00
Anthony Calosa
ad6716f00e Update Deckmasters Garfield vs. Finkel.txt 2019-11-18 07:17:34 +00:00
Hans Mackowiak
dffb63d95f Merge branch 'newBranch' into 'master'
Fix declare attackers

Closes #1205

See merge request core-developers/forge!2288
2019-11-18 04:19:10 +00:00
Anthony Calosa
5069c71dd8 Fix declare attackers 2019-11-18 04:19:10 +00:00
Anthony Calosa
287abb9f37 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-18 12:09:22 +08:00
Anthony Calosa
7f8325fb6c Fix declare attackers 2019-11-18 12:06:59 +08:00
swordshine
6c38674716 Merge branch 'german-translation' into 'master'
german translation update

See merge request core-developers/forge!2287
2019-11-18 00:51:47 +00:00
swordshine
54fdb69e88 Merge branch 'patch-2' into 'master'
Update proteus_staff.txt Remember Target Controller not Owner.

See merge request core-developers/forge!2283
2019-11-18 00:51:30 +00:00
Computica
068cee2326 Update proteus_staff.txt Remember Target Controller not Owner. 2019-11-18 00:51:29 +00:00
Alessandro Coli
e9c2e1034c Merge remote-tracking branch 'upstream/master' 2019-11-17 17:48:03 +01:00
Alessandro Coli
f453c2af78 Labels for the preferences of the new stack addition modal popup 2019-11-17 17:42:51 +01:00
Alessandro Coli
cc3c631cad Introduction of modal popup to notify when something is added to the
stack, including images for cards, complete with sources and targets.
2019-11-17 17:26:31 +01:00
Dagin Svezek
7cfd060ed8 Update de-DE.properties from forum 2019-11-17 09:18:03 +00:00
swordshine
c77f5e9b61 Merge branch 'newBranch' into 'master'
Fix images not loading when missing suffix

See merge request core-developers/forge!2285
2019-11-17 06:46:03 +00:00
swordshine
f18bd75257 Merge branch 'master' into 'master'
update simplified chinese translation

See merge request core-developers/forge!2286
2019-11-17 06:45:58 +00:00
CCTV-1
555a1f8411 update simplified chinese translation 2019-11-17 11:11:41 +08:00
Anthony Calosa
c600dc3b4f Update 2019-11-17 08:10:29 +08:00
Anthony Calosa
0f138a1bf5 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-17 08:06:43 +08:00
Anthony Calosa
1c19f36637 Fix cards like planes/phenomenon not loading an existing images that have .full/.fullborder 2019-11-17 08:02:11 +08:00
Michael Kamensky
d19973208c Merge branch 'newBranch' into 'master'
Add support for "fullborder" cards

See merge request core-developers/forge!2284
2019-11-16 15:20:12 +00:00
Anthony Calosa
0a9078a2ec Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-16 17:51:04 +08:00
Anthony Calosa
bf2368ee44 Update 2019-11-16 17:44:56 +08:00
Anthony Calosa
d0a23fbf14 Add support for ".fullborder" cards
(to differentiate full image cards and full image cards with full borders,
so it will only crop full image cards with full borders)
2019-11-16 17:36:30 +08:00
Michael Kamensky
015f561740 Merge branch 'translation11' into 'master'
Translation: All Abilities Triggers in Stack & Initial GameLogFormatter.

See merge request core-developers/forge!2252
2019-11-16 09:06:27 +00:00
klaxnek
cff4a29f1c Merge branch 'master' of https://git.cardforge.org/core-developers/forge into translation11
 Conflicts:
	forge-gui/res/languages/de-DE.properties
	forge-gui/res/languages/en-US.properties
	forge-gui/res/languages/es-ES.properties
	forge-gui/res/languages/zh-CN.properties
2019-11-16 09:59:06 +01:00
Michael Kamensky
f50ee0ba36 Merge branch 'newBranch' into 'master'
Fix permanents not updating/moving to its row when animated to creature.

See merge request core-developers/forge!2282
2019-11-15 06:04:31 +00:00
Anthony Calosa
fe5d8e537c Fix game pause 2019-11-15 11:14:54 +08:00
Anthony Calosa
d943891e4f additional check (prevent npe on mojhosto) 2019-11-15 10:11:57 +08:00
Anthony Calosa
da3d1d7099 Update 2019-11-15 08:56:35 +08:00
Anthony Calosa
86dd21ae7b Fix permanents not updating when animated to creature. 2019-11-15 06:57:43 +08:00
Hans Mackowiak
2d30184f76 Merge branch 'combatPhaseHandlerFix' into 'master'
Combat: initConstraints before Declare Attackers

See merge request core-developers/forge!2281
2019-11-14 11:12:31 +00:00
Hans Mackowiak
271063934a Combat: initConstraints before Declare Attackers 2019-11-14 11:12:31 +00:00
Alessandro Coli
3fb601adfb Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-11-13 19:23:30 +01:00
swordshine
757e11af42 Merge branch 'patch-8' into 'master'
November 11, 2019 Pioneer Banned Announcement

See merge request core-developers/forge!2280
2019-11-13 00:54:19 +00:00
Hans Mackowiak
7ec12fb58d November 11, 2019 Pioneer Banned Announcement 2019-11-13 00:54:18 +00:00
Hans Mackowiak
6c9cf02884 Merge branch 'newBranch' into 'master'
Fix Amass ability (Woodland Champion and Dreadhorde Invasion)

See merge request core-developers/forge!2279
2019-11-12 12:13:36 +00:00
Anthony Calosa
0c904e208a Add AmassTrigger Test
(If Woodland Champion will trigger from Eternal Skylord Amass Ability)
2019-11-12 19:49:01 +08:00
swordshine
d12a898333 Merge branch 'seven-dwarves' into 'master'
Add 7 Dwarves

See merge request core-developers/forge!2278
2019-11-12 07:52:57 +00:00
Anthony Calosa
0e665dc673 Fix Amass ability (Woodland Champion and Dreadhorde Invasion) 2019-11-12 13:31:16 +08:00
tehdiplomat
02299a0400 Add 7 Dwarves 2019-11-11 14:12:49 -05:00
Michael Kamensky
86d7069626 Merge branch 'master' into 'master'
Preparing Forge for Android publish 1.6.30.001 [incremental].

See merge request core-developers/forge!2277
2019-11-11 05:17:32 +00:00
Agetian
776b865761 - Preparing Forge for Android publish 1.6.30.001 [incremental]. 2019-11-11 08:10:57 +03:00
Blacksmith
a3a4ef22df Clear out release files in preparation for next release 2019-11-11 02:50:48 +00:00
Blacksmith
c2db78baf7 [maven-release-plugin] prepare for next development iteration 2019-11-11 02:45:55 +00:00
Blacksmith
9a30d78f54 [maven-release-plugin] prepare release forge-1.6.30 2019-11-11 02:45:50 +00:00
Blacksmith
db98ce160b Update README.txt for release 2019-11-11 02:43:16 +00:00
Sol
ce8b5b53e0 Merge branch 'update-release-files' into 'master'
Update Release files

See merge request core-developers/forge!2276
2019-11-11 02:32:02 +00:00
Sol
0c4055726c Update ANNOUNCEMENTS.txt 2019-11-11 02:26:43 +00:00
Michael Kamensky
64ae4bae0c Merge branch 'newBranch' into 'master'
Update some GUI elements on Mobile Networkplay

See merge request core-developers/forge!2274
2019-11-10 06:21:46 +00:00
Anthony Calosa
044cc793e8 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-09 21:04:48 +08:00
Alessandro Coli
ca81b2b55c Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-11-09 12:59:40 +01:00
Michael Kamensky
e310dc30d7 Merge branch 'pioneerdeckgen' into 'master'
Updated standard deckgen data

See merge request core-developers/forge!2275
2019-11-09 11:41:28 +00:00
Anthony Calosa
f239755249 Fix "controls" when alternating human vs ai, then ai vs ai play on mobile forge,
update refreshfield, update targeting arrows on 3 to 4 players
(shows attacked player on 3/4 player match...)
2019-11-09 19:28:21 +08:00
austinio7116
57686c0554 Updated standard deckgen data
(cherry picked from commit 75f1a60)
2019-11-09 09:04:06 +00:00
Anthony Calosa
5ecde572c3 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-09 06:27:14 +08:00
Anthony Calosa
23e9974950 Update some GUI elements on networkplay -> client 2019-11-09 06:20:13 +08:00
Anthony Calosa
ec98d128f1 prevent npe mojhosto 2019-11-09 06:16:58 +08:00
swordshine
5c07951604 Merge branch 'german-translation' into 'master'
fix typos

See merge request core-developers/forge!2273
2019-11-08 00:43:36 +00:00
Dagin Svezek
7be34625f6 fix typos 2019-11-07 14:03:24 +00:00
Alessandro Coli
f15762b746 Introduction of "wild duels" in quest 2019-11-07 13:26:22 +01:00
Alessandro Coli
e365e78756 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-11-07 13:23:11 +01:00
swordshine
5f6cb893ef Merge branch 'master' into 'master'
Added puzzle PS_ELD4. Added the relevant functionality to GateState and fixed a NPE.

See merge request core-developers/forge!2271
2019-11-07 06:17:25 +00:00
Agetian
3b636be2fe Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master 2019-11-07 08:10:19 +03:00
Agetian
1af940b034 - Simpler adventure card detection. 2019-11-07 08:08:03 +03:00
Agetian
8cb1789e60 - Added puzzle PS_ELD4.
- Added OnAdventure functionality to game states.
- Fixed a NPE when dev-adding a card to exile.
2019-11-07 08:06:31 +03:00
Michael Kamensky
01782de3a6 Merge branch 'patch-7' into 'master'
Update de-DE.properties from forum (twosat user)

See merge request core-developers/forge!2270
2019-11-07 04:02:59 +00:00
Michael Kamensky
3a7e35c51d Merge branch 'cardtranslationforgecore' into 'master'
Moved CardTranslation to forge-core.

See merge request core-developers/forge!2253
2019-11-07 04:02:57 +00:00
swordshine
bff24a1d3d Merge branch 'patch-6' into 'master'
Replace sprite_icons.png in darkred skin

See merge request core-developers/forge!2269
2019-11-07 00:52:17 +00:00
swordshine
8a075000a2 Merge branch 'patch-5' into 'master'
Replace bg_splash.png in Darkred skin

See merge request core-developers/forge!2268
2019-11-07 00:52:05 +00:00
Churrufli
5e0761d085 Update de-DE.properties from forum (twosat user) 2019-11-06 23:33:57 +00:00
Churrufli
2184ddf1bb Replace sprite_icons.png in darkred skin 2019-11-06 17:54:06 +00:00
Churrufli
fd032f6ccd Replace bg_splash.png in Darkred skin 2019-11-06 17:52:30 +00:00
Hans Mackowiak
164c819523 Merge branch 'patch-5' into 'master'
Update dread_warlock: added Warlock type

See merge request core-developers/forge!2267
2019-11-06 15:06:41 +00:00
Hans Mackowiak
987043ead2 Update dread_warlock: added Warlock type 2019-11-06 15:06:41 +00:00
swordshine
4aa9c224d0 Merge branch 'pioneerrandomquestworld' into 'master'
Pioneer random quest mode

See merge request core-developers/forge!2266
2019-11-06 08:32:13 +00:00
swordshine
2ac6fa4542 Merge branch 'elddeckgendata' into 'master'
Updated Modern and Standard Deckgen Data

See merge request core-developers/forge!2265
2019-11-06 08:31:48 +00:00
swordshine
2797f95cd3 Merge branch 'master' into 'master'
update simplified chinese translation

See merge request core-developers/forge!2264
2019-11-06 08:31:33 +00:00
austinio7116
5eb9be6248 Pioneer random quest mode 2019-11-06 08:07:21 +00:00
austinio7116
23eebf9037 Updated Modern and Standard Deckgen Data 2019-11-06 06:17:41 +00:00
CCTV-1
b59adab68d added missing translation label 2019-11-06 10:45:44 +08:00
CCTV-1
b2d44105be update simplified chinese translation 2019-11-06 10:44:19 +08:00
swordshine
2235546f2a Merge branch 'translation10' into 'master'
More translations: New menu settings, Search, Priority, PayMana, Discard, Order, Exile, Delve, ...

See merge request core-developers/forge!2251
2019-11-06 01:04:53 +00:00
swordshine
59d104f68b Merge branch 'pioneerdeckgen' into 'master'
Pioneer deckgen

See merge request core-developers/forge!2263
2019-11-06 01:04:07 +00:00
swordshine
6abdfd391d Merge branch '1191-format-pioneer' into 'master'
Resolve "Format: pioneer"

Closes #1191

See merge request core-developers/forge!2250
2019-11-06 01:04:02 +00:00
Hans Mackowiak
a6ff0b5b10 Resolve "Format: pioneer" 2019-11-06 01:04:02 +00:00
austinio7116
02969cfe5b Pioneer archetype deck generation added to UI 2019-11-05 23:02:58 +00:00
austinio7116
c6a2c35850 Pioneer initial meta
(cherry picked from commit af89555)
2019-11-05 22:37:00 +00:00
maustin
4c0a71f37d Merge branch '1191-format-pioneer' of https://git.cardforge.org/core-developers/forge into pioneerdeckgen 2019-11-05 22:36:19 +00:00
Hans Mackowiak
74e3bd1895 Pionier: November 2019 Banned cards 2019-11-05 12:05:34 +00:00
Hans Mackowiak
121c9f5012 add PioneerPredicate to magicDb 2019-11-05 08:36:19 +00:00
Hans Mackowiak
7b1cd816b7 Update formats 2019-11-05 08:25:43 +00:00
Alessandro Coli
02ae8f8108 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-11-05 08:31:54 +01:00
Michael Kamensky
6a76cc8bc6 Merge branch 'newBranch' into 'master'
Update Network and Dependency files

See merge request core-developers/forge!2259
2019-11-04 16:44:48 +00:00
swordshine
9b9c38126e Merge branch '1200-memory-theft-allows-discarding-of-a-land' into 'master'
Resolve "Memory Theft allows discarding of a land"

Closes #1200

See merge request core-developers/forge!2261
2019-11-04 14:26:01 +00:00
Michael Kamensky
e4ee0c768f Merge branch 'ManaPoolHiddenCleanup' into 'master'
ManaPool: no hidden keyword there, so no need for extra cleanup

See merge request core-developers/forge!2262
2019-11-04 13:46:08 +00:00
Hans Mackowiak
340de153c8 ManaPool: no hidden keyword there, so no need for extra cleanup 2019-11-04 13:46:08 +00:00
Hans Mackowiak
2bf477102d Update memory_theft: add nonLand part 2019-11-04 09:42:30 +00:00
Anthony Calosa
42a15b40b3 Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-11-04 07:47:27 +08:00
Michael Kamensky
a2589cd433 Merge branch 'patch-5' into 'master'
Update net-decks.txt adding Current Pioneer Decks

See merge request core-developers/forge!2260
2019-11-03 13:49:24 +00:00
Churrufli
7ec7025ed4 Update net-decks.txt adding Current Pioneer Decks 2019-11-03 07:40:41 +00:00
Anthony Calosa
5edeb6df94 removed config (log4j2 uses alternate config via xml) 2019-11-02 10:12:59 +08:00
Anthony Calosa
001a1981cf update log4j 1.2.17 -> log4j 2.11.2
(log4j 2.12.x latest needs higher Android API)
2019-11-02 10:07:13 +08:00
Anthony Calosa
446fb59473 some device are looking for this file so include it on storage
java.io.FileNotFoundException:
/storage/emulated/0/Forge/src/main/resources/log4jConfig.config
(No such file or directory)
2019-11-01 21:42:24 +08:00
Anthony Calosa
3b58d6df42 refactor rename 2019-11-01 17:46:14 +08:00
Anthony Calosa
a80c683901 support android 6 (slow networkplay) tested with two Android 6 device 2019-11-01 17:34:42 +08:00
Anthony Calosa
a5b65eaaed add old de/serialization for android 7.1 and below 2019-11-01 15:03:30 +08:00
Anthony Calosa
31182289b7 Update dependency and use custom de/encoder for netty 2019-11-01 12:41:30 +08:00
Anthony Calosa
85eb740264 aifixes NPE 2019-11-01 12:40:40 +08:00
Anthony Calosa
4318e23a40 support UST extended art 2019-11-01 12:39:57 +08:00
Alessandro Coli
b1b01f2426 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-31 14:10:41 +01:00
Hans Mackowiak
4ca7352d5c Merge branch 'fix-staticabilitycanttarget' into 'master'
Fix StaticAbilityCantTarget check not calling the common routine.

See merge request core-developers/forge!2258
2019-10-29 19:46:37 +00:00
Michael Kamensky
84905bd726 Fix StaticAbilityCantTarget check not calling the common routine. 2019-10-29 19:46:37 +00:00
swordshine
18e16368be Merge branch 'master' into 'master'
Added puzzle PS_ELD3 - Possibility Storm - Throne of Eldraine 03

See merge request core-developers/forge!2257
2019-10-29 07:51:49 +00:00
Agetian
7ed84c4c3f - Added puzzle PS_ELD3. 2019-10-29 09:34:39 +03:00
Michael Kamensky
f334211395 Merge branch 'newBranch' into 'master'
Mobile Forge: Card Sleeves & Round Border Refactor

See merge request core-developers/forge!2255
2019-10-26 14:46:09 +00:00
Alessandro Coli
164ca8541e Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-25 13:41:26 +02:00
Anthony Calosa
42f4126aff Prepare Sleeve for Desktop... 2019-10-25 15:37:13 +08:00
Anthony Calosa
5790e29daa Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-10-25 14:22:07 +08:00
Anthony Calosa
88a4a2c6cf Update 2019-10-25 14:21:25 +08:00
swordshine
90b72fc11e Merge branch '1194-resolute-rider-has-incorrect-activated-ability-cost' into 'master'
Resolve "Resolute Rider has incorrect activated ability cost"

Closes #1194

See merge request core-developers/forge!2256
2019-10-24 08:46:54 +00:00
Hans Mackowiak
00391df1f0 Fix Resolute Rider 2019-10-24 07:46:00 +00:00
swordshine
15de0c0bba Merge branch 'master' into 'master'
Added puzzle PS_ELD2 - Possibility Storm - Throne of Eldraine 02

See merge request core-developers/forge!2254
2019-10-24 01:00:06 +00:00
Agetian
a2fdce9be9 - Added puzzle PS_ELD2. 2019-10-23 22:42:52 +03:00
klaxnek
fa6fce9589 Moved CardTranslation to forge-core. We need it to translate card info in forge-game. 2019-10-23 11:47:21 +02:00
Anthony Calosa
cc1f03fc94 Update 2019-10-23 12:57:36 +08:00
Anthony Calosa
8b25f6f129 Fix Foil Overlay when Round Border is enabled 2019-10-23 11:57:56 +08:00
Anthony Calosa
b37937421c Merge remote-tracking branch 'remotes/core/master' into newBranch 2019-10-23 11:52:52 +08:00
klaxnek
df7be19487 Translate Permanent Creature 2019-10-23 00:56:36 +02:00
klaxnek
f17d2bf7fc Translate Trigger Abilities. Finished. 2019-10-23 00:24:15 +02:00
klaxnek
3369db8150 Translated Trigger Abilities (1) 2019-10-22 22:45:03 +02:00
klaxnek
408c9df2df Mobile: Merged duplicated switch 2019-10-22 21:24:13 +02:00
klaxnek
63b6d665a1 Mobile: Merge duplicated case in switch (QuestDraft with Draft) 2019-10-22 21:22:40 +02:00
klaxnek
cfc8b7fb28 Mobile: Translate Minor things 2019-10-22 21:18:30 +02:00
klaxnek
1497345a79 Translate GameLogFormatter. Mulligan and didn't attack 2019-10-22 20:29:50 +02:00
klaxnek
bbd2940b63 Translated scry log 2019-10-22 14:40:03 +02:00
klaxnek
b9c65fb8ee Translated Empty (Stack) 2019-10-22 14:22:03 +02:00
klaxnek
0b37b4e543 Translate Stack text 2019-10-22 14:20:46 +02:00
klaxnek
4c3e4f2170 Translate PlayerControllerHuman.java. Discard, order of cards, delve, exile. 2019-10-22 13:23:57 +02:00
klaxnek
dc12c50c1a Forgot lblCleanupPhase 2019-10-22 12:56:53 +02:00
klaxnek
2b986f5bac Translate PlayerControllerHuman.java. Discard cards 2019-10-22 12:50:15 +02:00
klaxnek
2accf7543e Translated Input Pay Mana. Expanded sentences in order to translate them. 2019-10-22 12:08:28 +02:00
klaxnek
ba37189410 Translate InputPassPriority.java 2019-10-22 11:36:36 +02:00
Hans Mackowiak
d578eee402 Add Pioneer Format 2019-10-22 08:47:00 +00:00
Hans Mackowiak
5107d89ef5 GameFormat: add Píoneer 2019-10-22 08:45:07 +00:00
Hans Mackowiak
72b8b5c98e Update StaticData: are the Predicates even used? 2019-10-22 08:42:12 +00:00
Anthony Calosa
402885391f Card Sleeves 2019-10-22 16:12:03 +08:00
klaxnek
b4d153ab3b Translate Search word in search filters 2019-10-22 09:51:03 +02:00
klaxnek
1a0cb62ac8 Translate Preload Extended Art 2019-10-22 09:42:16 +02:00
klaxnek
c0baf70c59 Translate new Settings menú 2019-10-22 09:37:05 +02:00
swordshine
166cf2623c Merge branch 'master' into 'master'
update Simplified Chinese translation

See merge request core-developers/forge!2249
2019-10-22 06:02:17 +00:00
CCTV-1
8567b69073 update 'Draft, Gauntlet and Puzzle Screens' Simplified Chinese translation 2019-10-22 13:01:37 +08:00
swordshine
3a4271e66d Merge branch 'updatetranslation' into 'master'
update new settings translation

See merge request core-developers/forge!2246
2019-10-22 03:05:25 +00:00
swordshine
8b723aebd9 Merge branch 'master' into 'master'
update BitmapFontWriter.java to latest version

See merge request core-developers/forge!2243
2019-10-22 03:05:18 +00:00
swordshine
eb59d6c86b Merge branch 'translation09' into 'master'
Mobile: Translate Draft, Gauntlet and Puzzle Screens.

See merge request core-developers/forge!2228
2019-10-22 03:05:04 +00:00
Sol
a291b75dd9 Merge branch 'patch-4' into 'master'
Questing Beast: fix Damage Trigger

See merge request core-developers/forge!2247
2019-10-22 00:41:25 +00:00
Hans Mackowiak
f1a76e1e76 Questing Beast: fix Damage Trigger 2019-10-22 00:41:25 +00:00
Sol
a391f7414f Merge branch 'updateBanList' into 'master'
BanList 2019-10-21

See merge request core-developers/forge!2248
2019-10-22 00:40:49 +00:00
Hans Mackowiak
299de54ba5 BanList 2019-10-21 2019-10-22 00:40:49 +00:00
CCTV-1
37bae14dfd update Simplified Chinese characters list 2019-10-19 10:26:43 +08:00
CCTV-1
d780aa43d4 update new settings translation 2019-10-18 18:30:59 +08:00
CCTV-1
91534776d1 convert \t to four spaces,makes the diff able to read 2019-10-17 11:07:00 +08:00
Alessandro Coli
ef82e11c53 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-16 14:10:58 +02:00
CCTV-1
31bb611ecf update BitmapFontWriter.java to latest version(https://github.com/libgdx/libgdx/blob/master/extensions/gdx-tools/src/com/badlogic/gdx/tools/bmfont/BitmapFontWriter.java) 2019-10-15 18:35:16 +08:00
Alessandro Coli
762481e28a Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-13 17:58:46 +02:00
Alessandro Coli
25194c7abe Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-12 11:07:46 +02:00
Alessandro Coli
967af29c47 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-11 18:34:39 +02:00
Alessandro Coli
ae9ee57d79 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-10 19:50:02 +02:00
Alessandro Coli
17706bd5e4 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-09 22:20:15 +02:00
Alessandro Coli
9ed54f726c Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-08 14:11:00 +02:00
Peter
53c88f0302 Added to contributors XD 2019-10-07 22:40:45 +02:00
Peter
ad1cc78578 Mobile: Translate Draft, Gauntlet and Puzzle Screens.
Fixed crash in LoadGameMenu (wrong translated enum...)
2019-10-07 22:39:00 +02:00
Alessandro Coli
f94a613eef Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-07 13:56:51 +02:00
Alessandro Coli
e6fa89206a Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-06 11:40:00 +02:00
Ryan1729
b010da744c progagate type information through to get rid of warning 2019-10-06 02:13:37 -06:00
Ryan1729
d53eb3a3fe pull all URLDecoder.decode calls into one method and suppress the warning since changing it appears to have broken things before. 2019-10-06 02:00:12 -06:00
Ryan1729
ea25ad2c3b use setVisible(true) instead of show to get rid of the warning 2019-10-06 01:49:06 -06:00
Ryan1729
ac7f34d3f5 Cast to Object as recommended by warning 2019-10-06 01:40:15 -06:00
Ryan1729
4969547938 inline capitalize 2019-10-06 01:36:37 -06:00
Ryan1729
6808be7a42 route all capitalize calls through a new method 2019-10-06 01:33:52 -06:00
Ryan1729
70986149ef do less stuff since we know what the arguments will be. 2019-10-06 01:05:42 -06:00
Ryan1729
bc859b3e52 inline wrap 2019-10-06 00:56:12 -06:00
Ryan1729
eb376b8eb3 pull all still needed WordUtils.wrap calls into one method 2019-10-06 00:55:29 -06:00
Alessandro Coli
9fce28bed7 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-04 23:13:19 +02:00
Alessandro Coli
0bcc0e9248 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-03 20:44:18 +02:00
Alessandro Coli
aecee3cea2 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-02 13:30:06 +02:00
Alessandro Coli
3432b9fdcd Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-10-01 18:56:14 +02:00
Alessandro Coli
8bde4d5f92 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-29 09:29:19 +02:00
Alessandro Coli
67c596726f Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-22 16:15:23 +02:00
Alessandro Coli
60fb1c0d02 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-21 12:28:37 +02:00
Alessandro Coli
3261e1a260 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-18 19:51:31 +02:00
Alessandro Coli
2e1fa8fa40 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-15 14:10:20 +02:00
Alessandro Coli
cadb2ae791 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-09-08 09:19:21 +02:00
Alessandro Coli
2d3990df81 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-31 18:28:27 +02:00
Alessandro Coli
23d4904ee7 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-28 11:34:45 +02:00
Alessandro Coli
f66f51b25e Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-23 14:33:15 +02:00
Alessandro Coli
826ff27bd1 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-21 17:17:24 +02:00
Alessandro Coli
132aa8d49a Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-19 12:49:07 +02:00
Alessandro Coli
67148cd84c Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-15 09:51:35 +02:00
Alessandro Coli
941e3a7537 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-13 15:42:20 +02:00
Alessandro Coli
4487952c28 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-10 23:21:59 +02:00
Alessandro Coli
5089663b07 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-09 19:32:29 +02:00
Alessandro Coli
3ec5bfd4ff Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-08-05 14:46:22 +02:00
Alessandro Coli
adb1ef35d9 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-20 13:12:50 +02:00
Alessandro Coli
df85278a44 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-18 12:51:43 +02:00
Alessandro Coli
7a04669560 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-18 09:09:03 +02:00
Alessandro Coli
2e24a1bde4 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-14 13:35:09 +02:00
Alessandro Coli
16134cb857 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-14 09:03:33 +02:00
Alessandro Coli
d396a8755b Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-12 18:52:27 +02:00
Alessandro Coli
7617b95fae Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-10 20:23:03 +02:00
Alessandro Coli
ecdda5b678 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-07 15:55:17 +02:00
Alessandro Coli
2a16a29ea2 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-07-02 19:15:49 +02:00
Alessandro Coli
81d7bec2cd Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-06-29 10:10:20 +02:00
Alessandro Coli
87ffbe4c20 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-06-22 17:22:36 +02:00
Alessandro Coli
94a0fb20d2 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-06-16 08:54:25 +02:00
Alessandro Coli
7313670d8f Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-06-12 18:32:48 +02:00
Alessandro Coli
5047e7732c Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-06-01 18:48:35 +02:00
Alessandro Coli
98a459ac9c Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-30 12:34:52 +02:00
Alessandro Coli
eec3f05dc7 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-28 13:29:02 +02:00
Alessandro Coli
4db2fd4ee7 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-26 08:53:55 +02:00
Alessandro Coli
41e0760678 Riallineamento con branch master remoto 2019-05-26 08:52:02 +02:00
Alessandro Coli
36b9689cf8 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-25 17:17:16 +02:00
Alessandro Coli
c5b09815e3 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-24 13:40:56 +02:00
Alessandro Coli
3da7b0f8e6 Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git 2019-05-21 20:38:45 +02:00
Alessandro Coli
1aa0d321cc Settings i like more for the AI 2019-05-21 20:37:30 +02:00
1168 changed files with 58128 additions and 14582 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.33</version>
</parent>
<artifactId>forge-ai</artifactId>

View File

@@ -1281,7 +1281,8 @@ public class AiBlockController {
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
}
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
if (attacker != null && attacker.getOwner() != null)
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
// Temporarily controlled object - don't trade with it
// TODO: find a more reliable way to figure out that control will be reestablished next turn
return false;

View File

@@ -579,7 +579,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
@Override
public PaymentDecision visit(CostReveal cost) {
final String type = cost.getType();
CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
CardCollectionView hand = player.getCardsIn(cost.getRevealFrom());
if (cost.payCostFromSource()) {
if (!hand.contains(source)) {

View File

@@ -91,9 +91,6 @@ public class ComputerUtil {
}
}
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -109,7 +106,7 @@ public class ComputerUtil {
if (chooseTargets != null) {
chooseTargets.run();
}
if (sa.hasParam("Bestow")) {
if (sa.isBestow()) {
sa.getHostCard().animateBestow();
}
@@ -219,9 +216,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -246,9 +240,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -267,9 +258,6 @@ public class ComputerUtil {
final Card source = newSA.getHostCard();
if (newSA.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(newSA);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
newSA.setHostCard(game.getAction().moveToStack(source, sa));
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
@@ -290,9 +278,6 @@ public class ComputerUtil {
if (ComputerUtilCost.canPayCost(sa, ai)) {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -2338,7 +2323,7 @@ public class ComputerUtil {
return chosen;
}
public static Object vote(Player ai, List<Object> options, SpellAbility sa, Multimap<Object, Player> votes) {
public static Object vote(Player ai, List<Object> options, SpellAbility sa, Multimap<Object, Player> votes, Player forPlayer) {
final Card source = sa.getHostCard();
final Player controller = source.getController();
final Game game = controller.getGame();

View File

@@ -82,6 +82,10 @@ public class ComputerUtilAbility {
final List<SpellAbility> spellAbilities = Lists.newArrayList();
for (final Card c : l) {
for (final SpellAbility sa : c.getSpellAbilities()) {
// Spells of permanents can't be activated on the battlefield
if (c.isPermanent() && sa.isSpell() && c.isInZone(ZoneType.Battlefield)) {
continue;
}
spellAbilities.add(sa);
}
if (c.isFaceDown() && c.isInZone(ZoneType.Exile) && !c.mayPlay(player).isEmpty()) {

View File

@@ -643,7 +643,7 @@ public class ComputerUtilCard {
return getMostProminentType(list, CardType.getAllCreatureTypes());
}
public static String getMostProminentType(final CardCollectionView list, final List<String> valid) {
public static String getMostProminentType(final CardCollectionView list, final Collection<String> valid) {
if (list.size() == 0) {
return "";
}
@@ -964,6 +964,22 @@ public class ComputerUtilCard {
}
chosen.add(chosenColor);
}
else if (logic.equals("HighestDevotionToColor")) {
int curDevotion = 0;
String chosenColor = MagicColor.Constant.WHITE;
CardCollectionView hand = ai.getCardsIn(ZoneType.Hand);
for(byte c : MagicColor.WUBRG) {
String devotionCode = "Count$Devotion." + MagicColor.toLongString(c);
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), devotionCode);
if (devotion > curDevotion && !CardLists.filter(hand, CardPredicates.isColor(c)).isEmpty()) {
curDevotion = devotion;
chosenColor = MagicColor.toLongString(c);
}
}
chosen.add(chosenColor);
}
}
if (chosen.isEmpty()) {
chosen.add(MagicColor.Constant.GREEN);
@@ -1431,7 +1447,8 @@ public class ComputerUtilCard {
}
if (pumpedDmg > dmg) {
if ((!c.hasKeyword(Keyword.INFECT) && pumpedDmg >= opp.getLife())
|| (c.hasKeyword(Keyword.INFECT) && opp.canReceiveCounters(CounterType.POISON) && pumpedDmg >= opp.getPoisonCounters())) {
|| (c.hasKeyword(Keyword.INFECT) && opp.canReceiveCounters(CounterType.POISON) && pumpedDmg >= opp.getPoisonCounters())
|| ("PumpForTrample".equals(sa.getParam("AILogic")))) {
return true;
}
}

View File

@@ -2389,7 +2389,7 @@ public class ComputerUtilCombat {
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
// Predict replacement effects
for (final Card ca : game.getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final ReplacementEffect re : ca.getReplacementEffects()) {
Map<String, String> params = re.getMapParams();
if (!re.getMode().equals(ReplacementType.DamageDone) || !params.containsKey("PreventionEffect")) {

View File

@@ -9,12 +9,10 @@ import forge.card.CardStateName;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.ability.AbilityFactory;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.card.token.TokenInfo;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
@@ -24,6 +22,7 @@ import forge.game.mana.ManaPool;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.ability.AbilityKey;
import forge.game.trigger.TriggerType;
@@ -244,7 +243,7 @@ public abstract class GameState {
if (card instanceof DetachedCardEffect) {
continue;
}
addCard(zone, card.getOwner() == ai ? aiCardTexts : humanCardTexts, card);
addCard(zone, card.getController() == ai ? aiCardTexts : humanCardTexts, card);
}
}
}
@@ -271,6 +270,10 @@ public abstract class GameState {
}
if (zoneType == ZoneType.Battlefield) {
if (c.getOwner() != c.getController()) {
// TODO: Handle more than 2-player games.
newText.append("|Owner:" + (c.getOwner().isAI() ? "AI" : "Human"));
}
if (c.isTapped()) {
newText.append("|Tapped");
}
@@ -362,6 +365,12 @@ public abstract class GameState {
if (c.isFaceDown()) {
newText.append("|FaceDown"); // Exiled face down
}
if (c.isAdventureCard() && c.getZone().is(ZoneType.Exile)) {
// TODO: this will basically default all exiled cards with Adventure to being "On Adventure".
// Need to figure out a better way to detect if it's actually on adventure.
newText.append("|OnAdventure");
}
}
if (zoneType == ZoneType.Battlefield || zoneType == ZoneType.Exile) {
@@ -807,6 +816,12 @@ public abstract class GameState {
break;
}
}
if (sa.hasParam("RememberTargets")) {
for (final GameObject o : sa.getTargets().getTargets()) {
sa.getHostCard().addRemembered(o);
}
}
}
private void handleScriptExecution(final Game game) {
@@ -966,14 +981,27 @@ public abstract class GameState {
spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim();
}
PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
Card c = null;
if (pc == null) {
System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
return;
if (StringUtils.isNumeric(spellDef)) {
// Precast from a specific host
c = idToCard.get(Integer.parseInt(spellDef));
if (c == null) {
System.err.println("ERROR: Could not find a card with ID " + spellDef + " to precast!");
return;
}
} else {
// Precast from a card by name
PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
if (pc == null) {
System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
return;
}
c = Card.fromPaperCard(pc, activator);
}
Card c = Card.fromPaperCard(pc, activator);
SpellAbility sa = null;
if (!scriptID.isEmpty()) {
@@ -1202,6 +1230,16 @@ public abstract class GameState {
c.setState(CardStateName.Flipped, true);
} else if (info.startsWith("Meld")) {
c.setState(CardStateName.Meld, true);
} else if (info.startsWith("OnAdventure")) {
String abAdventure = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell";
AbilitySub saAdventure = (AbilitySub)AbilityFactory.getAbility(abAdventure, c);
StringBuilder sbPlay = new StringBuilder();
sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card.");
saAdventure.setSVar("Play", sbPlay.toString());
saAdventure.setActivatingPlayer(c.getOwner());
saAdventure.resolve();
c.setExiledWith(c); // This seems to be the way it's set up internally. Potentially not needed here?
} else if (info.startsWith("IsCommander")) {
// TODO: This doesn't seem to properly restore the ability to play the commander. Why?
c.setCommander(true);

View File

@@ -502,20 +502,19 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes, boolean isOptional) {
public String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional) {
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), invalidTypes);
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty())
{
chosen = validTypes.get(0);
System.err.println("AI has no idea how to choose " + kindOfType +", defaulting to 1st element: chosen");
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty()) {
chosen = validTypes.iterator().next();
System.err.println("AI has no idea how to choose " + kindOfType +", defaulting to arbitrary element: chosen");
}
game.getAction().nofityOfValue(sa, player, chosen, player);
return chosen;
}
@Override
public Object vote(SpellAbility sa, String prompt, List<Object> options, ListMultimap<Object, Player> votes) {
return ComputerUtil.vote(player, options, sa, votes);
public Object vote(SpellAbility sa, String prompt, List<Object> options, ListMultimap<Object, Player> votes, Player forPlayer) {
return ComputerUtil.vote(player, options, sa, votes, forPlayer);
}
@Override

View File

@@ -1295,6 +1295,26 @@ public class SpecialCardAi {
}
}
// Timmerian Fiends
public static class TimmerianFiends {
public static boolean consider(final Player ai, final SpellAbility sa) {
final Card targeted = sa.getParentTargetingCard().getTargetCard();
if (targeted == null) {
return false;
}
if (targeted.isCreature()) {
if (ComputerUtil.aiLifeInDanger(ai, true, 0)) {
return true; // do it, hoping to save a valuable potential blocker etc.
}
return ComputerUtilCard.evaluateCreature(targeted) >= 200; // might need tweaking
} else {
// TODO: this currently compares purely by CMC. To be somehow improved, especially for stuff like the Power Nine etc.
return ComputerUtilCard.evaluatePermanentList(new CardCollection(targeted)) >= 3;
}
}
}
// Volrath's Shapeshifter
public static class VolrathsShapeshifter {
public static boolean consider(final Player ai, final SpellAbility sa) {

View File

@@ -1031,7 +1031,7 @@ public class AttachAi extends SpellAbilityAi {
Card c = null;
List<Card> magnetList = null;
String stCheck = null;
if (attachSource.isAura() || sa.hasParam("Bestow")) {
if (attachSource.isAura() || sa.isBestow()) {
stCheck = "EnchantedBy";
magnetList = CardLists.filter(list, new Predicate<Card>() {
@Override

View File

@@ -8,10 +8,7 @@ import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -69,9 +66,7 @@ public class ChooseColorAi extends SpellAbilityAi {
}
}
return false;
}
if (logic.equals("MostProminentInComputerDeck")) {
} else if (logic.equals("MostProminentInComputerDeck")) {
if ("Astral Cornucopia".equals(sourceName)) {
// activate in Main 2 hoping that the extra mana surplus will make a difference
// if there are some nonland permanents in hand
@@ -80,6 +75,11 @@ public class ChooseColorAi extends SpellAbilityAi {
return permanents.size() > 0 && ph.is(PhaseType.MAIN2, ai);
}
} else if (logic.equals("HighestDevotionToColor")) {
// currently only works more or less reliably in Main2 to cast own spells
if (!ph.is(PhaseType.MAIN2, ai)) {
return false;
}
}
boolean chance = MyRandom.getRandom().nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());

View File

@@ -34,12 +34,12 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.collect.FCollectionView;
//AB:GainControl|ValidTgts$Creature|TgtPrompt$Select target legendary creature|LoseControl$Untap,LoseControl|SpellDescription$Gain control of target xxxxxxx
@@ -54,8 +54,6 @@ import forge.util.collect.FCollectionView;
// (as a "&"-separated list; like Haste, Sacrifice CARDNAME at EOT, any standard keyword)
// OppChoice - set to True if opponent chooses creature (for Preacher) - not implemented yet
// Untap - set to True if target card should untap when control is taken
// DestroyTgt - actions upon which the tgt should be destroyed. same list as LoseControl
// NoRegen - set if destroyed creature can't be regenerated. used only with DestroyTgt
/**
* <p>
@@ -77,7 +75,7 @@ public class ControlGainAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions();
final Game game = ai.getGame();
final FCollectionView<Player> opponents = ai.getOpponents();
final PlayerCollection opponents = ai.getOpponents();
// if Defined, then don't worry about targeting
if (tgt == null) {
@@ -94,18 +92,19 @@ public class ControlGainAi extends SpellAbilityAi {
sa.setTargetingPlayer(targetingPlayer);
return targetingPlayer.getController().chooseTargetsFor(sa);
}
if (tgt.isRandomTarget()) {
sa.getTargets().add(Aggregates.random(tgt.getAllCandidates(sa, false)));
}
if (tgt.canOnlyTgtOpponent()) {
List<Player> oppList = Lists
.newArrayList(Iterables.filter(opponents, PlayerPredicates.isTargetableBy(sa)));
List<Player> oppList = opponents.filter(PlayerPredicates.isTargetableBy(sa));
if (oppList.isEmpty()) {
return false;
}
sa.getTargets().add(oppList.get(0));
if (tgt.isRandomTarget()) {
sa.getTargets().add(Aggregates.random(oppList));
} else {
sa.getTargets().add(oppList.get(0));
}
}
}

View File

@@ -5,6 +5,7 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
@@ -180,6 +181,13 @@ public class CopyPermanentAi extends SpellAbilityAi {
// if no targeting, it should always be ok
}
if ("TriggeredCardController".equals(sa.getParam("Controller"))) {
Card trigCard = (Card)sa.getTriggeringObject(AbilityKey.Card);
if (!mandatory && trigCard != null && trigCard.getController().isOpponentOf(aiPlayer)) {
return false;
}
}
return true;
}

View File

@@ -23,6 +23,14 @@ import java.util.Map;
public class CountersRemoveAi extends SpellAbilityAi {
@Override
protected boolean canPlayWithoutRestrict(final Player ai, final SpellAbility sa) {
if ("Always".equals(sa.getParam("AILogic"))) {
return true;
}
return super.canPlayWithoutRestrict(ai, sa);
}
/*
* (non-Javadoc)
*

View File

@@ -1,6 +1,7 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.*;
@@ -472,6 +473,22 @@ public class DamageDealAi extends DamageAiBase {
return bestTgt;
}
private Card getWorstPlaneswalkerToDamage(final List<Card> pws) {
Card bestTgt = null;
int bestScore = Integer.MAX_VALUE;
for (Card pw : pws) {
int curLoyalty = pw.getCounters(CounterType.LOYALTY);
if (curLoyalty < bestScore) {
bestScore = curLoyalty;
bestTgt = pw;
}
}
return bestTgt;
}
private List<Card> getTargetableCards(Player ai, SpellAbility sa, Player pl, TargetRestrictions tgt, Player activator, Card source, Game game) {
List<Card> hPlay = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), activator, source, sa);
@@ -556,6 +573,13 @@ public class DamageDealAi extends DamageAiBase {
sa.getTargets().add(enemy);
}
return true;
} else if ("DamageAfterPutCounter".equals(logic)
&& sa.getParent() != null
&& "P1P1".equals(sa.getParent().getParam("CounterType"))) {
// assuming the SA parent is of PutCounter type. Perhaps it's possible to predict counter multipliers here somehow?
final String amountStr = sa.getParent().getParamOrDefault("CounterNum", "1");
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa);
dmg += amount;
}
// AssumeAtLeastOneTarget is used for cards with funky targeting implementation like Fight with Fire which would
@@ -566,7 +590,10 @@ public class DamageDealAi extends DamageAiBase {
immediately |= ComputerUtil.playImmediately(ai, sa);
sa.resetTargets();
if (!(sa.getParent() != null && sa.getParent().isTargetNumberValid())) {
sa.resetTargets();
}
// target loop
TargetChoices tcs = sa.getTargets();
@@ -785,7 +812,7 @@ public class DamageDealAi extends DamageAiBase {
return false;
} else {
// If the trigger is mandatory, gotta choose my own stuff now
return this.damageChooseRequiredTargets(ai, sa, tgt, dmg, mandatory);
return this.damageChooseRequiredTargets(ai, sa, tgt, dmg);
}
} else {
// TODO is this good enough? for up to amounts?
@@ -862,12 +889,9 @@ public class DamageDealAi extends DamageAiBase {
* a {@link forge.game.spellability.TargetRestrictions} object.
* @param dmg
* a int.
* @param mandatory
* a boolean.
* @return a boolean.
*/
private boolean damageChooseRequiredTargets(final Player ai, final SpellAbility sa, final TargetRestrictions tgt, final int dmg,
final boolean mandatory) {
private boolean damageChooseRequiredTargets(final Player ai, final SpellAbility sa, final TargetRestrictions tgt, final int dmg) {
// this is for Triggered targets that are mandatory
final boolean noPrevention = sa.hasParam("NoPrevention");
final boolean divided = sa.hasParam("DividedAsYouChoose");
@@ -875,7 +899,7 @@ public class DamageDealAi extends DamageAiBase {
while (sa.getTargets().getNumTargeted() < tgt.getMinTargets(sa.getHostCard(), sa)) {
if (tgt.canTgtPlaneswalker()) {
final Card c = this.dealDamageChooseTgtPW(ai, sa, dmg, noPrevention, ai, mandatory);
final Card c = this.dealDamageChooseTgtPW(ai, sa, dmg, noPrevention, ai, true);
if (c != null) {
sa.getTargets().add(c);
if (divided) {
@@ -888,7 +912,7 @@ public class DamageDealAi extends DamageAiBase {
// TODO: This currently also catches planeswalkers that can be killed (still necessary? Or can be removed?)
if (tgt.canTgtCreature()) {
final Card c = this.dealDamageChooseTgtC(ai, sa, dmg, noPrevention, ai, mandatory);
final Card c = this.dealDamageChooseTgtC(ai, sa, dmg, noPrevention, ai, true);
if (c != null) {
sa.getTargets().add(c);
if (divided) {
@@ -909,6 +933,32 @@ public class DamageDealAi extends DamageAiBase {
}
}
// See if there's an indestructible target that can be used
CardCollection indestructible = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.Presets.PLANESWALKERS, CardPredicates.hasKeyword(Keyword.INDESTRUCTIBLE), CardPredicates.isTargetableBy(sa)));
if (!indestructible.isEmpty()) {
Card c = ComputerUtilCard.getWorstPermanentAI(indestructible, false, false, false, false);
sa.getTargets().add(c);
if (divided) {
tgt.addDividedAllocation(c, dmg);
break;
}
continue;
}
else if (tgt.canTgtPlaneswalker()) {
// Second pass for planeswalkers: choose AI's worst planeswalker
final Card c = getWorstPlaneswalkerToDamage(CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), Predicates.and(CardPredicates.Presets.PLANESWALKERS), CardPredicates.isTargetableBy(sa)));
if (c != null) {
sa.getTargets().add(c);
if (divided) {
tgt.addDividedAllocation(c, dmg);
break;
}
continue;
}
}
if (sa.canTarget(ai)) {
if (sa.getTargets().add(ai)) {
if (divided) {

View File

@@ -1,6 +1,8 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
@@ -157,6 +159,15 @@ public class DigAi extends SpellAbilityAi {
}
}
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List)
*/
@Override
public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> options) {
// an opponent choose a card from
return Iterables.getFirst(options, null);
}
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityAi#confirmAction(forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String)
*/

View File

@@ -514,6 +514,10 @@ public class DrawAi extends SpellAbilityAi {
@Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
if (!mandatory && !willPayCosts(ai, sa, sa.getPayCosts(), sa.getHostCard())) {
return false;
}
return targetAI(ai, sa, mandatory);
}

View File

@@ -11,6 +11,7 @@ import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.ability.ApiType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
@@ -307,6 +308,16 @@ public class EffectAi extends SpellAbilityAi {
if (!ComputerUtil.targetPlayableSpellCard(ai, list, sa, false)) {
return false;
}
} else if (logic.equals("Bribe")) {
Card host = sa.getHostCard();
Combat combat = game.getCombat();
if (combat != null && combat.isAttacking(host, ai) && !combat.isBlocked(host)
&& game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& !AiCardMemory.isRememberedCard(ai, host, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN)) {
AiCardMemory.rememberCard(ai, host, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN); // ideally needs once per combat or something
return true;
}
return false;
}
} else { //no AILogic
return false;

View File

@@ -45,6 +45,8 @@ public class FightAi extends SpellAbilityAi {
aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures);
List<Card> humCreatures = ai.getOpponents().getCreaturesInPlay();
humCreatures = CardLists.getTargetableCards(humCreatures, sa);
if (humCreatures.isEmpty())
return false; //prevent IndexOutOfBoundsException on MOJHOSTO variant
// assumes the triggered card belongs to the ai
if (sa.hasParam("Defined")) {

View File

@@ -1,15 +1,10 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilMana;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -24,6 +19,11 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class MillAi extends SpellAbilityAi {
@Override
@@ -38,6 +38,8 @@ public class MillAi extends SpellAbilityAi {
} else if (aiLogic.equals("LilianaMill")) {
// Only mill if a "Raise Dead" target is available, in case of control decks with few creatures
return CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES).size() >= 1;
} else if (aiLogic.equals("Rebirth")) {
return ai.getLife() <= 8;
}
return true;
}
@@ -194,6 +196,10 @@ public class MillAi extends SpellAbilityAi {
*/
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
if ("TimmerianFiends".equals(sa.getParam("AILogic"))) {
return SpecialCardAi.TimmerianFiends.consider(player, sa);
}
return true;
}

View File

@@ -1,7 +1,7 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.*;
import forge.game.Game;
@@ -12,11 +12,9 @@ import forge.game.card.CardPredicates;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
@@ -28,7 +26,6 @@ public class MustBlockAi extends SpellAbilityAi {
final Card source = sa.getHostCard();
final Game game = aiPlayer.getGame();
final Combat combat = game.getCombat();
final PhaseHandler ph = game.getPhaseHandler();
final boolean onlyLethal = !"AllowNonLethal".equals(sa.getParam("AILogic"));
if (combat == null || !combat.isAttacking(source)) {
@@ -39,7 +36,6 @@ public class MustBlockAi extends SpellAbilityAi {
return false;
}
final TargetRestrictions abTgt = sa.getTargetRestrictions();
final List<Card> list = determineGoodBlockers(source, aiPlayer, combat.getDefenderPlayerByAttacker(source), sa, onlyLethal,false);
if (!list.isEmpty()) {
@@ -69,7 +65,6 @@ public class MustBlockAi extends SpellAbilityAi {
@Override
protected boolean doTriggerAINoCost(final Player ai, SpellAbility sa, boolean mandatory) {
final Card source = sa.getHostCard();
final TargetRestrictions abTgt = sa.getTargetRestrictions();
// only use on creatures that can attack
if (!ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)) {
@@ -94,7 +89,7 @@ public class MustBlockAi extends SpellAbilityAi {
boolean chance = false;
if (abTgt != null) {
if (sa.usesTargeting()) {
final List<Card> list = determineGoodBlockers(definedAttacker, ai, ai.getWeakestOpponent(), sa, true,true);
if (list.isEmpty()) {
return false;
@@ -119,6 +114,9 @@ public class MustBlockAi extends SpellAbilityAi {
sa.getTargets().add(blocker);
chance = true;
} else if (sa.hasParam("Choices")) {
// currently choice is attacked player
return true;
} else {
return false;
}
@@ -126,16 +124,9 @@ public class MustBlockAi extends SpellAbilityAi {
return chance;
}
private List<Card> determineGoodBlockers(final Card attacker, final Player ai, Player defender, SpellAbility sa,
private List<Card> determineBlockerFromList(final Card attacker, final Player ai, Iterable<Card> options, SpellAbility sa,
final boolean onlyLethal, final boolean testTapped) {
final Card source = sa.getHostCard();
final TargetRestrictions abTgt = sa.getTargetRestrictions();
List<Card> list = Lists.newArrayList();
list = CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
list = CardLists.getTargetableCards(list, sa);
list = CardLists.getValidCards(list, abTgt.getValidTgts(), source.getController(), source, sa);
list = CardLists.filter(list, new Predicate<Card>() {
List<Card> list = CardLists.filter(options, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
boolean tapped = c.isTapped();
@@ -161,4 +152,40 @@ public class MustBlockAi extends SpellAbilityAi {
return list;
}
private List<Card> determineGoodBlockers(final Card attacker, final Player ai, Player defender, SpellAbility sa,
final boolean onlyLethal, final boolean testTapped) {
List<Card> list = Lists.newArrayList();
list = CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
if (sa.usesTargeting()) {
list = CardLists.getTargetableCards(list, sa);
}
return determineBlockerFromList(attacker, ai, list, sa, onlyLethal, testTapped);
}
@Override
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional,
Player targetedPlayer) {
final Card host = sa.getHostCard();
Card attacker = host;
if (sa.hasParam("DefinedAttacker")) {
List<Card> attackers = AbilityUtils.getDefinedCards(host, sa.getParam("DefinedAttacker"), sa);
attacker = Iterables.getFirst(attackers, null);
}
if (attacker == null) {
return Iterables.getFirst(options, null);
}
List<Card> better = determineBlockerFromList(attacker, ai, options, sa, false, false);
if (!better.isEmpty()) {
return Iterables.getFirst(options, null);
}
return Iterables.getFirst(options, null);
}
}

View File

@@ -5,11 +5,7 @@ import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.AiAttackController;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameObject;
@@ -221,6 +217,11 @@ public class ProtectAi extends SpellAbilityAi {
// Don't target cards that will die.
list = ComputerUtil.getSafeTargets(ai, sa, list);
// Don't target self if the cost includes sacrificing itself
if (ComputerUtilCost.isSacrificeSelfCost(sa.getPayCosts())) {
list.remove(source);
}
if (list.isEmpty()) {
return mandatory && protectMandatoryTarget(ai, sa, mandatory);
}

View File

@@ -63,6 +63,7 @@ public class SacrificeAi extends SpellAbilityAi {
final boolean destroy = sa.hasParam("Destroy");
Player opp = ai.getWeakestOpponent();
if (tgt != null) {
sa.resetTargets();
if (!opp.canBeTargetedBy(sa)) {
@@ -74,8 +75,16 @@ public class SacrificeAi extends SpellAbilityAi {
num = (num == null) ? "1" : num;
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa);
List<Card> list =
CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
List<Card> list = null;
try {
list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
} catch (NullPointerException e) {
return false;
} finally {
if (list == null)
return false;
}//prevent NPE on MoJhoSto
for (Card c : list) {
if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) {
return false;
@@ -131,15 +140,31 @@ public class SacrificeAi extends SpellAbilityAi {
amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
}
List<Card> humanList =
CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
List<Card> humanList = null;
try {
humanList = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
} catch (NullPointerException e) {
return false;
} finally {
if (humanList == null)
return false;
}//prevent NPE on MoJhoSto
// Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1
// (or X for X) trades for special decks
return humanList.size() >= amount;
} else if (defined.equals("You")) {
List<Card> computerList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
List<Card> computerList = null;
try {
computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
} catch (NullPointerException e) {
return false;
} finally {
if (computerList == null)
return false;
}//prevent NPE on MoJhoSto
for (Card c : computerList) {
if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) <= 135) {
return true;

View File

@@ -46,6 +46,12 @@ public class VoteAi extends SpellAbilityAi {
@Override
public int chooseNumber(Player player, SpellAbility sa, int min, int max, Map<String, Object> params) {
if (params.containsKey("Voter")) {
Player p = (Player)params.get("Voter");
if (p.isOpponentOf(player)) {
return min;
}
}
if (sa.getActivatingPlayer().isOpponentOf(player)) {
return min;
}

View File

@@ -29,6 +29,13 @@ public class GameStateEvaluator {
if (phase.isAfter(PhaseType.COMBAT_DAMAGE) || evalGame.isGameOver()) {
return null;
}
// If the current player has no creatures in play, there won't be any combat. This avoids
// an expensive game copy operation.
// Note: This is is safe to do because the simulation is based on the current game state,
// so there isn't a chance to play creatures in between.
if (evalGame.getPhaseHandler().getPlayerTurn().getCreaturesInPlay().isEmpty()) {
return null;
}
GameCopier copier = new GameCopier(evalGame);
Game gameCopy = copier.makeCopy();
gameCopy.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DAMAGE);

View File

@@ -23,6 +23,7 @@ import forge.util.TextUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
public class SpellAbilityPicker {
private Game game;
@@ -307,7 +308,7 @@ public class SpellAbilityPicker {
if (conditions == null) {
return true;
}
List<PhaseType> phases = conditions.getPhases();
Set<PhaseType> phases = conditions.getPhases();
return phases.isEmpty() || phases.contains(PhaseType.MAIN1);
}

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.33</version>
</parent>
<artifactId>forge-core</artifactId>
@@ -21,7 +21,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
</dependency>
</dependencies>

View File

@@ -111,7 +111,22 @@ public final class ImageKeys {
file = findFile(dir, TextUtil.fastReplace(filename, "AE", "Ae"));
if (file != null) { return file; }
}
//try fullborder...
if (filename.contains(".full")) {
String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
file = findFile(dir, fullborderFile);
if (file != null) { return file; }
// if there's an art variant try without it
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
if (file != null) { return file; }
}
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
if (!filename.contains(".full")) {
file = findFile(dir, TextUtil.addSuffix(filename,".full"));
if (file != null) { return file; }
file = findFile(dir, TextUtil.addSuffix(filename,".fullborder"));
if (file != null) { return file; }
}
// some S00 cards are really part of 6ED
String s2kAlias = getSetFolder("S00");
if (filename.startsWith(s2kAlias)) {

View File

@@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
public abstract class LobbyPlayer {
protected String name;
private int avatarIndex = -1;
private int sleeveIndex = -1;
private String avatarCardImageKey;
public LobbyPlayer(String name) {
@@ -59,9 +60,15 @@ public abstract class LobbyPlayer {
public int getAvatarIndex() {
return avatarIndex;
}
public int getSleeveIndex() {
return sleeveIndex;
}
public void setAvatarIndex(int avatarIndex) {
this.avatarIndex = avatarIndex;
}
public void setSleeveIndex(int sleeveIndex) {
this.sleeveIndex = sleeveIndex;
}
public String getAvatarCardImageKey() {
return avatarCardImageKey;

View File

@@ -35,6 +35,7 @@ public class StaticData {
private Predicate<PaperCard> standardPredicate;
private Predicate<PaperCard> brawlPredicate;
private Predicate<PaperCard> pioneerPredicate;
private Predicate<PaperCard> modernPredicate;
private Predicate<PaperCard> commanderPredicate;
private Predicate<PaperCard> oathbreakerPredicate;
@@ -197,13 +198,13 @@ public class StaticData {
public TokenDb getAllTokens() { return allTokens; }
public Predicate<PaperCard> getStandardPredicate() {
return standardPredicate;
}
public void setStandardPredicate(Predicate<PaperCard> standardPredicate) { this.standardPredicate = standardPredicate; }
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = standardPredicate; }
public void setPioneerPredicate(Predicate<PaperCard> pioneerPredicate) { this.pioneerPredicate = pioneerPredicate; }
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = modernPredicate; }
public void setCommanderPredicate(Predicate<PaperCard> commanderPredicate) { this.commanderPredicate = commanderPredicate; }
@@ -211,9 +212,11 @@ public class StaticData {
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
public Predicate<PaperCard> getModernPredicate() {
return modernPredicate;
}
public Predicate<PaperCard> getStandardPredicate() { return standardPredicate; }
public Predicate<PaperCard> getPioneerPredicate() { return pioneerPredicate; }
public Predicate<PaperCard> getModernPredicate() { return modernPredicate; }
public Predicate<PaperCard> getCommanderPredicate() { return commanderPredicate; }

View File

@@ -312,17 +312,21 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return tryGetCard(request);
}
public int getCardCollectorNumber(String cardName, String reqEdition) {
public String getCardCollectorNumber(String cardName, String reqEdition, int artIndex) {
cardName = getName(cardName);
CardEdition edition = editions.get(reqEdition);
if (edition == null)
return -1;
return null;
int numMatches = 0;
for (CardInSet card : edition.getCards()) {
if (card.name.equalsIgnoreCase(cardName)) {
return card.collectorNumber;
numMatches += 1;
if (numMatches == artIndex) {
return card.collectorNumber;
}
}
}
return -1;
return null;
}
private PaperCard tryGetCard(CardRequest request) {
@@ -553,6 +557,23 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return Lists.newArrayList(Iterables.filter(this.roAllCards, predicate));
}
// Do I want a foiled version of these cards?
@Override
public List<PaperCard> getAllCardsFromEdition(CardEdition edition) {
List<PaperCard> cards = Lists.newArrayList();
for(CardInSet cis : edition.getCards()) {
PaperCard card = this.getCard(cis.name, edition.getCode());
if (card == null) {
// Just in case the card is listed in the edition file but Forge doesn't support it
continue;
}
cards.add(card);
}
return cards;
}
@Override
public boolean contains(String name) {
return allCardsByName.containsKey(getName(name));

View File

@@ -38,6 +38,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -75,10 +77,10 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public static class CardInSet {
public final CardRarity rarity;
public final int collectorNumber;
public final String collectorNumber;
public final String name;
public CardInSet(final String name, final int collectorNumber, final CardRarity rarity) {
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity) {
this.name = name;
this.collectorNumber = collectorNumber;
this.rarity = rarity;
@@ -86,7 +88,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public String toString() {
StringBuilder sb = new StringBuilder();
if (collectorNumber != -1) {
if (collectorNumber != null) {
sb.append(collectorNumber);
sb.append(' ');
}
@@ -110,6 +112,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
private Type type;
private String name;
private String alias = null;
private String prerelease = null;
private boolean whiteBorder = false;
private FoilType foilType = FoilType.NOT_SUPPORTED;
private double foilChanceInBooster = 0;
@@ -178,6 +181,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public Type getType() { return type; }
public String getName() { return name; }
public String getAlias() { return alias; }
public String getPrerelease() { return prerelease; }
public FoilType getFoilType() { return foilType; }
public double getFoilChanceInBooster() { return foilChanceInBooster; }
public boolean getFoilAlwaysInCommonSlot() { return foilAlwaysInCommonSlot; }
@@ -188,6 +192,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public boolean getSmallSetOverride() { return smallSetOverride; }
public String getBoosterMustContain() { return boosterMustContain; }
public CardInSet[] getCards() { return cards; }
public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others
public Map<String, Integer> getTokens() { return tokenNormalized; }
@@ -264,24 +269,33 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
Map<String, Integer> tokenNormalized = new HashMap<>();
List<CardEdition.CardInSet> processedCards = new ArrayList<>();
if (contents.containsKey("cards")) {
final Pattern pattern = Pattern.compile(
/*
The following pattern will match the WAR Japanese art entries,
it should also match the Un-set and older alternate art cards
like Merseine from FEM (should the editions files ever be updated)
*/
//"(^(?<cnum>[0-9]+.?) )?((?<rarity>[SCURML]) )?(?<name>.*)$"
/* Ideally we'd use the named group above, but Android 6 and
earlier don't appear to support named groups.
So, untill support for those devices is officially dropped,
we'll have to suffice with numbered groups.
We are looking for:
* cnum - grouping #2
* rarity - grouping #4
* name - grouping #5
*/
"(^([0-9]+.?) )?(([SCURML]) )?(.*)$"
);
for(String line : contents.get("cards")) {
if (StringUtils.isBlank(line))
continue;
// Optional collector number at the start.
String[] split = line.split(" ", 2);
int collectorNumber = -1;
if (split.length >= 2 && StringUtils.isNumeric(split[0])) {
collectorNumber = Integer.parseInt(split[0]);
line = split[1];
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
String collectorNumber = matcher.group(2);
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
String cardName = matcher.group(5);
CardInSet cis = new CardInSet(cardName, collectorNumber, r);
processedCards.add(cis);
}
// You may omit rarity for early development
CardRarity r = CardRarity.smartValueOf(line.substring(0, 1));
boolean hadRarity = r != CardRarity.Unknown && line.charAt(1) == ' ';
String cardName = hadRarity ? line.substring(2) : line;
CardInSet cis = new CardInSet(cardName, collectorNumber, r);
processedCards.add(cis);
}
}
@@ -303,7 +317,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
tokenNormalized
);
FileSection section = FileSection.parse(contents.get("metadata"), "=");
FileSection section = FileSection.parse(contents.get("metadata"), FileSection.EQUALS_KV_SEPARATOR);
res.name = section.get("name");
res.date = parseDate(section.get("date"));
res.code = section.get("code");
@@ -333,6 +347,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
}
}
res.type = enumType;
res.prerelease = section.get("Prerelease", null);
switch(section.get("foil", "newstyle").toLowerCase()) {
case "notsupported":
@@ -413,6 +428,16 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
return res;
}
public Iterable<CardEdition> getPrereleaseEditions() {
List<CardEdition> res = Lists.newArrayList(this);
return Iterables.filter(res, new Predicate<CardEdition>() {
@Override
public boolean apply(final CardEdition edition) {
return edition.getPrerelease() != null;
}
});
}
public CardEdition getEditionByCodeOrThrow(final String code) {
final CardEdition set = this.get(code);
if (null == set) {

View File

@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
public boolean canBeBrawlCommander() {
CardType type = mainPart.getType();
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
}
public boolean canBeTinyLeadersCommander() {
CardType type = mainPart.getType();
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
}
public String getMeldWith() {

View File

@@ -594,8 +594,10 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER,
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY));
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
/** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
@@ -35,10 +36,8 @@ import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import forge.util.EnumUtil;
import forge.util.Settable;
/**
@@ -47,7 +46,6 @@ import forge.util.Settable;
* </p>
*
* @author Forge
* @version $Id: java 9708 2011-08-09 19:34:12Z jendave $
*/
public final class CardType implements Comparable<CardType>, CardTypeView {
private static final long serialVersionUID = 4629853583167022151L;
@@ -71,7 +69,8 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
Vanguard(false);
public final boolean isPermanent;
private static final ImmutableList<String> allCoreTypeNames = EnumUtil.getNames(CoreType.class);
private static Map<String, CoreType> stringToCoreType = EnumUtils.getEnumMap(CoreType.class);
private static final Set<String> allCoreTypeNames = stringToCoreType.keySet();
CoreType(final boolean permanent) {
isPermanent = permanent;
@@ -86,19 +85,8 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
Ongoing,
World;
private static final ImmutableList<String> allSuperTypeNames = EnumUtil.getNames(Supertype.class);
}
// This will be useful for faster parses
private static Map<String, CoreType> stringToCoreType = Maps.newHashMap();
private static Map<String, Supertype> stringToSupertype = Maps.newHashMap();
static {
for (final Supertype st : Supertype.values()) {
stringToSupertype.put(st.name(), st);
}
for (final CoreType ct : CoreType.values()) {
stringToCoreType.put(ct.name(), ct);
}
private static Map<String, Supertype> stringToSupertype = EnumUtils.getEnumMap(Supertype.class);
private static final Set<String> allSuperTypeNames = stringToSupertype.keySet();
}
private final Set<CoreType> coreTypes = EnumSet.noneOf(CoreType.class);
@@ -120,12 +108,12 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
public boolean add(final String t) {
boolean changed;
final CoreType ct = stringToCoreType.get(t);
final CoreType ct = EnumUtils.getEnum(CoreType.class, t);
if (ct != null) {
changed = coreTypes.add(ct);
}
else {
final Supertype st = stringToSupertype.get(t);
final Supertype st = EnumUtils.getEnum(Supertype.class, t);
if (st != null) {
changed = supertypes.add(st);
}
@@ -183,20 +171,28 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
subtypes.clear();
calculatedType = null;
}
public boolean remove(final Supertype st) {
return supertypes.remove(st);
}
public boolean remove(final String str) {
boolean changed = false;
if (CardType.isASupertype(str) && supertypes.remove(stringToSupertype.get(str))) {
changed = true;
} else if (CardType.isACardType(str) && coreTypes.remove(stringToCoreType.get(str))) {
changed = true;
} else if (subtypes.remove(str)) {
// try to remove sub type first if able
if (subtypes.remove(str)) {
changed = true;
} else {
Supertype st = EnumUtils.getEnum(Supertype.class, str);
if (st != null && supertypes.remove(st)) {
changed = true;
}
CoreType ct = EnumUtils.getEnum(CoreType.class, str);
if (ct != null && coreTypes.remove(ct)) {
changed = true;
}
}
if (changed) {
calculatedType = null;
}
@@ -267,15 +263,13 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (hasSubtype(t)) {
return true;
}
final char firstChar = t.charAt(0);
if (Character.isLowerCase(firstChar)) {
t = Character.toUpperCase(firstChar) + t.substring(1); //ensure string is proper case for enum types
}
final CoreType type = stringToCoreType.get(t);
t = StringUtils.capitalize(t);
final CoreType type = EnumUtils.getEnum(CoreType.class, t);
if (type != null) {
return hasType(type);
}
final Supertype supertype = stringToSupertype.get(t);
final Supertype supertype = EnumUtils.getEnum(Supertype.class, t);
if (supertype != null) {
return hasSupertype(supertype);
}
@@ -307,18 +301,18 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return subtypes.contains(creatureType) || subtypes.contains("AllCreatureTypes");
}
private static String toMixedCase(final String s) {
if (s.equals("")) {
if (s.isEmpty()) {
return s;
}
final StringBuilder sb = new StringBuilder();
// to handle hyphenated Types
// TODO checkout WordUtils for this
final String[] types = s.split("-");
for (int i = 0; i < types.length; i++) {
if (i != 0) {
sb.append("-");
}
sb.append(types[i].substring(0, 1).toUpperCase());
sb.append(types[i].substring(1).toLowerCase());
sb.append(StringUtils.capitalize(types[i]));
}
return sb.toString();
}
@@ -606,14 +600,14 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
public static class Constant {
public static final Settable LOADED = new Settable();
public static final List<String> BASIC_TYPES = Lists.newArrayList();
public static final List<String> LAND_TYPES = Lists.newArrayList();
public static final List<String> CREATURE_TYPES = Lists.newArrayList();
public static final List<String> SPELL_TYPES = Lists.newArrayList();
public static final List<String> ENCHANTMENT_TYPES = Lists.newArrayList();
public static final List<String> ARTIFACT_TYPES = Lists.newArrayList();
public static final List<String> WALKER_TYPES = Lists.newArrayList();
public static final Set<String> BASIC_TYPES = Sets.newHashSet();
public static final Set<String> LAND_TYPES = Sets.newHashSet();
public static final Set<String> CREATURE_TYPES = Sets.newHashSet();
public static final Set<String> SPELL_TYPES = Sets.newHashSet();
public static final Set<String> ENCHANTMENT_TYPES = Sets.newHashSet();
public static final Set<String> ARTIFACT_TYPES = Sets.newHashSet();
public static final Set<String> WALKER_TYPES = Sets.newHashSet();
// singular -> plural
public static final BiMap<String,String> pluralTypes = HashBiMap.create();
// plural -> singular
@@ -662,14 +656,14 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
}
};
}
///////// Utility methods
public static boolean isACardType(final String cardType) {
return getAllCardTypes().contains(cardType);
return EnumUtils.isValidEnum(CoreType.class, cardType);
}
public static ImmutableList<String> getAllCardTypes() {
public static Set<String> getAllCardTypes() {
return CoreType.allCoreTypeNames;
}
@@ -699,12 +693,12 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return sortedSubTypes;
}
public static List<String> getBasicTypes() {
return Collections.unmodifiableList(Constant.BASIC_TYPES);
public static Collection<String> getBasicTypes() {
return Collections.unmodifiableCollection(Constant.BASIC_TYPES);
}
public static List<String> getAllCreatureTypes() {
return Collections.unmodifiableList(Constant.CREATURE_TYPES);
public static Collection<String> getAllCreatureTypes() {
return Collections.unmodifiableCollection(Constant.CREATURE_TYPES);
}
public static List<String> getAllLandTypes() {
return ImmutableList.<String>builder()
@@ -714,7 +708,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
}
public static boolean isASupertype(final String cardType) {
return (Supertype.allSuperTypeNames.contains(cardType));
return EnumUtils.isValidEnum(Supertype.class, cardType);
}
public static boolean isASubType(final String cardType) {
@@ -740,7 +734,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
public static boolean isABasicLandType(final String cardType) {
return (Constant.BASIC_TYPES.contains(cardType));
}
public static boolean isAnEnchantmentType(final String cardType) {
return (Constant.ENCHANTMENT_TYPES.contains(cardType));
}

View File

@@ -28,6 +28,8 @@ public interface ICardDatabase extends Iterable<PaperCard> {
List<PaperCard> getAllCards(String cardName);
List<PaperCard> getAllCards(Predicate<PaperCard> predicate);
List<PaperCard> getAllCardsFromEdition(CardEdition edition);
Predicate<? super PaperCard> wasPrintedInSets(List<String> allowedSetCodes);
}

View File

@@ -21,7 +21,6 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.card.CardRules;
import forge.card.CardRulesPredicates;
@@ -37,8 +36,11 @@ import forge.util.TextUtil;
import org.apache.commons.lang3.Range;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
/**
* GameType is an enum to determine the type of current game. :)
@@ -71,7 +73,7 @@ public enum DeckFormat {
private final Set<String> bannedCards = ImmutableSet.of(
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
"Fastbond", "Flash", "Goblin Recruiter", "Grindstone", "Hermit Druid", "Imperial Seal", "Jeweled Bird", "Karakas", "Library of Alexandria", "Mana Crypt", "Mana Drain", "Mana Vault", "Metalworker", "Mind Twist", "Mishra's Workshop",
"Mox Emerald", "Mox Jet", "Mox Pearl", "Mox Ruby", "Mox Sapphire", "Necropotence", "Shahrazad", "Skullclamp", "Sol Ring", "Strip Mine", "Survival of the Fittest", "Sword of Body and Mind", "Time Vault", "Time Walk", "Timetwister",
"Mox Emerald", "Mox Jet", "Mox Pearl", "Mox Ruby", "Mox Sapphire", "Najeela, the Blade Blossom", "Necropotence", "Shahrazad", "Skullclamp", "Sol Ring", "Strip Mine", "Survival of the Fittest", "Sword of Body and Mind", "Time Vault", "Time Walk", "Timetwister",
"Timmerian Fiends", "Tolarian Academy", "Umezawa's Jitte", "Vampiric Tutor", "Wheel of Fortune", "Yawgmoth's Will");
@Override
@@ -324,23 +326,32 @@ public enum DeckFormat {
}
final int maxCopies = getMaxCardCopies();
if (maxCopies < Integer.MAX_VALUE) {
//Must contain no more than 4 of the same card
//shared among the main deck and sideboard, except
//basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony
//Must contain no more than 4 of the same card
//shared among the main deck and sideboard, except
//basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony
// Seven Dwarves can have 7 in the deck. More than 7 in deck + sb is ok in Limited
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
// should group all cards by name, so that different editions of same card are really counted as the same card
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) {
final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
if (simpleCard == null) {
return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey());
}
// should group all cards by name, so that different editions of same card are really counted as the same card
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) {
final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
// Might cause issues since it ignores "Special" Cards
if (simpleCard == null) {
return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey());
}
if (!canHaveAnyNumberOf(simpleCard) && cp.getValue() > maxCopies) {
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey());
}
if (canHaveAnyNumberOf(simpleCard)) {
continue;
}
Integer cardCopies = canHaveSpecificNumberInDeck(simpleCard);
if (cardCopies != null && deck.getMain().countByName(cp.getKey(), true) > cardCopies) {
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(cardCopies), "copies of the card", cp.getKey());
}
if (cardCopies == null && cp.getValue() > maxCopies) {
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey());
}
}
@@ -362,6 +373,16 @@ public enum DeckFormat {
"A deck can have any number of cards named CARDNAME.");
}
public static Integer canHaveSpecificNumberInDeck(final IPaperCard card) {
// Ideally, this would be parsed during card parsing and set this value
if (Iterables.contains(card.getRules().getMainPart().getKeywords(),
"A deck can have up to seven cards named CARDNAME.")) {
return 7;
}
return null;
}
public static String getPlaneSectionConformanceProblem(final CardPool planes) {
//Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
if (planes == null || planes.countAll() < 10) {
@@ -442,6 +463,9 @@ public enum DeckFormat {
if (this.equals(DeckFormat.Brawl)) {
return rules.canBeBrawlCommander();
}
if (this.equals(DeckFormat.TinyLeaders)) {
return rules.canBeTinyLeadersCommander();
}
return rules.canBeCommander();
}

View File

@@ -27,7 +27,7 @@ public class DeckSerializer {
}
final List<String> metadata = map.get("metadata");
if (metadata != null) {
return new DeckFileHeader(FileSection.parse(metadata, "="));
return new DeckFileHeader(FileSection.parse(metadata, FileSection.EQUALS_KV_SEPARATOR));
}
final List<String> general = map.get("general");
if (general != null) {

View File

@@ -6,6 +6,7 @@ import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.CardType.CoreType;
import forge.card.MagicColor;
import forge.util.PredicateCard;
import forge.util.PredicateString;
import org.apache.commons.lang3.StringUtils;
@@ -60,6 +61,8 @@ public interface IPaperCard extends InventoryItem {
return new PredicateNames(what);
}
public static PredicateCards cards(final List<PaperCard> what) { return new PredicateCards(what); }
private static final class PredicateColor implements Predicate<PaperCard> {
private final byte operand;
@@ -161,6 +164,25 @@ public interface IPaperCard extends InventoryItem {
}
}
private static final class PredicateCards extends PredicateCard<PaperCard> {
private final List<PaperCard> operand;
@Override
public boolean apply(final PaperCard card) {
for (final PaperCard element : this.operand) {
if (this.op(card, element)) {
return true;
}
}
return false;
}
private PredicateCards(final List<PaperCard> operand) {
super(StringOp.EQUALS);
this.operand = operand;
}
}
/**
* Pre-built predicates are stored here to allow their re-usage and
* easier access from code.

View File

@@ -108,7 +108,7 @@ public class PreconDeck implements InventoryItemFromSet {
// 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"), "=");
FileSection kv = FileSection.parse(sections.get("metadata"), FileSection.EQUALS_KV_SEPARATOR);
String imageFilename = kv.get("Image");
String description = kv.get("Description");
String deckEdition = kv.get("set");

View File

@@ -566,12 +566,8 @@ public class BoosterGenerator {
toAdd = IPaperCard.Predicates.printedInSets(sets);
} else if (operator.startsWith("fromSheet(") && invert) {
String sheetName = StringUtils.strip(operator.substring(9), "()\" ");
Iterable<PaperCard> src = StaticData.instance().getPrintSheets().get(sheetName).toFlatList();
List<String> cardNames = Lists.newArrayList();
for (PaperCard card : src) {
cardNames.add(card.getName());
}
toAdd = IPaperCard.Predicates.names(Lists.newArrayList(cardNames));
Iterable<PaperCard> cards = StaticData.instance().getPrintSheets().get(sheetName).toFlatList();
toAdd = IPaperCard.Predicates.cards(Lists.newArrayList(cards));
}
if (toAdd == null) {

View File

@@ -1,9 +1,6 @@
package forge.card;
package forge.util;
import com.esotericsoftware.minlog.Log;
import com.google.common.base.Charsets;
import forge.properties.ForgeConstants;
import forge.util.LineReader;
import java.io.FileInputStream;
import java.io.IOException;
@@ -15,12 +12,12 @@ public class CardTranslation {
private static Map <String, String> translatednames;
private static Map <String, String> translatedtypes;
private static Map <String, String> translatedoracles;
private static String languageSelected;
private static String languageSelected = "en-US";
private static void readTranslationFile(String language) {
private static void readTranslationFile(String language, String languagesDirectory) {
String filename = "cardnames-" + language + ".txt";
try (LineReader translationFile = new LineReader(new FileInputStream(ForgeConstants.LANG_DIR + filename), Charsets.UTF_8)) {
try (LineReader translationFile = new LineReader(new FileInputStream(languagesDirectory + filename), Charsets.UTF_8)) {
for (String line : translationFile.readLines()) {
String[] matches = line.split("\\|");
if (matches.length >= 2) {
@@ -34,7 +31,7 @@ public class CardTranslation {
}
}
} catch (IOException e) {
Log.error("Error reading translation file: cardnames-" + language + ".txt");
System.err.println("Error reading translation file: cardnames-" + language + ".txt");
}
}
@@ -66,7 +63,7 @@ public class CardTranslation {
}
public static HashMap<String, String> getTranslationTexts(String cardname, String altcardname) {
HashMap<String, String> translations = new HashMap<String, String>();
HashMap<String, String> translations = new HashMap<>();
translations.put("name", getTranslatedName(cardname));
translations.put("oracle", getTranslatedOracle(cardname));
translations.put("altname", getTranslatedName(altcardname));
@@ -78,14 +75,14 @@ public class CardTranslation {
return !languageSelected.equals("en-US");
}
public static void preloadTranslation(String language) {
public static void preloadTranslation(String language, String languagesDirectory) {
languageSelected = language;
if (needsTranslation()) {
translatednames = new HashMap<>();
translatedtypes = new HashMap<>();
translatedoracles = new HashMap<>();
readTranslationFile(languageSelected);
readTranslationFile(languageSelected, languagesDirectory);
}
}
}

View File

@@ -17,9 +17,12 @@
*/
package forge.util;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -56,34 +59,40 @@ public class FileSection {
protected FileSection(Map<String, String> lines0) {
lines = lines0;
}
/**
* Parses the.
*
* @param line the line
* @param kvSeparator the kv separator
* @param pairSeparator the pair separator
* @return the file section
*/
public static FileSection parse(final String line, final String kvSeparator, final String pairSeparator) {
Map<String, String> map = parseToMap(line, kvSeparator, pairSeparator);
return new FileSection(map);
}
public static Map<String, String> parseToMap(final String line, final String kvSeparator, final String pairSeparator) {
Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
if (!StringUtils.isEmpty(line)) {
final String[] pairs = line.split(Pattern.quote(pairSeparator));
final Pattern splitter = Pattern.compile(Pattern.quote(kvSeparator));
for (final String dd : pairs) {
final String[] v = splitter.split(dd, 2);
result.put(v[0].trim(), v.length > 1 ? v[1].trim() : "");
}
public static final Pattern DOLLAR_SIGN_KV_SEPARATOR = Pattern.compile(Pattern.quote("$"));
public static final Pattern ARROW_KV_SEPARATOR = Pattern.compile(Pattern.quote("->"));
public static final Pattern EQUALS_KV_SEPARATOR = Pattern.compile(Pattern.quote("="));
public static final Pattern COLON_KV_SEPARATOR = Pattern.compile(Pattern.quote(":"));
private static final String BAR_PAIR_SPLITTER = Pattern.quote("|");
private static Table<String, Pattern, Map<String, String>> parseToMapCache = HashBasedTable.create();
public static Map<String, String> parseToMap(final String line, final Pattern kvSeparator) {
Map<String, String> result = parseToMapCache.get(line, kvSeparator);
if (result != null) {
return result;
}
result = parseToMapImpl(line, kvSeparator);
parseToMapCache.put(line, kvSeparator, result);
return result;
}
private static Map<String, String> parseToMapImpl(final String line, final Pattern kvSeparator) {
if (StringUtils.isEmpty(line)) {
return Collections.emptyMap();
}
final Map<String, String> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
final String[] pairs = line.split(BAR_PAIR_SPLITTER);
for (final String dd : pairs) {
final String[] v = kvSeparator.split(dd, 2);
result.put(v[0].trim(), v.length > 1 ? v[1].trim() : "");
}
return Collections.unmodifiableMap(result);
}
/**
* Parses the.
*
@@ -91,11 +100,10 @@ public class FileSection {
* @param kvSeparator the kv separator
* @return the file section
*/
public static FileSection parse(final Iterable<String> lines, final String kvSeparator) {
public static FileSection parse(final Iterable<String> lines, final Pattern kvSeparator) {
final FileSection result = new FileSection();
final Pattern splitter = Pattern.compile(Pattern.quote(kvSeparator));
for (final String dd : lines) {
final String[] v = splitter.split(dd, 2);
final String[] v = kvSeparator.split(dd, 2);
result.lines.put(v[0].trim(), v.length > 1 ? v[1].trim() : "");
}

View File

@@ -56,7 +56,7 @@ public class Localizer {
public String getMessage(final String key, final Object... messageArguments) {
MessageFormat formatter = null;
try {
//formatter = new MessageFormat(resourceBundle.getString(key.toLowerCase()), locale);
formatter = new MessageFormat(resourceBundle.getString(key), locale);
@@ -72,15 +72,29 @@ public class Localizer {
formatter.setLocale(locale);
String formattedMessage = "CHAR ENCODING ERROR";
final String[] charsets = { "ISO-8859-1", "UTF-8" };
//Support non-English-standard characters
String detectedCharset = charset(new String(formatter.format(messageArguments)), new String[] { "ISO-8859-1", "UTF-8" });
String detectedCharset = charset(resourceBundle.getString(key), charsets);
final int argLength = messageArguments.length;
Object[] syncEncodingMessageArguments = new Object[argLength];
//when messageArguments encoding not equal resourceBundle.getString(key),convert to equal
//avoid convert to a have two encoding content formattedMessage string.
for (int i = 0; i < argLength; i++) {
String objCharset = charset(messageArguments[i].toString(), charsets);
try {
syncEncodingMessageArguments[i] = convert(messageArguments[i].toString(), objCharset, detectedCharset);
} catch (UnsupportedEncodingException ignored) {
System.err.println("Cannot Convert '" + messageArguments[i].toString() + "' from '" + objCharset + "' To '" + detectedCharset + "'");
return "encoding '" + key + "' translate string failure";
}
}
try {
formattedMessage = new String(formatter.format(messageArguments).getBytes(detectedCharset), StandardCharsets.UTF_8);
formattedMessage = new String(formatter.format(syncEncodingMessageArguments).getBytes(detectedCharset), StandardCharsets.UTF_8);
} catch(UnsupportedEncodingException ignored) {}
return formattedMessage;
}
public void setLanguage(final String languageRegionID, final String languagesDirectory) {

View File

@@ -0,0 +1,83 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2020 Jamin W. Collins
*
* 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.util;
import com.google.common.base.Predicate;
import forge.item.PaperCard;
/**
* Special predicate class to perform string operations.
*
* @param <T>
* the generic type
*/
public abstract class PredicateCard<T> implements Predicate<T> {
/** Possible operators for string operands. */
public enum StringOp {
/** The EQUALS. */
EQUALS,
}
/** The operator. */
private final StringOp operator;
/**
* Op.
*
* @param op1
* the op1
* @param op2
* the op2
* @return true, if successful
*/
protected final boolean op(final PaperCard op1, final PaperCard op2) {
switch (this.getOperator()) {
case EQUALS:
return op1.equals(op2);
default:
return false;
}
}
/**
* Instantiates a new predicate string.
*
* @param operator
* the operator
*/
public PredicateCard(final StringOp operator) {
this.operator = operator;
}
/**
* @return the operator
*/
public StringOp getOperator() {
return operator;
}
public static PredicateCard<PaperCard> equals(final PaperCard what) {
return new PredicateCard<PaperCard>(StringOp.EQUALS) {
@Override
public boolean apply(PaperCard subject) {
return op(subject, what);
}
};
}
}

View File

@@ -5,6 +5,8 @@ import forge.item.PaperCard;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableSortedMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -17,6 +19,22 @@ import java.util.Map.Entry;
*/
public class TextUtil {
static ImmutableSortedMap<Integer,String> romanMap = ImmutableSortedMap.<Integer,String>naturalOrder()
.put(1000, "M").put(900, "CM")
.put(500, "D").put(400, "CD")
.put(100, "C").put(90, "XC")
.put(50, "L").put(40, "XL")
.put(10, "X").put(9, "IX")
.put(5, "V").put(4, "IV").put(1, "I").build();
public final static String toRoman(int number) {
if (number <= 0) {
return "";
}
int l = romanMap.floorKey(number);
return romanMap.get(l) + toRoman(number-l);
}
/**
* Safely converts an object to a String.
*

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>forge</artifactId>
<groupId>forge</groupId>
<version>1.6.30-SNAPSHOT</version>
<version>1.6.33</version>
</parent>
<artifactId>forge-game</artifactId>
@@ -32,8 +32,8 @@
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-log4j</artifactId>
<version>1.7.5</version>
<artifactId>sentry-log4j2</artifactId>
<version>1.7.27</version>
</dependency>
</dependencies>

View File

@@ -72,8 +72,9 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
return this.mapParams;
}
public final String getParamOrDefault(String key, String defaultValue) {
return hasParam(key) ? getParam(key) : defaultValue;
public String getParamOrDefault(String key, String defaultValue) {
String param = mapParams.get(key);
return param != null ? param : defaultValue;
}
public String getParam(String key) {
@@ -560,4 +561,12 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
// this does overwrite the original MapParams
this.originalMapParams = Maps.newHashMap(this.mapParams);
}
protected void copyHelper(CardTraitBase copy, Card host) {
copy.originalMapParams = Maps.newHashMap(originalMapParams);
copy.mapParams = Maps.newHashMap(originalMapParams);
copy.sVars = Maps.newHashMap(sVars);
// dont use setHostCard to not trigger the not copied parts yet
copy.hostCard = host;
}
}

View File

@@ -168,6 +168,8 @@ public class ForgeScript {
return found;
} else if (property.equals("YouCtrl")) {
return sa.getActivatingPlayer().equals(sourceController);
} else if (property.equals("OppCtrl")) {
return sa.getActivatingPlayer().isOpponentOf(sourceController);
} else if (sa.getHostCard() != null) {
return sa.getHostCard().hasProperty(property, sourceController, source, spellAbility);
}

View File

@@ -914,4 +914,17 @@ public class Game {
}
return false;
}
public Player getControlVote() {
Player result = null;
long maxValue = 0;
for (Player p : getPlayers()) {
Long v = p.getHighestControlVote();
if (v != null && v > maxValue) {
maxValue = v;
result = p;
}
}
return result;
}
}

View File

@@ -6,12 +6,12 @@
* 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/>.
*/
@@ -57,7 +57,7 @@ import java.util.*;
/**
* Methods for common actions performed during a game.
*
*
* @author Forge
* @version $Id$
*/
@@ -80,7 +80,7 @@ public class GameAction {
public Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer position, SpellAbility cause) {
return changeZone(zoneFrom, zoneTo, c, position, cause, null);
}
private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer position, SpellAbility cause, Map<AbilityKey, Object> params) {
if (c.isCopiedSpell() || (c.isImmutable() && zoneTo.is(ZoneType.Exile))) {
// Remove Effect from command immediately, this is essential when some replacement
@@ -125,11 +125,16 @@ public class GameAction {
Card copied = null;
Card lastKnownInfo = null;
// get the LKI from above like ChangeZoneEffect
if (params != null && params.containsKey(AbilityKey.CardLKI)) {
lastKnownInfo = (Card) params.get(AbilityKey.CardLKI);
}
if (c.isSplitCard()) {
boolean resetToOriginal = false;
if (c.isManifested()) {
if (zoneFrom.is(ZoneType.Battlefield)) {
if (fromBattlefield) {
// Make sure the card returns from the battlefield as the original card with two halves
resetToOriginal = true;
}
@@ -164,8 +169,22 @@ public class GameAction {
// Don't copy Tokens, copy only cards leaving the battlefield
// and returning to hand (to recreate their spell ability information)
if (suppress || (!fromBattlefield && !toHand)) {
lastKnownInfo = c;
copied = c;
// if to Battlefield and it is caused by an replacement effect,
// try to get previous LKI if able
if (zoneTo.is(ZoneType.Battlefield)) {
if (cause != null && cause.isReplacementAbility()) {
ReplacementEffect re = cause.getReplacementEffect();
if (ReplacementType.Moved.equals(re.getMode())) {
lastKnownInfo = (Card) cause.getReplacingObject(AbilityKey.CardLKI);
}
}
}
if (lastKnownInfo == null) {
lastKnownInfo = CardUtil.getLKICopy(c);
}
} else {
// if from Battlefield to Graveyard and Card does exist in LastStateBattlefield
// use that instead
@@ -189,15 +208,13 @@ public class GameAction {
}
if (!c.isToken()) {
if (c.isCloned() || c.hasTextChangeState()) {
c.removeCloneStates();
c.removeTextChangeStates();
if (c.removeChangedState()) {
c.updateStateForView();
}
copied = CardFactory.copyCard(c, false);
if (fromBattlefield && copied.getCurrentStateName() != CardStateName.Original) {
if (fromBattlefield) {
// when a card leaves the battlefield, ensure it's in its original state
// (we need to do this on the object before copying it, or it won't work correctly e.g.
// on Transformed objects)
@@ -227,59 +244,6 @@ public class GameAction {
}
}
// special rule for Worms of the Earth
if (toBattlefield && game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLandBattlefield)) {
// something that is already a Land cant enter the battlefield
Card noLandLKI = c;
if (!c.isLand()) {
// check if something would be a land
noLandLKI = CardUtil.getLKICopy(c);
// this check needs to check if this card would be on the battlefield
noLandLKI.setLastKnownZone(zoneTo);
CardCollection preList = new CardCollection(noLandLKI);
checkStaticAbilities(false, Sets.newHashSet(noLandLKI), preList);
// fake etb counters thing, then if something changed,
// need to apply checkStaticAbilities again
if(!noLandLKI.isLand()) {
if (noLandLKI.putEtbCounters(null)) {
// counters are added need to check again
checkStaticAbilities(false, Sets.newHashSet(noLandLKI), preList);
}
}
}
if(noLandLKI.isLand()) {
// if it isn't on the Stack, it stays in that Zone
if (!c.isInZone(ZoneType.Stack)) {
return c;
}
// if something would only be a land when entering the battlefield and not before
// put it into the graveyard instead
zoneTo = c.getOwner().getZone(ZoneType.Graveyard);
// reset facedown
copied.setState(CardStateName.Original, false);
copied.setManifested(false);
copied.updateStateForView();
// not to battlefield anymore!
toBattlefield = false;
if (c.isCloned() || c.hasTextChangeState()) {
c.removeCloneStates();
c.removeTextChangeStates();
c.updateStateForView();
}
if (copied.getCurrentStateName() != CardStateName.Original) {
copied.setState(CardStateName.Original, false);
}
copied.updateStateForView();
}
}
if (!suppress) {
if (zoneFrom == null) {
copied.getOwner().addInboundToken(copied);
@@ -298,15 +262,29 @@ public class GameAction {
ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, repParams);
if (repres != ReplacementResult.NotReplaced) {
// reset failed manifested Cards back to original
if (c.isManifested()) {
if (c.isManifested() && !c.isInZone(ZoneType.Battlefield)) {
c.turnFaceUp(false, false);
}
if (game.getStack().isResolving(c) && !zoneTo.is(ZoneType.Graveyard) && repres == ReplacementResult.Prevented) {
copied.getOwner().removeInboundToken(copied);
return moveToGraveyard(c, cause, params);
}
copied.getOwner().removeInboundToken(copied);
if (repres == ReplacementResult.Prevented) {
if (game.getStack().isResolving(c) && !zoneTo.is(ZoneType.Graveyard)) {
return moveToGraveyard(c, cause, params);
}
copied.clearDevoured();
copied.clearDelved();
copied.clearConvoked();
copied.clearExploited();
}
// was replaced with another Zone Change
if (toBattlefield && !c.isInZone(ZoneType.Battlefield)) {
if (c.removeChangedState()) {
c.updateStateForView();
}
}
return c;
}
}
@@ -370,7 +348,7 @@ public class GameAction {
// do ETB counters after zone add
if (!suppress) {
if (toBattlefield ) {
if (toBattlefield) {
copied.putEtbCounters(table);
// enable replacement effects again
for (final ReplacementEffect re : copied.getReplacementEffects()) {
@@ -393,6 +371,14 @@ public class GameAction {
c.setMustAttackEntity(null);
}
// for ETB trigger to work correct,
// the LKI needs to be the Card itself,
// or it might not updated correctly
// TODO be reworked when ZoneTrigger Update is done
if (toBattlefield || zoneTo.is(ZoneType.Stack)) {
lastKnownInfo = c;
}
// Need to apply any static effects to produce correct triggers
checkStaticAbilities();
game.getTriggerHandler().clearInstrinsicActiveTriggers(c, zoneFrom);
@@ -415,7 +401,7 @@ public class GameAction {
}
game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, true);
if (zoneFrom != null && zoneFrom.is(ZoneType.Battlefield) && !zoneFrom.getPlayer().equals(zoneTo.getPlayer())) {
if (fromBattlefield && !zoneFrom.getPlayer().equals(zoneTo.getPlayer())) {
final Map<AbilityKey, Object> runParams2 = AbilityKey.mapFromCard(lastKnownInfo);
runParams2.put(AbilityKey.OriginalController, zoneFrom.getPlayer());
if(params != null) {
@@ -447,7 +433,7 @@ public class GameAction {
copied.clearExploited();
}
// rule 504.6: reveal a face-down card leaving the stack
// rule 504.6: reveal a face-down card leaving the stack
if (zoneFrom != null && zoneTo != null && zoneFrom.is(ZoneType.Stack) && !zoneTo.is(ZoneType.Battlefield) && wasFacedown) {
Card revealLKI = CardUtil.getLKICopy(c);
revealLKI.turnFaceUp(true, false);
@@ -491,7 +477,7 @@ public class GameAction {
// Remove all changed keywords
copied.removeAllChangedText(game.getNextTimestamp());
} else if (toBattlefield) {
// reset timestamp in changezone effects so they have same timestamp if ETB simutaneously
// reset timestamp in changezone effects so they have same timestamp if ETB simutaneously
copied.setTimestamp(game.getNextTimestamp());
for (Player p : game.getPlayers()) {
copied.getDamageHistory().setNotAttackedSinceLastUpkeepOf(p);
@@ -514,6 +500,11 @@ public class GameAction {
}
}
// Cards not on the battlefield / stack should not have controller
if (!zoneTo.is(ZoneType.Battlefield) && !zoneTo.is(ZoneType.Stack)) {
c.clearControllers();
}
return copied;
}
@@ -535,7 +526,7 @@ public class GameAction {
return moveTo(zoneTo, c, position, cause, null);
}
private Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
public final Card moveTo(final Zone zoneTo, Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
// FThreads.assertExecutedByEdt(false); // This code must never be executed from EDT,
// use FThreads.invokeInNewThread to run code in a pooled thread
return moveTo(zoneTo, c, null, cause, params);
@@ -556,6 +547,13 @@ public class GameAction {
c.setCastSA(null);
} else if (zoneTo.is(ZoneType.Stack)) {
c.setCastFrom(zoneFrom.getZoneType());
if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) {
cause.setLastStateBattlefield(game.getLastStateBattlefield());
cause.setLastStateGraveyard(game.getLastStateGraveyard());
c.setCastSA(cause);
} else {
c.setCastSA(null);
}
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
c.setCastFrom(null);
c.setCastSA(null);
@@ -574,16 +572,31 @@ public class GameAction {
public final void controllerChangeZoneCorrection(final Card c) {
System.out.println("Correcting zone for " + c.toString());
final Zone oldBattlefield = game.getZoneOf(c);
if (oldBattlefield == null || oldBattlefield.getZoneType() == ZoneType.Stack) {
if (oldBattlefield == null || oldBattlefield.is(ZoneType.Stack)) {
return;
}
final Player original = oldBattlefield.getPlayer();
final PlayerZone newBattlefield = c.getController().getZone(oldBattlefield.getZoneType());
final Player controller = c.getController();
if (original == null || controller == null || original.equals(controller)) {
return;
}
final PlayerZone newBattlefield = controller.getZone(oldBattlefield.getZoneType());
if (newBattlefield == null || oldBattlefield.equals(newBattlefield)) {
return;
}
// 702.94e A paired creature becomes unpaired if any of the following occur:
// another player gains control of it or the creature its paired with
if (c.isPaired()) {
Card partner = c.getPairedWith();
c.setPairedWith(null);
partner.setPairedWith(null);
partner.updateStateForView();
}
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
for (Player p : game.getPlayers()) {
((PlayerZoneBattlefield) p.getZone(ZoneType.Battlefield)).setTriggers(false);
@@ -613,8 +626,12 @@ public class GameAction {
}
public final Card moveToStack(final Card c, SpellAbility cause) {
return moveToStack(c, cause, null);
}
public final Card moveToStack(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
final Zone stack = game.getStackZone();
return moveTo(stack, c, cause);
return moveTo(stack, c, cause, params);
}
public final Card moveToGraveyard(final Card c, SpellAbility cause) {
@@ -629,7 +646,7 @@ public class GameAction {
public final Card moveToHand(final Card c, SpellAbility cause) {
return moveToHand(c, cause, null);
}
public final Card moveToHand(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone hand = c.getOwner().getZone(ZoneType.Hand);
return moveTo(hand, c, cause, params);
@@ -643,7 +660,7 @@ public class GameAction {
public final Card moveToPlay(final Card c, final Player p, SpellAbility cause) {
return moveToPlay(c, p, cause, null);
}
public final Card moveToPlay(final Card c, final Player p, SpellAbility cause, Map<AbilityKey, Object> params) {
// move to a specific player's Battlefield
final PlayerZone play = p.getZone(ZoneType.Battlefield);
@@ -653,7 +670,7 @@ public class GameAction {
public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause) {
return moveToBottomOfLibrary(c, cause, null);
}
public final Card moveToBottomOfLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
return moveToLibrary(c, -1, cause, params);
}
@@ -661,7 +678,7 @@ public class GameAction {
public final Card moveToLibrary(final Card c, SpellAbility cause) {
return moveToLibrary(c, cause, null);
}
public final Card moveToLibrary(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
return moveToLibrary(c, 0, cause, params);
}
@@ -669,7 +686,7 @@ public class GameAction {
public final Card moveToLibrary(Card c, int libPosition, SpellAbility cause) {
return moveToLibrary(c, libPosition, cause, null);
}
public final Card moveToLibrary(Card c, int libPosition, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone library = c.getOwner().getZone(ZoneType.Library);
if (libPosition == -1 || libPosition > library.size()) {
@@ -679,11 +696,15 @@ public class GameAction {
}
public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, SpellAbility cause) {
return moveToVariantDeck(c, zone, deckPosition, cause, null);
}
public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, SpellAbility cause, Map<AbilityKey, Object> params) {
final PlayerZone deck = c.getOwner().getZone(zone);
if (deckPosition == -1 || deckPosition > deck.size()) {
deckPosition = deck.size();
}
return changeZone(game.getZoneOf(c), deck, c, deckPosition, cause);
return changeZone(game.getZoneOf(c), deck, c, deckPosition, cause, params);
}
public final Card exile(final Card c, SpellAbility cause) {
@@ -701,7 +722,9 @@ public class GameAction {
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.Cause, cause);
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
if (origin != null) { // is generally null when adding via dev mode
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
}
if (params != null) {
runParams.putAll(params);
}
@@ -716,16 +739,20 @@ public class GameAction {
}
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause) {
return moveTo(name, c, libPosition, cause, null);
}
public final Card moveTo(final ZoneType name, final Card c, final int libPosition, SpellAbility cause, Map<AbilityKey, Object> params) {
// Call specific functions to set PlayerZone, then move onto moveTo
switch(name) {
case Hand: return moveToHand(c, cause);
case Library: return moveToLibrary(c, libPosition, cause);
case Battlefield: return moveToPlay(c, cause);
case Graveyard: return moveToGraveyard(c, cause);
case Exile: return exile(c, cause);
case Stack: return moveToStack(c, cause);
case PlanarDeck: return moveToVariantDeck(c, ZoneType.PlanarDeck, libPosition, cause);
case SchemeDeck: return moveToVariantDeck(c, ZoneType.SchemeDeck, libPosition, cause);
case Hand: return moveToHand(c, cause, params);
case Library: return moveToLibrary(c, libPosition, cause, params);
case Battlefield: return moveToPlay(c, c.getController(), cause, params);
case Graveyard: return moveToGraveyard(c, cause, params);
case Exile: return exile(c, cause, params);
case Stack: return moveToStack(c, cause, params);
case PlanarDeck: return moveToVariantDeck(c, ZoneType.PlanarDeck, libPosition, cause, params);
case SchemeDeck: return moveToVariantDeck(c, ZoneType.SchemeDeck, libPosition, cause, params);
default: // sideboard will also get there
return moveTo(c.getOwner().getZone(name), c, cause);
}
@@ -786,7 +813,7 @@ public class GameAction {
}
});
final Comparator<StaticAbility> comp = new Comparator<StaticAbility>() {
@Override
public int compare(final StaticAbility a, final StaticAbility b) {
@@ -1066,7 +1093,7 @@ public class GameAction {
if (!game.isGameOver()) {
checkGameOverCondition();
}
if (game.getAge() != GameStage.Play) {
return;
}
@@ -1551,8 +1578,7 @@ public class GameAction {
// Where there are none, it should bring up speed controls
game.fireEvent(new GameEventGameStarted(gameType, first, game.getPlayers()));
// Emissary's Plot
// runPreOpeningHandActions(first);
runPreOpeningHandActions(first);
game.setAge(GameStage.Mulligan);
for (final Player p1 : game.getPlayers()) {

View File

@@ -22,9 +22,10 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.card.CardStateName;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.*;
@@ -33,9 +34,15 @@ import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.*;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
@@ -75,77 +82,19 @@ public final class GameActionUtil {
Card source = sa.getHostCard();
final Game game = source.getGame();
if (sa.isSpell()) {
if (sa.isSpell() && !source.isInZone(ZoneType.Battlefield)) {
boolean lkicheck = false;
// need to be done before so it works with Vivien and Zoetic Cavern
if (source.isFaceDown() && source.isInZone(ZoneType.Exile)) {
if (!source.isLKI()) {
source = CardUtil.getLKICopy(source);
}
source.turnFaceUp(false, false);
lkicheck = true;
}
if (sa.hasParam("Bestow") && !source.isBestowed() && !source.isInZone(ZoneType.Battlefield)) {
if (!source.isLKI()) {
source = CardUtil.getLKICopy(source);
}
source.animateBestow(false);
lkicheck = true;
} else if (sa.isCastFaceDown()) {
// need a copy of the card to turn facedown without trigger anything
if (!source.isLKI()) {
source = CardUtil.getLKICopy(source);
}
source.turnFaceDownNoUpdate();
lkicheck = true;
} else if (sa.isAdventure() && !source.isInZone(ZoneType.Battlefield)) {
if (!source.isLKI()) {
source = CardUtil.getLKICopy(source);
}
source.setState(CardStateName.Adventure, false);
// need to reset CMC
source.setLKICMC(-1);
source.setLKICMC(source.getCMC());
lkicheck = true;
} else if (source.isSplitCard() && (sa.isLeftSplit() || sa.isRightSplit())) {
if (!source.isLKI()) {
source = CardUtil.getLKICopy(source);
}
if (sa.isLeftSplit()) {
if (!source.hasState(CardStateName.LeftSplit)) {
source.addAlternateState(CardStateName.LeftSplit, false);
source.getState(CardStateName.LeftSplit).copyFrom(
sa.getHostCard().getState(CardStateName.LeftSplit), true);
}
source.setState(CardStateName.LeftSplit, false);
}
if (sa.isRightSplit()) {
if (!source.hasState(CardStateName.RightSplit)) {
source.addAlternateState(CardStateName.RightSplit, false);
source.getState(CardStateName.RightSplit).copyFrom(
sa.getHostCard().getState(CardStateName.RightSplit), true);
}
source.setState(CardStateName.RightSplit, false);
}
// need to reset CMC
source.setLKICMC(-1);
source.setLKICMC(source.getCMC());
Card newHost = ((Spell)sa).getAlternateHost(source);
if (newHost != null) {
source = newHost;
lkicheck = true;
}
if (lkicheck) {
// double freeze tracker, so it doesn't update view
game.getTracker().freeze();
source.clearChangedCardKeywords(false);
CardCollection preList = new CardCollection(source);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(source), preList);
}
@@ -207,6 +156,58 @@ public final class GameActionUtil {
alternatives.add(newSA);
}
// need to be done there before static abilities does reset the card
if (sa.isBasicSpell()) {
for (final KeywordInterface inst : source.getKeywords()) {
final String keyword = inst.getOriginal();
if (keyword.startsWith("Escape")) {
final String[] k = keyword.split(":");
final Cost escapeCost = new Cost(k[1], true);
final SpellAbility newSA = sa.copyWithDefinedCost(escapeCost);
newSA.setActivatingPlayer(activator);
newSA.getMapParams().put("PrecostDesc", "Escape—");
newSA.getMapParams().put("CostDesc", escapeCost.toString());
// makes new SpellDescription
final StringBuilder desc = new StringBuilder();
desc.append(newSA.getCostDescription());
desc.append("(").append(inst.getReminderText()).append(")");
newSA.setDescription(desc.toString());
// Stack Description only for Permanent or it might crash
if (source.isPermanent()) {
final StringBuilder sbStack = new StringBuilder();
sbStack.append(sa.getStackDescription()).append(" (Escaped)");
newSA.setStackDescription(sbStack.toString());
}
newSA.setAlternativeCost(AlternativeCost.Escape);
newSA.getRestrictions().setZone(ZoneType.Graveyard);
alternatives.add(newSA);
} else if (keyword.startsWith("Flashback")) {
// if source has No Mana cost, and flashback doesn't have own one,
// flashback can't work
if (keyword.equals("Flashback") && source.getManaCost().isNoCost()) {
continue;
}
final SpellAbility flashback = sa.copy(activator);
flashback.setAlternativeCost(AlternativeCost.Flashback);
flashback.getRestrictions().setZone(ZoneType.Graveyard);
// there is a flashback cost (and not the cards cost)
if (keyword.contains(":")) {
final String[] k = keyword.split(":");
flashback.setPayCosts(new Cost(k[1], false));
}
alternatives.add(flashback);
}
}
}
// reset static abilities
if (lkicheck) {
game.getAction().checkStaticAbilities(false);
@@ -224,6 +225,7 @@ public final class GameActionUtil {
if (sa.isCycling() && activator.hasKeyword("CyclingForZero")) {
// set the cost to this directly to buypass non mana cost
final SpellAbility newSA = sa.copyWithDefinedCost("Discard<1/CARDNAME>");
newSA.setActivatingPlayer(activator);
newSA.setBasicSpell(false);
newSA.getMapParams().put("CostDesc", ManaCostParser.parse("0"));
// makes new SpellDescription
@@ -244,28 +246,6 @@ public final class GameActionUtil {
alternatives.add(newSA);
}
for (final KeywordInterface inst : source.getKeywords()) {
final String keyword = inst.getOriginal();
if (sa.isSpell() && keyword.startsWith("Flashback")) {
// if source has No Mana cost, and flashback doesn't have own one,
// flashback can't work
if (keyword.equals("Flashback") && source.getManaCost().isNoCost()) {
continue;
}
final SpellAbility flashback = sa.copy(activator);
flashback.setFlashBackAbility(true);
flashback.getRestrictions().setZone(ZoneType.Graveyard);
// there is a flashback cost (and not the cards cost)
if (keyword.contains(":")) {
final String[] k = keyword.split(":");
flashback.setPayCosts(new Cost(k[1], false));
}
alternatives.add(flashback);
}
}
return alternatives;
}
@@ -391,10 +371,11 @@ public final class GameActionUtil {
}
SpellAbility result = null;
final Card host = sa.getHostCard();
final Game game = host.getGame();
final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController();
host.getGame().getAction().checkStaticAbilities(false);
game.getAction().checkStaticAbilities(false);
boolean reset = false;
@@ -457,7 +438,60 @@ public final class GameActionUtil {
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
if (v > 0) {
host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp());
eff.setName(c.getName() + "'s Effect");
eff.addType("Effect");
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
eff.setOwner(activator);
eff.setImageKey(c.getImageKey());
eff.setColor(MagicColor.COLORLESS);
eff.setImmutable(true);
// try to get the SpellAbility from the mana ability
//eff.setEffectSource((SpellAbility)null);
eff.addRemembered(host);
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
CardFactoryUtil.setupETBReplacementAbility(saAb);
String desc = "It enters the battlefield with ";
desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
desc += " on it.";
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(saAb);
eff.addReplacementEffect(re);
// Forgot Trigger
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
parsedTrigger.setOverridingAbility(saForget);
eff.addTrigger(parsedTrigger);
eff.updateStateForView();
// TODO: Add targeting to the effect so it knows who it's dealing with
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
game.getAction().moveTo(ZoneType.Command, eff, null);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
if (result == null) {
result = sa.copy();
}

View File

@@ -385,7 +385,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
}
// CantTarget static abilities
for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
for (final Card ca : getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (stAb.applyAbility("CantAttach", attach, this)) {
return false;

View File

@@ -47,7 +47,7 @@ import java.util.Map.Entry;
public class GameFormat implements Comparable<GameFormat> {
private final String name;
public enum FormatType {Sanctioned, Casual, Historic, Digital, Custom}
public enum FormatSubType {Block, Standard, Extended, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
public enum FormatSubType {Block, Standard, Extended, Pioneer, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
// contains allowed sets, when empty allows all sets
private FormatType formatType;
@@ -290,6 +290,7 @@ public class GameFormat implements Comparable<GameFormat> {
private List<String> coreFormats = new ArrayList<>();
{
coreFormats.add("Standard.txt");
coreFormats.add("Pioneer.txt");
coreFormats.add("Modern.txt");
coreFormats.add("Legacy.txt");
coreFormats.add("Vintage.txt");
@@ -320,7 +321,7 @@ public class GameFormat implements Comparable<GameFormat> {
if (formatStrings == null){
return null;
}
FileSection section = FileSection.parse(formatStrings, ":");
FileSection section = FileSection.parse(formatStrings, FileSection.COLON_KV_SEPARATOR);
String title = section.get("name");
FormatType formatType;
try {
@@ -468,6 +469,10 @@ public class GameFormat implements Comparable<GameFormat> {
return this.map.get("Extended");
}
public GameFormat getPioneer() {
return this.map.get("Pioneer");
}
public GameFormat getModern() {
return this.map.get("Modern");
}

View File

@@ -33,11 +33,11 @@ import forge.game.player.RegisteredPlayer;
import forge.game.spellability.TargetChoices;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.maps.MapOfLists;
public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
private final GameLog log;
public GameLogFormatter(GameLog gameLog) {
log = gameLog;
}
@@ -52,16 +52,15 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
@Override
public GameLogEntry visit(GameEventScry ev) {
final Localizer localizer = Localizer.getInstance();
String scryOutcome = "";
String toTop = Lang.nounWithAmount(ev.toTop, "card") + " to the top of the library";
String toBottom = Lang.nounWithAmount(ev.toBottom, "card") + " to the bottom of the library";
if (ev.toTop > 0 && ev.toBottom > 0) {
scryOutcome = ev.player.toString() + " scried " + toTop + " and " + toBottom;
scryOutcome = localizer.getMessage("lblLogScryTopBottomLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop)).replace("%bottom", String.valueOf(ev.toBottom));
} else if (ev.toBottom == 0) {
scryOutcome = ev.player.toString() + " scried " + toTop;
scryOutcome = localizer.getMessage("lblLogScryTopLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop));
} else {
scryOutcome = ev.player.toString() + " scried " + toBottom;
scryOutcome = localizer.getMessage("lblLogScryBottomLibrary").replace("%s", ev.player.toString()).replace("%bottom", String.valueOf(ev.toBottom));
}
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, scryOutcome);
@@ -69,16 +68,15 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
@Override
public GameLogEntry visit(GameEventSurveil ev) {
final Localizer localizer = Localizer.getInstance();
String surveilOutcome = "";
String toLibrary = Lang.nounWithAmount(ev.toLibrary, "card") + " to the top of the library";
String toGraveyard = Lang.nounWithAmount(ev.toGraveyard, "card") + " to the graveyard";
if (ev.toLibrary > 0 && ev.toGraveyard > 0) {
surveilOutcome = ev.player.toString() + " surveiled " + toLibrary + " and " + toGraveyard;
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibraryGraveyard", ev.player.toString(), String.valueOf(ev.toLibrary), String.valueOf(ev.toGraveyard));
} else if (ev.toGraveyard == 0) {
surveilOutcome = ev.player.toString() + " surveiled " + toLibrary;
surveilOutcome = localizer.getMessage("lblLogSurveiledToLibrary", ev.player.toString(), String.valueOf(ev.toLibrary));
} else {
surveilOutcome = ev.player.toString() + " surveiled " + toGraveyard;
surveilOutcome = localizer.getMessage("lblLogSurveiledToGraveyard", ev.player.toString(), String.valueOf(ev.toGraveyard));
}
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, surveilOutcome);
@@ -86,21 +84,25 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
@Override
public GameLogEntry visit(GameEventSpellResolved ev) {
String messageForLog = ev.hasFizzled ? ev.spell.getHostCard().getName() + " ability fizzles." : ev.spell.getStackDescription();
String messageForLog = ev.hasFizzled ? Localizer.getInstance().getMessage("lblLogCardAbilityFizzles", ev.spell.getHostCard().toString()) : ev.spell.getStackDescription();
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, messageForLog);
}
@Override
public GameLogEntry visit(GameEventSpellAbilityCast event) {
String who = event.sa.getActivatingPlayer().getName();
String action = event.sa.isSpell() ? " cast " : event.sa.isTrigger() ? " triggered " : " activated ";
String what = event.sa.getStackDescription().startsWith("Morph ") ? "Morph" : event.sa.getHostCard().toString();
final Localizer localizer = Localizer.getInstance();
String player = event.sa.getActivatingPlayer().getName();
String action = event.sa.isSpell() ? localizer.getMessage("lblCast")
: event.sa.isTrigger() ? localizer.getMessage("lblTriggered")
: localizer.getMessage("lblActivated");
String object = event.sa.getStackDescription().startsWith("Morph ")
? localizer.getMessage("lblMorph")
: event.sa.getHostCard().toString();
StringBuilder sb = new StringBuilder();
sb.append(who).append(action).append(what);
String messageForLog = "";
if (event.sa.getTargetRestrictions() != null) {
sb.append(" targeting ");
StringBuilder sb = new StringBuilder();
List<TargetChoices> targets = event.sa.getAllTargetChoices();
// Include the TargetChoices from the stack instance, since the real target choices
@@ -111,10 +113,12 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
sb.append(ch.getTargetedString());
}
}
messageForLog = localizer.getMessage("lblLogPlayerActionObjectWitchTarget", player, action, object, sb.toString());
} else {
messageForLog = localizer.getMessage("lblLogPlayerActionObject", player, action, object);
}
sb.append(".");
return new GameLogEntry(GameLogEntryType.STACK_ADD, sb.toString());
return new GameLogEntry(GameLogEntryType.STACK_ADD, messageForLog);
}
@Override
@@ -123,7 +127,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
return null;
}
String modeChoiceOutcome = ev.player.toString() + " has chosen " + ev.mode + " for " + ev.cardName + ".";
String modeChoiceOutcome = Localizer.getInstance().getMessage("lblLogPlayerChosenModeForCard", ev.player.toString(), ev.mode, ev.cardName);
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, modeChoiceOutcome);
}
@@ -157,9 +161,9 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
final String message;
if (newLobbyPlayer == null) {
message = p.getName() + " has restored control over themself";
message = Localizer.getInstance().getMessage("lblLogPlayerHasRestoredControlThemself", p.getName());
} else {
message = p.getName() + "is controlled by" + newLobbyPlayer.getName();
message = Localizer.getInstance().getMessage("lblLogPlayerControlledTargetPlayer", p.getName(), newLobbyPlayer.getName());
}
return new GameLogEntry(GameLogEntryType.PLAYER_CONROL, message);
}
@@ -172,17 +176,18 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
@Override
public GameLogEntry visit(GameEventCardDamaged event) {
final Localizer localizer = Localizer.getInstance();
String additionalLog = "";
if (event.type == DamageType.Deathtouch) {
additionalLog = " (Deathtouch)";
additionalLog = localizer.getMessage("lblDeathtouch");
}
if (event.type == DamageType.M1M1Counters) {
additionalLog = " (As -1/-1 Counters)";
additionalLog = localizer.getMessage("lblAsM1M1Counters");
}
if (event.type == DamageType.LoyaltyLoss) {
additionalLog = " (Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
additionalLog = localizer.getMessage("lblRemovingNLoyaltyCounter", String.valueOf(event.amount));
}
String message = event.source.toString() + " deals " + event.amount + " damage" + additionalLog + " to " + event.card.toString() + ".";
String message = localizer.getMessage("lblSourceDealsNDamageToDest", event.source.toString(), String.valueOf(event.amount), additionalLog, event.card.toString());
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@@ -191,33 +196,36 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
*/
@Override
public GameLogEntry visit(GameEventLandPlayed ev) {
String message = ev.player.toString() + " played " + ev.land.toString();
String message = Localizer.getInstance().getMessage("lblLogPlayerPlayedLand", ev.player.toString(), ev.land.toString());
return new GameLogEntry(GameLogEntryType.LAND, message);
}
@Override
public GameLogEntry visit(GameEventTurnBegan event) {
String message = "Turn " + event.turnNumber + " (" + event.turnOwner.toString() + ")";
String message = Localizer.getInstance().getMessage("lblLogTurnNOwnerByPlayer", String.valueOf(event.turnNumber), event.turnOwner.toString());;
return new GameLogEntry(GameLogEntryType.TURN, message);
}
@Override
public GameLogEntry visit(GameEventPlayerDamaged ev) {
String extra = ev.infect ? " (as poison counters)" : "";
String damageType = ev.combat ? "combat" : "non-combat";
String message = ev.source.toString() + " deals " + ev.amount + " " + damageType + " damage to " + ev.target.toString() + extra + ".";
String extra = ev.infect ? Localizer.getInstance().getMessage("lblLogAsPoisonCounters") : "";
String damageType = ev.combat ? Localizer.getInstance().getMessage("lblCombat") : Localizer.getInstance().getMessage("lblNonCombat");
String message = Localizer.getInstance().getMessage("lblLogSourceDealsNDamageOfTypeToDest", ev.source.toString(),
String.valueOf(ev.amount), damageType, ev.target.toString(), extra);
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override
public GameLogEntry visit(GameEventPlayerPoisoned ev) {
String message = ev.receiver.toString() + " receives " + Lang.nounWithAmount(ev.amount, "posion counter") + " from " + ev.source.toString();
String message = Localizer.getInstance().getMessage("lblLogPlayerReceivesNPosionCounterFrom",
ev.receiver.toString(), String.valueOf(ev.amount), ev.source.toString());
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override
public GameLogEntry visit(final GameEventAttackersDeclared ev) {
final StringBuilder sb = new StringBuilder();
final Localizer localizer = Localizer.getInstance();
// Loop through Defenders
// Append Defending Player/Planeswalker
@@ -229,11 +237,10 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
continue;
}
if (sb.length() > 0) sb.append("\n");
sb.append(ev.player).append(" assigned ").append(Lang.joinHomogenous(attackers));
sb.append(" to attack ").append(k).append(".");
sb.append(localizer.getMessage("lblLogPlayerAssignedAttackerToAttackTarget", ev.player, Lang.joinHomogenous(attackers), k));
}
if (sb.length() == 0) {
sb.append(ev.player).append(" didn't attack this turn.");
sb.append(localizer.getMessage("lblPlayerDidntAttackThisTurn").replace("%s", ev.player.toString()));
}
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
}
@@ -265,13 +272,11 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
blockers = att.getValue();
if (blockers.isEmpty()) {
sb.append(controllerName).append(" didn't block ");
sb.append(Localizer.getInstance().getMessage("lblLogPlayerDidntBlockAttacker", controllerName, att.getKey()));
}
else {
sb.append(controllerName).append(" assigned ").append(Lang.joinHomogenous(blockers)).append(" to block ");
sb.append(Localizer.getInstance().getMessage("lblLogPlayerAssignedBlockerToBlockAttacker", controllerName, Lang.joinHomogenous(blockers), att.getKey()));
}
sb.append(att.getKey()).append(".");
firstAttacker = false;
}
}
@@ -281,7 +286,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
@Override
public GameLogEntry visit(GameEventMulligan ev) {
String message = ev.player.toString() + " has mulliganed down to " + ev.player.getZone(ZoneType.Hand).size() + " cards.";
String message = Localizer.getInstance().getMessage("lblPlayerHasMulliganedDownToNCards").replace("%d", String.valueOf(ev.player.getZone(ZoneType.Hand).size())).replace("%s", ev.player.toString());
return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
}

View File

@@ -0,0 +1,44 @@
/*
* 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.game;
import com.google.common.base.Predicate;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
/**
* <p>
* Predicate<GameObject> interface.
* </p>
*
* @author Forge
*/
public final class GameObjectPredicates {
public static final Predicate<GameObject> restriction(final String[] restrictions, final Player sourceController, final Card source, final SpellAbility spellAbility) {
return new Predicate<GameObject>() {
@Override
public boolean apply(final GameObject c) {
return (c != null) && c.isValid(restrictions, sourceController, source, spellAbility);
}
};
}
}

View File

@@ -1,5 +1,9 @@
package forge.game;
import java.util.EnumSet;
import java.util.Set;
import com.google.common.base.Enums;
import com.google.common.base.Function;
import forge.StaticData;
import forge.deck.CardPool;
@@ -144,4 +148,19 @@ public enum GameType {
public String getDescription() {
return description;
}
public static GameType smartValueOf(String name) {
return Enums.getIfPresent(GameType.class, name).orNull();
}
public static Set<GameType> listValueOf(final String values) {
final Set<GameType> result = EnumSet.noneOf(GameType.class);
for (final String s : values.split(",")) {
GameType g = GameType.smartValueOf(s);
if (g != null) {
result.add(g);
}
}
return result;
}
}

View File

@@ -25,7 +25,6 @@ public enum GlobalRuleChange {
alwaysWither ("All damage is dealt as though it's source had wither."),
attackerChoosesBlockers ("The attacking player chooses how each creature blocks each turn."),
manapoolsDontEmpty ("Mana pools don't empty as steps and phases end."),
noCycling ("Players can't cycle cards."),
noCreatureETBTriggers ("Creatures entering the battlefield don't cause abilities to trigger."),
noCreatureDyingTriggers ("Creatures dying don't cause abilities to trigger."),
noLegendRule ("The legend rule doesn't apply."),
@@ -35,8 +34,7 @@ public enum GlobalRuleChange {
onlyOneBlockerPerOpponent ("Each opponent can't block with more than one creature."),
onlyTwoBlockers ("No more than two creatures can block each combat."),
toughnessAssignsDamage ("Each creature assigns combat damage equal to its toughness rather than its power."),
blankIsChaos("Each blank roll of the planar dice is a {CHAOS} roll."),
noLandBattlefield("Lands can't enter the battlefield.");
blankIsChaos("Each blank roll of the planar dice is a {CHAOS} roll.");
private final String ruleText;

View File

@@ -19,6 +19,7 @@ import forge.game.zone.ZoneType;
import forge.item.PaperCard;
import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import java.util.*;
import java.util.Map.Entry;
@@ -291,12 +292,13 @@ public class Match {
}
}
final Localizer localizer = Localizer.getInstance();
if (!rAICards.isEmpty() && !rules.getGameType().isCardPoolLimited()) {
game.getAction().revealAnte("AI can't play these cards well", rAICards);
game.getAction().revealAnte(localizer.getMessage("lblAICantPlayCards"), rAICards);
}
if (!removedAnteCards.isEmpty()) {
game.getAction().revealAnte("These ante cards were removed", removedAnteCards);
game.getAction().revealAnte(localizer.getMessage("lblAnteCardsRemoved"), removedAnteCards);
}
}

View File

@@ -6,12 +6,12 @@
* 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/>.
*/
@@ -37,7 +37,7 @@ import com.google.common.collect.Maps;
* <p>
* StaticEffect class.
* </p>
*
*
* @author Forge
* @version $Id$
*/
@@ -72,7 +72,7 @@ public class StaticEffect {
/**
* setTimestamp TODO Write javadoc for this method.
*
*
* @param t
* a long
*/
@@ -82,7 +82,7 @@ public class StaticEffect {
/**
* getTimestamp. TODO Write javadoc for this method.
*
*
* @return a long
*/
public final long getTimestamp() {
@@ -93,7 +93,7 @@ public class StaticEffect {
* <p>
* Getter for the field <code>source</code>.
* </p>
*
*
* @return a {@link forge.game.card.Card} object.
*/
public final Card getSource() {
@@ -104,7 +104,7 @@ public class StaticEffect {
* <p>
* Getter for the field <code>affectedCards</code>.
* </p>
*
*
* @return a {@link forge.CardList} object.
*/
public final CardCollectionView getAffectedCards() {
@@ -115,7 +115,7 @@ public class StaticEffect {
* <p>
* Setter for the field <code>affectedCards</code>.
* </p>
*
*
* @param list
* a {@link forge.CardList} object.
*/
@@ -125,7 +125,7 @@ public class StaticEffect {
/**
* Gets the affected players.
*
*
* @return the affected players
*/
public final List<Player> getAffectedPlayers() {
@@ -134,7 +134,7 @@ public class StaticEffect {
/**
* Sets the affected players.
*
*
* @param list
* the new affected players
*/
@@ -144,7 +144,7 @@ public class StaticEffect {
/**
* setParams. TODO Write javadoc for this method.
*
*
* @param params
* a HashMap
*/
@@ -154,7 +154,7 @@ public class StaticEffect {
/**
* Gets the params.
*
*
* @return the params
*/
public final Map<String, String> getParams() {
@@ -171,13 +171,12 @@ public class StaticEffect {
/**
* Undo everything that was changed by this effect.
*
*
* @return a {@link CardCollectionView} of all affected cards.
*/
final CardCollectionView remove() {
final CardCollectionView affectedCards = getAffectedCards();
final List<Player> affectedPlayers = getAffectedPlayers();
//final Map<String, String> params = getParams();
String changeColorWordsTo = null;
@@ -242,6 +241,13 @@ public class StaticEffect {
p.setUnlimitedHandSize(false);
p.setMaxHandSize(p.getStartingHandSize());
p.removeChangedKeywords(getTimestamp());
p.removeMaxLandPlays(getTimestamp());
p.removeMaxLandPlaysInfinite(getTimestamp());
p.removeControlVote(getTimestamp());
p.removeAdditionalVote(getTimestamp());
p.removeAdditionalOptionalVote(getTimestamp());
}
// modify the affected card
@@ -273,6 +279,10 @@ public class StaticEffect {
affectedCard.removeChangedCardKeywords(getTimestamp());
}
if (hasParam("CantHaveKeyword")) {
affectedCard.removeCantHaveKeyword(getTimestamp());
}
if (addHiddenKeywords != null) {
for (final String k : addHiddenKeywords) {
affectedCard.removeHiddenExtrinsicKeyword(k);

View File

@@ -54,7 +54,8 @@ public final class AbilityFactory {
"Execute", // DelayedTrigger
"FallbackAbility", // Complex Unless costs which can be unpayable
"ChooseSubAbility", // Can choose a player via ChoosePlayer
"CantChooseSubAbility" // Can't choose a player via ChoosePlayer
"CantChooseSubAbility", // Can't choose a player via ChoosePlayer
"AnimateSubAbility" // For ChangeZone Effects to Animate before ETB
);
public enum AbilityRecordType {
@@ -382,21 +383,10 @@ public final class AbilityFactory {
* @param mapParams
*/
private static final void initializeParams(final SpellAbility sa, Map<String, String> mapParams) {
if (mapParams.containsKey("Flashback")) {
sa.setFlashBackAbility(true);
}
if (mapParams.containsKey("NonBasicSpell")) {
sa.setBasicSpell(false);
}
if (mapParams.containsKey("Dash")) {
sa.setDash(true);
}
if (mapParams.containsKey("Outlast")) {
sa.setOutlast(true);
}
}
/**
@@ -449,7 +439,7 @@ public final class AbilityFactory {
}
public static final Map<String, String> getMapParams(final String abString) {
return FileSection.parseToMap(abString, "$", "|");
return FileSection.parseToMap(abString, FileSection.DOLLAR_SIGN_KV_SEPARATOR);
}
public static final void adjustChangeZoneTarget(final Map<String, String> params, final SpellAbility sa) {

View File

@@ -260,6 +260,8 @@ public class AbilityUtils {
list = sa.getRootAbility().getPaidList("SacrificedCards");
} else if (defined.startsWith("Sacrificed")) {
list = sa.getRootAbility().getPaidList("Sacrificed");
} else if (defined.startsWith("Revealed")) {
list = sa.getRootAbility().getPaidList("Revealed");
} else if (defined.startsWith("DiscardedCards")) {
list = sa.getRootAbility().getPaidList("DiscardedCards");
} else if (defined.startsWith("Discarded")) {
@@ -1279,6 +1281,8 @@ public class AbilityUtils {
if (o instanceof Card) {
final Card rem = (Card) o;
sas.addAll(game.getCardState(rem).getSpellAbilities());
} else if (o instanceof SpellAbility) {
sas.add((SpellAbility) o);
}
}
}
@@ -1314,9 +1318,16 @@ public class AbilityUtils {
return;
}
Player pl = sa.getActivatingPlayer();
final Game game = pl.getGame();
if (sa.isTrigger() && sa.getParent() == null && sa.getPayCosts() != null) {
// when trigger cost are paid before the effect does resolve, need to clean the trigger
game.getTriggerHandler().resetActiveTriggers();
}
// do blessing there before condition checks
if (sa.isSpell() && sa.isBlessing() && !sa.getHostCard().isPermanent()) {
Player pl = sa.getActivatingPlayer();
if (pl != null && pl.getZone(ZoneType.Battlefield).size() >= 10) {
pl.setBlessing(true);
}
@@ -1331,7 +1342,7 @@ public class AbilityUtils {
return;
}
AbilityUtils.resolveApiAbility(sa, sa.getActivatingPlayer().getGame());
AbilityUtils.resolveApiAbility(sa, game);
}
private static void resolveSubAbilities(final SpellAbility sa, final Game game) {
@@ -1617,7 +1628,19 @@ public class AbilityUtils {
}
return count;
}
// Count$AttachedTo <DefinedCards related to spellability> <restriction>
if (sq[0].startsWith("AttachedTo")) {
final String[] k = l[0].split(" ");
int sum = 0;
for (Card card : AbilityUtils.getDefinedCards(sa.getHostCard(), k[1], sa)) {
// Hateful Eidolon: the script uses LKI so that the attached cards have to be defined
// This card needs the spellability ("Auras You control", you refers to the activating player)
// CardFactoryUtils.xCount doesn't have the sa parameter, SVar:X:TriggeredCard$Valid <restriction> cannot handle this
CardCollection list = CardLists.getValidCards(card.getAttachedCards(), k[2].split(","), sa.getActivatingPlayer(), c, sa);
sum += list.size();
}
return sum;
}
// Count$Adamant.<Color>.<True>.<False>
if (sq[0].startsWith("Adamant")) {
final String payingMana = StringUtils.join(sa.getRootAbility().getPayingMana());
@@ -1708,7 +1731,7 @@ public class AbilityUtils {
if (res.checkTimingRestrictions(tgtCard, newSA)
// still need to check the other restrictions like Aftermath
&& res.checkOtherRestrictions(tgtCard, newSA, controller)
&& newSA.checkOtherRestrictions()) {
&& newSA.checkOtherRestrictions(tgtCard)) {
sas.add(newSA);
}
}
@@ -1836,6 +1859,11 @@ public class AbilityUtils {
} else if (def.endsWith("Owner")) {
players.add(c.getOwner());
}
} else if (o instanceof SpellAbility) {
final SpellAbility c = (SpellAbility) o;
if (def.endsWith("Controller")) {
players.add(c.getHostCard().getController());
}
}
}
}

View File

@@ -337,6 +337,23 @@ public abstract class SpellAbilityEffect {
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
}
protected static void addForgetCounterTrigger(final Card card, final String counterType) {
String trig = "Mode$ CounterRemoved | TriggerZones$ Command | ValidCard$ Card.IsRemembered | CounterType$ " + counterType + " | NewCounterAmount$ 0 | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
}
protected static void addLeaveBattlefieldReplacement(final Card card, final SpellAbility sa, final String zone) {
final Card host = sa.getHostCard();

View File

@@ -8,6 +8,8 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.Map;
@@ -23,7 +25,7 @@ public class AbandonEffect extends SpellAbilityEffect {
Player controller = source.getController();
boolean isOptional = sa.hasParam("Optional");
if (isOptional && !controller.getController().confirmAction(sa, null, "Would you like to abandon the scheme " + source + "?")) {
if (isOptional && !controller.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblWouldYouLikeAbandonSource", CardTranslation.getTranslatedName(source.getName())))) {
return;
}

View File

@@ -9,6 +9,7 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
import forge.util.Lang;
import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils;
@@ -51,7 +52,7 @@ public class ActivateAbilityEffect extends SpellAbilityEffect {
continue;
}
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(
possibleAb, sa, "Choose a mana ability:", ImmutableMap.of());
possibleAb, sa, Localizer.getInstance().getMessage("lblChooseManaAbility"), ImmutableMap.of());
p.getController().playChosenSpellAbility(manaAb);
}
}

View File

@@ -8,6 +8,7 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.util.Localizer;
import java.util.List;
@@ -61,7 +62,7 @@ public class AddTurnEffect extends SpellAbilityEffect {
extra.setCantSetSchemesInMotion(true);
}
if (sa.hasParam("ShowMessage")) {
p.getGame().getAction().nofityOfValue(sa, p, p + " takes an extra turn.", null);
p.getGame().getAction().nofityOfValue(sa, p, Localizer.getInstance().getMessage("lblPlayerTakesExtraTurn", p.toString()), null);
}
}
}

View File

@@ -8,6 +8,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardZoneTable;
import forge.game.card.CounterType;
import forge.game.card.token.TokenInfo;
import forge.game.event.GameEventTokenCreated;
@@ -16,6 +17,7 @@ import forge.game.player.PlayerController;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.Localizer;
public class AmassEffect extends SpellAbilityEffect {
@@ -44,6 +46,17 @@ public class AmassEffect extends SpellAbilityEffect {
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
final boolean remember = sa.hasParam("RememberAmass");
boolean useZoneTable = true;
CardZoneTable triggerList = sa.getChangeZoneTable();
if (triggerList == null) {
triggerList = new CardZoneTable();
useZoneTable = false;
}
if (sa.hasParam("ChangeZoneTable")) {
sa.setChangeZoneTable(triggerList);
useZoneTable = true;
}
// create army token if needed
if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) {
final String tokenScript = "b_0_0_zombie_army";
@@ -54,14 +67,21 @@ public class AmassEffect extends SpellAbilityEffect {
// Should this be catching the Card that's returned?
Card c = game.getAction().moveToPlay(tok, sa);
if (c.getZone() != null) {
triggerList.put(ZoneType.None, c.getZone().getZoneType(), c);
}
c.updateStateForView();
}
if (!useZoneTable) {
triggerList.triggerChangesZoneAll(game);
triggerList.clear();
}
game.fireEvent(new GameEventTokenCreated());
}
CardCollectionView tgtCards = CardLists.getType(activator.getCardsIn(ZoneType.Battlefield), "Army");
tgtCards = pc.chooseCardsForEffect(tgtCards, sa, "Choose an army to put counters on", 1, 1, false);
tgtCards = pc.chooseCardsForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), 1, 1, false);
GameEntityCounterTable table = new GameEntityCounterTable();
for(final Card tgtCard : tgtCards) {

View File

@@ -20,7 +20,7 @@ package forge.game.ability.effects;
import forge.card.CardType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.keyword.Keyword;
import forge.game.spellability.SpellAbility;
import java.util.List;
@@ -101,6 +101,10 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
c.addChangedCardKeywords(keywords, removeKeywords,
sa.hasParam("RemoveAllAbilities"), sa.hasParam("RemoveIntrinsicAbilities"), timestamp);
if (sa.hasParam("CantHaveKeyword")) {
c.addCantHaveKeyword(timestamp, Keyword.setValueOf(sa.getParam("CantHaveKeyword")));
}
for (final String k : hiddenKeywords) {
c.addHiddenExtrinsicKeyword(k);
}
@@ -138,6 +142,8 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
c.removeChangedCardTraits(timestamp);
c.removeCantHaveKeyword(timestamp);
for (final String k : hiddenKeywords) {
c.removeHiddenExtrinsicKeyword(k);
}

View File

@@ -16,6 +16,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
public class AssignGroupEffect extends SpellAbilityEffect {
@@ -49,7 +50,7 @@ public class AssignGroupEffect extends SpellAbilityEffect {
Multimap<SpellAbility, GameObject> result = ArrayListMultimap.create();
for (GameObject g : defined) {
final String title = "Choose ability for " + g.toString();
final String title = Localizer.getInstance().getMessage("lblChooseAbilityForObject", g.toString());
Map<String, Object> params = Maps.newHashMap();
params.put("Affected", g);

View File

@@ -16,6 +16,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.List;
@@ -44,6 +46,14 @@ public class AttachEffect extends SpellAbilityEffect {
} else {
attachTo = targets.get(0);
}
String attachToName = null;
if (attachTo instanceof Card) {
attachToName = CardTranslation.getTranslatedName(((Card)attachTo).getName());
}
else {
attachToName = attachTo.toString();
}
final Player p = sa.getActivatingPlayer();
@@ -52,7 +62,9 @@ public class AttachEffect extends SpellAbilityEffect {
if (sa.hasParam("ChooseAnObject")) {
Card c = p.getController().chooseSingleEntityForEffect(attachments, sa, sa.getParam("ChooseAnObject"));
attachments.clear();
attachments.add(c);
if (c != null) {
attachments.add(c);
}
}
} else {
attachments = new CardCollection(source);
@@ -60,7 +72,7 @@ public class AttachEffect extends SpellAbilityEffect {
// If Cast Targets will be checked on the Stack
for (final Card attachment : attachments) {
String message = "Do you want to attach " + attachment + " to " + attachTo + "?";
String message = Localizer.getInstance().getMessage("lblDoYouWantAttachSourceToTarget", CardTranslation.getTranslatedName(attachment.getName()), attachToName);
if ( sa.hasParam("Optional") && !p.getController().confirmAction(sa, null, message) )
continue;
handleAttachment(attachment, attachTo, sa);
@@ -173,7 +185,7 @@ public class AttachEffect extends SpellAbilityEffect {
players.add(player);
}
}
final Player pa = p.getController().chooseSingleEntityForEffect(players, aura, source + " - Select a player to attach to.");
final Player pa = p.getController().chooseSingleEntityForEffect(players, aura, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", CardTranslation.getTranslatedName(source.getName())));
if (pa != null) {
handleAura(source, pa);
return true;
@@ -186,7 +198,7 @@ public class AttachEffect extends SpellAbilityEffect {
return false;
}
final Card o = p.getController().chooseSingleEntityForEffect(list, aura, source + " - Select a card to attach to.");
final Card o = p.getController().chooseSingleEntityForEffect(list, aura, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(source.getName())));
if (o != null) {
handleAura(source, o);
//source.enchantEntity((Card) o);

View File

@@ -11,6 +11,7 @@ import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.util.collect.FCollection;
import forge.util.Localizer;
public class BidLifeEffect extends SpellAbilityEffect {
@Override
@@ -27,7 +28,7 @@ public class BidLifeEffect extends SpellAbilityEffect {
if (sa.hasParam("StartBidding")) {
String start = sa.getParam("StartBidding");
if ("Any".equals(start)) {
startBidding = activator.getController().announceRequirements(sa, "Choose a starting bid", true);
startBidding = activator.getController().announceRequirements(sa, Localizer.getInstance().getMessage("lblChooseStartingBid"), true);
} else {
startBidding = AbilityUtils.calculateAmount(host, start, sa);
}
@@ -54,12 +55,12 @@ public class BidLifeEffect extends SpellAbilityEffect {
willBid = false;
for (final Player p : bidPlayers) {
final boolean result = p.getController().confirmBidAction(sa, PlayerActionConfirmMode.BidLife,
"Do you want to top bid? Current Bid =" + bid, bid, winner);
Localizer.getInstance().getMessage("lblDoYouWantTopBid") + bid, bid, winner);
willBid |= result;
if (result) { // a different choose number
bid += p.getController().chooseNumber(sa, "Bid life:", 1, 9);
bid += p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblBidLife") + ":", 1, 9);
winner = p;
host.getGame().getAction().nofityOfValue(sa, p, "topped bid with " + bid + " life", p);
host.getGame().getAction().nofityOfValue(sa, p, Localizer.getInstance().getMessage("lblTopBidWithValueLife", String.valueOf(bid)), p);
}
}
}

View File

@@ -6,6 +6,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import java.util.List;
@@ -30,7 +31,7 @@ public class BondEffect extends SpellAbilityEffect {
Card partner = cards.getFirst();
// skip choice if only one card on list
if (cards.size() > 1) {
partner = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(cards, sa, "Select a card to pair with");
partner = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(cards, sa, Localizer.getInstance().getMessage("lblSelectACardPair"));
}
// pair choices together

View File

@@ -13,6 +13,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import forge.util.CardTranslation;
import org.apache.commons.lang3.StringUtils;
@@ -44,7 +46,7 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
final FCollectionView<GameEntity> defs = combat.getDefenders();
final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa,
"Choose which defender to attack with " + c, false);
Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false);
if (originalDefender != null && !originalDefender.equals(defender)) {
AttackingBand ab = combat.getBandOfAttacker(c);
if (ab != null) {

View File

@@ -11,6 +11,7 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices;
import forge.game.zone.MagicStack;
import forge.util.Aggregates;
import forge.util.Localizer;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
@@ -50,8 +51,8 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
// Redirect rules read 'you MAY choose new targets' ... okay!
// TODO: Don't even ask to change targets, if the SA and subs don't actually have targets
boolean isOptional = sa.hasParam("Optional");
if (isOptional && !chooser.getController().confirmAction(sa, null, "Do you want to change targets of " + tgtSA.getHostCard() + "?")) {
continue;
if (isOptional && !chooser.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantChangeAbilityTargets", tgtSA.getHostCard().toString()))) {
continue;
}
if (changesOneTarget) {
// 1. choose a target of target spell

View File

@@ -14,6 +14,7 @@ import forge.game.card.Card;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.spellability.SpellAbility;
import forge.util.TextUtil;
import forge.util.Localizer;
public class ChangeTextEffect extends SpellAbilityEffect {
@@ -33,7 +34,7 @@ public class ChangeTextEffect extends SpellAbilityEffect {
final String[] changedColorWordsArray = sa.getParam("ChangeColorWord").split(" ");
if (changedColorWordsArray[0].equals("Choose")) {
originalColor = sa.getActivatingPlayer().getController().chooseColor(
"Choose a color word to replace", sa, ColorSet.ALL_COLORS);
Localizer.getInstance().getMessage("lblChooseColorReplace"), sa, ColorSet.ALL_COLORS);
changedColorWordOriginal = TextUtil.capitalize(MagicColor.toLongString(originalColor));
} else {
changedColorWordOriginal = changedColorWordsArray[0];
@@ -48,7 +49,7 @@ public class ChangeTextEffect extends SpellAbilityEffect {
possibleNewColors = ColorSet.fromMask(originalColor).inverse();
}
final byte newColor = sa.getActivatingPlayer().getController().chooseColor(
"Choose a new color word", sa, possibleNewColors);
Localizer.getInstance().getMessage("lblChooseNewColor"), sa, possibleNewColors);
changedColorWordNew = TextUtil.capitalize(MagicColor.toLongString(newColor));
} else {
changedColorWordNew = changedColorWordsArray[1];

View File

@@ -1,6 +1,8 @@
package forge.game.ability.effects;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
@@ -14,6 +16,7 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil;
import forge.util.Localizer;
import java.util.List;
import java.util.Map;
@@ -91,26 +94,16 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
sa.getActivatingPlayer().getController().reveal(handCards, ZoneType.Hand, handCards.get(0).getOwner());
}
}
cards = (CardCollection)AbilityUtils.filterListByType(cards, sa.getParam("ChangeType"), sa);
if (sa.hasParam("Optional")) {
final String targets = Lang.joinHomogenous(cards);
final String message;
if (sa.hasParam("OptionQuestion")) {
message = TextUtil.fastReplace(sa.getParam("OptionQuestion"), "TARGETS", targets);
message = TextUtil.fastReplace(sa.getParam("OptionQuestion"), "TARGETS", targets);
} else {
final StringBuilder sb = new StringBuilder();
sb.append("Move ");
sb.append(targets);
sb.append(" from ");
sb.append(Lang.joinHomogenous(origin));
sb.append(" to ");
sb.append(destination);
sb.append("?");
message = sb.toString();
message = Localizer.getInstance().getMessage("lblMoveTargetFromOriginToDestination", targets, Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME), destination.getTranslatedName());
}
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null, message)) {
@@ -159,7 +152,19 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
}
}
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
if (destination == ZoneType.Battlefield) {
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
// need LKI before Animate does apply
moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(c));
source.addRemembered(c);
AbilityUtils.resolve(sa.getAdditionalAbility("AnimateSubAbility"));
source.removeRemembered(c);
}
// Auras without Candidates stay in their current location
if (c.isAura()) {
final SpellAbility saAura = c.getFirstAttachSpell();
@@ -174,9 +179,9 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
Card movedCard = null;
if (sa.hasParam("GainControl")) {
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
movedCard = game.getAction().moveToPlay(c, sa.getActivatingPlayer(), sa);
movedCard = game.getAction().moveToPlay(c, sa.getActivatingPlayer(), sa, moveParams);
} else {
movedCard = game.getAction().moveTo(destination, c, libraryPos, sa);
movedCard = game.getAction().moveTo(destination, c, libraryPos, sa, moveParams);
if (destination == ZoneType.Exile && !c.isToken()) {
Card host = sa.getOriginalHost();
if (host == null) {
@@ -214,7 +219,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
if (destination == ZoneType.Battlefield) {
movedCard.setTimestamp(ts);
}
if (!movedCard.getZone().equals(originZone)) {
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), movedCard);
}

View File

@@ -4,6 +4,8 @@ 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 com.google.common.collect.Maps;
import forge.GameCommand;
import forge.card.CardStateName;
import forge.game.Game;
@@ -32,6 +34,8 @@ import forge.util.MessageUtil;
import forge.util.TextUtil;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.List;
import java.util.Map;
@@ -439,7 +443,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
hostCard.addRemembered(CardUtil.getLKICopy(tgtC));
}
final String prompt = TextUtil.concatWithSpace("Do you want to move", tgtC.toString(), "from", origin.toString(), "to", TextUtil.addSuffix(destination.toString(),"?"));
final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantMoveTargetFromOriToDest", CardTranslation.getTranslatedName(tgtC.getName()), Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME), destination.getTranslatedName()));
if (optional && !player.getController().confirmAction(sa, null, prompt) )
continue;
@@ -503,7 +507,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("AttachedTo"), tgtC.getController(), tgtC);
}
if (!list.isEmpty()) {
Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, tgtC + " - Select a card to attach to.");
Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", tgtC.toString()));
tgtC.attachToEntity(attachedTo);
} else { // When it should enter the battlefield attached to an illegal permanent it fails
continue;
@@ -513,7 +517,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("AttachedToPlayer")) {
FCollectionView<Player> list = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("AttachedToPlayer"), sa);
if (!list.isEmpty()) {
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, tgtC + " - Select a player to attach to.");
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", tgtC.toString()));
tgtC.attachToEntity(attachedTo);
}
else { // When it should enter the battlefield attached to an illegal player it fails
@@ -521,6 +525,17 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
// need LKI before Animate does apply
moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(tgtC));
hostCard.addRemembered(tgtC);
AbilityUtils.resolve(sa.getAdditionalAbility("AnimateSubAbility"));
hostCard.removeRemembered(tgtC);
}
// Auras without Candidates stay in their current
// location
if (tgtC.isAura()) {
@@ -528,13 +543,16 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (saAura != null) {
saAura.setActivatingPlayer(sa.getActivatingPlayer());
if (!saAura.getTargetRestrictions().hasCandidates(saAura, false)) {
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
tgtC.removeChangedState();
}
continue;
}
}
}
movedCard = game.getAction().moveTo(
tgtC.getController().getZone(destination), tgtC, sa);
tgtC.getController().getZone(destination), tgtC, sa, moveParams);
if (sa.hasParam("Unearth")) {
movedCard.setUnearthed(true);
movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, false,
@@ -560,7 +578,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
} else {
defender = player.getController().chooseSingleEntityForEffect(e, sa, "Declare a defender for " + movedCard );
defender = player.getController().chooseSingleEntityForEffect(e, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(movedCard.getName())));
}
if (defender != null) {
combat.addAttacker(movedCard, defender);
@@ -727,7 +745,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final StringBuilder sb = new StringBuilder();
sb.append(sa.getParam("AlternativeMessage")).append(" ");
sb.append(altFetchList.size()).append(" cards match your searching type in Alternate Zones.");
sb.append(altFetchList.size()).append(" " + Localizer.getInstance().getMessage("lblCardMatchSearchingTypeInAlternateZones"));
if (!decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneFromAltSource, sb.toString())) {
origin = alt;
@@ -749,7 +767,14 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final boolean optional = sa.hasParam("Optional");
if (optional) {
String message = MessageUtil.formatMessage(defined ? "Put that card from {player's} " + Lang.joinHomogenous(origin).toLowerCase() + " to " + destination.name().toLowerCase() : "Search {player's} " + Lang.joinHomogenous(origin).toLowerCase() + "?", decider, player);
String prompt;
if (defined) {
prompt = Localizer.getInstance().getMessage("lblPutThatCardFromPlayerOriginToDestination", "{player's}", Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME).toLowerCase(), destination.getTranslatedName().toLowerCase());
}
else {
prompt = Localizer.getInstance().getMessage("lblSearchPlayerZoneConfirm", "{player's}", Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME).toLowerCase());
}
String message = MessageUtil.formatMessage(prompt , decider, player);
if (!decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneGeneral, message)) {
return;
}
@@ -801,10 +826,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
CardCollectionView shown = !decider.hasKeyword("LimitSearchLibrary") ? player.getCardsIn(ZoneType.Library) : player.getCardsIn(ZoneType.Library, fetchNum);
// Look at whole library before moving onto choosing a card
delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(player), source.getName() + " - Looking at cards in ");
delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(player), CardTranslation.getTranslatedName(source.getName()) + " - " + Localizer.getInstance().getMessage("lblLookingCardIn") + " ");
}
else if (origin.contains(ZoneType.Hand) && player.isOpponentOf(decider)) {
delayedReveal = new DelayedReveal(player.getCardsIn(ZoneType.Hand), ZoneType.Hand, PlayerView.get(player), source.getName() + " - Looking at cards in ");
delayedReveal = new DelayedReveal(player.getCardsIn(ZoneType.Hand), ZoneType.Hand, PlayerView.get(player), CardTranslation.getTranslatedName(source.getName()) + " - " + Localizer.getInstance().getMessage("lblLookingCardIn") + " ");
}
}
@@ -821,7 +846,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
continue;
}
SpellAbility tgtSA = decider.getController().getAbilityToPlay(tgtCard, sas);
if (!decider.getController().confirmAction(tgtSA, null, "Do you want to play " + tgtCard + "?")) {
if (!decider.getController().confirmAction(tgtSA, null, Localizer.getInstance().getMessage("lblDoYouWantPlayCard", CardTranslation.getTranslatedName(tgtCard.getName())))) {
continue;
}
// if played, that card cannot be found
@@ -853,7 +878,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
final boolean champion = sa.hasParam("Champion");
final boolean forget = sa.hasParam("ForgetChanged");
final boolean imprint = sa.hasParam("Imprint");
String selectPrompt = sa.hasParam("SelectPrompt") ? sa.getParam("SelectPrompt") : MessageUtil.formatMessage("Select a card from {player's} " + Lang.joinHomogenous(origin).toLowerCase(), decider, player);
String selectPrompt = sa.hasParam("SelectPrompt") ? sa.getParam("SelectPrompt") : MessageUtil.formatMessage(Localizer.getInstance().getMessage("lblSelectCardFromPlayerZone", "{player's}", Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME).toLowerCase()), decider, player);
final String totalcmc = sa.getParam("WithTotalCMC");
int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa);
@@ -866,9 +891,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (! sa.hasParam("SelectPrompt")) {
// new default messaging for multi select
if (fetchList.size() > changeNum) {
selectPrompt = MessageUtil.formatMessage("Select up to " + changeNum + " cards from {player's} " + Lang.joinHomogenous(origin).toLowerCase(), decider, player);
//Select up to %changeNum cards from %players %origin
selectPrompt = MessageUtil.formatMessage(Localizer.getInstance().getMessage("lblSelectUpToNumCardFromPlayerZone", String.valueOf(changeNum), "{player's}", Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME).toLowerCase()), decider, player);
} else {
selectPrompt = MessageUtil.formatMessage("Select cards from {player's} " + Lang.joinHomogenous(origin).toLowerCase(), decider, player);
selectPrompt = MessageUtil.formatMessage(Localizer.getInstance().getMessage("lblSelectCardsFromPlayerZone", "{player's}", Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME).toLowerCase()), decider, player);
}
}
// ensure that selection is within maximum allowed changeNum
@@ -930,7 +956,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (c == null) {
final int num = Math.min(fetchList.size(), changeNum - i);
String message = "Cancel Search? Up to " + num + " more card" + (num != 1 ? "s" : "") + " can be selected.";
String message = Localizer.getInstance().getMessage("lblCancelSearchUpToSelectNumCards", String.valueOf(num));
if (fetchList.isEmpty() || decider.getController().confirmAction(sa, PlayerActionConfirmMode.ChangeZoneGeneral, message)) {
break;
@@ -973,6 +999,18 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("Tapped")) {
c.setTapped(true);
}
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
// need LKI before Animate does apply
moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(c));
source.addRemembered(c);
AbilityUtils.resolve(sa.getAdditionalAbility("AnimateSubAbility"));
source.removeRemembered(c);
}
if (sa.hasParam("GainControl")) {
Player newController = sa.getActivatingPlayer();
if (sa.hasParam("NewController")) {
@@ -1001,7 +1039,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (!list.isEmpty()) {
Card attachedTo = null;
if (list.size() > 1) {
attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, c + " - Select a card to attach to.");
attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName())));
}
else {
attachedTo = list.get(0);
@@ -1019,7 +1057,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("AttachedToPlayer")) {
FCollectionView<Player> list = AbilityUtils.getDefinedPlayers(source, sa.getParam("AttachedToPlayer"), sa);
if (!list.isEmpty()) {
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, c + " - Select a player to attach to.");
Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName())));
c.attachToEntity(attachedTo);
}
else { // When it should enter the battlefield attached to an illegal permanent it fails
@@ -1042,7 +1080,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
} else {
defender = player.getController().chooseSingleEntityForEffect(e, sa, "Declare a defender for " + c );
defender = player.getController().chooseSingleEntityForEffect(e, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())));
}
if (defender != null) {
combat.addAttacker(c, defender);
@@ -1099,7 +1137,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
c.addFaceupCommand(unanimate);
}
}
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, sa);
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, sa, moveParams);
if (sa.hasParam("Tapped")) {
movedCard.setTapped(true);
}

View File

@@ -18,6 +18,7 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils;
@@ -82,7 +83,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
for (final String type : CardType.getBasicTypes()) {
final CardCollectionView cl = CardLists.getType(land, type);
if (!cl.isEmpty()) {
final String prompt = "Choose " + Lang.nounWithAmount(1, type);
final String prompt = Localizer.getInstance().getMessage("lblChoose") + " " + Lang.nounWithAmount(1, type);
Card c = p.getController().chooseSingleEntityForEffect(cl, sa, prompt, false);
if (c != null) {
chosen.add(c);
@@ -98,10 +99,10 @@ public class ChooseCardEffect extends SpellAbilityEffect {
int chosenP = 0;
while (!creature.isEmpty()) {
Card c = p.getController().chooseSingleEntityForEffect(creature, sa,
"Select creature(s) with total power less than or equal to " + (totP - chosenP - negativeNum)
+ "\r\n(Selected:" + chosenPool + ")\r\n" + "(Total Power: " + chosenP + ")", chosenP <= totP);
Localizer.getInstance().getMessage("lblSelectCreatureWithTotalPowerLessOrEqualTo", (totP - chosenP - negativeNum))
+ "\r\n(" + Localizer.getInstance().getMessage("lblSelected") + ":" + chosenPool + ")\r\n(" + Localizer.getInstance().getMessage("lblTotalPowerNum", chosenP) + ")", chosenP <= totP);
if (c == null) {
if (p.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, "Cancel Choose?")) {
if (p.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, Localizer.getInstance().getMessage("lblCancelChooseConfirm"))) {
break;
}
} else {
@@ -118,7 +119,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
Aggregates.random(choices, validAmount, chosen);
} else {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a card ";
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, !sa.hasParam("Mandatory")));
}
}

View File

@@ -22,6 +22,7 @@ import forge.game.spellability.TargetRestrictions;
import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.ComparableOp;
import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils;
@@ -51,7 +52,9 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
final List<Player> tgtPlayers = getTargetPlayers(sa);
String valid = "Card";
String validDesc = "card";
String validDesc = null;
String message = null;
if (sa.hasParam("ValidCards")) {
valid = sa.getParam("ValidCards");
validDesc = sa.getParam("ValidDesc");
@@ -59,6 +62,17 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
boolean randomChoice = sa.hasParam("AtRandom");
boolean chooseFromDefined = sa.hasParam("ChooseFromDefinedCards");
if (!randomChoice) {
if (sa.hasParam("SelectPrompt")) {
message = sa.getParam("SelectPrompt");
} else if (null == validDesc) {
message = Localizer.getInstance().getMessage("lblChooseACardName");
} else {
message = Localizer.getInstance().getMessage("lblChooseASpecificCard", validDesc);
}
}
for (final Player p : tgtPlayers) {
if ((tgt == null) || p.canBeTargetedBy(sa)) {
String chosen = "";
@@ -99,11 +113,9 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
}
}
Collections.sort(faces);
chosen = p.getController().chooseCardName(sa, faces, "Choose a card name");
chosen = p.getController().chooseCardName(sa, faces, message);
} else {
// use CardFace because you might name a alternate name
final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card.";
// use CardFace because you might name a alternate names
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
if (sa.hasParam("ValidCards")) {
cpp = CardFacePredicates.valid(valid);
@@ -114,9 +126,12 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
host.setNamedCard(chosen);
if(!randomChoice) {
p.getGame().getAction().nofityOfValue(sa, host, p.getName() + " picked " + chosen, p);
p.getGame().getAction().nofityOfValue(sa, host, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
p.setNamedCard(chosen);
}
if (sa.hasParam("NoteFor")) {
p.addNoteForName(sa.getParam("NoteFor"), "Name:" + chosen);
}
}
}
}

View File

@@ -7,6 +7,7 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.Lang;
import forge.util.Localizer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -49,27 +50,28 @@ public class ChooseColorEffect extends SpellAbilityEffect {
List<String> chosenColors;
int cntMin = sa.hasParam("TwoColors") ? 2 : 1;
int cntMax = sa.hasParam("TwoColors") ? 2 : sa.hasParam("OrColors") ? colorChoices.size() : 1;
String prompt;
String prompt = null;
if (cntMax == 1) {
prompt = "Choose a color";
prompt = Localizer.getInstance().getMessage("lblChooseAColor");
}
else {
prompt = "Choose " + Lang.getNumeral(cntMin);
if (cntMax > cntMin) {
if (cntMax >= MagicColor.NUMBER_OR_COLORS) {
prompt += " or more";
} else {
prompt += " to " + Lang.getNumeral(cntMax);
}
if (cntMax >= MagicColor.NUMBER_OR_COLORS) {
prompt = Localizer.getInstance().getMessage("lblAtLastChooseNumColors", Lang.getNumeral(cntMin));
} else {
prompt = Localizer.getInstance().getMessage("lblChooseSpecifiedRangeColors", Lang.getNumeral(cntMin), Lang.getNumeral(cntMax));
}
}
else {
prompt = Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(cntMax));
}
prompt += " colors";
}
chosenColors = p.getController().chooseColors(prompt, sa, cntMin, cntMax, colorChoices);
if (chosenColors.isEmpty()) {
return;
}
card.setChosenColors(chosenColors);
p.getGame().getAction().nofityOfValue(sa, card, p.getName() + " picked " + Lang.joinHomogenous(chosenColors), p);
p.getGame().getAction().nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p);
}
}
}

View File

@@ -10,6 +10,7 @@ import forge.game.player.Player;
import forge.game.player.PlayerController.BinaryChoiceType;
import forge.game.spellability.SpellAbility;
import forge.util.collect.FCollection;
import forge.util.Localizer;
public class ChooseDirectionEffect extends SpellAbilityEffect {
@Override
@@ -18,11 +19,11 @@ public class ChooseDirectionEffect extends SpellAbilityEffect {
final Game game = source.getGame();
final FCollection<Player> left = new FCollection<>(game.getPlayers());
// TODO: We'd better set up turn order UI here
final String info = "Left (clockwise): " + left + "\r\nRight (anticlockwise):" + Lists.reverse(left);
final String info = Localizer.getInstance().getMessage("lblLeftClockwise") + ": " + left + "\r\n" + Localizer.getInstance().getMessage("lblRightAntiClockwise") + ":" + Lists.reverse(left);
sa.getActivatingPlayer().getController().notifyOfValue(sa, source, info);
boolean chosen = sa.getActivatingPlayer().getController().chooseBinary(sa,
"Choose a direction", BinaryChoiceType.LeftOrRight);
Localizer.getInstance().getMessage("lblChooseDirection"), BinaryChoiceType.LeftOrRight);
source.setChosenDirection(chosen ? Direction.Left : Direction.Right);
}
}

View File

@@ -9,6 +9,7 @@ import forge.game.event.GameEventCardModeChosen;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.util.MyRandom;
import forge.util.Localizer;
import java.util.List;
@@ -69,7 +70,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
int idxChosen = MyRandom.getRandom().nextInt(abilities.size());
chosenSA = abilities.get(idxChosen);
} else {
chosenSA = p.getController().chooseSingleSpellForEffect(abilities, sa, "Choose one",
chosenSA = p.getController().chooseSingleSpellForEffect(abilities, sa, Localizer.getInstance().getMessage("lblChooseOne"),
ImmutableMap.of());
}

View File

@@ -10,6 +10,7 @@ import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.MyRandom;
import forge.util.Localizer;
import java.util.List;
import java.util.Map;
@@ -57,7 +58,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
chosen = MyRandom.getRandom().nextInt(max - min) + min;
p.getGame().getAction().nofityOfValue(sa, p, Integer.toString(chosen), null);
} else {
String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : "Choose a number";
String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber");
if (anyNumber) {
Integer value = p.getController().announceRequirements(sa, title, true);
chosen = (value == null ? 0 : value);
@@ -72,7 +73,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
card.setChosenNumber(chosen);
}
if (sa.hasParam("Notify")) {
p.getGame().getAction().nofityOfValue(sa, card, p.getName() + " picked " + chosen, p);
p.getGame().getAction().nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
}
}
}
@@ -85,7 +86,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
for (Entry<Player, Integer> ev : chooseMap.entrySet()) {
int num = ev.getValue();
Player player = ev.getKey();
sb.append(player).append(" chose ").append(num);
sb.append(Localizer.getInstance().getMessage("lblPlayerChoseNum", player.getName(), String.valueOf(num)));
sb.append("\r\n");
if (num > highest) {
highestNum.clear();

View File

@@ -9,6 +9,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.Aggregates;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import java.util.List;
@@ -37,7 +38,7 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
final FCollectionView<Player> choices = sa.hasParam("Choices") ? AbilityUtils.getDefinedPlayers(
sa.getHostCard(), sa.getParam("Choices"), sa) : sa.getActivatingPlayer().getGame().getPlayersInTurnOrder();
final String choiceDesc = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a player";
final String choiceDesc = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoosePlayer");
final boolean random = sa.hasParam("Random");
for (final Player p : tgtPlayers) {

View File

@@ -12,6 +12,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils;
@@ -134,7 +135,7 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
final CardCollection chosen = new CardCollection();
if (tgt == null || p.canBeTargetedBy(sa)) {
for (int i = 0; i < validAmount; i++) {
final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a source ";
final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " ";
Card o = null;
do {
o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle);

View File

@@ -12,6 +12,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import java.util.Map;
@@ -74,7 +75,7 @@ public class ClashEffect extends SpellAbilityEffect {
*/
final Card source = sa.getHostCard();
final Player player = source.getController();
final Player opponent = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(player.getOpponents(), sa, "Choose a opponent") ;
final Player opponent = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(player.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseOpponent")) ;
final ZoneType lib = ZoneType.Library;
if (sa.hasParam("RememberClasher")) {
@@ -110,11 +111,11 @@ public class ClashEffect extends SpellAbilityEffect {
// TODO: Split cards will return two CMC values, so both players may become winners of clash
reveal.append(player).append(" reveals: ").append(pCard.getName()).append(". CMC = ").append(pCMC);
reveal.append(player).append(" " + Localizer.getInstance().getMessage("lblReveals") + ": ").append(pCard.getName()).append(". " + Localizer.getInstance().getMessage("lblCMC") + "= ").append(pCMC);
reveal.append("\r\n");
reveal.append(opponent).append(" reveals: ").append(oCard.getName()).append(". CMC = ").append(oCMC);
reveal.append(opponent).append(" " + Localizer.getInstance().getMessage("lblReveals") + ": ").append(oCard.getName()).append(". " + Localizer.getInstance().getMessage("lblCMC") + "= ").append(oCMC);
reveal.append("\r\n\r\n");
reveal.append(player).append(pCMC > oCMC ? " wins clash." : " loses clash.");
reveal.append(player).append(pCMC > oCMC ? " " + Localizer.getInstance().getMessage("lblWinsClash") + "." : " " + Localizer.getInstance().getMessage("lblLosesClash") + ".");
player.getGame().getAction().nofityOfValue(sa, source, reveal.toString(), null);
clashMoveToTopOrBottom(player, pCard, sa);

View File

@@ -9,6 +9,8 @@ import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.Arrays;
import java.util.List;
@@ -78,7 +80,7 @@ public class CloneEffect extends SpellAbilityEffect {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a card ";
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
cardToCopy = activator.getController().chooseSingleEntityForEffect(choices, sa, title, false);
} else if (sa.hasParam("Defined")) {
List<Card> cloneSources = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa);
@@ -93,7 +95,7 @@ public class CloneEffect extends SpellAbilityEffect {
}
final boolean optional = sa.hasParam("Optional");
if (optional && !host.getController().getController().confirmAction(sa, null, "Do you want to copy " + cardToCopy + "?")) {
if (optional && !host.getController().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantCopy", CardTranslation.getTranslatedName(cardToCopy.getName())))) {
return;
}

View File

@@ -7,6 +7,7 @@ import forge.game.card.CardCollectionView;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import java.util.List;
@@ -35,9 +36,9 @@ public class ControlExchangeVariantEffect extends SpellAbilityEffect {
CardCollectionView list2 = AbilityUtils.filterListByType(player2.getCardsIn(zone), type, sa);
int max = Math.min(list1.size(), list2.size());
// choose the same number of cards
CardCollectionView chosen1 = activator.getController().chooseCardsForEffect(list1, sa, "Choose cards: " + player1, 0, max, true);
CardCollectionView chosen1 = activator.getController().chooseCardsForEffect(list1, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player1, 0, max, true);
int num = chosen1.size();
CardCollectionView chosen2 = activator.getController().chooseCardsForEffect(list2, sa, "Choose cards: " + player2, num, num, true);
CardCollectionView chosen2 = activator.getController().chooseCardsForEffect(list2, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player2, num, num, true);
// check all cards can be controlled by the other player
for (final Card c : chosen1) {
if (!c.canBeControlledBy(player2)) {

View File

@@ -6,7 +6,6 @@ import java.util.List;
import com.google.common.collect.Lists;
import forge.GameCommand;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
@@ -18,15 +17,14 @@ import forge.game.combat.Combat;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.Player;
import forge.game.spellability.Ability;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import forge.util.CardTranslation;
public class ControlGainEffect extends SpellAbilityEffect {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
@@ -65,15 +63,17 @@ public class ControlGainEffect extends SpellAbilityEffect {
if (null == c || c.hasKeyword("Other players can't gain control of CARDNAME.")) {
return;
}
final Game game = host.getGame();
if (c.isInPlay()) {
c.removeTempController(tStamp);
game.getAction().controllerChangeZoneCorrection(c);
if (tapOnLose) {
c.tap();
}
} // if
host.removeGainControlTargets(c);
}
@Override
@@ -82,11 +82,9 @@ public class ControlGainEffect extends SpellAbilityEffect {
final boolean bUntap = sa.hasParam("Untap");
final boolean bTapOnLose = sa.hasParam("TapOnLose");
final boolean bNoRegen = sa.hasParam("NoRegen");
final boolean remember = sa.hasParam("RememberControlled");
final boolean forget = sa.hasParam("ForgetControlled");
final boolean attacking = sa.hasParam("Attacking");
final List<String> destroyOn = sa.hasParam("DestroyTgt") ? Arrays.asList(sa.getParam("DestroyTgt").split(",")) : null;
final List<String> keywords = sa.hasParam("AddKWs") ? Arrays.asList(sa.getParam("AddKWs").split(" & ")) : null;
final List<String> lose = sa.hasParam("LoseControl") ? Arrays.asList(sa.getParam("LoseControl").split(",")) : null;
@@ -187,18 +185,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
}
}
if (destroyOn != null) {
if (destroyOn.contains("LeavesPlay")) {
sa.getHostCard().addLeavesPlayCommand(getDestroyCommand(tgtC, source, bNoRegen));
}
if (destroyOn.contains("Untap")) {
sa.getHostCard().addUntapCommand(getDestroyCommand(tgtC, source, bNoRegen));
}
if (destroyOn.contains("LoseControl")) {
sa.getHostCard().addChangeControllerCommand(getDestroyCommand(tgtC, source, bNoRegen));
}
}
if (keywords != null) {
// Add keywords only until end of turn
final GameCommand untilKeywordEOT = new GameCommand() {
@@ -227,7 +213,7 @@ public class ControlGainEffect extends SpellAbilityEffect {
final FCollectionView<GameEntity> e = combat.getDefenders();
final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(e, sa,
"Declare a defender for " + tgtC);
Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(tgtC.getName())));
if (defender != null) {
combat.addAttacker(tgtC, defender);
@@ -239,43 +225,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
} // end foreach target
}
/**
* <p>
* getDestroyCommand.
* </p>
*
* @param i
* a int.
* @return a {@link forge.GameCommand} object.
*/
private static GameCommand getDestroyCommand(final Card c, final Card hostCard, final boolean bNoRegen) {
final GameCommand destroy = new GameCommand() {
private static final long serialVersionUID = 878543373519872418L;
@Override
public void run() {
final Game game = hostCard.getGame();
final Ability ability = new Ability(hostCard, ManaCost.ZERO) {
@Override
public void resolve() {
game.getAction().destroy(c, null, !bNoRegen, null);
}
};
final StringBuilder sb = new StringBuilder();
sb.append(hostCard).append(" - destroy ").append(c.getName()).append(".");
if (bNoRegen) {
sb.append(" It can't be regenerated.");
}
ability.setStackDescription(sb.toString());
ability.setTrigger(true);
game.getStack().addSimultaneousStackEntry(ability);
}
};
return destroy;
}
/**
* <p>
* getLoseControlCommand.

View File

@@ -27,6 +27,8 @@ import forge.util.Aggregates;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import forge.util.PredicateString.StringOp;
import forge.util.Localizer;
import forge.util.CardTranslation;
import org.apache.commons.lang3.StringUtils;
@@ -64,7 +66,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
final long timestamp = game.getNextTimestamp();
if (sa.hasParam("Optional")) {
if (!activator.getController().confirmAction(sa, null, "Copy this permanent?")) {
if (!activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblCopyPermanentConfirm"))) {
return;
}
}
@@ -145,7 +147,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
if (!choices.isEmpty()) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a card ";
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") +" ";
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false);
@@ -206,12 +208,12 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
GameEntity defender;
if ("True".equals(attacked)) {
FCollectionView<GameEntity> defs = game.getCombat().getDefenders();
defender = c.getController().getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c, false);
defender = c.getController().getController().chooseSingleEntityForEffect(defs, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false);
} else {
defender = AbilityUtils.getDefinedPlayers(host, sa.getParam("CopyAttacking"), sa).get(0);
if (sa.hasParam("ChoosePlayerOrPlaneswalker") && defender != null) {
FCollectionView<GameEntity> defs = game.getCombat().getDefendersControlledBy((Player) defender);
defender = c.getController().getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c + " {defender: "+ defender + "}", false);
defender = c.getController().getController().chooseSingleEntityForEffect(defs, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())) + " {" + Localizer.getInstance().getMessage("lblDefender") + ": " + defender + "}", false);
}
}
game.getCombat().addAttacker(copyInPlay, defender);
@@ -243,7 +245,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), copyInPlay.getController(), copyInPlay);
}
if (!list.isEmpty()) {
Card attachedTo = activator.getController().chooseSingleEntityForEffect(list, sa, copyInPlay + " - Select a card to attach to.");
Card attachedTo = activator.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", copyInPlay.toString()));
copyInPlay.attachToEntity(attachedTo);
} else {

View File

@@ -15,6 +15,8 @@ import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.ArrayList;
import java.util.Iterator;
@@ -66,7 +68,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
}
boolean isOptional = sa.hasParam("Optional");
if (isOptional && !controller.getController().confirmAction(sa, null, "Do you want to copy the spell " + card + "?")) {
if (isOptional && !controller.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoyouWantCopyTheSpell", CardTranslation.getTranslatedName(card.getName())))) {
return;
}
@@ -84,7 +86,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
final int spellCount = Integer.parseInt(sa.getParam("CopyMultipleSpells"));
for (int multi = 0; multi < spellCount && !tgtSpells.isEmpty(); multi++) {
String prompt = "Select " + Lang.getOrdinal(multi + 1) + " spell to copy to stack";
String prompt = Localizer.getInstance().getMessage("lblSelectMultiSpellCopyToStack", Lang.getOrdinal(multi + 1));
SpellAbility chosen = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, prompt,
ImmutableMap.of());
SpellAbility copiedSpell = CardFactory.copySpellAbilityAndPossiblyHost(card, chosen.getHostCard(), chosen, true);
@@ -96,7 +98,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
}
else if (sa.hasParam("CopyForEachCanTarget")) {
SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa,
"Select a spell to copy", ImmutableMap.of());
Localizer.getInstance().getMessage("lblSelectASpellCopy"), ImmutableMap.of());
chosenSA.setActivatingPlayer(controller);
// Find subability or rootability that has targets
SpellAbility targetedSA = chosenSA;
@@ -144,7 +146,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
valid.remove(originalTarget);
mayChooseNewTargets = false;
if (sa.hasParam("ChooseOnlyOne")) {
Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, "Choose one");
Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseOne"));
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
resetFirstTargetOnCopy(copy, choice, targetedSA);
copies.add(copy);
@@ -164,7 +166,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
}
else {
SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa,
"Select a spell to copy", ImmutableMap.of());
Localizer.getInstance().getMessage("lblSelectASpellCopy"), ImmutableMap.of());
chosenSA.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(

View File

@@ -12,6 +12,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.SpellPermanent;
import forge.game.trigger.TriggerType;
import forge.util.Localizer;
import java.util.Arrays;
import java.util.List;
@@ -174,7 +175,7 @@ public class CounterEffect extends SpellAbilityEffect {
String destination = srcSA.hasParam("Destination") ? srcSA.getParam("Destination") : tgtSA.isAftermath() ? "Exile" : "Graveyard";
if (srcSA.hasParam("DestinationChoice")) {//Hinder
List<String> pos = Arrays.asList(srcSA.getParam("DestinationChoice").split(","));
destination = srcSA.getActivatingPlayer().getController().chooseSomeType("a destination to remove", tgtSA, pos, null);
destination = srcSA.getActivatingPlayer().getController().chooseSomeType(Localizer.getInstance().getMessage("lblRemoveDestination"), tgtSA, pos, null);
}
if (tgtSA.isAbility()) {
// For Ability-targeted counterspells - do not move it anywhere,

View File

@@ -12,6 +12,8 @@ import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.List;
import java.util.Map;
@@ -109,10 +111,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
// only select cards if the counterNum is any
if (counterNum.equals("Any")) {
StringBuilder sb = new StringBuilder();
sb.append("Choose cards to take ").append(cType.getName()).append(" counters from");
srcCards = player.getController().chooseCardsForEffect(srcCards, sa, sb.toString(), 0, srcCards.size(), true);
srcCards = player.getController().chooseCardsForEffect(srcCards, sa, Localizer.getInstance().getMessage("lblChooseTakeCountersCard", cType.getName()), 0, srcCards.size(), true);
}
for (Card src : srcCards) {
@@ -134,10 +133,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
params.put("CounterType", cType);
params.put("Source", src);
params.put("Target", dest);
StringBuilder sb = new StringBuilder();
sb.append("Take how many ").append(cType.getName());
sb.append(" counters from ").append(src).append("?");
cnum = player.getController().chooseNumber(sa, sb.toString(), 0, cmax, params);
cnum = player.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounterFromCard", cType.getName(), CardTranslation.getTranslatedName(src.getName())), 0, cmax, params);
} else {
cnum = AbilityUtils.calculateAmount(host, counterNum, sa);
}
@@ -171,12 +167,8 @@ public class CountersMoveEffect extends SpellAbilityEffect {
tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), player, host, sa);
if (counterNum.equals("Any")) {
StringBuilder sb = new StringBuilder();
sb.append("Choose cards to get ").append(cType.getName());
sb.append(" counters from ").append(source).append(".");
tgtCards = player.getController().chooseCardsForEffect(
tgtCards, sa, sb.toString(), 0, tgtCards.size(), true);
tgtCards = player.getController().chooseCardsForEffect(tgtCards, sa,
Localizer.getInstance().getMessage("lblChooseCardToGetCountersFrom", cType.getName(), CardTranslation.getTranslatedName(source.getName())), 0, tgtCards.size(), true);
}
boolean updateSource = false;
@@ -200,9 +192,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
params.put("CounterType", cType);
params.put("Source", source);
params.put("Target", cur);
StringBuilder sb = new StringBuilder();
sb.append("Put how many ").append(cType.getName()).append(" counters on ").append(cur).append("?");
int cnum = player.getController().chooseNumber(sa, sb.toString(), 0, source.getCounters(cType), params);
int cnum = player.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblPutHowManyTargetCounterOnCard", cType.getName(), CardTranslation.getTranslatedName(cur.getName())), 0, source.getCounters(cType), params);
if (cnum > 0) {
source.subtractCounter(cType, cnum);
@@ -260,10 +250,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
params.put("CounterType", cType);
params.put("Source", source);
params.put("Target", cur);
StringBuilder sb = new StringBuilder();
sb.append("Take how many ").append(cType.getName());
sb.append(" counters from ").append(source).append("?");
cntToMove = pc.chooseNumber(sa, sb.toString(), 0, cntToMove, params);
cntToMove = pc.chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounterFromCard", cType.getName(), CardTranslation.getTranslatedName(source.getName())), 0, cntToMove, params);
}
if (source.getCounters(cType) >= cntToMove) {
@@ -289,17 +276,15 @@ public class CountersMoveEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap();
params.put("Source", source);
params.put("Target", dest);
String title = "Select type counters to remove";
String title = Localizer.getInstance().getMessage("lblSelectRemoveCounterType");
CounterType chosenType = pc.chooseCounterType(typeChoices, sa, title, params);
params = Maps.newHashMap();
params.put("CounterType", chosenType);
params.put("Source", source);
params.put("Target", dest);
StringBuilder sb = new StringBuilder();
sb.append("Take how many ").append(chosenType.getName()).append(" counters?");
int chosenAmount = pc.chooseNumber(
sa, sb.toString(), 0, Math.min(tgtCounters.get(chosenType), cntToMove), params);
int chosenAmount = pc.chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounters", chosenType.getName()),
0, Math.min(tgtCounters.get(chosenType), cntToMove), params);
if (chosenAmount > 0) {
dest.addCounter(chosenType, chosenAmount, player, true, table);

View File

@@ -14,6 +14,7 @@ import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
import forge.util.Localizer;
import java.util.List;
@@ -42,7 +43,7 @@ public class CountersProliferateEffect extends SpellAbilityEffect {
list.addAll(CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.hasCounters()));
List<GameEntity> result = pc.chooseEntitiesForEffect(list, 0, list.size(), null, sa,
"Choose any number of permanents and/or players for proliferate", p);
Localizer.getInstance().getMessage("lblChooseProliferateTarget"), p);
GameEntityCounterTable table = new GameEntityCounterTable();
for (final GameEntity ge : result) {

View File

@@ -26,6 +26,8 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Localizer;
import forge.util.CardTranslation;
import java.util.Map;
import java.util.Iterator;
@@ -33,61 +35,77 @@ import java.util.List;
public class CountersPutEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final Card card = sa.getHostCard();
final boolean dividedAsYouChoose = sa.hasParam("DividedAsYouChoose");
protected String getStackDescription(SpellAbility spellAbility) {
final StringBuilder stringBuilder = new StringBuilder();
final Card card = spellAbility.getHostCard();
final boolean dividedAsYouChoose = spellAbility.hasParam("DividedAsYouChoose");
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("CounterNum", "1"), sa);
if (sa.hasParam("Bolster")) {
sb.append("Bolster ").append(amount);
return sb.toString();
final int amount = AbilityUtils.calculateAmount(card, spellAbility.getParamOrDefault("CounterNum", "1"), spellAbility);
if (spellAbility.hasParam("Bolster")) {
stringBuilder.append("Bolster ").append(amount);
return stringBuilder.toString();
}
if (dividedAsYouChoose) {
sb.append("Distribute ");
stringBuilder.append("Distribute ");
} else {
sb.append("Put ");
stringBuilder.append("Put ");
}
if (sa.hasParam("UpTo")) {
sb.append("up to ");
if (spellAbility.hasParam("UpTo")) {
stringBuilder.append("up to ");
}
sb.append(amount).append(" ");
stringBuilder.append(amount).append(" ");
String type = sa.getParam("CounterType");
String type = spellAbility.getParam("CounterType");
if (type.equals("ExistingCounter")) {
sb.append("of an existing counter");
stringBuilder.append("of an existing counter");
} else {
sb.append( CounterType.valueOf(type).getName()).append(" counter");
stringBuilder.append(CounterType.valueOf(type).getName()).append(" counter");
}
if (amount != 1) {
sb.append("s");
stringBuilder.append("s");
}
if (dividedAsYouChoose) {
sb.append(" among ");
stringBuilder.append(" among ");
} else {
sb.append(" on ");
stringBuilder.append(" on ");
}
final List<Card> tgtCards = getTargetCards(sa);
final Iterator<Card> it = tgtCards.iterator();
while (it.hasNext()) {
final Card tgtC = it.next();
if (tgtC.isFaceDown()) {
sb.append("Morph");
} else {
sb.append(tgtC);
// if use targeting we show all targets and corresponding counters
if(spellAbility.usesTargeting()) {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
for(int i = 0; i < targetCards.size(); i++) {
Card targetCard = targetCards.get(i);
stringBuilder.append(targetCard).append(" (").append(spellAbility.getTargetRestrictions().getDividedMap().get(targetCard)).append(" counter)");
if(i == targetCards.size() - 2) {
stringBuilder.append(" and ");
}
else if(i + 1 < targetCards.size()) {
stringBuilder.append(", ");
}
}
} else {
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
final Iterator<Card> it = targetCards.iterator();
while (it.hasNext()) {
final Card targetCard = it.next();
if (targetCard.isFaceDown()) {
stringBuilder.append("Morph");
} else {
stringBuilder.append(targetCard);
}
if (it.hasNext()) {
sb.append(", ");
if (it.hasNext()) {
stringBuilder.append(", ");
}
}
}
sb.append(".");
stringBuilder.append(".");
return sb.toString();
return stringBuilder.toString();
}
@Override
@@ -129,7 +147,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
if (sa.hasParam("Bolster")) {
CardCollection creatsYouCtrl = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield), Presets.CREATURES);
CardCollection leastToughness = new CardCollection(Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetDefense));
tgtCards.addAll(pc.chooseCardsForEffect(leastToughness, sa, "Choose a creature with the least toughness", 1, 1, false));
tgtCards.addAll(pc.chooseCardsForEffect(leastToughness, sa, Localizer.getInstance().getMessage("lblChooseACreatureWithLeastToughness"), 1, 1, false));
tgtObjects.addAll(tgtCards);
} else {
tgtObjects.addAll(getDefinedOrTargeted(sa, "Defined"));
@@ -154,7 +172,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
if (existingCounter) {
final List<CounterType> choices = Lists.newArrayList();
if (obj instanceof GameEntity) {
GameEntity entity = (GameEntity)obj;
GameEntity entity = (GameEntity) obj;
// get types of counters
for (CounterType ct : entity.getCounters().keySet()) {
if (entity.canReceiveCounters(ct)) {
@@ -164,7 +182,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
if (eachExistingCounter) {
for(CounterType ct : choices) {
for (CounterType ct : choices) {
if (obj instanceof Player) {
((Player) obj).addCounter(ct, counterAmount, placer, true, table);
}
@@ -183,13 +201,14 @@ public class CountersPutEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap();
params.put("Target", obj);
StringBuilder sb = new StringBuilder();
sb.append("Select counter type to add to ");
sb.append(Localizer.getInstance().getMessage("lblSelectCounterTypeAddTo") + " ");
sb.append(obj);
counterType = pc.chooseCounterType(choices, sa, sb.toString(), params);
}
}
if (obj instanceof Card) {
boolean counterAdded = false;
counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(gameCard) : counterAmount;
if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
if (max != -1) {
@@ -199,7 +218,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap();
params.put("Target", obj);
params.put("CounterType", counterType);
counterAmount = pc.chooseNumber(sa, "How many counters?", 0, counterAmount, params);
counterAmount = pc.chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyCounters"), 0, counterAmount, params);
}
// Adapt need extra logic
@@ -235,8 +254,8 @@ public class CountersPutEffect extends SpellAbilityEffect {
continue;
}
String message = "Do you want to put " + counterAmount + " +1/+1 counters on " + gameCard + " ?";
Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, "Choose an opponent");
String message = Localizer.getInstance().getMessage("lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount), CardTranslation.getTranslatedName(gameCard.getName()));
Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseAnOpponent"));
if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message)) {
gameCard.setTributed(true);
@@ -244,15 +263,14 @@ public class CountersPutEffect extends SpellAbilityEffect {
continue;
}
}
if (rememberCards) {
card.addRemembered(gameCard);
}
final Zone zone = gameCard.getGame().getZoneOf(gameCard);
if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) {
if (etbcounter) {
gameCard.addEtbCounter(counterType, counterAmount, placer);
} else {
gameCard.addCounter(counterType, counterAmount, placer, true, table);
if (gameCard.addCounter(counterType, counterAmount, placer, true, table) > 0) {
counterAdded = true;
}
}
if (remember) {
final int value = gameCard.getTotalCountersToAdd();
@@ -283,9 +301,14 @@ public class CountersPutEffect extends SpellAbilityEffect {
if (etbcounter) {
gameCard.addEtbCounter(counterType, counterAmount, placer);
} else {
gameCard.addCounter(counterType, counterAmount, placer, false, table);
if (gameCard.addCounter(counterType, counterAmount, placer, false, table) > 0) {
counterAdded = true;
}
}
}
if (rememberCards && counterAdded) {
card.addRemembered(gameCard);
}
game.updateLastStateForCard(gameCard);
}
} else if (obj instanceof Player) {

View File

@@ -13,6 +13,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.Localizer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -97,11 +98,11 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
list = Lists.newArrayList(ctype);
}
String prompt = "Select type of counters to add or remove";
String prompt = Localizer.getInstance().getMessage("lblSelectCounterTypeToAddOrRemove");
CounterType chosenType = pc.chooseCounterType(list, sa, prompt, params);
params.put("CounterType", chosenType);
prompt = "What to do with that '" + chosenType.getName() + "' counter ";
prompt = Localizer.getInstance().getMessage("lblWhatToDoWithTargetCounter", chosenType.getName()) + " ";
Boolean putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params);
if (putCounter) {

View File

@@ -13,6 +13,7 @@ import forge.game.player.PlayerController;
import forge.game.spellability.SpellAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import java.util.Map;
@@ -84,8 +85,8 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Optional")) {
String ctrs = cntToRemove > 1 ? "counters" : num.equals("All") ? "all counters" : "a counter";
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null, "Remove " + ctrs + "?")) {
String ctrs = cntToRemove > 1 ? Localizer.getInstance().getMessage("lblCounters") : num.equals("All") ? Localizer.getInstance().getMessage("lblAllCounters") : Localizer.getInstance().getMessage("lblACounters");
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblRemove") + " " + ctrs + "?")) {
return;
}
}
@@ -129,10 +130,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
srcCards = game.getCardsIn(ZoneType.Battlefield);
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), player, card, sa);
if (num.equals("Any")) {
StringBuilder sb = new StringBuilder();
sb.append("Choose cards to take ").append(counterType.getName()).append(" counters from");
srcCards = player.getController().chooseCardsForEffect(srcCards, sa, sb.toString(), 0, srcCards.size(), true);
srcCards = player.getController().chooseCardsForEffect(srcCards, sa, Localizer.getInstance().getMessage("lblChooseCardsToTakeTargetCounters", counterType.getName()), 0, srcCards.size(), true);
}
} else {
srcCards = getTargetCards(sa);
@@ -172,7 +170,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap();
params.put("Target", gameCard);
params.put("CounterType", type);
String title = "Select the number of " + type + " counters to remove";
String title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type);
cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params);
}
@@ -213,10 +211,10 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap();
params.put("Target", entity);
String prompt = "Select type of counters to remove";
String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove");
CounterType chosenType = pc.chooseCounterType(
ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
prompt = "Select the number of " + chosenType.getName() + " counters to remove";
prompt = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", chosenType.getName());
int max = Math.min(cntToRemove, tgtCounters.get(chosenType));
params = Maps.newHashMap();
params.put("Target", entity);

View File

@@ -122,7 +122,7 @@ public class DamageAllEffect extends DamageBaseEffect {
if (!usedDamageMap) {
preventMap.triggerPreventDamage(false);
damageMap.triggerDamageDoneOnce(false, sa);
damageMap.triggerDamageDoneOnce(false, game, sa);
preventMap.clear();
damageMap.clear();

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