Bug Reports (snapshot builds)
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 11:28
It's a flaw project in architecture then, if AI is supposed to execute doTrigger for an ability it does not control...
or there's another possible solution - add AIPlayer parameter to all doTrigger overloads.
It's obvious that canPlayAI and doTrigger must not be called for human player
or there's another possible solution - add AIPlayer parameter to all doTrigger overloads.
It's obvious that canPlayAI and doTrigger must not be called for human player
Last edited by Max mtg on 05 Feb 2013, 11:30, edited 1 time in total.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by moomarc » 05 Feb 2013, 11:29
I can get it working via script if I Make the opponent the trigger controller and adjust the script to this:moomarc wrote:My apologies for leaving out that detail. I was the one that cast the Vexing Devil. Works fine if the opponent casts it.Max mtg wrote:That's just wonderful!moomarc wrote:Crash when Vexing Devil's ETB trigger resolves:
Detailed error trace:
java.lang.ClassCastException: forge.game.player.HumanPlayer cannot be cast to forge.game.player.AIPlayer
at forge.card.abilityfactory.CommonAbility.doTrigger(CommonAbility.java:72)
at forge.card.trigger.WrappedAbility.resolve(WrappedAbility.java:500)
at forge.card.abilityfactory.AbilityFactory.resolve(AbilityFactory.java:1526)
Edit: Changing the OptionalDecider to TriggeredCardOpponent doesn't help.
Who is casting Vexing Devil? If human is, then AI should decide if it wants the devil to deal him 4 dmg and die.
But it turned out that doTrigger was called for human player who is controlling the ability, but cannot choose!
- Code: Select all
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDealDamage | TriggerController$ TriggeredCardOpponent | OptionalDecider$ TriggeredCardOpponent | TriggerDescription$ When CARDNAME enters the battlefield, any opponent may have it deal 4 damage to him or her. If a player does, sacrifice CARDNAME.
SVar:TrigDealDamage:AB$ DealDamage | Cost$ 0 | Defined$ You | NumDmg$ 4 | SubAbility$ DBSacrifice
SVar:DBSacrifice:DB$ Sacrifice | Defined$ Self
Edit: The damage line could also be "DealDamage | Cost$ 0 | Defined$ TriggeredCardOpponent | NumDmg$ 4 | SubAbility$ DBSacrifice" but that's just semantics here. Is the opponent controlling the trigger the correct behaviour? (I realise that this card isn't multiplayer compatible yet and won't be until we store who decided, and for that matter, make it so that any of the opponents could decide).
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 11:36
Marc, might work for 2-player games.
Unsure about multiplayer, but for two players' game will definetelly do the job.
Yet this implementation violates rule 603.3a. (A triggered ability is controlled by the player who controlled its source at the time it triggered, unless it's a delayed triggered ability. To determine the controller of a delayed triggered ability, see rules 603.7d–f.)
Unsure about multiplayer, but for two players' game will definetelly do the job.
Yet this implementation violates rule 603.3a. (A triggered ability is controlled by the player who controlled its source at the time it triggered, unless it's a delayed triggered ability. To determine the controller of a delayed triggered ability, see rules 603.7d–f.)
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by moomarc » 05 Feb 2013, 11:40
In that case I'm not going to commit the hacked fix. I'll leave it up to one of you guys to figure out how to fix it properly.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 11:49
AI cannot respond to this card anyway. It is not even aware that 4/3 will come into play if it refuses to take damage (as it always probably did)
What could be done here is leave the script alone, but pass aiplayer (decider) to doTrigger call - but that involves change of function prototype all over inherited classes (read as: "lots of fun")
What could be done here is leave the script alone, but pass aiplayer (decider) to doTrigger call - but that involves change of function prototype all over inherited classes (read as: "lots of fun")
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by moomarc » 05 Feb 2013, 11:55
That's why I'm happy here on the bottom rung of java codingMax mtg wrote:What could be done here is leave the script alone, but pass aiplayer (decider) to doTrigger call - but that involves change of function prototype all over inherited classes (read as: "lots of fun")

-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Bug Reports (snapshot builds)
by friarsol » 05 Feb 2013, 13:12
This did work fairly recently. What changed to cause it to stop working? I think in general the AI would take the damage unless low on life.Max mtg wrote:AI cannot respond to this card anyway. It is not even aware that 4/3 will come into play if it refuses to take damage (as it always probably did)
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 13:18
It worked before r19394, but did it work correctly?friarsol wrote:This did work fairly recently. What changed to cause it to stop working?Max mtg wrote:AI cannot respond to this card anyway. It is not even aware that 4/3 will come into play if it refuses to take damage (as it always probably did)
As we have just learned human player was checked in doTrigger.
How will you explain it to AI? Ai should evaluate which is worse for it - have opponent sacrifice a 4/3 or avoid 4 damage.friarsol wrote:I think in general the AI would take the damage unless low on life.
What actually happens is doTrigger of forge.card.abilityfactory.ai.DamageDealAi (which is obviusly unaware of 4/3 to come)... called for a wrong player.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by friarsol » 05 Feb 2013, 16:16
Yes? Why would it say it worked otherwise. I cast the creature, the AI would choose to take damage unless it was low on life.Max mtg wrote:It worked before r19394, but did it work correctly?friarsol wrote:This did work fairly recently. What changed to cause it to stop working?Max mtg wrote:AI cannot respond to this card anyway. It is not even aware that 4/3 will come into play if it refuses to take damage (as it always probably did)
Is it the greatest choosing mechanism in the world? No, there's plenty of other things besides "am I low on life" that it could debate. Is this really a threat to me? Can I block it? Can i destroy it with something in hand/play?How will you explain it to AI? Ai should evaluate which is worse for it - have opponent sacrifice a 4/3 or avoid 4 damage.
But it was choosing to kill it unless it couldn't afford to.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 18:03
Read the card script first.friarsol wrote:Is it the greatest choosing mechanism in the world? No, there's plenty of other things besides "am I low on life" that it could debate. Is this really a threat to me? Can I block it? Can i destroy it with something in hand/play?How will you explain it to AI? Ai should evaluate which is worse for it - have opponent sacrifice a 4/3 or avoid 4 damage.
But it was choosing to kill it unless it couldn't afford to.
- Code: Select all
SVar:TrigDealDamage:AB$DealDamage | Cost$ 0 | Defined$ Opponent | NumDmg$ 4 | SubAbility$ DBSacrifice
SVar:DBSacrifice:DB$ Sacrifice | Defined$ Self
doTrigger has been called for human player. That is an error, which would not have been noted if there were no cast to AIPlayer
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by Max mtg » 05 Feb 2013, 19:21
r19416 - added aiPlayer parameters to doTrigger and chkAiDrawback, since the player taking decision is not always the ability activator.
This has fixed Vexing Devil related crash.
This has fixed Vexing Devil related crash.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by lzy » 06 Feb 2013, 15:25
Deathpact Angel should have flying
Last edited by Chris H. on 06 Feb 2013, 15:31, edited 1 time in total.
Reason: mouse-over
Reason: mouse-over
- lzy
- Posts: 3
- Joined: 06 Feb 2013, 15:21
- Has thanked: 0 time
- Been thanked: 0 time
Re: Bug Reports (snapshot builds)
by myk » 06 Feb 2013, 23:24
r19444
java.lang.ClassCastException: forge.game.player.HumanPlayer cannot be cast to forge.game.player.AIPlayer
at forge.game.ai.ComputerUtilMana.payManaCost(ComputerUtilMana.java:70)
Edit: too late for this bug report, but I just checked in a change that allows users to highlight and copy text from the game log in ViewWinLose (the screen that comes up after the match is over) so they can submit it with bug reports like this one.
java.lang.ClassCastException: forge.game.player.HumanPlayer cannot be cast to forge.game.player.AIPlayer
at forge.game.ai.ComputerUtilMana.payManaCost(ComputerUtilMana.java:70)
- Crash report | Open
- This is a Crash Report. An error has occurred. Please save this message to a file.
Please follow the instructions at this address to submit this Crash Report, plus what you were doing at the time:
http://tinyurl.com/3zzrnyb
Reporting bugs in Forge is very important. We thank you for your time.
forge.game.player.HumanPlayer cannot be cast to forge.game.player.AIPlayer
Version:
Forge version 1.3.8-SNAPSHOT-r19444
OS: Linux Version: 3.6.11-gentoo Architecture: amd64
Java Version: 1.6.0_24 Vendor: Sun Microsystems Inc.
Detailed error trace:
java.lang.ClassCastException: forge.game.player.HumanPlayer cannot be cast to forge.game.player.AIPlayer
at forge.game.ai.ComputerUtilMana.payManaCost(ComputerUtilMana.java:70)
at forge.game.ai.ComputerUtilCost.canPayCost(ComputerUtilCost.java:360)
at forge.game.ai.ComputerUtilCombat.predictPowerBonusOfAttacker(ComputerUtilCombat.java:1060)
at forge.game.ai.ComputerUtilCombat.damageIfUnblocked(ComputerUtilCombat.java:125)
at forge.game.ai.AiAttackController.doesHumanAttackAndWin(AiAttackController.java:353)
at forge.game.ai.AiAttackController.notNeededAsBlockers(AiAttackController.java:265)
at forge.game.ai.AiAttackController.getAttackers(AiAttackController.java:780)
at forge.game.ai.AiInputCommon.declareAttackers(AiInputCommon.java:118)
at forge.game.ai.AiInputCommon.showMessage(AiInputCommon.java:97)
at forge.gui.GuiInput.setInput(GuiInput.java:71)
at forge.gui.GuiInput.update(GuiInput.java:54)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.game.phase.PhaseHandler.nextPhase(PhaseHandler.java:515)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:732)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.control.input.InputControl.getActualInput(InputControl.java:239)
at forge.gui.GuiInput.update(GuiInput.java:50)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.control.input.InputControl.resetInput(InputControl.java:141)
at forge.control.input.InputControl.resetInput(InputControl.java:137)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:740)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.game.ai.AiInputCommon.showMessage(AiInputCommon.java:110)
at forge.gui.GuiInput.setInput(GuiInput.java:71)
at forge.gui.GuiInput.update(GuiInput.java:54)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.game.phase.PhaseHandler.nextPhase(PhaseHandler.java:515)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:732)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.control.input.InputControl.getActualInput(InputControl.java:239)
at forge.gui.GuiInput.update(GuiInput.java:50)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.control.input.InputControl.resetInput(InputControl.java:141)
at forge.control.input.InputControl.resetInput(InputControl.java:137)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:740)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.game.ai.AiInputCommon.showMessage(AiInputCommon.java:110)
at forge.gui.GuiInput.setInput(GuiInput.java:71)
at forge.gui.GuiInput.update(GuiInput.java:54)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.game.phase.PhaseHandler.nextPhase(PhaseHandler.java:515)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:732)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.control.input.InputControl.getActualInput(InputControl.java:239)
at forge.gui.GuiInput.update(GuiInput.java:50)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.control.input.InputControl.resetInput(InputControl.java:141)
at forge.control.input.InputControl.resetInput(InputControl.java:137)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:740)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.game.ai.AiInputCommon.showMessage(AiInputCommon.java:110)
at forge.gui.GuiInput.setInput(GuiInput.java:71)
at forge.gui.GuiInput.update(GuiInput.java:54)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.game.phase.PhaseHandler.nextPhase(PhaseHandler.java:515)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:732)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.control.input.InputControl.getActualInput(InputControl.java:239)
at forge.gui.GuiInput.update(GuiInput.java:50)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.control.input.InputControl.resetInput(InputControl.java:141)
at forge.control.input.InputControl.resetInput(InputControl.java:137)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:740)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.game.ai.AiInputCommon.showMessage(AiInputCommon.java:110)
at forge.gui.GuiInput.setInput(GuiInput.java:71)
at forge.gui.GuiInput.update(GuiInput.java:54)
at java.util.Observable.notifyObservers(Observable.java:159)
at java.util.Observable.notifyObservers(Observable.java:115)
at forge.util.MyObservable.updateObservers(MyObservable.java:38)
at forge.game.zone.MagicStack.finishResolving(MagicStack.java:1046)
at forge.card.abilityfactory.AbilityFactory.resolveSubAbilities(AbilityFactory.java:1552)
at forge.card.abilityfactory.AbilityFactory.resolve(AbilityFactory.java:1528)
at forge.game.zone.MagicStack.resolveStack(MagicStack.java:894)
at forge.game.phase.PhaseHandler.passPriority(PhaseHandler.java:735)
at forge.game.player.PlayerController.passPriority(PlayerController.java:72)
at forge.control.input.InputPassPriority.selectButtonOK(InputPassPriority.java:77)
at forge.gui.GuiInput.selectButtonOK(GuiInput.java:80)
at forge.gui.match.controllers.CMessage$2.actionPerformed(CMessage.java:51)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2012)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2335)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:404)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.AbstractButton.doClick(AbstractButton.java:374)
at javax.swing.AbstractButton.doClick(AbstractButton.java:354)
at forge.gui.toolbox.FButton$1.keyPressed(FButton.java:91)
at java.awt.Component.processKeyEvent(Component.java:6347)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2802)
at java.awt.Component.processEvent(Component.java:6166)
at java.awt.Container.processEvent(Container.java:2045)
at java.awt.Component.dispatchEventImpl(Component.java:4750)
at java.awt.Container.dispatchEventImpl(Container.java:2103)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1895)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:769)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1045)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:912)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:734)
at java.awt.Component.dispatchEventImpl(Component.java:4620)
at java.awt.Container.dispatchEventImpl(Container.java:2103)
at java.awt.Window.dispatchEventImpl(Window.java:2518)
at java.awt.Component.dispatchEvent(Component.java:4576)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:672)
at java.awt.EventQueue.access$400(EventQueue.java:96)
at java.awt.EventQueue$2.run(EventQueue.java:631)
at java.awt.EventQueue$2.run(EventQueue.java:629)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:116)
at java.awt.EventQueue$3.run(EventQueue.java:645)
at java.awt.EventQueue$3.run(EventQueue.java:643)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:642)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
Edit: too late for this bug report, but I just checked in a change that allows users to highlight and copy text from the game log in ViewWinLose (the screen that comes up after the match is over) so they can submit it with bug reports like this one.
- myk
- Posts: 439
- Joined: 17 Jan 2013, 02:39
- Location: California
- Has thanked: 38 times
- Been thanked: 57 times
Re: Bug Reports (snapshot builds)
by Max mtg » 07 Feb 2013, 09:17
r19451 should solve that.
AI is calling canPayCost for human player as well... probably to estimate his ability to pump creatures
chkAiDrawback is not performed when evaluating mana human could use.
Guess we should also do something about that huge stack trace. I personally don't like that many nested calls.
AI is calling canPayCost for human player as well... probably to estimate his ability to pump creatures
chkAiDrawback is not performed when evaluating mana human could use.
Guess we should also do something about that huge stack trace. I personally don't like that many nested calls.
Single class for single responsibility.
- Max mtg
- Programmer
- Posts: 1997
- Joined: 02 Jul 2011, 14:26
- Has thanked: 173 times
- Been thanked: 334 times
Re: Bug Reports (snapshot builds)
by friarsol » 07 Feb 2013, 13:14
Yea it would be nice if we had a more traditional game loop, where a state machine is checked each tick and events fired off as necessary. This would allow the AI to bubble down to the base loop after each priority action so their turns don't have this repetitive stack.Max mtg wrote:Guess we should also do something about that huge stack trace. I personally don't like that many nested calls.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Who is online
Users browsing this forum: No registered users and 46 guests