• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 02:22
CEST 08:22
KST 15:22
  • Home
  • Forum
  • Calendar
  • Streams
  • Liquipedia
  • Features
  • Store
  • EPT
  • TL+
  • StarCraft 2
  • Brood War
  • Smash
  • Heroes
  • Counter-Strike
  • Overwatch
  • Liquibet
  • Fantasy StarCraft
  • TLPD
  • StarCraft 2
  • Brood War
  • Blogs
Forum Sidebar
Events/Features
News
Featured News
Code S Season 2 - RO4 & Finals Results (2025)2Code S RO4 & Finals Preview: herO, Rogue, Classic, GuMiho0TL Team Map Contest #5: Presented by Monster Energy4Code S RO8 Preview: herO, Zoun, Bunny, Classic7Code S RO8 Preview: Rogue, GuMiho, Solar, Maru3
Community News
Weekly Cups (June 9-15): herO doubles on GSL week0Firefly suspended by EWC, replaced by Lancer11Classic & herO RO8 Interviews: "I think it’s time to teach [Rogue] a lesson."2Rogue & GuMiho RO8 interviews: "Lifting that trophy would be a testament to all I’ve had to overcome over the years and how far I’ve come on this journey.8Code S RO8 Results + RO4 Bracket (2025 Season 2)14
StarCraft 2
General
How herO can make history in the Code S S2 finals Rain's Behind the Scenes Storytime Firefly suspended by EWC, replaced by Lancer Code S Season 2 - RO4 & Finals Results (2025) Weekly Cups (June 9-15): herO doubles on GSL week
Tourneys
RSL: Revival, a new crowdfunded tournament series $3,500 WardiTV European League 2025 [GSL 2025] Code S: Season 2 - Semi Finals & Finals WardiTV Mondays Sparkling Tuna Cup - Weekly Open Tournament
Strategy
Simple Questions Simple Answers [G] Darkgrid Layout
Custom Maps
[UMS] Zillion Zerglings
External Content
Mutation # 478 Instant Karma Mutation # 477 Slow and Steady Mutation # 476 Charnel House Mutation # 475 Hard Target
Brood War
General
ASL20 Preliminary Maps BGH Auto Balance -> http://bghmmr.eu/ BW General Discussion Recent recommended BW games FlaSh Witnesses SCV Pull Off the Impossible vs Shu
Tourneys
[Megathread] Daily Proleagues [BSL 2v2] ProLeague Season 3 - Friday 21:00 CET Small VOD Thread 2.0 [BSL20] ProLeague Bracket Stage - Day 4
Strategy
I am doing this better than progamers do. [G] How to get started on ladder as a new Z player
Other Games
General Games
Stormgate/Frost Giant Megathread Nintendo Switch Thread Path of Exile Beyond All Reason What do you want from future RTS games?
Dota 2
Official 'what is Dota anymore' discussion
League of Legends
Heroes of the Storm
Simple Questions, Simple Answers Heroes of the Storm 2.0
Hearthstone
Heroes of StarCraft mini-set
TL Mafia
Vanilla Mini Mafia TL Mafia Community Thread
Community
General
US Politics Mega-thread Things Aren’t Peaceful in Palestine UK Politics Mega-thread Echoes of Revolution and Separation Russo-Ukrainian War Thread
Fan Clubs
SKT1 Classic Fan Club! Maru Fan Club
Media & Entertainment
Korean Music Discussion [Manga] One Piece
Sports
2024 - 2025 Football Thread Formula 1 Discussion NHL Playoffs 2024 TeamLiquid Health and Fitness Initiative For 2023
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread
TL Community
The Automated Ban List
Blogs
A Better Routine For Progame…
TrAiDoS
StarCraft improvement
iopq
Heero Yuy & the Tax…
KrillinFromwales
I was completely wrong ab…
jameswatts
Need Your Help/Advice
Glider
Trip to the Zoo
micronesia
Customize Sidebar...

Website Feedback

Closed Threads



Active: 32845 users

4 million views – the power of automation

Blogs > snipealot
Post a Reply
Normal
snipealot *
Profile Blog Joined February 2011
Korea (South)494 Posts
Last Edited: 2013-10-14 13:42:03
October 14 2013 13:16 GMT
#1
Warning: This post has a lot of really bad code. If you are a professional programmer you will likely cringe and go 'wtf' when you see some of it.

It has been a crazy 2 months. The automated bot system went online for snipe2 mid-august, and the 3 additional streams became available for 24/7 streaming early September. The arrival of Jangbi and Bisu on afreeca led to a 40% increase in viewer hours in September compared to August. If Bisu continues to stream every single day like he has so far this month we will probably see a similar increase in October. The interest in Bisu seems to have died down somewhat since he set 4 consecutive concurrent viewer records in September – the final one ending at 2373 viewers – but I have a feeling it’ll pick back up again when he participates in his first SOSPA event. Still, this is what the October viewer hours graph looks like so far thanks to Bisu:

[image loading]

Although graphs and statistics are interesting that’s not what this blog post is about. In this post I will go over the crude functions and mangled code that make up the snipealot bot systems, mainly focusing on the snipealot2 bot. There are a few differences in how they are all set up, but I will point this out when I get to those functions.

As with everything, the realization that it could all be automated popped into my head as I was working hard on finishing my dissertation. The deadline was coming up, so of course my brain was trying hard to make me focus on other things. My dissertation was on the rise of esports in Korea, so it wasn’t completely unrelated I guess. If anyone wants to read this they can find it HERE. (in korean)

Testing new code is always a 2-step process for me. I initially always write code and test it on my main computer before porting it to the relevant system – sometimes even testing important code on snipe3 before porting it to snipe2. The entire system relies on two simple scripting languages, mSL(mIRC scripting) and AHK(autohotkey). Although there are ways to have AHK send commands directly to mIRC, I’ve found the simplest way to have them communicate is by using simple text files. Both programs have the ability to read, write to and delete text files, and this combined with the timer system in mSL makes anything possible. To start with I’ll go over the code required to open/restart the standalone afreeca client. This code is used on snipe2 to restart the stream and on snipe3 every time it starts up. However it is not used on snipe0/snipe1 as they use IE and Silverlight to watch streams.

First the mIRC script:

+ Show Spoiler +
on *:text:!restartafreeca:#snipealot2 {
if ($read(c:allowedusers.txt, ns, $nick)) {
/run C:restartafreeca.ahk
}
}


This is the most basic function you can find in the code, the basis upon every single command is built. A command is written, the user who ran the command is checked vs a text file with all the moderators. If found the restartafreeca.ahk script is executed. This AHK script looks like this:

+ Show Spoiler +
Process, Close, afreecaplayer.exe
Process, Close, iexplore.exe
Sleep, 1000
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := True
Pwb.Navigate("http://gametv.afreeca.com/broad/index.html")
IELoad(Pwb) ;You need to send the IE handle to the function unless you define it as global.
{
If !Pwb ;If Pwb is not a valid pointer then quit
Return False
Loop ;Otherwise sleep for .1 seconds untill the page starts loading
Sleep,100
Until (Pwb.busy)
Loop ;Once it starts loading wait until completes
Sleep,100
Until (!Pwb.busy)
Loop ;optional check to wait for the page to completely load
Sleep,100
Until (Pwb.Document.Readystate = "Complete")
Return True
}
If IELoad(Pwb) = True
Pwb.Navigate("javascript:runPlayer('app_player')")
Sleep, 15000
Loop
{
FileReadLine, var1, C:setplayer.txt, 1
if ErrorLevel
break
ControlClick, x120 y50, afreeca list
Sleep, 500
ControlSend, Internet Explorer_Server1, {ctrl down}{shift down}{left}{ctrl up}{shift up}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, %var1%{enter}, afreeca list
Sleep, 1000
ControlClick, x50 y313, afreeca list
return
}
ComObjError(1)
Return


To explain it as a step by step process it works like this:

1. Close all instances of both IE and afreeca
2. Create an instance of Internet Explorer using ComObj
3. Navigate to the gametv afreeca page
4. Wait until the page is finished loading
5. Click the app_player button using javascript
6. After 15 seconds manually input the last player that was put on and try to enter the main room

This last part where it manually attempts to enter a room is a remnant from the first iteration of the stream-load code. I haven’t bothered to rewrite it yet on snipe2 as it works fine most of the time. This command is rarely used anyway on snipe2, and on snipe3 it has been rewritten and combined with the !setplayer command. This command is obviously used a lot and looks like this:

+ Show Spoiler +
on *:text:!setplayer*:#snipealot2 {
if (($read(c:allowedusers.txt, ns, $nick)) && (%playerchangechecktimer != 1)) {
if ($scanforplayer($2)) {
/remove c:streamdisconnected.txt
set %playerchangechecktimer 1
setplayer $scanforid($2)
unset %autovote.check
/timeravotestart off
/timerendautovote off
/run C:setplayer.ahk
if (%commercialtime != 1) {
set %commercialtime 1
msg $chan .commercial 60
inc %adruns. [ $+ [ $nick ] ]
set %commercial15limit 1
/timercommerciallimit off
/timercommerciallimit 1 900 /unset %commercial15limit
msg $chan Player change initiated - Running 60 second commercial break
/timer 1 480 /unset %commercialtime
}
msg $chan Changing to $2
/timercheckpreview 1 60 /checkpreview
/timer 1 80 /unset %playerchangechecktimer
/timer 1 5 /setoverlay $2
/quick_update $2 is now live!
/timerweibo 1 20 /weibo $2 is now live!
set %playedtime $calc($ctime - %playerstarttime)
write c:streamplayerstats.txt %currentplayer %playedtime %playerrace
if (%autovote == on) /resetautovote
set %currentplayername $2
set %currentplayer $scanforid($2)
set %playerstarttime $ctime
set %playerrace $findrace(%currentplayer)
/timerchecksetplayererror 1 13 /checksetplayererror
/tlsocket
/setafreecatext
}
else {
msg $chan No such Player found. If you wish to set an afreeca ID manually, use !setmanual
}
}
else if ($read(c:allowedusers.txt, ns, $nick)) {
msg $chan Player change too recent, please wait 1 minute.
}
}


Oh my god wall of text. It might look complicated but it really isn’t. In order to understand this command one needs to understand a few others first. As afreeca IDs are different from the players nicknames, these have to be used in order to let mods simply set players. These being the $scanforplayer, $scanforid and $setplayer aliases.
$scanforplayer + Show Spoiler +
 scanforplayer return $read(c:playerdatabase3.txt, nw, * $+ $1 $+ *) 

$scanforid + Show Spoiler +
 scanforid return $read(c:playerdatabase2.txt, ns, $1) 

$setplayer + Show Spoiler +
 setplayer write -c c:setplayer.txt $1 


The first one looks through playerdatabase3.txt for the nickname, the second looks through playerdatabase2.txt for the ID. Ignoring the /timerX off commands and variable unsets this command is pretty simple.

1. If the players nickname is found in the database using $scanforplayer, continue
2. Use $setplayer and $scanforid to find the ID of player $2 (the input after !setplayer) and write this to setplayer.txt
3. Disable a bunch of timers and unset variables in case this is a mod overriding the autovote system.
4. Run setplayer.ahk to put the player on stream
5. If a commercial has not been run within the past 8 minutes, run a commercial break to coincide with the afreeca ads
6. Write to the channel that player $2 is being put on
7. Start a timer to check for the afreeca preview screen (if the room is full this will trigger)
8. Start a timer preventing another !setplayer command for 80 seconds
9. Set the overlay (on a 5 second timer to allow for hiccups reading textfiles)
10. Attempt to post a tweet ($quick_update command) – Note weibo as well though this is disabled for now
11. Use a bunch of variables to write to a textfile how many seconds the previous player was on, then set these variables again for the current player. This is used for statistics and include the players afreecaID, seconds on stream this session and the players race(gotten from a database using the $findrace command)
12. Set a timer checking for an error message text file using the $checksetplayererror command after 13 seconds
13. Update the TL streamlist using $tlsocket
14. Write the current players afreeca streamlink to a text file + post it in the channel using $setafreecatext

This might look complicated but it is really simple. Most of the aliases work similarly, writing and reading from text files. OBSProject lets me set overlays that read from textfiles, so when the $setafreecatext writes this afreeca link to a text file it updates onscreen immediately. The same goes for the playername. The twitter script is written by a guy named FordLawnmower and can be found here. The $checksetplayererror alias simply checks for an error text file that gets created by the setplayer AHK script when a certain error pops up on afreeca. The setplayer autohotkey script looks like this:

+ Show Spoiler +
Process, Close, iexplore.exe
IfWinExist, BroadCastEndding Window
{
ControlClick, x183 y233, BroadCastEndding Window, , left, 1
}
FileDelete, C:setplayererror.txt
FileReadLine, var1, C:setplayer.txt, 1
Var2 = [url=http://live.afreeca.com:8079/app/index.cgi?szBjId=%Var1%]http://live.afreeca.com:8079/app/index.cgi?szBjId=%Var1%[/url]
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := False
Pwb.Navigate(Var2)
Sleep, 4000
jsPlayer = javascript:playBroad('%Var1%','app_launch');
Pwb.Navigate(jsPlayer)
Sleep, 5000
if WinExist("ahk_class #32770")
{
FileAppend, %Var1%, C:setplayererror.txt
ControlClick, OK, ahk_class #32770
ControlClick, &No, ahk_class #32770
}
ComObjError(1)


As you can see it uses much of the same code as the other scripts.

1. Close any instances of internet explorer
2. If the afreeca “broadcast has ended” window is present, close it
3. Delete the errorfile
4. Read the setplayer.txt file and put the players ID into a variable
5. Create a second variable that has the players live stream URL
6. Create a hidden IE instance then navigate to this URL
7. Attempt to open up the stream in the standalone player using a javascript function in the browser bar
8. Wait 5 seconds, if an error comes up (stream not on, player already on stream or already loading), create a text file and close the error

When this script is run the player will load up on stream. If the players main room is full it will still load up – but it will have a ‘preview’ bar up top and close down after 1 minute. Luckily this preview overlay is a separate window that AHK can scan for. As you might recall in step 7. Of the !setplayer command a 60s timer checking for this preview window starts up. This is the AHK script that gets run, detectpreview.ahk:

+ Show Spoiler +
IfWinExist, afreeca preview
{
IfWinNotExist, afreeca list
{
Sleep, 200
Click 432, 14
return
}
FileAppend, %FoundX%, c:streaminpreview.txt
FileReadLine, var1, C:setplayer.txt, 1
ControlClick, x160 y50, afreeca list
Sleep, 3000
ControlSend, Internet Explorer_Server1, {BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, {BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlClick, x150 y50, afreeca list
Sleep, 3000
ControlSend, Internet Explorer_Server1, ^{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, %var1%{enter}, afreeca list
Sleep, 3000
ControlClick, x43 y486, afreeca list
Sleep, 3000
ControlClick, x43 y486, afreeca list
Sleep, 3000
Process, Close, iexplore.exe
Sleep, 10000
if WinExist("ahk_class #32770")
{
ControlClick, OK, ahk_class #32770
ControlClick, &No, ahk_class #32770
}
return
}
Else {
Return
}


It is rather complicated because the moment the main room is full it becomes impossible to load streams through javascript functions. The script has to use simulated physical clicks to redirect to an alternate room. Step by step:

1. Check for the preview screen, if it exists continue
2. If the broadcaster list (a window in the afreeca client that lets you search for and find streams) does not exist, open it
3. Create a text file so mIRC knows AHK has found a preview window
4. Grab the afreeca ID from setplayer.txt and put it in a variable
5. Click in the search bar of the afreeca broadcaster list
6. Send a lot of backspace commands to remove any text that may or may not be in this search bar
7. Do it again for good measure
8. Click this god damn search bar again just in case it bugged out
9. Send a ton of backspace commands again this time while holding shift
10. Write the afreeca ID found in setplayer.txt and click enter
11. Click in a space on the list that usually has a secondary room link
12. Click in that spot again because $@!&#*(^@!(*&^!(*&^#
13. Close any instances of IE in case it clicked the wrong spot
14. If an error message pops up (because it clicked twice), close this error message

As some of you may or may not know the mods have the option of running commercials using the !commercial command. As I was looking through the AHK command list I found a pretty cool function that I realized could be used to make even this task automated. After playing around with this function for a while I managed to get it working semi-decently. It’s still a bit buggy when it comes to certain players like HiyA and by.hero, but overall I think it’s working quite well. Every 3 seconds the snipe2 computer runs imagesearch.ahk, a function that scans a part of the screen for the broodwar quit button. The mIRC script function looks like this:

+ Show Spoiler +
runimagesearch {
if (($exists(c:isinmenu.txt)) && (%commercialtime != 1)) {
/remove c:isinmenu.txt
if (%commercial15limit == 1) {
/timer 1 5 /msg #snipealot2 .commercial 60
msg #snipealot2 Player detected in broodwar menu - Running 60s commercial in 5 seconds
}
else {
/timer 1 5 /msg #snipealot2 .commercial 60
msg #snipealot2 Player detected in broodwar menu - Running 60s commercial in 5 seconds
}
/timer 1 5 /set %commercialtime 1
set %commercialoverride 1
/timer 1 5 /unset %commercialoverride
/timerimagesearch off
/inc %autoadcounter
/timer 1 490 /unset %commercialtime
set %commercial15limit 1
/timercommerciallimit off
/timercommerciallimit 1 900 /unset %commercial15limit
/timerrestartimagesearch 1 495 /timerimagesearch 0 3 /runimagesearch
}
else if (%commercialtime == 1) {
/timerimagesearch off
/timerrestartimagesearch 1 480 /timerimagesearch 0 3 /runimagesearch
}
else {
/run c:imagesearch.ahk
}
}


While the function has a few redundancies it works well. It used to have a 15sec delay and only run 30s commercials unless the time since last break was >15mins, but some time mid-september I decided to make it have a 5sec delay and automatic 60s breaks. The code is still in place for the 15min limit in case I ever decide to change it back though. The script is self is really simple.
1. Check for the isinmenu.txt file, if found run an ad, else if a mod has manually ran an ad, go into non-detection mode for 8 minutes - if neither of these match run imagesearch.ahk:

+ Show Spoiler +
FileDelete c:isinmenu.txt
Sleep, 200
CoordMode, Pixel, Screen
ImageSearch, FoundX, FoundY, 11,716, 262, 814, *130 C:quit.png
Sleep, 200
If (FoundX > 0) {
FileAppend, %FoundX%, c:isinmenu.txt
return
}
Else {
Return
}


1. Delete the textfile if it exists for some reason
2. Change to screen-coordinates instead of program-coordinates (in case of resolution change or window position change)
3. Scan the area between x11,y716 and x262, y814 for an image looking like quit.png (a picture of the bw quit button) with a margin of 130
4. If the image is found, create the isinmenu.txt file

Except for !setplayer I’d say the most used mod command is !online. Although it might seem simple this was probably the one I spent the most time on as it was through this command that I learned how to make AHK issue javascript commands as well as mIRC tokens. The process is rather complex but I’ll try to explain it as best I can. First we must start with the first mIRC alias:

+ Show Spoiler +
on *:text:!online:#snipealot2 {
if (($read(c:allowedusers.txt, ns, $nick)) && (%onlinechecktimer != 1)) {
/online
msg $chan List is over 2 minutes old, refreshing... Please wait.
set %onlinechecktimer 1
/timer 1 120 /unset %onlinechecktimer
/timer 1 10 /postonline
}
else if ($read(allowedusers.txt, ns, $nick)) {
msg $chan Players online: %onlineplayers
}
}

online {
if (%onlinechecktimer != 1) {
unset %onlineplayers
/run C:checkforplayers.ahk
/timer 1 10 /onlinewhileloop
}
else {
msg $chan Players online: %onlineplayers
}
}


1. If the command has not been run within the past 2 minutes, reset the %onlineplayers token and run checkforplayers.ahk
2. Start a timer that runs $onlinewhileloop after 10 seconds
3. If it has been run within the past 2 minutes, simply print the last found online players to the chat

This might seem simple enough but the idea is that it is a 3-step process. The first being this script, the second the AHK side of things:

+ Show Spoiler +
Process, Close, iexplore.exe
FileDelete C:playerson.txt
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := False
Pwb.Navigate("http://gametv.afreeca.com/broad/index.html")
IELoad(Pwb) ;You need to send the IE handle to the function unless you define it as global.
{
If !Pwb ;If Pwb is not a valid pointer then quit
Return False
Loop ;Otherwise sleep for .1 seconds untill the page starts loading
Sleep,100
Until (Pwb.busy)
Loop ;Once it starts loading wait until completes
Sleep,100
Until (!Pwb.busy)
Loop ;optional check to wait for the page to completely load
Sleep,100
Until (Pwb.Document.Readystate = "Complete")
Return True
}
IELoad(Pwb)
Pwb.Navigate("javascript:ShowBroadListForCate('00040001')")
Sleep, 500
Pwb.Navigate("javascript:setListRow('100')")
Sleep, 1000
Links := Pwb.Document.Links
Loop % Links.Length ; check each link
{
PlayersOnString.=Links[A_Index-1].InnerText
PlayersOnString.=" "
}
ComObjError(1)
FileAppend,
(
%PlayersOnString%
), c:playerson.txt
Return


1. Close IE, delete playerson.txt
2. Open a hidden IE window and navigate to the gametv afreeca page – this page has all the online streamers
3. Wait until the page has completely loaded
4. Using javascript, set the ShowBroadListForCate to starcraft:broodwar (스타 or 00040001)
5. Using javascript, set the number of streams to 100
6. Scan all the links in the page and put them into an array
7. Create a String and put the text from every single link into this string
8. Write this string to playerson.txt

This usually takes a few seconds to complete, but as the page can be slow loading the script has a 10 second window to do all this. After 10 seconds the following mIRC script $onlinewhileloop gets executed:

+ Show Spoiler +
onlinewhileloop {
set %x 1
while (%x <= $filelines) {
findplayer $idfromline(%x)
inc %x
}
}

postonline /msg #snipealot2 Players online: %onlineplayers
filelines return $lines(c:playerdatabase3.txt)
idfromline return $read(c:playerdatabase2.txt, n, $1)


Overall it’s a pretty complicated series of functions but in short the entire thing that happens when the !online command is issued can be explained as follows:
1. Open the afreeca gametv webpage, gather all afreeca IDs on a page that has the top 100 currently online scbw broadcasters and put these IDs into a textfile
2. Scan this textfile and compare afreeca IDs to a database of known players, if found put these players in a token(mirc script kind of array)
3. Write said token in the channel when done using the postonline command

A couple of days after Bisu started streaming late September I was contacted by TL. They were looking into a way for the TL streamlist to automatically update with the current player online. After some deliberation we came to the conclusion that the best way to do this was to write a script similar to the twitter one – basically send a POST to the TL website using mSL $sockwrite. This is what we came up with:

+ Show Spoiler +
on *:SOCKOPEN:tlnet:{
; Set the variables we want to send:
var %string title= $+ %currentplayername $+ &race= $+ %playerrace

; Send POST and Host
sockwrite -n $sockname POST /api/streams/update/xxxxxxx.json HTTP/1.1
sockwrite -n $sockname Host: wvvw.teamliquid.net

; Send the extra content headers
sockwrite -n $sockname Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sockwrite -n $sockname Content-Length: $len(%string)
sockwrite -n $sockname Content-Type: application/x-wvvw-form-urlencoded

; We are done, remember we have to send the %string last

sockwrite $sockname $crlf
sockwrite $sockname %string
}


This is what triggers when the $tlsocket alias is run at the end of commands like setplayer.

+ Show Spoiler +
tlsocket sockopen tlnet wvvw.teamliquid.net 80 


The final and rather crucial part of the snipealot2 system is the autovote script. Every 30 seconds an autohotkey script is run scanning for the afreeca “broadcast ended” window. If found the window will close and a 2 minute countdown will begin towards an autovote. 10 Seconds before the autovote begins the $online command is used to refresh the online players list from afreeca, then use the top 4 online players (according to the database) in the vote. An alias called $rollingtext is used during the voting in order to live-update the current vote on the screen. This is the same command that triggers when mods use !notify.

+ Show Spoiler +
rollingtext write -c c:streamrollinginfo.txt $1-

checkdisconnect {
if ($exists(c:streamdisconnected.txt)) {
/remove c:streamdisconnected.txt
msg #snipealot2 Streamer has disconnected - an automatic vote will begin in 2 minutes
set %autovote.check 1
/timerautovote 1 110 /autovote
}
else {
/run c:detectdisconnect.ahk
}
}

autovote {
if (%autovote.check == 1) {
msg #snipealot2 Autovote start in 10 seconds
msg #snipealot2 Refreshing online list
/online
/timeravotestart 1 10 /startautovote
}
}


If no mod has set another player or overridden the vote after 2 minutes the $startautovote will trigger:

+ Show Spoiler +
 startautovote {
set %autovote on
set %onlineplayers $addtok(%onlineplayers, NONE1, 32)
set %onlineplayers $addtok(%onlineplayers, NONE2, 32)
set %onlineplayers $addtok(%onlineplayers, NONE3, 32)
set %onlineplayers $addtok(%onlineplayers, NONE4, 32)
set %autovoteid1 $gettok(%onlineplayers, 1, 32)
set %autovoteid2 $gettok(%onlineplayers, 2, 32)
set %autovoteid3 $gettok(%onlineplayers, 3, 32)
set %autovoteid4 $gettok(%onlineplayers, 4, 32)
set %autovote1 0
set %autovote2 0
set %autovote3 0
set %autovote4 0
if (none isin %autovoteid1) /unset %autovoteid1
if (none isin %autovoteid2) /unset %autovoteid2
if (none isin %autovoteid3) /unset %autovoteid3
if (none isin %autovoteid4) /unset %autovoteid4
if (%autovoteid1 == $null) {
msg #snipealot2 No players found, delaying auto-vote for 10 minutes.
/timer 1 600 /autovote
}
else if (%autovoteid2 == $null) {
msg $snipealot Only one player found
/setplayer $scanforid(%autovoteid1)
run c:setplayer.ahk
setoverlay %autovoteid1
/quick_update %autovoteid1 is now live!
}
else {
msg #snipealot2 A vote has been automatically initiated
msg #snipealot2 The autovote will end in 60 seconds
msg #snipealot2 Choose one of the following players: %autovoteid1 %autovoteid2 %autovoteid3 %autovoteid4
/rollingtext AUTOVOTE IN PROGRESS - VOTE IN THE CHAT
/timerendautovote 1 60 /endautovote
/timerresetautovote 1 65 /resetautovote
}
}


This first alias needs to organize and set up the vote. This is done as follows:
1. Add 4 tokens to the %onlineplayers token. Why this is done will be clear in step4
2. Put the first 4 IDs in the %onlineplayers token into 4 distinct variables
3. Set 4 other variables as their total votes
4. If one of these 4 top variables that were set have ‘none’ In them, unset said variables. This is done so that it won’t run a vote for 4 players if only 2 are online
5. Check the first autovoteID if it has been unset, if this is the case either no players are online or the online players script bugged out. Either the afreeca page is lagging or no players are on – wait 10 minutes and try again.
6. Check the second autovoteID if it has been unset, if this is the case only 1 player is online. Put said player online without voting.
7. If the previous two steps returned as false, two or more players are online. Initiate vote and set timers to end and reset the vote after 1 minute.

Viewers will then vote for the players that are presented to them. This is done using the final text scan in the remote script:

+ Show Spoiler +
 on *:text:*:#snipealot2: {
if ((%voteid1 isin $1-) && ($nick !isin %voted)) {
inc %vote1
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid2 isin $1-) && ($nick !isin %voted)) {
inc %vote2
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid3 isin $1-) && ($nick !isin %voted)) {
inc %vote3
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid4 isin $1-) && ($nick !isin %voted)) {
inc %vote4
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%autovoteid1 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote1
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid2 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote2
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid3 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote3
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid4 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote4
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
else {
halt
}
}


As you might see this script is a bit of a clusterfuck. This is because it is a ‘catch-all’ for all the text in the snipealot chat. So far only the autovote and vote scripts use this but if I want to add the spambot banscript to the snipe2 system this is where I will put it in. If a vote is in progress it will scan the text for the players currently being voted for, then add a point to said player. A vote is only counted once. After 60 seconds are up the timer will initiate the $endautovote alias:

+ Show Spoiler +
 endautovote {
if ((%autovoteid4 == $null) && (%autovoteid3 == $null)) {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 )
}
elseif (%autovoteid4 == $null) {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 ), %autovoteid3 ( %autovote3 )
}
else {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 ), %autovoteid3 ( %autovote3 ), %autovoteid4 ( %vote4 )
}
set %autovotetoken $sorttok(%autovote1 %autovote2 %autovote3 %autovote4, 32, nr)
set %autovotewinner $gettok(%autovotetoken, 1, 32)
if (%autovotewinner == %autovote1) {
setplayer $scanforid(%autovoteid1)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid1
setoverlay %autovoteid1
set %currentplayer $scanforid(%autovoteid1)
set %currentplayername %autovoteid1
/quick_update %autovoteid1 is now live!
}
else if (%autovotewinner == %autovote2) {
setplayer $scanforid(%autovoteid2)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid2
setoverlay %autovoteid2
set %currentplayer $scanforid(%autovoteid2)
set %currentplayername %autovoteid2
/quick_update %autovoteid2 is now live!
}
else if (%autovotewinner == %autovote3) {
setplayer $scanforid(%autovoteid3)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid3
setoverlay %autovoteid3
set %currentplayer $scanforid(%autovoteid3)
set %currentplayername %autovoteid3
/quick_update %autovoteid3 is now live!
}
else if (%autovotewinner == %autovote4) {
setplayer $scanforid(%autovoteid4)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid4
setoverlay %autovoteid4
set %currentplayer $scanforid(%autovoteid4)
set %currentplayername %autovoteid4
/quick_update %autovoteid4 is now live!
}
else {
msg #snipealot2 Error - This shouldn't happen, notify snipealot
}
set %playerrace $findrace(%currentplayer)
/tlsocket
/resetautovote
/setafreecatext
}


This final script tallies the votes and puts on the winner. If there are two winners it will simply put the one listed higher in the database. When a winner is put on it will then post to twitter using the $quick_update command, then send an update to TL using $tlsocket. Finishing up it resets all variables using the $resetautovote alias.

I’m not sure how interesting you all find this but I hope that this can be a resource for someone who wishes to attempt something similar. This has been an amazing learning experience for me as I’ve never really studied programming. In spite of the fact that mSL and AHK are both rather crude scripting languages – I’d hardly call them programming languages – it works really well. Even the scripts that run within vmware on the snipe0/snipe1 work without much trouble at all.

In closing I’d like to say that setting up and programming everything over the past 2 months has been incredibly fun and fulfilling. I still have a long to-do list of things I’d like to implement, but alas I don’t think I’ll be able to do this before I leave. Hopefully I’ll be able to iron out any flaws in the existing system and make it perfectly stable before Christmas. If I can also manage to find a 1 year hosting place I might even be able to keep the stream running smoothly until I’m back here in Korea again.

-snipealot

****
vlaric
Profile Blog Joined July 2007
United States412 Posts
October 14 2013 13:30 GMT
#2
thanks for the stream! i've been watching it every day.
Wannabe zerg player
Epoxide
Profile Blog Joined March 2011
Magic Woods9326 Posts
October 14 2013 13:33 GMT
#3
LiquipediaSouma: EU MM is just Russian Roulette. Literally.
DarkPlasmaBall
Profile Blog Joined March 2010
United States44125 Posts
October 14 2013 13:34 GMT
#4
Congratulations on the milestone and thank you for the streams! They've been great
"There is nothing more satisfying than looking at a crowd of people and helping them get what I love." ~Day[9] Daily #100
BombiZombie
Profile Joined August 2013
Russian Federation27 Posts
October 14 2013 13:37 GMT
#5
[image loading]
Starcraft:Broodwar forever!
TylerThaCreator
Profile Blog Joined May 2011
United States906 Posts
October 14 2013 13:38 GMT
#6
wow, i very eagerly just read every single bit of this blog. althoug you claim your code is sloppy, its very logical and easy to follow. youre also able to explain every little bit of what you do, which is really cool. how do you have the time to do all this and write your thesis!!
aka SethN
Archas
Profile Blog Joined July 2010
United States6531 Posts
October 14 2013 13:40 GMT
#7
The room is ripe with the stench of bitches!
itsjustatank
Profile Blog Joined November 2010
Hong Kong9152 Posts
October 14 2013 14:19 GMT
#8
[image loading]
Photographer"nosotros estamos backamos" - setsuko
BLinD-RawR
Profile Blog Joined April 2010
ALLEYCAT BLUES50107 Posts
October 14 2013 14:32 GMT
#9


cheers!
Brood War EICWoo Jung Ho, never forget.| Twitter: @BLinDRawR
TL+ Member
Stratos
Profile Blog Joined July 2010
Czech Republic6104 Posts
October 14 2013 14:43 GMT
#10
the power of snipealot
En Taro Violet
GrazerRinge
Profile Blog Joined May 2010
999 Posts
October 14 2013 15:03 GMT
#11
"Successful people don't talk much. They listen and take action."
Ghin
Profile Blog Joined January 2005
United States2391 Posts
October 14 2013 15:17 GMT
#12
thanks for making it happen

the power of starcraft
Legalize drugs and murder.
ffswowsucks
Profile Blog Joined August 2005
Greece2294 Posts
October 14 2013 15:40 GMT
#13
Terran in particular is a notoriously strong race for a no brain skillhand bot style.
bGr.MetHiX
Profile Joined February 2011
Bulgaria511 Posts
October 14 2013 17:14 GMT
#14
snipealot , you are my hero.
Top50 GM EU Protoss from Bulgaria. Streaming with commentary : www.twitch.tv/hwbgmethix
FuDDx *
Profile Blog Joined October 2002
United States5008 Posts
October 14 2013 17:23 GMT
#15
snipealot <3 I wish I had the time to watch as much as I used too but I still love being able to watch and with 3 streams its just better and better!! Thank you!!
https://www.facebook.com/pages/Balloon-Man-FuDD/237447769616965?ref=hl
ne4aJIb
Profile Blog Joined July 2011
Russian Federation3209 Posts
October 14 2013 17:26 GMT
#16
streamalot
Bisu,Best,Stork,Jangbi and Flash, Fantasy, Leta, Light and Jaedong, Hydra, Zero, Soulkey assemble in ACE now!
endy
Profile Blog Joined May 2009
Switzerland8970 Posts
October 14 2013 17:55 GMT
#17
Thank you so much
ॐ
Ettick
Profile Blog Joined June 2011
United States2434 Posts
October 14 2013 18:07 GMT
#18
Thanks for making this stream, it's pretty much the only stream I watch at the moment.
Torenhire
Profile Blog Joined April 2009
United States11681 Posts
October 14 2013 18:11 GMT
#19
best stream on TL <3

Grats on the milestone
SirJolt: Well maybe if you weren't so big and stupid, it wouldn't have hit you.
Louuster
Profile Joined November 2010
Canada2869 Posts
October 14 2013 18:27 GMT
#20
Hi, my name is commander Shepard and this is my favorite stream on TL.

As a long time BW fan, being able to see daily FPV gameplay of players like Bisu and Mind is a dream come true
Kim Taek Yong fighting~
r.Evo
Profile Joined August 2006
Germany14080 Posts
October 14 2013 18:37 GMT
#21
You're such a hero.
"We don't make mistakes here, we call it happy little accidents." ~Bob Ross
Leeoku
Profile Joined May 2010
1617 Posts
October 14 2013 18:43 GMT
#22
I hate programming so much. But it's stuff like this that brings wonderful things. My reinterest in bw + your stream has definetly made it much faster. Thank you so much
Kittan
Profile Joined April 2012
Poland3999 Posts
October 14 2013 19:53 GMT
#23


The only thing I understood from this blog is that you are indeed a wizard, dark disciple of Rich, Priest of the BW Streaming Gods and are worthy of every goat I sacrificed to our Lords.
http://www.teamliquid.net/forum/viewmessage.php?topic_id=81288 <--- How I fell in love with a man, a team, a game and a website in a single day... | "There are no false gods, there is only the Emperor, and Choi Yun Sung is his prophet." -> Zona 40k
StarStruck
Profile Blog Joined April 2010
25339 Posts
October 14 2013 20:04 GMT
#24
On October 15 2013 03:11 Torenhire wrote:
best stream on TL <3

Grats on the milestone


I endorse this message.
sabas123
Profile Blog Joined December 2010
Netherlands3122 Posts
October 14 2013 20:24 GMT
#25
congrats
The harder it becomes, the more you should focus on the basics.
Birdie
Profile Blog Joined August 2007
New Zealand4438 Posts
October 14 2013 21:38 GMT
#26
Congrats on 4million, here's to 5million!
Red classic | A butterfly dreamed he was Zhuangzi | 4.5k, heading to 5k as support!
chaosTheory_14cc
Profile Blog Joined December 2010
Canada1270 Posts
October 14 2013 21:55 GMT
#27
You rock snipealot <3

thanks so much
BisuDagger
Profile Blog Joined October 2009
Bisutopia19224 Posts
October 14 2013 23:45 GMT
#28
As a programmer I really enjoyed reading through that code. Awesome post! I hope Bisu gets you to 5 million very quickly.
ModeratorFormer Afreeca Starleague Caster: http://afreeca.tv/ASL2ENG2
Shinrei
Profile Joined February 2007
United States236 Posts
October 15 2013 01:31 GMT
#29
One of the greatest heros the brood war community has ever known.
=^.^=
thezanursic
Profile Blog Joined July 2011
5478 Posts
October 15 2013 12:08 GMT
#30
Don't stop being awesome!
http://i45.tinypic.com/9j2cdc.jpg Let it be so!
s_k_911
Profile Joined August 2008
China358 Posts
January 06 2014 01:27 GMT
#31
Too difficult for me to understand it.
apm200 terran play for fun
Normal
Please log in or register to reply.
Live Events Refresh
Next event in 3h 38m
[ Submit Event ]
Live Streams
Refresh
StarCraft: Brood War
Britney 21100
Mong 276
Snow 272
JulyZerg 59
Shine 53
Noble 35
GoRush 20
ajuk12(nOOB) 19
Movie 14
Dota 2
NeuroSwarm158
Counter-Strike
Stewie2K1407
Other Games
summit1g6526
C9.Mang01034
WinterStarcraft620
JimRising 266
Mew2King139
Trikslyr29
Organizations
Dota 2
PGL Dota 2 - Secondary Stream5637
Other Games
gamesdonequick955
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 17 non-featured ]
StarCraft 2
• Berry_CruncH280
• OhrlRock 3
• AfreecaTV YouTube
• intothetv
• sooper7s
• Kozan
• IndyKCrew
• LaughNgamezSOOP
• Migwel
StarCraft: Brood War
• Azhi_Dahaki22
• ZZZeroYoutube
• STPLYoutube
• BSLYoutube
Dota 2
• lizZardDota295
League of Legends
• Rush1811
• Stunt954
• HappyZerGling122
Upcoming Events
RSL Revival
3h 38m
Cure vs Percival
ByuN vs Spirit
WardiTV Qualifier
9h 38m
PiGosaur Monday
17h 38m
RSL Revival
1d 3h
herO vs sOs
Zoun vs Clem
Replay Cast
1d 17h
The PondCast
2 days
RSL Revival
2 days
Harstem vs SHIN
Solar vs Cham
Replay Cast
2 days
RSL Revival
3 days
Reynor vs Scarlett
ShoWTimE vs Classic
uThermal 2v2 Circuit
3 days
[ Show More ]
SC Evo League
4 days
Circuito Brasileiro de…
4 days
Sparkling Tuna Cup
5 days
Liquipedia Results

Completed

Acropolis #3 - GSC
2025 GSL S2
Heroes 10 EU

Ongoing

JPL Season 2
BSL 2v2 Season 3
BSL Season 20
Acropolis #3
KCM Race Survival 2025 Season 2
NPSL S3
Rose Open S1
CSL 17: 2025 SUMMER
Copa Latinoamericana 4
RSL Revival: Season 1
Murky Cup #2
BLAST.tv Austin Major 2025
ESL Impact League Season 7
IEM Dallas 2025
PGL Astana 2025
Asian Champions League '25
BLAST Rivals Spring 2025
MESA Nomadic Masters
CCT Season 2 Global Finals
IEM Melbourne 2025
YaLLa Compass Qatar 2025
PGL Bucharest 2025

Upcoming

CSLPRO Last Chance 2025
CSLPRO Chat StarLAN 3
K-Championship
SEL Season 2 Championship
Esports World Cup 2025
HSC XXVII
Championship of Russia 2025
BLAST Open Fall 2025
Esports World Cup 2025
BLAST Bounty Fall 2025
BLAST Bounty Fall Qual
IEM Cologne 2025
FISSURE Playground #1
TLPD

1. ByuN
2. TY
3. Dark
4. Solar
5. Stats
6. Nerchio
7. sOs
8. soO
9. INnoVation
10. Elazer
1. Rain
2. Flash
3. EffOrt
4. Last
5. Bisu
6. Soulkey
7. Mini
8. Sharp
Sidebar Settings...

Advertising | Privacy Policy | Terms Of Use | Contact Us

Original banner artwork: Jim Warren
The contents of this webpage are copyright © 2025 TLnet. All Rights Reserved.