Jump to content

MTGO trading


Recommended Posts

I've been working on writing up some stuff for a trading bot for the Magic the gathering online game. Most of the core features i found here and there, but I wanted to share and get some feedback or help since there really was none when I was looking. The scripts I have so far will pretty much perform all the essential operations the bot is based on. I'd appreciate any comments or suggestions if you have any, and the code is extremely long since I'm almost done with it. It's based on OCR to determine what is being traded, enjoy! I haven't rn or compiled the whole thing since putting the parts together and adding stuff yet. It still needs a GUI to really be practical.

; http://msdn2.microsoft.com/en-us/library/a...office.11).aspx
#include <GUIConstants.au3>
#include <Array.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>
Dim $CardName
Dim $CardSet
Dim $CardQty
Dim $Update

;to update price lists, set update to 1, to only update several, change the statements in the program
$Update = 1
;StandingReserve's commonBot
;Version: 0.11
$tradeOn = 1
$maxtime = 600000
;add leftovers info
$greetMessage = "Hello, I'm an automated trader.  As you select cards, I will show you prices and update the total cost.  You have 10 minutes to complete your trade.  If you encounter any problems please PM betterwork."
$noTicket = "You have no tickets tradeable.  Please make a ticket tradeable or exit the trade"
$iniFileLines = 8
$os = "2000"
$resolutionX = 1024
$resolutionY = 768
$colordepth = 32

;Variables for screen locations
;Variables for checksum location for looking for beginning of trade
$top = 415
$left = 500
$bottom = 420
$right = 505

;Variables for checking for withdrawing from trade
;PixelGetColor(639,329) = 3356477 then
$withdrawX = 639
$withdrawY = 329
$withdrawColor = 3356477

;Variable to recognize 32 cards
;80,280,100,300
$CardTarget = 490423324
$cardTakenX1 = 80
$cardTakenY1 = 280
$cardTakenX2 = 100
$cardTakenY2 = 300

;Location of ticket already taken
;MouseClick("left",185,155,1,10)
$myTicketX = 185
$myTicketY = 155

;Variables for narrowing our search down to just tickets
;MouseClick("left",80,62,1,10)
;MouseClick("left",240,144,1,0)
;MouseClick("left",160,200,1,10)
$searchX = 80
$searchY = 62
$dropX = 240
$dropY = 144
$boosterX = 160
$boosterY = 200

;Ticket to take location
;if PixelGetColor(420,155) <> 9185056 then
$ticketX = 420
$ticketY = 155
$ticketColor = 9185056

;Tradebutton Location
;MouseClick("left",195,60,1,10)
$tradeButtonX = 195
$tradeButtonY = 60

;Make sure they don't cheat the bot
$cheatCheckX = 195
$cheatCheckY = 140
$myTicketsBackground = 2969133

;Variables for confirming the trade
$confirmDropX = 240
$confirmDropY = 330
$confirmClickX = 170
$confirmClickY = 345

;Variables to determine if they have confirmed
$theirConfirmX1 = 45
$theirConfirmY1 = 325
$theirConfirmX2 = 60
$theirConfirmY2 = 330
$theirConfirmChecksum = 518491551


;Final trade confirmation
$performThisTradeX = 715
$performThisTradeY = 600
$performThisTradeWaitX1 = 300
$performThisTradeWaitY1 = 460
$performThisTradeWaitX2 = 305
$performThisTradeWaitY2 = 465

;Checking for completed Trade
$tradeCompletedX = 500
$tradeCompletedY = 400
$tradeCompletedColor = 3290940
$tradeCompletedCheckX = 614
$tradeCompletedCheckY = 424
$completedDragStartX = 525
$completedDragStartY = 60
$completedDragFinishX = 800
$completedDragFinishY = 60
$completedDragClickX = 1000
$completedDragClickY = 55

;Canceling Trade Variables
$cancelTradeX = 775
$cancelTradeY = 600

;reset from withdrawel variables
$resetX = 606
$resetY = 418

;Chat location
$chatX = 285
$chatY = 710

;CardsRequest location
$RequestLeft = 19
$RequestRight = 412
$RequestTop = 209
$RequestBottom = 593

If $Update = 1 Then;update pricelists
    ListUpdate(SHM);shadowmoor
    ListUpdate(MOR);morningtide
    ListUpdate(LRW);lorwyn
    ListUpdate(FUT);futuresight
    ListUpdate(PLC);planar chaos
    ListUpdate(TSP);time spiral
    ListUpdate(CSP);coldsnap
    ListUpdate(10TH);tenth edition
    EndIf
Func OCR($left, $top, $right, $bottom);pass bounds to capture
Dim $miDoc, $Doc
Dim $str
Dim $oWord
Dim $sArray[500]
Dim $count
Const $miLANG_ENGLISH = 9
#CS Const $miLANG_ITALIAN = 16
    Const $miLANG_CZECH = 5
    Const $miLANG_DANISH = 6
    Const $miLANG_DUTCH = 19
    Const $miLANG_FINNISH = 11
    Const $miLANG_FRENCH = 12
    Const $miLANG_GERMAN = 7
    Const $miLANG_GREEK = 8
    Const $miLANG_HUNGARIAN = 14
   Const $miLANG_JAPANESE = 17
   Const $miLANG_KOREAN = 18
   Const $miLANG_NORWEGIAN = 20
   Const $miLANG_POLISH = 21
   Const $miLANG_PORTUGUESE = 22
   Const $miLANG_RUSSIAN = 25
   Const $miLANG_SPANISH = 10
   Const $miLANG_SWEDISH = 29
   Const $miLANG_TURKISH = 31
   Const $miLANG_SYSDEFAULT = 2048
   Const $miLANG_CHINESE_SIMPLIFIED = 2052
   Const $miLANG_CHINESE_TRADITIONAL = 1028
#CE

; Initialize error handler 
$oMyError = ObjEvent("AutoIt.Error","MyErrFunc")

;take screenshot
    $sTargetImage = "C:\Users\Brian\Desktop\mtgobot\OCR_tgt.jpg"
    _ScreenCapture_Capture($sTargetImage, $left, $top, $right, $bottom, $fCursor = False)

$miDoc = ObjCreate("MODI.Document")
$miDocView = ObjCreate("MiDocViewer.MiDocView")
$miDoc.Create("C:\Users\Brian\Desktop\mtgobot\OCR_tgt.jpg")
$miDoc.Ocr($miLANG_ENGLISH, True, False)

$i = 0

For $oWord in $miDoc.Images(0).Layout.Words

    $str = $str & $oWord.text & @CrLf
        ConsoleWrite($oWord.text & @CRLF)
    $sArray [$i] = $oWord.text
    $i += 1
Next
_FileWriteFromArray("C:\Users\Brian\Desktop\mtgobot\OCR_tgt.txt", $sArray, 1)
;test display array
;_ArrayDisplay($sArray,"OCR Result")



EndFunc

Func Done();look for done statement
Dim $miDoc, $Doc
Dim $str
Dim $oWord
Dim $sArray[500]
Dim $count
Const $miLANG_ENGLISH = 9

;take screenshot
    $sTargetImage = "C:\Users\Brian\Desktop\mtgobot\DONE_tgt.jpg"
    _ScreenCapture_Capture($sTargetImage, $left, $top, $right, $bottom, $fCursor = False); put in values to look for done

$miDoc = ObjCreate("MODI.Document")
$miDocView = ObjCreate("MiDocViewer.MiDocView")
$miDoc.Create("C:\Users\Brian\Desktop\mtgobot\DONE_tgt.jpg")
$miDoc.Ocr($miLANG_ENGLISH, True, False)

$i = 0

For $oWord in $miDoc.Images(0).Layout.Words

    $str = $str & $oWord.text & @CrLf
        ConsoleWrite($oWord.text & @CRLF)
    $sArray [$i] = $oWord.text
    $i += 1
Next
; sort the array to be able to do a binary search
$sArray = StringLower(_ArrayToString($sArray))
_ArraySort($sArray)
return _ArrayBinarySearch($sArray, "done")
EndFunc

Func PlayerName()
    EndFunc

;------------------------------ This is a COM Error handler --------------------------------
Func MyErrFunc()
  $HexNumber=hex($oMyError.number,8)
  Msgbox(0,"COM Error Test","We intercepted a COM Error !"     & @CRLF  & @CRLF & _
             "err.description is: " & @TAB & $oMyError.description  & @CRLF & _
             "err.windescription:"   & @TAB & $oMyError.windescription & @CRLF & _
             "err.number is: "       & @TAB & $HexNumber              & @CRLF & _
             "err.lastdllerror is: "   & @TAB & $oMyError.lastdllerror   & @CRLF & _
             "err.scriptline is: "   & @TAB & $oMyError.scriptline   & @CRLF & _
             "err.source is: "       & @TAB & $oMyError.source       & @CRLF & _
             "err.helpfile is: "       & @TAB & $oMyError.helpfile     & @CRLF & _
             "err.helpcontext is: " & @TAB & $oMyError.helpcontext _
            )
  SetError(1) ; to check for after this function returns
Endfunc

Func GetName();will only do one card for now, returns the card name
    _FileReadToArray("C:\Users\Brian\Desktop\mtgobot\OCR_tgt.txt", $sArray, 1)
    $i = 1

While StringIsDigit($sArray[$i]) = 0
    $CardName += " " & $sArray[$i]
    $i += 1
WEnd
    StringTrimLeft($CardName,1)
    return $CardName
EndFunc

Func GetQty($sArray);will only do one card for now, returns the quantity selected for trade
    _FileReadToArray("C:\Users\Brian\Desktop\mtgobot\OCR_tgt.txt", $sArray, 1)
    $i = 1
    $CardQty = 0
While $CardQty = 0
If StringIsDigit($sArray[$i]) = 1 Then
    $CardQty = $sArray[$i]
    Else
    $i += 1
EndIf
WEnd
return number($CardQty)
EndFunc

Func GetPrice($CardSet, $CardName);Pass abbreviated card set and card name
    Dim $Arrayline[999]
    Dim $PriceList[999][10]
    Dim $col
    Dim $row
    Dim $i
    
    _FileReadToArray("C:\Users\Brian\Desktop\mtgobot\Price_"&$CardSet&".txt",$Arrayline)
            $row = _ArraySearch($Arrayline, $CardName)+1
    return $Arrayline[$row]
EndFunc

Func GetSet()
    
EndFunc

Func ListUpdate($CardSet);Pass abbreviated card set
Dim $Arrayline[999]
Dim $PriceList[999][10]
Dim $col
Dim $row
Dim $oHTTP
Dim $HTMLSource
Dim $i

        $oHTTP = ObjCreate("winhttp.winhttprequest.5.1")
    $oHTTP.Open("GET","http://www.magictraders.com/cgi-bin/set_query.cgi?set="&$CardSet&"&excel=true") 
    $oHTTP.Send()
    $HTMLSource = $oHTTP.Responsetext
    $HTMLSource = StringTrimLeft($HTMLSource, StringInStr($HTMLSource, "Card")-1)
    $HTMLSource = StringReplace($HTMLSource,@LF,"|");couldn't get it without this intermediate step, unsure why
    $Arrayline = StringSplit($HTMLSource, "|")
$col = 1
$row = 0
$i = 1
                for $col = 1 to 8
                    $PriceList[$row][$col] = $Arrayline[$i]
                    $i = $i + 1
                Next
                $row = 1
      While $i <= $Arrayline[0]-8
                for $col = 1 to 8
                    $PriceList[$row][$col] = $Arrayline[$i]
                    $i = $i + 1
                Next
                $row = $row + 1
            WEnd
            _FileWriteFromArray("C:\Users\Brian\Desktop\mtgobot\Price_"&$CardSet&".txt",$Arrayline, 1)
            Run("Notepad.exe " & "C:\Users\Brian\Desktop\mtgobot\Price_"&$CardSet&".txt")

    EndFunc
    
;This function waits until the trade window pops up at a specific point.
Func waitForTrade($left,$top,$right,$bottom)
    $checksum = PixelChecksum($left,$top,$right,$bottom)
    while $checksum = PixelChecksum($left,$top,$right,$bottom)
        Sleep(100)
    WEnd
        enterTrade($left,$top)
EndFunc

Func enterTrade($x,$y)
    MouseClick("left",$x,$y, 1, 0)
    SellCards()
EndFunc

Func SellCards()
    sendMessage($greetMessage)
    $startTime = TimerInit()
    $ticketTaken = 0
    $temp = 1
    $confirmed = 0
    mouseClick("left",$myTicketX, $myTicketY, 1, 0)
    while $temp = 1

    ;First check if they have withdrawn from trade
        if PixelGetColor($withdrawX, $withdrawY) = $withdrawColor then
            ResetFromWithdraw()
        endif

    ;The checksum changes when a card has been added or subtracted
        $checksum = PixelChecksum($cardTakenX1, $cardTakenY1, $cardTakenX2 , $cardTakenY2)
        While $checksum = PixelChecksum($cardTakenX1, $cardTakenY1, $cardTakenX2 , $cardTakenY2)
            Sleep(100)
        WEnd
        
        OCR($RequestLeft, $RequestTop, $RequestRight, $RequestBottom);add ocr, write back, wait for done command
        
        $CardName = GetName()
        $CardSet = GetSet()
        $CardQty = GetQty()
        $CardPrice = GetPrice($CardSet, $CardName)
        sendMessage($CardName & " (" & $CardPrice & ")" & "total is " & Number($CardPrice*$CardQty) " type 'done' when finished")
        
        $TixQty = Ceiling($CardPrice*$CardQty)
        if Done() = <> -1 Then TakeTickets($TixQty)
        
        ;Make sure that they don't remove their ticket
            $safetyChecksum = PixelGetColor($cheatCheckX, $cheatCheckY)
            if $safetyChecksum = $myTicketsBackground then
                SendMessage("Please do not alter the trade")
            else
                if $confirmed = 0 then
                    MouseClick("left",$confirmDropX, $confirmDropY,1,10)
                    Sleep(50)
                    MouseClick("left",$confirmClickX, $confirmClickY,1,10)
                    $confirmed = 1
                endif
                
                if PixelGetColor($withdrawX, $withdrawY) = $withdrawColor then
                    ResetFromWithdraw()
                endif

                $confirmchecksum = PixelChecksum($theirConfirmX1, $theirConfirmY1, $theirConfirmX2, $theirConfirmY2)
                if $confirmchecksum = $TheirConfirmChecksum then
                    sleep(2000)
                    if PixelGetColor($withdrawX, $withdrawY) = $withdrawColor then
                        ResetFromWithdraw()
                    endif
                    performThisTrade()
                endif
            endif


        if TimerDiff($startTime) > $maxtime then
            abortTrade()
        endif
        
    ;Slow down the bot some
        sleep(500)
    wend        
EndFunc

Func performThisTrade()
    MouseClick("left",$performThisTradeX, $performThisTradeY)
    $waitchecksum = PixelChecksum($performThisTradeWaitX1,$performThisTradeWaitY1,$performThisTradeWaitX2,$performThisTradeWaitY2)
    while $waitchecksum = PixelChecksum($performThisTradeWaitX1,$performThisTradeWaitY1,$performThisTradeWaitX2,$performThisTradeWaitY2)
        sleep(20)
    wend
;see if they confirmed
    if pixelGetColor($tradeCompletedX, $tradeCompletedY) = $tradeCompletedColor then
        MouseClick("left",$tradeCompletedCheckX, $tradeCompletedCheckY)
        sleep(10)
        MouseClickDrag("left",$completedDragStartX, $completedDragStartY, $completedDragFinishX, $completedDragFinishY)
        MouseClick("left",$completedDragClickX,$completedDragClickY)
        waitForTrade($left,$top,$right,$bottom)
    else
    ;they canceled, we need to recover
        MouseClick("left",$tradeButtonX, $tradeButtonY)
        SellCards()
    endif
EndFunc

Func abortTrade()
    MouseClick("left",$cancelTradeX ,$cancelTradeY)
    sleep(500)
    waitForTrade($left,$top,$right,$bottom) 
EndFunc

Func resetFromWithdraw()
    MouseClick("left",$resetX,$resetY)
    waitForTrade($left,$top,$right,$bottom)
EndFunc

Func sendMessage($messageString)
    MouseClick("left",$chatX, $chatY)
    Send($messageString)
    Send("{ENTER}")
EndFunc

Func TakeTickets($TixQty)
    For $i = 1 to $TixQty
                ;Find a ticket
                MouseClick("left",$searchX , $searchY,1,10)
                Sleep(100)
                MouseClick("left",$dropX,$dropY,1,0)
                Sleep(100)
                MouseClick("left",$boosterX,$boosterY,1,10)
                Sleep(6000)
                if PixelGetColor($ticketX, $ticketY) <> $ticketColor then
                ;They don't have a ticket up for trade
                    sendMessage($noTicket)
                    Sleep(20)
                    MouseClick("left", $tradeButtonX, $tradeButtonY,1,10)
                else
                    MouseClick("left",$ticketX, $ticketY,1,10)
                    Sleep(20)
                    MouseClick("left",$tradeButtonX, $tradeButtonY,1,10)
                    $ticketTaken += 1
                    $confirmed = 0
                endif
            Next
        EndFunc

;These are values for checking the numbers of cards being transfered
;1: 3679399253
;2: 1426267079
;3: 4173342256
;4: 1439835295
;5: 1724459089
;6: 2880646084 
;7: 1121135944 
;8: 1938694045 
;9: 3701681956
;10: 493890957
;11: 1740194342
;12: 2902536487
;13: 476855108
;14: 1477851429
;15: 1764179205
;16: 1983987807
;17: 4997678
;18: 1694577754
;19: 387007444
;20: 3295953430
;21: 193285263
;22: 1355627408
;23: 3223930285
;24: 4224926606
;25: 217270126
;26: 437078728
;27: 2752072855
;28: 147668675
;29: 3134082621
;30: 1749044351
;31: 1753762558
;32: 2916104703 OR 490423324
;Unconfirmed: 406357036
;Confirmed: 518491551
;Binder Ring: 16382453 (x:639 y:329)
;MessageWindow Background: 3356477
Link to comment
Share on other sites

Nice topic. I'm prepared to help. I'm also working on my own bot...

Your code seems to work only with version 2. I don't have experience with OCR, but I think that PixelChecksum will return better results. Cannot see any login procedure, connection with database, don't use PixelGetColor(),...

Edited by Durovec
Link to comment
Share on other sites

Nice topic. I'm prepared to help. I'm also working on my own bot...

Your code seems to work only with version 2. I don't have experience with OCR, but I think that PixelChecksum will return better results. Cannot see any login procedure, connection with database, don't use PixelGetColor(),...

I'm not totally sure what I'm doing in the first place, but I haven't actually been able to test this at all in game yet. There is no login, I'm working on a GUI with controls to turn the bot on and off, so if the connection is lost for now thats a problem. I'd definitely apprecfiate any help.

Here's what i know works:

The ocr accurately identifies words and take screenshots of specified coordinates.

The price lists can be automatically updated.

The bot displays a message when the screen changes where it's looking for a trade window to open

The Checksum issue is this: how can you tell what the card name actually is you're looking at? The idea of this bot is you tell it to figure out the card name that shows up when a person selects to trade for it.

Thanks for the reply

Link to comment
Share on other sites

I like it! I haven't looked at any MTGO bots yet, but I've played MTGO before and I was thinking of making one. What had me stumped is how I was going to determine what cards I was looking at. Your use of OCR is exactly what I'm looking for.

I'm not totally sure what I'm doing in the first place, but I haven't actually been able to test this at all in game yet. There is no login, I'm working on a GUI with controls to turn the bot on and off, so if the connection is lost for now thats a problem. I'd definitely apprecfiate any help.

I think I'd worry about getting the whole process to work before working on a GUI to turn it off and on. That way you can handle disconnects. You can always go back in and add a way to turn it on and off later. Generally the way I go about it is program a working bot first then handle a GUI.

The Checksum issue is this: how can you tell what the card name actually is you're looking at? The idea of this bot is you tell it to figure out the card name that shows up when a person selects to trade for it.

That's what I was thinking.. OCR will give you the ability to price cards. He may be speaking from the perspective of writing a "3:1 or 2:1" bot, where you don't have to worry as much about what you're looking at. All you would have to do is filter out the cards you already have alot of and trade.

Anyways good job so far :-o

Link to comment
Share on other sites

The ocr accurately identifies words and take screenshots of specified coordinates.

I got started on the OCR function and I'm having difficulties with it. When I use an image of a card and give it to the reader the array returned skips over the name and starts with the rules text. If I crop the card.bmp file to just the title- it does capture the title like I wanted. However, it is reading "Calciderm" as ((Caiciderm . I tried cropping the bubble part of the title to remove the ((s but then it won't read the name again. Even if I leave those ((s there, I still have the issue that its reading Calciderm as Caiciderm. Are you running into any similar problems? I suppose I could just ignore them.. and in my database I'd have to call "calciderm" caiciderm.. but I'd rather find a solution than a work-around.

Link to comment
Share on other sites

I got started on the OCR function ...........into any similar problems? I suppose I could just ignore them.. and in my database I'd have to call "calciderm" caiciderm.. but I'd rather find a solution than a work-around.

Good to know, I'll look into it some more and see what I get. I'm on a 1024 x 768 resolution how bout you? O hey I gotta mention something. Don't use the cards vew, use the list view. It will work much better.

I wanted to post a screenshot to show how to put it in list mode but it only will insert images from the web. its attached instead see the arrow that button goes to list view, on top its on card view. I'll post the results of my ocr findings later, will try to read some cards from my deck editor's sideboard (might be same location as trade window).

post-37317-1215731898_thumb.jpg

Link to comment
Share on other sites

Ok, I'm going back to setting up the bot piece by piece. Here are my results so far and a few special instructions. First I replaced the marbled background image with just a black one so the ocr works better. Then I set up the GUI so the only thing that runs is the OCR when i tell the bot to run. I'm attaching my code as a file., and also the black bg. My results on this were that it took the screenshot of my sideboard cards and got every single card name correct. Next I'll be testing the price referrencing i think. If you guys need any help with running the script as it is so far, let me know, r if you have suggestions.

bot.au3

post-37317-1215752991_thumb.png

Link to comment
Share on other sites

  • 10 months later...

Ok, I'm going back to setting up the bot piece by piece. Here are my results so far and a few special instructions. First I replaced the marbled background image with just a black one so the ocr works better. Then I set up the GUI so the only thing that runs is the OCR when i tell the bot to run. I'm attaching my code as a file., and also the black bg. My results on this were that it took the screenshot of my sideboard cards and got every single card name correct. Next I'll be testing the price referrencing i think. If you guys need any help with running the script as it is so far, let me know, r if you have suggestions.

hi there.. i'm new here and i'm trying to make a trader bot for MTGO. I'm good at programming.. cause i'm creative.. but.. i have very big problems when i don't know anything like.. OCR.. what is ORC???. I understand a big part of your bot but i don't get how to know what card was selected by the customer}

plz help me i'll be very grateful

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...