Page 84 of 487

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:28
by Max mtg
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

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:29
by moomarc
moomarc wrote:
Max mtg wrote:
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.
That's just wonderful!
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!
My apologies for leaving out that detail. I was the one that cast the Vexing Devil. Works fine if the opponent casts it.
I can get it working via script if I Make the opponent the trigger controller and adjust the script to this:
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
I don't know if that's the correct fix though or just cover-up.

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

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:36
by Max mtg
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.)

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:40
by moomarc
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.

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:49
by Max mtg
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")

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 11:55
by moomarc
Max 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")
That's why I'm happy here on the bottom rung of java coding :wink:

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 13:12
by friarsol
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)
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.

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 13:18
by Max mtg
friarsol wrote:
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)
This did work fairly recently. What changed to cause it to stop working?
It worked before r19394, but did it work correctly?

As we have just learned human player was checked in doTrigger.

friarsol wrote:I think in general the AI would take the damage unless low on life.
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.
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.

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 16:16
by friarsol
Max mtg wrote:
friarsol wrote:
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)
This did work fairly recently. What changed to cause it to stop working?
It worked before r19394, but did it work correctly?
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.

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

But it was choosing to kill it unless it couldn't afford to.

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 18:03
by Max mtg
friarsol wrote:
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.
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?

But it was choosing to kill it unless it couldn't afford to.
Read the card script first.
Code: Select all
SVar:TrigDealDamage:AB$DealDamage | Cost$ 0 | Defined$ Opponent | NumDmg$ 4 | SubAbility$ DBSacrifice
SVar:DBSacrifice:DB$ Sacrifice | Defined$ Self
This is what AI is to decide about. No reference to creature, obviously.


doTrigger has been called for human player. That is an error, which would not have been noted if there were no cast to AIPlayer

Re: Bug Reports (snapshot builds)

PostPosted: 05 Feb 2013, 19:21
by Max mtg
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.

Re: Bug Reports (snapshot builds)

PostPosted: 06 Feb 2013, 15:25
by lzy
 Deathpact Angel should have flying

Re: Bug Reports (snapshot builds)

PostPosted: 06 Feb 2013, 23:24
by myk
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)

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)


apu_crash.jpeg

gamelog.jpeg


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.

Re: Bug Reports (snapshot builds)

PostPosted: 07 Feb 2013, 09:17
by Max mtg
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.

Re: Bug Reports (snapshot builds)

PostPosted: 07 Feb 2013, 13:14
by friarsol
Max mtg wrote:Guess we should also do something about that huge stack trace. I personally don't like that many nested calls.
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.