From ade6244c9df3d8b1935e0093f3d0aa7ee52c129c Mon Sep 17 00:00:00 2001 From: acidvegas Date: Tue, 4 Jul 2023 12:44:56 -0400 Subject: [PATCH] Initial commit --- .screens/preview.png | Bin 0 -> 33854 bytes LICENSE | 15 ++ README.md | 49 +++++ cancer.py | 461 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 525 insertions(+) create mode 100644 .screens/preview.png create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cancer.py diff --git a/.screens/preview.png b/.screens/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..01c1f8d75ad101dc2865198c03d555fdbd53c2ed GIT binary patch literal 33854 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 + +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 new file mode 100644 index 0000000..2a8d372 --- /dev/null +++ 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 new file mode 100644 index 0000000..c753646 --- /dev/null +++ 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