mirror of
https://github.com/correl/mage.git
synced 2024-12-01 03:00:09 +00:00
Merge branch 'master' into feature/momirFFA
This commit is contained in:
commit
51ea9972e0
10500 changed files with 119688 additions and 52835 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -132,4 +132,3 @@ Mage.Client/serverlist.txt
|
|||
client_secrets.json
|
||||
|
||||
dependency-reduced-pom.xml
|
||||
/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target/
|
|
@ -0,0 +1,89 @@
|
|||
1 [C17:106] Corpse Augur
|
||||
1 [C17:10] Galecaster Colossus
|
||||
1 [C17:111] Decree of Pain
|
||||
1 [C17:114] Go for the Throat
|
||||
1 [C17:115] Magus of the Abyss
|
||||
1 [C17:117] Necromantic Selection
|
||||
1 [C17:121] Puppeteer Clique
|
||||
1 [C17:12] Magus of the Mind
|
||||
1 [C17:131] Chaos Warp
|
||||
1 [C17:132] Comet Storm
|
||||
1 [C17:13] Portal Mage
|
||||
1 [C17:14] Bloodline Necromancer
|
||||
1 [C17:166] Cauldron Dance
|
||||
1 [C17:169] Crosis's Charm
|
||||
1 [C17:16] Curse of Disturbance
|
||||
1 [C17:171] Etherium-Horn Sorcerer
|
||||
1 [C17:173] Havengul Lich
|
||||
1 [C17:175] Izzet Chronarch
|
||||
1 [C17:177] Marchesa, the Black Rose
|
||||
1 [C17:178] Memory Plunder
|
||||
1 [C17:180] Mercurial Chemister
|
||||
1 [C17:183] Nin, the Pain Artist
|
||||
1 [C17:185] Niv-Mizzet, the Firemind
|
||||
1 [C17:186] Nivix Guildmage
|
||||
1 [C17:18] Kindred Dominance
|
||||
1 [C17:190] Rakdos Charm
|
||||
1 [C17:193] Shadowmage Infiltrator
|
||||
1 [C17:195] Silumgar's Command
|
||||
1 [C17:199] Terminate
|
||||
1 [C17:201] Vela the Night-Clad
|
||||
1 [C17:206] Commander's Sphere
|
||||
1 [C17:207] Darksteel Ingot
|
||||
1 [C17:210] Fellwar Stone
|
||||
1 [C17:217] Nevinyrral's Disk
|
||||
1 [C17:21] Vindictive Lich
|
||||
1 [C17:223] Sol Ring
|
||||
1 [C17:229] Unstable Obelisk
|
||||
1 [C17:232] Worn Powerstone
|
||||
1 [C17:242] Command Tower
|
||||
1 [C17:244] Crumbling Necropolis
|
||||
1 [C17:245] Dimir Aqueduct
|
||||
1 [C17:246] Dismal Backwater
|
||||
1 [C17:248] Evolving Wilds
|
||||
1 [C17:249] Exotic Orchard
|
||||
1 [C17:24] Curse of Opulence
|
||||
1 [C17:254] Grixis Panorama
|
||||
1 [C17:256] Izzet Boilerworks
|
||||
1 [C17:258] Jwar Isle Refuge
|
||||
1 [C17:264] Mystifying Maze
|
||||
1 [C17:26] Izzet Chemister
|
||||
1 [C17:270] Rakdos Carnarium
|
||||
1 [C17:283] Swiftwater Cliffs
|
||||
1 [C17:284] Temple of the False God
|
||||
1 [C17:285] Terramorphic Expanse
|
||||
1 [C17:289] Vivid Crag
|
||||
1 [C17:28] Shifting Shadow
|
||||
1 [C17:290] Vivid Creek
|
||||
1 [C17:292] Vivid Marsh
|
||||
1 [C17:305] Mountain
|
||||
1 [C17:306] Mountain
|
||||
1 [C17:39] Kess, Dissident Mage
|
||||
1 [C17:41] Mairsil, the Pretender
|
||||
1 [C17:47] Taigam, Sidisi's Hand
|
||||
1 [C17:54] Mirror of the Forebears
|
||||
1 [C17:56] Path of Ancestry
|
||||
1 [C17:80] Arcanis the Omnipotent
|
||||
1 [C17:81] Archaeomancer
|
||||
1 [C17:82] Azami, Lady of Scrolls
|
||||
1 [C17:83] Body Double
|
||||
1 [C17:84] Clone Legion
|
||||
1 [C17:85] Harbinger of the Tides
|
||||
1 [C17:86] Into the Roil
|
||||
1 [C17:87] Merchant of Secrets
|
||||
1 [C17:89] Opportunity
|
||||
1 [C17:90] Polymorphist's Jest
|
||||
1 [C17:91] Reality Shift
|
||||
1 [C17:92] Sea Gate Oracle
|
||||
1 [C17:93] Serendib Sorcerer
|
||||
1 [C17:94] Spelltwine
|
||||
1 [C17:97] Apprentice Necromancer
|
||||
1 [C17:9] Curse of Verbosity
|
||||
2 [C17:301] Swamp
|
||||
2 [C17:302] Swamp
|
||||
2 [C17:303] Swamp
|
||||
2 [C17:304] Mountain
|
||||
3 [C17:298] Island
|
||||
3 [C17:300] Island
|
||||
4 [C17:299] Island
|
||||
SB: 1 [C17:38] Inalla, Archmage Ritualist
|
|
@ -0,0 +1,97 @@
|
|||
1 [C17:234] Arcane Sanctum
|
||||
1 [C17:203] Armillary Sphere
|
||||
1 [C17:161] Atarka, World Render
|
||||
1 [C17:163] Bladewing the Risen
|
||||
1 [C17:15] Boneyard Scourge
|
||||
1 [C17:165] Broodmate Dragon
|
||||
1 [C17:242] Command Tower
|
||||
1 [C17:206] Commander's Sphere
|
||||
1 [C17:168] Crosis, the Purger
|
||||
1 [C17:133] Crucible of Fire
|
||||
1 [C17:243] Crucible of the Spirit Dragon
|
||||
1 [C17:244] Crumbling Necropolis
|
||||
1 [C17:107] Crux of Fate
|
||||
1 [C17:147] Cultivate
|
||||
1 [C17:30] Curse of Bounty
|
||||
1 [C17:24] Curse of Opulence
|
||||
1 [C17:9] Curse of Verbosity
|
||||
1 [C17:207] Darksteel Ingot
|
||||
1 [C17:110] Deathbringer Regent
|
||||
1 [C17:134] Dragon Tempest
|
||||
1 [C17:135] Dragonlord's Servant
|
||||
1 [C17:136] Dragonspeaker Shaman
|
||||
1 [C17:209] Dreamstone Hedron
|
||||
1 [C17:170] Dromoka, the Eternal
|
||||
1 [C17:137] Earthquake
|
||||
1 [C17:148] Elemental Bond
|
||||
1 [C17:149] Farseek
|
||||
1 [C17:211] Fist of Suns
|
||||
1 [C17:307] Forest
|
||||
1 [C17:308] Forest
|
||||
1 [C17:309] Forest
|
||||
1 [C17:4] Fortunate Few
|
||||
1 [C17:37] Fractured Identity
|
||||
1 [C17:251] Frontier Bivouac
|
||||
1 [C17:150] Frontier Siege
|
||||
1 [C17:255] Haven of the Spirit Dragon
|
||||
1 [C17:138] Hellkite Charger
|
||||
1 [C17:53] Herald's Horn
|
||||
1 [C17:174] Intet, the Dreamer
|
||||
1 [C17:298] Island
|
||||
1 [C17:299] Island
|
||||
1 [C17:300] Island
|
||||
1 [C17:257] Jungle Shrine
|
||||
1 [C17:11] Kindred Discovery
|
||||
1 [C17:154] Kodama's Reach
|
||||
1 [C17:176] Kolaghan, the Storm's Fury
|
||||
1 [C17:215] Lightning Greaves
|
||||
1 [C17:54] Mirror of the Forebears
|
||||
1 [C17:88] Monastery Siege
|
||||
1 [C17:263] Mystic Monastery
|
||||
1 [C17:218] Nihil Spellbomb
|
||||
1 [C17:184] Niv-Mizzet, Dracogenius
|
||||
1 [C17:265] Nomad Outpost
|
||||
1 [C17:45] O-Kagachi, Vengeful Kami
|
||||
1 [C17:187] Ojutai, Soul of Winter
|
||||
1 [C17:267] Opulent Palace
|
||||
1 [C17:67] Orator of Ojutai
|
||||
1 [C17:118] Painful Truths
|
||||
1 [C17:119] Palace Siege
|
||||
1 [C17:56] Path of Ancestry
|
||||
1 [C17:295] Plains
|
||||
1 [C17:296] Plains
|
||||
1 [C17:297] Plains
|
||||
1 [C17:156] Rain of Thorns
|
||||
1 [C17:55] Ramos, Dragon Engine
|
||||
1 [C17:141] Ryusei, the Falling Star
|
||||
1 [C17:274] Sandsteppe Citadel
|
||||
1 [C17:275] Savage Lands
|
||||
1 [C17:191] Savage Ventmaw
|
||||
1 [C17:6] Scalelord Reckoner
|
||||
1 [C17:192] Scion of the Ur-Dragon
|
||||
1 [C17:142] Scourge of Valkas
|
||||
1 [C17:277] Seaside Citadel
|
||||
1 [C17:194] Silumgar, the Drifting Death
|
||||
1 [C17:223] Sol Ring
|
||||
1 [C17:196] Spellbound Dragon
|
||||
1 [C17:225] Steel Hellkite
|
||||
1 [C17:74] Sunscorch Regent
|
||||
1 [C17:301] Swamp
|
||||
1 [C17:302] Swamp
|
||||
1 [C17:303] Swamp
|
||||
1 [C17:46] Taigam, Ojutai Master
|
||||
1 [C17:198] Teneb, the Harvester
|
||||
1 [C17:29] Territorial Hellkite
|
||||
1 [C17:143] Tyrant's Familiar
|
||||
1 [C17:144] Utvara Hellkite
|
||||
1 [C17:289] Vivid Crag
|
||||
1 [C17:290] Vivid Creek
|
||||
1 [C17:291] Vivid Grove
|
||||
1 [C17:292] Vivid Marsh
|
||||
1 [C17:293] Vivid Meadow
|
||||
1 [C17:49] Wasitora, Nekoru Queen
|
||||
1 [C17:230] Wayfarer's Bauble
|
||||
2 [C17:304] Mountain
|
||||
2 [C17:305] Mountain
|
||||
2 [C17:306] Mountain
|
||||
SB: 1 [C17:48] The Ur-Dragon
|
|
@ -0,0 +1,92 @@
|
|||
1 [C17:145] Abundance
|
||||
1 [C17:1] Alms Collector
|
||||
1 [C17:202] Argentum Armor
|
||||
1 [C17:2] Balan, Wandering Knight
|
||||
1 [C17:162] Behemoth Sledge
|
||||
1 [C17:235] Blighted Woodland
|
||||
1 [C17:50] Bloodforged Battle-Axe
|
||||
1 [C17:237] Blossoming Sands
|
||||
1 [C17:242] Command Tower
|
||||
1 [C17:58] Condemn
|
||||
1 [C17:146] Crushing Vines
|
||||
1 [C17:147] Cultivate
|
||||
1 [C17:30] Curse of Bounty
|
||||
1 [C17:3] Curse of Vitality
|
||||
1 [C17:59] Divine Reckoning
|
||||
1 [C17:209] Dreamstone Hedron
|
||||
1 [C17:247] Elfhame Palace
|
||||
1 [C17:248] Evolving Wilds
|
||||
1 [C17:172] Fleecemane Lion
|
||||
1 [C17:212] Grappling Hook
|
||||
1 [C17:252] Grasslands
|
||||
1 [C17:253] Graypelt Refuge
|
||||
1 [C17:51] Hammer of Nazahn
|
||||
1 [C17:151] Harmonize
|
||||
1 [C17:213] Hedron Archive
|
||||
1 [C17:52] Heirloom Blade
|
||||
1 [C17:53] Herald's Horn
|
||||
1 [C17:214] Hero's Blade
|
||||
1 [C17:31] Hungry Lynx
|
||||
1 [C17:152] Hunter's Prowess
|
||||
1 [C17:61] Jareth, Leonine Titan
|
||||
1 [C17:62] Jazal Goldmane
|
||||
1 [C17:153] Jedit Ojanen of Efrava
|
||||
1 [C17:63] Kemba, Kha Regent
|
||||
1 [C17:32] Kindred Summons
|
||||
1 [C17:260] Krosan Verge
|
||||
1 [C17:64] Leonin Arbiter
|
||||
1 [C17:65] Leonin Relic-Warder
|
||||
1 [C17:66] Leonin Shikari
|
||||
1 [C17:215] Lightning Greaves
|
||||
1 [C17:216] Loxodon Warhammer
|
||||
1 [C17:181] Mirari's Wake
|
||||
1 [C17:43] Mirri, Weatherlight Duelist
|
||||
1 [C17:261] Mosswort Bridge
|
||||
1 [C17:262] Myriad Landscape
|
||||
1 [C17:44] Nazahn, Revered Bladesmith
|
||||
1 [C17:155] Nissa's Pilgrimage
|
||||
1 [C17:266] Opal Palace
|
||||
1 [C17:68] Oreskos Explorer
|
||||
1 [C17:56] Path of Ancestry
|
||||
1 [C17:188] Phantom Nishoba
|
||||
1 [C17:189] Qasali Pridemage
|
||||
1 [C17:33] Qasali Slingers
|
||||
1 [C17:220] Quietus Spike
|
||||
1 [C17:69] Raksha Golden Cub
|
||||
1 [C17:157] Relic Crush
|
||||
1 [C17:272] Rogue's Passage
|
||||
1 [C17:71] Rout
|
||||
1 [C17:273] Saltcrusted Steppe
|
||||
1 [C17:278] Secluded Steppe
|
||||
1 [C17:72] Seht's Tiger
|
||||
1 [C17:279] Selesnya Guildgate
|
||||
1 [C17:280] Selesnya Sanctuary
|
||||
1 [C17:222] Skullclamp
|
||||
1 [C17:223] Sol Ring
|
||||
1 [C17:158] Soul's Majesty
|
||||
1 [C17:73] Spirit of the Hearth
|
||||
1 [C17:224] Staff of Nin
|
||||
1 [C17:281] Stirring Wildwood
|
||||
1 [C17:75] Sunspear Shikari
|
||||
1 [C17:226] Swiftfoot Boots
|
||||
1 [C17:228] Sword of Vengeance
|
||||
1 [C17:227] Sword of the Animist
|
||||
1 [C17:77] Taj-Nar Swordsmith
|
||||
1 [C17:284] Temple of the False God
|
||||
1 [C17:159] Temur Sabertooth
|
||||
1 [C17:285] Terramorphic Expanse
|
||||
1 [C17:286] Tranquil Expanse
|
||||
1 [C17:287] Tranquil Thicket
|
||||
1 [C17:34] Traverse the Outlands
|
||||
1 [C17:291] Vivid Grove
|
||||
1 [C17:293] Vivid Meadow
|
||||
1 [C17:78] White Sun's Zenith
|
||||
1 [C17:79] Wing Shards
|
||||
1 [C17:160] Zendikar Resurgent
|
||||
2 [C17:307] Forest
|
||||
2 [C17:308] Forest
|
||||
2 [C17:309] Forest
|
||||
2 [C17:295] Plains
|
||||
2 [C17:296] Plains
|
||||
3 [C17:297] Plains
|
||||
SB: 1 [C17:35] Arahbo, Roar of the World
|
|
@ -0,0 +1,94 @@
|
|||
1 [C17:100] Blood Tribute
|
||||
1 [C17:101] Bloodhusk Ritualist
|
||||
1 [C17:102] Bloodlord of Vaasgoth
|
||||
1 [C17:103] Butcher of Malakir
|
||||
1 [C17:104] Captivating Vampire
|
||||
1 [C17:105] Consuming Vapors
|
||||
1 [C17:108] Damnable Pact
|
||||
1 [C17:112] Drana, Kalastria Bloodchief
|
||||
1 [C17:113] Falkenrath Noble
|
||||
1 [C17:114] Go for the Throat
|
||||
1 [C17:116] Malakir Bloodwitch
|
||||
1 [C17:120] Pawn of Ulamog
|
||||
1 [C17:122] Read the Bones
|
||||
1 [C17:123] Sangromancer
|
||||
1 [C17:124] Sanguine Bond
|
||||
1 [C17:125] Skeletal Scrying
|
||||
1 [C17:126] Skeletal Vampire
|
||||
1 [C17:127] Syphon Mind
|
||||
1 [C17:128] Underworld Connections
|
||||
1 [C17:129] Vampire Nighthawk
|
||||
1 [C17:130] Vein Drinker
|
||||
1 [C17:139] Outpost Siege
|
||||
1 [C17:140] Rakish Heir
|
||||
1 [C17:14] Bloodline Necromancer
|
||||
1 [C17:164] Blood Baron of Vizkopa
|
||||
1 [C17:167] Crackling Doom
|
||||
1 [C17:16] Curse of Disturbance
|
||||
1 [C17:179] Merciless Eviction
|
||||
1 [C17:17] Kheru Mind-Eater
|
||||
1 [C17:182] Mortify
|
||||
1 [C17:197] Stromkirk Captain
|
||||
1 [C17:200] Tithe Drinker
|
||||
1 [C17:204] Blade of the Bloodchief
|
||||
1 [C17:205] Boros Signet
|
||||
1 [C17:207] Darksteel Ingot
|
||||
1 [C17:208] Door of Destinies
|
||||
1 [C17:20] Patron of the Vein
|
||||
1 [C17:218] Nihil Spellbomb
|
||||
1 [C17:219] Orzhov Signet
|
||||
1 [C17:221] Rakdos Signet
|
||||
1 [C17:222] Skullclamp
|
||||
1 [C17:223] Sol Ring
|
||||
1 [C17:22] Bloodsworn Steward
|
||||
1 [C17:231] Well of Lost Dreams
|
||||
1 [C17:232] Worn Powerstone
|
||||
1 [C17:233] Akoum Refuge
|
||||
1 [C17:236] Bloodfell Caves
|
||||
1 [C17:238] Bojuka Bog
|
||||
1 [C17:239] Boros Garrison
|
||||
1 [C17:23] Crimson Honor Guard
|
||||
1 [C17:240] Boros Guildgate
|
||||
1 [C17:241] Cinder Barrens
|
||||
1 [C17:242] Command Tower
|
||||
1 [C17:248] Evolving Wilds
|
||||
1 [C17:250] Forsaken Sanctuary
|
||||
1 [C17:259] Kabira Crossroads
|
||||
1 [C17:25] Disrupt Decorum
|
||||
1 [C17:265] Nomad Outpost
|
||||
1 [C17:266] Opal Palace
|
||||
1 [C17:268] Orzhov Basilica
|
||||
1 [C17:269] Orzhov Guildgate
|
||||
1 [C17:270] Rakdos Carnarium
|
||||
1 [C17:271] Rakdos Guildgate
|
||||
1 [C17:276] Scoured Barrens
|
||||
1 [C17:27] Kindred Charge
|
||||
1 [C17:282] Stone Quarry
|
||||
1 [C17:285] Terramorphic Expanse
|
||||
1 [C17:288] Urborg Volcano
|
||||
1 [C17:294] Wind-Scarred Crag
|
||||
1 [C17:295] Plains
|
||||
1 [C17:296] Plains
|
||||
1 [C17:297] Plains
|
||||
1 [C17:305] Mountain
|
||||
1 [C17:306] Mountain
|
||||
1 [C17:3] Curse of Vitality
|
||||
1 [C17:40] Licia, Sanguine Tribune
|
||||
1 [C17:42] Mathas, Fiend Seeker
|
||||
1 [C17:52] Heirloom Blade
|
||||
1 [C17:56] Path of Ancestry
|
||||
1 [C17:57] Blind Obedience
|
||||
1 [C17:5] Kindred Boon
|
||||
1 [C17:60] Fell the Mighty
|
||||
1 [C17:70] Return to Dust
|
||||
1 [C17:76] Swords to Plowshares
|
||||
1 [C17:8] Teferi's Protection
|
||||
1 [C17:95] Ambition's Cost
|
||||
1 [C17:96] Anowon, the Ruin Sage
|
||||
1 [C17:98] Black Market
|
||||
1 [C17:99] Blood Artist
|
||||
2 [C17:304] Mountain
|
||||
3 [C17:301] Swamp
|
||||
2 [C17:303] Swamp
|
||||
3 [C17:302] Swamp
|
||||
SB: 1 [C17:36] Edgar Markov
|
BIN
Mage.Client/sounds/GameCanStart.wav
Normal file
BIN
Mage.Client/sounds/GameCanStart.wav
Normal file
Binary file not shown.
|
@ -44,8 +44,6 @@ import javax.swing.event.PopupMenuEvent;
|
|||
import javax.swing.event.PopupMenuListener;
|
||||
import mage.cards.action.ActionCallback;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.client.chat.ChatPanelBasic;
|
||||
|
@ -134,8 +132,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
|
||||
private final BalloonTip balloonTip;
|
||||
|
||||
private java.util.List<CardInfo> missingCards;
|
||||
|
||||
/**
|
||||
* @return the session
|
||||
*/
|
||||
|
@ -513,18 +509,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
}
|
||||
|
||||
private void checkForNewImages() {
|
||||
long beforeCall = System.currentTimeMillis();
|
||||
missingCards = CardRepository.instance.findCards(new CardCriteria());
|
||||
LOGGER.info("Card pool load time: " + ((System.currentTimeMillis() - beforeCall) / 1000 + " seconds"));
|
||||
beforeCall = System.currentTimeMillis();
|
||||
if (DownloadPictures.checkForMissingCardImages(missingCards)) {
|
||||
LOGGER.info("Card images checking time: " + ((System.currentTimeMillis() - beforeCall) / 1000 + " seconds"));
|
||||
UserRequestMessage message = new UserRequestMessage("New images available", "Card images are missing (" + missingCards.size() + "). Do you want to download the images?"
|
||||
+ "<br><br><i>You can deactivate the image download check on application start in the preferences.</i>");
|
||||
message.setButton1("No", null);
|
||||
message.setButton2("Yes", PlayerAction.CLIENT_DOWNLOAD_CARD_IMAGES);
|
||||
showUserRequestDialog(message);
|
||||
}
|
||||
// Removed TODO: Remove related pref code
|
||||
}
|
||||
|
||||
public static void setActive(MagePane frame) {
|
||||
|
@ -978,8 +963,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
}//GEN-LAST:event_btnImagesActionPerformed
|
||||
|
||||
public void downloadImages() {
|
||||
java.util.List<CardInfo> cards = CardRepository.instance.findCards(new CardCriteria());
|
||||
DownloadPictures.startDownload(null, cards);
|
||||
DownloadPictures.startDownload();
|
||||
}
|
||||
|
||||
public void exitApp() {
|
||||
|
@ -1317,7 +1301,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
|||
Plugins.instance.downloadSymbols();
|
||||
break;
|
||||
case CLIENT_DOWNLOAD_CARD_IMAGES:
|
||||
DownloadPictures.startDownload(null, missingCards);
|
||||
DownloadPictures.startDownload();
|
||||
break;
|
||||
case CLIENT_DISCONNECT:
|
||||
if (SessionHandler.isConnected()) {
|
||||
|
|
|
@ -27,20 +27,9 @@
|
|||
*/
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import mage.cards.MageCard;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.ClientEventType;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.Listener;
|
||||
|
@ -50,6 +39,13 @@ import mage.view.CardsView;
|
|||
import mage.view.SimpleCardView;
|
||||
import org.mage.card.arcane.CardPanel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CardArea extends JPanel implements MouseListener {
|
||||
|
||||
protected final CardEventSource cardEventSource = new CardEventSource();
|
||||
|
@ -240,15 +236,15 @@ public class CardArea extends JPanel implements MouseListener {
|
|||
e.consume();
|
||||
if (obj instanceof Card) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((Card) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((Card) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
} else if (obj instanceof MageCard) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((MageCard) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((MageCard) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(),ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,14 +266,14 @@ public class CardArea extends JPanel implements MouseListener {
|
|||
checkMenu(e, null);
|
||||
}
|
||||
} else {
|
||||
cardEventSource.actionConsumedEvent("action-consumed");
|
||||
cardEventSource.fireEvent(ClientEventType.ACTION_CONSUMED);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMenu(MouseEvent Me, SimpleCardView card) {
|
||||
if (Me.isPopupTrigger()) {
|
||||
Me.consume();
|
||||
cardEventSource.showPopupMenuEvent(card, Me.getComponent(), Me.getX(), Me.getY(), "show-popup-menu");
|
||||
cardEventSource.fireEvent(card, Me.getComponent(), Me.getX(), Me.getY(), ClientEventType.SHOW_POP_UP_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,13 @@
|
|||
*/
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.Serializable;
|
||||
import mage.client.util.*;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.EventDispatcher;
|
||||
import mage.client.util.EventSource;
|
||||
import mage.client.util.Listener;
|
||||
import mage.view.SimpleCardView;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -49,42 +48,22 @@ public class CardEventSource implements EventSource<Event>, Serializable {
|
|||
dispatcher.addListener(listener);
|
||||
}
|
||||
|
||||
public void setNumber(SimpleCardView card, String message, int number) {
|
||||
dispatcher.fireEvent(new Event(card, message, number));
|
||||
public void fireEvent(SimpleCardView card, ClientEventType eventType, int number){
|
||||
dispatcher.fireEvent(new Event(card, eventType, number));
|
||||
}
|
||||
|
||||
public void removeSpecificCard(SimpleCardView card, String message) {
|
||||
dispatcher.fireEvent(new Event(card, message));
|
||||
public void fireEvent(ClientEventType eventType){
|
||||
dispatcher.fireEvent(new Event(null, eventType));
|
||||
}
|
||||
|
||||
public void addSpecificCard(SimpleCardView card, String message) {
|
||||
dispatcher.fireEvent(new Event(card, message));
|
||||
public void fireEvent(SimpleCardView card, ClientEventType eventType){
|
||||
dispatcher.fireEvent(new Event(card, eventType));
|
||||
}
|
||||
|
||||
public void doubleClick(SimpleCardView card, String message) {
|
||||
dispatcher.fireEvent(new Event(card, message));
|
||||
}
|
||||
|
||||
public void altDoubleClick(SimpleCardView card, String message) {
|
||||
dispatcher.fireEvent(new Event(card, message));
|
||||
}
|
||||
|
||||
public void removeFromMainEvent(String message) {
|
||||
dispatcher.fireEvent(new Event(null, message));
|
||||
}
|
||||
|
||||
public void removeFromSideboardEvent(String message) {
|
||||
dispatcher.fireEvent(new Event(null, message));
|
||||
}
|
||||
|
||||
public void showPopupMenuEvent(SimpleCardView card, Component component, int x, int y, String message) {
|
||||
public void fireEvent(SimpleCardView card, Component component, int x, int y, ClientEventType message) {
|
||||
dispatcher.fireEvent(new Event(card, message, x, y, component));
|
||||
}
|
||||
|
||||
public void actionConsumedEvent(String message) {
|
||||
dispatcher.fireEvent(new Event(null, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearListeners() {
|
||||
dispatcher.clearListeners();
|
||||
|
|
|
@ -33,22 +33,10 @@
|
|||
*/
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import mage.cards.MageCard;
|
||||
import mage.client.deckeditor.SortSetting;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.ClientEventType;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.Listener;
|
||||
|
@ -57,6 +45,13 @@ import mage.view.CardView;
|
|||
import mage.view.CardsView;
|
||||
import org.mage.card.arcane.CardPanel;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -321,15 +316,15 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
Object obj = e.getSource();
|
||||
if (obj instanceof Card) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((Card) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((Card) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
} else if (obj instanceof MageCard) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((MageCard) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((MageCard) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,6 @@ import java.util.*;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CardsList extends javax.swing.JPanel implements MouseListener, ICardGrid {
|
||||
|
@ -475,9 +474,9 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
|
||||
setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
|
||||
setMinimumSize(new java.awt.Dimension(30, 30));
|
||||
setPreferredSize((!Beans.isDesignTime())?
|
||||
(GUISizeHelper.editorCardDimension)
|
||||
:(new Dimension(600, 600)));
|
||||
setPreferredSize((!Beans.isDesignTime()) ?
|
||||
(GUISizeHelper.editorCardDimension)
|
||||
: (new Dimension(600, 600)));
|
||||
setRequestFocusEnabled(false);
|
||||
|
||||
panelControl.setMaximumSize(new java.awt.Dimension(32767, 23));
|
||||
|
@ -522,7 +521,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
chkPiles.setMargin(new java.awt.Insets(3, 2, 2, 2));
|
||||
chkPiles.addActionListener(evt -> chkPilesActionPerformed(evt));
|
||||
|
||||
cbSortBy.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "SortBy" }));
|
||||
cbSortBy.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"SortBy"}));
|
||||
cbSortBy.setToolTipText("Sort the cards if card view is active.");
|
||||
cbSortBy.setMaximumSize(new java.awt.Dimension(120, 20));
|
||||
cbSortBy.setMinimumSize(new java.awt.Dimension(120, 20));
|
||||
|
@ -553,36 +552,36 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
javax.swing.GroupLayout panelControlLayout = new javax.swing.GroupLayout(panelControl);
|
||||
panelControl.setLayout(panelControlLayout);
|
||||
panelControlLayout.setHorizontalGroup(
|
||||
panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createSequentialGroup()
|
||||
.addComponent(lblCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblLandCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblCreatureCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(chkPiles)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(cbSortBy, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(jToggleListView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jToggleCardView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createSequentialGroup()
|
||||
.addComponent(lblCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblLandCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lblCreatureCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(chkPiles)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(cbSortBy, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(jToggleListView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jToggleCardView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
panelControlLayout.setVerticalGroup(
|
||||
panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createSequentialGroup()
|
||||
.addGroup(panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lblCount)
|
||||
.addComponent(lblLandCount)
|
||||
.addComponent(lblCreatureCount)
|
||||
.addComponent(chkPiles))
|
||||
.addComponent(cbSortBy, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jToggleListView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jToggleCardView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 0, 0))
|
||||
panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createSequentialGroup()
|
||||
.addGroup(panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(panelControlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lblCount)
|
||||
.addComponent(lblLandCount)
|
||||
.addComponent(lblCreatureCount)
|
||||
.addComponent(chkPiles))
|
||||
.addComponent(cbSortBy, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jToggleListView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jToggleCardView, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
|
||||
jToggleListView.getAccessibleContext().setAccessibleDescription("Switch between image and table view.");
|
||||
|
@ -593,16 +592,16 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(panelControl, javax.swing.GroupLayout.PREFERRED_SIZE, 467, Short.MAX_VALUE)
|
||||
.addComponent(panelCardArea)
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(panelControl, javax.swing.GroupLayout.PREFERRED_SIZE, 467, Short.MAX_VALUE)
|
||||
.addComponent(panelCardArea)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(panelControl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(2, 2, 2)
|
||||
.addComponent(panelCardArea, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE))
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(panelControl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(2, 2, 2)
|
||||
.addComponent(panelCardArea, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
@ -660,15 +659,15 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
e.consume();
|
||||
if (obj instanceof Card) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((Card) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((Card) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((Card) obj).getOriginal(), ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
} else if (obj instanceof MageCard) {
|
||||
if (e.isAltDown()) {
|
||||
cardEventSource.altDoubleClick(((MageCard) obj).getOriginal(), "alt-double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
cardEventSource.doubleClick(((MageCard) obj).getOriginal(), "double-click");
|
||||
cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -695,7 +694,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
|
|||
private void checkMenu(MouseEvent Me, SimpleCardView card) {
|
||||
if (Me.isPopupTrigger()) {
|
||||
Me.consume();
|
||||
cardEventSource.showPopupMenuEvent(card, Me.getComponent(), Me.getX(), Me.getY(), "show-popup-menu");
|
||||
cardEventSource.fireEvent(card, Me.getComponent(), Me.getX(), Me.getY(), ClientEventType.SHOW_POP_UP_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,17 +34,11 @@
|
|||
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.cards.CardDimensions;
|
||||
import mage.cards.MageCard;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.CardViewRarityComparator;
|
||||
import mage.client.util.ClientEventType;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.Listener;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
|
@ -53,6 +47,12 @@ import mage.view.CardView;
|
|||
import mage.view.CardsView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -186,7 +186,7 @@ public class DraftGrid extends javax.swing.JPanel implements MouseListener {
|
|||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
Object obj = e.getSource();
|
||||
if (obj instanceof MageCard) {
|
||||
this.cardEventSource.doubleClick(((MageCard)obj).getOriginal(), "pick-a-card");
|
||||
this.cardEventSource.fireEvent(((MageCard)obj).getOriginal(), ClientEventType.PICK_A_CARD);
|
||||
this.hidePopup();
|
||||
AudioManager.playOnDraftSelect();
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ public class DraftGrid extends javax.swing.JPanel implements MouseListener {
|
|||
if (this.markedCard != null) {
|
||||
markedCard.setSelected(false);
|
||||
}
|
||||
this.cardEventSource.doubleClick(((MageCard)obj).getOriginal(), "mark-a-card");
|
||||
this.cardEventSource.fireEvent(((MageCard)obj).getOriginal(), ClientEventType.MARK_A_CARD);
|
||||
markedCard = ((MageCard)obj);
|
||||
markedCard.setSelected(true);
|
||||
repaint();
|
||||
|
|
|
@ -70,7 +70,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
if (card.isSelected()) {
|
||||
stack.set(i, null);
|
||||
removeCardView(card);
|
||||
eventSource.removeSpecificCard(card, "remove-specific-card");
|
||||
eventSource.fireEvent(card, ClientEventType.REMOVE_SPECIFIC_CARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
for (CardView card : cards) {
|
||||
card.setSelected(true);
|
||||
addCardView(card, false);
|
||||
eventSource.addSpecificCard(card, "add-specific-card");
|
||||
eventSource.fireEvent(card, ClientEventType.ADD_SPECIFIC_CARD);
|
||||
}
|
||||
layoutGrid();
|
||||
cardContent.repaint();
|
||||
|
@ -381,7 +381,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
for (int i = 0; i < stack.size(); ++i) {
|
||||
CardView card = stack.get(i);
|
||||
if (card.isSelected()) {
|
||||
eventSource.removeSpecificCard(card, "remove-specific-card");
|
||||
eventSource.fireEvent(card, ClientEventType.REMOVE_SPECIFIC_CARD);
|
||||
stack.set(i, null);
|
||||
removeCardView(card);
|
||||
}
|
||||
|
@ -1497,7 +1497,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
if (acard.getName().equals(card.getName())) {
|
||||
CardView pimpedCard = new CardView(acard);
|
||||
addCardView(pimpedCard, false);
|
||||
eventSource.addSpecificCard(pimpedCard, "add-specific-card");
|
||||
eventSource.fireEvent(pimpedCard, ClientEventType.ADD_SPECIFIC_CARD);
|
||||
pimpedCards.put(pimpedCard, 1);
|
||||
didModify = true;
|
||||
}
|
||||
|
@ -1748,9 +1748,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
if (e.getClickCount() == 1) {
|
||||
cardClicked(card, e);
|
||||
} else if (e.isAltDown()) {
|
||||
eventSource.altDoubleClick(card, "alt-double-click");
|
||||
eventSource.fireEvent(card, ClientEventType.ALT_DOUBLE_CLICK);
|
||||
} else {
|
||||
eventSource.doubleClick(card, "double-click");
|
||||
eventSource.fireEvent(card, ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1776,7 +1776,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
|||
|
||||
if (duplicated) {
|
||||
sortIntoGrid(card);
|
||||
eventSource.addSpecificCard(card, "add-specific-card");
|
||||
eventSource.fireEvent(card, ClientEventType.ADD_SPECIFIC_CARD);
|
||||
// Update layout
|
||||
layoutGrid();
|
||||
// Update draw
|
||||
|
|
|
@ -32,10 +32,6 @@
|
|||
*/
|
||||
package mage.client.deckeditor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.*;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardLayout;
|
||||
|
@ -43,12 +39,18 @@ import mage.client.cards.BigCard;
|
|||
import mage.client.cards.CardEventSource;
|
||||
import mage.client.cards.DragCardGrid;
|
||||
import mage.client.constants.Constants.DeckEditorMode;
|
||||
import mage.client.util.ClientEventType;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.Listener;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CardsView;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -124,8 +126,8 @@ public class DeckArea extends javax.swing.JPanel {
|
|||
// Add to hidden and move to sideboard
|
||||
for (CardView card : cards) {
|
||||
hiddenCards.add(card.getId());
|
||||
maindeckVirtualEvent.removeSpecificCard(card, "remove-specific-card");
|
||||
sideboardVirtualEvent.addSpecificCard(card, "add-specific-card");
|
||||
maindeckVirtualEvent.fireEvent(card, ClientEventType.REMOVE_SPECIFIC_CARD);
|
||||
sideboardVirtualEvent.fireEvent(card, ClientEventType.ADD_SPECIFIC_CARD);
|
||||
}
|
||||
loadDeck(lastDeck, lastBigCard);
|
||||
}
|
||||
|
|
|
@ -27,23 +27,6 @@
|
|||
*/
|
||||
package mage.client.deckeditor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.decks.Deck;
|
||||
|
@ -72,6 +55,18 @@ import mage.view.CardView;
|
|||
import mage.view.SimpleCardView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -280,11 +275,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
component.clearCardEventListeners();
|
||||
component.addCardEventListener(
|
||||
(Listener<Event>) event -> {
|
||||
switch (event.getEventName()) {
|
||||
case "double-click":
|
||||
switch (event.getEventType()) {
|
||||
case DOUBLE_CLICK:
|
||||
moveSelectorCardToDeck(event);
|
||||
break;
|
||||
case "alt-double-click":
|
||||
case ALT_DOUBLE_CLICK:
|
||||
if (mode == DeckEditorMode.FREE_BUILDING) {
|
||||
moveSelectorCardToSideboard(event);
|
||||
} else {
|
||||
|
@ -292,10 +287,10 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
moveSelectorCardToDeck(event);
|
||||
}
|
||||
break;
|
||||
case "remove-main":
|
||||
case REMOVE_MAIN:
|
||||
DeckEditorPanel.this.deckArea.getDeckList().removeSelection();
|
||||
break;
|
||||
case "remove-sideboard":
|
||||
case REMOVE_SIDEBOARD:
|
||||
DeckEditorPanel.this.deckArea.getSideboardList().removeSelection();
|
||||
break;
|
||||
}
|
||||
|
@ -306,8 +301,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
this.deckArea.addDeckEventListener(
|
||||
(Listener<Event>) event -> {
|
||||
if (mode == DeckEditorMode.FREE_BUILDING) {
|
||||
switch (event.getEventName()) {
|
||||
case "double-click": {
|
||||
switch (event.getEventType()) {
|
||||
case DOUBLE_CLICK: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getCards()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -319,7 +314,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
refreshDeck();
|
||||
break;
|
||||
}
|
||||
case "alt-double-click": {
|
||||
case ALT_DOUBLE_CLICK: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getCards()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -332,11 +327,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
refreshDeck();
|
||||
break;
|
||||
}
|
||||
case "set-number": {
|
||||
case SET_NUMBER: {
|
||||
setCardNumberToCardsList(event, deck.getCards());
|
||||
break;
|
||||
}
|
||||
case "remove-specific-card": {
|
||||
case REMOVE_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getCards()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -347,7 +342,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "add-specific-card": {
|
||||
case ADD_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (CardView) event.getSource();
|
||||
deck.getCards().add(retrieveTemporaryCard(cardView));
|
||||
break;
|
||||
|
@ -355,9 +350,9 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
} else {
|
||||
// constructing phase or sideboarding during match -> card goes always to sideboard
|
||||
switch (event.getEventName()) {
|
||||
case "double-click":
|
||||
case "alt-double-click": {
|
||||
switch (event.getEventType()) {
|
||||
case DOUBLE_CLICK:
|
||||
case ALT_DOUBLE_CLICK: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getCards()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -371,7 +366,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
refreshDeck();
|
||||
break;
|
||||
}
|
||||
case "remove-specific-card": {
|
||||
case REMOVE_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getCards()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -382,7 +377,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "add-specific-card": {
|
||||
case ADD_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (CardView) event.getSource();
|
||||
deck.getCards().add(retrieveTemporaryCard(cardView));
|
||||
break;
|
||||
|
@ -395,8 +390,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
(Listener<Event>) event -> {
|
||||
if (mode == DeckEditorMode.FREE_BUILDING) {
|
||||
// normal edit mode
|
||||
switch (event.getEventName()) {
|
||||
case "double-click":
|
||||
switch (event.getEventType()) {
|
||||
case DOUBLE_CLICK:
|
||||
// remove card from sideboard (don't add it to deck)
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getSideboard()) {
|
||||
|
@ -408,7 +403,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
hidePopup();
|
||||
refreshDeck();
|
||||
break;
|
||||
case "alt-double-click":
|
||||
case ALT_DOUBLE_CLICK:
|
||||
// remove card from sideboard
|
||||
cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getSideboard()) {
|
||||
|
@ -421,11 +416,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
hidePopup();
|
||||
refreshDeck();
|
||||
break;
|
||||
case "set-number": {
|
||||
case SET_NUMBER: {
|
||||
setCardNumberToCardsList(event, deck.getSideboard());
|
||||
break;
|
||||
}
|
||||
case "remove-specific-card": {
|
||||
case REMOVE_SPECIFIC_CARD: {
|
||||
cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -436,7 +431,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "add-specific-card": {
|
||||
case ADD_SPECIFIC_CARD: {
|
||||
cardView = (CardView) event.getSource();
|
||||
deck.getSideboard().add(retrieveTemporaryCard(cardView));
|
||||
break;
|
||||
|
@ -444,8 +439,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
} else {
|
||||
// construct phase or sideboarding during match
|
||||
switch (event.getEventName()) {
|
||||
case "remove-specific-card": {
|
||||
switch (event.getEventType()) {
|
||||
case REMOVE_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
@ -456,13 +451,13 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "add-specific-card": {
|
||||
case ADD_SPECIFIC_CARD: {
|
||||
SimpleCardView cardView = (CardView) event.getSource();
|
||||
deck.getSideboard().add(retrieveTemporaryCard(cardView));
|
||||
break;
|
||||
}
|
||||
case "double-click":
|
||||
case "alt-double-click":
|
||||
case DOUBLE_CLICK:
|
||||
case ALT_DOUBLE_CLICK:
|
||||
SimpleCardView cardView = (SimpleCardView) event.getSource();
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (card.getId().equals(cardView.getId())) {
|
||||
|
|
|
@ -33,6 +33,7 @@ import mage.client.cards.CardEventSource;
|
|||
import mage.client.cards.ICardGrid;
|
||||
import mage.client.deckeditor.SortSetting;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.ClientEventType;
|
||||
import mage.client.util.Config;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.Listener;
|
||||
|
@ -146,7 +147,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
|
|||
}
|
||||
|
||||
// no easy logic for merge :)
|
||||
for (Iterator<Entry<UUID, CardView>> i = cards.entrySet().iterator(); i.hasNext();) {
|
||||
for (Iterator<Entry<UUID, CardView>> i = cards.entrySet().iterator(); i.hasNext(); ) {
|
||||
Entry<UUID, CardView> entry = i.next();
|
||||
if (!showCards.containsKey(entry.getKey())) {
|
||||
i.remove();
|
||||
|
@ -306,25 +307,25 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
|
|||
|
||||
public void setNumber(int index, int number) {
|
||||
CardView card = view.get(index);
|
||||
cardEventSource.setNumber(card, "set-number", number);
|
||||
cardEventSource.fireEvent(card, ClientEventType.SET_NUMBER, number);
|
||||
}
|
||||
|
||||
public void doubleClick(int index) {
|
||||
CardView card = view.get(index);
|
||||
cardEventSource.doubleClick(card, "double-click");
|
||||
cardEventSource.fireEvent(card, ClientEventType.DOUBLE_CLICK);
|
||||
}
|
||||
|
||||
public void altDoubleClick(int index) {
|
||||
CardView card = view.get(index);
|
||||
cardEventSource.altDoubleClick(card, "alt-double-click");
|
||||
cardEventSource.fireEvent(card, ClientEventType.ALT_DOUBLE_CLICK);
|
||||
}
|
||||
|
||||
public void removeFromMainEvent(int index) {
|
||||
cardEventSource.removeFromMainEvent("remove-main");
|
||||
cardEventSource.fireEvent(ClientEventType.REMOVE_MAIN);
|
||||
}
|
||||
|
||||
public void removeFromSideEvent(int index) {
|
||||
cardEventSource.removeFromSideboardEvent("remove-sideboard");
|
||||
cardEventSource.fireEvent(ClientEventType.REMOVE_SIDEBOARD);
|
||||
}
|
||||
|
||||
public void addListeners(final JTable table) {
|
||||
|
|
|
@ -121,10 +121,16 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="tooltipDelayLabel" pref="308" max="32767" attributes="0"/>
|
||||
<Component id="showCardName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="tooltipDelay" alignment="1" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="tooltipDelayLabel" pref="308" max="32767" attributes="0"/>
|
||||
<Component id="tooltipDelay" alignment="1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="showCardName" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="showFullImagePath" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
|
@ -133,7 +139,10 @@
|
|||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="showCardName" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="showCardName" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="showFullImagePath" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="tooltipDelayLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
|
@ -176,6 +185,24 @@
|
|||
<Property name="value" type="int" value="300"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="showFullImagePath">
|
||||
<Properties>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Show the path Xmage is expecting for this card's image (only displays if missing)"/>
|
||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
|
||||
<Color id="Default Cursor"/>
|
||||
</Property>
|
||||
<Property name="label" type="java.lang.String" value="Display image path for missing images"/>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Display image path for missing images"/>
|
||||
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Show the path Xmage is expecting for this card's image (only displays if missing)"/>
|
||||
</AccessibilityProperties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showFullImagePathActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="main_game">
|
||||
|
|
|
@ -91,6 +91,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
|
||||
public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay";
|
||||
public static final String KEY_SHOW_CARD_NAMES = "showCardNames";
|
||||
public static final String KEY_SHOW_FULL_IMAGE_PATH = "showFullImagePath";
|
||||
public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile";
|
||||
public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently";
|
||||
public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker";
|
||||
|
@ -399,6 +400,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
tabMain = new javax.swing.JPanel();
|
||||
main_card = new javax.swing.JPanel();
|
||||
showCardName = new javax.swing.JCheckBox();
|
||||
showFullImagePath = new javax.swing.JCheckBox();
|
||||
tooltipDelayLabel = new javax.swing.JLabel();
|
||||
tooltipDelay = new javax.swing.JSlider();
|
||||
main_game = new javax.swing.JPanel();
|
||||
|
@ -613,28 +615,48 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
tooltipDelay.setToolTipText("<HTML>The time the appearance of the tooltip window for a card is delayed.<br>\nIf set to zero, the tooltip window won't be shown at all.");
|
||||
tooltipDelay.setValue(300);
|
||||
|
||||
showFullImagePath.setSelected(false);
|
||||
showFullImagePath.setToolTipText("Show the path Xmage is expecting for this card's image (only displays if missing)");
|
||||
showFullImagePath.setActionCommand("");
|
||||
showFullImagePath.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
|
||||
showFullImagePath.setLabel("Display image path for missing images");
|
||||
showFullImagePath.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
showFullImagePathActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.jdesktop.layout.GroupLayout main_cardLayout = new org.jdesktop.layout.GroupLayout(main_card);
|
||||
main_card.setLayout(main_cardLayout);
|
||||
main_cardLayout.setHorizontalGroup(
|
||||
main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(main_cardLayout.createSequentialGroup()
|
||||
.add(6, 6, 6)
|
||||
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
|
||||
.add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)
|
||||
.add(org.jdesktop.layout.GroupLayout.LEADING, showCardName)
|
||||
.add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
|
||||
.add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)
|
||||
.add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.add(main_cardLayout.createSequentialGroup()
|
||||
.add(showCardName)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
|
||||
.add(showFullImagePath)))
|
||||
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
main_cardLayout.setVerticalGroup(
|
||||
main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(main_cardLayout.createSequentialGroup()
|
||||
.add(showCardName)
|
||||
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
|
||||
.add(showCardName)
|
||||
.add(showFullImagePath))
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(tooltipDelayLabel)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
showFullImagePath.getAccessibleContext().setAccessibleName("Display image path for missing images");
|
||||
showFullImagePath.getAccessibleContext().setAccessibleDescription("Show the path Xmage is expecting for this card's image (only displays if missing)");
|
||||
|
||||
main_game.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game"));
|
||||
|
||||
nonLandPermanentsInOnePile.setSelected(true);
|
||||
|
@ -720,7 +742,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
.add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap(255, Short.MAX_VALUE))
|
||||
);
|
||||
main_gameLayout.setVerticalGroup(
|
||||
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
|
@ -2679,6 +2701,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
// main
|
||||
save(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "true", "false", UPDATE_CACHE_POLICY);
|
||||
save(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true", "false", UPDATE_CACHE_POLICY);
|
||||
save(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true", "false", UPDATE_CACHE_POLICY);
|
||||
save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY);
|
||||
save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY);
|
||||
save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY);
|
||||
|
@ -3119,6 +3142,9 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
});
|
||||
}//GEN-LAST:event_bttnResetControlsActionPerformed
|
||||
|
||||
private void showFullImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showFullImagePathActionPerformed
|
||||
}//GEN-LAST:event_showFullImagePathActionPerformed
|
||||
|
||||
private void showProxySettings() {
|
||||
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
|
||||
switch (proxyType) {
|
||||
|
@ -3222,6 +3248,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
private static void loadPhases(Preferences prefs) {
|
||||
load(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "300");
|
||||
load(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true");
|
||||
load(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true");
|
||||
load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true");
|
||||
load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true");
|
||||
load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true");
|
||||
|
@ -3898,6 +3925,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
private javax.swing.JButton saveButton;
|
||||
private javax.swing.JCheckBox showAbilityPickerForced;
|
||||
private javax.swing.JCheckBox showCardName;
|
||||
private javax.swing.JCheckBox showFullImagePath;
|
||||
private javax.swing.JCheckBox showPlayerNamesPermanently;
|
||||
private javax.swing.JSlider sliderCardSizeHand;
|
||||
private javax.swing.JSlider sliderCardSizeMaxBattlefield;
|
||||
|
|
|
@ -438,7 +438,10 @@ class UpdateSeatsTask extends SwingWorker<Void, TableView> {
|
|||
int current = getPlayersCount(tableView);
|
||||
if (current != count) {
|
||||
if (count > 0) {
|
||||
if (current > count) {
|
||||
if (current == tableView.getSeats().size()) {
|
||||
MageTray.instance.displayMessage("The game can start.");
|
||||
AudioManager.playGameCanStart();
|
||||
} else if (current > count) {
|
||||
MageTray.instance.displayMessage("New player joined your game.");
|
||||
AudioManager.playPlayerJoinedTable();
|
||||
} else {
|
||||
|
|
|
@ -33,9 +33,25 @@
|
|||
*/
|
||||
package mage.client.draft;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.components.tray.MageTray;
|
||||
import mage.client.deckeditor.SortSettingDraft;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.*;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.client.util.gui.BufferedImageBuilder;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
@ -46,43 +62,7 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.Timer;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.components.tray.MageTray;
|
||||
import mage.client.deckeditor.SortSettingDraft;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.CardsViewUtil;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.ImageHelper;
|
||||
import mage.client.util.Listener;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.client.util.gui.BufferedImageBuilder;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.view.CardsView;
|
||||
import mage.view.DraftPickView;
|
||||
import mage.view.DraftView;
|
||||
import mage.view.SimpleCardView;
|
||||
import mage.view.SimpleCardsView;
|
||||
import mage.view.UserRequestMessage;
|
||||
import org.apache.log4j.Logger;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -304,7 +284,7 @@ public class DraftPanel extends javax.swing.JPanel {
|
|||
|
||||
this.draftPicks.clearCardEventListeners();
|
||||
this.draftPicks.addCardEventListener((Listener<Event>) event -> {
|
||||
if (event.getEventName().equals("show-popup-menu")) {
|
||||
if (event.getEventType() == ClientEventType.SHOW_POP_UP_MENU) {
|
||||
if (event.getSource() != null) {
|
||||
// Popup Menu Card
|
||||
cardIdPopupMenu = ((SimpleCardView) event.getSource()).getId();
|
||||
|
@ -322,7 +302,7 @@ public class DraftPanel extends javax.swing.JPanel {
|
|||
this.draftBooster.clearCardEventListeners();
|
||||
this.draftBooster.addCardEventListener(
|
||||
(Listener<Event>) event -> {
|
||||
if (event.getEventName().equals("pick-a-card")) {
|
||||
if (event.getEventType() == ClientEventType.PICK_A_CARD) {
|
||||
SimpleCardView source = (SimpleCardView) event.getSource();
|
||||
DraftPickView view = SessionHandler.sendCardPick(draftId, source.getId(), cardsHidden);
|
||||
if (view != null) {
|
||||
|
@ -332,7 +312,7 @@ public class DraftPanel extends javax.swing.JPanel {
|
|||
setMessage("Waiting for other players");
|
||||
}
|
||||
}
|
||||
if (event.getEventName().equals("mark-a-card")) {
|
||||
if (event.getEventType() == ClientEventType.MARK_A_CARD) {
|
||||
SimpleCardView source = (SimpleCardView) event.getSource();
|
||||
SessionHandler.sendCardMark(draftId, source.getId());
|
||||
}
|
||||
|
|
|
@ -27,61 +27,6 @@
|
|||
*/
|
||||
package mage.client.game;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import static java.awt.Component.LEFT_ALIGNMENT;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.GroupLayout.Alignment;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneUI;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.action.ActionCallback;
|
||||
import mage.choices.Choice;
|
||||
|
@ -95,51 +40,43 @@ import mage.client.components.KeyboundButton;
|
|||
import mage.client.components.MageComponents;
|
||||
import mage.client.components.ext.dlg.DialogManager;
|
||||
import mage.client.components.layout.RelativeLayout;
|
||||
import mage.client.dialog.CardInfoWindowDialog;
|
||||
import mage.client.dialog.*;
|
||||
import mage.client.dialog.CardInfoWindowDialog.ShowType;
|
||||
import mage.client.dialog.PickChoiceDialog;
|
||||
import mage.client.dialog.PickNumberDialog;
|
||||
import mage.client.dialog.PickPileDialog;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import static mage.client.dialog.PreferencesDialog.*;
|
||||
import mage.client.dialog.ShowCardsDialog;
|
||||
import mage.client.game.FeedbackPanel.FeedbackMode;
|
||||
import mage.client.plugins.adapters.MageActionCallback;
|
||||
import mage.client.plugins.impl.Plugins;
|
||||
import mage.client.util.CardsViewUtil;
|
||||
import mage.client.util.*;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.GUISizeHelper;
|
||||
import mage.client.util.GameManager;
|
||||
import mage.client.util.Listener;
|
||||
import mage.client.util.audio.AudioManager;
|
||||
import mage.client.util.gui.ArrowBuilder;
|
||||
import mage.client.util.gui.MageDialogState;
|
||||
import mage.constants.Constants;
|
||||
import mage.constants.EnlargeMode;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.PlayerAction;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_ABILITY_FIRST;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_ABILITY_LAST;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_NAME_FIRST;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_NAME_LAST;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.events.PlayerQueryEvent;
|
||||
import mage.view.AbilityPickerView;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CardsView;
|
||||
import mage.view.ExileView;
|
||||
import mage.view.GameView;
|
||||
import mage.view.LookedAtView;
|
||||
import mage.view.MatchView;
|
||||
import mage.view.PlayerView;
|
||||
import mage.view.RevealedView;
|
||||
import mage.view.SimpleCardsView;
|
||||
import mage.view.UserRequestMessage;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.arcane.CardPanel;
|
||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.GroupLayout.Alignment;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneDivider;
|
||||
import javax.swing.plaf.basic.BasicSplitPaneUI;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static mage.client.dialog.PreferencesDialog.*;
|
||||
import static mage.constants.PlayerAction.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com, nantuko8
|
||||
*/
|
||||
|
@ -2251,7 +2188,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
// Event listener for the ShowCardsDialog
|
||||
private Listener<Event> getShowCardsEventListener(final ShowCardsDialog dialog) {
|
||||
return (Listener<Event>) event -> {
|
||||
if (event.getEventName().equals("show-popup-menu")) {
|
||||
if (event.getEventType() == ClientEventType.SHOW_POP_UP_MENU) {
|
||||
if (event.getComponent() != null && event.getComponent() instanceof CardPanel) {
|
||||
JPopupMenu menu = ((CardPanel) event.getComponent()).getPopupMenu();
|
||||
if (menu != null) {
|
||||
|
@ -2260,7 +2197,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (event.getEventName().equals("action-consumed")) {
|
||||
if (event.getEventType() == ClientEventType.ACTION_CONSUMED) {
|
||||
dialog.removeDialog();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
*/
|
||||
package mage.client.remote;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.*;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
|
@ -48,11 +52,6 @@ import mage.view.*;
|
|||
import mage.view.ChatMessage.MessageType;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -325,11 +324,11 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
break;
|
||||
}
|
||||
case VIEW_LIMITED_DECK: {
|
||||
TableClientMessage message = (TableClientMessage) callback.getData();
|
||||
DeckView deckView = message.getDeck();
|
||||
Deck deck = DeckUtil.construct(deckView);
|
||||
viewLimitedDeck(deck, message.getTableId(), message.getTime());
|
||||
break;
|
||||
TableClientMessage message = (TableClientMessage) callback.getData();
|
||||
DeckView deckView = message.getDeck();
|
||||
Deck deck = DeckUtil.construct(deckView);
|
||||
viewLimitedDeck(deck, message.getTableId(), message.getTime());
|
||||
break;
|
||||
}
|
||||
case CONSTRUCT: {
|
||||
TableClientMessage message = (TableClientMessage) callback.getData();
|
||||
|
@ -356,14 +355,6 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DRAFT_INFORM: // if (callback.getMessageId() > messageId) {
|
||||
{
|
||||
DraftClientMessage message = (DraftClientMessage) callback.getData();
|
||||
}
|
||||
// } else {
|
||||
// logger.warn("message out of sequence - ignoring");
|
||||
// }
|
||||
break;
|
||||
case DRAFT_INIT: {
|
||||
DraftClientMessage message = (DraftClientMessage) callback.getData();
|
||||
DraftPanel panel = MageFrame.getDraft(callback.getObjectId());
|
||||
|
|
|
@ -28,11 +28,9 @@
|
|||
|
||||
package mage.client.table;
|
||||
|
||||
import mage.client.util.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import mage.client.util.Event;
|
||||
import mage.client.util.EventDispatcher;
|
||||
import mage.client.util.EventSource;
|
||||
import mage.client.util.Listener;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -48,7 +46,7 @@ public class PlayerTypeEventSource implements EventSource<Event>, Serializable {
|
|||
}
|
||||
|
||||
public void playerTypeChanged() {
|
||||
dispatcher.fireEvent(new Event(null, "playerTypeChanged"));
|
||||
dispatcher.fireEvent(new Event(null, ClientEventType.PLAYER_TYPE_CHANGED));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package mage.client.util;
|
||||
|
||||
public enum ClientEventType {
|
||||
SET_NUMBER,
|
||||
ACTION_CONSUMED,
|
||||
DOUBLE_CLICK,
|
||||
ALT_DOUBLE_CLICK,
|
||||
REMOVE_MAIN,
|
||||
REMOVE_SIDEBOARD,
|
||||
SHOW_POP_UP_MENU,
|
||||
REMOVE_SPECIFIC_CARD,
|
||||
ADD_SPECIFIC_CARD,
|
||||
PICK_A_CARD,
|
||||
MARK_A_CARD,
|
||||
PLAYER_TYPE_CHANGED
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -38,27 +38,27 @@ import java.io.Serializable;
|
|||
public class Event implements Serializable {
|
||||
private final Object source;
|
||||
private final Component component;
|
||||
private final String eventName;
|
||||
private final ClientEventType eventType;
|
||||
private final int number;
|
||||
private final int xPos;
|
||||
private final int yPos;
|
||||
|
||||
public Event(Object source, String eventName) {
|
||||
this(source, eventName, 0);
|
||||
public Event(Object source, ClientEventType eventType) {
|
||||
this(source, eventType, 0);
|
||||
}
|
||||
|
||||
public Event(Object source, String eventName, int number) {
|
||||
public Event(Object source, ClientEventType eventType, int number) {
|
||||
this.source = source;
|
||||
this.eventName = eventName;
|
||||
this.eventType = eventType;
|
||||
this.number = number;
|
||||
this.xPos = 0;
|
||||
this.yPos = 0;
|
||||
this.component = null;
|
||||
}
|
||||
|
||||
public Event(Object source, String eventName, int xPos, int yPos, Component component) {
|
||||
public Event(Object source, ClientEventType eventType, int xPos, int yPos, Component component) {
|
||||
this.source = source;
|
||||
this.eventName = eventName;
|
||||
this.eventType = eventType;
|
||||
this.number =0;
|
||||
this.xPos = xPos;
|
||||
this.yPos = yPos;
|
||||
|
@ -69,8 +69,8 @@ public class Event implements Serializable {
|
|||
return source;
|
||||
}
|
||||
|
||||
public String getEventName() {
|
||||
return eventName;
|
||||
public ClientEventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
|
|
|
@ -40,6 +40,7 @@ public class AudioManager {
|
|||
private MageClip tournamentStarted = null;
|
||||
private MageClip yourGameStarted = null;
|
||||
private MageClip playerJoinedTable = null;
|
||||
private MageClip gameCanStart = null;
|
||||
private MageClip playerSubmittedDeck = null;
|
||||
private MageClip playerWhispered = null;
|
||||
private MageClip playerLeft = null;
|
||||
|
@ -219,6 +220,13 @@ public class AudioManager {
|
|||
checkAndPlayClip(audioManager.playerJoinedTable);
|
||||
}
|
||||
|
||||
public static void playGameCanStart() {
|
||||
if (audioManager.gameCanStart == null) {
|
||||
audioManager.gameCanStart = new MageClip(Constants.BASE_SOUND_PATH + "GameCanStart.wav", AudioGroup.OtherSounds);
|
||||
}
|
||||
checkAndPlayClip(audioManager.gameCanStart);
|
||||
}
|
||||
|
||||
public static void playYourGameStarted() {
|
||||
if (audioManager.yourGameStarted == null) {
|
||||
audioManager.yourGameStarted = new MageClip(Constants.BASE_SOUND_PATH + "OnGameStart.wav", AudioGroup.OtherSounds);
|
||||
|
|
|
@ -31,7 +31,8 @@ import java.util.UUID;
|
|||
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
||||
|
||||
/**
|
||||
* Class for drawing the mage card object by using a form based JComponent approach
|
||||
* Class for drawing the mage card object by using a form based JComponent
|
||||
* approach
|
||||
*
|
||||
* @author arcane, nantuko, noxx, stravant
|
||||
*/
|
||||
|
@ -68,10 +69,13 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
private final GlowText titleText;
|
||||
private final GlowText ptText;
|
||||
private final JLabel fullImageText;
|
||||
private String fullImagePath = null;
|
||||
|
||||
private boolean hasImage = false;
|
||||
|
||||
private boolean displayTitleAnyway;
|
||||
private boolean displayFullImagePath;
|
||||
|
||||
private final static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||
|
||||
|
@ -218,6 +222,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
}
|
||||
|
||||
displayTitleAnyway = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_CARD_NAMES, "true").equals("true");
|
||||
displayFullImagePath = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_FULL_IMAGE_PATH, "false").equals("true");
|
||||
|
||||
// Title Text
|
||||
titleText = new GlowText();
|
||||
|
@ -229,6 +234,12 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
titleText.setWrap(true);
|
||||
add(titleText);
|
||||
|
||||
// Full path to image text
|
||||
fullImageText = new JLabel();
|
||||
fullImageText.setText(fullImagePath);
|
||||
fullImageText.setForeground(Color.BLACK);
|
||||
add(fullImageText);
|
||||
|
||||
// PT Text
|
||||
ptText = new GlowText();
|
||||
if (gameCard.isCreature()) {
|
||||
|
@ -300,10 +311,19 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
doLayout();
|
||||
}
|
||||
|
||||
private void setFullPath(String fullImagePath) {
|
||||
this.fullImagePath = fullImagePath;
|
||||
this.fullImagePath = this.fullImagePath.replaceAll("\\\\", "\\\\<br>");
|
||||
this.fullImagePath = this.fullImagePath.replaceAll("/", "/<br>");
|
||||
this.fullImagePath = "<html>" + this.fullImagePath + "</html>";
|
||||
fullImageText.setText(!displayFullImagePath ? "" : this.fullImagePath);
|
||||
doLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferResources(final CardPanel panelAbstract) {
|
||||
if (panelAbstract instanceof CardPanelComponentImpl) {
|
||||
CardPanelComponentImpl panel = (CardPanelComponentImpl)panelAbstract;
|
||||
CardPanelComponentImpl panel = (CardPanelComponentImpl) panelAbstract;
|
||||
synchronized (panel.imagePanel) {
|
||||
if (panel.imagePanel.hasImage()) {
|
||||
setImage(panel.imagePanel.getSrcImage());
|
||||
|
@ -456,6 +476,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
boolean showText = (!isAnimationPanel() && fontHeight < 12);
|
||||
titleText.setVisible(showText);
|
||||
ptText.setVisible(showText);
|
||||
fullImageText.setVisible(fullImagePath != null);
|
||||
|
||||
if (showText) {
|
||||
int fontSize = cardHeight / 11;
|
||||
|
@ -465,6 +486,9 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
int titleY = Math.round(cardHeight * (9f / 680)) + getTextOffset();
|
||||
titleText.setBounds(cardXOffset + titleX, cardYOffset + titleY, cardWidth - titleX, cardHeight - titleY);
|
||||
|
||||
fullImageText.setFont(getFont().deriveFont(Font.PLAIN, 10));
|
||||
fullImageText.setBounds(cardXOffset, cardYOffset + titleY, cardWidth, cardHeight - titleY);
|
||||
|
||||
ptText.setFont(getFont().deriveFont(Font.BOLD, fontSize));
|
||||
Dimension ptSize = ptText.getPreferredSize();
|
||||
ptText.setSize(ptSize.width, ptSize.height);
|
||||
|
@ -529,6 +553,9 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
} else {
|
||||
srcImage = ImageCache.getThumbnail(gameCard);
|
||||
}
|
||||
if (srcImage == null) {
|
||||
setFullPath(ImageCache.getFilePath(gameCard, getCardWidth()));
|
||||
}
|
||||
UI.invokeLater(() -> {
|
||||
if (stamp == updateArtImageStamp) {
|
||||
hasImage = srcImage != null;
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
*/
|
||||
package org.mage.card.arcane;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -19,8 +16,8 @@ import java.util.regex.Pattern;
|
|||
|
||||
/**
|
||||
* @author stravant@gmail.com
|
||||
*
|
||||
* Various static utilities for use in the card renderer
|
||||
* <p>
|
||||
* Various static utilities for use in the card renderer
|
||||
*/
|
||||
public final class CardRendererUtils {
|
||||
|
||||
|
@ -124,6 +121,8 @@ public final class CardRendererUtils {
|
|||
}
|
||||
|
||||
public static String killReminderText(String rule) {
|
||||
return killReminderTextPattern.matcher(rule).replaceAll("");
|
||||
return killReminderTextPattern.matcher(rule).replaceAll("")
|
||||
.replaceAll("<i>", "")
|
||||
.replaceAll("</i>", "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -602,7 +602,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
int partWidth = (int) Math.max(30, 0.20f * cardWidth);
|
||||
|
||||
// Is it a creature?
|
||||
boolean isVehicle = cardView.getSubTypes().contains("Vehicle");
|
||||
boolean isVehicle = cardView.getSubTypes().contains(SubType.VEHICLE);
|
||||
if (cardView.isCreature() || isVehicle) {
|
||||
int x = cardWidth - borderWidth - partWidth;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
/**
|
||||
|
@ -9,12 +10,38 @@ import org.mage.plugins.card.images.CardDownloadData;
|
|||
public interface CardImageSource {
|
||||
|
||||
String generateURL(CardDownloadData card) throws Exception;
|
||||
|
||||
String generateTokenUrl(CardDownloadData card) throws Exception;
|
||||
|
||||
String getNextHttpImageUrl();
|
||||
|
||||
String getFileForHttpImage(String httpImageUrl);
|
||||
|
||||
String getSourceName();
|
||||
|
||||
float getAverageSize();
|
||||
|
||||
int getTotalImages();
|
||||
boolean isTokenSource();
|
||||
|
||||
default int getTokenImages() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default boolean isTokenSource() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void doPause(String httpImageUrl);
|
||||
|
||||
default ArrayList<String> getSupportedSets() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default boolean isSetSupportedComplete(String setCode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isImageProvided(String setCode, String cardName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,10 @@
|
|||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
import org.mage.plugins.card.utils.CardImageUtils;
|
||||
|
@ -13,6 +16,202 @@ import org.mage.plugins.card.utils.CardImageUtils;
|
|||
public enum MagicCardsImageSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
|
||||
private static final Set<String> supportedSets = new LinkedHashSet<String>() {
|
||||
{
|
||||
// add("PTC"); // Prerelease Events
|
||||
add("LEA");
|
||||
add("LEB");
|
||||
add("2ED");
|
||||
add("ARN");
|
||||
add("ATQ");
|
||||
add("3ED");
|
||||
add("LEG");
|
||||
add("DRK");
|
||||
add("FEM");
|
||||
add("4ED");
|
||||
add("ICE");
|
||||
add("CHR");
|
||||
add("HML");
|
||||
add("ALL");
|
||||
add("MIR");
|
||||
add("VIS");
|
||||
add("5ED");
|
||||
add("POR");
|
||||
add("WTH");
|
||||
add("TMP");
|
||||
add("STH");
|
||||
add("EXO");
|
||||
add("P02");
|
||||
add("UGL");
|
||||
add("USG");
|
||||
add("DD3DVD");
|
||||
add("DD3EVG");
|
||||
add("DD3GVL");
|
||||
add("DD3JVC");
|
||||
|
||||
add("ULG");
|
||||
add("6ED");
|
||||
add("UDS");
|
||||
add("PTK");
|
||||
add("S99");
|
||||
add("MMQ");
|
||||
// add("BRB");Battle Royale Box Set
|
||||
add("NEM");
|
||||
add("S00");
|
||||
add("PCY");
|
||||
add("INV");
|
||||
// add("BTD"); // Beatdown Boxset
|
||||
add("PLS");
|
||||
add("7ED");
|
||||
add("APC");
|
||||
add("ODY");
|
||||
// add("DKM"); // Deckmasters 2001
|
||||
add("TOR");
|
||||
add("JUD");
|
||||
add("ONS");
|
||||
add("LGN");
|
||||
add("SCG");
|
||||
add("8ED");
|
||||
add("MRD");
|
||||
add("DST");
|
||||
add("5DN");
|
||||
add("CHK");
|
||||
add("UNH");
|
||||
add("BOK");
|
||||
add("SOK");
|
||||
add("9ED");
|
||||
add("RAV");
|
||||
add("GPT");
|
||||
add("DIS");
|
||||
add("CSP");
|
||||
add("TSP");
|
||||
add("TSB");
|
||||
add("PLC");
|
||||
add("FUT");
|
||||
add("10E");
|
||||
add("MED");
|
||||
add("LRW");
|
||||
add("EVG");
|
||||
add("MOR");
|
||||
add("SHM");
|
||||
add("EVE");
|
||||
add("DRB");
|
||||
add("ME2");
|
||||
add("ALA");
|
||||
add("DD2");
|
||||
add("CON");
|
||||
add("DDC");
|
||||
add("ARB");
|
||||
add("M10");
|
||||
// add("TD0"); // Magic Online Deck Series
|
||||
add("V09");
|
||||
add("HOP");
|
||||
add("ME3");
|
||||
add("ZEN");
|
||||
add("DDD");
|
||||
add("H09");
|
||||
add("WWK");
|
||||
add("DDE");
|
||||
add("ROE");
|
||||
add("DPA");
|
||||
add("ARC");
|
||||
add("M11");
|
||||
add("V10");
|
||||
add("DDF");
|
||||
add("SOM");
|
||||
// add("TD0"); // Commander Theme Decks
|
||||
add("PD2");
|
||||
add("ME4");
|
||||
add("MBS");
|
||||
add("DDG");
|
||||
add("NPH");
|
||||
add("CMD");
|
||||
add("M12");
|
||||
add("V11");
|
||||
add("DDH");
|
||||
add("ISD");
|
||||
add("PD3");
|
||||
add("DKA");
|
||||
add("DDI");
|
||||
add("AVR");
|
||||
add("PC2");
|
||||
add("M13");
|
||||
add("V12");
|
||||
add("DDJ");
|
||||
add("RTR");
|
||||
add("CM1");
|
||||
// add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia
|
||||
add("GTC");
|
||||
add("DDK");
|
||||
add("DGM");
|
||||
add("MMA");
|
||||
add("M14");
|
||||
add("V13");
|
||||
add("DDL");
|
||||
add("THS");
|
||||
add("C13");
|
||||
add("BNG");
|
||||
add("DDM");
|
||||
add("JOU");
|
||||
// add("MD1"); // Modern Event Deck
|
||||
add("CNS");
|
||||
add("VMA");
|
||||
add("M15");
|
||||
add("V14");
|
||||
add("DDN");
|
||||
add("KTK");
|
||||
add("C14");
|
||||
// add("DD3"); // Duel Decks Anthology
|
||||
add("FRF");
|
||||
add("DDO");
|
||||
add("DTK");
|
||||
add("TPR");
|
||||
add("MM2");
|
||||
add("ORI");
|
||||
add("V15");
|
||||
add("DDP");
|
||||
add("BFZ");
|
||||
add("EXP");
|
||||
add("C15");
|
||||
// add("PZ1"); // Legendary Cube
|
||||
add("OGW");
|
||||
add("DDQ");
|
||||
add("W16");
|
||||
add("SOI");
|
||||
add("EMA");
|
||||
add("EMN");
|
||||
add("V16");
|
||||
add("CN2");
|
||||
add("DDR");
|
||||
add("KLD");
|
||||
add("MPS");
|
||||
// add("PZ2"); // Treasure Chests
|
||||
add("C16");
|
||||
add("PCA");
|
||||
add("AER");
|
||||
add("MM3");
|
||||
add("DDS");
|
||||
add("W17");
|
||||
add("AKH");
|
||||
add("MPS");
|
||||
add("CMA");
|
||||
add("E01");
|
||||
add("HOU");
|
||||
add("C17");
|
||||
// add("XLN");
|
||||
// add("DDT");
|
||||
// add("IMA");
|
||||
// add("E02");
|
||||
// add("V17");
|
||||
// add("UST");
|
||||
// add("RIX");
|
||||
// add("A25");
|
||||
// add("DOM");
|
||||
// add("M19");
|
||||
}
|
||||
};
|
||||
|
||||
private static final Map<String, String> setNameTokenReplacement = new HashMap<String, String>() {
|
||||
{
|
||||
put("10E", "tenth-edition");
|
||||
|
@ -146,7 +345,6 @@ public enum MagicCardsImageSource implements CardImageSource {
|
|||
return "magiccards.info";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNextHttpImageUrl() {
|
||||
return null;
|
||||
|
@ -221,7 +419,15 @@ public enum MagicCardsImageSource implements CardImageSource {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,20 +24,221 @@
|
|||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
*/
|
||||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Pete Rossi
|
||||
*/
|
||||
public enum MagidexImageSource implements CardImageSource {
|
||||
instance;
|
||||
|
||||
public enum MagidexImageSource implements CardImageSource {
|
||||
instance;
|
||||
private final Set<String> supportedSets;
|
||||
|
||||
MagidexImageSource() {
|
||||
supportedSets = new LinkedHashSet<>();
|
||||
// supportedSets.add("PTC"); // Prerelease Events
|
||||
// supportedSets.add("FNMP");
|
||||
supportedSets.add("JR");
|
||||
supportedSets.add("LEA");
|
||||
supportedSets.add("LEB");
|
||||
supportedSets.add("2ED");
|
||||
supportedSets.add("ARN");
|
||||
supportedSets.add("ATQ");
|
||||
supportedSets.add("3ED");
|
||||
supportedSets.add("LEG");
|
||||
supportedSets.add("DRK");
|
||||
supportedSets.add("FEM");
|
||||
supportedSets.add("4ED");
|
||||
supportedSets.add("ICE");
|
||||
supportedSets.add("CHR");
|
||||
supportedSets.add("HML");
|
||||
supportedSets.add("ALL");
|
||||
supportedSets.add("MIR");
|
||||
supportedSets.add("VIS");
|
||||
supportedSets.add("5ED");
|
||||
supportedSets.add("POR");
|
||||
supportedSets.add("WTH");
|
||||
supportedSets.add("TMP");
|
||||
supportedSets.add("STH");
|
||||
supportedSets.add("EXO");
|
||||
supportedSets.add("P02");
|
||||
supportedSets.add("UGL");
|
||||
supportedSets.add("USG");
|
||||
supportedSets.add("DD3DVD");
|
||||
supportedSets.add("DD3EVG");
|
||||
supportedSets.add("DD3GVL");
|
||||
supportedSets.add("DD3JVC");
|
||||
|
||||
supportedSets.add("ULG");
|
||||
supportedSets.add("6ED");
|
||||
supportedSets.add("UDS");
|
||||
supportedSets.add("PTK");
|
||||
supportedSets.add("S99");
|
||||
supportedSets.add("MMQ");
|
||||
// supportedSets.add("BRB");Battle Royale Box Set
|
||||
supportedSets.add("NEM");
|
||||
supportedSets.add("S00");
|
||||
supportedSets.add("PCY");
|
||||
supportedSets.add("INV");
|
||||
// supportedSets.add("BTD"); // Beatdown Boxset
|
||||
supportedSets.add("PLS");
|
||||
supportedSets.add("7ED");
|
||||
supportedSets.add("APC");
|
||||
supportedSets.add("ODY");
|
||||
// supportedSets.add("DKM"); // Deckmasters 2001
|
||||
supportedSets.add("TOR");
|
||||
supportedSets.add("JUD");
|
||||
supportedSets.add("ONS");
|
||||
supportedSets.add("LGN");
|
||||
supportedSets.add("SCG");
|
||||
supportedSets.add("8ED");
|
||||
supportedSets.add("MRD");
|
||||
supportedSets.add("DST");
|
||||
supportedSets.add("5DN");
|
||||
supportedSets.add("CHK");
|
||||
supportedSets.add("UNH");
|
||||
supportedSets.add("BOK");
|
||||
supportedSets.add("SOK");
|
||||
supportedSets.add("9ED");
|
||||
supportedSets.add("RAV");
|
||||
supportedSets.add("GPT");
|
||||
supportedSets.add("DIS");
|
||||
supportedSets.add("CSP");
|
||||
supportedSets.add("TSP");
|
||||
supportedSets.add("TSB");
|
||||
supportedSets.add("PLC");
|
||||
supportedSets.add("FUT");
|
||||
supportedSets.add("10E");
|
||||
supportedSets.add("MED");
|
||||
supportedSets.add("LRW");
|
||||
supportedSets.add("EVG");
|
||||
supportedSets.add("MOR");
|
||||
supportedSets.add("SHM");
|
||||
supportedSets.add("EVE");
|
||||
supportedSets.add("DRB");
|
||||
supportedSets.add("ME2");
|
||||
supportedSets.add("ALA");
|
||||
supportedSets.add("DD2");
|
||||
supportedSets.add("CON");
|
||||
supportedSets.add("DDC");
|
||||
supportedSets.add("ARB");
|
||||
supportedSets.add("M10");
|
||||
// supportedSets.add("TD0"); // Magic Online Deck Series
|
||||
supportedSets.add("V09");
|
||||
supportedSets.add("HOP");
|
||||
supportedSets.add("ME3");
|
||||
supportedSets.add("ZEN");
|
||||
supportedSets.add("DDD");
|
||||
supportedSets.add("H09");
|
||||
supportedSets.add("WWK");
|
||||
supportedSets.add("DDE");
|
||||
supportedSets.add("ROE");
|
||||
supportedSets.add("DPA");
|
||||
supportedSets.add("ARC");
|
||||
supportedSets.add("M11");
|
||||
supportedSets.add("V10");
|
||||
supportedSets.add("DDF");
|
||||
supportedSets.add("SOM");
|
||||
// supportedSets.add("TD0"); // Commander Theme Decks
|
||||
supportedSets.add("PD2");
|
||||
supportedSets.add("ME4");
|
||||
supportedSets.add("MBS");
|
||||
supportedSets.add("DDG");
|
||||
supportedSets.add("NPH");
|
||||
supportedSets.add("CMD");
|
||||
supportedSets.add("M12");
|
||||
supportedSets.add("V11");
|
||||
supportedSets.add("DDH");
|
||||
supportedSets.add("ISD");
|
||||
supportedSets.add("PD3");
|
||||
supportedSets.add("DKA");
|
||||
supportedSets.add("DDI");
|
||||
supportedSets.add("AVR");
|
||||
supportedSets.add("PC2");
|
||||
supportedSets.add("M13");
|
||||
supportedSets.add("V12");
|
||||
supportedSets.add("DDJ");
|
||||
supportedSets.add("RTR");
|
||||
supportedSets.add("CM1");
|
||||
// supportedSets.add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia
|
||||
supportedSets.add("GTC");
|
||||
supportedSets.add("DDK");
|
||||
supportedSets.add("DGM");
|
||||
supportedSets.add("MMA");
|
||||
supportedSets.add("M14");
|
||||
supportedSets.add("V13");
|
||||
supportedSets.add("DDL");
|
||||
supportedSets.add("THS");
|
||||
supportedSets.add("C13");
|
||||
supportedSets.add("BNG");
|
||||
supportedSets.add("DDM");
|
||||
supportedSets.add("JOU");
|
||||
// supportedSets.add("MD1"); // Modern Event Deck
|
||||
supportedSets.add("CNS");
|
||||
supportedSets.add("VMA");
|
||||
supportedSets.add("M15");
|
||||
supportedSets.add("V14");
|
||||
supportedSets.add("DDN");
|
||||
supportedSets.add("KTK");
|
||||
supportedSets.add("C14");
|
||||
// supportedSets.add("DD3"); // Duel Decks Anthology
|
||||
supportedSets.add("FRF");
|
||||
supportedSets.add("DDO");
|
||||
supportedSets.add("DTK");
|
||||
supportedSets.add("TPR");
|
||||
supportedSets.add("MM2");
|
||||
supportedSets.add("ORI");
|
||||
supportedSets.add("V15");
|
||||
supportedSets.add("DDP");
|
||||
supportedSets.add("BFZ");
|
||||
supportedSets.add("EXP");
|
||||
supportedSets.add("C15");
|
||||
// supportedSets.add("PZ1"); // Legendary Cube
|
||||
supportedSets.add("OGW");
|
||||
supportedSets.add("DDQ");
|
||||
supportedSets.add("W16");
|
||||
supportedSets.add("SOI");
|
||||
supportedSets.add("EMA");
|
||||
supportedSets.add("EMN");
|
||||
supportedSets.add("V16");
|
||||
supportedSets.add("CN2");
|
||||
supportedSets.add("DDR");
|
||||
supportedSets.add("KLD");
|
||||
supportedSets.add("MPS");
|
||||
// supportedSets.add("PZ2"); // Treasure Chests
|
||||
supportedSets.add("C16");
|
||||
supportedSets.add("PCA");
|
||||
supportedSets.add("AER");
|
||||
supportedSets.add("MM3");
|
||||
supportedSets.add("DDS");
|
||||
supportedSets.add("W17");
|
||||
supportedSets.add("AKH");
|
||||
supportedSets.add("MPS");
|
||||
supportedSets.add("CMA");
|
||||
supportedSets.add("E01");
|
||||
supportedSets.add("HOU");
|
||||
supportedSets.add("C17");
|
||||
// supportedSets.add("XLN");
|
||||
// supportedSets.add("DDT");
|
||||
// supportedSets.add("IMA");
|
||||
// supportedSets.add("E02");
|
||||
// supportedSets.add("V17");
|
||||
// supportedSets.add("UST");
|
||||
// supportedSets.add("RIX");
|
||||
// supportedSets.add("A25");
|
||||
// supportedSets.add("DOM");
|
||||
// supportedSets.add("M19");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
|
@ -68,10 +269,23 @@ public enum MagidexImageSource implements CardImageSource {
|
|||
}
|
||||
|
||||
// This will properly escape the url
|
||||
URI uri = new URI("http", "magidex.com", "/extstatic/card/" + cardSet + '/' + cardDownloadName + ".jpg", null, null);
|
||||
return uri.toASCIIString();
|
||||
URI uri = new URI("http", "magidex.com", "/extstatic/card/" + formatSetName(cardSet) + '/' + cardDownloadName + ".jpg", null, null);
|
||||
return uri.toASCIIString();
|
||||
}
|
||||
|
||||
private String formatSetName(String setName) {
|
||||
if (setNameReplacement.containsKey(setName)) {
|
||||
setName = setNameReplacement.get(setName);
|
||||
}
|
||||
return setName;
|
||||
}
|
||||
|
||||
private static final Map<String, String> setNameReplacement = new HashMap<String, String>() {
|
||||
{
|
||||
put("JR", "pJGP");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String generateTokenUrl(CardDownloadData card) {
|
||||
return null;
|
||||
|
@ -95,4 +309,11 @@ public enum MagidexImageSource implements CardImageSource {
|
|||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,10 @@
|
|||
*/
|
||||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -377,4 +376,10 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
|
|||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImageProvided(String setCode, String cardName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,9 +35,11 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.prefs.Preferences;
|
||||
|
@ -57,11 +59,12 @@ import org.mage.plugins.card.images.CardDownloadData;
|
|||
public enum MythicspoilerComSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
private Map<String, String> setsAliases;
|
||||
private Map<String, String> cardNameAliases;
|
||||
private Map<String, Set<String>> cardNameAliasesStart;
|
||||
private final Map<String, String> setsAliases;
|
||||
private final Map<String, String> cardNameAliases;
|
||||
private final Map<String, Set<String>> cardNameAliasesStart;
|
||||
private final Map<String, Map<String, String>> sets;
|
||||
|
||||
private final Set<String> supportedSets;
|
||||
private final Map<String, Map<String, String>> manualLinks;
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
|
@ -69,9 +72,192 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
}
|
||||
|
||||
MythicspoilerComSource() {
|
||||
supportedSets = new LinkedHashSet<>();
|
||||
// supportedSets.add("LEA");
|
||||
supportedSets.add("LEB");
|
||||
// supportedSets.add("2ED");
|
||||
supportedSets.add("ARN");
|
||||
supportedSets.add("ATQ");
|
||||
supportedSets.add("3ED");
|
||||
supportedSets.add("LEG");
|
||||
supportedSets.add("DRK");
|
||||
supportedSets.add("FEM");
|
||||
// supportedSets.add("4ED");
|
||||
supportedSets.add("ICE");
|
||||
supportedSets.add("CHR");
|
||||
supportedSets.add("HML");
|
||||
supportedSets.add("ALL");
|
||||
supportedSets.add("MIR");
|
||||
supportedSets.add("VIS");
|
||||
// supportedSets.add("5ED");
|
||||
// supportedSets.add("POR");
|
||||
supportedSets.add("WTH");
|
||||
supportedSets.add("TMP");
|
||||
supportedSets.add("STH");
|
||||
supportedSets.add("EXO");
|
||||
// supportedSets.add("P02");
|
||||
// supportedSets.add("UGL");
|
||||
supportedSets.add("USG");
|
||||
// supportedSets.add("DD3DVD");
|
||||
// supportedSets.add("DD3EVG");
|
||||
// supportedSets.add("DD3GVL");
|
||||
// supportedSets.add("DD3JVC");
|
||||
|
||||
// supportedSets.add("ULG");
|
||||
// supportedSets.add("6ED");
|
||||
supportedSets.add("UDS");
|
||||
supportedSets.add("PTK");
|
||||
// supportedSets.add("S99");
|
||||
supportedSets.add("MMQ");
|
||||
// supportedSets.add("BRB");Battle Royale Box Set
|
||||
supportedSets.add("NEM");
|
||||
// supportedSets.add("S00");
|
||||
supportedSets.add("PCY");
|
||||
supportedSets.add("INV");
|
||||
// supportedSets.add("BTD"); // Beatdown Boxset
|
||||
supportedSets.add("PLS");
|
||||
supportedSets.add("7ED");
|
||||
supportedSets.add("APC");
|
||||
supportedSets.add("ODY");
|
||||
// supportedSets.add("DKM"); // Deckmasters 2001
|
||||
supportedSets.add("TOR");
|
||||
supportedSets.add("JUD");
|
||||
supportedSets.add("ONS");
|
||||
supportedSets.add("LGN");
|
||||
supportedSets.add("SCG");
|
||||
supportedSets.add("8ED");
|
||||
supportedSets.add("MRD");
|
||||
supportedSets.add("DST");
|
||||
supportedSets.add("5DN");
|
||||
supportedSets.add("CHK");
|
||||
supportedSets.add("UNH");
|
||||
supportedSets.add("BOK");
|
||||
supportedSets.add("SOK");
|
||||
supportedSets.add("9ED");
|
||||
supportedSets.add("RAV");
|
||||
supportedSets.add("GPT");
|
||||
supportedSets.add("DIS");
|
||||
supportedSets.add("CSP");
|
||||
supportedSets.add("TSP");
|
||||
supportedSets.add("TSB");
|
||||
supportedSets.add("PLC");
|
||||
supportedSets.add("FUT");
|
||||
supportedSets.add("10E");
|
||||
supportedSets.add("MED");
|
||||
supportedSets.add("LRW");
|
||||
supportedSets.add("EVG");
|
||||
supportedSets.add("MOR");
|
||||
supportedSets.add("SHM");
|
||||
supportedSets.add("EVE");
|
||||
supportedSets.add("DRB");
|
||||
// supportedSets.add("ME2");
|
||||
supportedSets.add("ALA");
|
||||
// supportedSets.add("DD2");
|
||||
supportedSets.add("CON");
|
||||
// supportedSets.add("DDC");
|
||||
supportedSets.add("ARB");
|
||||
supportedSets.add("M10");
|
||||
// supportedSets.add("TD0"); // Magic Online Deck Series
|
||||
// supportedSets.add("V09");
|
||||
supportedSets.add("HOP");
|
||||
// supportedSets.add("ME3");
|
||||
supportedSets.add("ZEN");
|
||||
// supportedSets.add("DDD");
|
||||
supportedSets.add("H09");
|
||||
supportedSets.add("WWK");
|
||||
// supportedSets.add("DDE");
|
||||
supportedSets.add("ROE");
|
||||
supportedSets.add("DPA");
|
||||
supportedSets.add("ARC");
|
||||
supportedSets.add("M11");
|
||||
// supportedSets.add("V10");
|
||||
// supportedSets.add("DDF");
|
||||
supportedSets.add("SOM");
|
||||
// supportedSets.add("TD0"); // Commander Theme Decks
|
||||
// supportedSets.add("PD2");
|
||||
// supportedSets.add("ME4");
|
||||
supportedSets.add("MBS");
|
||||
// supportedSets.add("DDG");
|
||||
supportedSets.add("NPH");
|
||||
supportedSets.add("CMD");
|
||||
supportedSets.add("M12");
|
||||
supportedSets.add("V11");
|
||||
// supportedSets.add("DDH");
|
||||
supportedSets.add("ISD");
|
||||
supportedSets.add("PD3");
|
||||
supportedSets.add("DKA");
|
||||
// supportedSets.add("DDI");
|
||||
supportedSets.add("AVR");
|
||||
// supportedSets.add("PC2");
|
||||
supportedSets.add("M13");
|
||||
// supportedSets.add("V12");
|
||||
// supportedSets.add("DDJ");
|
||||
supportedSets.add("RTR");
|
||||
// supportedSets.add("CM1");
|
||||
// supportedSets.add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia
|
||||
supportedSets.add("GTC");
|
||||
// supportedSets.add("DDK");
|
||||
supportedSets.add("DGM");
|
||||
// supportedSets.add("MMA");
|
||||
supportedSets.add("M14");
|
||||
supportedSets.add("V13");
|
||||
// supportedSets.add("DDL");
|
||||
supportedSets.add("THS");
|
||||
supportedSets.add("C13");
|
||||
supportedSets.add("BNG");
|
||||
// supportedSets.add("DDM");
|
||||
supportedSets.add("JOU");
|
||||
// supportedSets.add("MD1"); // Modern Event Deck
|
||||
// supportedSets.add("CNS");
|
||||
// supportedSets.add("VMA");
|
||||
supportedSets.add("M15");
|
||||
supportedSets.add("V14");
|
||||
supportedSets.add("DDN");
|
||||
supportedSets.add("KTK");
|
||||
supportedSets.add("C14");
|
||||
// supportedSets.add("DD3"); // Duel Decks Anthology
|
||||
supportedSets.add("FRF");
|
||||
// supportedSets.add("DDO");
|
||||
// supportedSets.add("DTK");
|
||||
// supportedSets.add("TPR");
|
||||
supportedSets.add("MM2");
|
||||
supportedSets.add("ORI");
|
||||
// supportedSets.add("V15");
|
||||
// supportedSets.add("DDP");
|
||||
supportedSets.add("BFZ");
|
||||
// supportedSets.add("EXP");
|
||||
supportedSets.add("C15");
|
||||
// supportedSets.add("PZ1"); // Legendary Cube
|
||||
supportedSets.add("OGW");
|
||||
// supportedSets.add("DDQ");
|
||||
// supportedSets.add("W16");
|
||||
supportedSets.add("SOI");
|
||||
supportedSets.add("EMA");
|
||||
supportedSets.add("EMN");
|
||||
// supportedSets.add("V16");
|
||||
supportedSets.add("CN2");
|
||||
// supportedSets.add("DDR");
|
||||
supportedSets.add("KLD");
|
||||
// supportedSets.add("MPS");
|
||||
// supportedSets.add("PZ2");
|
||||
supportedSets.add("C16");
|
||||
// supportedSets.add("PCA");
|
||||
supportedSets.add("AER");
|
||||
supportedSets.add("MM3");
|
||||
// supportedSets.add("W17");
|
||||
supportedSets.add("AKH");
|
||||
supportedSets.add("MPS");
|
||||
supportedSets.add("CMA");
|
||||
supportedSets.add("E01");
|
||||
supportedSets.add("HOU");
|
||||
supportedSets.add("C17");
|
||||
supportedSets.add("IMA");
|
||||
supportedSets.add("XLN");
|
||||
|
||||
sets = new LinkedHashMap<>();
|
||||
setsAliases = new HashMap<>();
|
||||
setsAliases.put("exp", "bfz");
|
||||
setsAliases.put("xln", "ixa");
|
||||
cardNameAliases = new HashMap<>();
|
||||
// set+wrong name from web side => correct card name
|
||||
cardNameAliases.put("MM2-otherwordlyjourney", "otherworldlyjourney");
|
||||
|
@ -88,6 +274,25 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
cardNameAliases.put("AKH-reducerumble", "reducerubble");
|
||||
cardNameAliases.put("AKH-forsakethewordly", "forsaketheworldly");
|
||||
cardNameAliases.put("AKH-kefnatsmonument", "kefnetsmonument");
|
||||
cardNameAliases.put("XLN-kinjaliscaller", "kinjalliscaller");
|
||||
cardNameAliases.put("XLN-lookoutsdecision", "lookoutsdispersal");
|
||||
cardNameAliases.put("XLN-infuriatedgladiodon", "ragingswordtooth");
|
||||
cardNameAliases.put("XLN-redoubledvolley", "repeatingbarrage");
|
||||
|
||||
// <card name, card link>
|
||||
manualLinks = new HashMap<>();
|
||||
HashMap<String, String> links = new HashMap<>();
|
||||
links.put("templeofaclazotz", "templeofaclazotz");
|
||||
links.put("conquerorsfoothold", "conquerorsfoothold");
|
||||
links.put("primalwellspring", "primalwellspring");
|
||||
links.put("azcantathesunkenruin", "azcantathesunkenruin");
|
||||
links.put("spiresoforazca", "spiresoforazca");
|
||||
links.put("treasurecove", "treasurecove");
|
||||
links.put("itlimoccradleofthesun", "itlimoccradleofthesun");
|
||||
links.put("lostvale", "lostvale");
|
||||
links.put("adantothefirstfort", "adantothefirstport");
|
||||
links.put("spitfirebastion", "spitfirebastion");
|
||||
manualLinks.put("XLN", links);
|
||||
|
||||
cardNameAliasesStart = new HashMap<>();
|
||||
HashSet<String> names = new HashSet<>();
|
||||
|
@ -184,7 +389,12 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
pageLinks.put(cardName, baseUrl + cardLink);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> linksToAdd = manualLinks.get(cardSet);
|
||||
if (linksToAdd != null) {
|
||||
for (Map.Entry<String, String> link : linksToAdd.entrySet()) {
|
||||
pageLinks.put(link.getKey(), baseUrl + "cards/" + link.getValue() + ".jpg");
|
||||
}
|
||||
}
|
||||
return pageLinks;
|
||||
}
|
||||
|
||||
|
@ -243,4 +453,12 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,223 @@
|
|||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
/**
|
||||
* @author Quercitron
|
||||
*
|
||||
*/
|
||||
public enum ScryfallImageSource implements CardImageSource {
|
||||
public enum ScryfallImageSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
|
||||
private final Set<String> supportedSets;
|
||||
|
||||
ScryfallImageSource() {
|
||||
supportedSets = new LinkedHashSet<>();
|
||||
// supportedSets.add("PTC"); //
|
||||
supportedSets.add("LEA");
|
||||
supportedSets.add("LEB");
|
||||
supportedSets.add("2ED");
|
||||
supportedSets.add("ARN");
|
||||
supportedSets.add("ATQ");
|
||||
supportedSets.add("3ED");
|
||||
supportedSets.add("LEG");
|
||||
supportedSets.add("DRK");
|
||||
supportedSets.add("FEM");
|
||||
supportedSets.add("4ED");
|
||||
supportedSets.add("ICE");
|
||||
supportedSets.add("CHR");
|
||||
supportedSets.add("HML");
|
||||
supportedSets.add("ALL");
|
||||
supportedSets.add("MIR");
|
||||
supportedSets.add("VIS");
|
||||
supportedSets.add("5ED");
|
||||
supportedSets.add("POR");
|
||||
supportedSets.add("WTH");
|
||||
supportedSets.add("TMP");
|
||||
supportedSets.add("STH");
|
||||
supportedSets.add("EXO");
|
||||
supportedSets.add("P02");
|
||||
supportedSets.add("UGL");
|
||||
supportedSets.add("USG");
|
||||
supportedSets.add("DD3DVD");
|
||||
supportedSets.add("DD3EVG");
|
||||
supportedSets.add("DD3GVL");
|
||||
supportedSets.add("DD3JVC");
|
||||
|
||||
supportedSets.add("ULG");
|
||||
supportedSets.add("6ED");
|
||||
supportedSets.add("UDS");
|
||||
supportedSets.add("PTK");
|
||||
supportedSets.add("S99");
|
||||
supportedSets.add("MMQ");
|
||||
// supportedSets.add("BRB");Battle Royale Box Set
|
||||
supportedSets.add("NEM");
|
||||
supportedSets.add("S00");
|
||||
supportedSets.add("PCY");
|
||||
supportedSets.add("INV");
|
||||
// supportedSets.add("BTD"); // Beatdown Boxset
|
||||
supportedSets.add("PLS");
|
||||
supportedSets.add("7ED");
|
||||
supportedSets.add("APC");
|
||||
supportedSets.add("ODY");
|
||||
// supportedSets.add("DKM"); // Deckmasters 2001
|
||||
supportedSets.add("TOR");
|
||||
supportedSets.add("JUD");
|
||||
supportedSets.add("ONS");
|
||||
supportedSets.add("LGN");
|
||||
supportedSets.add("SCG");
|
||||
supportedSets.add("8ED");
|
||||
supportedSets.add("MRD");
|
||||
supportedSets.add("DST");
|
||||
supportedSets.add("5DN");
|
||||
supportedSets.add("CHK");
|
||||
supportedSets.add("UNH");
|
||||
supportedSets.add("BOK");
|
||||
supportedSets.add("SOK");
|
||||
supportedSets.add("9ED");
|
||||
supportedSets.add("RAV");
|
||||
supportedSets.add("GPT");
|
||||
supportedSets.add("DIS");
|
||||
supportedSets.add("CSP");
|
||||
supportedSets.add("TSP");
|
||||
supportedSets.add("TSB");
|
||||
supportedSets.add("PLC");
|
||||
supportedSets.add("FUT");
|
||||
supportedSets.add("10E");
|
||||
supportedSets.add("MED");
|
||||
supportedSets.add("LRW");
|
||||
supportedSets.add("EVG");
|
||||
supportedSets.add("MOR");
|
||||
supportedSets.add("SHM");
|
||||
supportedSets.add("EVE");
|
||||
supportedSets.add("DRB");
|
||||
supportedSets.add("ME2");
|
||||
supportedSets.add("ALA");
|
||||
supportedSets.add("DD2");
|
||||
supportedSets.add("CON");
|
||||
supportedSets.add("DDC");
|
||||
supportedSets.add("ARB");
|
||||
supportedSets.add("M10");
|
||||
// supportedSets.add("TD0"); // Magic Online Deck Series
|
||||
supportedSets.add("V09");
|
||||
supportedSets.add("HOP");
|
||||
supportedSets.add("ME3");
|
||||
supportedSets.add("ZEN");
|
||||
supportedSets.add("DDD");
|
||||
supportedSets.add("H09");
|
||||
supportedSets.add("WWK");
|
||||
supportedSets.add("DDE");
|
||||
supportedSets.add("ROE");
|
||||
supportedSets.add("DPA");
|
||||
supportedSets.add("ARC");
|
||||
supportedSets.add("M11");
|
||||
supportedSets.add("V10");
|
||||
supportedSets.add("DDF");
|
||||
supportedSets.add("SOM");
|
||||
// supportedSets.add("TD0"); // Commander Theme Decks
|
||||
supportedSets.add("PD2");
|
||||
supportedSets.add("ME4");
|
||||
supportedSets.add("MBS");
|
||||
supportedSets.add("DDG");
|
||||
supportedSets.add("NPH");
|
||||
supportedSets.add("CMD");
|
||||
supportedSets.add("M12");
|
||||
supportedSets.add("V11");
|
||||
supportedSets.add("DDH");
|
||||
supportedSets.add("ISD");
|
||||
supportedSets.add("PD3");
|
||||
supportedSets.add("DKA");
|
||||
supportedSets.add("DDI");
|
||||
supportedSets.add("AVR");
|
||||
supportedSets.add("PC2");
|
||||
supportedSets.add("M13");
|
||||
supportedSets.add("V12");
|
||||
supportedSets.add("DDJ");
|
||||
supportedSets.add("RTR");
|
||||
supportedSets.add("CM1");
|
||||
// supportedSets.add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia
|
||||
supportedSets.add("GTC");
|
||||
supportedSets.add("DDK");
|
||||
supportedSets.add("DGM");
|
||||
supportedSets.add("MMA");
|
||||
supportedSets.add("M14");
|
||||
supportedSets.add("V13");
|
||||
supportedSets.add("DDL");
|
||||
supportedSets.add("THS");
|
||||
supportedSets.add("C13");
|
||||
supportedSets.add("BNG");
|
||||
supportedSets.add("DDM");
|
||||
supportedSets.add("JOU");
|
||||
// supportedSets.add("MD1"); // Modern Event Deck
|
||||
supportedSets.add("CNS");
|
||||
supportedSets.add("VMA");
|
||||
supportedSets.add("M15");
|
||||
supportedSets.add("V14");
|
||||
supportedSets.add("DDN");
|
||||
supportedSets.add("KTK");
|
||||
supportedSets.add("C14");
|
||||
// supportedSets.add("DD3"); // Duel Decks Anthology
|
||||
supportedSets.add("FRF");
|
||||
supportedSets.add("DDO");
|
||||
supportedSets.add("DTK");
|
||||
supportedSets.add("TPR");
|
||||
supportedSets.add("MM2");
|
||||
supportedSets.add("ORI");
|
||||
supportedSets.add("V15");
|
||||
supportedSets.add("DDP");
|
||||
supportedSets.add("BFZ");
|
||||
supportedSets.add("EXP");
|
||||
supportedSets.add("C15");
|
||||
// supportedSets.add("PZ1"); // Legendary Cube
|
||||
supportedSets.add("OGW");
|
||||
supportedSets.add("DDQ");
|
||||
supportedSets.add("W16");
|
||||
supportedSets.add("SOI");
|
||||
supportedSets.add("EMA");
|
||||
supportedSets.add("EMN");
|
||||
supportedSets.add("V16");
|
||||
supportedSets.add("CN2");
|
||||
supportedSets.add("DDR");
|
||||
supportedSets.add("KLD");
|
||||
supportedSets.add("MPS");
|
||||
// supportedSets.add("PZ2");
|
||||
supportedSets.add("C16");
|
||||
supportedSets.add("PCA");
|
||||
supportedSets.add("AER");
|
||||
supportedSets.add("MM3");
|
||||
supportedSets.add("DDS");
|
||||
supportedSets.add("W17");
|
||||
supportedSets.add("AKH");
|
||||
supportedSets.add("MPS");
|
||||
supportedSets.add("CMA");
|
||||
supportedSets.add("E01");
|
||||
supportedSets.add("HOU");
|
||||
supportedSets.add("C17");
|
||||
supportedSets.add("XLN");
|
||||
// supportedSets.add("DDT");
|
||||
supportedSets.add("IMA");
|
||||
// supportedSets.add("E02");
|
||||
// supportedSets.add("V17");
|
||||
// supportedSets.add("UST");
|
||||
// supportedSets.add("RIX");
|
||||
// supportedSets.add("A25");
|
||||
// supportedSets.add("DOM");
|
||||
// supportedSets.add("M19");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateURL(CardDownloadData card) throws Exception {
|
||||
return "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/" + card.getCollectorId() + "?format=image";
|
||||
return "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
|
||||
+ card.getCollectorId()
|
||||
+ (card.isSecondSide() ? "b" : "")
|
||||
+ "?format=image";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,7 +242,7 @@ public enum ScryfallImageSource implements CardImageSource {
|
|||
|
||||
@Override
|
||||
public float getAverageSize() {
|
||||
return 240;
|
||||
return 90;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,4 +277,11 @@ public enum ScryfallImageSource implements CardImageSource {
|
|||
put("MBP", "pmei");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
*/
|
||||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -37,8 +34,14 @@ import java.io.InputStreamReader;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
import org.mage.plugins.card.images.DownloadPictures;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -46,11 +49,12 @@ import java.util.Map;
|
|||
*/
|
||||
public enum TokensMtgImageSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
instance;
|
||||
private static final Logger logger = Logger.getLogger(TokensMtgImageSource.class);
|
||||
|
||||
|
||||
private List<TokenData> tokensData;
|
||||
// [[EXP/Name, TokenData>
|
||||
private HashMap<String, ArrayList<TokenData>> tokensData;
|
||||
private static final Set<String> supportedSets = new LinkedHashSet<String>();
|
||||
|
||||
private final Object tokensDataSync = new Object();
|
||||
|
||||
|
@ -100,7 +104,12 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
"Sorin",
|
||||
"Tamiyo",
|
||||
"Teferi",
|
||||
"Venser",};
|
||||
"Venser",
|
||||
// Custom Emblems
|
||||
"Yoda",
|
||||
"Obi-Wan Kenobi",
|
||||
"Aurra Sing"
|
||||
};
|
||||
|
||||
private static final Map<String, String> SET_NAMES_REPLACEMENT = new HashMap<String, String>() {
|
||||
{
|
||||
|
@ -134,36 +143,31 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
// e.g. http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg -- token number 010
|
||||
// We don't know these numbers, but we can take them from a file
|
||||
// with tokens information that can be downloaded from the site.
|
||||
List<TokenData> newTokensData = getTokensData();
|
||||
|
||||
if (newTokensData.isEmpty()) {
|
||||
if (tokensData.isEmpty()) {
|
||||
logger.info("Source " + getSourceName() + " provides no token data.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<TokenData> matchedTokens = new ArrayList<>();
|
||||
for (TokenData token : newTokensData) {
|
||||
if (name.equalsIgnoreCase(token.getName()) && set.equalsIgnoreCase(token.getExpansionSetCode())) {
|
||||
matchedTokens.add(token);
|
||||
}
|
||||
String key = set + "/" + name;
|
||||
List<TokenData> list = tokensData.get(key);
|
||||
if (list == null) {
|
||||
logger.info("Could not find data for token " + name + ", set " + set + ".");
|
||||
return null;
|
||||
}
|
||||
//
|
||||
// if (matchedTokens.isEmpty()) {
|
||||
// logger.info("Could not find data for token " + name + ", set " + set + ".");
|
||||
// return null;
|
||||
// }
|
||||
|
||||
TokenData tokenData;
|
||||
if (type == 0) {
|
||||
if (matchedTokens.size() > 1) {
|
||||
if (list.size() > 1) {
|
||||
logger.info("Multiple images were found for token " + name + ", set " + set + '.');
|
||||
}
|
||||
tokenData = matchedTokens.get(0);
|
||||
logger.info("Token found: " + name + ", set " + set + '.');
|
||||
tokenData = list.get(0);
|
||||
} else {
|
||||
if (type > matchedTokens.size()) {
|
||||
if (type > list.size()) {
|
||||
logger.warn("Not enough images for token with type " + type + ", name " + name + ", set " + set + '.');
|
||||
return null;
|
||||
}
|
||||
tokenData = matchedTokens.get(card.getType() - 1);
|
||||
tokenData = list.get(card.getType() - 1);
|
||||
}
|
||||
|
||||
String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_'
|
||||
|
@ -172,15 +176,26 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
return url;
|
||||
}
|
||||
|
||||
private List<TokenData> getTokensData() throws IOException {
|
||||
private HashMap<String, ArrayList<TokenData>> getTokensData() throws IOException {
|
||||
synchronized (tokensDataSync) {
|
||||
if (tokensData == null) {
|
||||
tokensData = new ArrayList<>();
|
||||
DownloadPictures.getInstance().updateAndViewMessage("Creating token data...");
|
||||
tokensData = new HashMap<>();
|
||||
|
||||
// get tokens data from resource file
|
||||
try(InputStream inputStream = this.getClass().getResourceAsStream("/tokens-mtg-onl-list.csv")) {
|
||||
try (InputStream inputStream = this.getClass().getResourceAsStream("/tokens-mtg-onl-list.csv")) {
|
||||
List<TokenData> fileTokensData = parseTokensData(inputStream);
|
||||
tokensData.addAll(fileTokensData);
|
||||
for (TokenData tokenData : fileTokensData) {
|
||||
String key = tokenData.getExpansionSetCode() + "/" + tokenData.getName();
|
||||
ArrayList<TokenData> list = tokensData.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
tokensData.put(key, list);
|
||||
supportedSets.add(tokenData.getExpansionSetCode());
|
||||
logger.info("Added key: " + key);
|
||||
}
|
||||
list.add(tokenData);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
logger.warn("Failed to get tokens description from resource file tokens-mtg-onl-list.csv", exception);
|
||||
}
|
||||
|
@ -188,27 +203,33 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
// description on site may contain new information
|
||||
// try to add it
|
||||
URL url = new URL("http://tokens.mtg.onl/data/SetsWithTokens.csv");
|
||||
try(InputStream inputStream = url.openStream()) {
|
||||
try (InputStream inputStream = url.openStream()) {
|
||||
List<TokenData> siteTokensData = parseTokensData(inputStream);
|
||||
List<TokenData> newTokensData = new ArrayList<>();
|
||||
for (TokenData siteData : siteTokensData) {
|
||||
boolean isNew = true;
|
||||
for (TokenData fileData : tokensData) {
|
||||
if (siteData.getName().equalsIgnoreCase(fileData.getName())
|
||||
&& siteData.getNumber().equalsIgnoreCase(fileData.getNumber())
|
||||
&& siteData.getExpansionSetCode().equalsIgnoreCase(fileData.getExpansionSetCode())) {
|
||||
isNew = false;
|
||||
break;
|
||||
String key = siteData.getExpansionSetCode() + "/" + siteData.getName();
|
||||
supportedSets.add(siteData.getExpansionSetCode());
|
||||
ArrayList<TokenData> list = tokensData.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
tokensData.put(key, list);
|
||||
list.add(siteData);
|
||||
} else {
|
||||
boolean newToken = true;
|
||||
for (TokenData tokenData : list) {
|
||||
if (siteData.getNumber().equals(tokenData.number)) {
|
||||
newToken = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newToken) {
|
||||
list.add(siteData);
|
||||
}
|
||||
}
|
||||
if (isNew) {
|
||||
newTokensData.add(siteData);
|
||||
}
|
||||
}
|
||||
|
||||
tokensData.addAll(newTokensData);
|
||||
} catch (Exception exception) {
|
||||
logger.warn("Failed to get tokens description from tokens.mtg.onl", exception);
|
||||
DownloadPictures.getInstance().updateAndViewMessage("");
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Failed to get tokens description from tokens.mtg.onl", ex);
|
||||
DownloadPictures.getInstance().updateAndViewMessage(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,8 +240,8 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
private List<TokenData> parseTokensData(InputStream inputStream) throws IOException {
|
||||
List<TokenData> newTokensData = new ArrayList<>();
|
||||
|
||||
try(InputStreamReader inputReader = new InputStreamReader(inputStream, "Cp1252");
|
||||
BufferedReader reader = new BufferedReader(inputReader)) {
|
||||
try (InputStreamReader inputReader = new InputStreamReader(inputStream, "Cp1252");
|
||||
BufferedReader reader = new BufferedReader(inputReader)) {
|
||||
// we have to specify encoding to read special comma
|
||||
|
||||
reader.readLine(); // skip header
|
||||
|
@ -285,7 +306,17 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
|
||||
@Override
|
||||
public int getTotalImages() {
|
||||
return -1;
|
||||
return getTokenImages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTokenImages() {
|
||||
try {
|
||||
getTokensData();
|
||||
} catch (IOException ex) {
|
||||
logger.error(getSourceName() + ": Loading available data failed. " + ex.getMessage());
|
||||
}
|
||||
return tokensData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -296,4 +327,28 @@ public enum TokensMtgImageSource implements CardImageSource {
|
|||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImageProvided(String setCode, String cardName) {
|
||||
try {
|
||||
getTokensData();
|
||||
} catch (IOException ex) {
|
||||
java.util.logging.Logger.getLogger(TokensMtgImageSource.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
String key = setCode + "/" + cardName;
|
||||
return (tokensData.containsKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSetSupportedComplete(String setCode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,10 +34,13 @@ import java.net.HttpURLConnection;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -46,6 +49,7 @@ import mage.client.MageFrame;
|
|||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.remote.Connection;
|
||||
import mage.remote.Connection.ProxyType;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
@ -58,10 +62,13 @@ import org.mage.plugins.card.images.CardDownloadData;
|
|||
public enum WizardCardsImageSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
private Map<String, String> setsAliases;
|
||||
private Map<String, String> languageAliases;
|
||||
private final Map<String, Map<String, String>> sets;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(WizardCardsImageSource.class);
|
||||
|
||||
private final Map<String, String> setsAliases;
|
||||
private final Map<String, String> languageAliases;
|
||||
private final Map<String, Map<String, String>> sets;
|
||||
private final Set<String> supportedSets;
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
|
@ -69,6 +76,198 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
}
|
||||
|
||||
WizardCardsImageSource() {
|
||||
supportedSets = new LinkedHashSet<>();
|
||||
// supportedSets.add("PTC"); // Prerelease Events
|
||||
supportedSets.add("LEA");
|
||||
supportedSets.add("LEB");
|
||||
supportedSets.add("2ED");
|
||||
supportedSets.add("ARN");
|
||||
supportedSets.add("ATQ");
|
||||
supportedSets.add("3ED");
|
||||
supportedSets.add("LEG");
|
||||
supportedSets.add("DRK");
|
||||
supportedSets.add("FEM");
|
||||
supportedSets.add("4ED");
|
||||
supportedSets.add("ICE");
|
||||
supportedSets.add("CHR");
|
||||
supportedSets.add("HML");
|
||||
supportedSets.add("ALL");
|
||||
supportedSets.add("MIR");
|
||||
supportedSets.add("VIS");
|
||||
supportedSets.add("5ED");
|
||||
supportedSets.add("POR");
|
||||
supportedSets.add("WTH");
|
||||
supportedSets.add("TMP");
|
||||
supportedSets.add("STH");
|
||||
supportedSets.add("EXO");
|
||||
supportedSets.add("P02");
|
||||
supportedSets.add("UGL");
|
||||
supportedSets.add("USG");
|
||||
supportedSets.add("DD3DVD");
|
||||
supportedSets.add("DD3EVG");
|
||||
supportedSets.add("DD3GVL");
|
||||
supportedSets.add("DD3JVC");
|
||||
|
||||
supportedSets.add("ULG");
|
||||
supportedSets.add("6ED");
|
||||
supportedSets.add("UDS");
|
||||
supportedSets.add("PTK");
|
||||
supportedSets.add("S99");
|
||||
supportedSets.add("MMQ");
|
||||
// supportedSets.add("BRB");Battle Royale Box Set
|
||||
supportedSets.add("NEM");
|
||||
supportedSets.add("S00");
|
||||
supportedSets.add("PCY");
|
||||
supportedSets.add("INV");
|
||||
// supportedSets.add("BTD"); // Beatdown Boxset
|
||||
supportedSets.add("PLS");
|
||||
supportedSets.add("7ED");
|
||||
supportedSets.add("APC");
|
||||
supportedSets.add("ODY");
|
||||
// supportedSets.add("DKM"); // Deckmasters 2001
|
||||
supportedSets.add("TOR");
|
||||
supportedSets.add("JUD");
|
||||
supportedSets.add("ONS");
|
||||
supportedSets.add("LGN");
|
||||
supportedSets.add("SCG");
|
||||
supportedSets.add("8ED");
|
||||
supportedSets.add("MRD");
|
||||
supportedSets.add("DST");
|
||||
supportedSets.add("5DN");
|
||||
supportedSets.add("CHK");
|
||||
supportedSets.add("UNH");
|
||||
supportedSets.add("BOK");
|
||||
supportedSets.add("SOK");
|
||||
supportedSets.add("9ED");
|
||||
supportedSets.add("RAV");
|
||||
supportedSets.add("GPT");
|
||||
supportedSets.add("DIS");
|
||||
supportedSets.add("CSP");
|
||||
supportedSets.add("TSP");
|
||||
supportedSets.add("TSB");
|
||||
supportedSets.add("PLC");
|
||||
supportedSets.add("FUT");
|
||||
supportedSets.add("10E");
|
||||
supportedSets.add("MED");
|
||||
supportedSets.add("LRW");
|
||||
supportedSets.add("EVG");
|
||||
supportedSets.add("MOR");
|
||||
supportedSets.add("SHM");
|
||||
supportedSets.add("EVE");
|
||||
supportedSets.add("DRB");
|
||||
supportedSets.add("ME2");
|
||||
supportedSets.add("ALA");
|
||||
supportedSets.add("DD2");
|
||||
supportedSets.add("CON");
|
||||
supportedSets.add("DDC");
|
||||
supportedSets.add("ARB");
|
||||
supportedSets.add("M10");
|
||||
// supportedSets.add("TD0"); // Magic Online Deck Series
|
||||
supportedSets.add("V09");
|
||||
supportedSets.add("HOP");
|
||||
supportedSets.add("ME3");
|
||||
supportedSets.add("ZEN");
|
||||
supportedSets.add("DDD");
|
||||
supportedSets.add("H09");
|
||||
supportedSets.add("WWK");
|
||||
supportedSets.add("DDE");
|
||||
supportedSets.add("ROE");
|
||||
supportedSets.add("DPA");
|
||||
supportedSets.add("ARC");
|
||||
supportedSets.add("M11");
|
||||
supportedSets.add("V10");
|
||||
supportedSets.add("DDF");
|
||||
supportedSets.add("SOM");
|
||||
// supportedSets.add("TD0"); // Commander Theme Decks
|
||||
supportedSets.add("PD2");
|
||||
supportedSets.add("ME4");
|
||||
supportedSets.add("MBS");
|
||||
supportedSets.add("DDG");
|
||||
supportedSets.add("NPH");
|
||||
supportedSets.add("CMD");
|
||||
supportedSets.add("M12");
|
||||
supportedSets.add("V11");
|
||||
supportedSets.add("DDH");
|
||||
supportedSets.add("ISD");
|
||||
supportedSets.add("PD3");
|
||||
supportedSets.add("DKA");
|
||||
supportedSets.add("DDI");
|
||||
supportedSets.add("AVR");
|
||||
supportedSets.add("PC2");
|
||||
supportedSets.add("M13");
|
||||
supportedSets.add("V12");
|
||||
supportedSets.add("DDJ");
|
||||
supportedSets.add("RTR");
|
||||
supportedSets.add("CM1");
|
||||
// supportedSets.add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia
|
||||
supportedSets.add("GTC");
|
||||
supportedSets.add("DDK");
|
||||
supportedSets.add("DGM");
|
||||
supportedSets.add("MMA");
|
||||
supportedSets.add("M14");
|
||||
supportedSets.add("V13");
|
||||
supportedSets.add("DDL");
|
||||
supportedSets.add("THS");
|
||||
supportedSets.add("C13");
|
||||
supportedSets.add("BNG");
|
||||
supportedSets.add("DDM");
|
||||
supportedSets.add("JOU");
|
||||
// supportedSets.add("MD1"); // Modern Event Deck
|
||||
supportedSets.add("CNS");
|
||||
supportedSets.add("VMA");
|
||||
supportedSets.add("M15");
|
||||
supportedSets.add("V14");
|
||||
supportedSets.add("DDN");
|
||||
supportedSets.add("KTK");
|
||||
supportedSets.add("C14");
|
||||
// supportedSets.add("DD3"); // Duel Decks Anthology
|
||||
supportedSets.add("FRF");
|
||||
supportedSets.add("DDO");
|
||||
supportedSets.add("DTK");
|
||||
supportedSets.add("TPR");
|
||||
supportedSets.add("MM2");
|
||||
supportedSets.add("ORI");
|
||||
supportedSets.add("V15");
|
||||
supportedSets.add("DDP");
|
||||
supportedSets.add("BFZ");
|
||||
supportedSets.add("EXP");
|
||||
supportedSets.add("C15");
|
||||
// supportedSets.add("PZ1"); // Legendary Cube
|
||||
supportedSets.add("OGW");
|
||||
supportedSets.add("DDQ");
|
||||
supportedSets.add("W16");
|
||||
supportedSets.add("SOI");
|
||||
supportedSets.add("EMA");
|
||||
supportedSets.add("EMN");
|
||||
supportedSets.add("V16");
|
||||
supportedSets.add("CN2");
|
||||
supportedSets.add("DDR");
|
||||
supportedSets.add("KLD");
|
||||
supportedSets.add("MPS");
|
||||
// supportedSets.add("PZ2"); // Treasure Chests
|
||||
supportedSets.add("C16");
|
||||
supportedSets.add("PCA");
|
||||
supportedSets.add("AER");
|
||||
supportedSets.add("MM3");
|
||||
supportedSets.add("DDS");
|
||||
supportedSets.add("W17");
|
||||
supportedSets.add("AKH");
|
||||
supportedSets.add("MPS");
|
||||
supportedSets.add("CMA");
|
||||
supportedSets.add("E01");
|
||||
supportedSets.add("HOU");
|
||||
supportedSets.add("C17");
|
||||
supportedSets.add("XLN");
|
||||
// supportedSets.add("DDT"); // Duel Decks: Merfolk vs. Goblins
|
||||
// supportedSets.add("IMA"); // Iconic Msters
|
||||
// supportedSets.add("E02"); // Explorers of Ixalan
|
||||
// supportedSets.add("V17"); // From the Vault: Transform
|
||||
// supportedSets.add("UST"); // Unstable
|
||||
// supportedSets.add("RIX"); // Rivals of Ixalan
|
||||
// supportedSets.add("A25"); // Masters 25
|
||||
// supportedSets.add("DOM"); // Dominaria
|
||||
// supportedSets.add("M19"); // Core 2019
|
||||
|
||||
sets = new HashMap<>();
|
||||
setsAliases = new HashMap<>();
|
||||
setsAliases.put("2ED", "Unlimited Edition");
|
||||
|
@ -102,6 +301,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
setsAliases.put("C14", "Commander 2014");
|
||||
setsAliases.put("C15", "Commander 2015");
|
||||
setsAliases.put("C16", "Commander 2016");
|
||||
setsAliases.put("C17", "Commander 2017");
|
||||
setsAliases.put("CMA", "Commander Anthology");
|
||||
setsAliases.put("CHK", "Champions of Kamigawa");
|
||||
setsAliases.put("CHR", "Chronicles");
|
||||
|
@ -140,6 +340,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
setsAliases.put("DRK", "The Dark");
|
||||
setsAliases.put("DST", "Darksteel");
|
||||
setsAliases.put("DTK", "Dragons of Tarkir");
|
||||
setsAliases.put("E01", "Archenemy: Nicol Bolas");
|
||||
setsAliases.put("EMN", "Eldritch Moon");
|
||||
setsAliases.put("EMA", "Eternal Masters");
|
||||
setsAliases.put("EVE", "Eventide");
|
||||
|
@ -272,18 +473,20 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
}
|
||||
|
||||
private Map<String, String> getSetLinks(String cardSet) {
|
||||
ConcurrentHashMap<String, String> setLinks = new ConcurrentHashMap<>();
|
||||
LinkedHashMap<String, String> setLinks = new LinkedHashMap<>();
|
||||
ExecutorService executor = Executors.newFixedThreadPool(10);
|
||||
try {
|
||||
String setNames = setsAliases.get(cardSet);
|
||||
String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
|
||||
for (String setName : setNames.split("\\^")) {
|
||||
String URLSetName = URLEncoder.encode(setName, "UTF-8");
|
||||
// String URLSetName = URLEncoder.encode(setName, "UTF-8");
|
||||
String URLSetName = setName.replaceAll(" ", "%20");
|
||||
int page = 0;
|
||||
int firstMultiverseIdLastPage = 0;
|
||||
Pages:
|
||||
while (page < 999) {
|
||||
String searchUrl = "http://gatherer.wizards.com/Pages/Search/Default.aspx?page=" + page + "&output=spoiler&method=visual&action=advanced&set=+[%22" + URLSetName + "%22]";
|
||||
String searchUrl = "http://gatherer.wizards.com/Pages/Search/Default.aspx?sort=cn+&page=" + page + "&action=advanced&output=spoiler&method=visual&set=+%5B%22" + URLSetName + "%22%5D";
|
||||
logger.debug("URL: " + searchUrl);
|
||||
Document doc = getDocument(searchUrl);
|
||||
Elements cardsImages = doc.select("img[src^=../../Handlers/]");
|
||||
if (cardsImages.isEmpty()) {
|
||||
|
@ -307,7 +510,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Exception when parsing the wizards page: " + ex.getMessage());
|
||||
logger.error("Exception when parsing the wizards page: " + ex.getMessage());
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
|
@ -327,14 +530,15 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None"));
|
||||
Document doc;
|
||||
if (proxyType == ProxyType.NONE) {
|
||||
doc = Jsoup.connect(urlString).get();
|
||||
doc = Jsoup.connect(urlString).timeout(60 * 1000).get();
|
||||
} else {
|
||||
String proxyServer = prefs.get("proxyAddress", "");
|
||||
int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0"));
|
||||
URL url = new URL(urlString);
|
||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, proxyPort));
|
||||
HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy);
|
||||
|
||||
uc.setConnectTimeout(10000);
|
||||
uc.setReadTimeout(60000);
|
||||
uc.connect();
|
||||
|
||||
String line;
|
||||
|
@ -356,7 +560,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
if (!variations.isEmpty()) {
|
||||
int landNumber = 1;
|
||||
for (Element variation : variations) {
|
||||
Integer landMultiverseId = Integer.parseInt(variation.attr("onclick").replaceAll("[^\\d]", ""));
|
||||
Integer landMultiverseId = Integer.parseInt(variation.attr("href").replaceAll("[^\\d]", ""));
|
||||
links.put((cardName + landNumber).toLowerCase(), generateLink(landMultiverseId));
|
||||
landNumber++;
|
||||
}
|
||||
|
@ -435,6 +639,9 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
String setNames = setsAliases.get(cardSet);
|
||||
if (setNames != null) {
|
||||
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
|
||||
if (setLinks == null || setLinks.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String link = setLinks.get(card.getDownloadName().toLowerCase());
|
||||
if (link == null) {
|
||||
int length = collectorId.length();
|
||||
|
@ -444,11 +651,11 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
}
|
||||
|
||||
int number = Integer.parseInt(collectorId.substring(0, length));
|
||||
|
||||
if (setLinks.size() >= number) {
|
||||
link = setLinks.get(Integer.toString(number - 1));
|
||||
} else {
|
||||
link = setLinks.get(Integer.toString(number - 21));
|
||||
List<String> l = new ArrayList<>(setLinks.values());
|
||||
if (l.size() >= number) {
|
||||
link = l.get(number - 1);
|
||||
} else {;
|
||||
link = l.get(number - 21);
|
||||
if (link != null) {
|
||||
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
|
||||
}
|
||||
|
@ -460,6 +667,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
return link;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -474,16 +682,24 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
|
||||
private final class GetImageLinkTask implements Runnable {
|
||||
|
||||
private final int multiverseId;
|
||||
private final String cardName;
|
||||
private final String preferedLanguage;
|
||||
private final ConcurrentHashMap setLinks;
|
||||
private int multiverseId;
|
||||
private String cardName;
|
||||
private String preferedLanguage;
|
||||
private LinkedHashMap setLinks;
|
||||
|
||||
public GetImageLinkTask(int multiverseId, String cardName, String preferedLanguage, ConcurrentHashMap setLinks) {
|
||||
this.multiverseId = multiverseId;
|
||||
this.cardName = cardName;
|
||||
this.preferedLanguage = preferedLanguage;
|
||||
this.setLinks = setLinks;
|
||||
public GetImageLinkTask(int multiverseId, String cardName, String preferedLanguage, LinkedHashMap setLinks) {
|
||||
try {
|
||||
this.multiverseId = multiverseId;
|
||||
this.cardName = cardName;
|
||||
this.preferedLanguage = preferedLanguage;
|
||||
this.setLinks = setLinks;
|
||||
} catch (Exception ex) {
|
||||
logger.error(ex.getMessage());
|
||||
logger.error("multiverseId: " + multiverseId);
|
||||
logger.error("cardName: " + cardName);
|
||||
logger.error("preferedLanguage: " + preferedLanguage);
|
||||
logger.error("setLinks: " + setLinks.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -496,7 +712,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
setLinks.put(cardName.toLowerCase(), generateLink(preferedMultiverseId));
|
||||
}
|
||||
} catch (IOException | NumberFormatException ex) {
|
||||
System.out.println("Exception when parsing the wizards page: " + ex.getMessage());
|
||||
logger.error("Exception when parsing the wizards page: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,4 +731,12 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class CardDownloadData {
|
|||
}
|
||||
|
||||
public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor, boolean token, boolean twoFacedCard, boolean secondSide) {
|
||||
this(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor, token, false, false, "");
|
||||
this(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor, token, twoFacedCard, secondSide, "");
|
||||
}
|
||||
|
||||
public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor, boolean token, boolean twoFacedCard, boolean secondSide, String tokenClassName) {
|
||||
|
@ -72,7 +72,7 @@ public class CardDownloadData {
|
|||
this.usesVariousArt = card.usesVariousArt;
|
||||
this.tokenSetCode = card.tokenSetCode;
|
||||
this.tokenDescriptor = card.tokenDescriptor;
|
||||
this.tokenClassName = tokenClassName;
|
||||
this.tokenClassName = card.tokenClassName;
|
||||
this.fileName = card.fileName;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mage.plugins.card.images;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
@ -14,18 +15,25 @@ import java.util.Set;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.FileImageOutputStream;
|
||||
import javax.swing.*;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.constants.Constants;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.client.util.sets.ConstructedFormats;
|
||||
import mage.remote.Connection;
|
||||
import static mage.remote.Connection.ProxyType.HTTP;
|
||||
import static mage.remote.Connection.ProxyType.NONE;
|
||||
import static mage.remote.Connection.ProxyType.SOCKS;
|
||||
import net.java.truevfs.access.TFile;
|
||||
import net.java.truevfs.access.TFileOutputStream;
|
||||
import net.java.truevfs.access.TVFS;
|
||||
|
@ -37,51 +45,97 @@ import org.mage.plugins.card.utils.CardImageUtils;
|
|||
|
||||
public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable {
|
||||
|
||||
private static DownloadPictures instance;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DownloadPictures.class);
|
||||
|
||||
public static final String ALL_IMAGES = "- All images from that source";
|
||||
public static final String ALL_STANDARD_IMAGES = "- All images from standard from that source";
|
||||
public static final String ALL_TOKENS = "- Only all token images from that source";
|
||||
|
||||
private JDialog dialog;
|
||||
private final JProgressBar bar;
|
||||
private final JOptionPane dlg;
|
||||
private boolean cancel;
|
||||
private final JButton closeButton;
|
||||
private final JButton startDownloadButton;
|
||||
private int cardIndex;
|
||||
private List<CardDownloadData> cards;
|
||||
private List<CardDownloadData> type2cards;
|
||||
private final JComboBox jComboBox1;
|
||||
private final JLabel jLabel1;
|
||||
private static boolean offlineMode = false;
|
||||
private JCheckBox checkBox;
|
||||
private List<CardDownloadData> allCardsMissingImage;
|
||||
private List<CardDownloadData> cardsToDownload;
|
||||
|
||||
private int missingCards = 0;
|
||||
private int missingTokens = 0;
|
||||
|
||||
List<String> selectedSetCodes = new ArrayList<>();
|
||||
|
||||
private final JComboBox jComboBoxServer;
|
||||
private final JLabel jLabelMessage;
|
||||
private final JLabel jLabelAllMissing;
|
||||
private final JLabel jLabelServer;
|
||||
|
||||
private final JComboBox jComboBoxSet;
|
||||
private final JLabel jLabelSet;
|
||||
|
||||
private final Object sync = new Object();
|
||||
|
||||
private static CardImageSource cardImageSource;
|
||||
|
||||
private Proxy p = Proxy.NO_PROXY;
|
||||
|
||||
// private ExecutorService executor = Executors.newFixedThreadPool(10);
|
||||
public static void main(String[] args) {
|
||||
startDownload(null, null);
|
||||
enum DownloadSources {
|
||||
WIZARDS("wizards.com", WizardCardsImageSource.instance),
|
||||
MYTHICSPOILER("mythicspoiler.com", MythicspoilerComSource.instance),
|
||||
TOKENS("tokens.mtg.onl", TokensMtgImageSource.instance),
|
||||
// MTG_ONL("mtg.onl", MtgOnlTokensImageSource.instance), Not working correctly yet
|
||||
ALTERNATIVE("alternative.mtg.onl", AltMtgOnlTokensImageSource.instance),
|
||||
GRAB_BAG("GrabBag", GrabbagImageSource.instance),
|
||||
MAGIDEX("magidex.com", MagidexImageSource.instance),
|
||||
SCRYFALL("scryfall.com", ScryfallImageSource.instance);
|
||||
// MAGICCARDS("magiccards.info", MagicCardsImageSource.instance)
|
||||
|
||||
private final String text;
|
||||
private final CardImageSource source;
|
||||
|
||||
DownloadSources(String text, CardImageSource sourceInstance) {
|
||||
this.text = text;
|
||||
this.source = sourceInstance;
|
||||
}
|
||||
|
||||
public CardImageSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void startDownload(JFrame frame, List<CardInfo> allCards) {
|
||||
List<CardDownloadData> cards = getNeededCards(allCards);
|
||||
public static DownloadPictures getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
startDownload();
|
||||
}
|
||||
|
||||
public static void startDownload() {
|
||||
|
||||
/*
|
||||
* if (cards == null || cards.isEmpty()) {
|
||||
* JOptionPane.showMessageDialog(null,
|
||||
* "All card pictures have been downloaded."); return; }
|
||||
*/
|
||||
DownloadPictures download = new DownloadPictures(cards);
|
||||
JDialog dlg = download.getDlg(frame);
|
||||
dlg.setVisible(true);
|
||||
dlg.dispose();
|
||||
download.cancel = true;
|
||||
instance = new DownloadPictures(MageFrame.getInstance());
|
||||
Thread t1 = new Thread(new LoadMissingCardData(instance));
|
||||
t1.start();
|
||||
instance.getDlg().setVisible(true);
|
||||
instance.getDlg().dispose();
|
||||
instance.cancel = true;
|
||||
}
|
||||
|
||||
public JDialog getDlg(JFrame frame) {
|
||||
String title = "Downloading";
|
||||
|
||||
final JDialog dialog = this.dlg.createDialog(frame, title);
|
||||
closeButton.addActionListener(e -> dialog.setVisible(false));
|
||||
public JDialog getDlg() {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
@ -89,75 +143,77 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
public DownloadPictures(List<CardDownloadData> cards) {
|
||||
this.cards = cards;
|
||||
static int WIDTH = 400;
|
||||
|
||||
bar = new JProgressBar(this);
|
||||
public DownloadPictures(JFrame frame) {
|
||||
|
||||
cardsToDownload = new ArrayList<>();
|
||||
|
||||
JPanel p0 = new JPanel();
|
||||
p0.setLayout(new BoxLayout(p0, BoxLayout.Y_AXIS));
|
||||
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
jLabel1 = new JLabel();
|
||||
jLabel1.setText("Please select server:");
|
||||
|
||||
jLabel1.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
p0.add(jLabel1);
|
||||
jLabelMessage = new JLabel();
|
||||
jLabelMessage.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
jLabelMessage.setText("Initializing image download...");
|
||||
p0.add(jLabelMessage);
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
ComboBoxModel jComboBox1Model = new DefaultComboBoxModel(new String[]{
|
||||
// "magiccards.info",
|
||||
"wizards.com",
|
||||
"mythicspoiler.com",
|
||||
"tokens.mtg.onl", //"mtgimage.com (HQ)",
|
||||
"mtg.onl",
|
||||
"alternative.mtg.onl",
|
||||
"GrabBag",
|
||||
"magidex.com",
|
||||
"scryfall.com", //"mtgathering.ru HQ",
|
||||
//"mtgathering.ru MQ",
|
||||
//"mtgathering.ru LQ",
|
||||
});
|
||||
jComboBox1 = new JComboBox();
|
||||
|
||||
cardImageSource = MagicCardsImageSource.instance;
|
||||
jLabelAllMissing = new JLabel();
|
||||
|
||||
jComboBox1.setModel(jComboBox1Model);
|
||||
jComboBox1.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
jComboBox1.addActionListener(e -> {
|
||||
JComboBox cb = (JComboBox) e.getSource();
|
||||
switch (cb.getSelectedIndex() + 1) {
|
||||
case 0:
|
||||
cardImageSource = MagicCardsImageSource.instance;
|
||||
break;
|
||||
case 1:
|
||||
cardImageSource = WizardCardsImageSource.instance;
|
||||
break;
|
||||
case 2:
|
||||
cardImageSource = MythicspoilerComSource.instance;
|
||||
break;
|
||||
case 3:
|
||||
cardImageSource = TokensMtgImageSource.instance;
|
||||
break;
|
||||
case 4:
|
||||
cardImageSource = MtgOnlTokensImageSource.instance;
|
||||
break;
|
||||
case 5:
|
||||
cardImageSource = AltMtgOnlTokensImageSource.instance;
|
||||
break;
|
||||
case 6:
|
||||
cardImageSource = GrabbagImageSource.instance;
|
||||
break;
|
||||
case 7:
|
||||
cardImageSource = MagidexImageSource.instance;
|
||||
break;
|
||||
case 8:
|
||||
cardImageSource = ScryfallImageSource.instance;
|
||||
break;
|
||||
jLabelAllMissing.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
// jLabelAllMissing.setText("Computing number of missing images...");
|
||||
p0.add(jLabelAllMissing);
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
jLabelServer = new JLabel();
|
||||
jLabelServer.setText("Please select image source:");
|
||||
jLabelServer.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
jLabelServer.setVisible(false);
|
||||
p0.add(jLabelServer);
|
||||
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
jComboBoxServer = new JComboBox();
|
||||
jComboBoxServer.setModel(new DefaultComboBoxModel(DownloadSources.values()));
|
||||
jComboBoxServer.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
jComboBoxServer.setAlignmentY(Component.LEFT_ALIGNMENT);
|
||||
jComboBoxServer.addItemListener((ItemEvent event) -> {
|
||||
if (event.getStateChange() == ItemEvent.SELECTED) {
|
||||
comboBoxServerItemSelected(event);
|
||||
}
|
||||
updateCardsToDownload();
|
||||
});
|
||||
p0.add(jComboBox1);
|
||||
Dimension d = jComboBoxServer.getPreferredSize();
|
||||
d.width = WIDTH;
|
||||
jComboBoxServer.setPreferredSize(d);
|
||||
p0.add(jComboBoxServer);
|
||||
jComboBoxServer.setVisible(false);
|
||||
|
||||
// set the first source as default
|
||||
cardImageSource = WizardCardsImageSource.instance;
|
||||
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
// Set selection ---------------------------------
|
||||
jLabelSet = new JLabel();
|
||||
jLabelSet.setText("Please select sets to download the images for:");
|
||||
jLabelSet.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
jLabelSet.setVisible(false);
|
||||
p0.add(jLabelSet);
|
||||
|
||||
jComboBoxSet = new JComboBox();
|
||||
// jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
|
||||
jComboBoxSet.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
jComboBoxSet.addItemListener((ItemEvent event) -> {
|
||||
if (event.getStateChange() == ItemEvent.SELECTED) {
|
||||
comboBoxSetItemSelected(event);
|
||||
}
|
||||
});
|
||||
|
||||
p0.add(jComboBoxSet);
|
||||
jComboBoxSet.setVisible(false);
|
||||
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
// Start
|
||||
|
@ -165,78 +221,168 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
startDownloadButton.addActionListener(e -> {
|
||||
new Thread(DownloadPictures.this).start();
|
||||
startDownloadButton.setEnabled(false);
|
||||
checkBox.setEnabled(false);
|
||||
});
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
// Progress
|
||||
bar = new JProgressBar(this);
|
||||
p0.add(bar);
|
||||
bar.setStringPainted(true);
|
||||
int count = cards.size();
|
||||
float mb = (count * cardImageSource.getAverageSize()) / 1024;
|
||||
bar.setString(String.format(cardIndex == cards.size() ? "%d of %d cards finished! Please close!"
|
||||
: "%d of %d cards finished! Please wait! [%.1f Mb]", 0, cards.size(), mb));
|
||||
Dimension d = bar.getPreferredSize();
|
||||
d.width = 300;
|
||||
|
||||
d = bar.getPreferredSize();
|
||||
d.width = WIDTH;
|
||||
bar.setPreferredSize(d);
|
||||
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
checkBox = new JCheckBox("Download images for Standard (Type2) only");
|
||||
p0.add(checkBox);
|
||||
p0.add(Box.createVerticalStrut(5));
|
||||
|
||||
checkBox.addActionListener(e -> updateCardsToDownload());
|
||||
bar.setVisible(false);
|
||||
|
||||
// JOptionPane
|
||||
Object[] options = {startDownloadButton, closeButton = new JButton("Cancel")};
|
||||
startDownloadButton.setVisible(false);
|
||||
closeButton.addActionListener(e -> dialog.setVisible(false));
|
||||
closeButton.setVisible(false);
|
||||
|
||||
dlg = new JOptionPane(p0, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[1]);
|
||||
dialog = this.dlg.createDialog(frame, "Downloading images");
|
||||
}
|
||||
|
||||
public static boolean checkForMissingCardImages(List<CardInfo> allCards) {
|
||||
AtomicBoolean missedCardTFiles = new AtomicBoolean();
|
||||
allCards.parallelStream().forEach(card -> {
|
||||
if (!missedCardTFiles.get()) {
|
||||
if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty()) {
|
||||
CardDownloadData url = new CardDownloadData(card.getName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(),
|
||||
0, "", "", false, card.isDoubleFaced(), card.isNightCard());
|
||||
TFile file = new TFile(CardImageUtils.generateImagePath(url));
|
||||
if (!file.exists()) {
|
||||
missedCardTFiles.set(true);
|
||||
public void setAllMissingCards() {
|
||||
updateAndViewMessage("Get all available cards from the repository...");
|
||||
List<CardInfo> cards = CardRepository.instance.findCards(new CardCriteria());
|
||||
updateAndViewMessage("Check which images are missing ...");
|
||||
this.allCardsMissingImage = getNeededCards(cards);
|
||||
updateAndViewMessage("Check which images the current source is providing ...");
|
||||
jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
|
||||
|
||||
updateCardsToDownload(jComboBoxSet.getSelectedItem().toString());
|
||||
|
||||
jComboBoxServer.setVisible(true);
|
||||
jLabelServer.setVisible(true);
|
||||
jComboBoxSet.setVisible(true);
|
||||
jLabelSet.setVisible(true);
|
||||
bar.setVisible(true);
|
||||
startDownloadButton.setVisible(true);
|
||||
closeButton.setVisible(true);
|
||||
|
||||
updateAndViewMessage("");
|
||||
}
|
||||
|
||||
private void comboBoxServerItemSelected(ItemEvent evt) {
|
||||
if (jComboBoxServer.isEnabled()) {
|
||||
cardImageSource = ((DownloadSources) evt.getItem()).getSource();
|
||||
// update the available sets / token comboBox
|
||||
jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
|
||||
updateCardsToDownload(jComboBoxSet.getSelectedItem().toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAndViewMessage(String text) {
|
||||
jLabelMessage.setText(text);
|
||||
if (dialog != null) {
|
||||
dialog.pack();
|
||||
dialog.validate();
|
||||
dialog.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] getSetsForCurrentImageSource() {
|
||||
// Set the available sets to the combo box
|
||||
ArrayList<String> supportedSets = cardImageSource.getSupportedSets();
|
||||
List<String> setNames = new ArrayList<>();
|
||||
if (supportedSets != null) {
|
||||
setNames.add(ALL_IMAGES);
|
||||
setNames.add(ALL_STANDARD_IMAGES);
|
||||
}
|
||||
if (cardImageSource.isTokenSource()) {
|
||||
setNames.add(ALL_TOKENS);
|
||||
}
|
||||
if (supportedSets != null) {
|
||||
for (String setCode : supportedSets) {
|
||||
ExpansionSet expansionSet = Sets.findSet(setCode);
|
||||
if (expansionSet != null) {
|
||||
setNames.add(expansionSet.getName());
|
||||
} else {
|
||||
logger.error(cardImageSource.getSourceName() + ": Expansion set for code " + setCode + " not found!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (setNames.isEmpty()) {
|
||||
logger.error("Source " + cardImageSource.getSourceName() + " creates no selectable items.");
|
||||
setNames.add("not avalable");
|
||||
}
|
||||
return setNames.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private void updateCardsToDownload(String itemText) {
|
||||
selectedSetCodes.clear();
|
||||
switch (itemText) {
|
||||
case ALL_IMAGES:
|
||||
if (cardImageSource.getSupportedSets() == null) {
|
||||
selectedSetCodes = cardImageSource.getSupportedSets();
|
||||
} else {
|
||||
selectedSetCodes.addAll(cardImageSource.getSupportedSets());
|
||||
}
|
||||
break;
|
||||
case ALL_STANDARD_IMAGES:
|
||||
List<String> standardSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD);
|
||||
for (String setCode : cardImageSource.getSupportedSets()) {
|
||||
if (standardSets.contains(setCode)) {
|
||||
selectedSetCodes.add(setCode);
|
||||
} else {
|
||||
logger.debug("Set code " + setCode + " from download source " + cardImageSource.getSourceName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ALL_TOKENS:
|
||||
break;
|
||||
default:
|
||||
int nonSetEntries = 0;
|
||||
if (cardImageSource.getSupportedSets() != null) {
|
||||
nonSetEntries = 2;
|
||||
}
|
||||
if (cardImageSource.isTokenSource()) {
|
||||
nonSetEntries++;
|
||||
}
|
||||
selectedSetCodes.add(cardImageSource.getSupportedSets().get(jComboBoxSet.getSelectedIndex() - nonSetEntries));
|
||||
}
|
||||
cardsToDownload.clear();
|
||||
int numberTokenImagesAvailable = 0;
|
||||
int numberCardImagesAvailable = 0;
|
||||
for (CardDownloadData data : allCardsMissingImage) {
|
||||
if (data.isToken()) {
|
||||
if (cardImageSource.isTokenSource() && cardImageSource.isImageProvided(data.getSet(), data.getName())) {
|
||||
numberTokenImagesAvailable++;
|
||||
cardsToDownload.add(data);
|
||||
}
|
||||
} else {
|
||||
if (selectedSetCodes != null && selectedSetCodes.contains(data.getSet())) {
|
||||
if (cardImageSource.isSetSupportedComplete(data.getSet()) || cardImageSource.isImageProvided(data.getSet(), data.getName())) {
|
||||
numberCardImagesAvailable++;
|
||||
cardsToDownload.add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return missedCardTFiles.get();
|
||||
}
|
||||
|
||||
private void updateCardsToDownload() {
|
||||
List<CardDownloadData> cardsToDownload = cards;
|
||||
if (type2cardsOnly()) {
|
||||
selectType2andTokenCardsIfNotYetDone();
|
||||
cardsToDownload = type2cards;
|
||||
}
|
||||
updateProgressText(cardsToDownload.size());
|
||||
updateProgressText(numberCardImagesAvailable, numberTokenImagesAvailable);
|
||||
}
|
||||
|
||||
private boolean type2cardsOnly() {
|
||||
return checkBox.isSelected();
|
||||
private void comboBoxSetItemSelected(ItemEvent event) {
|
||||
// Update the cards to download related to the selected set
|
||||
updateCardsToDownload(event.getItem().toString());
|
||||
}
|
||||
|
||||
private void selectType2andTokenCardsIfNotYetDone() {
|
||||
if (type2cards == null) {
|
||||
type2cards = new ArrayList<>();
|
||||
for (CardDownloadData data : cards) {
|
||||
if (data.isType2() || data.isToken()) {
|
||||
type2cards.add(data);
|
||||
}
|
||||
private void updateProgressText(int cardCount, int tokenCount) {
|
||||
missingTokens = 0;
|
||||
for (CardDownloadData card : allCardsMissingImage) {
|
||||
if (card.isToken()) {
|
||||
missingTokens++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressText(int cardCount) {
|
||||
float mb = (cardCount * cardImageSource.getAverageSize()) / 1024;
|
||||
bar.setString(String.format(cardIndex == cardCount ? "%d of %d cards finished! Please close!"
|
||||
: "%d of %d cards finished! Please wait! [%.1f Mb]", 0, cardCount, mb));
|
||||
missingCards = allCardsMissingImage.size() - missingTokens;
|
||||
jLabelAllMissing.setText("Missing: " + missingCards + " card images / " + missingTokens + " token images");
|
||||
int imageSum = cardCount + tokenCount;
|
||||
float mb = (imageSum * cardImageSource.getAverageSize()) / 1024;
|
||||
bar.setString(String.format(cardIndex == imageSum ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!"
|
||||
: "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", 0, imageSum, cardCount, tokenCount, mb));
|
||||
}
|
||||
|
||||
private static String createDownloadName(CardInfo card) {
|
||||
|
@ -262,11 +408,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
logger.warn("No formats defined. Try connecting to a server first!");
|
||||
}
|
||||
|
||||
int numberCardImages = allCards.size();
|
||||
int numberWithoutTokens = 0;
|
||||
List<CardDownloadData> allCardsUrls = Collections.synchronizedList(new ArrayList<>());
|
||||
try {
|
||||
offlineMode = true;
|
||||
allCards.parallelStream().forEach(card -> {
|
||||
if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty()
|
||||
&& !ignoreUrls.contains(card.getSetCode())) {
|
||||
|
@ -286,6 +429,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
if (card.getSecondSideName() == null || card.getSecondSideName().trim().isEmpty()) {
|
||||
throw new IllegalStateException("Second side card can't have empty name.");
|
||||
}
|
||||
|
||||
url = new CardDownloadData(card.getSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), true);
|
||||
url.setType2(isType2);
|
||||
allCardsUrls.add(url);
|
||||
|
@ -301,21 +445,18 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
allCardsUrls.add(cardDownloadData);
|
||||
}
|
||||
} else if (card.getCardNumber().isEmpty() || "0".equals(card.getCardNumber())) {
|
||||
System.err.println("There was a critical error!");
|
||||
logger.error("Card has no collector ID and won't be sent to client: " + card.getName());
|
||||
} else if (card.getSetCode().isEmpty()) {
|
||||
System.err.println("There was a critical error!");
|
||||
logger.error("Card has no set name and won't be sent to client:" + card.getName());
|
||||
} else {
|
||||
logger.info("Card was not selected: " + card.getName());
|
||||
}
|
||||
});
|
||||
numberWithoutTokens = allCards.size();
|
||||
allCardsUrls.addAll(getTokenCardUrls());
|
||||
} catch (Exception e) {
|
||||
logger.error(e);
|
||||
}
|
||||
|
||||
int numberAllTokenImages = allCardsUrls.size() - numberWithoutTokens;
|
||||
|
||||
/**
|
||||
* check to see which cards we already have
|
||||
*/
|
||||
|
@ -329,22 +470,13 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
}
|
||||
});
|
||||
|
||||
int tokenImages = 0;
|
||||
for (CardDownloadData card : cardsToDownload) {
|
||||
logger.debug((card.isToken() ? "Token" : "Card") + " image to download: " + card.getName() + " (" + card.getSet() + ')');
|
||||
if (card.isToken()) {
|
||||
tokenImages++;
|
||||
}
|
||||
}
|
||||
logger.info("Check download images (total card images: " + numberCardImages + ", total token images: " + numberAllTokenImages + ')');
|
||||
logger.info(" => Missing card images: " + (cardsToDownload.size() - tokenImages));
|
||||
logger.info(" => Missing token images: " + tokenImages);
|
||||
return new ArrayList<>(cardsToDownload);
|
||||
}
|
||||
|
||||
public static ArrayList<CardDownloadData> getTokenCardUrls() throws RuntimeException {
|
||||
ArrayList<CardDownloadData> list = new ArrayList<>();
|
||||
InputStream in = DownloadPictures.class.getClassLoader().getResourceAsStream("card-pictures-tok.txt");
|
||||
InputStream in = DownloadPictures.class
|
||||
.getClassLoader().getResourceAsStream("card-pictures-tok.txt");
|
||||
|
||||
if (in == null) {
|
||||
logger.error("resources input stream is null");
|
||||
|
@ -446,9 +578,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
if (p != null) {
|
||||
HashSet<String> ignoreUrls = SettingsManager.getIntance().getIgnoreUrls();
|
||||
|
||||
List<CardDownloadData> cardsToDownload = this.checkBox.isSelected() ? type2cards : cards;
|
||||
|
||||
update(0, cardsToDownload.size());
|
||||
logger.info("Started download of " + cardsToDownload.size() + " images from source: " + cardImageSource.getSourceName());
|
||||
|
||||
int numberOfThreads = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_THREADS, "10"));
|
||||
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
|
||||
|
@ -457,7 +588,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
|
||||
CardDownloadData card = cardsToDownload.get(i);
|
||||
|
||||
logger.debug("Downloading card: " + card.getName() + " (" + card.getSet() + ')');
|
||||
logger.debug("Downloading image: " + card.getName() + " (" + card.getSet() + ')');
|
||||
|
||||
String url;
|
||||
if (ignoreUrls.contains(card.getSet()) || card.isToken()) {
|
||||
|
@ -482,7 +613,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
} catch (Exception ex) {
|
||||
}
|
||||
} else if (cardImageSource.getTotalImages() == -1) {
|
||||
logger.info("Card not available on " + cardImageSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')');
|
||||
logger.info("Image not available on " + cardImageSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')');
|
||||
synchronized (sync) {
|
||||
update(cardIndex + 1, cardsToDownload.size());
|
||||
}
|
||||
|
@ -513,6 +644,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
System.gc();
|
||||
}
|
||||
closeButton.setText("Close");
|
||||
updateCardsToDownload(jComboBoxSet.getSelectedItem().toString());
|
||||
}
|
||||
|
||||
static String convertStreamToString(java.io.InputStream is) {
|
||||
|
@ -604,6 +736,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
if (temporaryFile != null && temporaryFile.length() > 100) {
|
||||
useTempFile = true;
|
||||
} else {
|
||||
|
||||
cardImageSource.doPause(url.getPath());
|
||||
httpConn = url.openConnection(p);
|
||||
httpConn.connect();
|
||||
|
@ -708,29 +841,52 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
|
||||
if (cardIndex < count) {
|
||||
float mb = ((count - card) * cardImageSource.getAverageSize()) / 1024;
|
||||
bar.setString(String.format("%d of %d cards finished! Please wait! [%.1f Mb]",
|
||||
bar.setString(String.format("%d of %d image downloads finished! Please wait! [%.1f Mb]",
|
||||
card, count, mb));
|
||||
} else {
|
||||
List<CardDownloadData> remainingCards = Collections.synchronizedList(new ArrayList<>());
|
||||
DownloadPictures.this.cards.parallelStream().forEach(cardDownloadData -> {
|
||||
DownloadPictures.this.allCardsMissingImage.parallelStream().forEach(cardDownloadData -> {
|
||||
TFile file = new TFile(CardImageUtils.generateImagePath(cardDownloadData));
|
||||
if (!file.exists()) {
|
||||
remainingCards.add(cardDownloadData);
|
||||
}
|
||||
});
|
||||
|
||||
DownloadPictures.this.cards = new ArrayList<>(remainingCards);
|
||||
// remove the cards not downloaded to get the siccessfull downloaded cards
|
||||
DownloadPictures.this.cardsToDownload.removeAll(remainingCards);
|
||||
DownloadPictures.this.allCardsMissingImage.removeAll(DownloadPictures.this.cardsToDownload);
|
||||
|
||||
count = DownloadPictures.this.cards.size();
|
||||
count = remainingCards.size();
|
||||
|
||||
if (count == 0) {
|
||||
bar.setString("0 cards remaining! Please close!");
|
||||
bar.setString("0 images remaining! Please close!");
|
||||
} else {
|
||||
bar.setString(String.format("%d cards remaining! Please choose another source!", count));
|
||||
// bar.setString(String.format("%d cards remaining! Please choose another source!", count));
|
||||
startDownloadButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
|
||||
class LoadMissingCardData implements Runnable {
|
||||
|
||||
private static DownloadPictures downloadPictures;
|
||||
|
||||
public LoadMissingCardData(DownloadPictures downloadPictures) {
|
||||
LoadMissingCardData.downloadPictures = downloadPictures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
downloadPictures.setAllMissingCards();
|
||||
}
|
||||
|
||||
public static void main() {
|
||||
|
||||
(new Thread(new LoadMissingCardData(downloadPictures))).start();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,6 +157,53 @@ public final class ImageCache {
|
|||
});
|
||||
}
|
||||
|
||||
public static String getFilePath(CardView card, int width) {
|
||||
String key = getKey(card, card.getName(), Integer.toString(width));
|
||||
boolean usesVariousArt = false;
|
||||
if (key.matches(".*#usesVariousArt.*")) {
|
||||
usesVariousArt = true;
|
||||
key = key.replace("#usesVariousArt", "");
|
||||
}
|
||||
boolean thumbnail = false;
|
||||
if (key.matches(".*#thumb.*")) {
|
||||
thumbnail = true;
|
||||
key = key.replace("#thumb", "");
|
||||
}
|
||||
Matcher m = KEY_PATTERN.matcher(key);
|
||||
|
||||
if (m.matches()) {
|
||||
String name = m.group(1);
|
||||
String set = m.group(2);
|
||||
Integer type = Integer.parseInt(m.group(3));
|
||||
String collectorId = m.group(4);
|
||||
if (collectorId.equals("null")) {
|
||||
collectorId = "0";
|
||||
}
|
||||
String tokenSetCode = m.group(5);
|
||||
String tokenDescriptor = m.group(6);
|
||||
|
||||
CardDownloadData info = new CardDownloadData(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor);
|
||||
|
||||
String path;
|
||||
if (collectorId.isEmpty() || "0".equals(collectorId)) {
|
||||
info.setToken(true);
|
||||
path = CardImageUtils.generateFullTokenImagePath(info);
|
||||
if (path == null) {
|
||||
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename;
|
||||
}
|
||||
} else {
|
||||
path = CardImageUtils.generateImagePath(info);
|
||||
}
|
||||
|
||||
if (thumbnail && path.endsWith(".jpg")) {
|
||||
return buildThumbnailPath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private ImageCache() {
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,19 @@ public final class CardImageUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param card
|
||||
* @return String regardless of whether image exists
|
||||
*/
|
||||
public static String generateFullTokenImagePath(CardDownloadData card) {
|
||||
if (card.isToken()) {
|
||||
String filePath = getTokenImagePath(card);
|
||||
return filePath;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String getTokenImagePath(CardDownloadData card) {
|
||||
String filename = generateImagePath(card);
|
||||
|
||||
|
|
|
@ -1096,6 +1096,16 @@
|
|||
|Generate|TOK:WWK|Snake|||SnakeToken|
|
||||
|Generate|TOK:WWK|Soldier Ally|||JoinTheRanksSoldierToken|
|
||||
|Generate|TOK:WWK|Wolf|||WolfToken|
|
||||
|Generate|TOK:XLN|Dinosaur|||DinosaurToken|
|
||||
|Generate|TOK:XLN|Illusion|||JaceCunningCastawayIllusionToken|
|
||||
|Generate|TOK:XLN|Merfolk|||MerfolkHexproofToken|
|
||||
|Generate|TOK:XLN|Pirate|||PirateToken|
|
||||
|Generate|TOK:XLN|Plant|||DefenderPlantToken|
|
||||
|Generate|TOK:XLN|Treasure|1||TreasureToken|
|
||||
|Generate|TOK:XLN|Treasure|2||TreasureToken|
|
||||
|Generate|TOK:XLN|Treasure|3||TreasureToken|
|
||||
|Generate|TOK:XLN|Treasure|4||TreasureToken|
|
||||
|Generate|TOK:XLN|Vampire|||IxalanVampireToken|
|
||||
|Generate|TOK:ZEN|Angel|||AngelToken|
|
||||
|Generate|TOK:ZEN|Beast|||BeastToken2|
|
||||
|Generate|TOK:ZEN|Bird|||BirdToken|
|
||||
|
|
|
@ -74,6 +74,6 @@ dd3evg=ddaevg
|
|||
dd3gvl=ddagvl
|
||||
dd3jvc=ddajvc
|
||||
# Remove setname as soon as the images can be downloaded
|
||||
ignore.urls=TOK,DDT,V17,IMA,XLN,RIX,,E02,M19,M25,DOM,UST,H17
|
||||
ignore.urls=TOK,DDT,V17,RIX,E02,M19,M25,DOM,UST,H17
|
||||
# sets ordered by release time (newest goes first)
|
||||
token.lookup.order=M19,M25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
|
|
@ -222,7 +222,7 @@ Eldrazi Spawn, 1a, -, -, -, Creature - Eldrazi Spawn, Aleksi Briclot, Sacrifice
|
|||
Eldrazi Spawn, 1b, -, -, -, Creature - Eldrazi Spawn, Mark Tedin, Sacrifice this creature: Add {1} to your mana pool.
|
||||
Eldrazi Spawn, 1c, -, -, -, Creature - Eldrazi Spawn, Veronique Meignaud, Sacrifice this creature: Add {1} to your mana pool.
|
||||
Elemental, 2, R, *|*, -, Creature - Elemental, Jung Park, -
|
||||
Hellion, 3, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Ooze, 4, G, *|*, -, Creature - Ooze, Daniel Ljunggren, -
|
||||
Tuktuk The Returned, 5, -, 5|5, -, Legendary Artifact Creature - Goblin Golem, Franz Vohwinkel, -
|
||||
|
||||
|
@ -344,7 +344,7 @@ Soldier, 3, W, 1|1, -, Creature - Soldier, Greg Staples, -
|
|||
Drake, 4, U, 2|2, -, Creature - Drake, Svetlin Velinov, Flying
|
||||
Zombie, 5, B, 2|2, -, Creature - Zombie, Lucas Graciano, -
|
||||
Goblin, 6, R, 1|1, -, Creature - Goblin, Karl Kopinski, -
|
||||
Hellion, 7, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Beast, 8, G, 3|3, -, Creature - Beast, John Donahue, -
|
||||
Saproling, 9, G, 1|1, -, Creature - Saproling, Brad Rigney, -
|
||||
Wurm, 10, G, 6|6, -, Creature - Wurm, Anthony Francisco, -
|
||||
|
@ -664,7 +664,7 @@ DDP - Duel Decks: Zendikar vs. Eldrazi (2015-08-28)
|
|||
Eldrazi Spawn, 076, -, -, -, Creature - Eldrazi Spawn, Aleksi Briclot, Sacrifice this creature: Add {1} to your mana pool.
|
||||
Eldrazi Spawn, 077, -, -, -, Creature - Eldrazi Spawn, Veronique Meignaud, Sacrifice this creature: Add {1} to your mana pool.
|
||||
Eldrazi Spawn, 078, -, -, -, Creature - Eldrazi Spawn, Mark Tedin, Sacrifice this creature: Add {1} to your mana pool.
|
||||
Hellion, 079, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, -
|
||||
Plant, 080, G, -, -, Creature - Plant, Daren Bader, -
|
||||
|
||||
BFZ - Battle for Zendikar (2015-10-09)
|
||||
|
@ -745,3 +745,20 @@ Clue, 015, -, -, -, Artifact - Clue, James Paick, {2}‚ Sacrifice this Artifact
|
|||
Clue, 016, -, -, -, Artifact - Clue, Franz Vohwinkel, {2}‚ Sacrifice this Artifact: Draw a card.
|
||||
Jace Emblem, 017, -, -, -, Emblem - Jace, Tyler Jacobson, Whenever an opponent casts his or her first spell each turn<72> counter that spell.
|
||||
Arlinn Emblem, 018, -, -, -, Emblem - Arlinn, Winona Nelson, Creatures you control have haste and '{T}: This creature deals damage equal to its power to target creature or player.'
|
||||
|
||||
|
||||
SWS - Star Wars Custom set
|
||||
|
||||
Rebel, 001, W, 1|1, -, Creature - Rebel, Alex Konstad, -
|
||||
Trooper, 002, W, 1|1, -, Creature - Trooper, Darren Tan, -
|
||||
Tusken Raider, 003, W, 1|1, -, Creature - Tusken Raider, William O'Connor, -
|
||||
Ewok, 004, G, 1|1, -, Creature - Ewok, Chris NG, -
|
||||
Hunter, 005, R, 4|4, -, Creature - Hunter, Steve Argyle, -
|
||||
Royal Guard, 006, R, 2|2, -, Creature - Soldier, Aldo Katayanagi, First Strike
|
||||
AT-AT, 007, -, 5|5, -, Artifact Creature - AT-AT, Prokhoda, When this creature dies<65> create two 1/1 white Trooper creature tokens.
|
||||
B-Wing, 008, -, 1|1, -, Artifact Creature - Rebel Starship, Anthony Devine, Spaceflight
|
||||
Droid, 009, -, 1|1, -, Artifact Creature - Droid, PeetuGee, -
|
||||
TIE Fighter, 010, -, 1|1, -, Artifact Creature - Starship, Darren Tan, Spaceflight
|
||||
Yoda Emblem, 011, -, -, -, Emblem - Yoda, Jerry Vanderstelt, Hexproof<6F> you and your creatures have.
|
||||
Obi-Wan Kenobi Emblem, 012, -, -, -, Emblem - Obi-Wan Kenobi, Jerry Vanderstelt, Creatures you control get +1/+1 and have vigilance<63> first strike<6B> and lifelink.
|
||||
Aurra Sing Emblem, 013, -, -, -, Emblem - Aurra Sing, Willman1701, Whenever a nontoken creature you control leaves the battlefield<6C> discard a card.
|
||||
|
|
Can't render this file because it contains an unexpected character in line 549 and column 140.
|
|
@ -37,11 +37,20 @@ public enum ClientCallbackMethod {
|
|||
GAME_TARGET("gameTarget"),
|
||||
GAME_CHOOSE_ABILITY("gameChooseAbility"),
|
||||
GAME_CHOOSE_PILE("gameChoosePile"),
|
||||
GAME_CHOOSE_CHOICE("gameChooseChoice"), GAME_ASK("gameAsk"), GAME_SELECT("gameSelect"), GAME_PLAY_MANA("gamePlayMana"), GAME_PLAY_XMANA("gamePlayXMana"), GAME_GET_AMOUNT("gameSelectAmount"), DRAFT_INIT("draftInit"), DRAFT_INFORM("draftInform"), DRAFT_PICK("draftPick"), DRAFT_UPDATE("draftUpdate");
|
||||
GAME_CHOOSE_CHOICE("gameChooseChoice"),
|
||||
GAME_ASK("gameAsk"),
|
||||
GAME_SELECT("gameSelect"),
|
||||
GAME_PLAY_MANA("gamePlayMana"),
|
||||
GAME_PLAY_XMANA("gamePlayXMana"),
|
||||
GAME_GET_AMOUNT("gameSelectAmount"),
|
||||
DRAFT_INIT("draftInit"),
|
||||
// DRAFT_INFORM("draftInform"),
|
||||
DRAFT_PICK("draftPick"),
|
||||
DRAFT_UPDATE("draftUpdate");
|
||||
|
||||
String value;
|
||||
|
||||
ClientCallbackMethod(String value){
|
||||
ClientCallbackMethod(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.swing.*;
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.decks.InvalidDeckException;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.cards.repository.ExpansionInfo;
|
||||
|
@ -691,8 +690,6 @@ public class SessionImpl implements Session {
|
|||
}
|
||||
return server.joinTable(sessionId, roomId, tableId, playerName, playerType, skill, deckList, password);
|
||||
}
|
||||
} catch (InvalidDeckException iex) {
|
||||
handleInvalidDeckException(iex);
|
||||
} catch (GameException ex) {
|
||||
handleGameException(ex);
|
||||
} catch (MageException ex) {
|
||||
|
@ -1547,11 +1544,6 @@ public class SessionImpl implements Session {
|
|||
client.showError(ex.getMessage());
|
||||
}
|
||||
|
||||
private void handleInvalidDeckException(InvalidDeckException iex) {
|
||||
logger.warn(iex.getMessage() + '\n' + iex.getInvalid());
|
||||
client.showError(iex.getMessage() + '\n' + iex.getInvalid());
|
||||
}
|
||||
|
||||
private void handleGameException(GameException ex) {
|
||||
logger.warn(ex.getMessage());
|
||||
client.showError(ex.getMessage());
|
||||
|
|
|
@ -8,6 +8,7 @@ import mage.interfaces.rate.RateCallback;
|
|||
import mage.util.RandomUtil;
|
||||
|
||||
import java.util.*;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* Builds deck from provided card pool.
|
||||
|
@ -114,7 +115,7 @@ public final class DeckBuilder {
|
|||
* @param count
|
||||
*/
|
||||
private static void addCardsToDeck(final Collection<MageScoredCard> remainingCards, final int minCost, final int maxCost,
|
||||
final int count) {
|
||||
final int count) {
|
||||
|
||||
for (int c = count; c > 0; c--) {
|
||||
|
||||
|
@ -140,7 +141,8 @@ public final class DeckBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds lands from non basic land (if provided), adds basic lands getting them from provided {@link RateCallback}}.
|
||||
* Adds lands from non basic land (if provided), adds basic lands getting
|
||||
* them from provided {@link RateCallback}}.
|
||||
*
|
||||
* @param allowedColors
|
||||
* @param landCardPool
|
||||
|
@ -241,9 +243,9 @@ public final class DeckBuilder {
|
|||
int type;
|
||||
if (card.isCreature()) {
|
||||
type = 10;
|
||||
} else if (card.getSubtype(null).contains("Equipment")) {
|
||||
} else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) {
|
||||
type = 8;
|
||||
} else if (card.getSubtype(null).contains("Aura")) {
|
||||
} else if (card.getSubtype(null).contains(SubType.AURA)) {
|
||||
type = 5;
|
||||
} else if (card.isInstant()) {
|
||||
type = 7;
|
||||
|
@ -251,11 +253,11 @@ public final class DeckBuilder {
|
|||
type = 6;
|
||||
}
|
||||
|
||||
this.score =
|
||||
// 5*card.getValue() + // not possible now
|
||||
3 * cardRater.rateCard(card) +
|
||||
// 3*card.getRemoval() + // not possible now
|
||||
type + getManaCostScore(card, allowedColors);
|
||||
this.score
|
||||
= // 5*card.getValue() + // not possible now
|
||||
3 * cardRater.rateCard(card)
|
||||
+ // 3*card.getRemoval() + // not possible now
|
||||
type + getManaCostScore(card, allowedColors);
|
||||
}
|
||||
|
||||
private int getManaCostScore(Card card, List<ColoredManaSymbol> allowedColors) {
|
||||
|
|
|
@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
|||
public final static int MAGE_VERSION_MAJOR = 1;
|
||||
public final static int MAGE_VERSION_MINOR = 4;
|
||||
public final static int MAGE_VERSION_PATCH = 26;
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V2";
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V7";
|
||||
public final static String MAGE_VERSION_INFO = "";
|
||||
|
||||
private final int major;
|
||||
|
|
|
@ -41,8 +41,10 @@ public class DuelCommander extends Commander {
|
|||
banned.add("Channel");
|
||||
banned.add("Chrome Mox");
|
||||
banned.add("Dig Through Time");
|
||||
banned.add("Eidolon of the Great Revel");
|
||||
banned.add("Emrakul, the Aeons Torn");
|
||||
banned.add("Entomb");
|
||||
banned.add("Fireblast");
|
||||
banned.add("Food Chain");
|
||||
banned.add("Gaea's Cradle");
|
||||
banned.add("Gifts Ungiven");
|
||||
|
@ -68,11 +70,13 @@ public class DuelCommander extends Commander {
|
|||
banned.add("Necrotic Ooze");
|
||||
banned.add("Oath of Druids");
|
||||
banned.add("Polymorph");
|
||||
banned.add("Price of Progress");
|
||||
banned.add("Protean Hulk");
|
||||
banned.add("Sensei's Divining Top");
|
||||
banned.add("Shahrazad");
|
||||
banned.add("Sol Ring");
|
||||
banned.add("Strip Mine");
|
||||
banned.add("Sulfuric Vortex");
|
||||
banned.add("The Tabernacle at Pendrell Vale");
|
||||
banned.add("Time Vault");
|
||||
banned.add("Time Walk");
|
||||
|
@ -84,6 +88,7 @@ public class DuelCommander extends Commander {
|
|||
bannedCommander.add("Breya, Etherium Shaper");
|
||||
bannedCommander.add("Bruse Tarl, Boorish Herder");
|
||||
bannedCommander.add("Derevi, Empyrial Tactician");
|
||||
bannedCommander.add("Edgar Markov");
|
||||
bannedCommander.add("Edric, Spymaster of Trest");
|
||||
bannedCommander.add("Erayo, Soratami Ascendant");
|
||||
bannedCommander.add("Geist of Saint Traft");
|
||||
|
|
|
@ -109,6 +109,15 @@ public class HistoricalType2 extends Constructed {
|
|||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
|
||||
// debug code for finding set info
|
||||
// System.out.println();
|
||||
// for (ExpansionSet set : Sets.getInstance().values()) {
|
||||
// if (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION) {
|
||||
// System.out.println("Set:\t" + set.getCode() + "\t" + set.getReleaseDate() + "\t" + set.getName() + "\t" + set.getBlockName());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
Map<String, String> leastInvalid = null;
|
||||
|
||||
boolean valid = false;
|
||||
|
|
|
@ -36,17 +36,20 @@ public class MTGO1v1Commander extends Commander {
|
|||
public MTGO1v1Commander() {
|
||||
super("MTGO 1v1 Commander");
|
||||
banned.add("Ancestral Recall");
|
||||
banned.add("Arcum Dagsson");
|
||||
banned.add("Back to Basics");
|
||||
banned.add("Balance");
|
||||
banned.add("Baral, Chief of Compliance");
|
||||
banned.add("Bazaar of Baghdad");
|
||||
banned.add("Black Lotus");
|
||||
banned.add("Braids, Cabal Minion");
|
||||
banned.add("Brainstorm");
|
||||
banned.add("Channel");
|
||||
banned.add("Derevi, Empyrial Tactician");
|
||||
banned.add("Demonic Tutor");
|
||||
banned.add("Dig Through Time");
|
||||
banned.add("Edric, Spymaster of Trest");
|
||||
banned.add("Emrakul, the Aeons Torn");
|
||||
banned.add("Enlightened Tutor");
|
||||
banned.add("Entomb");
|
||||
banned.add("Fastbond");
|
||||
banned.add("Food Chain");
|
||||
|
@ -55,6 +58,7 @@ public class MTGO1v1Commander extends Commander {
|
|||
banned.add("Griselbrand");
|
||||
banned.add("Hermit Druid");
|
||||
banned.add("Humility");
|
||||
banned.add("Imperial Seal");
|
||||
banned.add("Karakas");
|
||||
banned.add("Library of Alexandria");
|
||||
banned.add("Mana Crypt");
|
||||
|
@ -68,6 +72,7 @@ public class MTGO1v1Commander extends Commander {
|
|||
banned.add("Mox Pearl");
|
||||
banned.add("Mox Ruby");
|
||||
banned.add("Mox Sapphire");
|
||||
banned.add("Mystical Tutor");
|
||||
banned.add("Natural Order");
|
||||
banned.add("Necropotence");
|
||||
banned.add("Oath of Druids");
|
||||
|
@ -88,8 +93,8 @@ public class MTGO1v1Commander extends Commander {
|
|||
banned.add("Treachery");
|
||||
banned.add("Treasure Cruise");
|
||||
banned.add("Vial Smasher the Fierce");
|
||||
banned.add("Vampiric Tutor");
|
||||
banned.add("Yamgmoth's Bargain");
|
||||
banned.add("Yisan, the Wanderer Bard");
|
||||
banned.add("Zur the Enchanter");
|
||||
}
|
||||
}
|
|
@ -73,9 +73,7 @@ public class Standard extends Constructed {
|
|||
}
|
||||
}
|
||||
banned.add("Aetherworks Marvel");
|
||||
banned.add("Emrakul, the Promised End");
|
||||
banned.add("Felidar Guardian");
|
||||
banned.add("Reflector Mage");
|
||||
banned.add("Smuggler's Copter");
|
||||
}
|
||||
|
||||
|
@ -83,6 +81,6 @@ public class Standard extends Constructed {
|
|||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(set.getReleaseDate());
|
||||
// Sets from fall block are normally released in September and January
|
||||
return cal.get(Calendar.MONTH) > 8 || cal.get(Calendar.MONTH) < 2;
|
||||
return cal.get(Calendar.MONTH) > 7 || cal.get(Calendar.MONTH) < 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ public class Vintage extends Constructed {
|
|||
restricted.add("Memory Jar");
|
||||
restricted.add("Merchant Scroll");
|
||||
restricted.add("Mind's Desire");
|
||||
restricted.add("Monastery Mentory");
|
||||
restricted.add("Mox Emerald");
|
||||
restricted.add("Mox Jet");
|
||||
restricted.add("Mox Pearl");
|
||||
|
@ -104,6 +105,7 @@ public class Vintage extends Constructed {
|
|||
restricted.add("Ponder");
|
||||
restricted.add("Sol Ring");
|
||||
restricted.add("Strip Mine");
|
||||
restricted.add("Thorn of Amethyst");
|
||||
restricted.add("Time Vault");
|
||||
restricted.add("Time Walk");
|
||||
restricted.add("Timetwister");
|
||||
|
@ -114,7 +116,6 @@ public class Vintage extends Constructed {
|
|||
restricted.add("Vampiric Tutor");
|
||||
restricted.add("Wheel of Fortune");
|
||||
restricted.add("Windfall");
|
||||
restricted.add("Yawgmoth's Bargain");
|
||||
restricted.add("Yawgmoth's Will");
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#Generated by Maven
|
||||
#Mon Aug 28 09:53:46 CEST 2017
|
||||
#Fri Sep 15 22:14:29 CEST 2017
|
||||
version=1.4.26
|
||||
groupId=org.mage
|
||||
artifactId=mage-game-pennydreadfulcommanderfreeforall
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package mage.player.ai.ma;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author ubeefx, nantuko
|
||||
*/
|
||||
|
@ -56,7 +56,7 @@ public final class ArtificialScoringSystem {
|
|||
//score + =cardDefinition.getActivations().size()*50;
|
||||
//score += cardDefinition.getManaActivations().size()*80;
|
||||
} else {
|
||||
if (permanent.getSubtype(game).contains("Equipment")) {
|
||||
if (permanent.getSubtype(game).contains(SubType.EQUIPMENT)) {
|
||||
score += 100;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public final class ArtificialScoringSystem {
|
|||
}
|
||||
score += equipments * 50 + enchantments * 100;
|
||||
|
||||
if (!permanent.canAttack(game)) {
|
||||
if (!permanent.canAttack(null, game)) {
|
||||
score -= 100;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,19 +25,17 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -50,15 +48,16 @@ public class CombatEvaluator {
|
|||
public int evaluate(Permanent creature, Game game) {
|
||||
if (!values.containsKey(creature.getId())) {
|
||||
int value = 0;
|
||||
if (creature.canAttack(game))
|
||||
if (creature.canAttack(null, game)) {
|
||||
value += 2;
|
||||
}
|
||||
value += creature.getPower().getValue();
|
||||
value += creature.getToughness().getValue();
|
||||
value += creature.getAbilities().getEvasionAbilities().size();
|
||||
value += creature.getAbilities().getProtectionAbilities().size();
|
||||
value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())?1:0;
|
||||
value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())?2:0;
|
||||
value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId())?1:0;
|
||||
value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()) ? 1 : 0;
|
||||
value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId()) ? 2 : 0;
|
||||
value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId()) ? 1 : 0;
|
||||
values.put(creature.getId(), value);
|
||||
}
|
||||
return values.get(creature.getId());
|
||||
|
|
|
@ -1514,7 +1514,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
if (object != null) {
|
||||
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = getSpellAbilities(object, game.getState().getZone(object.getId()), game);
|
||||
if (useableAbilities != null && !useableAbilities.isEmpty()) {
|
||||
game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(useableAbilities.values()));
|
||||
// game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(useableAbilities.values()));
|
||||
// TODO: Improve this
|
||||
return (SpellAbility) useableAbilities.values().iterator().next();
|
||||
}
|
||||
|
@ -1939,7 +1939,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
|
||||
protected int combatPotential(Permanent creature, Game game) {
|
||||
log.debug("combatPotential");
|
||||
if (!creature.canAttack(game)) {
|
||||
if (!creature.canAttack(null, game)) {
|
||||
return 0;
|
||||
}
|
||||
int potential = creature.getPower().getValue();
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.apache.log4j.Logger;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* Class responsible for reading ratings from resources and rating given cards.
|
||||
|
@ -60,9 +61,9 @@ public final class RateCard {
|
|||
type = 15;
|
||||
} else if (card.isCreature()) {
|
||||
type = 10;
|
||||
} else if (card.getSubtype(null).contains("Equipment")) {
|
||||
} else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) {
|
||||
type = 8;
|
||||
} else if (card.getSubtype(null).contains("Aura")) {
|
||||
} else if (card.getSubtype(null).contains(SubType.AURA)) {
|
||||
type = 5;
|
||||
} else if (card.isInstant()) {
|
||||
type = 7;
|
||||
|
@ -77,7 +78,7 @@ public final class RateCard {
|
|||
}
|
||||
|
||||
private static int isRemoval(Card card) {
|
||||
if (card.getSubtype(null).contains("Aura") || card.isInstant() || card.isSorcery()) {
|
||||
if (card.getSubtype(null).contains(SubType.AURA) || card.isInstant() || card.isSorcery()) {
|
||||
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
for (Effect effect : ability.getEffects()) {
|
||||
|
|
|
@ -46,6 +46,7 @@ import mage.choices.ChoiceImpl;
|
|||
import mage.constants.*;
|
||||
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
|
||||
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterAttackingCreature;
|
||||
import mage.filter.common.FilterBlockingCreature;
|
||||
import mage.filter.common.FilterCreatureForCombat;
|
||||
|
@ -726,7 +727,10 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// It's end of turn phase
|
||||
if (!skippedAtLeastOnce
|
||||
|| (playerId.equals(game.getActivePlayerId())
|
||||
&& !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) {
|
||||
&& !controllingPlayer
|
||||
.getUserData()
|
||||
.getUserSkipPrioritySteps()
|
||||
.isStopOnAllEndPhases())) {
|
||||
skippedAtLeastOnce = true;
|
||||
if (passWithManaPoolCheck(game)) {
|
||||
return false;
|
||||
|
@ -834,10 +838,23 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return !controllingPlayer.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType());
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
String isNull = controllingPlayer.getUserData() == null ? "null" : "not null";
|
||||
logger.error("null pointer exception UserData = " + isNull);
|
||||
if (controllingPlayer.getUserData() != null) {
|
||||
if (controllingPlayer.getUserData().getUserSkipPrioritySteps() != null) {
|
||||
if (game.getStep() != null) {
|
||||
if (game.getStep().getType() == null) {
|
||||
logger.error("game.getStep().getType() == null");
|
||||
}
|
||||
} else {
|
||||
logger.error("game.getStep() == null");
|
||||
}
|
||||
} else {
|
||||
logger.error("UserData.getUserSkipPrioritySteps == null");
|
||||
}
|
||||
} else {
|
||||
logger.error("UserData == null");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1042,21 +1059,26 @@ public class HumanPlayer extends PlayerImpl {
|
|||
updateGameStatePriority("selectAttackers", game);
|
||||
FilterCreatureForCombat filter = filterCreatureForCombat.copy();
|
||||
filter.add(new ControllerIdPredicate(attackingPlayerId));
|
||||
|
||||
while (!abort) {
|
||||
if (passedAllTurns
|
||||
|| passedUntilEndStepBeforeMyTurn
|
||||
|| (!getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction()
|
||||
|| (!getControllingPlayersUserData(game)
|
||||
.getUserSkipPrioritySteps()
|
||||
.isStopOnDeclareAttackersDuringSkipAction()
|
||||
&& (passedTurn
|
||||
|| passedTurnSkipStack
|
||||
|| passedUntilEndOfTurn
|
||||
|| passedUntilNextMain))) {
|
||||
return;
|
||||
if (checkIfAttackersValid(game)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Map<String, Serializable> options = new HashMap<>();
|
||||
|
||||
List<UUID> possibleAttackers = new ArrayList<>();
|
||||
for (Permanent possibleAttacker : game.getBattlefield().getActivePermanents(filter, attackingPlayerId, game)) {
|
||||
if (possibleAttacker.canAttack(game)) {
|
||||
if (possibleAttacker.canAttack(null, game)) {
|
||||
possibleAttackers.add(possibleAttacker.getId());
|
||||
}
|
||||
}
|
||||
|
@ -1095,46 +1117,14 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// attack selected default defender
|
||||
declareAttacker(attacker.getId(), attackedDefender, game, false);
|
||||
}
|
||||
} else if (response.getBoolean() != null) {
|
||||
// check if enough attackers are declared
|
||||
if (!game.getCombat().getCreaturesForcedToAttack().isEmpty()) {
|
||||
if (!game.getCombat().getAttackers().containsAll(game.getCombat().getCreaturesForcedToAttack().keySet())) {
|
||||
int forcedAttackers = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (UUID creatureId : game.getCombat().getCreaturesForcedToAttack().keySet()) {
|
||||
boolean validForcedAttacker = false;
|
||||
if (game.getCombat().getAttackers().contains(creatureId)) {
|
||||
Set<UUID> possibleDefender = game.getCombat().getCreaturesForcedToAttack().get(creatureId);
|
||||
if (possibleDefender.isEmpty()
|
||||
|| possibleDefender.contains(game.getCombat().getDefenderId(creatureId))) {
|
||||
validForcedAttacker = true;
|
||||
}
|
||||
}
|
||||
if (validForcedAttacker) {
|
||||
forcedAttackers++;
|
||||
} else {
|
||||
Permanent creature = game.getPermanent(creatureId);
|
||||
if (creature != null) {
|
||||
sb.append(creature.getIdName()).append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (game.getCombat().getMaxAttackers() > forcedAttackers) {
|
||||
int requireToAttack = Math.min(game.getCombat().getMaxAttackers() - forcedAttackers, game.getCombat().getCreaturesForcedToAttack().size() - forcedAttackers);
|
||||
String message = (requireToAttack == 1 ? " more attacker that is " : " more attackers that are ")
|
||||
+ "forced to attack.\nCreature"
|
||||
+ (requireToAttack == 1 ? "" : "s") + " forced to attack: ";
|
||||
game.informPlayer(this, sb.insert(0, message)
|
||||
.insert(0, requireToAttack)
|
||||
.insert(0, "You have to attack with ").toString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (response.getInteger() != null) { // F-Key
|
||||
if (checkIfAttackersValid(game)) {
|
||||
return;
|
||||
}
|
||||
} else if (response.getBoolean() != null) { // ok button
|
||||
if (checkIfAttackersValid(game)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} else if (response.getInteger() != null) {
|
||||
return;
|
||||
} else if (response.getUUID() != null) {
|
||||
Permanent attacker = game.getPermanent(response.getUUID());
|
||||
if (attacker != null) {
|
||||
|
@ -1148,8 +1138,95 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean checkIfAttackersValid(Game game) {
|
||||
if (!game.getCombat().getCreaturesForcedToAttack().isEmpty()) {
|
||||
if (!game.getCombat().getAttackers().containsAll(game.getCombat().getCreaturesForcedToAttack().keySet())) {
|
||||
int forcedAttackers = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (UUID creatureId : game.getCombat().getCreaturesForcedToAttack().keySet()) {
|
||||
boolean validForcedAttacker = false;
|
||||
if (game.getCombat().getAttackers().contains(creatureId)) {
|
||||
Set<UUID> possibleDefender = game.getCombat().getCreaturesForcedToAttack().get(creatureId);
|
||||
if (possibleDefender.isEmpty()
|
||||
|| possibleDefender.contains(game.getCombat().getDefenderId(creatureId))) {
|
||||
validForcedAttacker = true;
|
||||
}
|
||||
}
|
||||
if (validForcedAttacker) {
|
||||
forcedAttackers++;
|
||||
} else {
|
||||
Permanent creature = game.getPermanent(creatureId);
|
||||
if (creature != null) {
|
||||
sb.append(creature.getIdName()).append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (game.getCombat().getMaxAttackers() > forcedAttackers) {
|
||||
int requireToAttack = Math.min(game.getCombat().getMaxAttackers() - forcedAttackers, game.getCombat().getCreaturesForcedToAttack().size() - forcedAttackers);
|
||||
String message = (requireToAttack == 1 ? " more attacker that is " : " more attackers that are ")
|
||||
+ "forced to attack.\nCreature"
|
||||
+ (requireToAttack == 1 ? "" : "s") + " forced to attack: ";
|
||||
game.informPlayer(this, sb.insert(0, message)
|
||||
.insert(0, requireToAttack)
|
||||
.insert(0, "You have to attack with ").toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if enough attackers are declared
|
||||
// check if players have to be attacked
|
||||
Set<UUID> playersToAttackIfAble = new HashSet<>();
|
||||
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(null, true, game).entrySet()) {
|
||||
RequirementEffect effect = entry.getKey();
|
||||
for (Ability ability : entry.getValue()) {
|
||||
UUID playerToAttack = effect.playerMustBeAttackedIfAble(ability, game);
|
||||
if (playerToAttack != null) {
|
||||
playersToAttackIfAble.add(playerToAttack);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!playersToAttackIfAble.isEmpty()) {
|
||||
Set<UUID> checkPlayersToAttackIfAble = new HashSet<>(playersToAttackIfAble);
|
||||
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
|
||||
checkPlayersToAttackIfAble.remove(combatGroup.getDefendingPlayerId());
|
||||
}
|
||||
|
||||
for (UUID forcedToAttackId : checkPlayersToAttackIfAble) {
|
||||
Player forcedToAttack = game.getPlayer(forcedToAttackId);
|
||||
|
||||
for (Permanent attacker : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getId(), game)) {
|
||||
|
||||
if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
|
||||
GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER,
|
||||
forcedToAttackId, attacker.getId(), attacker.getControllerId()), game)) {
|
||||
continue;
|
||||
}
|
||||
// if attacker needs a specific defender to attack so select that one instead
|
||||
if (game.getCombat().getCreaturesForcedToAttack().containsKey(attacker.getId())) {
|
||||
Set<UUID> possibleDefenders = game.getCombat().getCreaturesForcedToAttack().get(attacker.getId());
|
||||
if (!possibleDefenders.isEmpty() && !possibleDefenders.contains(forcedToAttackId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(attacker.getId(), game);
|
||||
if (playersToAttackIfAble.contains(defendingPlayerId)) {
|
||||
// already attacks other player taht has to be attacked
|
||||
continue;
|
||||
}
|
||||
if (defendingPlayerId != null || attacker.canAttackInPrinciple(forcedToAttackId, game)) {
|
||||
game.informPlayer(this, "You are forced to attack " + forcedToAttack.getName() + " or a controlled planeswalker e.g. with " + attacker.getIdName() + ".");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void removeAttackerIfPossible(Game game, Permanent attacker) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(attacker, game).entrySet()) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(attacker, false, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect) entry.getKey();
|
||||
if (effect.mustAttack(game)) {
|
||||
if (game.getCombat().getMaxAttackers() >= game.getCombat().getCreaturesForcedToAttack().size()
|
||||
|
@ -1223,7 +1300,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy();
|
||||
filter.add(new ControllerIdPredicate(defendingPlayerId));
|
||||
if (game.getBattlefield().count(filter, null, playerId, game) == 0
|
||||
&& !getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockerIfNoneAvailable()) {
|
||||
&& !getControllingPlayersUserData(game)
|
||||
.getUserSkipPrioritySteps()
|
||||
.isStopOnDeclareBlockerIfNoneAvailable()) {
|
||||
return;
|
||||
}
|
||||
while (!abort) {
|
||||
|
|
|
@ -548,8 +548,6 @@ public class MageServerImpl implements MageServer {
|
|||
UUID userId = session.get().getUserId();
|
||||
ChatManager.instance.leaveChat(chatId, userId);
|
||||
}
|
||||
} else {
|
||||
logger.warn("The chatId is null. sessionId = " + sessionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -374,11 +374,9 @@ public class Session {
|
|||
call.setMessageId(messageId++);
|
||||
callbackHandler.handleCallbackOneway(new Callback(call));
|
||||
} catch (HandleCallbackException ex) {
|
||||
// ex.printStackTrace();
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
logger.warn("SESSION CALLBACK EXCEPTION - " + user.getName() + " userId " + userId);
|
||||
logger.warn(" - method: " + call.getMethod());
|
||||
logger.warn(" - cause: " + getBasicCause(ex).toString());
|
||||
user.setUserState(User.UserState.Disconnected);
|
||||
logger.warn("SESSION CALLBACK EXCEPTION - " + user.getName() + " userId " + userId + " - cause: " + getBasicCause(ex).toString());
|
||||
logger.trace("Stack trace:", ex);
|
||||
SessionManager.instance.disconnect(sessionId, LostConnection);
|
||||
});
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
*/
|
||||
package mage.server;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -41,7 +39,9 @@ import org.jboss.remoting.callback.InvokerCallbackHandler;
|
|||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum SessionManager {
|
||||
|
||||
instance;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SessionManager.class);
|
||||
|
||||
private final ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();
|
||||
|
@ -153,14 +153,6 @@ public enum SessionManager {
|
|||
|
||||
}
|
||||
|
||||
public Map<String, Session> getSessions() {
|
||||
Map<String, Session> map = new HashMap<>();
|
||||
for (Map.Entry<String, Session> entry : sessions.entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin requested the disconnect of a user
|
||||
*
|
||||
|
|
|
@ -38,7 +38,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import mage.MageException;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.decks.InvalidDeckException;
|
||||
import mage.constants.RangeOfInfluence;
|
||||
import mage.constants.TableState;
|
||||
import mage.game.*;
|
||||
|
@ -414,7 +413,17 @@ public class TableController {
|
|||
}
|
||||
}
|
||||
if (!Main.isTestMode() && !table.getValidator().validate(deck)) {
|
||||
throw new InvalidDeckException("Invalid deck for this format", table.getValidator().getInvalid());
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("Invalid deck for the selected ").append(table.getValidator().getName()).append(" format. \n\n");
|
||||
for (Map.Entry<String, String> entry : table.getValidator().getInvalid().entrySet()) {
|
||||
sb.append(entry.getKey()).append(": ").append(entry.getValue()).append('\n');
|
||||
}
|
||||
sb.append("\n\nAdd enough cards and try again!");
|
||||
_user.get().showUserMessage("Submit deck", sb.toString());
|
||||
return false;
|
||||
}
|
||||
submitDeck(userId, playerId, deck);
|
||||
return true;
|
||||
|
|
|
@ -35,6 +35,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.constants.TableState;
|
||||
|
@ -66,7 +69,10 @@ public enum TableManager {
|
|||
private static final DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
private final ConcurrentHashMap<UUID, TableController> controllers = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock controllersLock = new ReentrantReadWriteLock();
|
||||
|
||||
private final ConcurrentHashMap<UUID, Table> tables = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock tablesLock = new ReentrantReadWriteLock();
|
||||
|
||||
/**
|
||||
* Defines how often checking process should be run on server.
|
||||
|
@ -88,25 +94,45 @@ public enum TableManager {
|
|||
|
||||
public Table createTable(UUID roomId, UUID userId, MatchOptions options) {
|
||||
TableController tableController = new TableController(roomId, userId, options);
|
||||
controllers.put(tableController.getTable().getId(), tableController);
|
||||
tables.put(tableController.getTable().getId(), tableController.getTable());
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
}
|
||||
|
||||
public Table createTable(UUID roomId, MatchOptions options) {
|
||||
TableController tableController = new TableController(roomId, null, options);
|
||||
controllers.put(tableController.getTable().getId(), tableController);
|
||||
tables.put(tableController.getTable().getId(), tableController.getTable());
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
}
|
||||
|
||||
public Table createTournamentTable(UUID roomId, UUID userId, TournamentOptions options) {
|
||||
TableController tableController = new TableController(roomId, userId, options);
|
||||
controllers.put(tableController.getTable().getId(), tableController);
|
||||
tables.put(tableController.getTable().getId(), tableController.getTable());
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
}
|
||||
|
||||
private void putTables(UUID tableId, Table table) {
|
||||
final Lock w = tablesLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
tables.put(tableId, table);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void putControllers(UUID controllerId, TableController tableController) {
|
||||
final Lock w = controllersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
controllers.put(controllerId, tableController);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Table getTable(UUID tableId) {
|
||||
return tables.get(tableId);
|
||||
}
|
||||
|
@ -119,7 +145,27 @@ public enum TableManager {
|
|||
}
|
||||
|
||||
public Collection<Table> getTables() {
|
||||
return tables.values();
|
||||
Collection<Table> newTables = new ArrayList<>();
|
||||
final Lock r = tablesLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newTables.addAll(tables.values());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newTables;
|
||||
}
|
||||
|
||||
public Collection<TableController> getControllers() {
|
||||
Collection<TableController> newControllers = new ArrayList<>();
|
||||
final Lock r = controllersLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newControllers.addAll(controllers.values());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newControllers;
|
||||
}
|
||||
|
||||
public Optional<TableController> getController(UUID tableId) {
|
||||
|
@ -164,7 +210,7 @@ public enum TableManager {
|
|||
|
||||
// removeUserFromAllTablesAndChat user from all tournament sub tables
|
||||
public void userQuitTournamentSubTables(UUID userId) {
|
||||
for (TableController controller : controllers.values()) {
|
||||
for (TableController controller : getControllers()) {
|
||||
if (controller.getTable() != null) {
|
||||
if (controller.getTable().isTournamentSubTable()) {
|
||||
controller.leaveTable(userId);
|
||||
|
@ -177,7 +223,7 @@ public enum TableManager {
|
|||
|
||||
// removeUserFromAllTablesAndChat user from all sub tables of a tournament
|
||||
public void userQuitTournamentSubTables(UUID tournamentId, UUID userId) {
|
||||
for (TableController controller : controllers.values()) {
|
||||
for (TableController controller : getControllers()) {
|
||||
if (controller.getTable().isTournamentSubTable() && controller.getTable().getTournament().getId().equals(tournamentId)) {
|
||||
if (controller.hasPlayer(userId)) {
|
||||
controller.leaveTable(userId);
|
||||
|
@ -268,12 +314,6 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
// public boolean replayTable(UUID userId, UUID tableId) {
|
||||
// if (controllers.containsKey(tableId)) {
|
||||
// return controllers.get(tableId).replayTable(userId);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
public void endGame(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
if (controllers.get(tableId).endGameAndStartNextGame()) {
|
||||
|
@ -321,11 +361,24 @@ public enum TableManager {
|
|||
public void removeTable(UUID tableId) {
|
||||
TableController tableController = controllers.get(tableId);
|
||||
if (tableController != null) {
|
||||
controllers.remove(tableId);
|
||||
Lock w = controllersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
controllers.remove(tableId);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
tableController.cleanUp(); // deletes the table chat and references to users
|
||||
|
||||
Table table = tables.get(tableId);
|
||||
tables.remove(tableId);
|
||||
w = tablesLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
tables.remove(tableId);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
|
||||
Match match = table.getMatch();
|
||||
Game game = null;
|
||||
if (match != null) {
|
||||
|
@ -383,8 +436,7 @@ public enum TableManager {
|
|||
debugServerState();
|
||||
}
|
||||
logger.debug("TABLE HEALTH CHECK");
|
||||
List<Table> tableCopy = new ArrayList<>(tables.values());
|
||||
for (Table table : tableCopy) {
|
||||
for (Table table : getTables()) {
|
||||
try {
|
||||
if (table.getState() != TableState.FINISHED
|
||||
&& ((System.currentTimeMillis() - table.getStartTime().getTime()) / 1000) > 30) { // removeUserFromAllTablesAndChat only if table started longer than 30 seconds ago
|
||||
|
|
|
@ -159,15 +159,15 @@ public class User {
|
|||
public void setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
if (sessionId.isEmpty()) {
|
||||
userState = UserState.Disconnected;
|
||||
setUserState(UserState.Disconnected);
|
||||
lostConnection();
|
||||
logger.trace("USER - lost connection: " + userName + " id: " + userId);
|
||||
|
||||
} else if (userState == UserState.Created) {
|
||||
userState = UserState.Connected;
|
||||
setUserState(UserState.Connected);
|
||||
logger.trace("USER - created: " + userName + " id: " + userId);
|
||||
} else {
|
||||
userState = UserState.Connected;
|
||||
setUserState(UserState.Connected);
|
||||
reconnect();
|
||||
logger.trace("USER - reconnected: " + userName + " id: " + userId);
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ public class User {
|
|||
}
|
||||
lastActivity = new Date();
|
||||
if (userState == UserState.Disconnected) { // this can happen if user reconnects very fast after disconnect
|
||||
userState = UserState.Connected;
|
||||
setUserState(UserState.Connected);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ public class User {
|
|||
} else {
|
||||
// Table is missing after connection was lost during sideboard.
|
||||
// Means other players were removed or conceded the game?
|
||||
logger.error("sideboarding id not found : " + entry.getKey());
|
||||
logger.debug(getName() + " reconnects during sideboarding but tableId not found: " + entry.getKey());
|
||||
}
|
||||
}
|
||||
ServerMessagesUtil.instance.incReconnects();
|
||||
|
@ -450,12 +450,14 @@ public class User {
|
|||
TournamentManager.instance.quit(tournamentId, userId);
|
||||
}
|
||||
userTournaments.clear();
|
||||
constructing.clear();
|
||||
logger.trace("REMOVE " + userName + " Tables " + tables.size());
|
||||
for (Entry<UUID, Table> entry : tables.entrySet()) {
|
||||
logger.debug("-- leave tableId: " + entry.getValue().getId());
|
||||
TableManager.instance.leaveTable(userId, entry.getValue().getId());
|
||||
}
|
||||
tables.clear();
|
||||
sideboarding.clear();
|
||||
logger.trace("REMOVE " + userName + " Game sessions: " + gameSessions.size());
|
||||
for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) {
|
||||
logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId());
|
||||
|
|
|
@ -196,7 +196,7 @@ public enum UserManager {
|
|||
Calendar calendarRemove = Calendar.getInstance();
|
||||
calendarRemove.add(Calendar.MINUTE, -8);
|
||||
List<User> toRemove = new ArrayList<>();
|
||||
logger.info("Start Check Expired");
|
||||
logger.debug("Start Check Expired");
|
||||
ArrayList<User> userList = new ArrayList<>();
|
||||
final Lock r = lock.readLock();
|
||||
r.lock();
|
||||
|
@ -227,7 +227,7 @@ public enum UserManager {
|
|||
handleException(ex);
|
||||
}
|
||||
}
|
||||
logger.info("Users to remove " + toRemove.size());
|
||||
logger.debug("Users to remove " + toRemove.size());
|
||||
final Lock w = lock.readLock();
|
||||
w.lock();
|
||||
try {
|
||||
|
@ -237,7 +237,7 @@ public enum UserManager {
|
|||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
logger.info("End Check Expired");
|
||||
logger.debug("End Check Expired");
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
|
|
@ -24,10 +24,16 @@
|
|||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
*/
|
||||
package mage.server.draft;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.game.draft.Draft;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
|
@ -39,14 +45,6 @@ import mage.view.DraftPickView;
|
|||
import mage.view.DraftView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -89,21 +87,10 @@ public class DraftSession {
|
|||
UserManager.instance
|
||||
.getUser(userId).
|
||||
ifPresent(user -> user.fireCallback(
|
||||
new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), getDraftView())));
|
||||
new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), getDraftView())));
|
||||
}
|
||||
}
|
||||
|
||||
// not used
|
||||
//
|
||||
public void inform(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance
|
||||
.getUser(userId)
|
||||
.ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INFORM, draft.getId(), new DraftClientMessage(getDraftView(), message))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void draftOver() {
|
||||
if (!killed) {
|
||||
UserManager.instance
|
||||
|
|
|
@ -31,6 +31,9 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import mage.MageException;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -80,7 +83,11 @@ public class GameController implements GameCallback {
|
|||
protected static final ScheduledExecutorService timeoutIdleExecutor = ThreadExecutor.instance.getTimeoutIdleExecutor();
|
||||
|
||||
private final ConcurrentHashMap<UUID, GameSessionPlayer> gameSessions = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock gameSessionsLock = new ReentrantReadWriteLock();
|
||||
|
||||
private final ConcurrentHashMap<UUID, GameSessionWatcher> watchers = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock gameWatchersLock = new ReentrantReadWriteLock();
|
||||
|
||||
private final ConcurrentHashMap<UUID, PriorityTimer> timers = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<UUID, UUID> userPlayerMap;
|
||||
|
@ -114,7 +121,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
public void cleanUp() {
|
||||
cancelTimeout();
|
||||
for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) {
|
||||
for (GameSessionPlayer gameSessionPlayer : getGameSessions()) {
|
||||
gameSessionPlayer.cleanUp();
|
||||
}
|
||||
ChatManager.instance.destroyChatSession(chatId);
|
||||
|
@ -301,7 +308,13 @@ public class GameController implements GameCallback {
|
|||
String joinType;
|
||||
if (gameSession == null) {
|
||||
gameSession = new GameSessionPlayer(game, userId, playerId);
|
||||
gameSessions.put(playerId, gameSession);
|
||||
final Lock w = gameSessionsLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
gameSessions.put(playerId, gameSession);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
joinType = "joined";
|
||||
} else {
|
||||
joinType = "rejoined";
|
||||
|
@ -314,8 +327,8 @@ public class GameController implements GameCallback {
|
|||
|
||||
private synchronized void startGame() {
|
||||
if (gameFuture == null) {
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
|
||||
entry.getValue().init();
|
||||
for (GameSessionPlayer gameSessionPlayer : getGameSessions()) {
|
||||
gameSessionPlayer.init();
|
||||
}
|
||||
|
||||
GameWorker worker = new GameWorker(game, choosingPlayerId, this);
|
||||
|
@ -413,7 +426,13 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
GameSessionWatcher gameWatcher = new GameSessionWatcher(userId, game, false);
|
||||
watchers.put(userId, gameWatcher);
|
||||
final Lock w = gameWatchersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
watchers.put(userId, gameWatcher);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
gameWatcher.init();
|
||||
user.addGameWatchInfo(game.getId());
|
||||
ChatManager.instance.broadcast(chatId, user.getName(), " has started watching", MessageColor.BLUE, true, ChatMessage.MessageType.STATUS, null);
|
||||
|
@ -422,7 +441,13 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
public void stopWatching(UUID userId) {
|
||||
watchers.remove(userId);
|
||||
final Lock w = gameWatchersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
watchers.remove(userId);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
ChatManager.instance.broadcast(chatId, user.getName(), " has stopped watching", MessageColor.BLUE, true, ChatMessage.MessageType.STATUS, null);
|
||||
});
|
||||
|
@ -673,11 +698,11 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
public void endGame(final String message) throws MageException {
|
||||
for (final GameSessionPlayer gameSession : gameSessions.values()) {
|
||||
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
||||
gameSession.gameOver(message);
|
||||
gameSession.removeGame();
|
||||
}
|
||||
for (final GameSessionWatcher gameWatcher : watchers.values()) {
|
||||
for (final GameSessionWatcher gameWatcher : getGameSessionWatchers()) {
|
||||
gameWatcher.gameOver(message);
|
||||
}
|
||||
TableManager.instance.endGame(tableId);
|
||||
|
@ -722,10 +747,10 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (final GameSessionPlayer gameSession : gameSessions.values()) {
|
||||
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
||||
gameSession.update();
|
||||
}
|
||||
for (final GameSessionWatcher gameWatcher : watchers.values()) {
|
||||
for (final GameSessionWatcher gameWatcher : getGameSessionWatchers()) {
|
||||
gameWatcher.update();
|
||||
}
|
||||
}
|
||||
|
@ -734,12 +759,12 @@ public class GameController implements GameCallback {
|
|||
Table table = TableManager.instance.getTable(tableId);
|
||||
if (table != null) {
|
||||
if (table.getMatch() != null) {
|
||||
for (final GameSessionPlayer gameSession : gameSessions.values()) {
|
||||
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
||||
gameSession.endGameInfo(table);
|
||||
}
|
||||
// TODO: inform watchers about game end and who won
|
||||
}
|
||||
}
|
||||
// TODO: inform watchers about game end and who won
|
||||
}
|
||||
|
||||
private synchronized void ask(UUID playerId, final String question, final Map<String, Serializable> options) throws MageException {
|
||||
|
@ -814,12 +839,12 @@ public class GameController implements GameCallback {
|
|||
message.append(game.getStep().getType().toString()).append(" - ");
|
||||
}
|
||||
message.append("Waiting for ").append(game.getPlayer(playerId).getLogName());
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : getGameSessionsMap().entrySet()) {
|
||||
if (!entry.getKey().equals(playerId)) {
|
||||
entry.getValue().inform(message.toString());
|
||||
}
|
||||
}
|
||||
for (final GameSessionWatcher watcher : watchers.values()) {
|
||||
for (final GameSessionWatcher watcher : getGameSessionWatchers()) {
|
||||
watcher.inform(message.toString());
|
||||
}
|
||||
}
|
||||
|
@ -834,14 +859,13 @@ public class GameController implements GameCallback {
|
|||
return;
|
||||
}
|
||||
final String message = new StringBuilder(game.getStep().getType().toString()).append(" - Waiting for ").append(controller.getName()).toString();
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : getGameSessionsMap().entrySet()) {
|
||||
boolean skip = players.stream().anyMatch(playerId -> entry.getKey().equals(playerId));
|
||||
|
||||
if (!skip) {
|
||||
entry.getValue().inform(message);
|
||||
}
|
||||
}
|
||||
for (final GameSessionWatcher watcher : watchers.values()) {
|
||||
for (final GameSessionWatcher watcher : getGameSessionWatchers()) {
|
||||
watcher.inform(message);
|
||||
}
|
||||
}
|
||||
|
@ -858,7 +882,7 @@ public class GameController implements GameCallback {
|
|||
for (StackTraceElement e : ex.getStackTrace()) {
|
||||
sb.append(e.toString()).append('\n');
|
||||
}
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
|
||||
for (final Entry<UUID, GameSessionPlayer> entry : getGameSessionsMap().entrySet()) {
|
||||
entry.getValue().gameError(sb.toString());
|
||||
}
|
||||
}
|
||||
|
@ -995,6 +1019,42 @@ public class GameController implements GameCallback {
|
|||
void execute(UUID player);
|
||||
}
|
||||
|
||||
private Map<UUID, GameSessionPlayer> getGameSessionsMap() {
|
||||
Map<UUID, GameSessionPlayer> newGameSessionsMap = new HashMap<>();
|
||||
final Lock r = gameSessionsLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newGameSessionsMap.putAll(gameSessions);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newGameSessionsMap;
|
||||
}
|
||||
|
||||
private List<GameSessionPlayer> getGameSessions() {
|
||||
List<GameSessionPlayer> newGameSessions = new ArrayList<>();
|
||||
final Lock r = gameSessionsLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newGameSessions.addAll(gameSessions.values());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newGameSessions;
|
||||
}
|
||||
|
||||
private List<GameSessionWatcher> getGameSessionWatchers() {
|
||||
List<GameSessionWatcher> newGameSessionWatchers = new ArrayList<>();
|
||||
final Lock r = gameSessionsLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newGameSessionWatchers.addAll(watchers.values());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newGameSessionWatchers;
|
||||
}
|
||||
|
||||
private GameSessionPlayer getGameSession(UUID playerId) {
|
||||
if (!timers.isEmpty()) {
|
||||
Player player = game.getState().getPlayer(playerId);
|
||||
|
|
|
@ -24,13 +24,17 @@
|
|||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
*/
|
||||
package mage.server.game;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.PlayerAction;
|
||||
|
@ -46,10 +50,17 @@ public enum GameManager {
|
|||
instance;
|
||||
|
||||
private final ConcurrentHashMap<UUID, GameController> gameControllers = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock gameControllersLock = new ReentrantReadWriteLock();
|
||||
|
||||
public UUID createGameSession(Game game, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
GameController gameController = new GameController(game, userPlayerMap, tableId, choosingPlayerId, gameOptions);
|
||||
gameControllers.put(game.getId(), gameController);
|
||||
final Lock w = gameControllersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
gameControllers.put(game.getId(), gameController);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
return gameController.getSessionId();
|
||||
}
|
||||
|
||||
|
@ -151,7 +162,13 @@ public enum GameManager {
|
|||
GameController gameController = gameControllers.get(gameId);
|
||||
if (gameController != null) {
|
||||
gameController.cleanUp();
|
||||
gameControllers.remove(gameId);
|
||||
final Lock w = gameControllersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
gameControllers.remove(gameId);
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +192,15 @@ public enum GameManager {
|
|||
return gameControllers.size();
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<UUID, GameController> getGameController() {
|
||||
return gameControllers;
|
||||
public Map<UUID, GameController> getGameController() {
|
||||
Map<UUID, GameController> newControllers = new HashMap<>();
|
||||
final Lock r = gameControllersLock.readLock();
|
||||
r.lock();
|
||||
try {
|
||||
newControllers.putAll(gameControllers);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
return newControllers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,9 +170,11 @@ public class TournamentSession {
|
|||
}
|
||||
|
||||
private void removeTournamentForUser() {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
-> user.removeTournament(playerId));
|
||||
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().removeTable(playerId);
|
||||
user.get().removeTournament(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class AcrobaticManeuver extends CardImpl {
|
|||
Effect effect = new ExileTargetForSourceEffect();
|
||||
effect.setApplyEffectsAfter();
|
||||
this.getSpellAbility().addEffect(effect);
|
||||
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, true));
|
||||
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect());
|
||||
|
||||
// Draw a card.
|
||||
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
|
||||
|
|
|
@ -54,12 +54,11 @@ public class ActOfAggression extends CardImpl {
|
|||
}
|
||||
|
||||
public ActOfAggression(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R/P}{R/P}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R/P}{R/P}");
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
|
||||
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
|
||||
this.getSpellAbility().addEffect(new UntapTargetEffect());
|
||||
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
|
||||
this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature"));
|
||||
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn."));
|
||||
}
|
||||
|
||||
public ActOfAggression(final ActOfAggression card) {
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -46,16 +45,14 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
public class ActOfTreason extends CardImpl {
|
||||
|
||||
public ActOfTreason(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// Gain control of target creature until end of turn. Untap that creature.
|
||||
// It gains haste until end of turn. (It can attack and {T} this turn.)
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
|
||||
this.getSpellAbility().addEffect(new UntapTargetEffect());
|
||||
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
|
||||
|
||||
this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature"));
|
||||
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn."));
|
||||
}
|
||||
|
||||
public ActOfTreason(final ActOfTreason card) {
|
||||
|
|
74
Mage.Sets/src/mage/cards/a/AdantoTheFirstFort.java
Normal file
74
Mage.Sets/src/mage/cards/a/AdantoTheFirstFort.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.mana.WhiteManaAbility;
|
||||
import mage.constants.SuperType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.token.IxalanVampireToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AdantoTheFirstFort extends CardImpl {
|
||||
|
||||
public AdantoTheFirstFort(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
|
||||
|
||||
this.addSuperType(SuperType.LEGENDARY);
|
||||
|
||||
this.nightCard = true;
|
||||
|
||||
// T: Add W to your mana pool.
|
||||
this.addAbility(new WhiteManaAbility());
|
||||
|
||||
// 2W, T: Create a 1/1 white Vampire creature token with lifelink.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new IxalanVampireToken()), new ManaCostsImpl("{2}{W}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public AdantoTheFirstFort(final AdantoTheFirstFort card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdantoTheFirstFort copy() {
|
||||
return new AdantoTheFirstFort(this);
|
||||
}
|
||||
}
|
85
Mage.Sets/src/mage/cards/a/AdantoVanguard.java
Normal file
85
Mage.Sets/src/mage/cards/a/AdantoVanguard.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.common.SourceAttackingCondition;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostSourceEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
|
||||
import mage.abilities.keyword.IndestructibleAbility;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AdantoVanguard extends CardImpl {
|
||||
|
||||
public AdantoVanguard(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
|
||||
|
||||
this.subtype.add(SubType.VAMPIRE);
|
||||
this.subtype.add(SubType.SOLDIER);
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// As long as Adanto Vanguard is attacking, it gets +2/+0.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
|
||||
new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield),
|
||||
SourceAttackingCondition.instance,
|
||||
"As long as {this} is attacking, it gets +2/+0"
|
||||
)));
|
||||
|
||||
// Pay 4 life: Adanto Vanguard gains indestructible until end of turn.
|
||||
this.addAbility(new SimpleActivatedAbility(
|
||||
Zone.BATTLEFIELD,
|
||||
new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn),
|
||||
new PayLifeCost(4)
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
public AdantoVanguard(final AdantoVanguard card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdantoVanguard copy() {
|
||||
return new AdantoVanguard(this);
|
||||
}
|
||||
}
|
|
@ -100,7 +100,7 @@ class AdaptiveAutomatonAddSubtypeEffect extends ContinuousEffectImpl {
|
|||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
SubType subtype = (SubType) game.getState().getValue(permanent.getId() + "_type");
|
||||
if (subtype != null && !permanent.getSubtype(game).contains(subtype)) {
|
||||
if (subtype != null && !permanent.hasSubtype(subtype, game)) {
|
||||
permanent.getSubtype(game).add(subtype);
|
||||
}
|
||||
}
|
||||
|
|
160
Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java
Normal file
160
Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.common.FilterNonlandPermanent;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetNonlandPermanent;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AdmiralBeckettBrass extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Pirates you control");
|
||||
private static final FilterNonlandPermanent filter2 = new FilterNonlandPermanent("nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.PIRATE));
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
filter2.add(new ControllerDealtDamageByPiratesPredicate());
|
||||
}
|
||||
|
||||
public AdmiralBeckettBrass(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}");
|
||||
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.PIRATE);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Other Pirates you control get +1/+1.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true)));
|
||||
|
||||
// At the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
||||
Ability ability = new BeginningOfEndStepTriggeredAbility(new GainControlTargetEffect(Duration.Custom, true), TargetController.YOU, false);
|
||||
ability.addTarget(new TargetNonlandPermanent(filter2));
|
||||
this.addAbility(ability, new DamagedByPiratesWatcher());
|
||||
}
|
||||
|
||||
public AdmiralBeckettBrass(final AdmiralBeckettBrass card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdmiralBeckettBrass copy() {
|
||||
return new AdmiralBeckettBrass(this);
|
||||
}
|
||||
}
|
||||
|
||||
class DamagedByPiratesWatcher extends Watcher {
|
||||
|
||||
private final Map<UUID, Set<UUID>> damageSourceIds = new HashMap<>();
|
||||
|
||||
public DamagedByPiratesWatcher() {
|
||||
super(DamagedByPiratesWatcher.class.getSimpleName(), WatcherScope.GAME);
|
||||
}
|
||||
|
||||
public DamagedByPiratesWatcher(final DamagedByPiratesWatcher watcher) {
|
||||
super(watcher);
|
||||
for (UUID playerId : watcher.damageSourceIds.keySet()) {
|
||||
Set<UUID> creatures = new HashSet<>();
|
||||
creatures.addAll(watcher.damageSourceIds.get(playerId));
|
||||
this.damageSourceIds.put(playerId, creatures);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamagedByPiratesWatcher copy() {
|
||||
return new DamagedByPiratesWatcher(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) {
|
||||
if (((DamagedPlayerEvent) event).isCombatDamage()) {
|
||||
Permanent creature = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (creature != null && creature.hasSubtype(SubType.PIRATE, game)) {
|
||||
if (damageSourceIds.keySet().contains(event.getTargetId())) {
|
||||
damageSourceIds.get(event.getTargetId()).add(creature.getId());
|
||||
} else {
|
||||
Set<UUID> creatureSet = new HashSet<>();
|
||||
creatureSet.add(creature.getId());
|
||||
damageSourceIds.put(event.getTargetId(), creatureSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean damagedByEnoughPirates(UUID sourceId, Game game) {
|
||||
return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
damageSourceIds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class ControllerDealtDamageByPiratesPredicate implements Predicate<Permanent> {
|
||||
|
||||
public ControllerDealtDamageByPiratesPredicate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Permanent input, Game game) {
|
||||
DamagedByPiratesWatcher watcher = (DamagedByPiratesWatcher) game.getState().getWatchers().get(DamagedByPiratesWatcher.class.getSimpleName());
|
||||
if (watcher != null) {
|
||||
return watcher.damagedByEnoughPirates(input.getControllerId(), game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
146
Mage.Sets/src/mage/cards/a/AerialCaravan.java
Normal file
146
Mage.Sets/src/mage/cards/a/AerialCaravan.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Library;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AerialCaravan extends CardImpl {
|
||||
|
||||
public AerialCaravan(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.SOLDIER);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// {1}{U}{U}: Exile the top card of your library. Until end of turn, you may play that card.
|
||||
this.addAbility(new SimpleActivatedAbility(new AerialCaravanExileEffect(), new ManaCostsImpl("{1}{U}{U}")));
|
||||
}
|
||||
|
||||
public AerialCaravan(final AerialCaravan card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AerialCaravan copy() {
|
||||
return new AerialCaravan(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AerialCaravanExileEffect extends OneShotEffect {
|
||||
|
||||
public AerialCaravanExileEffect() {
|
||||
super(Outcome.Detriment);
|
||||
this.staticText = "Exile the top card of your library. Until end of turn, you may play that card";
|
||||
}
|
||||
|
||||
public AerialCaravanExileEffect(final AerialCaravanExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AerialCaravanExileEffect copy() {
|
||||
return new AerialCaravanExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (sourcePermanent != null && controller != null && controller.getLibrary().hasCards()) {
|
||||
Library library = controller.getLibrary();
|
||||
Card card = library.removeFromTop(game);
|
||||
if (card != null) {
|
||||
String exileName = sourcePermanent.getIdName() + " <this card may be played the turn it was exiled>";
|
||||
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), exileName);
|
||||
ContinuousEffect effect = new AerialCaravanCastFromExileEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class AerialCaravanCastFromExileEffect extends AsThoughEffectImpl {
|
||||
|
||||
public AerialCaravanCastFromExileEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
|
||||
staticText = "You may play the card from exile";
|
||||
}
|
||||
|
||||
public AerialCaravanCastFromExileEffect(final AerialCaravanCastFromExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AerialCaravanCastFromExileEffect copy() {
|
||||
return new AerialCaravanCastFromExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
return source.getControllerId().equals(affectedControllerId)
|
||||
&& objectId.equals(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||
|
@ -35,13 +34,16 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterCard;
|
||||
import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author magenoxx_at_gmail.com
|
||||
|
@ -76,7 +78,7 @@ public class AetherBurst extends CardImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
((DynamicTargetCreaturePermanent) target).setMaxNumberOfTargets(amount + 1);
|
||||
target.setMaxNumberOfTargets(amount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,14 +33,17 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.PayEnergyCost;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlSourceEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -60,9 +63,7 @@ public class AethergeodeMiner extends CardImpl {
|
|||
this.addAbility(new AttacksTriggeredAbility(new GetEnergyCountersControllerEffect(2), false));
|
||||
|
||||
// Pay {E}{E}: Exile Aethergeode Miner, then return it to the battlefield under its owner's control.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileSourceEffect(true), new PayEnergyCost(2));
|
||||
ability.addEffect(new ReturnToBattlefieldUnderOwnerControlSourceEffect());
|
||||
this.addAbility(ability);
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AethergeodeMinerEffect(), new PayEnergyCost(2)));
|
||||
}
|
||||
|
||||
public AethergeodeMiner(final AethergeodeMiner card) {
|
||||
|
@ -74,3 +75,34 @@ public class AethergeodeMiner extends CardImpl {
|
|||
return new AethergeodeMiner(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AethergeodeMinerEffect extends OneShotEffect {
|
||||
|
||||
public AethergeodeMinerEffect() {
|
||||
super(Outcome.Neutral);
|
||||
this.staticText = "Exile {this}, then return it to the battlefield under its owner's control";
|
||||
}
|
||||
|
||||
public AethergeodeMinerEffect(final AethergeodeMinerEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AethergeodeMinerEffect copy() {
|
||||
return new AethergeodeMinerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
if (permanent.moveToExile(source.getSourceId(), "Aethergeode Miner", source.getSourceId(), game)) {
|
||||
Card card = game.getExile().getCard(source.getSourceId(), game);
|
||||
if (card != null) {
|
||||
return card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
129
Mage.Sets/src/mage/cards/a/AgelessSentinels.java
Normal file
129
Mage.Sets/src/mage/cards/a/AgelessSentinels.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BlocksTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.DefenderAbility;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AgelessSentinels extends CardImpl {
|
||||
|
||||
public AgelessSentinels(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
|
||||
|
||||
this.subtype.add(SubType.WALL);
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Defender
|
||||
this.addAbility(DefenderAbility.getInstance());
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// When Ageless Sentinels blocks, it becomes a Bird Giant, and it loses defender.
|
||||
Ability ability = new BlocksTriggeredAbility(new AgelessSentinelsEffect(), false, false, true);
|
||||
Effect effect = new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.WhileOnBattlefield);
|
||||
effect.setText("and it loses defender");
|
||||
ability.addEffect(effect);
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public AgelessSentinels(final AgelessSentinels card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgelessSentinels copy() {
|
||||
return new AgelessSentinels(this);
|
||||
}
|
||||
|
||||
private class AgelessSentinelsEffect extends ContinuousEffectImpl {
|
||||
|
||||
public AgelessSentinelsEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.BecomeCreature);
|
||||
staticText = "it becomes a Bird Giant,";
|
||||
}
|
||||
|
||||
public AgelessSentinelsEffect(final AgelessSentinelsEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgelessSentinelsEffect copy() {
|
||||
return new AgelessSentinelsEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
switch (layer) {
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
permanent.getSubtype(game).clear();
|
||||
permanent.getSubtype(game).add(SubType.BIRD, SubType.GIANT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.TypeChangingEffects_4;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||
|
@ -42,6 +41,8 @@ import mage.game.permanent.token.CatToken;
|
|||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Plopman
|
||||
|
@ -95,7 +96,7 @@ class AjanisChosenEffect extends OneShotEffect {
|
|||
Token token = new CatToken();
|
||||
if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) {
|
||||
Permanent enchantment = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
if (enchantment != null && enchantment.getSubtype(game).contains("Aura")) {
|
||||
if (enchantment != null && enchantment.hasSubtype(SubType.AURA, game)) {
|
||||
for (UUID tokenId : token.getLastAddedTokenIds()) {
|
||||
Permanent tokenPermanent = game.getPermanent(tokenId);
|
||||
if (tokenPermanent != null) {
|
||||
|
|
|
@ -30,7 +30,7 @@ package mage.cards.a;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.AttacksEachTurnStaticAbility;
|
||||
import mage.abilities.common.AttacksEachCombatStaticAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
|
@ -65,7 +65,7 @@ public class AkoumFirebird extends CardImpl {
|
|||
this.addAbility(HasteAbility.getInstance());
|
||||
|
||||
// Akoum Firebird attacks each turn if able.
|
||||
this.addAbility(new AttacksEachTurnStaticAbility());
|
||||
this.addAbility(new AttacksEachCombatStaticAbility());
|
||||
|
||||
// <i>Landfall</i>-Whenever a land enters the battlefield under your control, you may pay {4}{R}{R}.
|
||||
// If you do, return Akoum Firebird from your graveyard to the battlefield.
|
||||
|
|
78
Mage.Sets/src/mage/cards/a/AkuDjinn.java
Normal file
78
Mage.Sets/src/mage/cards/a/AkuDjinn.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.common.counter.AddCountersAllEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AkuDjinn extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature each opponent controls");
|
||||
|
||||
static {
|
||||
filter.add(new ControllerPredicate(TargetController.OPPONENT));
|
||||
}
|
||||
|
||||
public AkuDjinn(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
|
||||
|
||||
this.subtype.add(SubType.DJINN);
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(6);
|
||||
|
||||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// At the beginning of your upkeep, put a +1/+1 counter on each creature each opponent controls.
|
||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), TargetController.YOU, false));
|
||||
}
|
||||
|
||||
public AkuDjinn(final AkuDjinn card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AkuDjinn copy() {
|
||||
return new AkuDjinn(this);
|
||||
}
|
||||
}
|
68
Mage.Sets/src/mage/cards/a/AlabasterPotion.java
Normal file
68
Mage.Sets/src/mage/cards/a/AlabasterPotion.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.common.GainLifeTargetEffect;
|
||||
import mage.abilities.effects.common.PreventDamageToTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.target.common.TargetCreatureOrPlayer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AlabasterPotion extends CardImpl {
|
||||
|
||||
public AlabasterPotion(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}");
|
||||
|
||||
// Choose one - Target player gains X life; or prevent the next X damage that would be dealt to target creature or player this turn.
|
||||
this.getSpellAbility().addEffect(new GainLifeTargetEffect(new ManacostVariableValue()));
|
||||
this.getSpellAbility().addTarget(new TargetPlayer());
|
||||
Mode mode = new Mode();
|
||||
mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, new ManacostVariableValue()));
|
||||
mode.getTargets().add(new TargetCreatureOrPlayer());
|
||||
this.getSpellAbility().addMode(mode);
|
||||
}
|
||||
|
||||
public AlabasterPotion(final AlabasterPotion card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlabasterPotion copy() {
|
||||
return new AlabasterPotion(this);
|
||||
}
|
||||
}
|
69
Mage.Sets/src/mage/cards/a/AlabornZealot.java
Normal file
69
Mage.Sets/src/mage/cards/a/AlabornZealot.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BlocksTriggeredAbility;
|
||||
import mage.abilities.effects.common.DestroySourceEffect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AlabornZealot extends CardImpl {
|
||||
|
||||
public AlabornZealot(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
|
||||
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.SOLDIER);
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// When Alaborn Zealot blocks a creature, destroy that creature and Alaborn Zealot.
|
||||
Ability ability = new BlocksTriggeredAbility(new DestroyTargetEffect().setText("destroy that creature"), false, true, true);
|
||||
ability.addEffect(new DestroySourceEffect().setText("and {this}"));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public AlabornZealot(final AlabornZealot card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlabornZealot copy() {
|
||||
return new AlabornZealot(this);
|
||||
}
|
||||
}
|
|
@ -47,22 +47,23 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
|||
/**
|
||||
*
|
||||
* @author noxx
|
||||
|
||||
*
|
||||
*/
|
||||
public class AlchemistsRefuge extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("nonland cards");
|
||||
private static final FilterCard filter = new FilterCard("spells");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.not(new CardTypePredicate(CardType.LAND)));
|
||||
}
|
||||
|
||||
public AlchemistsRefuge(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
|
||||
|
||||
// {tap}: Add {C} to your mana pool.
|
||||
this.addAbility(new ColorlessManaAbility());
|
||||
|
||||
// {G}{U}, {tap}: You may cast nonland cards this turn as though they had flash.
|
||||
// {G}{U}, {tap}: You may cast spells this turn as though they had flash.
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||
new AddContinuousEffectToGame(new CastAsThoughItHadFlashAllEffect(Duration.EndOfTurn, filter)),
|
||||
new CompositeCost(new ManaCostsImpl("{G}{U}"), new TapSourceCost(), "{G}{U}, {T}")));
|
||||
|
|
|
@ -42,9 +42,7 @@ import mage.constants.SubType;
|
|||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
|
@ -54,16 +52,8 @@ import mage.target.common.TargetCardInHand;
|
|||
*/
|
||||
public class AlexiZephyrMage extends CardImpl {
|
||||
|
||||
private final UUID originalId;
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("Target creatures");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.CREATURE));
|
||||
}
|
||||
|
||||
public AlexiZephyrMage(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.SPELLSHAPER);
|
||||
|
@ -74,22 +64,12 @@ public class AlexiZephyrMage extends CardImpl {
|
|||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{X}{U}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))));
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURES));
|
||||
this.addAbility(ability);
|
||||
|
||||
originalId = ability.getOriginalId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustTargets(Ability ability, Game game) {
|
||||
if (ability.getOriginalId().equals(originalId)) {
|
||||
ability.getTargets().clear();
|
||||
ability.addTarget(new TargetPermanent(ability.getManaCostsToPay().getX(), filter));
|
||||
}
|
||||
}
|
||||
|
||||
public AlexiZephyrMage(final AlexiZephyrMage card) {
|
||||
super(card);
|
||||
this.originalId = card.originalId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,7 @@ import mage.abilities.dynamicvalue.common.DomainValue;
|
|||
import mage.abilities.effects.common.DrawCardTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AbilityWord;
|
||||
import mage.constants.CardType;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
|
@ -42,11 +43,13 @@ import mage.target.TargetPlayer;
|
|||
public class AlliedStrategies extends CardImpl {
|
||||
|
||||
public AlliedStrategies(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}");
|
||||
|
||||
// Domain - Target player draws a card for each basic land type among lands he or she controls.
|
||||
this.getSpellAbility().addEffect(new DrawCardTargetEffect(new DomainValue(true)));
|
||||
this.getSpellAbility().addTarget(new TargetPlayer());
|
||||
this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN);
|
||||
|
||||
}
|
||||
|
||||
public AlliedStrategies(final AlliedStrategies card) {
|
||||
|
|
|
@ -109,6 +109,6 @@ class AlphaStatusDynamicValue implements DynamicValue {
|
|||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "each other creature on the battlefield that shares a creature type with it";
|
||||
return "other creature on the battlefield that shares a creature type with it";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -41,15 +40,16 @@ import mage.constants.SubType;
|
|||
*/
|
||||
public class AlphaTyrranax extends CardImpl {
|
||||
|
||||
public AlphaTyrranax (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}");
|
||||
public AlphaTyrranax(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}");
|
||||
this.subtype.add(SubType.DINOSAUR);
|
||||
this.subtype.add(SubType.BEAST);
|
||||
|
||||
this.power = new MageInt(6);
|
||||
this.toughness = new MageInt(5);
|
||||
}
|
||||
|
||||
public AlphaTyrranax (final AlphaTyrranax card) {
|
||||
public AlphaTyrranax(final AlphaTyrranax card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
|
|||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
|
||||
*
|
||||
*/
|
||||
public class AltarGolem extends CardImpl {
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class AltarGolem extends CardImpl {
|
|||
}
|
||||
|
||||
public AltarGolem(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}");
|
||||
this.subtype.add(SubType.GOLEM);
|
||||
|
||||
this.power = new MageInt(0);
|
||||
|
@ -74,7 +74,7 @@ public class AltarGolem extends CardImpl {
|
|||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Altar Golem's power and toughness are each equal to the number of creatures on the battlefield.
|
||||
DynamicValue amount = new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("creatures in play"));
|
||||
DynamicValue amount = new PermanentsOnBattlefieldCount(new FilterCreaturePermanent("creatures on the battlefield"));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(amount, Duration.EndOfGame)));
|
||||
|
||||
// Altar Golem doesn't untap during your untap step.
|
||||
|
|
106
Mage.Sets/src/mage/cards/a/AnZerrinRuins.java
Normal file
106
Mage.Sets/src/mage/cards/a/AnZerrinRuins.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
|
||||
import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AnZerrinRuins extends CardImpl {
|
||||
|
||||
public AnZerrinRuins(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}");
|
||||
|
||||
// As An-Zerrin Ruins enters the battlefield, choose a creature type.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.UnboostCreature)));
|
||||
|
||||
// Creatures of the chosen type don't untap during their controllers' untap steps.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AnZerrinRuinsDontUntapEffect()));
|
||||
}
|
||||
|
||||
public AnZerrinRuins(final AnZerrinRuins card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnZerrinRuins copy() {
|
||||
return new AnZerrinRuins(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AnZerrinRuinsDontUntapEffect extends DontUntapInControllersUntapStepAllEffect {
|
||||
|
||||
public AnZerrinRuinsDontUntapEffect() {
|
||||
super(Duration.WhileOnBattlefield, TargetController.ANY, new FilterCreaturePermanent());
|
||||
}
|
||||
|
||||
public AnZerrinRuinsDontUntapEffect(final AnZerrinRuinsDontUntapEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnZerrinRuinsDontUntapEffect copy() {
|
||||
return new AnZerrinRuinsDontUntapEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game)) {
|
||||
Permanent sourcePerm = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null && sourcePerm != null) {
|
||||
SubType subtype = (SubType) game.getState().getValue(sourcePerm.getId() + "_type");
|
||||
if (permanent.hasSubtype(subtype, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return "Creatures of the chosen type don't untap during their controllers' untap steps.";
|
||||
}
|
||||
}
|
101
Mage.Sets/src/mage/cards/a/AnaSanctuary.java
Normal file
101
Mage.Sets/src/mage/cards/a/AnaSanctuary.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SanctuaryTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AnaSanctuary extends CardImpl {
|
||||
|
||||
public AnaSanctuary(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
||||
|
||||
// At the beginning of your upkeep, if you control a blue or black permanent, target creature gets +1/+1 until end of turn. If you control a blue permanent and a black permanent, that creature gets +5/+5 until end of turn instead.
|
||||
Ability ability = new SanctuaryTriggeredAbility(
|
||||
new BoostEffect(1), new BoostEffect(5), ObjectColor.BLACK, ObjectColor.BLUE,
|
||||
"At the beginning of your upkeep, if you control a blue or black permanent, "
|
||||
+ "target creature gets +1/+1 until end of turn. If you control a blue permanent and a black permanent, that creature gets +5/+5 until end of turn instead."
|
||||
);
|
||||
ability.addTarget(new TargetCreaturePermanent());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public AnaSanctuary(final AnaSanctuary card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnaSanctuary copy() {
|
||||
return new AnaSanctuary(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BoostEffect extends OneShotEffect {
|
||||
|
||||
private final int amount;
|
||||
|
||||
BoostEffect(int amount) {
|
||||
super(Outcome.Benefit);
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
BoostEffect(final BoostEffect effect) {
|
||||
super(effect);
|
||||
this.amount = effect.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoostEffect copy() {
|
||||
return new BoostEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
ContinuousEffect effect = new BoostTargetEffect(amount, amount, Duration.EndOfTurn);
|
||||
effect.setTargetPointer(new FixedTarget(source.getFirstTarget()));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -27,8 +27,6 @@
|
|||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.*;
|
||||
|
@ -40,6 +38,8 @@ import mage.game.Game;
|
|||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Quercitron
|
||||
|
@ -99,7 +99,7 @@ class AncestralMemoriesEffect extends OneShotEffect {
|
|||
|
||||
TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.LIBRARY, new FilterCard("two cards to put in your hand"));
|
||||
if (player.choose(Outcome.Benefit, cards, target, game)) {
|
||||
for (UUID targetId : (List<UUID>)target.getTargets()) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
Card card = cards.get(targetId, game);
|
||||
if (card != null) {
|
||||
card.moveToZone(Zone.HAND, source.getSourceId(), game, false);
|
||||
|
|
59
Mage.Sets/src/mage/cards/a/AncientBrontodon.java
Normal file
59
Mage.Sets/src/mage/cards/a/AncientBrontodon.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author caldover
|
||||
*/
|
||||
public class AncientBrontodon extends CardImpl {
|
||||
|
||||
public AncientBrontodon(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}{G}");
|
||||
|
||||
this.subtype.add(SubType.DINOSAUR);
|
||||
this.power = new MageInt(9);
|
||||
this.toughness = new MageInt(9);
|
||||
}
|
||||
|
||||
public AncientBrontodon(final AncientBrontodon card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AncientBrontodon copy() {
|
||||
return new AncientBrontodon(this);
|
||||
}
|
||||
}
|
|
@ -25,29 +25,25 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.costs.mana.ColoredManaCost;
|
||||
import mage.abilities.condition.common.SourceAttackingCondition;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalActivatedAbility;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -55,15 +51,24 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*/
|
||||
public class AncientHellkite extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("creature defending player controls");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.CREATURE));
|
||||
filter.add(new DefendingPlayerControlsPredicate());
|
||||
}
|
||||
|
||||
public AncientHellkite(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}{R}");
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
|
||||
this.power = new MageInt(6);
|
||||
this.toughness = new MageInt(6);
|
||||
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
this.addAbility(new AncientHellkiteAbility());
|
||||
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{R}"), SourceAttackingCondition.instance);
|
||||
ability.addTarget(new TargetPermanent(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public AncientHellkite(final AncientHellkite card) {
|
||||
|
@ -76,71 +81,3 @@ public class AncientHellkite extends CardImpl {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class AncientHellkiteAbility extends ActivatedAbilityImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filterTemplate = new FilterCreaturePermanent("creature defending player controls");
|
||||
|
||||
public AncientHellkiteAbility() {
|
||||
super(Zone.BATTLEFIELD, new DamageTargetEffect(1));
|
||||
addCost(new AncientHellkiteCost());
|
||||
addManaCost(new ColoredManaCost(ColoredManaSymbol.R));
|
||||
addTarget(new TargetCreaturePermanent(filterTemplate));
|
||||
}
|
||||
|
||||
public AncientHellkiteAbility(final AncientHellkiteAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AncientHellkiteAbility copy() {
|
||||
return new AncientHellkiteAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
UUID defenderId = game.getCombat().getDefenderId(sourceId);
|
||||
if (defenderId != null) {
|
||||
FilterCreaturePermanent filter = filterTemplate.copy();
|
||||
filter.add(new ControllerIdPredicate(defenderId));
|
||||
|
||||
this.getTargets().clear();
|
||||
TargetCreaturePermanent target = new TargetCreaturePermanent(filter);
|
||||
this.addTarget(target);
|
||||
return super.activate(game, noMana);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class AncientHellkiteCost extends CostImpl {
|
||||
|
||||
public AncientHellkiteCost() {
|
||||
this.text = "Activate this ability only if Ancient Hellkite is attacking";
|
||||
}
|
||||
|
||||
public AncientHellkiteCost(final AncientHellkiteCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AncientHellkiteCost copy() {
|
||||
return new AncientHellkiteCost(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (permanent != null && permanent.isAttacking()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
this.paid = true;
|
||||
return paid;
|
||||
}
|
||||
|
||||
}
|
|
@ -52,15 +52,17 @@ import mage.game.permanent.Permanent;
|
|||
public class AncientOoze extends CardImpl {
|
||||
|
||||
public AncientOoze(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}");
|
||||
this.subtype.add(SubType.OOZE);
|
||||
|
||||
this.color.setGreen(true);
|
||||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(0);
|
||||
|
||||
// Ancient Ooze's power and toughness are each equal to the total converted mana cost of other creatures you control.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new AncientOozePowerToughnessValue(), Duration.EndOfGame)));
|
||||
// Ancient Ooze's power and toughness are each equal to the total converted mana cost of other creatures you control.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new AncientOozePowerToughnessValue(), Duration.EndOfGame)
|
||||
.setText("{this}'s power and toughness are each equal to the total converted mana cost of other creatures you control.")
|
||||
));
|
||||
}
|
||||
|
||||
public AncientOoze(final AncientOoze card) {
|
||||
|
@ -78,8 +80,8 @@ class AncientOozePowerToughnessValue implements DynamicValue {
|
|||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
int value = 0;
|
||||
for(Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)){
|
||||
if(creature != null && !sourceAbility.getSourceId().equals(creature.getId())){
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)) {
|
||||
if (creature != null && !sourceAbility.getSourceId().equals(creature.getId())) {
|
||||
value += creature.getConvertedManaCost();
|
||||
}
|
||||
}
|
||||
|
|
89
Mage.Sets/src/mage/cards/a/AngelicVoices.java
Normal file
89
Mage.Sets/src/mage/cards/a/AngelicVoices.java
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.InvertCondition;
|
||||
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
|
||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AngelicVoices extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("nonartifact, nonwhite creatures");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.not(
|
||||
Predicates.or(
|
||||
new CardTypePredicate(CardType.ARTIFACT),
|
||||
new ColorPredicate(ObjectColor.WHITE)
|
||||
)
|
||||
));
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
public AngelicVoices(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
|
||||
|
||||
// Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures.
|
||||
this.addAbility(new SimpleStaticAbility(
|
||||
Zone.BATTLEFIELD,
|
||||
new ConditionalContinuousEffect(
|
||||
new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield),
|
||||
new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)),
|
||||
"Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures."
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
public AngelicVoices(final AngelicVoices card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AngelicVoices copy() {
|
||||
return new AngelicVoices(this);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue