Advertisement
pneum0re

OpenDota API for your Eggdrop Bot

Jun 7th, 2018
363
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 16.95 KB | None | 0 0
  1. ############################################################
  2. #                                                          #
  3. # Author:  Kim "kimpact" Slavinjak                         #
  4. # E-Mail:  kim@kimpact.info                                #
  5. # IRC:     #kimpact @ quakenet                             #
  6. # Date:    08.06.2018                                      #
  7. # Version: 0.2                                             #
  8. # Info:    This script uses the OpenDota API to call REST  #
  9. #          services  and fetch json data to display over   #
  10. #          your Eggdrop Bot. This script will create a     #
  11. #          a file called recentmatch in your home          #
  12. #          directory to remember the last game you played. #
  13. #          If you have questions, need help or have        #
  14. #          suggestions feel free to email me or find me    #
  15. #          on quakenet                                     #
  16. #                                                          #
  17. # Installation:                                            #
  18. #                                                          #
  19. #       You need these lines in your eggdrop.conf          #
  20. #     -) set dotaapi(owner_steamid) "10694300"             #
  21. #            -> change the number to your steamid32        #
  22. #     -) set dotaapi(post_recent_matches) 1                #
  23. #            -> set this param to 1 and the bot will       #
  24. #               look if your steamid has played a new      #
  25. #               match every 40 minutes and post the stats  #
  26. #               in the channel below                       #
  27. #     -) set dotaapi(channel) "#kimpact"                   #
  28. #            -> change to the channel you want the bot     #
  29. #               to post stats in                           #
  30. #     -) source scripts/dotaapi.tcl                        #
  31. #                                                          #
  32. # History:                                                 #
  33. #                                                          #
  34. #     -) 08.06.18 - Init of the tcl script                 #
  35. #     -) 09.06.18 - Added proc to periodically check       #
  36. #               recent matches of designated player        #
  37. #               in eggdrop conf defined player             #
  38. #               and write it publicly to channel           #
  39. #     -) 13.06.18 - Added call to return latest match      #
  40. #               stats per privmsg and alot of              #
  41. #               coloring to the dota stats                 #
  42. #                                                          #
  43. ############################################################
  44.  
  45. #Required Packages
  46. ############################################################
  47. package require http
  48. package require rest
  49. package require tls
  50. package require json
  51.  
  52. #Global variables
  53. ###########################################################
  54. global dotaapi
  55.  
  56. #Inits for packages
  57. ############################################################
  58. http::register https 443 tls:socket
  59.  
  60. #Bindings
  61. ############################################################
  62. bind msg - "wl" msg:restwl
  63. bind msg - "last_match" msg:last_match
  64. bind msg - "httpswl" msg:httpswl
  65.  
  66. #Automation of procdedures
  67. ############################################################
  68. if { ![info exists recentmatch_running] && $dotaapi(post_recent_matches) } {
  69.     timer 0 opendota:recent_match
  70.     set recentmatch_running 1
  71. }
  72.  
  73. #Procedures
  74. ############################################################
  75.  
  76. #This procedure is needed to initialize TLS
  77. #If this isn't used, all https connections will be rejected
  78. #Therefore if you're just planning on calling http you
  79. #can delete it
  80. proc tls:socket args {
  81.     set opts [lrange $args 0 end-2]
  82.     set host [lindex $args end-1]
  83.     set port [lindex $args end]
  84.  
  85.     ::tls::socket -servername $host {*}$opts $host $port
  86.  
  87.     ::tls::socket -ssl3 false -ssl2 false -tls1 true -servername $host {*}$opts $host $port
  88. }
  89.  
  90. #Checks if the steamid32 is set and only numbers
  91. proc steam:checkid args {
  92.     set steamid [lindex $args 0]
  93.  
  94.     if { $steamid != "" && [regexp {^[0-9]*$} $steamid] } {
  95.         return 1
  96.     } else {
  97.         putlog "SteamId '$steamid' rejected"
  98.         return 0
  99.     }
  100. }
  101.  
  102. #returns statistics of last match of received steamid
  103. #per privmasg
  104. proc msg:last_match { nick host hand args } {
  105.     set steam_id [lindex $args 0]
  106.     putlog "msg:last_match - received call from $nick for steam id $steam_id"
  107.  
  108.     if { [steam:checkid $steam_id] } {
  109.         #get latest match into dict
  110.         set d_result [opendota:get_last_match $steam_id]
  111.  
  112.         set lane [dict get $d_result "lane_role"]
  113.         set lane [opendota:get_lane_string $lane]
  114.  
  115.         set player_slot [dict get $d_result "player_slot"]
  116.         set player_slot [opendota:get_radiant_dire $player_slot]
  117.  
  118.         set radiant_win [dict get $d_result "radiant_win"]
  119.  
  120.         set game_mode [dict get $d_result "game_mode"]
  121.         set lobby_type [dict get $d_result "lobby_type"]
  122.         set game_type [opendota:game_type $game_mode $lobby_type]
  123.  
  124.         set kills [dict get $d_result "kills"]
  125.         set deaths [dict get $d_result "deaths"]
  126.         set assists [dict get $d_result "assists"]
  127.         set xp_per_min [dict get $d_result "xp_per_min"]
  128.         set gold_per_min [dict get $d_result "gold_per_min"]
  129.         set hero_damage [dict get $d_result "hero_damage"]
  130.         set tower_damage [dict get $d_result "tower_damage"]
  131.         set hero_healing [dict get $d_result "hero_healing"]
  132.         set last_hits [dict get $d_result "last_hits"]
  133.         set leaver_status [dict get $d_result "leaver_status"]
  134.         set party_size [dict get $d_result "party_size"]
  135.  
  136.         set hero_id [dict get $d_result "hero_id"]
  137.         set hero_name [opendota:get_hero_name $hero_id]
  138.  
  139.         set lastmatchid [dict get $d_result "match_id"]
  140.  
  141.         #Output starts here
  142.         #Finding out if we won
  143.         if { ($player_slot == "radiant" && $radiant_win == true) || ($player_slot == "dire" && $radiant_win == false) } {
  144.                 puthelp "PRIVMSG $nick :\00303,01GG!\00309,01 Won the last \037$game_type\037 game as \037\00311,01$hero_name\037\00303,01 \00309,01in the \037$lane\037! \00303,01GG!"
  145.             } else {
  146.                 puthelp "PRIVMSG $nick :\00304,01Unfortunately lost last \037$game_type\037 game as\00311,01 \037\00313,01$hero_name\037\00304,01 in the \037$lane\037.\00307,01.\00308,01."
  147.             }
  148.  
  149.             puthelp "PRIVMSG $nick :\00300,01With a\00304,01 \00303,01K\00304,01D\00307,01A \00309,01$kills\00300,01|\00304,01$deaths\00300,01|\00307,01$assists\00309,01 \00300,01and\00309,01 \037\00313,01$last_hits\037 Last Hits\00300,01,"
  150.             puthelp "PRIVMSG $nick :\037\00311,01$xp_per_min\037 XP/min\00309,01 \00300,01and\00309,01 \037\00308,01$gold_per_min\037 Gold/min\00300,01,"
  151.             puthelp "PRIVMSG $nick :\00300,01they were able to inflict\00309,01 \037\00313,01$hero_damage\037\00305,01 \00313,01damage\00309,01 \00300,01to the enemy heroes and\00309,01 \037\00313,01$tower_damage\037\00306,01 \00313,01damage\00306,01 \00300,01to their towers.\00309,01"
  152.             if { $hero_healing > 250 } {
  153.                 puthelp "PRIVMSG $nick :\00300,01All the while healing their friends and themselves for\00309,01 \037$hero_healing\037\00300,01."
  154.             }
  155.             if { $party_size > 1 && $lobby_type != "9" } {
  156.                 puthelp "PRIVMSG $nick :\00300,01By the by, they had the support of \037\00307,01[expr $party_size - 1] friend/s\037\00300,01 in form of a party."
  157.             }
  158.             if { $leaver_status > 0 } {
  159.                 puthelp "PRIVMSG $nick :\00314,01A\00315,01n\00300,01d \00314,01a\00315,01p\00300,01p\00315,01a\00314,01r\00315,01e\00300,01n\00315,01t\00314,01l\00315,01y\00300,01 \00314,01s\00315,01o\00300,01m\00315,01e\00314,01o\00315,01n\00300,01e \00315,01d\00314,01i\00315,01d\00300,01n\00315,01'\00314,01t\00300,01 \00315,01t\00300,01h\00315,01i\00314,01n\00315,01k\00300,01 i\00315,01t\00300,01 \00314,01w\00315,01a\00300,01s \00315,01w\00314,01o\00315,01r\00300,01t\00315,01h\00300,01 \00314,01t\00315,01h\00300,01e\00315,01i\00314,01r\00300,01 \00315,01t\00300,01i\00315,01m\00314,01e\00300,01 \00315,01t\00300,01o \00315,01s\00314,01t\00315,01a\00300,01y \00315,01u\00314,01n\00315,01t\00300,01i\00315,01l\00300,01 \00314,01t\00315,01h\00300,01e\00315,01 e\00314,01n\00315,01d\00300,01 o\00315,01f\00300,01 \00314,01t\00315,01h\00300,01e \00315,01m\00314,01a\00315,01t\00300,01c\00315,01h\00300,01."
  160.             }
  161.             puthelp "PRIVMSG $nick :\00304,01O\00307,01p\00308,01e\00303,01n\00309,01d\00311,01o\00312,01t\00306,01a\00304,01 L\00307,01i\00308,01n\00303,01k\00300,01: \00310,01https://www.opendota.com/matches/$lastmatchid"
  162.     } else {
  163.         puthelp "PRIVMSG $nick :Please call this function by messaging the bot with '/msg kimbot wl {yourSteamId}'"
  164.     }
  165. }
  166.  
  167. #get last played match from opendota and returns a dict with the stats
  168. proc opendota:get_last_match args {
  169.     set steam_id [lindex $args 0]
  170.    
  171.     set url "https://api.opendota.com/api/players/$steam_id/recentMatches"
  172.     set query "$steam_id"
  173.  
  174.     set res [rest::simple $url $query {
  175.         method get
  176.         content-type json  
  177.     }]
  178.    
  179.     #converting the received json to a dict
  180.     set d_result [json::json2dict $res]
  181.     set d_result [lindex $d_result 0]
  182.  
  183.     #since the opendota API returns the last 20 matches
  184.     #we only get the latest match out of the list
  185.     return $d_result
  186. }
  187.  
  188. #periodically posts match data of the most recent match
  189. #in the home channel of the bot
  190. proc opendota:recent_match args {
  191.     global dotaapi
  192.    
  193.     #check if set steamid is valid
  194.     if { [steam:checkid $dotaapi(owner_steamid)] && $dotaapi(channel) != ""} {
  195.         #open/create file and read the last known match (last known to the bot)
  196.         set fs [open "~/recentmatch" a+]
  197.         seek $fs 0
  198.         gets $fs bots_lastmatchid
  199.         close $fs
  200.  
  201.         putlog "opendota:recent_match - Last Match ID: '$bots_lastmatchid'"
  202.  
  203.         set d_result [opendota:get_last_match $dotaapi(owner_steamid)]
  204.         set lastmatchid [dict get $d_result "match_id"]
  205.  
  206.         if { $lastmatchid != $bots_lastmatchid } {
  207.             putlog "A new game was played by $dotaapi(owner_steamid) with the matchid $lastmatchid"
  208.             #write the new matchid to the filesystem
  209.             set fs [open "~/recentmatch" w]
  210.             puts $fs $lastmatchid
  211.             close $fs
  212.            
  213.             set lane [dict get $d_result "lane_role"]
  214.             set lane [opendota:get_lane_string $lane]
  215.  
  216.             set player_slot [dict get $d_result "player_slot"]
  217.             set player_slot [opendota:get_radiant_dire $player_slot]
  218.  
  219.             set radiant_win [dict get $d_result "radiant_win"]
  220.  
  221.             set game_mode [dict get $d_result "game_mode"]
  222.             set lobby_type [dict get $d_result "lobby_type"]
  223.             set game_type [opendota:game_type $game_mode $lobby_type]
  224.  
  225.             set kills [dict get $d_result "kills"]
  226.             set deaths [dict get $d_result "deaths"]
  227.             set assists [dict get $d_result "assists"]
  228.             set xp_per_min [dict get $d_result "xp_per_min"]
  229.             set gold_per_min [dict get $d_result "gold_per_min"]
  230.             set hero_damage [dict get $d_result "hero_damage"]
  231.             set tower_damage [dict get $d_result "tower_damage"]
  232.             set hero_healing [dict get $d_result "hero_healing"]
  233.             set last_hits [dict get $d_result "last_hits"]
  234.             set leaver_status [dict get $d_result "leaver_status"]
  235.             set party_size [dict get $d_result "party_size"]
  236.  
  237.             set hero_id [dict get $d_result "hero_id"]
  238.             set hero_name [opendota:get_hero_name $hero_id]
  239.  
  240.             #Output starts here
  241.             #Finding out if we won
  242.             if { ($player_slot == "radiant" && $radiant_win == true) || ($player_slot == "dire" && $radiant_win == false) } {
  243.                 puthelp "PRIVMSG $dotaapi(channel) :\00303,01GG!\00309,01 Won the last \037$game_type\037 game as \037\00311,01$hero_name\037\00303,01 \00309,01in the \037$lane\037! \00303,01GG!"
  244.             } else {
  245.                 puthelp "PRIVMSG $dotaapi(channel) :\00304,01Unfortunately lost last \037$game_type\037 game as\00311,01 \037\00313,01$hero_name\037\00304,01 in the \037$lane\037.\00307,01.\00308,01."
  246.             }
  247.  
  248.             puthelp "PRIVMSG $dotaapi(channel) :\00300,01With a\00304,01 \00303,01K\00304,01D\00307,01A \00309,01$kills\00300,01|\00304,01$deaths\00300,01|\00307,01$assists\00309,01 \00300,01and\00309,01 \037\00313,01$last_hits\037 Last Hits\00300,01,"
  249.             puthelp "PRIVMSG $dotaapi(channel) :\037\00311,01$xp_per_min\037 XP/min\00309,01 \00300,01and\00309,01 \037\00308,01$gold_per_min\037 Gold/min\00300,01,"
  250.             puthelp "PRIVMSG $dotaapi(channel) :\00300,01they were able to inflict\00309,01 \037\00313,01$hero_damage\037\00305,01 \00313,01damage\00309,01 \00300,01to the enemy heroes and\00309,01 \037\00313,01$tower_damage\037\00306,01 \00313,01damage\00306,01 \00300,01to their towers.\00309,01"
  251.             if { $hero_healing > 250 } {
  252.                 puthelp "PRIVMSG $dotaapi(channel) :\00300,01All the while healing their friends and themselves for\00309,01 \037$hero_healing\037\00300,01."
  253.             }
  254.             if { $party_size > 1 && $lobby_type != "9" } {
  255.                 puthelp "PRIVMSG $dotaapi(channel) :\00300,01By the by, they had the support of \037\00307,01[expr $party_size - 1] friend/s\037\00300,01 in form of a party."
  256.             }
  257.             if { $leaver_status > 0 } {
  258.                 puthelp "PRIVMSG $dotaapi(channel) :\00314,01A\00315,01n\00300,01d \00314,01a\00315,01p\00300,01p\00315,01a\00314,01r\00315,01e\00300,01n\00315,01t\00314,01l\00315,01y\00300,01 \00314,01s\00315,01o\00300,01m\00315,01e\00314,01o\00315,01n\00300,01e \00315,01d\00314,01i\00315,01d\00300,01n\00315,01'\00314,01t\00300,01 \00315,01t\00300,01h\00315,01i\00314,01n\00315,01k\00300,01 i\00315,01t\00300,01 \00314,01w\00315,01a\00300,01s \00315,01w\00314,01o\00315,01r\00300,01t\00315,01h\00300,01 \00314,01t\00315,01h\00300,01e\00315,01i\00314,01r\00300,01 \00315,01t\00300,01i\00315,01m\00314,01e\00300,01 \00315,01t\00300,01o \00315,01s\00314,01t\00315,01a\00300,01y \00315,01u\00314,01n\00315,01t\00300,01i\00315,01l\00300,01 \00314,01t\00315,01h\00300,01e\00315,01 e\00314,01n\00315,01d\00300,01 o\00315,01f\00300,01 \00314,01t\00315,01h\00300,01e \00315,01m\00314,01a\00315,01t\00300,01c\00315,01h\00300,01."
  259.             }
  260.             puthelp "PRIVMSG $dotaapi(channel) :\00304,01O\00307,01p\00308,01e\00303,01n\00309,01d\00311,01o\00312,01t\00306,01a\00304,01 L\00307,01i\00308,01n\00303,01k\00300,01: \00310,01https://www.opendota.com/matches/$lastmatchid"
  261.         } else {
  262.             putlog "openddota:recentmatch - No new match played since then"
  263.         }
  264.  
  265.         #call the function in 40 minutes again
  266.         timer 40 opendota:recent_match
  267.         return 1
  268.     } else {
  269.         putlog "opendota:recent_match - The owner_steamid or channel is not set accordingly"   
  270.         putlog "opendota:recent_match - Please add 'set dotaapi(owner_steamid) {YourSteamId32}' and 'set dotaapi(channel) {#ChannelYourBotIsIn}' before dotaapi.tcl in the bots config"
  271.         return 0
  272.     }
  273. }
  274.  
  275. #returns which type of game was played
  276. #TODO Add all game_modes
  277. proc opendota:game_type args {
  278.     if { [llength $args] == 2 } {
  279.         #game_mode: 22=normal, 23=turbo, 2=captains draft
  280.         set game_mode [lindex $args 0]
  281.         #lobby_type: 7=ranked, 0=unranked, 9=battlecup
  282.         set lobby_type [lindex $args 1]
  283.  
  284.         switch $lobby_type {
  285.             0 {
  286.                 set result "unranked"
  287.             }
  288.             7 {
  289.                 set result "ranked"
  290.             }
  291.             9 {
  292.                 set result "battlecup"
  293.             }
  294.             default {
  295.                 set result "unknown lobby"
  296.             }
  297.         }
  298.  
  299.         switch $game_mode {
  300.             2 {
  301.                 set result "$result captains draft"
  302.             }
  303.             22 {
  304.                 set result "$result normal"
  305.             }
  306.             23 {
  307.                 set result "$result turbo"
  308.             }
  309.             default {
  310.                 set result "$result unknown game_mode"
  311.             }
  312.         }
  313.  
  314.         return $result
  315.     } else {
  316.         putlog "opendota:game_type - need 2 parameter: 1#: game_mode 2#: lobby_type"
  317.         return 0
  318.     }
  319. }
  320.  
  321. #returns if player was radiant or dire
  322. proc opendota:get_radiant_dire args {
  323.     set radiant_dire_id [lindex $args 0]
  324.  
  325.     #player_slot: 0-4=radiant, 128-132=dire
  326.     if { $radiant_dire_id < 5 } {
  327.         return "radiant"
  328.     } else {
  329.         return "dire"
  330.     }
  331. }
  332.  
  333. #returns name of the lane
  334. proc opendota:get_lane_string args {
  335.     set lane [lindex $args 0]
  336.  
  337.     #lane: 1=safelane, 2=mid, 3=offlane
  338.     switch $lane {
  339.         1 {
  340.             set lane "safelane"
  341.         }
  342.         2 {
  343.             set lane "midlane"
  344.         }
  345.         3 {
  346.             set lane "offlane"
  347.         }
  348.     }
  349.     return $lane
  350. }
  351.  
  352. #get hero name through hero id
  353. #this procedure shouldnt actually be called everytime but rather
  354. #once per day or so and cached on the filesystem. Will do in a future update
  355. #TODO save hero infos locally and crosscheck for updates daily
  356. proc opendota:get_hero_name args {
  357.     set hero_id [lindex $args 0]
  358.     set url "https://api.opendota.com/api/heroes"
  359.     set query ""
  360.  
  361.     set res [rest::simple $url $query {
  362.         method get
  363.         content-type json  
  364.     }]
  365.    
  366.     #converting the received json to a dict
  367.     set d_result [json::json2dict $res]
  368.  
  369.     #set heroinfo [lindex $d_result $hero_id-2]
  370.     foreach hero_info $d_result {
  371.         if { [dict get $hero_info "id"] == $hero_id } {
  372.             set hero_name [dict get $hero_info "localized_name"]
  373.             break
  374.         }
  375.     }
  376.  
  377.     return $hero_name
  378. }
  379.  
  380. #Bot replies with a msg with Wins and Losses of given steamid32
  381. proc msg:restwl { nick host hand args } {
  382.     set steamid [lindex $args 0]
  383.     putlog "W/L Call for SteamId $steamid by $nick received"
  384.  
  385.     if { [steam:checkid $steamid] } {
  386.         set url "https://api.opendota.com/api/players/$steamid/wl"
  387.         set query "$steamid"
  388.  
  389.         set res [rest::simple $url $query {
  390.             method get
  391.             content-type json  
  392.         }]
  393.        
  394.         #converting the received json to a dict
  395.         set d_result [json::json2dict $res]
  396.        
  397.         #Only respond if the received json contained keys and values
  398.         #and color the response flashy
  399.         if { [dict size $d_result] > 0 } {
  400.             puthelp "PRIVMSG $nick :\0033 Wins: \003 [dict get $d_result "win"]"
  401.             puthelp "PRIVMSG $nick :\0034 Loses: \003 [dict get $d_result "lose"]"
  402.         }
  403.     } else {
  404.         puthelp "PRIVMSG $nick :Please call this function by messaging the bot with '/msg kimbot wl {yourSteamId}'"
  405.     }  
  406. }
  407.  
  408. proc msg:httpswl { nick host hand args } {
  409.     global owner_steamid
  410.  
  411.     set token [::http::geturl "https://api.opendota.com/api/players/$steamid/wl" -type application/json]
  412.     putlog "Token: $token"
  413.     putlog "Data in Token: [::http::data $token]"
  414.     puthelp "PRIVMSG $nick :[::http::data $token]"
  415. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement