I can attest to having had a bunch of custom cards which worked just fine in earlier versions (just upgraded from 1.4.6) which now cause Forge to crash whenever I try to load decks containing them. Interestingly, it loads the cards into the deck builder just fine. I've gone ahead and reported it, though I can't post a link to the report.
If it helps anyone, the error is always pretty close to:
- NullPointerException | Open
- Code: Select all
Forge Version: 1.5.31-r28300Mu (mixed revisions detected; please update from the root directory)
Operating System: Windows 8 6.2 amd64
Java Version: 1.7.0_21 Oracle Corporation
java.lang.NullPointerException
at forge.card.CardDb$SetPreference.accept(CardDb.java:65)
at forge.card.CardDb.getCardFromEdition(CardDb.java:319)
at forge.card.CardDb.getCardFromEdition(CardDb.java:297)
at forge.card.CardDb.getCardFromEdition(CardDb.java:292)
at forge.card.CardEdition$Collection.getEarliestEditionWithAllCards(CardEdition.java:419)
at forge.deck.DeckProxy.getEdition(DeckProxy.java:102)
at forge.itemmanager.ColumnDef$42.apply(ColumnDef.java:353)
at forge.itemmanager.ColumnDef$42.apply(ColumnDef.java:350)
at forge.itemmanager.views.ItemListView$ItemTableModel.getValueAt(ItemListView.java:707)
at javax.swing.JTable.getValueAt(Unknown Source)
at javax.swing.JTable.prepareRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at forge.toolbox.FSkin$SkinnedTable.paintComponent(FSkin.java:2778)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at forge.toolbox.FScrollPane.paint(FScrollPane.java:86)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager$3.run(Unknown Source)
at javax.swing.RepaintManager$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1000(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Notably, it does just fine with cards that don't exist at all, and doesn't crash until you try to scroll a deck with custom cards into view.
To keep things fun, here's a couple of the offending cards. Yes, they are kind of ridiculous. Was making them mostly to have fun with ideas and see how much I could stretch the engine. They all worked pretty much as intended in earlier versions of Forge. I am curious as to how possible it would be to make Khepri kind of balanced. (kudos to anyone who gets the references, by the way)
- Khepri | Open
- Basically, you control all creatures, but they all get -1/-1. Would have liked to make all their activated abilities more expensive too, but wasn't sure how to do that. Flying Human Advisor for flavor reasons.
- Code: Select all
Name:Khepri
ManaCost:G G U U B B B
Types: Legendary Creature Human Advisor
PT:1/2
K:Flying
A:AB$ GainControl | Cost$ 0 | ValidTgts$ Permanent.Creature | TgtPrompt$ Select target creature | LoseControl$ LeavesPlay,LoseControl | SpellDescription$ Gain control of target creature for as long as you control CARDNAME.
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ -1 | AddToughness$ -1 | Description$ Creatures you control get -1/-1.
Oracle:Flying\nCreatures you control get -1/-1.\n{0}: Gain control of target creature for as long as you control Khepri.
- Behemoth | Open
- Huge, shrouded thing that deals tons of undirected damage and can redirect damage targeted at it. Goes back into the deck from the graveyard to make it a bit trickier to cheat out.
- Code: Select all
Name:Endbringer Behemoth
ManaCost:2 R R R B B B
Types:Legendary Creature Endbringer
PT:8/10
K:Shroud
K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library.
A:AB$ DamageAll | Cost$ T X | XColor$ R | NumDmg$ X | References$ X | ValidCards$ Creature.Other | ValidPlayers$ Each | ValidDescription$ each creature without flying and each player. | SpellDescription$ CARDNAME deals X damage to each other creature and each player.
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ TrigDamage | Description$ If damage would be dealt to CARDNAME, redirect it to target creature or player.
SVar:X:Count$xPaid
SVar:TrigShuffle:AB$ ChangeZoneAll | Cost$ 0 | Defined$ TriggeredCardOwner | ChangeType$ Card | Origin$ Graveyard | Destination$ Library | Shuffle$ True
SVar:TrigDamage:AB$ DealDamage | Cost$ 0 | ValidTgts$ Creature,Player | TgtPrompt$ Select target creature or player | NumDmg$ DmgDealt | SpellDescription$ CARDNAME redirects damage to target creature or player.
SVar:DmgDealt:ReplaceCount$DamageAmount
Oracle:Shroud/nTrample/nWhen Behemoth is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library.\nIf damage would be dealt to Behemoth, redirect it to target creature or player.\n{T}{X}: Behemoth deals X damage to each other creature and each player. Spend only red mana on this ability.
- Leviathan | Open
- Huge, shrouded thing that has islandwalk, turns lands into islands when it attacks, and can tap to deal damage divided as you like equal to the number of islands on the battlefield. I screwed up the 'turning lands into islands' thing a bit and it doesn't change the name of the lands, but it does in fact cause them to tap for U, so I didn't bother to fix it. At about this time I got bored of writing out the oracle text.
- Code: Select all
Name:Endbringer Leviathan
ManaCost:2 U U U B B B
Types:Legendary Creature Endbringer
PT:8/10
K:Shroud
K:Islandwalk
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigAttack | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, target land becomes an Island. This effect lasts indefinitely.
A:AB$ DealDamage | Cost$ T | ValidTgts$ Creature,Player | TgtPrompt$ Select target creature and/or player to distribute damage to | NumDmg$ X | References$ X,MaxTgts | TargetMin$ 0 | TargetMax$ X | DividedAsYouChoose$ X | References$ X| SpellDescription$ Deal X damage, divided as you choose among any number of target creatures and players, where X is the number of Islands on the battlefield.
SVar:NumPlayers:PlayerCountPlayers$Amount/Plus.NumCreatures
SVar:NumCreatures:Count$Valid Creature
SVar:MaxTgts:SVar$NumPlayers/Plus.1
SVar:X:Count$Valid Island
SVar:TrigAttack:AB$ Animate | Cost$ 0 | ValidTgts$ Land | TgtPrompt$ Select target land | Types$ Island | OverwriteTypes$ True | KeepSupertypes$ True | KeepCardTypes$ True | RemoveAllAbilities$ True | Permanent$ True | SpellDescription$ Target land becomes an Island.
SVar:TrigShuffle:AB$ ChangeZoneAll | Cost$ 0 | Defined$ TriggeredCardOwner | ChangeType$ Card | Origin$ Graveyard | Destination$ Library | Shuffle$ True
Oracle:Yadda yadda.
Also, this is a card I've been working on but haven't gotten able to work. At first I thought it was a problem with the card, but now I'm not sure since Forge has been breaking on other known to work cards as well. If it raises any red flags please let me know.
- Gogmazios | Open
- Huge, black, legendary lizard with monstrosity 10 for 5xB + 5xR. Before turning monstrous, can tap a creature for B B and it won't untap next turn. After turning monstrous, it immediately gains flying and deals 5 damage to each creature and player, and it gains a copy of its old ability for BR BR which also deals 3 damage to the targeted creature. Mostly to see if it was possible, I tried to have it enter the battlefield with a custom named counter on it, and let it tap and remove the counter to deal 10 damage to a creature. Most of what I did with this card was just to see if I could get forge to do it, though it also makes a pretty amazing over the top win condition, and everything it can do is inspired by what its a reference to. Different from the other three, I might add.
- Code: Select all
Name:Gogmazios
ManaCost: B B B B B B
Types: Legendary Creature Lizard
PT:10/10
K: Monstrosity 10:B B B B B R R R R R
S:Mode$ Continuous | Affected$ Card.Self+IsMonstrous | AddKeyword$ Flying | Description$ As long as CARDNAME is monstrous, it has flying.
T:Mode$ ChangesZone | ValidCard$ Card.wasCastFromHand+Self | Destination$ Battlefield | Static$ True | Execute$ ETBCounter | TriggerDescription$ CARDNAME enters the battlefield with a dragonator counter on it if you cast it from your hand.
SVar:ETBCounter:AB$PutCounter | Cost$ 0 | Defined$ Self | CounterType$ DRAGONATOR | CounterNum$ 1
T:Mode$ BecomeMonstrous | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDamage | SubAbility$ MonAni | TriggerDescription$ When CARDNAME becomes Monstrous, it does five damage to each other creature and each player, and gains "{RB}{RB}: Tap target creature, and CARDNAME does three damage to it. It does not untap during its controller's next untap step."
SVar:TrigDamage:AB$ DamageAll | Cost$ 0 | NumDmg$ 3 | ValidCards$ Creature.Other | ValidPlayers$ Each
A:AB$ DealDamage | Cost$ T SubCounter<1/DRAGONATOR> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 10 | SpellDescription$ CARDNAME deals 10 damage to target creature.
A:SP$ Tap | Cost$ B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBPump | SpellDescription$ Tap target creature. That creature doesn't untap during its controller's next untap step.
SVar:DBPump:DB$ PumpAll | Defined$ Targeted | ValidCards$ Creature | KW$ HIDDEN This card doesn't untap during your next untap step. | Permanent$ True
SVar:MonAni:Mode$ Animate$ | Cost$ 0 | ValidTarget$ Self | sVars$ModTap
SVar:ModTap:AB$ Tap | Cost$ BR BR | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBDamage | SpellDescription$ Tap target creature and CARDNAME does three damage to it. That creature doesn't untap during its controller's next untap step.
SVar:DBDamage:AB$ Deal Damage | Cost$ 0 | ValidTgts$ Target | NumDmg$ 3 | SubAbility$ DBPump
Oracle:{B}{B}{B}{B}{B}{R}{R}{R}{R}{R}: Monstrosity 10. (If this creature isn't monstrous, put ten +1/+1 counters on it and it becomes monstrous.\nWhen Gogmazios becomes monstrous, it deals five damage to each other creature and each player, and gains flying and "{BR}{BR}: Tap target creature, and Gogmazios does three damage to it. It does not untap during its controller's next untap step."\nGogmazios enters the battlefield with a Dragonator counter on it.\n{T}, remove one Dragonator counter from Gogmazios: Deal ten damage to target creature.\n{B}{B}: Tap target creature. It does not untap during its controller's next untap step.