############################################################
# #
# Author: Kim "kimpact" Slavinjak #
# E-Mail: [email protected] #
# IRC: #kimpact @ quakenet #
# Date: 08.06.2018 #
# Version: 0.2 #
# Info: This script uses the OpenDota API to call REST #
# services and fetch json data to display over #
# your Eggdrop Bot. This script will create a #
# a file called recentmatch in your home #
# directory to remember the last game you played. #
# If you have questions, need help or have #
# suggestions feel free to email me or find me #
# on quakenet #
# #
# Installation: #
# #
# You need these lines in your eggdrop.conf #
# -) set dotaapi(owner_steamid) "10694300" #
# -> change the number to your steamid32 #
# -) set dotaapi(post_recent_matches) 1 #
# -> set this param to 1 and the bot will #
# look if your steamid has played a new #
# match every 40 minutes and post the stats #
# in the channel below #
# -) set dotaapi(channel) "#kimpact" #
# -> change to the channel you want the bot #
# to post stats in #
# -) source scripts/dotaapi.tcl #
# #
# History: #
# #
# -) 08.06.18 - Init of the tcl script #
# -) 09.06.18 - Added proc to periodically check #
# recent matches of designated player #
# in eggdrop conf defined player #
# and write it publicly to channel #
# -) 13.06.18 - Added call to return latest match #
# stats per privmsg and alot of #
# coloring to the dota stats #
# #
############################################################
#Required Packages
############################################################
package require http
package require rest
package require tls
package require json
#Global variables
###########################################################
global dotaapi
#Inits for packages
############################################################
http::register https 443 tls:socket
#Bindings
############################################################
bind msg - "wl" msg:restwl
bind msg - "last_match" msg:last_match
bind msg - "httpswl" msg:httpswl
#Automation of procdedures
############################################################
if { ![info exists recentmatch_running] && $dotaapi(post_recent_matches) } {
timer 0 opendota:recent_match
set recentmatch_running 1
}
#Procedures
############################################################
#This procedure is needed to initialize TLS
#If this isn't used, all https connections will be rejected
#Therefore if you're just planning on calling http you
#can delete it
proc tls:socket args {
set opts [lrange $args 0 end-2]
set host [lindex $args end-1]
set port [lindex $args end]
::tls::socket -servername $host {*}$opts $host $port
::tls::socket -ssl3 false -ssl2 false -tls1 true -servername $host {*}$opts $host $port
}
#Checks if the steamid32 is set and only numbers
proc steam:checkid args {
set steamid [lindex $args 0]
if { $steamid != "" && [regexp {^[0-9]*$} $steamid] } {
return 1
} else {
putlog "SteamId '$steamid' rejected"
return 0
}
}
#returns statistics of last match of received steamid
#per privmasg
proc msg:last_match { nick host hand args } {
set steam_id [lindex $args 0]
putlog "msg:last_match - received call from $nick for steam id $steam_id"
if { [steam:checkid $steam_id] } {
#get latest match into dict
set d_result [opendota:get_last_match $steam_id]
set lane [dict get $d_result "lane_role"]
set lane [opendota:get_lane_string $lane]
set player_slot [dict get $d_result "player_slot"]
set player_slot [opendota:get_radiant_dire $player_slot]
set radiant_win [dict get $d_result "radiant_win"]
set game_mode [dict get $d_result "game_mode"]
set lobby_type [dict get $d_result "lobby_type"]
set game_type [opendota:game_type $game_mode $lobby_type]
set kills [dict get $d_result "kills"]
set deaths [dict get $d_result "deaths"]
set assists [dict get $d_result "assists"]
set xp_per_min [dict get $d_result "xp_per_min"]
set gold_per_min [dict get $d_result "gold_per_min"]
set hero_damage [dict get $d_result "hero_damage"]
set tower_damage [dict get $d_result "tower_damage"]
set hero_healing [dict get $d_result "hero_healing"]
set last_hits [dict get $d_result "last_hits"]
set leaver_status [dict get $d_result "leaver_status"]
set party_size [dict get $d_result "party_size"]
set hero_id [dict get $d_result "hero_id"]
set hero_name [opendota:get_hero_name $hero_id]
set lastmatchid [dict get $d_result "match_id"]
#Output starts here
#Finding out if we won
if { ($player_slot == "radiant" && $radiant_win == true) || ($player_slot == "dire" && $radiant_win == false) } {
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!"
} else {
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."
}
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,"
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,"
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"
if { $hero_healing > 250 } {
puthelp "PRIVMSG $nick :\00300,01All the while healing their friends and themselves for\00309,01 \037$hero_healing\037\00300,01."
}
if { $party_size > 1 && $lobby_type != "9" } {
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."
}
if { $leaver_status > 0 } {
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."
}
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"
} else {
puthelp "PRIVMSG $nick :Please call this function by messaging the bot with '/msg kimbot wl {yourSteamId}'"
}
}
#get last played match from opendota and returns a dict with the stats
proc opendota:get_last_match args {
set steam_id [lindex $args 0]
set url "https://api.opendota.com/api/players/$steam_id/recentMatches"
set query "$steam_id"
set res [rest::simple $url $query {
method get
content-type json
}]
#converting the received json to a dict
set d_result [json::json2dict $res]
set d_result [lindex $d_result 0]
#since the opendota API returns the last 20 matches
#we only get the latest match out of the list
return $d_result
}
#periodically posts match data of the most recent match
#in the home channel of the bot
proc opendota:recent_match args {
global dotaapi
#check if set steamid is valid
if { [steam:checkid $dotaapi(owner_steamid)] && $dotaapi(channel) != ""} {
#open/create file and read the last known match (last known to the bot)
set fs [open "~/recentmatch" a+]
seek $fs 0
gets $fs bots_lastmatchid
close $fs
putlog "opendota:recent_match - Last Match ID: '$bots_lastmatchid'"
set d_result [opendota:get_last_match $dotaapi(owner_steamid)]
set lastmatchid [dict get $d_result "match_id"]
if { $lastmatchid != $bots_lastmatchid } {
putlog "A new game was played by $dotaapi(owner_steamid) with the matchid $lastmatchid"
#write the new matchid to the filesystem
set fs [open "~/recentmatch" w]
puts $fs $lastmatchid
close $fs
set lane [dict get $d_result "lane_role"]
set lane [opendota:get_lane_string $lane]
set player_slot [dict get $d_result "player_slot"]
set player_slot [opendota:get_radiant_dire $player_slot]
set radiant_win [dict get $d_result "radiant_win"]
set game_mode [dict get $d_result "game_mode"]
set lobby_type [dict get $d_result "lobby_type"]
set game_type [opendota:game_type $game_mode $lobby_type]
set kills [dict get $d_result "kills"]
set deaths [dict get $d_result "deaths"]
set assists [dict get $d_result "assists"]
set xp_per_min [dict get $d_result "xp_per_min"]
set gold_per_min [dict get $d_result "gold_per_min"]
set hero_damage [dict get $d_result "hero_damage"]
set tower_damage [dict get $d_result "tower_damage"]
set hero_healing [dict get $d_result "hero_healing"]
set last_hits [dict get $d_result "last_hits"]
set leaver_status [dict get $d_result "leaver_status"]
set party_size [dict get $d_result "party_size"]
set hero_id [dict get $d_result "hero_id"]
set hero_name [opendota:get_hero_name $hero_id]
#Output starts here
#Finding out if we won
if { ($player_slot == "radiant" && $radiant_win == true) || ($player_slot == "dire" && $radiant_win == false) } {
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!"
} else {
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."
}
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,"
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,"
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"
if { $hero_healing > 250 } {
puthelp "PRIVMSG $dotaapi(channel) :\00300,01All the while healing their friends and themselves for\00309,01 \037$hero_healing\037\00300,01."
}
if { $party_size > 1 && $lobby_type != "9" } {
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."
}
if { $leaver_status > 0 } {
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."
}
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"
} else {
putlog "openddota:recentmatch - No new match played since then"
}
#call the function in 40 minutes again
timer 40 opendota:recent_match
return 1
} else {
putlog "opendota:recent_match - The owner_steamid or channel is not set accordingly"
putlog "opendota:recent_match - Please add 'set dotaapi(owner_steamid) {YourSteamId32}' and 'set dotaapi(channel) {#ChannelYourBotIsIn}' before dotaapi.tcl in the bots config"
return 0
}
}
#returns which type of game was played
#TODO Add all game_modes
proc opendota:game_type args {
if { [llength $args] == 2 } {
#game_mode: 22=normal, 23=turbo, 2=captains draft
set game_mode [lindex $args 0]
#lobby_type: 7=ranked, 0=unranked, 9=battlecup
set lobby_type [lindex $args 1]
switch $lobby_type {
0 {
set result "unranked"
}
7 {
set result "ranked"
}
9 {
set result "battlecup"
}
default {
set result "unknown lobby"
}
}
switch $game_mode {
2 {
set result "$result captains draft"
}
22 {
set result "$result normal"
}
23 {
set result "$result turbo"
}
default {
set result "$result unknown game_mode"
}
}
return $result
} else {
putlog "opendota:game_type - need 2 parameter: 1#: game_mode 2#: lobby_type"
return 0
}
}
#returns if player was radiant or dire
proc opendota:get_radiant_dire args {
set radiant_dire_id [lindex $args 0]
#player_slot: 0-4=radiant, 128-132=dire
if { $radiant_dire_id < 5 } {
return "radiant"
} else {
return "dire"
}
}
#returns name of the lane
proc opendota:get_lane_string args {
set lane [lindex $args 0]
#lane: 1=safelane, 2=mid, 3=offlane
switch $lane {
1 {
set lane "safelane"
}
2 {
set lane "midlane"
}
3 {
set lane "offlane"
}
}
return $lane
}
#get hero name through hero id
#this procedure shouldnt actually be called everytime but rather
#once per day or so and cached on the filesystem. Will do in a future update
#TODO save hero infos locally and crosscheck for updates daily
proc opendota:get_hero_name args {
set hero_id [lindex $args 0]
set url "https://api.opendota.com/api/heroes"
set query ""
set res [rest::simple $url $query {
method get
content-type json
}]
#converting the received json to a dict
set d_result [json::json2dict $res]
#set heroinfo [lindex $d_result $hero_id-2]
foreach hero_info $d_result {
if { [dict get $hero_info "id"] == $hero_id } {
set hero_name [dict get $hero_info "localized_name"]
break
}
}
return $hero_name
}
#Bot replies with a msg with Wins and Losses of given steamid32
proc msg:restwl { nick host hand args } {
set steamid [lindex $args 0]
putlog "W/L Call for SteamId $steamid by $nick received"
if { [steam:checkid $steamid] } {
set url "https://api.opendota.com/api/players/$steamid/wl"
set query "$steamid"
set res [rest::simple $url $query {
method get
content-type json
}]
#converting the received json to a dict
set d_result [json::json2dict $res]
#Only respond if the received json contained keys and values
#and color the response flashy
if { [dict size $d_result] > 0 } {
puthelp "PRIVMSG $nick :\0033 Wins: \003 [dict get $d_result "win"]"
puthelp "PRIVMSG $nick :\0034 Loses: \003 [dict get $d_result "lose"]"
}
} else {
puthelp "PRIVMSG $nick :Please call this function by messaging the bot with '/msg kimbot wl {yourSteamId}'"
}
}
proc msg:httpswl { nick host hand args } {
global owner_steamid
set token [::http::geturl "https://api.opendota.com/api/players/$steamid/wl" -type application/json]
putlog "Token: $token"
putlog "Data in Token: [::http::data $token]"
puthelp "PRIVMSG $nick :[::http::data $token]"
}
Comments
0 B
|0 👍
/0 👎
0 B
|👍
/👎