It is currently 27 Aug 2025, 21:20
   
Text Size

Bug Reports (snapshot builds)

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Re: Bug Reports (snapshot builds)

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

Postby moomarc » 05 Feb 2013, 11:29

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).
-Marc
User avatar
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)

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

Postby 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
User avatar
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)

Postby 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")
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)

Postby moomarc » 05 Feb 2013, 11:55

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:
-Marc
User avatar
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)

Postby friarsol » 05 Feb 2013, 13:12

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.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Bug Reports (snapshot builds)

Postby Max mtg » 05 Feb 2013, 13:18

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

Postby friarsol » 05 Feb 2013, 16:16

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.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Bug Reports (snapshot builds)

Postby Max mtg » 05 Feb 2013, 18:03

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

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

Postby 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
lzy
 
Posts: 3
Joined: 06 Feb 2013, 15:21
Has thanked: 0 time
Been thanked: 0 time

Re: Bug Reports (snapshot builds)

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

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.
myk
 
Posts: 439
Joined: 17 Jan 2013, 02:39
Location: California
Has thanked: 38 times
Been thanked: 57 times

Re: Bug Reports (snapshot builds)

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

Postby friarsol » 07 Feb 2013, 13:14

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.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 30 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 30 users online :: 0 registered, 0 hidden and 30 guests (based on users active over the past 10 minutes)
Most users ever online was 7303 on 15 Jul 2025, 20:46

Users browsing this forum: No registered users and 30 guests

Login Form