diff --git a/.screens/preview.png b/.screens/preview.png
Binary files differ.
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2023, acidvegas <acid.vegas@acid.vegas>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
@@ -0,0 +1,49 @@
+# CANCER
+> bad habits for internet relay chat
+
+![](.screens/preview.png)
+
+## Information
+A fun bot that brings some bad habits on to IRC. Smoke cigarettes, smoke weed, and drink beer in your channels!
+
+Blow `!smoke` in the face of the opers, get bloody buck from !chug and vomit over the backlog.
+
+The bot includes colored ASCII art cigarettes, joints, and beers, that change everytime you drink or smoke.
+
+There is a various games and other fun things that generally promote user interactions in the channel.
+
+Try it out, join **#superbowl** on *irc.supernets.org* now, we have beer!
+
+**Warning:** This bot highly encourages *unthrottled* flooding! This may or may not be suited for your IRC network and/or channel(s).
+
+**Optional**: Network operator privledges can be given to the bot for a fun feature where if someone does `!smoke` and it is the last hit of a cigarette, they will have a 1 in 100 chance of being `/KILL`'d from the network, aka **KILLED BY CANCER**
+
+## Commands
+| Command | Description |
+| --------------- | ---------------------------------------------------------- |
+| `@cancer` | Information about the bot |
+| `@cancer stats` | Return bot statistics for the channel |
+| `!100` | 1 in 100 chance to get a 100 *(big `!smoke`)* |
+| `!beer [nick]` | Grab a beer or toss one to someone |
+| `!chainsmoke` | Start a game of Chain Smoke |
+| `!chug` | Sip beer |
+| `!dragrace` | Start a game of Drag Race |
+| `!extendo` | 1 in 100 chance to get an EXTENDO *(big `!toke`)* |
+| `!fatfuck` | 1 in 100 chance to get a FATFUCK *(fat `!smoke`/`!toke`)* |
+| `!letschug` | LET'S FUCKING CHUG! |
+| `!letstoke` | LET'S FUCKING TOKE! |
+| `!toke` | Hit joint |
+| `!smoke` | Hit cigarette |
+| `!nosmoking` | Disable the bot for 30 seconds |
+
+## Todo
+- Too drunk/Vomit features trigged from `!chug`
+- `!cigar` smoking and `!pizza` eating
+- ASCII art for cigarette packs, lighter, nosmoking, vomit
+- Fastest to respond w/ command timers for somthing.
+- Keep track of how many chugged, smoked, & toked per-nick for `!top` command.
+
+___
+
+###### Mirrors
+[acid.vegas](https://git.acid.vegas/cancer) • [GitHub](https://github.com/acidvegas/cancer) • [GitLab](https://gitlab.com/acidvegas/cancer) • [SourceHut](https://git.sr.ht/~acidvegas/cancer) • [SuperNETs](https://git.supernets.org/acidvegas/cancer)
diff --git a/cancer.py b/cancer.py
@@ -0,0 +1,461 @@
+#!/usr/bin/env python
+# Cancer IRC Bot - Developed by acidvegas in Python (https://git.acid.vegas/cancer)
+
+'''
+WARNING: This bot highly encourages flooding!
+
+Commands:
+ @cancer | Information about the bot
+ @cancer stats | Return bot statistics for the channel
+ !100 | 1 in 100 chance to get a 100 (big !smoke)
+ !beer [nick] | Grab a beer or toss one to someone
+ !chainsmoke | Start a game of Chain Smoke
+ !chug | Sip beer
+ !dragrace | Start a game of Drag Race
+ !extendo | 1 in 100 chance to get an EXTENDO (big !toke)
+ !fatfuck | 1 in 100 chance to get a FATFUCK (fat !smoke/!toke)
+ !letschug | LET'S FUCKING CHUG!
+ !letstoke | LET'S FUCKING TOKE!
+ !toke | Hit joint
+ !smoke | Hit cigarette
+ !nosmoking | Disable the bot for 30 seconds
+'''
+
+import asyncio
+import json
+import os
+import random
+import ssl
+import time
+
+# Connection
+server = 'irc.server.com'
+port = 6697
+use_ipv6 = False
+use_ssl = True
+vhost = None
+channel = '#chats'
+key = None
+
+# Identity
+nickname = 'CANCER'
+username = 'smokesome'
+realname = 'git.acid.vegas/cancer'
+
+# Login
+nickserv_password = None
+network_password = None
+operator_password = None
+
+# Settings
+user_modes = 'BdDg' # +d requires additional ! and @ to be in your set::channel-command-prefix on UnrealIRCd
+
+# Formatting Control Characters / Color Codes
+bold = '\x02'
+italic = '\x1D'
+underline = '\x1F'
+reverse = '\x16'
+reset = '\x0f'
+white = '00'
+black = '01'
+blue = '02'
+green = '03'
+red = '04'
+brown = '05'
+purple = '06'
+orange = '07'
+yellow = '08'
+light_green = '09'
+cyan = '10'
+light_cyan = '11'
+light_blue = '12'
+pink = '13'
+grey = '14'
+light_grey = '15'
+
+def color(msg, foreground, background=None):
+ return f'\x03{foreground},{background}{msg}{reset}' if background else f'\x03{foreground}{msg}{reset}'
+
+def debug(data):
+ print('{0} | [~] - {1}'.format(time.strftime('%I:%M:%S'), data))
+
+def error(data, reason=None):
+ 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))
+
+def luck(odds):
+ return True if random.randint(1,odds) == 1 else False
+
+def ssl_ctx():
+ ctx = ssl.create_default_context()
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+ return ctx
+
+class Generate: # degenerate *
+ def beer():
+ glass = color(' ', light_grey, light_grey)
+ return glass + color(''.join(random.choice((' :.')) for _ in range(9)), orange, yellow) + glass
+
+ def cigarette(size):
+ filter = color(';.`-,:.`;', yellow, orange)+color(' ', yellow, yellow)
+ cigarette = color('|'*size, light_grey, white)
+ cherry = color('\u259A', random.choice((red,yellow,orange)), black)+color('\u259A', random.choice((red,yellow,orange)), grey)
+ smoke = color('-' + ''.join(random.choice((';:-.,_`~\'')) for _ in range(random.randint(5,8))), grey)
+ return filter + cigarette + cherry + smoke
+
+ def joint(size):
+ joint = color('/'*size, light_grey, white)
+ cherry = color('\u259A', random.choice((red,yellow,orange)), black)+color('\u259A', random.choice((red,yellow,orange)), grey)
+ smoke = color('-' + ''.join(random.choice((';:-.,_`~\'')) for _ in range(random.randint(5,8))), grey)
+ return joint + cherry + smoke
+
+ def mug(size):
+ glass = color(' ', light_grey, light_grey)
+ empty = f'{glass} {glass}'
+ foam = glass + color(':::::::::', light_grey, white) + glass
+ bottom = color(' ', light_grey, light_grey)
+ mug = [foam,Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer(),Generate.beer()]
+ for i in range(8-size):
+ mug.pop()
+ mug.insert(0, empty)
+ for i in range(len(mug)):
+ if i == 2 or i == 7:
+ mug[i] += glass + glass
+ elif i > 2 and i < 7:
+ mug[i] += ' ' + glass
+ mug.append(bottom)
+ return mug
+
+class Bot():
+ def __init__(self):
+ self.fat = False
+ self.event = None
+ self.nicks = list()
+ self.stats = {'hits':25,'sips':8,'chugged':0,'smoked':0,'toked':0,'chain':0,'drag':0}
+ self.loops = {'chainsmoke':None,'dragrace':None,'letschug':None,'letstoke':None,'nosmoking':None,'timers':None}
+ self.status = True
+ self.reader = None
+ self.writer = None
+
+ async def raw(self, data):
+ self.writer.write(data[:510].encode('utf-8') + b'\r\n')
+ await self.writer.drain()
+
+ async def action(self, chan, msg):
+ await self.sendmsg(chan, f'\x01ACTION {msg}\x01')
+
+ async def sendmsg(self, target, msg):
+ await self.raw(f'PRIVMSG {target} :{msg}')
+
+ async def notice(self, target, msg):
+ await self.raw(f'NOTICE {target} :{msg}')
+
+ async def connect(self):
+ while True:
+ try:
+ options = {
+ 'host' : server,
+ 'port' : port,
+ 'limit' : 1024,
+ 'ssl' : ssl_ctx() if use_ssl else None,
+ 'family' : 10 if use_ipv6 else 2,
+ 'local_addr' : vhost
+ }
+ self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), 15)
+ await self.raw(f'USER {username} 0 * :{realname}')
+ await self.raw('NICK ' + nickname)
+ except Exception as ex:
+ error('error: failed to connect to ' + server, ex)
+ else:
+ if os.path.isfile('stats.json'):
+ with open('stats.json') as stats_file:
+ self.stats = json.loads(stats_file.read())
+ debug('reloaded stats')
+ await self.listen()
+ for loop in self.loops:
+ if self.loops[loop]:
+ self.loops[loop].cancel()
+ self.stats['chain'] = 0
+ self.stats['drag'] = 0
+ self.event = None
+ self.nicks = list()
+ self.status = True
+ finally:
+ await asyncio.sleep(30)
+
+ async def loop_nosmoking(self):
+ await asyncio.sleep(30)
+ self.status = True
+
+ async def loop_timers(self):
+ while True:
+ try:
+ if time.strftime('%I:%M') == '04:20':
+ await self.sendmsg(channel, color('S M O K E W E E D E R R D A Y', light_green))
+ await self.sendmsg(channel, color('ITZ DAT MUTHA FUCKN 420 BITCH', yellow))
+ await self.sendmsg(channel, color('LIGHT UP A NICE GOOD FAT FUCK', red))
+ await asyncio.sleep(120)
+ elif time.strftime('%I:%M %p') == '02:00 AM':
+ await self.sendmsg(channel, '.ascii phish')
+ await asyncio.sleep(120)
+ elif time.strftime('%I:%M') == '12:00': # the biscuit hour..
+ with open('stats.json', 'w') as stats_file:
+ json.dump(self.stats, stats_file)
+ await asyncio.sleep(120)
+ except Exception as ex:
+ error('error: loop_timers failed', ex)
+ finally:
+ await asyncio.sleep(20)
+
+ async def loop_chainsmoke(self):
+ self.nicks = dict()
+ try:
+ await self.notice(channel, 'Starting a round of {0} in {1} seconds!'.format(color('ChainSmoke', red), color('10', white)))
+ 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)))
+ await asyncio.sleep(10)
+ await self.action(channel, 'Round starts in 3...')
+ await asyncio.sleep(1)
+ await self.action(channel, '2...')
+ await asyncio.sleep(1)
+ await self.action(channel, '1...')
+ await asyncio.sleep(1)
+ await self.action(channel, color('GO', light_green))
+ self.status = True
+ await asyncio.sleep(60)
+ self.status = False
+ await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color(' CHAINSMOKE ROUND IS OVER ', red, yellow))
+ await self.sendmsg(channel, color('Counting cigarette butts...', yellow))
+ await asyncio.sleep(10)
+ await self.sendmsg(channel, '{0} smoked {1} cigarettes!'.format(channel, color(str(self.stats['chain']), light_blue)))
+ if self.nicks:
+ guy = max(self.nicks, key=self.nicks.get)
+ await self.sendmsg(channel, '{0} smoked the most cigarettes... {1}'.format(guy, self.nicks[guy]))
+ except Exception as ex:
+ error('error: loop_chainsmoke failed', ex)
+ finally:
+ self.stats['chain'] = 0
+ self.nicks = list()
+ self.event = None
+ self.status = True
+
+ async def loop_dragrace(self):
+ self.hits = 25
+ try:
+ await self.notice(channel, 'Starting a round of {0} in {1} seconds!'.format(color('DragRace', red), color('10', white)))
+ 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)))
+ await asyncio.sleep(10)
+ await self.action(channel, 'Round starts in 3...')
+ await asyncio.sleep(1)
+ await self.action(channel, '2...')
+ await asyncio.sleep(1)
+ await self.action(channel, '1...')
+ await asyncio.sleep(1)
+ await self.action(channel, color('GO', light_green))
+ self.stats['drag'] = time.time()
+ except Exception as ex:
+ error('error: loop_dragrace failed', ex)
+ finally:
+ self.status = True
+
+ async def loop_letschug(self, nick):
+ self.nicks.append(nick)
+ try:
+ await self.sendmsg(channel, color(f'OH SHIT {nick} is drunk', light_green))
+ await self.notice(channel, color(f'Time to TOTALLY CHUG in {channel.upper()} in 30 seconds, type !chug to join', light_green))
+ await asyncio.sleep(10)
+ await self.sendmsg(channel, color('LOL we CHUG in 20 get ready ' + ' '.join(self.nicks), light_green))
+ await asyncio.sleep(10)
+ await self.sendmsg(channel, color('YO we CHUG in 10 get ready ' + ' '.join(self.nicks), light_green))
+ await asyncio.sleep(5)
+ await self.sendmsg(channel, color('alright CHUG in 5', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('4..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('3..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('2..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('1..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color(' '.join(self.nicks) + ' .. CHUG!', light_green))
+ except Exception as ex:
+ error('error: loop_letschug failed', ex)
+ finally:
+ self.event = None
+ self.nicks = list()
+
+ async def loop_letstoke(self, nick):
+ self.nicks.append(nick)
+ try:
+ await self.sendmsg(channel, color(f'YO {nick} is high', light_green))
+ await self.notice(channel, color(f'Time to FUCKING toke in {channel.upper()}, type !toke to join', light_green))
+ await asyncio.sleep(10)
+ await self.sendmsg(channel, color('OH SHIT we toke in 20 get ready ' + ' '.join(self.nicks), light_green))
+ await asyncio.sleep(10)
+ await self.sendmsg(channel, color('OH SHIT we toke in 10 get ready ' + ' '.join(self.nicks), light_green))
+ await asyncio.sleep(5)
+ await self.sendmsg(channel, color('alright toke in 5', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('4..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('3..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('2..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color('1..', light_green))
+ await asyncio.sleep(1)
+ await self.sendmsg(channel, color(' '.join(self.nicks) + ' .. toke!', light_green))
+ except Exception as ex:
+ error('error: loop_letstoke failed', ex)
+ finally:
+ self.event = None
+ self.nicks = list()
+
+ async def listen(self):
+ while True:
+ try:
+ if self.reader.at_eof():
+ break
+ data = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), 500)
+ line = data.decode('utf-8').strip()
+ args = line.split()
+ debug(line)
+ if line.startswith('ERROR :Closing Link:'):
+ raise Exception('Connection has closed.')
+ elif args[0] == 'PING':
+ await self.raw('PONG '+args[1][1:])
+ elif args[1] == '001':
+ if user_modes:
+ await self.raw(f'MODE {nickname} +{user_modes}')
+ if nickserv_password:
+ await self.sendmsg('NickServ', f'IDENTIFY {nickname} {nickserv_password}')
+ if operator_password:
+ await self.raw(f'OPER {username} {operator_password}')
+ await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel)
+ self.loops['timers'] = asyncio.create_task(self.loop_timers())
+ elif args[1] == '433':
+ error('The bot is already running or nick is in use.') # nick change
+ elif args[1] == 'INVITE' and len(args) == 4:
+ invited = args[2]
+ chan = args[3][1:]
+ if invited == nickname and chan == channel:
+ await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel)
+ elif args[1] == 'KICK' and len(args) >= 4:
+ chan = args[2]
+ kicked = args[3]
+ if kicked == nickname and chan == channel:
+ await asyncio.sleep(3)
+ await self.raw(f'JOIN {channel} {key}') if key else await self.raw('JOIN ' + channel)
+ elif args[1] == 'PART' and len(args) >= 3:
+ chan = args[2]
+ if chan == channel:
+ nick = args[0].split('!')[0][1:]
+ await self.action(nick, f'blows smoke in {nick}\'s face...')
+ elif args[1] == 'PRIVMSG' and len(args) >= 4:
+ nick = args[0].split('!')[0][1:]
+ chan = args[2]
+ msg = ' '.join(args[3:])[1:]
+ if chan == channel:
+ if self.status:
+ args = msg.split()
+ if msg == '@cancer':
+ await self.sendmsg(chan, bold + 'CANCER IRC Bot - Developed by acidvegas in Python - https://git.acid.vegas/cancer')
+ elif msg == '@cancer stats':
+ 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)))
+ 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)))
+ 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)))
+ elif msg in ('!100','!extendo','!fatfuck') and luck(100):
+ if msg == '!fatfuck':
+ self.fat = True
+ 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)))
+ else:
+ self.stats['hits'] = 100
+ if msg == '!100':
+ 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)))
+ else:
+ 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)))
+ elif args[0] == '!beer':
+ if len(args) == 1:
+ target = nick
+ elif len(args) == 2:
+ target = args[1]
+ beer = '{0}{1}{2}'.format(color(' ', white, white), color(' BUD ', white, random.choice((blue,brown))), color('c', grey, white))
+ await self.action(chan, f'throws {color(target, white)} an ice cold {beer} =)')
+ if luck(100):
+ await asyncio.sleep(2)
+ await self.action(chan, 'suddenly feels more gay...')
+ elif msg == '!chainsmoke' and not self.event:
+ self.status = False
+ self.event = 'chainsmoke'
+ self.loops['chainsmoke'] = asyncio.create_task(self.loop_chainsmoke())
+ elif msg == '!chug':
+ if self.event == 'letschug':
+ if nick in self.nicks:
+ await self.sendmsg(chan, color(nick + ' you are already chuggin u wastoid!', light_green))
+ else:
+ self.nicks.append(nick)
+ await self.sendmsg(chan, color(nick + ' joined the CHUG session!', light_green))
+ else:
+ if self.stats['sips'] <= 0:
+ self.stats['sips'] = 8
+ self.stats['chugged'] += 1
+ for line in Generate.mug(self.stats['sips']):
+ await self.sendmsg(chan, line)
+ self.stats['sips'] -= random.choice((1,2))
+ elif msg == '!dragrace' and not self.event:
+ self.status = False
+ self.event = 'dragrace'
+ self.loops['dragrace'] = asyncio.create_task(self.loop_dragrace())
+ elif msg == '!letschug' and not self.event:
+ self.event = 'letschug'
+ self.loops['letschug'] = asyncio.create_task(self.loop_letschug(nick))
+ elif msg == '!letstoke' and not self.event:
+ self.event = 'letstoke'
+ self.loops['letstoke'] = asyncio.create_task(self.loop_letstoke(nick))
+ elif msg == '!nosmoking':
+ self.status = False
+ self.loops['nosmoking'] = asyncio.create_task(self.loop_nosmoking())
+ elif msg in ('!smoke','!toke'):
+ option = 'smoked' if msg == '!smoke' else 'toked'
+ if self.event == 'letstoke' and msg == '!toke':
+ if nick in self.nicks:
+ await self.sendmsg(chan, color(nick + ' you are already toking u stoner!', light_green))
+ else:
+ self.nicks.append(nick)
+ await self.sendmsg(chan, color(nick + ' joined the TOKE session!', light_green))
+ else:
+ if self.stats['hits'] <= 0:
+ self.stats['hits'] = 25
+ self.stats[option] += 1
+ if self.fat:
+ self.fat = False
+ if self.event == 'chainsmoke' and msg == '!smoke':
+ self.nicks[nick] = self.nicks[nick]+1 if nick in self.nicks else 1
+ self.stats['chain'] += 1
+ elif self.event == 'dragrace' and msg == '!smoke':
+ 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)))
+ self.event = None
+ self.stats['drag'] = 0
+ elif luck(25) and msg == '!smoke':
+ await self.raw(f'KILL {nick} CANCER KILLED {nick.upper()} - QUIT SMOKING TODAY! +1 800-QUIT-NOW')
+ else:
+ object = Generate.cigarette(self.stats['hits']) if msg == '!smoke' else Generate.joint(self.stats['hits'])
+ cigarette = Generate.cigarette(self.stats['hits'])
+ if self.fat:
+ for i in range(3):
+ await self.sendmsg(chan, object)
+ else:
+ await self.sendmsg(chan, object)
+ self.stats['hits'] -= random.choice((1,2))
+ except (UnicodeDecodeError, UnicodeEncodeError):
+ pass
+ except Exception as ex:
+ error(self.display + 'fatal error occured', ex)
+ break
+
+# Main
+asyncio.run(Bot().connect())
+\ No newline at end of file
| | | |