2015-01-21 19:24:18 +00:00
#!/usr/bin/python
# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python
# Import some necessary libraries.
import socket
import os
import sys
2015-06-22 13:01:16 -05:00
import time
2015-01-21 19:24:18 +00:00
from optparse import OptionParser
import fileinput
import random
import formatter
import get_users
2018-02-28 21:08:22 +00:00
import names
2015-01-21 19:24:18 +00:00
import mentions
import pretty_date
import inflect
2015-02-12 21:15:16 +00:00
import puzzle
2015-01-21 19:24:18 +00:00
parser = OptionParser ()
parser . add_option ( "-s" , "--server" , dest = "server" , default = '127.0.0.1' ,
help = "the server to connect to" , metavar = "SERVER" )
parser . add_option ( "-c" , "--channel" , dest = "channel" , default = '#bot_test' ,
help = "the channel to join" , metavar = "CHANNEL" )
parser . add_option ( "-n" , "--nick" , dest = "nick" , default = 'tildebot' ,
help = "the nick to use" , metavar = "NICK" )
( options , args ) = parser . parse_args ()
p = inflect . engine ()
2015-02-12 21:15:16 +00:00
challenges = {}
2015-02-02 19:47:47 +00:00
SCORE_FILE = "tildescores.txt"
JACKPOT_FILE = "tildejackpot.txt"
JACKPOT_MIN = 3
DEBUG = False
2015-01-21 19:24:18 +00:00
def ping ():
ircsock . send ( "PONG :pingis \n " )
def sendmsg ( chan , msg ):
ircsock . send ( "PRIVMSG " + chan + " :" + msg + " \n " )
def joinchan ( chan ):
ircsock . send ( "JOIN " + chan + " \n " )
def hello ():
ircsock . send ( "PRIVMSG " + channel + " :Hello! \n " )
def too_recent ( time1 , time2 ):
if ( int ( time1 ) - int ( time2 ) < 60 * 60 ):
return True
else :
return False
2017-03-30 21:39:44 +00:00
def get_positive ():
2017-08-04 12:06:58 +00:00
return random . choice ([ 'Yes' , 'Yep' , 'Yeppers' , 'Correct' , 'You got it' , 'Yeah' , 'Right on' , 'Uh-huh' , 'Positive' , 'Totally right' , 'Close enough' , 'That \' s it' ])
2017-03-30 21:39:44 +00:00
def get_negative ():
2017-08-04 12:06:58 +00:00
return random . choice ([ 'No' , 'Nope' , 'Sorry' , 'Wrong' , 'Nuh-uh' , 'Negatory' , 'Incorrect' , 'Not today' , 'Try again' , 'Maybe later' , 'Probably not' , 'Answer hazy' , 'Not quite' , \
'Not even close' ])
2017-03-30 21:39:44 +00:00
def get_superlative ( score ):
if score > 4 :
return random . choice ([ "super cool" , "totally rad" , "extraordinary" , "dynomite" , "#topdrawer" , "a #TopLad" , "the cat's meow" , "a tilde town hero" , "my favorite person" , "incredibly lucky" , \
2017-08-04 12:06:58 +00:00
"unbelievable" , "a tilde town hunk" , "could bring all the boys to the yard" , "worth twice their weight in gold" , "the hero we need" , "no ordinary townie" ]);
2017-03-30 21:39:44 +00:00
elif score > 2 :
return random . choice ([ "really cool" , "pretty neat" , "rather nice" , "a dynamic doggo" , "radical" , "intense" , "pretty lucky" , "knows the territory" , "has what it takes" , "has mad skillz" , \
2017-08-04 12:06:58 +00:00
"going the distance" , "a hard worker" , "my sunshine" , "ready to rumble" ]);
2017-03-30 21:39:44 +00:00
else :
2017-08-04 12:06:58 +00:00
return random . choice ([ "cool" , "nice" , "acceptible" , "good enough" , "a promising pupper" , "better than a horse" , "swell" , "a little lucky" , "just credible" , "my friend" , "probably not a robot" , \
"valuable to the team" ]);
2017-03-30 21:39:44 +00:00
def get_bad_thing ():
return random . choice ([ "is a meanie" , "mugs me right off" , "is worse than a horse" , "smells like a ghost" , "probably didn't bathe today" , "didn't guess hard enough" , "isn't lucky" , \
"smells of elderberries" , "should reconsider their life choices" , "did't believe in the heart of the tilde" , "came to the wrong chat channel" , "should have stopped while they were ahead" , \
2017-08-04 12:06:58 +00:00
"requires annotations from an authoratative source" , "could have been a contender" , "spreads vicious rumors" , "drank my milkshake" , "is probably cheating" , "is trying too hard" ]);
2017-03-30 21:39:44 +00:00
2018-02-28 21:08:22 +00:00
def get_prize ( name , isHuman , bonus = 0 ):
2016-09-07 15:58:36 +00:00
prizes = [ 1 ] * 8 + [ 2 ] * 4 + [ 3 ] * 2 + [ 5 ] * isHuman #no 5pt prize for non-humans
prize = random . choice ( prizes ) + bonus
2015-02-12 21:15:16 +00:00
if ( random . randint ( 1 , 10 ) > 6 - 4 * isHuman ): #80% of the time it's a normal prize (40% for not humans)
2018-02-28 21:08:22 +00:00
return [ prize , name + ": " + ( get_positive () if isHuman else get_negative ()) + "! You are " + get_superlative ( prize ) + " and get " + p . number_to_words ( prize ) + " tildes!" ]
2015-02-02 19:47:47 +00:00
else : #20% of the time its a jackpot situation
with open ( JACKPOT_FILE , "r+" ) as jackpotfile :
jackpot = int ( jackpotfile . readline () . strip ( " \n " ))
jackpotfile . seek ( 0 )
jackpotfile . truncate ()
2015-02-12 21:15:16 +00:00
if ( random . randint ( 1 , 10 ) > 1 or not isHuman ): #90% of the time it's a non-prize. non-humans never win jackpot
2016-09-07 15:58:36 +00:00
new_jackpot = jackpot + max ( 1 , prize )
jackpotfile . write ( str ( new_jackpot )) #increase the jackpot by the prize size
2018-02-28 21:08:22 +00:00
return [ 0 , name + " " + get_bad_thing () + " and gets no tildes! (Jackpot is now " + str ( new_jackpot ) + " tildes)" ]
2015-02-02 19:47:47 +00:00
else : #hit jackpot!
jackpotfile . write ( str ( JACKPOT_MIN ))
2018-02-28 21:08:22 +00:00
return [ jackpot , name + " hit the jackpot and won **" + p . number_to_words ( jackpot ) + " tildes!**" ]
2015-02-02 19:47:47 +00:00
def show_jackpot ( channel ):
with open ( JACKPOT_FILE , "r" ) as jackpotfile :
2015-02-06 19:35:22 +00:00
jackpot = int ( jackpotfile . readline () . strip ( " \n " ))
2015-02-02 19:47:47 +00:00
ircsock . send ( "PRiVMSG " + channel + " :The jackpot is currently " + p . number_to_words ( jackpot ) + " tildes! \n " )
2015-01-21 19:24:18 +00:00
2018-02-28 21:08:22 +00:00
def give_tilde ( channel , user , name , time , human , bonus = 0 ):
2015-01-21 19:24:18 +00:00
found = False
2015-02-02 19:47:47 +00:00
with open ( SCORE_FILE , "r+" ) as scorefile :
2015-01-21 19:24:18 +00:00
scores = scorefile . readlines ()
scorefile . seek ( 0 )
scorefile . truncate ()
for score in scores :
person = score . strip ( " \n " ) . split ( "&^%" )
if ( person [ 0 ] == user ):
found = True
2015-02-02 19:47:47 +00:00
if ( too_recent ( time , person [ 2 ]) and not DEBUG ):
2018-02-28 21:08:22 +00:00
ircsock . send ( "PRIVMSG " + channel + " :" + name + " asked for a tilde too recently and " + get_bad_thing () + ". Try again later. \n " )
2015-01-21 19:24:18 +00:00
else :
2018-02-28 21:08:22 +00:00
prize = get_prize ( name , human , bonus )
2015-01-21 19:24:18 +00:00
score = person [ 0 ] + "&^%" + str ( int ( person [ 1 ]) + prize [ 0 ]) + "&^%" + time + " \n "
ircsock . send ( "PRIVMSG " + channel + " :" + prize [ 1 ] + " \n " )
scorefile . write ( score )
if ( not found ):
2018-02-28 21:08:22 +00:00
prize = get_prize ( name , True , bonus )
2015-01-21 19:24:18 +00:00
ircsock . send ( "PRIVMSG " + channel + " :Welcome to the tilde game! Here's " + p . number_to_words ( prize [ 0 ] + 1 ) + " free tilde(s) to start you off. \n " )
scorefile . write ( user + "&^%" + str ( prize [ 0 ] + 1 ) + "&^%" + time + " \n " )
2018-02-28 21:08:22 +00:00
def show_tildescore ( channel , user , name ):
2015-02-02 19:47:47 +00:00
with open ( SCORE_FILE , "r" ) as scorefile :
2015-01-21 19:24:18 +00:00
for idx , score in enumerate ( scorefile ):
person = score . strip ( " \n " ) . split ( "&^%" )
if ( person [ 0 ] == user ):
2018-02-28 21:08:22 +00:00
ircsock . send ( "PRIVMSG " + channel + " :" + name + " has " + p . number_to_words ( person [ 1 ]) + " tildes! \n " )
2015-01-21 19:24:18 +00:00
return
#person has not played yet
2018-02-28 21:08:22 +00:00
ircsock . send ( "PRIVMSG " + channel + " :" + name + " has no tildes yet! \n " )
2015-01-21 19:24:18 +00:00
2018-02-28 21:08:22 +00:00
def challenge ( channel , user , name , time ):
2015-02-12 21:15:16 +00:00
if ( channel != "#bots" and not DEBUG ):
2018-02-28 21:08:22 +00:00
ircsock . send ( "PRIVMSG " + channel + " :" + name + " is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.** \n " )
2015-02-12 21:15:16 +00:00
return
global challenges ;
challenge = puzzle . make_puzzle ();
challenges [ user ] = challenge [ 0 ]; #challenges[USER] = ANSWER
2018-02-28 21:08:22 +00:00
ircsock . send ( "PRIVMSG " + channel + " :" + name + ": " + challenge [ 1 ] + " \n " );
2015-02-12 21:15:16 +00:00
2018-02-28 21:08:22 +00:00
def challenge_response ( channel , user , name , time , msg ):
2015-02-12 21:15:16 +00:00
global challenges
print ( msg );
if ( challenges . has_key ( user )):
2016-03-10 11:54:42 -05:00
bonus = 1 if str ( challenges [ user ]) . find ( ',' ) != - 1 else 0 #give a bonus for prime factoring
2017-03-30 21:39:44 +00:00
if ( msg . lower () == str ( challenges [ user ]) . lower () or msg == p . number_to_words ( challenges [ user ])):
2018-02-28 21:08:22 +00:00
give_tilde ( channel , user , name , time , True , bonus );
2015-02-12 21:15:16 +00:00
else :
2018-02-28 21:08:22 +00:00
give_tilde ( channel , user , name , time , False , 0 );
2015-02-12 21:15:16 +00:00
del challenges [ user ]; #delete the user from challenges either way
2015-01-21 19:24:18 +00:00
def rollcall ( channel ):
ircsock . send ( "PRIVMSG " + channel + " :tildebot reporting! I respond to !tilde !tildescore \n " )
def connect ( server , channel , botnick ):
ircsock . connect (( server , 6667 ))
ircsock . send ( "USER " + botnick + " " + botnick + " " + botnick + " :krowbar \n " ) # user authentication
ircsock . send ( "NICK " + botnick + " \n " )
joinchan ( channel )
2015-02-12 21:15:16 +00:00
if ( not DEBUG ):
joinchan ( "#bots" )
2015-01-21 19:24:18 +00:00
def get_user_from_message ( msg ):
try :
i1 = msg . index ( ':' ) + 1
i2 = msg . index ( '!' )
return msg [ i1 : i2 ]
except ValueError :
return ""
def listen ():
while 1 :
ircmsg = ircsock . recv ( 2048 )
2016-02-05 13:32:53 -05:00
for msg in ircmsg . split ( ' \n ' ):
msg = msg . strip ( ' \n\r ' )
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
if msg . find ( "PING :" ) != - 1 :
ping ()
2015-01-21 19:24:18 +00:00
2016-02-05 13:34:19 -05:00
formatted = formatter . format_message ( msg )
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
if "" == formatted :
continue
2015-01-21 19:24:18 +00:00
# print formatted
2016-02-05 13:32:53 -05:00
split = formatted . split ( " \t " )
iTime = split [ 0 ]
user = split [ 1 ]
2018-02-28 21:08:22 +00:00
name = names . get_name ( user )
2016-02-05 13:32:53 -05:00
command = split [ 2 ]
channel = split [ 3 ]
messageText = split [ 4 ]
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
if msg . find ( ":!tildescore" ) != - 1 :
2018-02-28 21:08:22 +00:00
show_tildescore ( channel , user , name )
2016-02-05 13:32:53 -05:00
elif msg . find ( ":!tilde" ) != - 1 and not challenges . has_key ( user ):
2018-02-28 21:08:22 +00:00
challenge ( channel , user , name , iTime )
2018-07-16 21:43:26 +01:00
elif challenges . has_key ( user ) and ( channel == "#bots" or DEBUG ):
2018-02-28 21:08:22 +00:00
challenge_response ( channel , user , name , iTime , messageText )
#give_tilde(channel, user, name, iTime)
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
if msg . find ( ":!jackpot" ) != - 1 :
2015-02-02 19:47:47 +00:00
show_jackpot ( channel )
2016-02-05 13:32:53 -05:00
if msg . find ( ":!rollcall" ) != - 1 :
rollcall ( channel )
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
if msg . find ( "PING :" ) != - 1 :
ping ()
2015-01-21 19:24:18 +00:00
2016-02-05 13:32:53 -05:00
sys . stdout . flush ()
time . sleep ( 1 )
2015-01-21 19:24:18 +00:00
ircsock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
connect ( options . server , options . channel , options . nick )
listen ()