cancer- 🚬 bad habits 🍺 for internet relay chat |
git clone git://git.acid.vegas/cancer.git |
Log | Files | Refs | Archive | README | LICENSE |
cancer.py (19530B)
1 #!/usr/bin/env python 2 # Cancer IRC Bot - Developed by acidvegas in Python (https://git.acid.vegas/cancer) 3 4 ''' 5 WARNING: This bot highly encourages flooding! 6 7 Commands: 8 @cancer | Information about the bot 9 @cancer stats | Return bot statistics for the channel 10 !100 | 1 in 100 chance to get a 100 (big !smoke) 11 !beer [nick] | Grab a beer or toss one to someone 12 !chainsmoke | Start a game of Chain Smoke 13 !chug | Sip beer 14 !dragrace | Start a game of Drag Race 15 !extendo | 1 in 100 chance to get an EXTENDO (big !toke) 16 !fatfuck | 1 in 100 chance to get a FATFUCK (fat !smoke/!toke) 17 !letschug | LET'S FUCKING CHUG! 18 !letstoke | LET'S FUCKING TOKE! 19 !toke | Hit joint 20 !smoke | Hit cigarette 21 !nosmoking | Disable the bot for 30 seconds 22 ''' 23 24 import asyncio 25 import json 26 import os 27 import random 28 import ssl 29 import time 30 31 # Connection 32 server = 'irc.supernets.org' 33 port = 6697 34 use_ipv6 = False 35 use_ssl = True 36 vhost = None 37 channel = '#dev' 38 key = None 39 40 # Identity 41 nickname = '[DEV]CANCER' 42 username = 'smokesome' 43 realname = 'git.acid.vegas/cancer' 44 45 # Login 46 nickserv_password = None 47 network_password = None 48 operator_password = None 49 50 # Settings 51 user_modes = 'BdDg' # +d requires additional ! and @ to be in your set::channel-command-prefix on UnrealIRCd 52 53 # Formatting Control Characters / Color Codes 54 bold = '\x02' 55 italic = '\x1D' 56 underline = '\x1F' 57 reverse = '\x16' 58 reset = '\x0f' 59 white = '00' 60 black = '01' 61 blue = '02' 62 green = '03' 63 red = '04' 64 brown = '05' 65 purple = '06' 66 orange = '07' 67 yellow = '08' 68 light_green = '09' 69 cyan = '10' 70 light_cyan = '11' 71 light_blue = '12' 72 pink = '13' 73 grey = '14' 74 light_grey = '15' 75 76 def color(msg, foreground, background=None): 77 return f'\x03{foreground},{background}{msg}{reset}' if background else f'\x03{foreground}{msg}{reset}' 78 79 def debug(data): 80 print('{0} | [~] - {1}'.format(time.strftime('%I:%M:%S'), data)) 81 82 def error(data, reason=None): 83 print('{0} | [!] - {1} ({2})'.format(time.strftime('%I:%M:%S'), data, str(reason))) if reason else print('{0} | [!] - {1}'.format(time.strftime('%I:%M:%S'), data)) 84 85 def luck(odds): 86 return True if random.randint(1,odds) == 1 else False 87 88 def ssl_ctx(): 89 ctx = ssl.create_default_context() 90 ctx.check_hostname = False 91 ctx.verify_mode = ssl.CERT_NONE 92 return ctx 93 94 class Generate: # degenerate * 95 async def can(chan, target): 96 beer_choice = random.choice(['bud','modelo','ultra']) 97 beer_temp = random.choice(['a piss warm','an ice cold','an empty']) 98 if beer_choice == 'bud': 99 beer = '{0}{1}{2}'.format(color(' ', white, white), color(' BUD ', white, random.choice((blue,brown))), color('c', grey, white)) 100 await Cancer.action(chan, f'throws {color(target, white)} {beer_temp} {beer} =)') 101 if luck(100): 102 await asyncio.sleep(2) 103 await Cancer.action(chan, 'suddenly feels more gay...') 104 elif beer_choice == 'modelo': 105 beer = '{0}{1}{2}'.format(color(' ', orange, orange), color('Modelo', blue, yellow), color('c', grey, orange)) # props to opal 106 await Cancer.action(chan, f'throws {color(target, white)} {beer_temp} {beer} =)') 107 elif beer_choice == 'modelo': 108 beer = '{0}{1}'.format(color(' ULTRA ', blue, white), color('🬃', red, white)) # warm 109 await Cancer.action(chan, f'throws {color(target, white)} {beer_temp} {beer} =)') 110 111 def beer(): 112 glass = color(' ', light_grey, light_grey) 113 return glass + color(''.join(random.choice((' :.')) for _ in range(9)), orange, yellow) + glass 114 115 def cigarette(size): 116 filter = color(';.`-,:.`;', yellow, orange)+color(' ', yellow, yellow) 117 cigarette = color('|'*size, light_grey, white) 118 cherry = color('\u259A', random.choice((red,yellow,orange)), black)+color('\u259A', random.choice((red,yellow,orange)), grey) 119 smoke = color('-' + ''.join(random.choice((';:-.,_`~\'')) for _ in range(random.randint(5,8))), grey) 120 return filter + cigarette + cherry + smoke 121 122 def joint(size): 123 joint = color('/'*size, light_grey, white) 124 cherry = color('\u259A', random.choice((red,yellow,orange)), black)+color('\u259A', random.choice((red,yellow,orange)), grey) 125 smoke = color('-' + ''.join(random.choice((';:-.,_`~\'')) for _ in range(random.randint(5,8))), grey) 126 return joint + cherry + smoke 127 128 def mug(size): 129 glass = color(' ', light_grey, light_grey) 130 empty = f'{glass} {glass}' 131 foam = glass + color(':::::::::', light_grey, white) + glass 132 bottom = color(' ', light_grey, light_grey) 133 mug = [foam,Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer()] 134 for i in range(8-size): 135 mug.pop() 136 mug.insert(0, empty) 137 for i in range(len(mug)): 138 if i == 2 or i == 7: 139 mug[i] += glass + glass 140 elif i > 2 and i < 7: 141 mug[i] += ' ' + glass 142 mug.append(bottom) 143 return mug 144 145 class Bot(): 146 def __init__(self): 147 self.fat = False 148 self.event = None 149 self.nicks = list() 150 self.stats = {'hits':25,'sips':8,'chugged':0,'smoked':0,'toked':0,'chain':0,'drag':0} 151 self.loops = {'chainsmoke':None,'dragrace':None,'letschug':None,'letstoke':None,'nosmoking':None,'timers':None} 152 self.status = True 153 self.reader = None 154 self.writer = None 155 156 async def raw(self, data): 157 self.writer.write(data[:510].encode('utf-8') + b'\r\n') 158 await self.writer.drain() 159 160 async def action(self, chan, msg): 161 await self.sendmsg(chan, f'\x01ACTION {msg}\x01') 162 163 async def sendmsg(self, target, msg): 164 await self.raw(f'PRIVMSG {target} :{msg}') 165 166 async def notice(self, target, msg): 167 await self.raw(f'NOTICE {target} :{msg}') 168 169 async def connect(self): 170 while True: 171 try: 172 options = { 173 'host' : server, 174 'port' : port, 175 'limit' : 1024, 176 'ssl' : ssl_ctx() if use_ssl else None, 177 'family' : 10 if use_ipv6 else 2, 178 'local_addr' : vhost 179 } 180 self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), 15) 181 await self.raw(f'USER {username} 0 * :{realname}') 182 await self.raw('NICK ' + nickname) 183 except Exception as ex: 184 error('error: failed to connect to ' + server, ex) 185 else: 186 if os.path.isfile('stats.json'): 187 with open('stats.json') as stats_file: 188 self.stats = json.loads(stats_file.read()) 189 debug('reloaded stats') 190 await self.listen() 191 for loop in self.loops: 192 if self.loops[loop]: 193 self.loops[loop].cancel() 194 self.stats['chain'] = 0 195 self.stats['drag'] = 0 196 self.event = None 197 self.nicks = list() 198 self.status = True 199 finally: 200 await asyncio.sleep(30) 201 202 async def loop_nosmoking(self): 203 await asyncio.sleep(30) 204 self.status = True 205 206 async def loop_timers(self): 207 while True: 208 try: 209 if time.strftime('%I:%M') == '04:20': 210 await self.sendmsg(channel, color('S M O K E W E E D E R R D A Y', light_green)) 211 await self.sendmsg(channel, color('ITZ DAT MUTHA FUCKN 420 BITCH', yellow)) 212 await self.sendmsg(channel, color('LIGHT UP A NICE GOOD FAT FUCK', red)) 213 await asyncio.sleep(120) 214 elif time.strftime('%I:%M %p') == '02:00 AM': 215 await self.sendmsg(channel, '.ascii phish') 216 await asyncio.sleep(120) 217 elif time.strftime('%I:%M') == '12:00': # the biscuit hour.. 218 with open('stats.json', 'w') as stats_file: 219 json.dump(self.stats, stats_file) 220 await asyncio.sleep(120) 221 except Exception as ex: 222 error('error: loop_timers failed', ex) 223 finally: 224 await asyncio.sleep(20) 225 226 async def loop_chainsmoke(self): 227 self.nicks = dict() 228 try: 229 await self.notice(channel, 'Starting a round of {0} in {1} seconds!'.format(color('ChainSmoke', red), color('10', white))) 230 await self.notice(channel, '[{0}] {1} {2} {3}'.format(color('How To Play', light_blue), color('Type', yellow), color('!smoke', light_green), color('to hit a cigarette. The cigarette goes down a little after each hit. Once you finish a cigarette, a new one will be lit for you. You will have 60 seconds to chain smoke as many cigarettes as possible.', yellow))) 231 await asyncio.sleep(10) 232 await self.action(channel, 'Round starts in 3...') 233 await asyncio.sleep(1) 234 await self.action(channel, '2...') 235 await asyncio.sleep(1) 236 await self.action(channel, '1...') 237 await asyncio.sleep(1) 238 await self.action(channel, color('GO', light_green)) 239 self.status = True 240 await asyncio.sleep(60) 241 self.status = False 242 await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow)) 243 await asyncio.sleep(1) 244 await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow)) 245 await asyncio.sleep(1) 246 await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow)) 247 await self.sendmsg(channel, color('Counting cigarette butts...', yellow)) 248 await asyncio.sleep(10) 249 await self.sendmsg(channel, '{0} smoked {1} cigarettes!'.format(channel, color(str(self.stats['chain']), light_blue))) 250 if self.nicks: 251 guy = max(self.nicks, key=self.nicks.get) 252 await self.sendmsg(channel, '{0} smoked the most cigarettes... {1}'.format(guy, self.nicks[guy])) 253 except Exception as ex: 254 error('error: loop_chainsmoke failed', ex) 255 finally: 256 self.stats['chain'] = 0 257 self.nicks = list() 258 self.event = None 259 self.status = True 260 261 async def loop_dragrace(self): 262 self.hits = 25 263 try: 264 await self.notice(channel, 'Starting a round of {0} in {1} seconds!'.format(color('DragRace', red), color('10', white))) 265 await self.notice(channel, '[{0}] {1} {2} {3}'.format(color('How To Play', light_blue), color('Type', yellow), color('!smoke', light_green), color('to hit a cigarette. The cigarette goes down a little after each hit. You will have 10 seconds to smoke as quickly as possible.', yellow))) 266 await asyncio.sleep(10) 267 await self.action(channel, 'Round starts in 3...') 268 await asyncio.sleep(1) 269 await self.action(channel, '2...') 270 await asyncio.sleep(1) 271 await self.action(channel, '1...') 272 await asyncio.sleep(1) 273 await self.action(channel, color('GO', light_green)) 274 self.stats['drag'] = time.time() 275 except Exception as ex: 276 error('error: loop_dragrace failed', ex) 277 finally: 278 self.status = True 279 280 async def loop_letschug(self, nick): 281 self.nicks.append(nick) 282 try: 283 await self.sendmsg(channel, color(f'OH SHIT {nick} is drunk', light_green)) 284 await self.notice(channel, color(f'Time to TOTALLY CHUG in {channel.upper()} in 30 seconds, type !chug to join', light_green)) 285 await asyncio.sleep(10) 286 await self.sendmsg(channel, color('LOL we CHUG in 20 get ready ' + ' '.join(self.nicks), light_green)) 287 await asyncio.sleep(10) 288 await self.sendmsg(channel, color('YO we CHUG in 10 get ready ' + ' '.join(self.nicks), light_green)) 289 await asyncio.sleep(5) 290 await self.sendmsg(channel, color('alright CHUG in 5', light_green)) 291 await asyncio.sleep(1) 292 await self.sendmsg(channel, color('4..', light_green)) 293 await asyncio.sleep(1) 294 await self.sendmsg(channel, color('3..', light_green)) 295 await asyncio.sleep(1) 296 await self.sendmsg(channel, color('2..', light_green)) 297 await asyncio.sleep(1) 298 await self.sendmsg(channel, color('1..', light_green)) 299 await asyncio.sleep(1) 300 await self.sendmsg(channel, color(' '.join(self.nicks) + ' .. CHUG!', light_green)) 301 except Exception as ex: 302 error('error: loop_letschug failed', ex) 303 finally: 304 self.event = None 305 self.nicks = list() 306 307 async def loop_letstoke(self, nick): 308 self.nicks.append(nick) 309 try: 310 await self.sendmsg(channel, color(f'YO {nick} is high', light_green)) 311 await self.notice(channel, color(f'Time to FUCKING toke in {channel.upper()}, type !toke to join', light_green)) 312 await asyncio.sleep(10) 313 await self.sendmsg(channel, color('OH SHIT we toke in 20 get ready ' + ' '.join(self.nicks), light_green)) 314 await asyncio.sleep(10) 315 await self.sendmsg(channel, color('OH SHIT we toke in 10 get ready ' + ' '.join(self.nicks), light_green)) 316 await asyncio.sleep(5) 317 await self.sendmsg(channel, color('alright toke in 5', light_green)) 318 await asyncio.sleep(1) 319 await self.sendmsg(channel, color('4..', light_green)) 320 await asyncio.sleep(1) 321 await self.sendmsg(channel, color('3..', light_green)) 322 await asyncio.sleep(1) 323 await self.sendmsg(channel, color('2..', light_green)) 324 await asyncio.sleep(1) 325 await self.sendmsg(channel, color('1..', light_green)) 326 await asyncio.sleep(1) 327 await self.sendmsg(channel, color(' '.join(self.nicks) + ' .. toke!', light_green)) 328 except Exception as ex: 329 error('error: loop_letstoke failed', ex) 330 finally: 331 self.event = None 332 self.nicks = list() 333 334 async def listen(self): 335 while True: 336 try: 337 if self.reader.at_eof(): 338 break 339 data = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), 500) 340 line = data.decode('utf-8').strip() 341 args = line.split() 342 debug(line) 343 if line.startswith('ERROR :Closing Link:'): 344 raise Exception('Connection has closed.') 345 elif args[0] == 'PING': 346 await self.raw('PONG '+args[1][1:]) 347 elif args[1] == '001': 348 if user_modes: 349 await self.raw(f'MODE {nickname} +{user_modes}') 350 if nickserv_password: 351 await self.sendmsg('NickServ', f'IDENTIFY {nickname} {nickserv_password}') 352 if operator_password: 353 await self.raw(f'OPER {username} {operator_password}') 354 await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel) 355 self.loops['timers'] = asyncio.create_task(self.loop_timers()) 356 elif args[1] == '433': 357 error('The bot is already running or nick is in use.') # nick change 358 elif args[1] == 'INVITE' and len(args) == 4: 359 invited = args[2] 360 chan = args[3][1:] 361 if invited == nickname and chan == channel: 362 await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel) 363 elif args[1] == 'KICK' and len(args) >= 4: 364 chan = args[2] 365 kicked = args[3] 366 if kicked == nickname and chan == channel: 367 await asyncio.sleep(3) 368 await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel) 369 elif args[1] == 'PART' and len(args) >= 3: 370 chan = args[2] 371 if chan == channel: 372 nick = args[0].split('!')[0][1:] 373 await self.action(nick, f'blows smoke in {nick}\'s face...') 374 elif args[1] == 'PRIVMSG' and len(args) >= 4: 375 nick = args[0].split('!')[0][1:] 376 chan = args[2] 377 msg = ' '.join(args[3:])[1:] 378 if chan == channel: 379 if self.status: 380 args = msg.split() 381 if msg == '@cancer': 382 await self.sendmsg(chan, bold + 'CANCER IRC Bot - Developed by acidvegas in Python - https://git.acid.vegas/cancer') 383 elif msg == '@cancer stats': 384 await self.sendmsg(chan, 'Chugged : {0} beers {1}'.format(color(self.stats['chugged'], light_blue), color('({0:,} cases)'.format(int(self.stats['chugged']/24)), grey))) 385 await self.sendmsg(chan, 'Smoked : {0} cigarettes {1}'.format(color(self.stats['smoked'], light_blue), color('({0:,} packs)'.format(int(self.stats['smoked']/24)), grey))) 386 await self.sendmsg(chan, 'Toked : {0} joints {1}'.format(color(self.stats['toked'], light_blue), color('({0:,} grams)'.format(int(self.stats['toked']/3)), grey))) 387 elif msg in ('!100','!extendo','!fatfuck') and luck(100): 388 if msg == '!fatfuck': 389 self.fat = True 390 await self.sendmsg(chan, '{0}{1}{2}'.format(color(' !!! ', red, green), color('AWWW SHIT, IT\'S TIME FOR THAT MARLBORO FATFUCK', black, green), color(' !!! ', red, green))) 391 else: 392 self.stats['hits'] = 100 393 if msg == '!100': 394 await self.sendmsg(chan, '{0}{1}{2}'.format(color(' !!! ', white, red), color('AWWW SHIT, IT\'S TIME FOR THAT NEWPORT 100', red, white), color(' !!! ', white, red))) 395 else: 396 await self.sendmsg(chan, '{0}{1}{2}'.format(color(' !!! ', red, green), color('OHHH FUCK, IT\'S TIME FOR THAT 420 EXTENDO', yellow, green), color(' !!! ', red, green))) 397 elif args[0] == '!beer': 398 if len(args) == 1: 399 target = nick 400 elif len(args) == 2: 401 target = args[1] 402 await Generate.can(chan, target) 403 elif msg == '!chainsmoke' and not self.event: 404 self.status = False 405 self.event = 'chainsmoke' 406 self.loops['chainsmoke'] = asyncio.create_task(self.loop_chainsmoke()) 407 elif msg == '!chug': 408 if self.event == 'letschug': 409 if nick in self.nicks: 410 await self.sendmsg(chan, color(nick + ' you are already chuggin u wastoid!', light_green)) 411 else: 412 self.nicks.append(nick) 413 await self.sendmsg(chan, color(nick + ' joined the CHUG session!', light_green)) 414 else: 415 if self.stats['sips'] <= 0: 416 self.stats['sips'] = 8 417 self.stats['chugged'] += 1 418 for line in Generate.mug(self.stats['sips']): 419 await self.sendmsg(chan, line) 420 self.stats['sips'] -= random.choice((1,2)) 421 elif msg == '!dragrace' and not self.event: 422 self.status = False 423 self.event = 'dragrace' 424 self.loops['dragrace'] = asyncio.create_task(self.loop_dragrace()) 425 elif msg == '!letschug' and not self.event: 426 self.event = 'letschug' 427 self.loops['letschug'] = asyncio.create_task(self.loop_letschug(nick)) 428 elif msg == '!letstoke' and not self.event: 429 self.event = 'letstoke' 430 self.loops['letstoke'] = asyncio.create_task(self.loop_letstoke(nick)) 431 elif msg == '!nosmoking': 432 self.status = False 433 self.loops['nosmoking'] = asyncio.create_task(self.loop_nosmoking()) 434 elif msg in ('!smoke','!toke'): 435 option = 'smoked' if msg == '!smoke' else 'toked' 436 if self.event == 'letstoke' and msg == '!toke': 437 if nick in self.nicks: 438 await self.sendmsg(chan, color(nick + ' you are already toking u stoner!', light_green)) 439 else: 440 self.nicks.append(nick) 441 await self.sendmsg(chan, color(nick + ' joined the TOKE session!', light_green)) 442 else: 443 if self.stats['hits'] <= 0: 444 self.stats['hits'] = 25 445 self.stats[option] += 1 446 if self.fat: 447 self.fat = False 448 if self.event == 'chainsmoke' and msg == '!smoke': 449 self.nicks[nick] = self.nicks[nick]+1 if nick in self.nicks else 1 450 self.stats['chain'] += 1 451 elif self.event == 'dragrace' and msg == '!smoke': 452 await self.sendmsg(chan, 'It took {0} seconds for {1} to smoke a cigarette!'.format(color('{:.2f}'.format(time.time()-self.stats['drag']), light_blue), color(chan, white))) 453 self.event = None 454 self.stats['drag'] = 0 455 elif luck(25) and msg == '!smoke': 456 await self.raw(f'KILL {nick} CANCER KILLED {nick.upper()} - QUIT SMOKING TODAY! +1 800-QUIT-NOW') 457 else: 458 object = Generate.cigarette(self.stats['hits']) if msg == '!smoke' else Generate.joint(self.stats['hits']) 459 if self.fat: 460 for i in range(3): 461 await self.sendmsg(chan, object) 462 else: 463 await self.sendmsg(chan, object) 464 self.stats['hits'] -= random.choice((1,2)) 465 except (UnicodeDecodeError, UnicodeEncodeError): 466 pass 467 except Exception as ex: 468 error(self.display + 'fatal error occured', ex) 469 break 470 471 # Main 472 Cancer = Bot() 473 asyncio.run(Cancer.connect())