Created
December 10, 2020 16:01
-
-
Save EdGruberman/b92d15cee0e6845546a4f5850a82e7a8 to your computer and use it in GitHub Desktop.
Revisions
-
EdGruberman created this gist
Dec 10, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,1104 @@ on *:START:{ sentinel.load } on *:EXIT:{ sentinel.unload } on *:CONNECT:{ if ( $hget(sentinel.general,autoactivate) == 1 && $hget(sentinel.general.status,activated) != 1 ) sentinel.activate } alias sentinel.load { ;--Load settings from ini file into hash tables hmake sentinel.irc 5 hload -i sentinel.irc sentinel.ini irc if ( $hget(sentinel.irc,admin) == $null ) hadd sentinel.irc admin #clan.private password if ( $hget(sentinel.irc,tv) == $null ) hadd sentinel.irc tv #clan.tv if ( $hget(sentinel.irc,monitor) == $null ) hadd sentinel.irc monitor #clan hmake sentinel.general 5 hload -i sentinel.general sentinel.ini general hadd sentinel.general version v0.5.0b - 2008/06/11 by EdGruberman hadd sentinel.general url http://sentinel.rjump.com if ( $hget(sentinel.general,port.type) == $null ) hadd sentinel.general port.type dynamic if ( $hget(sentinel.general,port.log) == $null ) hadd sentinel.general port.log 49889 if ( $hget(sentinel.general,show.connects) == $null ) hadd sentinel.general show.connects 1 if ( $hget(sentinel.general,show.sayteam) == $null ) hadd sentinel.general show.sayteam 1 .fullname Sentinel Bot $hget(sentinel.general,version) hmake sentinel.server 5 hload -i sentinel.server sentinel.ini server if ( $hget(sentinel.server,address) == $null ) hadd sentinel.server address 127.0.0.1 if ( $hget(sentinel.server,rcon_password) == $null ) hadd sentinel.server rcon_password password hmake sentinel.log 5 hload -i sentinel.log sentinel.ini log hmake sentinel.teams 20 hload -i sentinel.teams sentinel.ini teams if ( $hget(sentinel.teams,0).item == 0 ) { hadd sentinel.teams Blue 12 hadd sentinel.teams Red 04 hadd sentinel.teams Green 03 hadd sentinel.teams Yellow 08 hadd sentinel.teams Spectator 14 hadd sentinel.teams Console 07 hadd sentinel.teams Unassigned 15 } hmake sentinel.rules.default 5 hload -i sentinel.rules.default sentinel.ini rules.default if ( $hget(sentinel.rules.default,players) == $null ) hadd sentinel.rules.default players $ctime Default 8 if ( $hget(sentinel.rules.default,max) == $null ) hadd sentinel.rules.default max $ctime Default 900 if ( $hget(sentinel.rules.default,min) == $null ) hadd sentinel.rules.default min $ctime Default 300 if ( $hget(sentinel.rules.default,type) == $null ) hadd sentinel.rules.default type $ctime Default ignore if ( $hget(sentinel.rules.default,maps) == $null ) hadd sentinel.rules.default maps $ctime Default cp_badlands cp_dustbowl cp_granary cp_gravelpit cp_well ctf_2fort ctf_well pl_goldrush tc_hydro hmake sentinel.invited 5 hload -i sentinel.invited sentinel.ini invited ;--Load the rules for any invited channels var %i = 1 while ( %i <= $hget(sentinel.invited,0).item ) { hmake [ sentinel.rules. $+ [ $hget(sentinel.invited,%i).item ] ] 5 hload -i [ sentinel.rules. $+ [ $hget(sentinel.invited,%i).item ] ] sentinel.ini [ rules. $+ [ $hget(sentinel.invited,%i).item ] ] inc %i } } alias sentinel.unload { sentinel.deactivate | hfree -w sentinel.* } alias sentinel.activate { if ( $hget(sentinel.general.status,activated) == 1 ) return hadd -m sentinel.general.status activated 1 ;--Join monitor and admin irc channels join $hget(sentinel.irc,monitor) if ( ($gettok($hget(sentinel.irc,monitor),2,32) != $null) ) .timersentinel.monitor.pw 1 2 mode #$gettok($hget(sentinel.irc,monitor),1,32) +k $gettok($hget(sentinel.irc,monitor),2,32) join $hget(sentinel.irc,admin) if ( ($gettok($hget(sentinel.irc,admin),2,32) != $null) ) .timersentinel.admin.pw 1 2 mode #$gettok($hget(sentinel.irc,admin),1,32) +k $gettok($hget(sentinel.irc,admin),2,32) ;--Join invited irc channels var %i = 1 while ( %i <= $hget(sentinel.invited,0).item ) { join $hget(sentinel.invited,%i).item $gettok($hget(sentinel.invited,%i).data,3,32) inc %i } sentinel.server.open } alias sentinel.deactivate { if ( $hget(sentinel.general.status,activated) != 1) return hadd sentinel.general.status activated 0 sentinel.server.close ;--Depart invited channels var %i = 1 while ( %i <= $hget(sentinel.invited,0).item ) { part $gettok($hget(sentinel.invited,%i).item,1,32) 5Bot Deactivated inc %i } ;--Depart irc channels part $gettok($hget(sentinel.irc,admin),1,32) 5Bot Deactivated part $gettok($hget(sentinel.irc,monitor),1,32) 5Bot Deactivated ;--Clean-up yer mess! hfree -w sentinel.server.* hfree -w sentinel.rcon.* timers off } alias sentinel.server.open { ;--Join the tv channel and then open the log socket. hmake sentinel.server.status 5 join $hget(sentinel.irc,tv) if ( ($gettok($hget(sentinel.irc,tv),2,32) != $null) ) .timersentinel.tv.pw 1 2 mode #$gettok($hget(sentinel.irc,tv),1,32) +k $gettok($hget(sentinel.irc,tv),2,32) sentinel.rcon status .timersentinel.rcon 1 3 sentinel.rcon sv_visiblemaxplayers .timersentinel.log.open 1 3 sentinel.log.open } alias sentinel.server.close { ;--Close the log socket and leave the tv channel. hfree sentinel.server.status sentinel.log.close if ( ($gettok($hget(sentinel.irc,tv),1,32) != $gettok($hget(sentinel.irc,admin),1,32)) $& && ($gettok($hget(sentinel.irc,tv),1,32) != $gettok($hget(sentinel.irc,monitor),1,32)) ) $& part $gettok($hget(sentinel.irc,tv),1,32) 5Server Closed else msg $gettok($hget(sentinel.irc,tv),1,32) 5Server Closed } alias sentinel.server.address { var %address = $hget(sentinel.server,address) if ( $pos(%address,:,0) == 0 ) var %address = %address $+ :27015 return $replace(%address,:,$chr(32)) } alias sentinel.port { var %port = $hget(sentinel.general,$1) if ( $hget(sentinel.general,port.type) == dynamic ) return $null else return %port } alias sentinel.log.open { hadd sentinel.general.status log.status Open sockudp -k sentinel.socket.log $sentinel.port(port.log) $sentinel.server.address sentinel.rcon logaddress_add $ip $+ : $+ $sock(sentinel.socket.log).port } alias sentinel.log.close { hadd sentinel.general.status log.status Closed sentinel.rcon logaddress_del $ip $+ : $+ $sock(sentinel.socket.log).port sockclose sentinel.socket.log } alias sentinel.log.check { ;--If log has been explicitly closed, don't re-open it! if ( $hget(sentinel.general.status,log.status) == Closed ) return ;--If no log entry for over 5 mins, check status which will generate a log entry for the rcon. if ( $sock(sentinel.socket.log).lr > $calc(5 * 60) ) sentinel.rcon status ;--If no log entry still in over 15 mins, attempt to reopen the log. if ( $sock(sentinel.socket.log).lr > $calc(15 * 60) ) sentinel.log.open } alias sentinel.log.address { var %address = $hget(sentinel.log,address) if ( $pos(%address,:,0) == 0 ) var %address = %address $+ :28888 return $replace(%address,:,$chr(32)) } alias sentinel.rcon { var %cmd = $1- if ( $1 == =rcon ) var %cmd = $2- ;--Save command in the rcon queue. var %request_id = $sentinel.rcon.queue(%cmd) ;--If this is an =rcon request, associate the request_id with the response target. if ( $1 == =rcon ) set -u10 %sentinel.rcon.response %sentinel.rcon.response %request_id ;--If the socket is already attempting to authenticate, just let it do it's thing. if ( %sentinel.socket.rcon.status == authenticating ) return if ( $sock(sentinel.socket.rcon).to == $null ) { set -u15 %sentinel.socket.rcon.status authenticating sockclose sentinel.socket.rcon sockopen sentinel.socket.rcon $sentinel.server.address } else { sentinel.rcon.write %request_id } return %request_id } alias sentinel.rcon.queue { var %id = $hget(sentinel.rcon.queue,$hget(sentinel.rcon.queue,0).item).item + 1 hadd -m sentinel.rcon.queue %id $1- return %id } alias sentinel.rcon.queue.check { if ( $hget(sentinel.rcon.queue,$1) != $null ) sentinel.rcon.write $1 } on *:SOCKOPEN:sentinel.socket.rcon:{ ;--Set 15 second connection timeout. .timersentinel.socket.rcon.timeout 1 15 sockclose sentinel.socket.rcon ;--Send the initial authentication request. sentinel.rcon.write 0 unset %sentinel.rcon.request_id } alias sentinel.rcon.write { ;--Retrieve command in rcon queue. var %request_id = $1 var %cmd = $hget(sentinel.rcon.queue,%request_id) var %type = 2 ;--If request_id is 0, this needs to be an authentication request. if ( %request_id == 0 ) { var %type = 3 var %cmd = $hget(sentinel.server,rcon_password) } var %packet_size = $calc(10 + $len(%cmd)) ;--Compile packet data to be sent. bset &packet 1 %packet_size bset &packet 5 %request_id bset &packet 9 %type bset -t &packet 13 %cmd bset &packet $calc(13 + $len(%cmd)) 0 0 ;--Debug output. if ( %sentinel.rcon.debug == 2 ) debug.binvar &packet RCON TCP OUT $chr($asc(|)) FROM: $sock(sentinel.socket.rcon).bindip $+ : $+ $sock(sentinel.socket.rcon).bindport $chr($asc(|)) TO: $sock(sentinel.socket.rcon).ip $+ : $+ $sock(sentinel.socket.rcon).port if ( %sentinel.rcon.debug >= 1 ) { echo -s $timestamp RCON TCP OUT $chr($asc(|)) FROM: $sock(sentinel.socket.rcon).bindip $+ : $+ $sock(sentinel.socket.rcon).bindport $chr($asc(|)) TO: $sock(sentinel.socket.rcon).ip $+ : $+ $sock(sentinel.socket.rcon).port echo -si11 ---------- Packet Size: %packet_size -- Request ID: %request_id -- Request Type: %type echo -si11 ---------- %cmd } ;--Actual socket write. sockwrite sentinel.socket.rcon &packet [ .timersentinel.rcon.queue $+ [ %request_id ] ] 1 10 sentinel.rcon.queue.check %request_id } on *:SOCKREAD:sentinel.socket.rcon:{ ;--Reset 15 second connection timeout. .timersentinel.socket.rcon.timeout 1 15 sockclose sentinel.socket.rcon sockread $sock(sentinel.socket.rcon).rq &data if ( %sentinel.rcon.debug == 2 ) debug.binvar &data RCON TCP IN $chr($asc(|)) FROM: $sock(sentinel.socket.rcon).ip $+ : $+ $sock(sentinel.socket.rcon).port $chr($asc(|)) TO: $sock(sentinel.socket.rcon).bindip $+ : $+ $sock(sentinel.socket.rcon).bindport ;--Might be more than one packet of data. Seperate each packet by finding the double null at the end of the packet. var %i = 1 while (%i <= $bvar(&data,0)) { var %eop = $bfind(&data,$calc(%i + 12),0) + 1 if ( %eop == 1 ) var %eop = $bvar(&data,0) bcopy -c &packet 1 &data %i $calc(%eop - %i + 1) sentinel.rcon.parsePacket &packet var %i = %eop + 1 } } alias sentinel.rcon.parsePacket { var %packet_size = $calc($bvar($1,1) + $bvar($1, 2) * 256 + $bvar($1, 3) * (256 ^ 2) + $bvar($1, 4) * (256 ^ 3)) var %request_id = $calc($bvar($1,5) + $bvar($1, 6) * 256 + $bvar($1, 7) * (256 ^ 2) + $bvar($1, 8) * (256 ^ 3)) var %type = $calc($bvar($1,9) + $bvar($1,10) * 256 + $bvar($1,11) * (256 ^ 2) + $bvar($1,12) * (256 ^ 3)) ;--Parse strings seperated by linefeeds into a hash table. var %i = 13 var %j = 1 while (%i <= $calc($bvar($1,0) - 2)) { var %len = $calc($bfind($1,%i,10) - %i) if ( %len < 0 ) var %len = $calc($bvar($1,0) - %i - 2) if ( %len >= 0 ) { hadd -m sentinel.rcon.string1 %j $bvar($1,%i,%len).text inc %j } var %i = $calc(%i + %len + 1) } ;--Debug output if ( %sentinel.rcon.debug >= 1 ) { echo -s $timestamp RCON TCP IN $chr($asc(|)) FROM: $sock(sentinel.socket.rcon).ip $+ : $+ $sock(sentinel.socket.rcon).port $chr($asc(|)) TO: $sock(sentinel.socket.rcon).bindip $+ : $+ $sock(sentinel.socket.rcon).bindport echo -si11 ---------- Packet Size: %packet_size -- Request ID: %request_id -- Response Type: %type var %i = 1 while ( %i <= $hget(sentinel.rcon.string1,0).item ) { echo -si11 ---------- String 1: $hget(sentinel.rcon.string1,%i) inc %i } } if ( %type == 2 ) { ;--SERVERDATA_AUTH_RESPONSE ;--If a request_id is 0xFFFFFFFF(4294967295) or not matching any request_id we've sent, then it's an error. ;--The exception is that when we first open or close and reopen the rcon socket, we send the authentication as request_id = 0. if ( (%request_id != 4294967295) && (($hget(sentinel.rcon.queue,%request_id) != $null) || (%request_id == 0)) ) { unset %sentinel.socket.rcon.status ;--Send every command that built up in the rcon queue while authenticating now. ;--As the queue may start emptying before we finish stepping through it, save out a list of request ids first. var %i = 1 while ( %i <= $hget(sentinel.rcon.queue,0).item ) { var %id_list = %id_list $hget(sentinel.rcon.queue,%i).item inc %i } var %i = 1 while ( %i <= $numtok(%id_list,32) ) { sentinel.rcon.write $gettok(%id_list,%i,32) inc %i } } else { echo 4 -s RCON Authentication Error: %request_id } } elseif ( %type == 0 ) { ;--SERVERDATA_RESPONSE_VALUE if ( %request_id != 0 ) { ;--Not an authentication request response. So, remove request from the rcon queue and parse the data. hdel sentinel.rcon.queue %request_id if ( $hget(sentinel.rcon.string1,0).item > 0 ) sentinel.rcon.parse %request_id } } else echo 4 -s Unrecognized RCON Response Type: %type hfree -w sentinel.rcon.string1 } alias sentinel.rcon.parse { ;--Here is where we do meaningful manipulation of the data in the packets we got. var %lines = $hget(sentinel.rcon.string1,0).item ;--If this is the response to an =rcon command, then show the results back if ( $1 == $gettok(%sentinel.rcon.response,2,32) ) { var %i = 1 while ( %i <= %lines ) { ;--Frequently rcon responses end with two linefeeds resulting in an empty line following the response. ;--No reason to relay an empty line at the end in IRC. if ( (%i == $hget(sentinel.rcon.string1,0).item) && ($hget(sentinel.rcon.string1,%i) == $null) ) { } else msg $gettok(%sentinel.rcon.response,1,32) RCON: $hget(sentinel.rcon.string1,%i) inc %i } unset %sentinel.rcon.response } ;--"status" response; Example: ;hostname: EdGruberman's Test Server ;version : 1.0.3.1/14 3504 secure ;udp/ip : 192.168.1.103:27015 ;map : cp_roswell at: 0 x, 0 y, 0 z ;players : 2 (24 max) ; ;# userid name uniqueid connected ping loss state adr ;# 1 "EdGruberman" STEAM_0:0:204432 54:06 69 0 active 192.168.1.11:27005 ;# 2 "Player" BOT active if ( $gettok($hget(sentinel.rcon.string1,1),1,32) == hostname: ) { ;hfree -w sentinel.server.status hadd -m sentinel.server.status hostname $gettok($hget(sentinel.rcon.string1,1),2-,32) hadd -m sentinel.server.status map $gettok($hget(sentinel.rcon.string1,4),3,32) hadd -m sentinel.server.status player.max $mid($gettok($hget(sentinel.rcon.string1,5),4,32),2) ;--Verify TV channel topic var %tv = $gettok($hget(sentinel.irc,tv),1,32) if ( $chan(%tv).topic != MAP: $+ $hget(sentinel.server.status,map) $+ on $hget(sentinel.server.status,hostname) at $hget(sentinel.server,address) ) $& topic %tv MAP: $+ $hget(sentinel.server.status,map) $+ on $hget(sentinel.server.status,hostname) at $hget(sentinel.server,address) ;--Clean out/reset old player information hfree -w sentinel.rcon.status hadd -m sentinel.server.status player.count 0 hadd -m sentinel.server.status bot.count 0 ;--Loop through player list var %i = 8 while ( %i <= %lines ) { var %line = $hget(sentinel.rcon.string1,%i) ;--Example: # 1 "EdGruberman" STEAM:0:1:204432 25:09 19 0 active 192.168.1.11:27005 ;--Example: #68 "Player" BOT active var %p_name = $gettok(%line,2,$asc(")) var %p_stats = $gettok(%line,3,$asc(")) var %p_uniqueid = $gettok(%p_stats,1,32) var %p_userid = $mid($gettok(%line,1,$asc(")),2) if ( %p_uniqueid == BOT ) hinc -m sentinel.server.status bot.count elseif ( $left(%p_uniqueid,4) == hltv ) hinc -m sentinel.server.status hltv.count else { ;--.rcon.status = ID1 time2 ping3 loss4 adr5 state6 name7- hinc -m sentinel.server.status player.count hadd -m sentinel.rcon.status %p_userid %p_uniqueid $gettok(%p_stats,2-4,32) $gettok(%p_stats,6,32) $gettok(%p_stats,5,32) %p_name } inc %i } ;--Since we've just processed the current status, might as well check to see if anyone wants to be updated sentinel.notify } ;--Server variable response; Example: "maxplayers" is "12" elseif ( $left($hget(sentinel.rcon.string1,1),1) == " ) { tokenize $asc(") $hget(sentinel.rcon.string1,1) hadd -m sentinel.server.status $1 $3 } ;--server_game_time response; Example: Server game time: 499.919983 elseif ( $gettok($hget(sentinel.rcon.string1,1),1-3,32) == Server game time: ) { tokenize 32 $hget(sentinel.rcon.string1,1) hadd -m sentinel.server.status server_game_time $gettok($4,1,$asc(.)) } ;--logaddress_add response; Example: logaddress_add: 1.2.3.4:49889 elseif ( $gettok($hget(sentinel.rcon.string1,1),1,32) == logaddress_add: ) { if ( $gettok($hget(sentinel.rcon.string1,1),2,32) == $ip $+ : $+ $sock(sentinel.socket.log).port ) $& msg $gettok($hget(sentinel.irc,tv),1,32) 5Server Opened } else { } } on *:UDPREAD:sentinel.socket.log:{ ;--Only accept data from our designated server. if ( $sock(sentinel.socket.log).saddr != $gettok($sentinel.server.address,1,32) ) return sockread $sock(sentinel.socket.log).rq &packet if ($sockbr == 0) return if (%sentinel.log.debug == 2) debug.binvar &packet LOG UDP IN $chr($asc(|)) FROM: $sock(sentinel.socket.log).saddr $+ : $+ $sock(sentinel.socket.log).sport $chr($asc(|)) TO: $sock(sentinel.socket.log).ip $+ : $+ $sock(sentinel.socket.log).port sentinel.log.parsePacket &packet } alias sentinel.log.parsePacket { var %line = $bvar($1,1,$bvar($1,0)).text if ( %sentinel.log.debug >= 1 ) { echo -s $timestamp LOG UDP IN $chr($asc(|)) FROM: $sock(sentinel.socket.log).saddr $+ : $+ $sock(sentinel.socket.log).sport $chr($asc(|)) TO: $sock(sentinel.socket.log).ip $+ : $+ $sock(sentinel.socket.log).port echo -si11 ---------- %line } ;--Strip the header and the last character which is always a linefeed. if ( $left(%line,6) == ÿÿÿÿRL ) sentinel.log.parse $left($mid(%line,6),$calc($len($mid(%line,6)) - 1)) } alias sentinel.log.parse { var %tv = $gettok($hget(sentinel.irc,tv),1,32) var %monitor = $gettok($hget(sentinel.irc,monitor),1,32) var %admin = $gettok($hget(sentinel.irc,admin),1,32) ;--Reset 1min timer to check if still open .timersentinel.log.check -o 0 60 sentinel.log.check ;--Record to log file if desired if ( $hget(sentinel.log,file) != $null ) { write $shortfn($hget(sentinel.log,file)) $+ $replace($hget(sentinel.server,address),:,.) $+ .log $1- } ;--Example: L 07/09/2003 - 23:34:02: Kick: "EdGruberman<5><204432><>" was kicked by "Console" (message "spawn camping") ;--Example: L 07/09/2003 - 23:34:02: Kick: "EdGruberman<6><204432><>" was kicked by "Console" if ( $5 == Kick: ) { tokenize $asc(") $1- msg %tv * $sentinel.format.player($2) was kicked. $iif($len($6) > 0,Reason: 07 $+ $6) } ;--Example: L 07/09/2003 - 22:49:21: Started map "avanti" (CRC "-2138426516") elseif ( $5-6 == Started map ) { set -u120 %sentinel.status mapchange sentinel.rcon status ;--We know all players start out as Unassigned at a map change. var %i = 1 while ( %i <= $hget(sentinel.rcon.status,0).item ) { hadd -m sentinel.players Unassigned $gettok($hget(sentinel.players,%i).data,2,32) inc %i } tokenize $asc(") $1- msg %tv ¯¯¯¯¯¯¯¯¯¯ Map changed to " $+ $2 $+ " ¯¯¯¯¯¯¯¯¯¯ topic %tv MAP: $+ $2 $+ on $hget(sentinel.server.status,hostname) at $hget(sentinel.server,address) } ;--Example: L 07/09/2003 - 23:21:40: Team "Blue" scored "0" with "1" player (kills "0") (kills_unaccounted "0") elseif ( ($5 = Team) && ($7 == scored) ) { tokenize $asc(") $1- msg %tv ===== $sentinel.format.team($2) scored $4 $+ pts with $6 players on $hget(sentinel.server.status,map) $+ . ===== } ;--Example: L 06/15/2008 - 21:01:22: Team "Blue" triggered "pointcaptured" (cp "0") (cpname "Courtyard") (numcappers "4") (player1 "^N^BlueInGreen<53><STEAM_0:0:17012120><Blue>") (position1 "921 2765 -152") (player2 "BladeGamer[cnlm]<62><STEAM_0:1:17491723><Blue>") (position2 "886 2866 -152") (player3 "Swashbuckler<94><STEAM_0:1:5199409><Blue>") (position3 "892 2745 -152") (player4 "ScorpioZ<108><STEAM_0:1:7492850><Blue>") (position4 "866 2812 -152") elseif ( ($5 = Team) && ($7 == triggered) ) { tokenize $asc(") $1- if ( $4 == pointcaptured ) msg %tv ===== $sentinel.format.team($2) captured $8 $+ with $10 cappers on $hget(sentinel.server.status,map) $+ . ===== } ;--Example: L 06/18/2008 - 10:59:42: server_message: "quit" elseif ( $5-6 == server_message: "quit" ) { msg %tv Server shutdown. } ;--Player event... parse type of event elseif ( $left($5,1) == " ) { var %playerinfo = $mid($1-,27,$calc($pos($1-,",2) - 27)) var %team = $replace($mid($gettok(%playerinfo,-1,$asc(>)),2),$chr(32),_) var %player = $left(%playerinfo,$calc($pos(%playerinfo,<,$calc($pos(%playerinfo,<,0) - 2)) - 1)) var %userid_tok = $gettok(%playerinfo,$calc($numtok(%playerinfo,$asc(<)) - 2),$asc(<)) var %userid = $left(%userid_tok,$calc($len(%userid_tok) - 1)) ;--Ensure players hash is up to date on team status for player. hadd -m sentinel.players %userid %team $gettok($hget(sentinel.players,%userid),2,32) var %event_start = $calc($pos($1-,",2) + 2) var %event_end = $calc($pos($1-,",3) - 1) if ( %event_end == -1 ) { var %event_end = $calc($len($1-) + 1) } var %event = $mid($1-,%event_start,$calc(%event_end - %event_start)) ;--Example: L 06/14/2008 - 16:14:04: "CYBER<69><STEAM_0:1:1485814><Red>" say_team "sry" ;--Example: L 06/14/2008 - 00:28:01: "Console<0><Console><Console>" say "#sentinel.tv | EdGruberman : hi" if ( %event == say || ( (%event == say_team) && ($hget(sentinel.general,show.sayteam) == 1) ) ) { var %text_start = $pos($1-,",3) + 1 var %text_end = $len($1-) var %text = $mid($1-,%text_start,$calc(%text_end - %text_start)) var %admin = $mid(%text,$pos(%text,admin,1),5) if ( %event == say_team ) { if ( %team != Spectator ) var %playerinfo = $chr(40) $+ TEAM $+ $chr(41) %playerinfo else var %playerinfo = $chr(40) $+ Spectator $+ $chr(41) %playerinfo } if ( (%event == say) && (%team == Spectator) ) { var %playerinfo = *SPEC* %playerinfo } if ( (%team == Unassigned) && (%event == say) ) var %playerinfo = *DEAD* %playerinfo if ( (%team == Unassigned) && (%event == say_team) ) var %playerinfo = *DEAD* $+ %playerinfo var %message = $sentinel.format.player(%playerinfo) : $replace(%text,admin, $+ %admin $+ ) msg %tv %message if ( admin isin %text ) { msg %monitor 07 $+ %tv $chr($asc(|)) %message } } ;--Example: L 07/09/2003 - 10:17:54: "EdGruberman<1><204432><>" connected, address "1.2.3.4:27005" elseif ( %event == connected, address ) { if ( $hget(sentinel.general,show.connects) == 1 ) { tokenize $asc(") $1- msg %tv * $sentinel.format.player(%playerinfo) $+ < $+ $mid($gettok(%playerinfo,-2,$asc(>)),2) $+ > is trying to connect $& $iif($hget(sentinel.general,show.ip) == 1,from $4,) } } ;--Example: L 07/09/2003 - 23:07:42: "EdGruberman<2><204432><>" entered the game elseif ( %event == entered the game ) { if ( ($hget(sentinel.general,show.connects) == 1) && (%sentinel.status != mapchange) ) { msg %tv * $sentinel.format.player(%playerinfo) $+ < $+ $mid($gettok(%playerinfo,-2,$asc(>)),2) $+ > has entered the game. sentinel.rcon status } else { .timersentinel.enteredthegame 1 15 sentinel.rcon status .timersentinel.players 1 30 sentinel.players %tv } } ;--Example: L 06/15/2008 - 22:01:51: "EdGruberman<111><STEAM_0:0:204432><Blue>" disconnected (reason "Disconnect by user.") elseif ( %event == disconnected $chr(40) $+ reason ) { if ( $hget(sentinel.general,show.connects) == 1 ) { tokenize $asc(") $1- var %reason = $4 if ($right(%reason,1) = $chr(10)) var %reason = $mid(%reason,1,$calc($len(%reason) - 1)) msg %tv * $sentinel.format.player(%playerinfo) $+ < $+ $mid($gettok(%playerinfo,-2,$asc(>)),2) $+ > disconnected. $chr(40) $+ %reason $+ $chr(41) } sentinel.rcon status } ;--Example: L 07/09/2003 - 23:21:54: "EdGruberman<3><204432><Blue>" changed name to "Luka" elseif ( %event == changed name to ) { tokenize $asc(") $1- msg %tv * $sentinel.format.player(%playerinfo) changed name to " $+ $4 $+ ". } ;--Example: L 07/09/2003 - 23:35:39: "EdGruberman<6><204432><SPECTATOR>" joined team "Blue" elseif ( %event == joined team ) { tokenize $asc(") $1- hadd -m sentinel.players %userid $4 $gettok($hget(sentinel.players,%userid),2,32) } else { } } else { } } alias sentinel.format.weapon { ;--Returns an irc formatted, ascii art representation of a weapon if ( $1 == axe ) { return 14.04/14` } elseif ( $1 == caltrop ) { return 15¸ } elseif ( $1 == medikit ) { return 15,00[04,00+15,00] } elseif ( $1 == spanner ) { return 14©==C } else { return $null } } alias sentinel.format.player { ;--Returns the player name passed to it colored according to it's team as per the ini ;--Color is left open, must terminate in calling function if so desired ;--Example: EdGruberman<4><204432><#Dustbowl_team1> ;--Example: Console<0><Console><Console> var %team = $replace($mid($gettok($1,-1,$asc(>)),2),$chr(32),_) var %color = $gettok($hget(sentinel.teams,%team),1,32) var %player = $left($1-,$calc($pos($1-,<,$calc($pos($1-,<,0) - 2)) - 1)) if ( %color == $null && %team != $null ) { var %color = 01 $+ < $+ %team $+ > } if ( %color != $null ) { var %color = $+ %color } return %color $+ %player } alias sentinel.format.team { ;--Returns the team name passed to it colored as per the ini ;--Color is left open, must terminate in calling function if so desired var %color = $gettok($hget(sentinel.teams,$replace($1,$chr(32),_)),1,32) var %team = $gettok($hget(sentinel.teams,$replace($1,$chr(32),_)),2,32) if ( %team == $null ) { var %team = $1 } if ( %color == $null ) { return " $+ %team $+ " } else { return $+ %color $+ %team } } on *:INVITE:#:{ join $chan .timersentinel.invite.check 1 5 sentinel.invite.check $nick $chan } alias sentinel.invite.check { ;--If invited to the admin channel, just say there so the =activate command can be used correctly. if ( $2 == $gettok($hget(sentinel.irc,admin),1,32) ) return ;--Force users to use /invite so the bot can record who exactly invited it if ( $1 = ChanServ ) { msg $2 rawr! you need to use the following command to invite me: /invite $me $2 | part $2 | return } ;--If ChanServ is not a part of channel, don't stick around if ( ChanServ !isop $2 ) { msg $2 i will only stay in a registered channel, sorry... :~( | part $2 | return } ;--Notify the monitor channel then join and introduce yerself! msg $gettok($hget(sentinel.irc,monitor),1,32) rawr! i just got invited to $2 by $1 $+ ! i feel teh 4<3 ;)~ msg $2 rawr! i'm a Sentinel bot! msg $1 i've just added $2 to my list of auto-joins because you invited me. all ops in $2 can use =rules to change my channel notification settings. use =rules help to get started! ;--Save invited information to ini hadd sentinel.invited $2 $ctime $1 hsave -i sentinel.invited sentinel.ini invited } on *:KICK:#:{ ;--For the GameSurge IRC network, after netsplits ChanServ will kick you with the reason of "Net Rider" for channel management purposes. ;--Simply rejoining the channel is acceptable. The trick is make sure we have the password or not. if ( ( $knick == $me ) && ( $1- == Net Rider ) ) { if ( $chan == $gettok($hget(sentinel.irc,monitor),1,32) ) { var %rejoin = $hget(sentinel.irc,monitor) } elseif ( $chan == $gettok($hget(sentinel.irc,admin),1,32) ) { var %rejoin = $hget(sentinel.irc,admin) } elseif ( $chan == $gettok($hget(sentinel.irc,tv),1,32) ) { var %rejoin = $hget(sentinel.irc,tv) } else { var %rejoin = $chan } join %rejoin return } ;--If this is the admin channel, just leave as expected to. if ( $2 == $gettok($hget(sentinel.irc,admin),1,32) ) return ;--Else it looks like this really is a goodbye. :~( if ( $knick == $me ) { part $chan 5Sentinel Bot: Removed from service. notice $nick thx for having me! i won't come back to $chan unless someone invites me again... msg $gettok($hget(sentinel.irc,monitor),1,32) $+ $nick just kicked me outta $chan ... :~( i fear they might not wub me anymore *sniff* ;--Remove this channel from the invited list hdel sentinel.invited $chan hsave -i sentinel.invited sentinel.ini invited ;--Remove all the rules for this channel hfree [ sentinel.rules. $+ [ $chan ] ] remini sentinel.ini [ rules. $+ [ $chan ] ] } } on *:TEXT:=rules*:#:{ if ( $nick !isop $chan ) { [ .timersentinel.denied 1 1 notice $nick Denied: You lack operator status in $chan $+ . } else { if ( $2 == $null ) { ;--Get channel rules var %players = $hget([ sentinel.rules. $+ [ $chan ] ],players) var %maps = $hget([ sentinel.rules. $+ [ $chan ] ],maps) var %type = $hget([ sentinel.rules. $+ [ $chan ] ],type) var %min = $hget([ sentinel.rules. $+ [ $chan ] ],min) var %max = $hget([ sentinel.rules. $+ [ $chan ] ],max) ;--If a rule is not defined for a channel, use the default if ( %players == $null ) { var %players = $hget(sentinel.rules.default,players) } if ( %maps == $null ) { var %maps = $hget(sentinel.rules.default,maps) } if ( %type == $null ) { var %type = $hget(sentinel.rules.default,type) } if ( %min == $null ) { var %min = $hget(sentinel.rules.default,min) } if ( %max == $null ) { var %max = $hget(sentinel.rules.default,max) } ;--Give the user the info notice $nick $chan $+ : Players = $gettok(%players,3,32) $+ $chr(40) $+ Default: $gettok($hget(sentinel.rules.default,players),3,32) $+ $chr(41) $chr($asc(|)) Min number of players, bots are not counted. notice $nick $chan $+ : Min = $gettok(%min,3,32) $+ $chr(40) $+ Default: $gettok($hget(sentinel.rules.default,min),3,32) $+ $chr(41) $chr($asc(|)) Shortest time in seconds before bot can notify again. notice $nick $chan $+ : Max = $gettok(%max,3,32) $+ $chr(40) $+ Default: $gettok($hget(sentinel.rules.default,max),3,32) $+ $chr(41) $chr($asc(|)) Longest time in seconds bot will wait before notifying again. notice $nick $chan $+ : Type = $gettok(%type,3,32) $+ $chr(40) $+ Default: $gettok($hget(sentinel.rules.default,type),3,32) $+ $chr(41) $chr($asc(|)) If notify, Maps contains maps to notify if played. If ignore, Maps contains maps that no notifications will occur on. notice $nick $chan $+ : Maps = $gettok(%maps,3-,32) } else { ;--Verify the parameter is one this function accepts var %params = players min max forced type maps help if ( $findtok(%params,$lower($2),0,32) == 0 ) { [ .timersentinel. $+ [ $nick ] ] 1 1 notice $nick Error: I don't understand the $2 parameter. See =rules help for more info. } elseif ( $lower($2) == help ) { [ .timersentinel. $+ [ $nick ] $+ 1 ] 1 1 notice $nick =rules ( View/change/reset channel notification rules for all servers with this command. ) [ .timersentinel. $+ [ $nick ] $+ 2 ] 1 1 notice $nick Syntax: =rules $chr($asc([)) $+ <rule_name> $+ $chr($asc([)) <rule_value> $+ $chr($asc(])) $+ $chr($asc(])) [ .timersentinel. $+ [ $nick ] $+ 3 ] 1 1 notice $nick To view the channel's current rules, do not include any parameters. Example: =rules [ .timersentinel. $+ [ $nick ] $+ 4 ] 1 1 notice $nick To edit a rule, include the <rule_name> and the <rule_value> parameters. Example: =rules min 120 [ .timersentinel. $+ [ $nick ] $+ 5 ] 1 1 notice $nick To reset a rule to default, only put the <rule_name> parameter. Example: =rules min } else { ;--Edit hash entry if param $3- isn't null, else del the hash entry var %old = $gettok($hget([ sentinel.rules. $+ [ $chan ] ],$2),3-,32) if ( %old == $null ) { var %old = $gettok($hget(sentinel.rules.default,$2),3-,32) } if ( $3- != $null ) { hadd -m [ sentinel.rules. $+ [ $chan ] ] $2 $ctime $nick $3- } else { hdel [ sentinel.rules. $+ [ $chan ] ] $2 } hsave -i [ sentinel.rules. $+ [ $chan ] ] sentinel.ini [ rules. $+ [ $chan ] ] if ( $3- != $null ) { [ .timersentinel. $+ [ $nick ] ] 1 1 notice $nick $+ $2 rule changed for $chan $+ from " $+ %old $+ " to " $+ $3- $+ " } else { [ .timersentinel. $+ [ $nick ] ] 1 1 notice $nick $+ $2 rule reset to default for $chan $+ from " $+ %old $+ " to " $+ $gettok($hget(sentinel.rules.default,$2),3-,32) $+ " } } } } } on *:TEXT:=help:*:{ var %adminop = $iif($nick isop $gettok($hget(sentinel.irc,admin),1,32),$true,$false) var %monitorop = $iif($nick isop $gettok($hget(sentinel.irc,monitor),1,32) || $nick isop $gettok($hget(sentinel.irc,tv),1,32),$true,$false) var %status = You $iif(%adminop,are,are not) an op in the admin channel ( $+ $gettok($hget(sentinel.irc,admin),1,32) $+ ) and you $iif(%monitorop,are,are not) an op in the monitor ( $+ $gettok($hget(sentinel.irc,monitor),1,32) $+ ) or tv ( $+ $gettok($hget(sentinel.irc,tv),1,32) $+ ) channel. [ .timersentinel. $+ [ $nick ] $+ 1 ] 1 1 notice $nick %status $iif(%adminop || %monitorop,With your current status you can use the following commands:,) if ( ( $nick isop $chan ) && ( $chan != $gettok($hget(sentinel.irc,tv),1,32) ) ) { [ .timersentinel. $+ [ $nick ] $+ 2 ] 1 1 notice $nick =rules help :: Adjusts channel notification criteria. :: Usable in any channel except $gettok($hget(sentinel.irc,tv),1,32) by Ops in calling channel } if ( $nick isop $gettok($hget(sentinel.irc,monitor),1,32) || $nick isop $gettok($hget(sentinel.irc,tv),1,32)$nick isop $gettok($hget(sentinel.irc,admin),1,32) ) { [ .timersentinel. $+ [ $nick ] $+ 3 ] 1 1 notice $nick =chat <message> :: Sends <message> into game public chat. :: Usable only in $gettok($hget(sentinel.irc,tv),1,32) by Ops in $gettok($hget(sentinel.irc,monitor),1,32) or $gettok($hget(sentinel.irc,tv),1,32) [ .timersentinel. $+ [ $nick ] $+ 4 ] 1 1 notice $nick =status :: Displays current game status on server. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,monitor),1,32) or $gettok($hget(sentinel.irc,tv),1,32) [ .timersentinel. $+ [ $nick ] $+ 5 ] 1 1 notice $nick =players[ <player_name>] :: Lists current player names or detailed player info if <player_name> matches a current player. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,monitor),1,32) or $gettok($hget(sentinel.irc,tv),1,32) [ .timersentinel. $+ [ $nick ] $+ 6 ] 1 1 notice $nick =invited :: Lists channels bot has been invited into. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,monitor),1,32) or $gettok($hget(sentinel.irc,tv),1,32) } if ( $nick isop $gettok($hget(sentinel.irc,admin),1,32) ) { [ .timersentinel. $+ [ $nick ] $+ 7 ] 1 1 notice $nick =close :: Closes server log/rcon interaction with bot but keeps bot available in irc to open. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,admin),1,32) [ .timersentinel. $+ [ $nick ] $+ 8 ] 1 1 notice $nick =open :: Opens server log/rcon interaction with bot. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,admin),1,32) if ( $hget(sentinel.general,allowrcon) == 1 ) { [ .timersentinel. $+ [ $nick ] $+ 9 ] 1 1 notice $nick =rcon <cmd> :: Issues RCON command <cmd> to server. :: Usable in any channel by Ops in $gettok($hget(sentinel.irc,admin),1,32) } } [ .timersentinel. $+ [ $nick ] $+ 9 ] 1 1 notice $nick Sentinel Bot $hget(sentinel.general,version) :: $hget(sentinel.general,url) } on *:TEXT:=rcon *:*:{ if ( $nick !isop $gettok($hget(sentinel.irc,admin),1,32) ) { .timersentinel.denied 1 1 notice $nick Denied: You lack operator status in $gettok($hget(sentinel.irc,admin),1,32) $+ . | return } if ( $hget(sentinel.general,allowrcon) != 1 ) { .timersentinel.disabled 1 1 notice $nick Feature Disabled: RCON access not allowed. | return } if ( %sentinel.rcon.response != $null ) { [ .timersentinel. $+ [ $nick ] ] 1 1 notice $nick RCON Temporarily Unavailable. Currently in use $iif($left(%sentinel.rcon.response,1) == $chr($asc(#)),in,by) %sentinel.rcon.response $+ . Please try again in a few seconds. } set -u10 %sentinel.rcon.response $iif($chan != $null,$chan,$nick) sentinel.rcon =rcon $2- } on *:TEXT:=chat *:#:{ if ( $chan != $gettok($hget(sentinel.irc,tv),1,32) ) return if ( $nick !isop $gettok($hget(sentinel.irc,monitor),1,32) && $nick !isop $gettok($hget(sentinel.irc,tv),1,32) && $nick !isop $gettok($hget(sentinel.irc,admin),1,32) ) return var %message = $strip($2-) if ( %message == $null ) return var %message = $chan $chr($asc(|)) $nick : %message sentinel.rcon say %message } on *:TEXT:=close:*:{ if ( $nick isop $gettok($hget(sentinel.irc,admin),1,32) ) sentinel.server.close } on *:TEXT:=open:*:{ if ( $nick isop $gettok($hget(sentinel.irc,admin),1,32) ) sentinel.server.open } on *:TEXT:=activate:*:{ if ( $nick isop $gettok($hget(sentinel.irc,admin),1,32) ) sentinel.activate } on *:TEXT:=deactivate:*:{ if ( $nick isop $gettok($hget(sentinel.irc,admin),1,32) ) sentinel.deactivate } alias sentinel.servers { msg $1 $+ %i $+ $chr(40) $+ $+ %closed $+ $+ $chr(41) $chr($asc(|)) $+ 1,15 $hget([ server $+ [ %i ] $+ .status ],hostName) $+ $chr(40) $+ $hget([ server $+ [ %i ] ],ip) $+ : $+ $hget([ server $+ [ %i ] ],port) $+ $chr(41) $+ $chr($asc(|)) $hget([ server $+ [ %i ] ],tv) $+ $chr($asc(|)) $+ 1,15 $hget([ server $+ [ %i ] $+ .status ],map) $+ $chr(40) $+ $hget([ server $+ [ %i ] $+ .status ],playerCount) $+ $chr($asc(/)) $+ $hget([ server $+ [ %i ] $+ .status ],playerMax) $+ $chr(41) } on *:TEXT:=invited:*:{ echo -s chan: $chan nick: $nick if ( $nick !isop $gettok($hget(sentinel.irc,monitor),1,32) && $nick !isop $gettok($hget(sentinel.irc,tv),1,32) && $nick !isop $gettok($hget(sentinel.irc,admin),1,32) ) { return } [ .timersentinel.invited. $+ [ $chan ] ] 1 2 sentinel.invited $iif($chan != $null,$chan,$nick) } alias sentinel.invited { if ($hget(sentinel.invited,0).item == 0) { msg $1 Nobody has invited me. :~( return } var %i = 1 while ( %i <= $hget(sentinel.invited,0).item ) { var %invited = $hget(sentinel.invited,%i).item $hget(sentinel.invited,%i).data msg $1 $gettok(%invited,1,32) $chr($asc(|)) $+ 1,15 $gettok(%invited,3,32) $+ $chr($asc(|)) $asctime($gettok(%invited,2,32),m/d/yy @ h:mmtt) inc %i } } on *:TEXT:=status:*:{ if ( $nick !isop $gettok($hget(sentinel.irc,monitor),1,32) && $nick !isop $gettok($hget(sentinel.irc,tv),1,32) && $nick !isop $gettok($hget(sentinel.irc,admin),1,32) ) { return } if ( $timer(sentinel.status) == $null ) { sentinel.rcon server_game_time .timersentinel.rcon.mp_timelimit 1 1 sentinel.rcon mp_timelimit .timersentinel.rcon.sm_nextmap 1 1 sentinel.rcon sm_nextmap } .timersentinel.status 1 3 sentinel.status $iif($chan != $null,$chan,$nick) } alias sentinel.status { if ($hget(sentinel.server.status,sv_visiblemaxplayers) == -1) var %max = $hget(sentinel.server.status,player.max) else var %max = $hget(sentinel.server.status,sv_visiblemaxplayers) hadd -m sentinel.server.status playersNbots $hget(sentinel.server.status,player.count) $+ / $+ %max players if ( $hget(sentinel.server.status,bot.count) > 0 ) { hadd -m sentinel.server.status playersNbots $hget(sentinel.server.status,playersNbots) $chr($asc(|)) + $+ $hget(sentinel.server.status,bot.count) bots } if ( $hget(sentinel.server.status,mp_timelimit) = 0 ) var %timeleft = No Time Limit else { var %timeleft = $calc($hget(sentinel.server.status,mp_timelimit) * 60 - $hget(sentinel.server.status,server_game_time)) if (%timeleft < 0) var %timeleft = 0 var %timeleft = $duration(%timeleft) left } var %status = 14 $+ $hget(sentinel.server.status,hostname) $+ $chr($asc(|)) 5Status: $hget(sentinel.server.status,map) :: $hget(sentinel.server.status,playersNbots) :: %timeleft if ($hget(sentinel.server.status,sm_nextmap) != $null) var %status = %status :: Next map is " $+ $hget(sentinel.server.status,sm_nextmap) $+ " var %status = %status :: steam://connect/ $+ $hget(sentinel.server,address) msg $1 %status } on *:TEXT:=players*:*:{ if ( $nick !isop $gettok($hget(sentinel.irc,monitor),1,32) && $nick !isop $gettok($hget(sentinel.irc,tv),1,32) && $nick !isop $gettok($hget(sentinel.irc,admin),1,32) ) { return } .timersentinel.players 1 3 sentinel.players $iif($chan != $null,$chan,$nick) $2- } alias sentinel.players { ;--Remove the mapchange status at this point unset %sentinel.status if ( $hget(sentinel.rcon.status,0).item == 0 ) { msg $1 5Players: None :~( | return } if ( $2 != $null ) { var %i = 1 while ( %i <= $hget(sentinel.rcon.status,0).item ) { if ( $gettok($hget(sentinel.rcon.status,%i).data,7-,32) == $2- ) { tokenize 32 $1 $hget(sentinel.rcon.status,%i).data ;--sentinel.rcon.status = ID2 time3 ping4 loss5 adr6 state7 name8- var %team = $hget(sentinel.players,$hget(sentinel.rcon.status,%i).item) var %pinfo = $8- $+ $chr($asc(<)) $+ 0 $+ $chr($asc(>)) $+ $chr($asc(<)) $+ 0 $+ $chr($asc(>)) $+ $chr($asc(<)) $+ %team $+ $chr($asc(>)) msg $1 5Player Info: $sentinel.format.player(%pinfo) $+ $chr($asc(|)) $2 $chr($asc(|)) $4 $+ ms $+ $chr(40) $+ loss= $+ $5 $+ $chr(41) $chr($asc(|)) $3 $iif($7 != active,$chr($asc(|)) $7,) } inc %i } } else { var %i = 1 :nextplayer tokenize 32 $1 $hget(sentinel.rcon.status,%i).data ;--sentinel.rcon.status = ID2 time3 ping4 loss5 adr6 state7 name8- var %team = $hget(sentinel.players,$hget(sentinel.rcon.status,%i).item) var %pinfo = $8- $+ $chr($asc(<)) $+ 0 $+ $chr($asc(>)) $+ $chr($asc(<)) $+ 0 $+ $chr($asc(>)) $+ $chr($asc(<)) $+ %team $+ $chr($asc(>)) var %names = %names " $+ $sentinel.format.player(%pinfo) $+ $+ " if ( $gettok($calc(%i / 5),2,$asc(.)) == $null ) { msg $1 5Players: %names var %names = $null } inc %i if ( $hget(sentinel.rcon.status,%i).data != $null ) { if ( %names != $null ) var %names = %names $+ , goto nextplayer } else { if ( %names != $null ) msg $1 5Players: %names var %names = $null } } } alias sentinel.notify { ;--Check individual channel notification rules var %i = -1 while ( %i <= $hget(sentinel.invited,0).item ) { if ( %i == -1 ) { var %chan = $gettok($hget(sentinel.irc,monitor),1,32) } elseif ( %i == 0 ) { var %chan = $gettok($hget(sentinel.irc,admin),1,32) } else { var %chan = $hget(sentinel.invited,%i).item } ;--Setup status and channel rule variables var %status.map = $hget(sentinel.server.status,map) var %status.player.count = $hget(sentinel.server.status,player.count) var %status.hostname = $hget(sentinel.server.status,hostname) if ($hget(sentinel.server.status,sv_visiblemaxplayers) == -1) var %max = $hget(sentinel.server.status,player.max) else var %max = $hget(sentinel.server.status,sv_visiblemaxplayers) var %status.player.max = %max var %rules.players = $gettok($hget([ sentinel.rules. $+ [ %chan ] ],players),3,32) var %rules.maps = $gettok($hget([ sentinel.rules. $+ [ %chan ] ],maps),3-,32) var %rules.type = $gettok($hget([ sentinel.rules. $+ [ %chan ] ],type),3,32) var %rules.max = $gettok($hget([ sentinel.rules. $+ [ %chan ] ],max),3,32) var %rules.min = $gettok($hget([ sentinel.rules. $+ [ %chan ] ],min),3,32) var %rules.default.players = $gettok($hget(sentinel.rules.default,players),3,32) var %rules.default.maps = $gettok($hget(sentinel.rules.default,maps),3-,32) var %rules.default.type = $gettok($hget(sentinel.rules.default,type),3,32) var %rules.default.max = $gettok($hget(sentinel.rules.default,max),3,32) var %rules.default.min = $gettok($hget(sentinel.rules.default,min),3,32) if ( %rules.players == $null ) { var %rules.players = %rules.default.players } if ( %rules.maps == $null ) { var %rules.maps = %rules.default.maps } if ( %rules.type == $null ) { var %rules.type = %rules.default.type } if ( %rules.max == $null ) { var %rules.max = %rules.default.max } if ( %rules.min == $null ) { var %rules.min = %rules.default.min } ;--Compare status to rules for channel, if a rule is broken, the loop continues on the next channel if ( %status.player.count < %rules.players ) { inc %i | continue } if ( %rules.type != notify ) { if ( $findtok($lower(%rules.maps),$lower(%status.map),1,32) != $null ) { inc %i | continue } } else { if ( $findtok($lower(%rules.maps),$lower(%status.map),1,32) == $null ) { inc %i | continue } } var %last.ctime = $hget([ sentinel.notify. $+ [ %chan ] ],last.ctime) var %last.player.count = $hget([ sentinel.notify. $+ [ %chan ] ],last.player.count) if ( $calc($ctime - %last.ctime) < %rules.min ) { inc %i | continue } if ( (%status.players <= %last.player.count) && ($calc($ctime - %last.ctime) < %rules.max) ) { inc %i | continue } ;--All rules met with current status, send out the alert var %info = 5 $+ %status.map is being played on 12 $+ %status.hostname $+ $chr(40) $hget(sentinel.server,address) $chr(41) 5with %status.player.count $+ $chr($asc(/)) $+ %status.player.max players! Join in on the carnage!! msg %chan %info hadd -m [ sentinel.notify. $+ [ %chan ] ] last.ctime $ctime hadd -m [ sentinel.notify. $+ [ %chan ] ] last.player.count %status.player.count inc %i } } dialog sentinel.options { title "Sentinel Bot Options" size -1 -1 186 168 option dbu tab "General", 29, 1 0 182 149 check "Automatically activate Sentinel Bot on IRC connection", 9, 6 17 144 10, tab 29 edit "", 14, 29 37 50 10, tab 29 autohs edit "", 18, 128 37 50 10, tab 29 autohs edit "", 15, 29 48 50 10, tab 29 autohs edit "", 21, 128 48 50 10, tab 29 autohs edit "", 16, 29 59 50 10, tab 29 autohs edit "", 22, 128 59 50 10, tab 29 autohs edit "", 4, 50 85 67 10, tab 29 autohs edit "", 5, 50 96 67 10, tab 29 autohs edit "", 26, 30 121 138 10, tab 29 autohs edit "", 27, 30 132 67 10, tab 29 autohs box "IRC Channels", 10, 4 29 178 45, tab 29 text "Admin:", 11, 7 39 22 8, tab 29 right text "Admin Password:", 17, 81 39 47 8, tab 29 right text "TV Password:", 19, 81 50 47 8, tab 29 right text "TV:", 12, 7 50 22 8, tab 29 right text "Monitor:", 13, 7 61 22 8, tab 29 right text "Monitor Password:", 20, 81 61 47 8, tab 29 right box "Server", 1, 4 77 178 34, tab 29 text "Address:", 2, 7 87 43 8, tab 29 right text "RCON Password:", 3, 7 98 43 8, tab 29 right text "Example: 1.2.3.4:27015", 8, 118 87 60 8, disable tab 29 text "File:", 24, 7 123 23 8, tab 29 right text "Address:", 25, 7 134 23 8, tab 29 right box "Logging", 23, 4 114 178 33, tab 29 text "Example: 1.2.3.4:28888", 28, 98 134 60 8, disable tab 29 button "...", 53, 169 122 9 8, tab 29 tab "Default Rules", 30 edit "", 43, 31 18 21 10, tab 30 autohs edit "", 42, 31 29 21 10, tab 30 autohs edit "", 41, 31 40 21 10, tab 30 autohs edit "", 37, 9 63 71 10, tab 30 autohs right list 36, 9 73 71 63, tab 30 sort size extsel button "Add", 38, 81 63 30 10, tab 30 button "Remove", 39, 81 74 30 10, tab 30 radio "Ignore when Maps are played", 40, 89 105 82 10, tab 30 radio "Notify when Maps are played", 47, 89 116 82 10, tab 30 text "Minimum number of players, bots are not counted.", 44, 53 20 124 8, tab 30 text "Shortest time in seconds before bot notifies again.", 45, 53 31 124 8, tab 30 text "Longest time in seconds before bot notifies again.", 46, 53 42 124 8, tab 30 box "Maps", 48, 4 53 178 94, tab 30 text "Players:", 31, 6 20 25 8, tab 30 right text "Type:", 33, 88 96 27 8, tab 30 text "Min:", 34, 6 31 25 8, tab 30 right text "Max:", 35, 6 42 25 8, tab 30 right text ":Selected", 32, 19 136 23 8, tab 30 text "0", 50, 7 136 12 8, tab 30 right text ":Total", 51, 58 136 15 8, tab 30 text "0", 52, 45 136 13 8, tab 30 right tab "Features", 300 box "TV Channel Display", 58, 4 17 178 59, tab 300 check "Player connects and disconnects", 305, 9 26 92 10, tab 300 check "Player IP and ID information upon connection", 310, 18 38 122 10, tab 300 check "Team chat (say_team / mm2)", 315, 9 50 158 10, tab 300 check "Allow RCON access to Ops in Admin channel", 325, 9 81 118 10, tab 300 tab "Advanced", 59 radio "Dynamic", 61, 9 26 33 10, tab 59 radio "Static", 62, 9 38 32 10, tab 59 box "Port Options", 68, 4 17 178 60, tab 59 text "Preferrably in the Private Port range of 49152 through 65535", 60, 72 53 78 14, disable tab 59 text "Log:", 66, 24 61 18 8, disable tab 59 right edit "", 64, 42 60 23 10, disable tab 59 limit 5 link "v0.0.0b - YYYY/MM/DD by EdGruberman", 49, 3 156 98 8 button "OK", 6, 105 154 37 12, ok button "Cancel", 7, 146 154 37 12, default cancel } on *:DIALOG:sentinel.options:sclick:53:{ var %folder = $sdir($iif($did(26) != $null,$did(26),.),Select Log File Location) did -ra sentinel.options 26 $iif(%folder != $null,%folder,$did(26)) } on *:DIALOG:sentinel.options:sclick:49:{ url -an $hget(sentinel.general,url) } on *:DIALOG:sentinel.options:sclick:36:{ sentinel.options.update } alias sentinel.options.update { did -ra sentinel.options 50 $did(sentinel.options,36,0).sel did -ra sentinel.options 52 $did(sentinel.options,36).lines } on *:DIALOG:sentinel.options:sclick:38:{ ;--Add entered map to list var %map = $replace($did(37),$chr(32),$null) if ( %map == $null ) { return } did -i sentinel.options 36 1 %map did -r sentinel.options 37 sentinel.options.update } on *:DIALOG:sentinel.options:sclick:39:{ ;--Remove selected maps from list var %i = $did(36,0).sel while ( %i > 0 ) { var %sel = $did(36,%i).sel did -ra sentinel.options 37 $did(36,%sel) did -d sentinel.options 36 %sel dec %i } sentinel.options.update } on *:DIALOG:sentinel.options:sclick:61:{ ;--Dynamic ports selected did -b sentinel.options 60,64,66 } on *:DIALOG:sentinel.options:sclick:62:{ ;--Static ports selected did -e sentinel.options 60,64,66 } on *:DIALOG:sentinel.options:sclick:305:{ ;--Connects/Disconnects display toggled if ( $did(305).state == 1 ) { did -e sentinel.options 310 } else { did -b sentinel.options 310 } } on *:DIALOG:sentinel.options:init:0:{ ;--General Tab if ( $hget(sentinel.general,autoactivate) == 1 ) { did -c sentinel.options 9 } did -ra sentinel.options 14 $gettok($hget(sentinel.irc,admin),1,32) did -ra sentinel.options 18 $gettok($hget(sentinel.irc,admin),2,32) did -ra sentinel.options 15 $gettok($hget(sentinel.irc,tv),1,32) did -ra sentinel.options 21 $gettok($hget(sentinel.irc,tv),2,32) did -ra sentinel.options 16 $gettok($hget(sentinel.irc,monitor),1,32) did -ra sentinel.options 22 $gettok($hget(sentinel.irc,monitor),2,32) did -ra sentinel.options 4 $hget(sentinel.server,address) did -ra sentinel.options 5 $hget(sentinel.server,rcon_password) did -ra sentinel.options 26 $hget(sentinel.log,file) did -ra sentinel.options 27 $hget(sentinel.log,address) ;--Default Rules Tab didtok sentinel.options 36 32 $gettok($hget(sentinel.rules.default,maps),3-,32) sentinel.options.update did -ra sentinel.options 43 $gettok($hget(sentinel.rules.default,players),3,32) did -ra sentinel.options 42 $gettok($hget(sentinel.rules.default,min),3,32) did -ra sentinel.options 41 $gettok($hget(sentinel.rules.default,max),3,32) if ( $gettok($hget(sentinel.rules.default,type),3,32) == ignore ) { did -c sentinel.options 40 } else { did -c sentinel.options 47 } ;--Features Tab if ( $hget(sentinel.general,show.connects) == 1 ) { did -c sentinel.options 305 } else { did -b sentinel.options 310 } if ( $hget(sentinel.general,show.ip) == 1 ) { did -c sentinel.options 310 } if ( $hget(sentinel.general,show.sayteam) == 1 ) { did -c sentinel.options 315 } if ( $hget(sentinel.general,allowrcon) == 1 ) { did -c sentinel.options 325 } ;--Advanced Tab if ( $hget(sentinel.general,port.type) == dynamic ) { did -c sentinel.options 61 did -b sentinel.options 60,64,66 } else { did -c sentinel.options 62 did -e sentinel.options 60,64,66 } did -ra sentinel.options 64 $hget(sentinel.general,port.log) ;--Link did -ra sentinel.options 49 $hget(sentinel.general,version) ;--If bot is activated, disable disruptive settings if ( $hget(sentinel.general.status,activated) == 1 ) { did -b sentinel.options 14,15,16,4,61,62,64 } } on *:DIALOG:sentinel.options:sclick:6:{ ;--OK clicked, update all hash tables and save to ini file hadd sentinel.general autoactivate $did(9).state hadd sentinel.general show.connects $did(305).state hadd sentinel.general show.ip $did(310).state hadd sentinel.general show.sayteam $did(315).state hadd sentinel.general allowrcon $did(325).state hadd sentinel.general port.type $iif($did(62).state == 1,static,dynamic) hadd sentinel.general port.log $did(64) hsave -i sentinel.general sentinel.ini general hadd sentinel.irc admin $did(14) $did(18) hadd sentinel.irc tv $did(15) $did(21) hadd sentinel.irc monitor $did(16) $did(22) hsave -i sentinel.irc sentinel.ini irc hadd sentinel.server address $did(4) hadd sentinel.server rcon_password $did(5) hsave -i sentinel.server sentinel.ini server hadd sentinel.log file $did(26) hadd sentinel.log address $did(27) hsave -i sentinel.log sentinel.ini log hadd sentinel.rules.default players $ctime Default $did(43) hadd sentinel.rules.default min $ctime Default $did(42) hadd sentinel.rules.default max $ctime Default $did(41) hadd sentinel.rules.default type $ctime Default $iif($did(40).state == 1,ignore,notify) var %i = 1 hadd sentinel.rules.default maps $ctime Default while ( %i <= $did(36).lines ) { hadd sentinel.rules.default maps $ctime Default $gettok($hget(sentinel.rules.default,maps),3-,32) $did(36,%i) inc %i } hsave -i sentinel.rules.default sentinel.ini rules.default } menu status,channel,menubar { Sentinel Bot .$iif($status != connected || $hget(sentinel.general.status,activated) == 1,$style(2)) Activate:sentinel.activate .$iif($hget(sentinel.general.status,activated) != 1,$style(2)) Deactivate:sentinel.deactivate .- .Options...:{ if ( $dialog(sentinel.options).hwnd == $null ) { dialog -am sentinel.options sentinel.options } | dialog -v sentinel.options } } alias debug.binvar { ;--This is a generic routine that will output the contents of a binary variable to the status window ;--much like a network packet analyzer commonly displays such binary information. var %header = _OFFSET__00 01 02 03 04 05 06 07___08 09 0A 0B 0C 0D 0E 0F___01234567 89ABCDEF echo -s $str(_,$len(%header)) echo -s $timestamp $2- echo -s %header var %offset = 0 var %i = 1 while (%i <= $bvar($1,0)) { var %line = %line $+ $chr(32) $+ $base($bvar($1,%i),10,16,2) var %char = $bvar($1,%i).text if (($bvar($1,%i) < 33) || ($bvar($1,%i) > 126)) var %char = . if ($calc((%i - 9) % 8) == 0) { var %text = %text $+ $chr(32) $+ %char } else { var %text = %text $+ %char } if (($calc(%i % 8) == 0) && ($calc(%i % 16) != 0)) { var %line = %line $+ $chr(32) $+ _ } if (($calc(%i % 16) == 0) || (%i == $bvar($1,0))) { if ((%i = $bvar($1,0)) && ($calc($bvar($1,0) % 16) > 0)) { var %line = %line $+ $str($chr(32) $+ __,$calc(16 - ($bvar($1,0) % 16) - 8)) if ($calc(16 - ($bvar($1,0) % 16) - 8) > 0) var %line = %line _ var %ext = $calc(16 - ($bvar($1,0) % 16)) if ( %ext > 8) var %ext = 8 var %line = %line $str($chr(32) $+ __,%ext) } echo -s $base(%offset,10,16,8) %line _ %text var %line, %text var %offset = %offset + 16 } inc %i } echo -s $str(¯,$len(%header)) }