diff --git a/.gitignore b/.gitignore index 84953b3..090dea9 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ dmypy.json # Mac .ds_store test.py +*.pickle diff --git a/Mafia.py b/Mafia.py index 565d4fa..c83cb26 100644 --- a/Mafia.py +++ b/Mafia.py @@ -7,6 +7,7 @@ import math import mysql.connector import mysql.connector.pooling +import pickle import praw import random import re @@ -22,20 +23,19 @@ from time import sleep def main(): - with open('statements.json') as jsonFile1: + with open('init/statements.json') as jsonFile1: stm = json.load(jsonFile1) - with open('save.json') as jsonFile2: + with open('data/save.json') as jsonFile2: sve = json.load(jsonFile2) - with open('settings.json') as jsonFile3: + with open('init/settings.json') as jsonFile3: cfg = json.load(jsonFile3) exceptCnt = 0 state = sve['state'] curCycle = sve['curCycle'] - curPos = sve['curPos'] - reddit = praw.Reddit(cfg['praw']) - sub = reddit.subreddit(cfg['sub']) + reddit = praw.Reddit(cfg['reddit']['praw']) + sub = reddit.subreddit(cfg['reddit']['sub']) commentStream = sub.stream.comments(skip_existing=True,pause_after=-1) inboxStream = reddit.inbox.stream(pause_after=-1) @@ -43,7 +43,8 @@ def main(): pool = db.get_connection() con = pool.cursor(prepared=True) - cache = [] + idCache = [] + itemCache = {} lastCmd = '' def log_commit(func): @@ -60,7 +61,7 @@ def wrapper(*args, **kwargs): utc = item.created_utc result = func(*args, **kwargs) - pattern = re.search(r'^![\w]{1,}\s([\w\d_]{1,20})', command) + pattern = re.search(r'^![\w]{1,}\s([\w\d_\-\s]+)', command) readable = time.strftime('%m/%d/%Y %H:%M:%S', time.gmtime(utc)) action = '' @@ -82,13 +83,62 @@ def wrapper(*args, **kwargs): return result return wrapper + def game_command(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + pattern = re.search(r'^!([a-z]{4,})\s(?:u/)?([\w\d_\-]+)\s?$', item.body) + search = '' + + if (state == 0): + item.reply(stm['err']['notStarted']) + return -1 + + + if (func.__name__ != 'burnUser'): + if pattern: + search = pattern.group(2) + else: + item.reply(stm['err']['impFmt']) + return -1 + + try: + con.execute(stm['preStm']['chkUsr'], (item.author.name,)) + r = con.fetchall() + + if (len(r) <= 0): + item.reply(stm['err']['spec']) + return -1 + + con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['commands']['useThreshold'])) + r = con.fetchall() + + if (len(r) <= 0): + item.reply(stm['err']['noParticipate']) + return -1 + + if ((func.__name__ != 'unlockTier') and (func.__name__ != 'burnUser')): + con.execute(stm['preStm']['digupUser'], (search,)) + r = con.fetchall() + + if (len(r) <= 0): + item.reply(stm['err']['notFound']) + return -1 + + result = func(*args, **kwargs) + + except mysql.connector.Error as e: + print(f'SQL EXCEPTION @ {func.__name__} : {args} - {kwargs}\n{e}') + con.close() + os._exit(-1) + return result + return wrapper def schdWarn(min=00): - reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['schdWarn'].format(min)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['schdWarn'].format(min)) print(f'Cycle Warning {min}') def autoCycle(): - with open('save.json') as jsonFile2: + with open('data/save.json') as jsonFile2: sve = json.load(jsonFile2) curCycle = sve['curCycle'] cycle(curCycle) @@ -98,406 +148,297 @@ def scheduleJobs(): schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1).zfill(2)}:30').do(schdWarn,min=30) schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1).zfill(2)}:45').do(schdWarn,min=15) schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1).zfill(2)}:55').do(schdWarn,min=5) - schedule.every().day.at(f'{str(cfg["clock"]["hour1"]).zfill(2)}:00').do(autoCycle, curCycle) + schedule.every().day.at(f'{str(cfg["clock"]["hour1"]).zfill(2)}:00').do(autoCycle) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1).zfill(2)}:30').do(schdWarn,min=30) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1).zfill(2)}:45').do(schdWarn,min=15) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1).zfill(2)}:55').do(schdWarn,min=5) - schedule.every().day.at(f'{str(cfg["clock"]["hour2"]).zfill(2)}:00').do(autoCycle, curCycle) + schedule.every().day.at(f'{str(cfg["clock"]["hour2"]).zfill(2)}:00').do(autoCycle) schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1 + 12).zfill(2)}:30').do(schdWarn,min=30) schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1 + 12).zfill(2)}:45').do(schdWarn,min=15) schedule.every().day.at(f'{str(cfg["clock"]["hour1"] - 1 + 12).zfill(2)}:55').do(schdWarn,min=5) - schedule.every().day.at(f'{str(cfg["clock"]["hour1"] + 12).zfill(2)}:00').do(autoCycle, curCycle) + schedule.every().day.at(f'{str(cfg["clock"]["hour1"] + 12).zfill(2)}:00').do(autoCycle) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1 + 12).zfill(2)}:30').do(schdWarn,min=30) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1 + 12).zfill(2)}:45').do(schdWarn,min=15) schedule.every().day.at(f'{str(cfg["clock"]["hour2"] - 1 + 12).zfill(2)}:55').do(schdWarn,min=5) - schedule.every().day.at(f'{str(cfg["clock"]["hour2"] + 12).zfill(2)}:00').do(autoCycle, curCycle) + schedule.every().day.at(f'{str(cfg["clock"]["hour2"] + 12).zfill(2)}:00').do(autoCycle) + + schedule.every(1).to(3).hours.do(makeComment) print("Jobs Scheduled") @log_commit def gameState(state): - pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-s)?', item.body) - setState = pattern.group(1) + pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-[sS])?', item.body) + setState = int(pattern.group(1)) silent = pattern.group(2) - players = 0 if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: gameState')) return -1 else: - con.execute(stm['preStm']['getAll']) - result = con.fetchall() - players = len(result) - - for row in result: - if ((setState == '0') and (silent == None) and (cfg['allowBotBroadcast'] == 1)): - reddit.redditor(row[0]).message('The game has paused!', stm['reply']['gamePause']) - elif ((setState == '1') and (silent == None) and (cfg['allowBotBroadcast'] == 1)): - reddit.redditor(row[0]).message('The game has started!', stm['reply']['gameStart'].format(cfg['sub'], cfg['targetPost'])) - sleep(0.2) - - if ((setState == '0') and (silent == None)): - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['pause']) + if ((setState == 0) and (silent == None)): + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['pause']) comment.mod.distinguish(how='yes', sticky=True) - elif ((setState == '1') and (silent == None)): - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['start'].format(players)) - comment.mod.distinguish(how='yes', sticky=True) - elif ((setState == '2') and (silent == None)): - endGame() + elif ((setState == 1) and (silent == None)): + gameStart() + elif ((setState == 2) and (silent == None)): + gameEnd() if (item.author.name != '*SELF*'): item.reply(f'**gamestate changed to {setState}**') - save(setState, curCycle, curPos) + save(setState, curCycle) return setState @log_commit - def addUser(curPos): - con.execute(stm['preStm']['chkUsrState'],(item.author.name,)) - result = con.fetchall() + def addUser(): + if (state == 1): + item.reply(stm['err']['alreadyStarted']) + return -1 - if(len(result) > 0): - con.execute(stm['preStm']['addExistingUser'], (cfg['maxRequests'], item.author.name)) - item.reply(stm['reply']['addUser'].format(item.author.name, result[0][0].title(), result[0][1], cfg['sub'], cfg['targetPost'])) - sub.flair.set(item.author, text=stm['flairs']['alive'].format(1), flair_template_id=cfg['flairID']['alive']) - reddit.submission(id=cfg['targetPost']).reply(f'u/{item.author.name} has rejoined.') - return curPos - else: - if ((curPos >= len(stm['roles'][0]))): - curPos = 0 + con.execute(stm['preStm']['chkUsrState'],(item.author.name,)) + r = con.fetchall() - random.seed(time.time()) - if ((curPos == 0) or (curPos == 1)): - loc = stm['location'][0][random.randint(0, len(stm['location'][0]) - 1)] + if(len(r) > 0): + con.execute(stm['preStm']['addExistingUser'], (cfg['commands']['maxRequests'], item.author.name)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['addExistingUser'].format(item.author.name)) else: - loc = stm['location'][1][random.randint(0, len(stm['location'][1]) - 1)] + con.execute(stm['preStm']['addUser'], (item.created_utc, item.author.name)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['addUser'].format(item.author.name)) - item.reply(stm['reply']['addUser'].format(item.author.name, stm['roles'][0][curPos], loc, cfg['sub'], cfg['targetPost'])) sub.flair.set(item.author, text=stm['flairs']['alive'].format(1), flair_template_id=cfg['flairID']['alive']) - reddit.submission(id=cfg['targetPost']).reply(f'u/{item.author.name} has joined.') - - con.execute(stm['preStm']['addUser'], (item.created_utc, item.author.name, stm['roles'][0][curPos], loc, cfg['maxRequests'], cfg['maxRequests'])) - curPos += 1 - save(state, curCycle, curPos) - return curPos + item.reply(stm['reply']['addUser'].format(item.author.name)) + setItems(item.author.name, item) @log_commit def removeUser(): - con.execute(stm['preStm']['leave'], (curCycle, item.author.name)) - item.reply(stm['reply']['removeUser']) + con.execute(stm['preStm']['removeUser'], (curCycle, item.author.name)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['removeUser'].format(item.author.name)) sub.flair.delete(item.author) - reddit.submission(id=cfg['targetPost']).reply(f'u/{item.author.name} has left.') + setItems(item.author.name, None) @log_commit + @game_command def voteUser(): - pattern = re.search(r'^!vote\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - round = curCycle + 1 - day = int(math.ceil(round/2)) - mode = { - 0: 'Day', - 1: 'Night' - } - - if pattern: - name = pattern.group(2) - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) - return -1 - - if ((cfg['allowAllVote'] == 0)): - if ((str(r[0][1]) == 'HANDLER') or (str(r[0][1]) == 'ANALYST')): - item.reply(stm['reply']['err']['role']) - return -1 - - if ((cfg['allowVoteAnyTime'] == 0)): - if ((((r[0][1] == 'ASSASSIN') or (r[0][1] == 'HANDLER')) and (curCycle % 2 == 0)) or (((r[0][1] == 'OPERATIVE') or (r[0][1] == 'ANALYST')) and (curCycle % 2 != 0))): - item.reply(stm['reply']['err']['cycle'].format(mode[curCycle % 2])) - return -1 + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() - con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['cmtThreshold'])) - r = con.fetchall() + if (r[0][0] < cfg['commands']['unlockVote']): + item.reply(stm['err']['notUnlocked']) + return -1 - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) - return -1 + pattern = re.search(r'^!vote\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) + target = pattern.group(1) + con.execute(stm['preStm']['digupUser'], (target,)) + r = con.fetchall() - con.execute(stm['preStm']['digupUser'], (name,)) - r = con.fetchall() + if ((len(r) <= 0) or (r[0][2]) != 1): + item.reply(stm['err']['notAlive']) + return -1 - if ((len(r) <= 0) or (r[0][1]) == 0): - item.reply(stm['reply']['err']['notFound']) - return -1 + con.execute(stm['preStm']['voteUser'], (item.author.name, target)) + success = con.rowcount - con.execute(stm['preStm']['voteUser'], (item.author.name, name, name)) - success = con.rowcount + if ((r[0][1] > cfg['commands']['escapeHit']) and (success > 0)): + sendMessage(target, stm['reply']['hitAlertEsc'].format(target, curCycle + 1)) + item.reply(stm['reply']['voteUser']) + elif (success > 0): + sendMessage(target, stm['reply']['hitAlert'].format(target, curCycle + 1)) item.reply(stm['reply']['voteUser']) - - if (((str(r[0][1]) == 'ASSASSIN') or (str(r[0][1]) == 'OPERATIVE')) and (success > 0)): - reddit.redditor(name).message('A hit has been put on you!', stm['reply']['hitAlertEsc'].format(name, round)) - elif (success > 0): - reddit.redditor(name).message('A hit has been put on you!', stm['reply']['hitAlert'].format(name, round)) else: - item.reply(stm['reply']['err']['nmFmt']) + item.reply(stm['err']['voteUser']) + return -1 @log_commit + @game_command def burnUser(): - pattern = re.search(r'^!burn', item.body) - round = curCycle + 1 - day = int(math.ceil(round/2)) - selfRole = '' - burned = '' - burnedRole = '' - side = 0 - - if (curCycle < cfg['allowBurnAfter']): - item.reply(stm['reply']['err']['noBurnYet']) - return -1 - - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) + if (r[0][0] < cfg['commands']['unlockBurn']): + item.reply(stm['err']['notUnlocked']) return -1 - con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['cmtThreshold'])) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) + if (curCycle < cfg['commands']['burnAfter']): + item.reply(stm['err']['noBurnYet']) return -1 con.execute(stm['preStm']['chkBurn'], (item.author.name,)) r = con.fetchall() if (len(r) <= 0): - item.reply(stm['reply']['err']['burnUsed']) + item.reply(stm['err']['burnUsed']) return -1 - selfRole = r[0][1] - - if ((selfRole == 'ASSASSIN') or (selfRole == 'HANDLER')): - side = 0 - else: - side = 1 - - con.execute(stm['preStm']['burn'][side], (item.author.name,)) - r = con.fetchall() + tier = r[0][2] + selfTeam = r[0][1] + oppTeam = selfTeam + 2 + con.execute(stm['preStm']['burn'][selfTeam], (item.author.name,)) + toBurn = con.fetchall() + con.execute(stm['preStm']['burn'][oppTeam]) + toReport = con.fetchall() - if (len(r) <= 0): - item.reply(stm['reply']['err']['noBurnLeft']) + if ((len(toBurn) <= 0) or (len(toReport) <= 0)): + item.reply(stm['err']['noBurnLeft']) return -1 - random.seed(time.time()) - rand = random.randint(0, len(r) - 1) - burned = r[rand][0] - burnedRole = r[rand][1] - - if ((selfRole == 'ASSASSIN') or (selfRole == 'HANDLER')): - side = 2 - else: - side = 3 - - con.execute(stm['preStm']['burn'][side]) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noBurnLeft']) - return -1 - - target = r[random.randint(0, len(r) - 1)] - + burned = toBurn[0][random.randint(0, len(toBurn) - 1)] + exposed = toReport[0][random.randint(0, len(toReport) - 1)] + deathMsg = random.randint(0,len(stm['deathMsg']) - 1) con.execute(stm['preStm']['burn'][4], (item.author.name,)) con.execute(stm['preStm']['burn'][5], (burned,)) - - n = random.randint(0,len(stm['deathMsg']) - 1) - sub.flair.set(reddit.redditor(burned), text=stm['flairs']['dead'].format(burnedRole, stm['deathMsg'][n], day), flair_template_id=cfg['flairID']['dead']) - reddit.redditor(burned).message('You have been burned!', stm['reply']['burnedUser'].format(item.author.name, round)) - item.reply(stm['reply']['burnUser'].format(target[0], target[1])) - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['burnUser'].format(item.author.name, burned)) + con.execute(stm['preStm']['log'], (time.time(), burned, 'Betrayed')) + con.execute(stm['preStm']['log'], (time.time(), exposed, 'Exposed')) + sub.flair.set(reddit.redditor(burned), text=stm['flairs']['dead'].format(stm['deathMsg'][deathMsg], curCycle + 1), flair_template_id=cfg['flairID']['dead']) + item.reply(stm['reply']['burnUser'].format(burned, exposed, stm['teams'][0][(selfTeam + 1) % 2])) + + if (tier >= cfg['commands']['burnQuietly']): + sendMessage(burned, stm['reply']['burnedUserQuietly'].format(stm['deathMsg'][deathMsg], curCycle + 1)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['burnUserQuietly'].format(burned, stm['deathMsg'][deathMsg])) + else: + sendMessage(burned, stm['reply']['burnedUser'].format(stm['deathMsg'][deathMsg], item.author.name, curCycle + 1)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['burnUser'].format(burned, stm['deathMsg'][deathMsg], item.author.name,)) @log_commit + @game_command def reviveUser(): - pattern = re.search(r'^!revive\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - round = curCycle + 1 - day = int(math.ceil(round/2)) + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() - if (cfg['allowRevive'] == 0): - item.reply(stm['reply']['err']['disallowRevive']) + if (r[0][0] < cfg['commands']['unlockRevive']): + item.reply(stm['err']['notUnlocked']) return -1 - if pattern: - name = pattern.group(2) - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) - return -1 - - con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['cmtThreshold'])) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) - return -1 - - con.execute(stm['preStm']['revive'][0], (item.author.name,)) - r = con.fetchall() + con.execute(stm['preStm']['revive'][0], (item.author.name,)) + r = con.fetchall() - if (len(r) <= 0): - item.reply(stm['reply']['err']['reviveUsed']) - return -1 + if (len(r) <= 0): + item.reply(stm['err']['reviveUsed']) + return -1 - con.execute(stm['preStm']['revive'][1], (name,)) - r = con.fetchall() + pattern = re.search(r'^!revive\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) + target = pattern.group(1) + con.execute(stm['preStm']['revive'][1], (target,)) + r = con.fetchall() - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - return -1 + if (len(r) <= 0): + item.reply(stm['err']['alive']) + return -1 - con.execute(stm['preStm']['revive'][2], (item.author.name,)) - con.execute(stm['preStm']['revive'][3], (name,)) - sub.flair.set(reddit.redditor(name), text=stm['flairs']['alive'].format(day), flair_template_id=cfg['flairID']['alive']) - reddit.redditor(name).message('You have been revived!', stm['reply']['revivedUser'].format(item.author.name)) - item.reply(stm['reply']['reviveUser'].format(name)) - reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['revive']) - else: - item.reply(stm['reply']['err']['nmFmt']) + con.execute(stm['preStm']['revive'][2], (item.author.name,)) + con.execute(stm['preStm']['revive'][3], (target,)) + sub.flair.set(reddit.redditor(target), text=stm['flairs']['alive'].format(curCycle + 1, flair_template_id=cfg['flairID']['alive'])) + sendMessage(target, stm['reply']['revivedUser'].format(item.author.name)) + item.reply(stm['reply']['reviveUser'].format(target)) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['revive']) @log_commit + @game_command def digupUser(): - pattern = re.search(r'^!digup\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - random.seed(time.time()) - cred = random.randint(25,75) - role = 0 - - if pattern: - name = pattern.group(2) - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) - return -1 - elif ((str(r[0][1]) == 'ASSASSIN') or (str(r[0][1]) == 'OPERATIVE')): - cred = random.randint(1,25) - - con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['cmtThreshold'])) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) - return -1 + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + tier = r[0][0] - con.execute(stm['preStm']['digupUser'], (name,)) - r = con.fetchall() + pattern = re.search(r'^!digup\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) + con.execute(stm['preStm']['digupUser'], (pattern.group(1),)) + r = con.fetchall() - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - return -1 + random.seed(time.time()) + role = '' + maxTeams = len(stm['teams'][0]) - 1 + maxRoles = len(stm['teams'][1][0]) - 1 + cred = ((tier + 1) * 25) - random.randint(0,25) - if ((cred >= 1) and (cred < 25)): - if (random.randint(0,7) == 0): - role = stm['roles'][1][r[0][0]] - else: - role = (stm['roles'][1][r[0][0]] + random.randint(1,2)) % 4 - elif ((cred >= 25) and (cred < 50)): - if (random.randint(0,4) == 0): - role = stm['roles'][1][r[0][0]] - else: - role = (stm['roles'][1][r[0][0]] + random.randint(1,2)) % 4 - elif ((cred >= 50) and (cred < 75)): - if (random.randint(0,2) == 0): - role = stm['roles'][1][r[0][0]] - else: - role = (stm['roles'][1][r[0][0]] + random.randint(1,2)) % 4 + if (tier == 0): + if (random.randint(0,7) == 0): + role = stm['teams'][0][r[0][0]] + else: + role = stm['teams'][0][random.randint(0,maxTeams)] + elif (tier == 1): + if (random.randint(0,5) == 0): + role = stm['teams'][1][r[0][0]][r[0][1]] else: - role = stm['roles'][1][r[0][0]] + role = stm['teams'][2][random.randint(0,maxTeams)][random.randint(0,maxRoles)] + elif (tier >= 2): + if (random.randint(0,3) == 0): + role = stm['teams'][2][r[0][0]][r[0][1]] + else: + role = stm['teams'][2][random.randint(0,maxTeams)][random.randint(0,maxRoles)] - item.reply(stm['reply']['digupUser'].format(name, stm['reply']['digupUserBody'][0][role], stm['reply']['digupUserBody'][1][r[0][1]], str(cred))) - else: - item.reply(stm['reply']['err']['nmFmt']) + item.reply(stm['reply']['digupUser'][0][0].format(pattern.group(1), role, stm['reply']['digupUser'][1][r[0][2]], cred)) @log_commit + @game_command def locateUser(): - pattern = re.search(r'^!locate\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - role = 0 + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() - if pattern: - name = pattern.group(2) - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) - r = con.fetchall() + if (r[0][0] < cfg['commands']['unlockLocate']): + item.reply(stm['err']['notUnlocked']) + return -1 - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) - return -1 + pattern = re.search(r'^!locate\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) + name = pattern.group(1) + con.execute(stm['preStm']['locateUser'], (name,)) + r = con.fetchall() - con.execute(stm['preStm']['chkCmt'], (item.author.name,cfg['cmtThreshold'])) - r = con.fetchall() + item.reply(stm['reply']['locateUser'].format(name, r[0][0])) - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) - return -1 + @log_commit + @game_command + def requestUser(): + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() - con.execute(stm['preStm']['locateUser'], (name,)) - r = con.fetchall() + if (r[0][0] < cfg['commands']['unlockRequest']): + item.reply(stm['err']['notUnlocked']) + return -1 - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - return -1 + con.execute(stm['preStm']['request'][0], (item.author.name,)) + r = con.fetchall() - item.reply(stm['reply']['locateUser'].format(name, r[0][0])) - else: - item.reply(stm['reply']['err']['nmFmt']) + if (len(r) <= 0): + item.reply(stm['err']['noRequestLeft']) + return -1 + + pattern = re.search(r'^!request\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) + item.reply(stm['reply']['requestUser']) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['requestUser'].format(pattern.group(1), stm['teams'][0][r[0][1]])) + con.execute(stm['preStm']['request'][1], (item.author.name,)) @log_commit - def requestUser(): - pattern = re.search(r'^!request\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' + @game_command + def unlockTier(): + pattern = re.search(r'^![a-z]{4,}\s(?:u/)?([\w\d\-]+)\s?$', item.body) + code = '' if pattern: - name = pattern.group(2) - con.execute(stm['preStm']['chkUsr'], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['spec']) - return -1 - - con.execute(stm['preStm']['chkCmt'], (item.author.name, cfg['cmtThreshold'])) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noParticipate']) - return -1 + code = pattern.group(1) + else: + item.reply(stm['err']['impFmt']) + return -1 - con.execute(stm['preStm']['request'][0], (item.author.name,)) - r = con.fetchall() + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + tier = r[0][0] + team = r[0][1] - if (len(r) <= 0): - item.reply(stm['reply']['err']['noRequestLeft']) - return -1 + if (tier > len(cfg['codes']) - 1): + item.reply(stm['err']['maxTier']) + return -1 - con.execute(stm['preStm']['digupUser'], (name,)) - r = con.fetchall() + if (cfg['codes'][tier] == code): + con.execute(stm['preStm']['unlock'][1], (item.author.name,)) - if ((len(r) <= 0) or (r[0][1]) == 0): - item.reply(stm['reply']['err']['notFound']) - return -1 + if (tier == cfg['commands']['addRequestsOn']): + con.execute(stm['preStm']['unlock'][2], (cfg['commands']['addRequests'], item.author.name)) + item.reply(stm['reply']['addRequests'].format(cfg['commands']['addRequests'])) - con.execute(stm['preStm']['request'][1], (item.author.name,)) - item.reply(stm['reply']['requestUser']) - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['requestUser'].format(name, item.author.name)) + item.reply(stm['reply']['promote'].format(stm['teams'][1][team][tier + 1])) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['promote'].format(tier + 2)) else: - item.reply(stm['reply']['err']['nmFmt']) + item.reply(stm['err']['wrongCode']) + return -1 @log_commit def getList(): @@ -507,20 +448,16 @@ def getList(): aliveNum = 0 con.execute(stm['preStm']['getList'][0]) - result = con.fetchall() - - for row in result: - if (cfg['allowRevive'] == 1): - dead += f'\n* u/{row[0].title()}: ???' - else: - dead += f'\n* u/{row[0].title()}: {row[1]}' + r = con.fetchall() + for row in r: + dead += f'\n* u/{row[0]}' deadNum += 1 con.execute(stm['preStm']['getList'][1]) - result = con.fetchall() + r = con.fetchall() - for row in result: + for row in r: alive += f'\n* u/{row[0]}' aliveNum += 1 @@ -528,45 +465,34 @@ def getList(): @log_commit def getStats(): - round = curCycle + 1 - day = int(math.ceil((round)/2)) - role = '' - user = 0 - alive = 0 - killed = 0 - good = 0 - bad = 0 - mode = { - 0: 'Day', - 1: 'Night' - } - - con.execute(stm['preStm']['digupUser'], (item.author.name,)) - result = con.fetchall() + team = 'The Spectators' + tier = 'Spectator' + loc = 'Nowhere' + status = 'not playing' - if (len(result) == 1): - role = result[0][0] - user = result[0][1] - else: - role = 'spectator' + con.execute(stm['preStm']['chkUsrState'], (item.author.name,)) + r = con.fetchall() + + if (len(r) == 1): + team = stm['teams'][0][r[0][0]] + tier = stm['teams'][1][r[0][0]][r[0][1]] + loc = r[0][2] + status = stm['alive'][r[0][3]] con.execute(stm['preStm']['cycle']['getAliveCnt']) result = con.fetchall() alive = result[0][0] killed = result[0][1] - if (state > 0): - con.execute(stm['preStm']['cycle']['getRoleCnt']) - result = con.fetchall() - bad = result[0][0] - good = result[0][1] + con.execute(stm['preStm']['cycle']['getTeamCnt']) + result = con.fetchall() + bad = result[0][0] + good = result[0][1] item.reply(stm['reply']['getSts'][0][0].format(stm['reply']['getSts'][1][state], \ - mode[curCycle % 2], day, round, role.title(), stm['reply']['digupUserBody'][1][user], \ - alive, good, bad, killed, alive + killed, stm['reply']['getSts'][2][cfg['allowAllVote']], \ - stm['reply']['getSts'][2][cfg['allowVoteAnyTime']], stm['reply']['getSts'][2][cfg['allowRevive']], \ - cfg['allowBurnAfter'], cfg['voteThreshold'], cfg['voteOneAfter'], \ - cfg['maxRequests'], cfg['kickAfter'])) + curCycle + 1, tier, team, loc, status, alive, good, bad, killed, alive + killed, \ + cfg['commands']['burnAfter'], cfg['commands']['voteThreshold'], \ + cfg['commands']['voteOneAfter'], cfg['commands']['maxRequests'], cfg['kickAfter'])) @log_commit def showHelp(): @@ -577,26 +503,115 @@ def showRules(): item.reply(stm['reply']['showRules']) @log_commit - def cycle(curCycle): - round = curCycle + 1 - nextRound = round + 1 - day = int(math.ceil(nextRound/2)) - alive = 0 - killed = 0 - good = 0 - bad = 0 - mode = { - 0: 'Day', - 1: 'Night' - } - threshold = 1 + def makeComment(): + random.seed(time.time()) + + if (random.randint(0, 2) == 0): + con.execute(stm['preStm']['cycle']['getVotes']) + r = con.fetchall() + + if (len(r) <= 0): + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['warn']['noVotes'][random.randint(0, len(stm['comment']['warn']['noVotes']) - 1)]) + return + else: + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['warn']['votes'][random.randint(0, len(stm['comment']['warn']['votes']) - 1)]) + return + + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['spook'][random.randint(0, len(stm['comment']['spook']) - 1)]) + + @log_commit + def gameStart(): + con.execute(stm['preStm']['getPlaying']) + r = con.fetchall() + players = len(r) + curPos = 0 random.seed(time.time()) + random.shuffle(r) + + for row in r: + team = curPos % 2 + + random.seed(time.time()) + loc = stm['location'][team][random.randint(0, len(stm['location'][team]) - 1)] + con.execute(stm['preStm']['joinTeam'], (team, loc, row[0])) + sendMessage(row[0], stm['reply']['gameStart'].format(stm['teams'][0][team], loc, players, cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + curPos += 1 + sleep(0.2) + + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['start'].format(players)) + comment.mod.distinguish(how='yes', sticky=True) + + @log_commit + def gameEnd(): + round = curCycle + 1 + con.execute(stm['preStm']['cycle']['resetInactive']) + con.execute(stm['preStm']['cycle']['incrementInactive']) + con.execute(stm['preStm']['cycle']['resetComment']) + con.execute(stm['preStm']['cycle']['getInactive'], (cfg['kickAfter'],)) + r = con.fetchall() + + for row in r: + sub.flair.delete(reddit.redditor(row[0])) + reddit.redditor(row[0]).message('You have been kicked!', stm['reply']['cycle'][2]) + sleep(0.2) + + con.execute(stm['preStm']['cycle']['getAliveCnt']) + r = con.fetchall() + alive = r[0][0] + killed = r[0][1] + + print(f'\nAlive: {alive} | Killed {killed}') + + if (cfg['commands']['allowBotBroadcast'] == 1): + con.execute(stm['preStm']['getDead']) + r = con.fetchall() + + for row in r: + sendMessage(row[0], stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + sleep(0.2) + + con.execute(stm['preStm']['cycle']['getAlive']) + r = con.fetchall() + + for row in r: + if (cfg['commands']['allowBotBroadcast'] == 1): + sendMessage(row[0], stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + + sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['survived'].format(stm['teams'][0][row[1]], round), flair_template_id=cfg['flairID']['alive']) + sleep(0.2) + + con.execute(stm['preStm']['getWinner']) + r = con.fetchall() + bad = r[0][0] + good = r[0][1] + + if (good == bad): + winner = 'NOBODY' + elif (good > bad): + winner = 'MI6' + else: + winner = 'The Twelve' + + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['end'].format(winner, alive, killed)) + comment.mod.distinguish(how='yes', sticky=True) + + @log_commit + def cycle(curCycle): + if (state == 0): + item.reply(stm['err']['notStarted']) + return -1 + + if (item.author.name not in cfg['adminUsr']): + con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: cycle')) + return -1 - if (curCycle > cfg['voteOneAfter']): + threshold = 1 + + if (curCycle > cfg['commands']['voteOneAfter']): threshold = 1 else: - threshold = cfg['voteThreshold'] + threshold = cfg['commands']['voteThreshold'] con.execute(stm['preStm']['cycle']['resetInactive']) con.execute(stm['preStm']['cycle']['incrementInactive']) @@ -606,7 +621,7 @@ def cycle(curCycle): for row in result: con.execute(stm['preStm']['log'], (time.time(), row[0], 'Inactive Kick')) sub.flair.delete(reddit.redditor(row[0])) - reddit.redditor(row[0]).message('You have been kicked!', stm['reply']['cycle'][2]) + sendMessage(row[0], stm['reply']['cycle'][2]) sleep(0.2) con.execute(stm['preStm']['cycle']['removeInactive'], (cfg['kickAfter'],)) @@ -615,24 +630,25 @@ def cycle(curCycle): for row in result: con.execute(stm['preStm']['chkUsr'], (row[0],)) - role = con.fetchall() + r = con.fetchall() + tier = r[0][2] + + if (tier <= cfg['commands']['escapeHit']): + continue + con.execute(stm['preStm']['cycle']['getVoteTarget'], (row[0],)) target = con.fetchall() - if ((len(role) >= 1) and (len(target) >= 1)): - if (role[0][1] == 'ANALYST') or (role[0][1] == 'HANDLER'): - continue - - con.execute(stm['preStm']['cycle']['getVoters'], (row[0],row[0])) + if (len(target) >= 1): + con.execute(stm['preStm']['cycle']['getVoters'], (row[0], row[0])) list = con.fetchall() for user in list: - if (target[0][0] == user[0][0]): - print('success') - con.execute(stm['preStm']['log'], (time.time(), target[0][0], f'{target[0][0]} Escaped')) + if (target[0][0] == user[0]): + con.execute(stm['preStm']['log'], (time.time(), row[0], 'Escaped')) con.execute(stm['preStm']['cycle']['voteEscaped'], (row[0],)) - reddit.redditor(target[0]).message('You have escaped!', stm['reply']['cycle'][3]) - print(f' > {target[0]} escaped') + sendMessage(row[0], stm['reply']['cycle'][3]) + print(f' > {row[0]} escaped') con.execute(stm['preStm']['cycle']['killPlayer'], (curCycle, threshold)) con.execute(stm['preStm']['cycle']['getAliveCnt']) @@ -642,135 +658,67 @@ def cycle(curCycle): print(f'\nAlive: {alive} | Killed {killed}') - con.execute(stm['preStm']['cycle']['getRoleCnt']) + con.execute(stm['preStm']['cycle']['getTeamCnt']) result = con.fetchall() bad = result[0][0] good = result[0][1] - print(f'MI6 remaining: {good}') - print(f'The Twelve remaining: {bad}') + print(f'MI6: {good} | The Twelve: {bad}') con.execute(stm['preStm']['cycle']['getDead'], (threshold,)) result = con.fetchall() + for row in result: + con.execute(stm['preStm']['cycle']['getKilledMe'], (row[0],)) + r = con.fetchall() killedMe = '' - if (cfg['allowVoteAnyTime'] == 1): - con.execute(stm['preStm']['cycle']['getKilledMe'], (row[0],)) - r = con.fetchall() - - for v in r: - killedMe += f'* u/{v[0]}\n' - else: - killedMe = 'Hidden for this game mode.' + for v in r: + killedMe += f'* u/{v[0]}\n' random.seed(time.time()) n = random.randint(0,len(stm['deathMsg']) - 1) - - if (cfg['allowRevive'] == 1): - sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['dead'].format('???', stm['deathMsg'][n],day), flair_template_id=cfg['flairID']['dead']) - else: - sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['dead'].format(row[1].title(), stm['deathMsg'][n],day), flair_template_id=cfg['flairID']['dead']) - - reddit.redditor(row[0]).message('You have been killed!', stm['reply']['cycle'][0].format(stm['deathMsg'][n], day, killedMe, alive, good, bad, killed, alive + killed)) + sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['dead'].format(stm['deathMsg'][n], curCycle + 1), flair_template_id=cfg['flairID']['dead']) + sendMessage(row[0], stm['reply']['cycle'][0].format(stm['deathMsg'][n], curCycle + 1, killedMe, alive, good, bad, killed, alive + killed)) con.execute(stm['preStm']['log'], (time.time(), row[0], 'Killed')) - print(f' > {target[0]} killed') + print(f' > {row[0]} killed') sleep(0.2) con.execute(stm['preStm']['cycle']['getAlive']) result = con.fetchall() + for row in result: - sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['alive'].format(day), flair_template_id=cfg['flairID']['alive']) + sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['alive'].format(curCycle + 2), flair_template_id=cfg['flairID']['alive']) + # sendMessage(row[0], stm['reply']['cycle'][1].format(curCycle + 2, alive, good, bad, killed, alive + killed)) sleep(0.2) con.execute('TRUNCATE TABLE VoteCall'); - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['cycle'].format(mode[round % 2], day, nextRound, alive, good, bad, killed, alive + killed)) + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['cycle'].format(curCycle + 2, alive, good, bad, killed, alive + killed)) comment.mod.distinguish(how='yes', sticky=True) - - if (item != None): item.reply(f'**Moved to cycle {round} (Round: {nextRound})**') - curCycle = round - save(state, curCycle, curPos) + if (item != None): item.reply(f'**Moved to Round {curCycle + 2}**') + print(f'Moved to Round {curCycle + 1}') + curCycle += 1 + save(state, curCycle) return curCycle - @log_commit - def endGame(): - round = curCycle + 1 - day = int(math.ceil(round/2)) - alive = -1 - killed = -1 - good = -1 - bad = -1 - winner = '' - - con.execute(stm['preStm']['cycle']['resetInactive']) - con.execute(stm['preStm']['cycle']['incrementInactive']) - con.execute(stm['preStm']['cycle']['resetComment']) - con.execute(stm['preStm']['cycle']['getInactive'], (cfg['kickAfter'],)) - result = con.fetchall() - for row in result: - sub.flair.delete(reddit.redditor(row[0])) - reddit.redditor(row[0]).message('You have been kicked!', stm['reply']['cycle'][2]) - sleep(0.2) - - con.execute(stm['preStm']['cycle']['getAliveCnt']) - result = con.fetchall() - alive = result[0][0] - killed = result[0][1] - - print(f'\nAlive: {alive} | Killed {killed}') - - con.execute(stm['preStm']['getWinner']) - result = con.fetchall() - good = result[0][0] - bad = result[0][1] - - con.execute(stm['preStm']['getDead']) - result = con.fetchall() - - if (cfg['allowBotBroadcast'] == 1): - for row in result: - reddit.redditor(row[0]).message('The game has ended!', stm['reply']['gameEnd'].format(cfg['sub'], cfg['targetPost'])) - sleep(0.2) - - con.execute(stm['preStm']['cycle']['getAlive']) - result = con.fetchall() - - for row in result: - if (cfg['allowBotBroadcast'] == 1): - reddit.redditor(row[0]).message('The game has ended!', stm['reply']['gameEnd']) - - sub.flair.set(reddit.redditor(row[0]), text=stm['flairs']['survived'].format(row[1], day), flair_template_id=cfg['flairID']['alive']) - sleep(0.2) - - if (good == bad): - winner = 'NOBODY' - elif (good > bad): - winner = 'MI6' - else: - winner = 'The Twelve' - - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['end'].format(winner, alive, killed)) - comment.mod.distinguish(how='yes', sticky=True) - @log_commit def broadcast(): - if (cfg['allowBotBroadcast'] == 0): - item.reply('Broadcast Disabled') - return - pattern = re.search(r'^!BROADCAST\s([\s\w\d!@#$%^&*()_+{}|:\'<>?\-=\[\]\;\',./’]+)', item.body) msg = pattern.group(1) if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: broadcast')) + return -1 + + if (cfg['commands']['allowBotBroadcast'] == 0): + item.reply('Broadcast Disabled') return - else: - con.execute(stm['preStm']['getAll']) - result = con.fetchall() - for row in result: - reddit.redditor(row[0]).message('Announcement', msg) - sleep(0.2) + con.execute(stm['preStm']['getAll']) + r = con.fetchall() + for row in r: + sendMessage(row[0], msg) + sleep(0.2) @log_commit def restart(): @@ -778,44 +726,19 @@ def restart(): if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: restart')) - return - else: - con.execute(stm['preStm']['restart'], (cfg['maxRequests'],)) - con.execute('SELECT `username` FROM Mafia') - result = con.fetchall() - random.shuffle(result) - curPos = 2 - - for row in result: - if (curPos >= len(stm['roles'][0])): - curPos = 0 - - random.seed(time.time()) - if ((curPos == 0) or (curPos == 1)): - loc = stm['location'][0][random.randint(0, len(stm['location'][0]) - 1)] - else: - loc = stm['location'][1][random.randint(0, len(stm['location'][1]) - 1)] - - con.execute(stm['preStm']['replaceUser'], (time.time(), row[0], stm['roles'][0][curPos], loc)) - - if (cfg['allowBotBroadcast'] == 1): - reddit.redditor(row[0]).message('A new game is starting', stm['reply']['newGame'].format(row[0], stm['roles'][0][curPos].title())) - - curPos += 1 - sub.flair.set(row[0], text=stm['flairs']['alive'].format(1), flair_template_id=cfg['flairID']['alive']) - sleep(0.2) + return -1 - con.execute('TRUNCATE TABLE VoteCall;'); - con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'restart')) - con.execute('COMMIT;') - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['restart']) - comment.mod.distinguish(how='yes', sticky=True) - save(0, 0, 0) + con.execute(stm['preStm']['restart']) + con.execute('TRUNCATE TABLE VoteCall;'); + con.execute('COMMIT;') + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['restart']) + comment.mod.distinguish(how='yes', sticky=True) + save(0, 0) - if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') - print('REMOTE RESTART RECEIVED') - con.close() - os._exit(1) + if (item.author.name != '*SELF*'): item.reply('**Restarting Game**') + print('REMOTE RESTART RECEIVED') + con.close() + os._exit(1) @log_commit def reset(): @@ -823,26 +746,31 @@ def reset(): if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: reset')) - return - else: - con.execute('SELECT `username` FROM Mafia') - result = con.fetchall() + return -1 - for row in result: - sub.flair.delete(row[0]) + con.execute('SELECT `username` FROM Mafia') + r = con.fetchall() - con.execute('TRUNCATE TABLE Mafia;'); - con.execute('TRUNCATE TABLE VoteCall;'); - con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'reset')) - con.execute('COMMIT;') - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['reset']) - comment.mod.distinguish(how='yes', sticky=True) - save(0, 0, 0) + for row in r: + sub.flair.delete(row[0]) - if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') - print('REMOTE RESET RECEIVED') - con.close() - os._exit(1) + con.execute('TRUNCATE TABLE Mafia;'); + con.execute('TRUNCATE TABLE VoteCall;'); + con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'reset')) + con.execute('COMMIT;') + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['reset']) + comment.mod.distinguish(how='yes', sticky=True) + save(0, 0) + + try: + os.remove('data/items.pickle') + except: + pass + + if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') + print('REMOTE RESET RECEIVED') + con.close() + os._exit(1) @log_commit def halt(): @@ -850,16 +778,36 @@ def halt(): if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: halt')) - return - else: - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['halt']) + return -1 + + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['halt']) + comment.mod.distinguish(how='yes', sticky=True) + con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'halt')) + con.execute('COMMIT;') + if (item.author.name != '*SELF*'): item.reply('**Stopping Game**') + print('REMOTE HALT RECEIVED') + con.close() + os._exit(1) + + def rateLimit(): + limits = json.loads(str(reddit.auth.limits).replace("'", "\"")) + + if (limits['remaining'] < 10): + reset = (limits["reset_timestamp"] + 10) - time.time() + print(f'Sleeping for: {reset} seconds') + print(time.strftime('%m/%d/%Y %H:%M:%S', time.gmtime(limits["reset_timestamp"]))) + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['rateLimit'].format(reset)) comment.mod.distinguish(how='yes', sticky=True) - con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'halt')) - con.execute('COMMIT;') - if (item.author.name != '*SELF*'): item.reply('**Stopping Game**') - print('REMOTE HALT RECEIVED') - con.close() - os._exit(1) + sleep(reset) + + def sendMessage(name, message): + if(getItems(name) != None): + getItems(name).reply(message) + rateLimit() + else: + print(f'WARNING. {name} not found in items.pickle. Falling back on alternate') + reddit.redditor(name).message('Mafia', message) + rateLimit() con.execute(stm['preStm']['main'][0]) con.execute(stm['preStm']['main'][1], (time.time(),)) @@ -868,15 +816,14 @@ def halt(): con.execute('SHOW PROCESSLIST') conStat = con.fetchall() + scheduleJobs() + print(f'Connected as {str(reddit.user.me())}') print(f'Database Connections: {len(conStat)}') print(f'state: {state}') print(f'curCycle: {curCycle} (Cycle: {curCycle + 1})') - print(f'curPos: {curPos}') print('______') - scheduleJobs() - while True: if (state == 1): schedule.run_pending() @@ -886,14 +833,14 @@ def halt(): if comment is None: break - if ((comment.submission.id == cfg['targetPost']) and (comment.id not in cache)): - if (len(cache) > 1000): - cache = [] + if ((comment.submission.id == cfg['reddit']['targetPost']) and (comment.id not in idCache)): + if (len(idCache) > 1000): + idCache = [] if(re.search(r'^!(join|leave|vote|digup|rules|help|stats)', comment.body)): - comment.reply(stm['reply']['err']['notPM']) + comment.reply(stm['err']['notPM']) - cache.append(comment.id) + idCache.append(comment.id) con.execute(stm['preStm']['comment'], (comment.author.name,)) con.execute('COMMIT;') @@ -910,22 +857,24 @@ def halt(): except: pass - if ((re.search(r'^!join', item.body)) and (curCycle <= cfg['allowJoinUptTo'])): - curPos = addUser(curPos) + if (re.search(r'^!join', item.body)): + addUser() elif (re.search(r'^!leave', item.body)): removeUser() - elif ((re.search(r'^!vote', item.body)) and (state == 1)): + elif (re.search(r'^!vote', item.body)): voteUser() - elif ((re.search(r'^!burn$', item.body)) and (state == 1)): + elif (re.search(r'^!burn$', item.body)): burnUser() - elif ((re.search(r'^!revive', item.body)) and (state == 1)): + elif (re.search(r'^!revive', item.body)): reviveUser() - elif ((re.search(r'^!digup', item.body)) and (state == 1)): + elif (re.search(r'^!digup', item.body)): digupUser() - elif ((re.search(r'^!locate', item.body)) and (state == 1)): + elif (re.search(r'^!locate', item.body)): locateUser() - elif ((re.search(r'^!request', item.body)) and (state == 1)): + elif (re.search(r'^!request', item.body)): requestUser() + elif (re.search(r'^!unlock', item.body)): + unlockTier() elif ((re.search(r'^!list', item.body))): getList() elif (re.search(r'^!stats', item.body)): @@ -936,8 +885,8 @@ def halt(): showRules() elif (re.search(r'^!GAMESTATE', item.body)): state = gameState(state) - elif ((re.search(r'^!CYCLE', item.body)) and (state == 1)): - cycle = cycle(curCycle) + elif (re.search(r'^!CYCLE', item.body)): + curCycle = cycle(curCycle) elif (re.search(r'^!BROADCAST', item.body)): broadcast() elif (re.search(r'^!RESTART', item.body)): @@ -947,7 +896,7 @@ def halt(): elif (re.search(r'^!HALT', item.body)): halt() else: - item.reply(stm['reply']['err']['unkCmd'][0][0].format(stm['reply']['err']['unkCmd'][1][state])) + item.reply(stm['err']['unkCmd']) item.mark_read() lastCmd = item.body.strip() @@ -960,16 +909,38 @@ def halt(): con.close() -def save(state, curCycle, curPos): - with open('save.json', 'r+') as jsonFile2: +def save(state, curCycle): + with open('data/save.json', 'r+') as jsonFile2: tmp = json.load(jsonFile2) tmp['state'] = int(state) tmp['curCycle'] = int(curCycle) - tmp['curPos'] = int(curPos) jsonFile2.seek(0) json.dump(tmp, jsonFile2) jsonFile2.truncate() +def setItems(k, v): + tmp = {} + + if (os.path.getsize('data/items.pickle') > 0): + with open('data/items.pickle', 'rb') as itemsFile: + tmp = pickle.load(itemsFile) + tmp[k] = v + else: + print('WARNING items.pickle not found. Creating new one.') + tmp[k] = v + + with open('data/items.pickle', 'wb') as itemsFile: + pickle.dump(tmp, itemsFile) + +def getItems(k): + if os.path.getsize('data/items.pickle') > 0: + with open('data/items.pickle', 'rb') as itemsFile: + tmp = pickle.load(itemsFile) + return tmp[k] + else: + print('items.pickle not found. WARNING') + return None + def exit_gracefully(signum, frame): signal.signal(signal.SIGINT, original_sigint) diff --git a/README.md b/README.md index da83ce6..4793693 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Mafia: MI6 VS The Twelve V1 +# Mafia: MI6 VS The Twelve V2 **Who will survive? MI6 or The Twelve ?!** @@ -10,45 +10,54 @@ Play against other members to find out who amongst each other you can trust and *It is not recommended to play on mobile web. Please use Reddit Desktop, official Reddit App, or third party client that supports live chat.* -1. Each user is given a secret role. You cannot see each other’s roles. You may choose to bluff or try to be truthful. Introduce yourself at the beginning of the game to set the scene. -2. You must investigate each other to determine who is on what side. -3. During the Day, MI6 agents can investigate and kill users who they suspect are in The Twelve. During the Night, The Twelve can investigate and kill users who they suspect are in MI6. **Each Cycle lasts 6 hours. 2 Day/Night Rounds, 4 Cycles per day.** -4. **A user must receive at least 2 votes to be executed**. Teams members are not immune to each other. You may end up killing your own team members out of suspicion. Users who do not actively participate in the investigation may not use the !vote or !digup commands. -5. At the end of each cycle, an announcement will be made how many people are alive how many were killed. -6. You must choose your allies carefully to seek out the enemy. +1. Each user is assigned to either MI6 or the Twelve. +2. You must investigate each other to determine who is on what side and eliminate the opponent. +3. Decipher and decrypt the clues provided in order to advance your rank and unlock more powerful investigation tools. +4. Vote out players who you suspect are the enemy. A player must receive a certain number of hits in order to be killed. After a certain amount of time, the number of votes required will be lowered to 1. Votes, aka hits, only last per round. +4. At the end of each round, an announcement will be made how many people are alive how many were killed. +5. You must choose your allies carefully to seek out the enemy. **Tips:** -* You do not need to make a new PM for each command. Simply reply to any existing PM from the bot. -* Investigators can use the !digup command multiple times times on the same user to get a better picture of their role. +- This is a passive game, you are not required to be on actively. However, users who are inactive for more than 48 hours will be kicked. +- It is recommended that you use Reddit Desktop Redesign, official Reddit apps, or third party app client that supports Reddit's Live Chat feature. +- You do not need to make a new PM for each command. Simply reply to any existing PM from the bot. +- Working in pairs is the ultimate way to win! But who can you trust? +- Use the !digup command multiple times on the same user to get a better picture of their role. +- If you are not able to use a command because you are getting a comment participation message, use a different command, such as !stats, to refresh the database so that it pulls the latest information. Note: It may take Reddit up to 30 seconds to update its comments. **Roles** -|Role|Description| -|:-|:-| -|Handler|The Twelve. Can investigate users more reliably.| -|Assassin|The Twelve. Chance of escaping a kill order on them.| -|Analyst|MI6. Can investigate users more reliably.| -|Operative|MI6. Chance of escaping a kill order on them.| +|Team|Role|Tier|Description| +|:-|:-|:-|:-| +|The Twelve|Trainee|1|Access to digup (low accuracy), vote, and max 3 requests.| +|The Twelve|Assassin|2|Digup accuracy increased.| +|The Twelve|Handler|3|Digup accuracy increased. Unlocked locate and burn command (Tier 3 or lower). 3 Additional requests. Can escape hits.| +|The Twelve|Keeper|4|Revive unlocked. Burn does not announce who you are.| +|MI6|Recruit|1|Access to digup (low accuracy), vote, and max 3 requests.| +|MI6|Analyst|2|Digup accuracy increased.| +|MI6|Operative|3|Digup accuracy increased. Unlocked locate and burn command (Tier 3 or lower). 3 Additional requests. Can escape hits.| +|MI6|Supervisor|4|Revive unlocked. Burn does not announce who you are.| **Commands** -All commands must be sent privately to u/DozenIncBOT +All commands must be sent privately to u/DozenIncBOT. To use investigative commands, use must comment at least once per round to avoid being kicked for inactivity. -|Command|Description| -|:-|:-| -|!join|Join the game. Note: You cannot rejoin once the game has started.| -|!leave|Leave the game.| -|!list|Shows dead and alive players.| -|!request USERNAME|Ask for intel anonymously on a player.| -|!burn|Exposes one of your team members for guaranteed intelligence about the other team. Can only be used once. Can be used by all. Unlocked after round 8.| -|!revive USERNAME|Brings back a player from the dead. Can only be used once| -|!vote USERNAME|Vote on who to eliminate. Can be changed until the Cycle ends.| -|!digup USERNAME|Investigate the roles of other users. Has varying degree of reliability.| -|!locate USERNAME|Shows the user's location. May give a clue as to what side they are on. Can be used by all. Limited number of uses.| -|!stats|Gets the current stats for the game.| -|!help|Shows all commands available.| -|!rules|Shows the rules.| +|Command|Description|Unlock Tier| +|:-|:-|:-| +|!join|Join the game. Note: You cannot rejoin once the game has started.|1| +|!leave|Leave the game.|1| +|!list|Shows dead and alive players.|1| +|!request USERNAME|Ask for intel anonymously on a player. Limited number of uses.|1| +|!burn|Exposes one of your team members for guaranteed intelligence about the other team. Can only be used once.|3| +|!revive USERNAME|Brings back a player from the dead. Can only be used once|4| +|!vote USERNAME|Vote on who to eliminate. Can not be changed once voted per round.|2| +|!digup USERNAME|Investigate the roles of other users. Has varying degree of reliability based on your tier|1| +|!locate USERNAME|Shows the user's location. May give a clue as to what side they are on.|3| +|!stats|Gets the current stats for the game.|1| +|!help|Shows all commands available.|1| +|!rules|Shows the rules.|1| +|!unlock CODE|Enter a secret code in order to level up to the next tier.|1| **Flairs** diff --git a/data/save.json b/data/save.json new file mode 100644 index 0000000..2d35f5b --- /dev/null +++ b/data/save.json @@ -0,0 +1 @@ +{"state": 0, "curCycle": 0} \ No newline at end of file diff --git a/database.sql b/database.sql deleted file mode 100644 index 2da7502..0000000 --- a/database.sql +++ /dev/null @@ -1,114 +0,0 @@ --- MySQL dump 10.17 Distrib 10.3.22-MariaDB, for debian-linux-gnueabihf (armv8l) --- --- Host: 127.0.0.1 Database: Reddit --- ------------------------------------------------------ --- Server version 10.3.22-MariaDB-0+deb10u1 - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `Log` --- - -DROP TABLE IF EXISTS `Log`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Log` ( - `utc` int(11) NOT NULL, - `username` varchar(20) COLLATE utf8_bin NOT NULL, - `action` varchar(255) COLLATE utf8_bin NOT NULL, - PRIMARY KEY (`utc`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `Mafia` --- - -DROP TABLE IF EXISTS `Mafia`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Mafia` ( - `utc` int(11) NOT NULL, - `username` varchar(20) COLLATE utf8_bin NOT NULL, - `role` varchar(20) COLLATE utf8_bin NOT NULL, - `loc` varchar(45) COLLATE utf8_bin DEFAULT NULL, - `alive` tinyint(3) unsigned NOT NULL DEFAULT 1, - `diedOnCycle` int(11) DEFAULT NULL, - `burn` tinyint(4) NOT NULL DEFAULT 1, - `revive` int(11) NOT NULL DEFAULT 1, - `request` int(11) NOT NULL DEFAULT 3, - `comment` int(11) NOT NULL DEFAULT 0, - `inactive` int(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`utc`), - UNIQUE KEY `Mafiacol_UNIQUE` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Temporary table structure for view `RoleCnt` --- - -DROP TABLE IF EXISTS `RoleCnt`; -/*!50001 DROP VIEW IF EXISTS `RoleCnt`*/; -SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; -/*!50001 CREATE TABLE `RoleCnt` ( - `role` tinyint NOT NULL, - `count` tinyint NOT NULL -) ENGINE=MyISAM */; -SET character_set_client = @saved_cs_client; - --- --- Table structure for table `VoteCall` --- - -DROP TABLE IF EXISTS `VoteCall`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `VoteCall` ( - `username` varchar(20) COLLATE utf8_bin NOT NULL, - `vote` varchar(20) COLLATE utf8_bin NOT NULL, - PRIMARY KEY (`username`), - UNIQUE KEY `username_UNIQUE` (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Final view structure for view `RoleCnt` --- - -/*!50001 DROP TABLE IF EXISTS `RoleCnt`*/; -/*!50001 DROP VIEW IF EXISTS `RoleCnt`*/; -/*!50001 SET @saved_cs_client = @@character_set_client */; -/*!50001 SET @saved_cs_results = @@character_set_results */; -/*!50001 SET @saved_col_connection = @@collation_connection */; -/*!50001 SET character_set_client = utf8 */; -/*!50001 SET character_set_results = utf8 */; -/*!50001 SET collation_connection = utf8_general_ci */; -/*!50001 CREATE ALGORITHM=UNDEFINED */ -/*!50013 DEFINER=`DozenIncBOT`@`localhost` SQL SECURITY DEFINER */ -/*!50001 VIEW `RoleCnt` AS select `Mafia`.`role` AS `role`,count(`Mafia`.`role`) AS `count` from `Mafia` where `Mafia`.`alive` = '1' group by `Mafia`.`role` order by `Mafia`.`role` desc */; -/*!50001 SET character_set_client = @saved_cs_client */; -/*!50001 SET character_set_results = @saved_cs_results */; -/*!50001 SET collation_connection = @saved_col_connection */; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2020-06-29 15:37:24 diff --git a/init/database.sql b/init/database.sql new file mode 100644 index 0000000..0b3088f --- /dev/null +++ b/init/database.sql @@ -0,0 +1,146 @@ +-- MySQL Script generated by MySQL Workbench +-- Wed Jul 8 00:41:18 2020 +-- Model: New Model Version: 1.0 +-- MySQL Workbench Forward Engineering + +SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; + +-- ----------------------------------------------------- +-- Schema mydb +-- ----------------------------------------------------- +-- ----------------------------------------------------- +-- Schema Reddit +-- ----------------------------------------------------- +DROP SCHEMA IF EXISTS `Reddit` ; + +-- ----------------------------------------------------- +-- Schema Reddit +-- ----------------------------------------------------- +CREATE SCHEMA IF NOT EXISTS `Reddit` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin ; +-- ----------------------------------------------------- +-- Schema reddit +-- ----------------------------------------------------- +DROP SCHEMA IF EXISTS `reddit` ; + +-- ----------------------------------------------------- +-- Schema reddit +-- ----------------------------------------------------- +CREATE SCHEMA IF NOT EXISTS `reddit` ; +USE `Reddit` ; + +-- ----------------------------------------------------- +-- Table `Reddit`.`Log` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `Reddit`.`Log` ; + +CREATE TABLE IF NOT EXISTS `Reddit`.`Log` ( + `utc` INT NOT NULL, + `username` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, + `action` VARCHAR(255) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, + PRIMARY KEY (`utc`)) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8 +COLLATE = utf8_bin; + + +-- ----------------------------------------------------- +-- Table `Reddit`.`Mafia` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `Reddit`.`Mafia` ; + +CREATE TABLE `Mafia` ( + `utc` int NOT NULL, + `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `team` int NOT NULL DEFAULT '-1', + `tier` int NOT NULL DEFAULT '0', + `loc` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `alive` int NOT NULL DEFAULT '1', + `diedOnCycle` int DEFAULT NULL, + `burn` int NOT NULL DEFAULT '1', + `revive` int NOT NULL DEFAULT '1', + `request` int NOT NULL DEFAULT '3', + `comment` int NOT NULL DEFAULT '0', + `inactive` int NOT NULL DEFAULT '0', + PRIMARY KEY (`utc`), + UNIQUE KEY `Mafiacol_UNIQUE` (`username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin + +CREATE UNIQUE INDEX `Mafiacol_UNIQUE` ON `Reddit`.`Mafia` (`username` ASC) VISIBLE; + + +-- ----------------------------------------------------- +-- Table `Reddit`.`VoteCall` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `Reddit`.`VoteCall` ; + +CREATE TABLE IF NOT EXISTS `Reddit`.`VoteCall` ( + `username` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, + `vote` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, + PRIMARY KEY (`username`)) +ENGINE = InnoDB +DEFAULT CHARACTER SET = utf8 +COLLATE = utf8_bin; + +CREATE UNIQUE INDEX `username_UNIQUE` ON `Reddit`.`VoteCall` (`username` ASC) VISIBLE; + +USE `reddit` ; +USE `Reddit` ; + +-- ----------------------------------------------------- +-- procedure role_cnt +-- ----------------------------------------------------- + +USE `Reddit`; +DROP procedure IF EXISTS `Reddit`.`role_cnt`; + +DELIMITER $$ +USE `Reddit`$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `role_cnt`() +BEGIN +SELECT team,COUNT(*) as cnt +FROM Mafia +GROUP BY team +ORDER BY team DESC; +END$$ + +DELIMITER ; + +-- ----------------------------------------------------- +-- procedure role_cnt_alive +-- ----------------------------------------------------- + +USE `Reddit`; +DROP procedure IF EXISTS `Reddit`.`role_cnt_alive`; + +DELIMITER $$ +USE `Reddit`$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `role_cnt_alive`() +BEGIN +SELECT team,COUNT(*) as cnt +FROM Mafia +WHERE alive=1 +GROUP BY team +ORDER BY team DESC; +END$$ + +DELIMITER ; +USE `reddit` ; + +-- ----------------------------------------------------- +-- Placeholder table for view `reddit`.`rolecnt` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `reddit`.`rolecnt` (`team` INT, `count` INT); + +-- ----------------------------------------------------- +-- View `reddit`.`rolecnt` +-- ----------------------------------------------------- +DROP TABLE IF EXISTS `reddit`.`rolecnt`; +DROP VIEW IF EXISTS `reddit`.`rolecnt` ; +USE `reddit`; +CREATE OR REPLACE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `Reddit`.`rolecnt` AS select `Reddit`.`Mafia`.`team` AS `team`,count(`Reddit`.`Mafia`.`team`) AS `count` from `Reddit`.`Mafia` where (`Reddit`.`Mafia`.`alive` = '1') group by `Reddit`.`Mafia`.`team` order by `Reddit`.`Mafia`.`team` desc; + +SET SQL_MODE=@OLD_SQL_MODE; +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; +SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; diff --git a/init/default_settings.json b/init/default_settings.json new file mode 100644 index 0000000..cceface --- /dev/null +++ b/init/default_settings.json @@ -0,0 +1,49 @@ +{ + "adminUsr": [ + "*SELF*" + ], + "clock": { + "hour1": 3, + "hour2": 9 + }, + "codes": [ + "123", + "456", + "789" + ], + "commands": { + "allowBotBroadcast": 1, + "addRequests": 3, + "addRequestsOn": 1, + "burnAfter": 7, + "burnQuietly": 3, + "escapeHit": 1, + "maxRequests": 3, + "reviveAfter": 1, + "unlockBurn": 2, + "unlockLocate": 2, + "unlockRequest": 0, + "unlockRevive": 3, + "unlockVote": 1, + "useThreshold": 1, + "voteOneAfter": 11, + "voteThreshold": 2 + }, + "flairID": { + "alive": "", + "dead": "" + }, + "kickAfter": 8, + "reddit": { + "praw": "", + "sub": "", + "targetPost": "" + }, + "sql": { + "database": "Reddit", + "host": "127.0.0.1", + "password": "", + "port": "3306", + "user": "" + } +} diff --git a/init/settings.json b/init/settings.json new file mode 100644 index 0000000..ca5534e --- /dev/null +++ b/init/settings.json @@ -0,0 +1,51 @@ +{ + "adminUsr": [ + "*SELF*", + "DozenIncBOT", + "goldenninjadragon" + ], + "clock": { + "hour1": 3, + "hour2": 9 + }, + "codes": [ + "SENSATIONAL-CHOCHOLATE-PISTOLS", + "A7J-3LX-GZ1", + "1836-0322-0935" + ], + "commands": { + "allowBotBroadcast": 1, + "addRequests": 3, + "addRequestsOn": 1, + "burnAfter": 7, + "burnQuietly": 3, + "escapeHit": 1, + "maxRequests": 3, + "reviveAfter": 1, + "unlockBurn": 2, + "unlockLocate": 2, + "unlockRequest": 0, + "unlockRevive": 3, + "unlockVote": 1, + "useThreshold": 1, + "voteOneAfter": 11, + "voteThreshold": 2 + }, + "flairID": { + "alive": "", + "dead": "" + }, + "kickAfter": 8, + "reddit": { + "praw": "DozenIncBOT", + "sub": "SomethingsNotRight", + "targetPost": "hoohm0" + }, + "sql": { + "database": "Reddit", + "host": "127.0.0.1", + "password": "684239715", + "port": "3306", + "user": "root" + } +} diff --git a/init/statements.json b/init/statements.json new file mode 100644 index 0000000..1763956 --- /dev/null +++ b/init/statements.json @@ -0,0 +1,334 @@ +{ + "alive": [ + "Dead", + "Alive", + "not playing", + "kicked for inactivity" + ], + "comment": { + "actions": { + "addUser": "u/{} has joined", + "addExistingUser": "u/{} has rejoined", + "burnUser": "u/{} was {} by u/{} for intelligence!", + "burnUserQuietly": "u/{} was {} by someone high in command for intelligence!", + "promote": "A player has been promoted to tier {}!", + "removeUser": "u/{} has left", + "requestUser": "A request for intel on u/{} has been filed by {}.", + "revive": "A player was revived.", + "schdWarn": "Round ending in {} minutes!" + }, + "spook": [ + "Trust no one.", + "There is darnkness in here.", + "If I killed everybody who betrayed me, there'd be no one left.", + "You Should Never Tell A Psychopath They Are A Psychopath. It Upsets Them.", + "You Should Really Ask Before You Touch A Person.", + "Traitors everywhere.", + "Betryal is inevitable.", + "Crack those codes!", + "Who's working for who?", + "Sometimes when you love someone you do crazy things.", + "Lies, Decaption, Deceit on every turn.", + "Back-stabbers, double-crossers, trouble-makers.", + "Spot the liars!", + "Tread carefully.", + "Actions have consequences.", + "It's a trap!", + "The rondevu point has moved.", + "Hmmm.", + "Are you sure about that?" + ], + "warn": { + "noVotes": [ + "Lazy, Lazy, Lazy", + "Shame", + "I should fire some of you", + "I think its time some of you left", + "Management Sucks", + "This is so borrriinnnngggg", + "It's quiet... A little *too* quiet", + "Hello?", + "I haven't heard anything in a while from our informant. This is worrying.", + "Comms have gone silent", + "Waiting for our informants to make contact", + "Awaiting orders", + "No new intelligence to report." + ], + "votes": [ + "This should be interesting", + "O_O", + "Who will betray who?", + "Watch out!", + "I Have To Kill You Now", + "Uh oh", + "Things are about to heat up", + "People are on the move", + "Things are happening in the shadows", + "The shadows are moving", + "An encrypted message was intercepted!", + "An annonomys tip was dropped", + "We have recieved the package", + "Our contact has made the signal. The exchange is happening.", + "Orders Recieved", + "Its getting spicy now!" + ] + } + }, + "deathMsg": [ + "Stabbed in the heart", + "Stabbed in the eye", + "Killed by blunt force trauma", + "Poisoned", + "Electrocuted", + "Strangled by a hose", + "Neck snapped with PJs on", + "Strung upside down and slit open", + "Suffocated by perfume", + "Stabbed by a pitchfork", + "Run over while reversing", + "Choked by an elevator", + "Pushed off a building", + "Burnt alive while sleeping", + "Clubbed on the head", + "Killed by bad tuning", + "Suffocated by powder", + "Drowned", + "Castrated", + "Chocked with a toilet brush", + "Killed by a mysterious heart attack", + "Axed in the back", + "Throat slit", + "Killed by a tiny chair", + "Run over by bus", + "Paralysed by neurotoxin", + "Chopped and boiled down", + "Fed to the pigs", + "Chopped and blended", + "Run over by train" + ], + "err": { + "alive": "The player is alive.", + "alreadyStarted": "The game has already started.", + "burnUsed": "You have already used your abulity to burn.", + "impFmt": "Invalid command input.", + "maxTier": "You have already reached the max tier available.", + "noBurnLeft": "There is no one left to burn on your or the other's team.", + "noBurnYet": "The burn command is not yet unlocked.", + "noParticipate": "To use this command, you must comment at least once per round to maintain active status. Users who become inactive for more than 2 days (4 rounds) will be kicked.", + "noRequestLeft": "You have used your alloted requests", + "notAlive": "The player is not alive", + "notFound": "Cannot find that user or the user is not playing in the game.\n\nNote: Usernames are case-sensitive.", + "notPM": "Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", + "notStarted": "The game has not started yet.", + "notUnlocked": "Command not authorized!.\n\nCrack more game codes to unlock this command.", + "reviveUsed": "You have already used your abulity to revive.", + "spec": "You are a spectator. You cannot use this command.", + "unkCmd": "Invalid Command. Type !help for a list of commands.", + "unkPM": "Unknown Command. Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", + "voteUser": "You already casted your vote for this round.", + "wrongCode": "Access Denied. Try Again." + }, + "flairs": { + "alive": "Mafia: Alive - Round {}", + "dead": "Mafia: {} on Round {}", + "survived": "{}: Survived to Round {}" + }, + "location": [ + [ + "London", + "Paris", + "Cuba", + "Not Cuba", + "Poland", + "Russia", + "Barcelona", + "Vienna", + "Spain", + "Berlin", + "Moscow", + "Amsterdam", + "Royal Albert Hall" + ], + [ + "London", + "Not Cuba", + "Poland", + "Russia", + "Barcelona", + "Tuscany", + "Vienna", + "Spain", + "New Malden", + "Moscow", + "Oxford", + "Royal Albert Hall", + "Scotland" + ] + ], + "preStm": { + "addDummy": "INSERT IGNORE INTO Mafia (`utc`,`username`,`team`,`alive`,`inactive`) VALUES ('0', 'DozenIncBOT', 2, 3,-999) ON DUPLICATE KEY UPDATE `username`=`username`,`team`=2, `alive`=3;", + "addUser": "INSERT IGNORE INTO Mafia (`utc`, `username`) VALUES (%s, %s) ON DUPLICATE KEY UPDATE `alive`='1';", + "addExistingUser": "UPDATE Mafia SET `alive`=1,`request`=%s WHERE `username`=%s;", + "burn": [ + "SELECT `username` FROM Mafia WHERE (`team`=0 AND `alive`=1 AND NOT `username`=%s);", + "SELECT `username` FROM Mafia WHERE (`team`=1 AND `alive`=1 AND NOT `username`=%s);", + "SELECT `username` FROM Mafia WHERE (`team`=1 AND `alive`=1);", + "SELECT `username` FROM Mafia WHERE (`team`=0 AND `alive`=1);", + "UPDATE Mafia SET `burn`=0 WHERE `username`=%s", + "UPDATE Mafia SET `alive`=0 WHERE `username`=%s" + ], + "chkBurn": "SELECT `username`,`team`,`tier` FROM Mafia WHERE (`username`=%s AND `burn`=1);", + "chkCmt": "SELECT `username` FROM Mafia WHERE (`username`=%s AND `comment`>=%s);", + "chkUsr": "SELECT `username`,`team`,`tier` FROM Mafia WHERE (`username`=%s AND (`alive`=0 or `alive`=1));", + "chkUsrState": "SELECT `team`,`tier`,`loc`,`alive`,`burn`,`revive`,`request` From Mafia WHERE `username`=%s", + "comment": "UPDATE Mafia SET `comment` = `comment` + 1 WHERE `username`=%s;", + "cycle": { + "getVotes": "SELECT DISTINCT `vote` From VoteCall", + "getVoteTarget": "SELECT `vote` FROM VoteCall WHERE `username`=%s;", + "getVoters": "SELECT `username` FROM VoteCall WHERE (NOT `username`=%s AND `vote`=%s);", + "voteEscaped": "UPDATE VoteCall SET `vote`='' WHERE `vote`=%s;", + "killPlayer": "UPDATE Mafia SET `alive`='0',`diedOnCycle`=%s WHERE username IN (SELECT vote FROM VoteCall GROUP BY VOTE HAVING COUNT(*) >= %s)", + "getAliveCnt":"SELECT (SELECT COUNT(team) FROM Mafia WHERE `alive`='1') AS alive, (SELECT COUNT(team) FROM Mafia WHERE (`alive`='0' AND NOT `username`='DozenIncBOT')) AS dead", + "getTeamCnt": "SELECT (SELECT COUNT(team) FROM Mafia WHERE (`alive`= 1 AND `team`=0)) AS TWELVE, (SELECT COUNT(team) FROM Mafia WHERE (`alive`= 1 AND `team`=1)) AS MI6", + "getDead": "SELECT v.vote,m.team,count(*) AS cnt FROM VoteCall v, Mafia m WHERE v.vote = m.username GROUP BY v.vote HAVING cnt >= %s ORDER BY cnt DESC;", + "getKilledMe": "SELECT `username` FROM VoteCall WHERE `vote`=%s", + "getAlive": "SELECT `username`,`team` FROM Mafia WHERE `alive`='1';", + "resetInactive": "UPDATE Mafia SET `inactive` = 0 WHERE (`comment`>0 AND `alive`=1);", + "incrementInactive": "UPDATE Mafia SET `inactive` = `inactive` + 1 WHERE (`comment`=0 AND `alive` = 1);", + "resetComment": "UPDATE Mafia SET `comment`=0 WHERE `comment`>0", + "getInactive": "SELECT username FROM Mafia WHERE (`inactive`>=%s AND `alive`=1);", + "removeInactive": "UPDATE Mafia SET `alive`=3 WHERE (`inactive`>=%s AND `alive`=1);" + }, + "digupUser": "SELECT `team`,`tier`,`alive` FROM Mafia WHERE (`username`=%s AND (`alive`=0 OR `alive`=1));", + "getAll": "SELECT `username` FROM Mafia WHERE ((`alive`=0 OR `alive`=1) AND NOT `username`='DozenIncBOT');", + "getDead": "SELECT `username`,`team` FROM Mafia WHERE `alive`=0;", + "getList": [ + "SELECT `username` FROM Mafia WHERE (`alive`=0 AND NOT `username`='DozenIncBOT') ORDER BY `username` asc;", + "SELECT `username` FROM Mafia WHERE `alive`=1 ORDER BY `username` asc;" + ], + "getPlaying": "SELECT `username` FROM Mafia WHERE (`alive`=1 AND NOT `username`='DozenIncBOT');", + "getWinner": "SELECT (SELECT COUNT(team) FROM Mafia WHERE (`alive`='1' AND `team`=0)) AS TWELVE, (SELECT COUNT(team) FROM Mafia WHERE (`alive`='1' AND `team`=1)) AS MI6", + "joinTeam": "UPDATE Mafia SET `team`=%s,`loc`=%s WHERE `username`=%s;", + "locateUser": "SELECT `loc` FROM Mafia WHERE `username`=%s;", + "log": "INSERT IGNORE INTO Log (`utc`,`username`,`action`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `utc`=`utc`;", + "main": [ + "SET SQL_SAFE_UPDATES = 0;", + "INSERT INTO Log (`utc`,`username`,`action`) VALUES (%s, '*SELF*', 'Game Initalized');" + ], + "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s WHERE `username`=%s;", + "request": [ + "SELECT `username`,`team` FROM Mafia WHERE `username`=%s AND `request`>0;", + "UPDATE Mafia SET `request`=`request` - 1 WHERE `username`=%s" + ], + "restart": "UPDATE Mafia SET `team`=-1,`tier`=0,`loc`=Null,`alive`=1,`burn`=1,`revive`=1,`request`=3,`comment`=0,`inactive`=0 WHERE (`alive`=0 or `alive`=1);", + "revive": [ + "SELECT `username` FROM Mafia WHERE `username`=%s AND `revive`=1;", + "SELECT `username` FROM Mafia WHERE `username`=%s AND `alive`=0;", + "UPDATE Mafia SET `revive`=0 WHERE `username`=%s", + "UPDATE Mafia SET `alive`=1 WHERE `username`=%s" + ], + "unlock": [ + "SELECT `tier`,`team` FROM Mafia WHERE `username`=%s;", + "UPDATE Mafia SET `tier` = `tier` + 1 WHERE `username`=%s;", + "UPDATE Mafia SET `request` = `request` + %s WHERE `username`=%s;" + ], + "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `username`=`username`;" + }, + "reply": { + "addRequests": "+{} Requests Added.", + "addUser": "Hello u/{}, you have joined the game!\n\nYour team will be assigned at the start of the game.\n\nType all commands here.\n\nYou can leave the game by replying !leave to this message. **You cannot rejoin once the game has started!**\n\nFor help type !help.\nType !rules for the rules.", + "burnUser": "You have burned u/{}!\n\nIntelligence Report:\n\nu/{} is {}", + "burnedUser": "You have been {} by u/{} on round {}!\n\nYou are now a spectator, but can haunt your killer from beyond the grave. Others can view how you died on your user flair.", + "burnedUserQuietly": "You have been {} by on round {}!\n\nSomeone higher up has decided to betray their own. You are now a spectator. Others can view how you died on your user flair.", + "cycle": [ + "**You Were Killed!**\n\nYou were \"{}\" on round {}.\nBy:\n{}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nThank you for playing. You are now a spectator. Others can view how you died on your user flair.", + "**You survived another day!**\n\nNow round {}.\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nHappy Hunting!", + "You were inactive for 48 hours and were automatically kicked from the game. Please wait until after the current game ends to rejoin.", + "You have escaped your hit! Take back revenge now!" + ], + "digupUser": [ + [ + "**Intelligence Report**\n\nu/{} is believed to be {} and is {}.\n\n^(This information is believed to be {}% credible.)" + ], + [ + "deceased", + "alive", + "not in the game", + "not in the game" + ] + ], + "gameEnd": "The game has ended. [**Check the game thread to see who won**](https://reddit.com/r/{}/comments/{})\n\nThank you for playing!\n\nIf you don't want to keep your game flair, you can change it back by clicking on the community options button.", + "gameStart": "The game has started.\n\n**You are with {} and are working in {}!**\nThere are {} players.\n\nInvestigate everyone around you and help your team survive! \n\n[Don't forget to introduce yourself.](https://reddit.com/r/{}/comments/{})\n\n^(You do not need to be present at all times to play. However, if you are inactive for more than 48 hours you will be kicked for inactivity.)", + "getList": "Total players: {}\n\nDead: {}\n{}\n\nAlive: {}\n{}", + "getSts": [ + [ + "**Current Stats**\n\nGame is {} on round {}.\n\nYou're a/an {} with {}.\nYour location is {}.\nYou are {}.\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* Burn after round {}\n* Vote threshold: {}\n* Single vote after round {}\n* Max requests: {}\n* Kick inactive after {} rounds" + ], + [ + "not active", + "active", + "over" + ], + [ + "Disabled", + "Enabled" + ] + ], + "hitAlertEsc": " Watch out u/{}! A hit has been put on you!. \n\nYou can escape this hit by correctly voting any of the people who put a hit on you.\n\nThis hit will expire after this round, round {}.", + "hitAlert": "Watch out u/{}! A hit has been put on you!. \n\nYou may try to convice others to change their vote or be killed! Higher ranking members have the ability to escape.\n\nThis hit will expire after this round, round {}.", + "locateUser": "u/{} is located at {}", + "promote": "Code Accepted!\n\nYou have been promoted to {}.", + "removeUser": "You have left the game. You can rejoin before the game starts.", + "requestUser": "Your info request has been posted.", + "reviveUser": "You have revived {}!", + "revivedUser": "You have been revived by u/{}!\n\nGet back into the game and win!", + "showHelp": "List of available commands:\n* !burn: Exposes one of your teammates randomly for a 100% credible Intelligence Report. Can only be used once\n* !digup USERNAME: Gather intelligence on a user.\n* !help: Shows help.\n* !join: Join the game.\n* !leave: Leave the game. You cannot rejoin once the game has started.\n* !list: Show all players.\n* !locate USERNAME: Shows the location of the user.\n* !request USERNAME: Ask for intel on a player. Limited number of uses.\n* !rules: Shows the rules.\n* !revive USERNAME: Bring back one user back from the dead. Can only be used once.\n* !stats: Shows current number of players.\n* !unlock CODE: Enter a code to level up your rank and gain new investigative powers.\n* !vote USERNAME: Vote on which user to be eliminated.", + "showRules": "Rules:\n1. Each user is assigned to either MI6 or the Twelve.\n2. You must investigate each other to determine who is on what side and eliminate the opponent.\n3. Decipher and decrypt the clues provided in order to advance your rank and unlock more powerful investigation tools.\n4. Vote out players who you suspect are the enemy. A player must receive a certain number of hits in order to be killed. After a certain amount of time, the number of votes required will be lowered to 1. Votes, aka hits, only last per round.\n4. At the end of each round, an announcement will be made how many people are alive how many were killed.\n5. You must choose your allies carefully to seek out the enemy.", + "voteUser": "Your vote has been locked in for this round." + }, + "teams": [ + [ + "The Twelve", + "MI6" + ], + [ + [ + "Trainee", + "Assassin", + "Handler", + "Keeper" + ], + [ + "Recruit", + "Analyst", + "Operative", + "Supervisor" + ] + ], + [ + [ + "a Trainee", + "an Assassin", + "a Handler", + "a Keeper" + ], + [ + "a Recruit", + "an Analyst", + "an Operative", + "a Supervisor" + ] + ] + ], + "sticky": { + "cycle": "It is now Round {}.\n\n* Alive: {}\n* MI6: {}\n* The Twelve: {}\n* Killed: {}\n* Total: {}", + "end": "The game has ended! Thanks for playing!\n\n**{} WINS!**\n* Survivors: {}\n* Killed: {}\n\nYou can choose to keep your flairs or remove them by clicking the Edit flair button in the community info tab.", + "halt": "The game has been halted! Please wait for further information about this interuption.", + "pause": "The game is not active.\n\nUsers can join or leave by [private messaging](https://www.reddit.com/message/compose/?to=DozenIncBOT) me with !join or !leave.\n\n[**Send Command Here**](https://www.reddit.com/message/compose/?to=DozenIncBOT)", + "rateLimit": "Attention the bot has reached its current rate limit.\n\nBot execution will be paused for {} seconds.", + "reset": "The game has ended and is being reset. Commands are no longer being read.\n\nPlease wait for further information.", + "restart": "The current game has ended and will be restarted. Teams will be reassigned on game start.\n\nPlease wait for further information.", + "round": "It is now **{}** on Round {}.\n\n* Alive: {}\n* MI6: {}\n* The Twelve: {}\n* Killed: {}\n* Total Players: {}\n\nGood Luck.", + "start": "The game has started with {} players.\n\nIntroduce yourself to each other and seek out the enemy." + } +} diff --git a/save.json b/save.json deleted file mode 100644 index bc0bf34..0000000 --- a/save.json +++ /dev/null @@ -1 +0,0 @@ -{"state": 0, "curCycle": 0, "curPos": 0} diff --git a/settings.json b/settings.json deleted file mode 100644 index 32d72b3..0000000 --- a/settings.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "adminUsr": [ - "*SELF*" - ], - "allowAllVote": 1, - "allowBotBroadcast": 1, - "allowBurnAfter": 7, - "allowJoinUptTo": 1, - "allowRevive": 0, - "allowVoteAnyTime": 1, - "clock": { - "hour1": 3, - "hour2": 9 - }, - "cmtThreshold": 0, - "flairID": { - "alive": "", - "dead": "" - }, - "kickAfter": 8, - "maxRequests": 3, - "praw": "DozenIncBOT", - "sql": { - "database": "Reddit", - "host": "127.0.0.1", - "password": "", - "port": "3306", - "user": "" - }, - "sub": "", - "targetPost": "", - "voteOneAfter": 11, - "voteThreshold": 1 -} diff --git a/statements.json b/statements.json deleted file mode 100644 index a67d5cd..0000000 --- a/statements.json +++ /dev/null @@ -1,242 +0,0 @@ -{ - "deathMsg": [ - "Stabbed in the heart", - "Stabbed in the eye", - "Killed by blunt force trauma", - "Poisoned", - "Electrocuted", - "Strangled by a hose", - "Neck snapped with PJs on", - "Strung upside down and slit open", - "Suffocated by perfume", - "Stabbed by a pitchfork", - "Run over while reversing", - "Choked by an elevator", - "Fell off a building", - "Burnt while sleeping", - "Clubbed on the head", - "Killed by bad tuning", - "Suffocated by powder", - "Drowned", - "Castrated", - "Chocked with a toilet brush", - "Had a mysterious heart attack", - "Axed in the back", - "Throat slit", - "Killed by tiny chair", - "Run over by bus", - "Paralysed by neurotoxin", - "Chopped and boiled down", - "Fed to the pigs", - "Chopped and blended", - "Run over by train" - ], - "flairs": { - "alive": "Mafia: Alive - Round {}", - "dead": "{}: {} on Round {}", - "survived": "{}: Survived to Round {}" - }, - "location": [ - [ - "London", - "Paris", - "Cuba", - "Not Cuba", - "Poland", - "Russia", - "Barcelona", - "Vienna", - "Spain", - "Berlin", - "Moscow", - "Amsterdam", - "Royal Albert Hall" - ], - [ - "London", - "Not Cuba", - "Poland", - "Russia", - "Barcelona", - "Tuscany", - "Vienna", - "Spain", - "New Malden", - "Moscow", - "Oxford", - "Royal Albert Hall", - "Scotland" - ] - ], - "preStm": { - "addDummy": "INSERT IGNORE INTO Mafia (`utc`,`username`,`role`,`alive`,`inactive`) VALUES ('0', 'DozenIncBOT', 'DUMMY', '0','-999') ON DUPLICATE KEY UPDATE `username`=`username`,`role`='DUMMY', `alive`='0';", - "burn": [ - "SELECT `username`,`role` FROM Mafia WHERE ((`role`='ASSASSIN' OR `role`='HANDLER') AND `alive`=1 AND NOT `username`=%s);", - "SELECT `username`,`role` FROM Mafia WHERE ((`role`='OPERATIVE' OR `role`='ANALYST') AND `alive`=1 AND NOT `username`=%s);", - "SELECT `username`,`role` FROM Mafia WHERE ((`role`='OPERATIVE' OR `role`='ANALYST') AND `alive`=1);", - "SELECT `username`,`role` FROM Mafia WHERE ((`role`='ASSASSIN' OR `role`='HANDLER') AND `alive`=1);", - "UPDATE Mafia SET `burn`=0 WHERE `username`=%s", - "UPDATE Mafia SET `alive`=0 WHERE `username`=%s" - ], - "addUser": "INSERT IGNORE INTO Mafia (`utc`,`username`,`role`, `loc`, `diedOnCycle`, `request`) VALUES (%s, %s, %s, %s, 0, %s) ON DUPLICATE KEY UPDATE `alive`=1,`diedOnCycle`=0, `request`=%s;", - "addExistingUser": "UPDATE Mafia SET `alive`=1,`request`=%s WHERE `username`=%s;", - "chkBurn": "SELECT `username`,`role` FROM Mafia WHERE (`username`=%s AND `burn`=1);", - "chkCmt": "SELECT `username` FROM Mafia WHERE (`username`=%s AND `comment`>%s);", - "chkUsr": "SELECT `username`,`role` FROM Mafia WHERE (`username`=%s AND `alive`=1);", - "chkUsrState": "SELECT `role`,`loc`,`alive`,`burn`,`revive`,`request` From Mafia WHERE `username`=%s", - "comment": "UPDATE Mafia SET `comment` = `comment` + 1 WHERE `username`=%s;", - "cycle": { - "getVotes": "SELECT DISTINCT `vote` From VoteCall", - "getVoteTarget": "SELECT `vote` FROM VoteCall WHERE `username`=%s;", - "getVoters": "SELECT `username` FROM VoteCall WHERE (NOT `username`=%s AND `vote`=%s);", - "voteEscaped": "UPDATE VoteCall SET `vote`='' WHERE `vote`=%s;", - "killPlayer": "UPDATE Mafia SET `alive`='0',`diedOnCycle`=%s WHERE username IN (SELECT vote FROM VoteCall GROUP BY VOTE HAVING COUNT(*) >= %s)", - "getAliveCnt":"SELECT (SELECT COUNT(role) FROM Mafia WHERE (`alive`='1')) AS alive, (SELECT COUNT(role) FROM Mafia WHERE (`alive`='0' AND NOT `username`='DozenIncBOT')) AS dead", - "getRoleCnt": "SELECT (SELECT COUNT(role) FROM Mafia WHERE `alive`= 1 AND (`role`='ASSASSIN' OR `role`='HANDLER')) AS A, (SELECT COUNT(role) FROM Mafia WHERE `alive`= 1 AND (`role`='OPERATIVE' OR `role`='ANALYST')) AS B", - "getDead": "SELECT v.vote,m.role,count(*) AS cnt FROM VoteCall v, Mafia m WHERE v.vote = m.username GROUP BY v.vote HAVING cnt >= %s ORDER BY cnt DESC;", - "getKilledMe": "SELECT `username` FROM VoteCall WHERE `vote`=%s", - "getAlive": "SELECT `username`,`role` FROM Mafia WHERE `alive`='1';", - "resetInactive": "UPDATE Mafia SET `inactive` = 0 WHERE (`comment`>0 AND `alive`=1);", - "incrementInactive": "UPDATE Mafia SET `inactive` = `inactive` + 1 WHERE (`comment`=0 AND `alive` = 1);", - "resetComment": "UPDATE Mafia SET `comment`=0 WHERE `comment`>0", - "getInactive": "SELECT username FROM Mafia WHERE (`inactive`>=%s AND `alive`=1);", - "removeInactive": "UPDATE Mafia SET `alive`=3 WHERE (`inactive`>=%s AND `alive`=1);" - }, - "digupUser": "SELECT `role`,`alive` FROM Mafia WHERE (`username`=%s AND (`alive`=0 OR `alive`=1));", - "getAll": "SELECT `username` FROM Mafia WHERE ((`alive`=0 OR `alive`=1) AND NOT `username`='DozenIncBOT');", - "getDead": "SELECT `username`,`role` FROM Mafia WHERE `alive`=0;", - "getList": [ - "SELECT `username`,`role` FROM Mafia WHERE (`alive`=0 AND NOT `username`='DozenIncBOT') ORDER BY `username` asc;", - "SELECT `username` FROM Mafia WHERE `alive`=1 ORDER BY `username` asc;" - ], - "getWinner": "SELECT (SELECT COUNT(role) FROM Mafia WHERE (`alive`='1' AND (`role`='OPERATIVE' OR `role`='ANALYST'))) AS MI6, (SELECT COUNT(role) FROM Mafia WHERE (`alive`='1' AND (`role`='ASSASSIN' OR `role`='HANDLER'))) AS TWELVE", - "leave": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s WHERE `username`=%s;", - "locateUser": "SELECT `loc` FROM Mafia WHERE (`username`=%s AND `alive`=1);", - "log": "INSERT IGNORE INTO Log (`utc`,`username`,`action`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `utc`=`utc`;", - "main": [ - "SET SQL_SAFE_UPDATES = 0;", - "INSERT INTO Log (`utc`,`username`,`action`) VALUES (%s, '*SELF*', 'Game Initalized');" - ], - "replaceUser": "REPLACE INTO Mafia (`utc`,`username`,`role`, `loc`) VALUES (%s, %s, %s, %s)", - "request": [ - "SELECT `username` FROM Mafia WHERE `username`=%s AND `request`>0;", - "UPDATE Mafia SET `request`=`request` - 1 WHERE `username`=%s" - ], - "restart": "UPDATE Mafia SET `loc`='London',`alive`='1',`diedOnCycle`=0,`burn`=1,`revive`=1,`request`=%s,`comment`=0,`inactive`=0;", - "revive": [ - "SELECT `username`,`role` FROM Mafia WHERE `username`=%s AND `revive`=1;", - "SELECT `username`,`role` FROM Mafia WHERE `username`=%s AND `alive`=0;", - "UPDATE Mafia SET `revive`=0 WHERE `username`=%s", - "UPDATE Mafia SET `alive`=1 WHERE `username`=%s" - ], - "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `vote`=%s;" - }, - "reply": { - "addUser": "Hello u/{}, you have joined the game!\n\nYour role is: *{}*.\nLocation: {}\n\nSHHHH!!! Don't tell anyone! [Leave a comment so people know you're playing.](https://reddit.com/r/{}/comments/{})\n\nType all commands here.\n\nYou can leave the game by replying !leave to this message. **You cannot rejoin once the game has started!**\n\nFor help type !help.\nType !rules for the rules.", - "burnUser": "You have burned a teammate!\n\nIntelligence Report:\n\nu/{} is a {}", - "burnedUser": "You have been exposed by u/{} on round {}!\n\nThank you for playing. You are now a spectator, but can haunt your killer from beyond the grave. Others can view how you died on your user flair.", - "cycle": [ - "**You Were Killed!**\n\nYou were \"{}\" on round {}.\nBy:\n{}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nThank you for playing. You are now a spectator. Others can view how you died on your user flair.", - "**You survived another day!**\n\nNow round {}.\n\nPlayers alive: {}\nPlayes killed:{}\nMI6 Agents Remaining: {}\nThe Twelve Remaining: {}\n\nHappy Hunting!", - "You were inactive for 48 hours and were automatically kicked from the game. Please wait until after the current game ends to rejoin.", - "You have escaped your hit! Take back revenge now!" - ], - "digupUser": "**Intelligence Report**\n\nu/{} is believed to be {} and is currently {}\n\n^(This information is believed to be {}% credible.)", - "digupUserBody": [ - [ - "an Assassin", - "a Handler", - "an Operative", - "an Analyst" - ], - [ - "deceased.", - "alive.", - "not in the game.", - "not in the game." - ] - ], - "err": { - "burnUsed": "You have already used your abulity to burn.", - "cycle": "You cannot vote at this time. It is currently {}", - "disallowRevive": "The revive command has been disabled for this game.", - "noBurnLeft": "There is no one left to burn", - "noBurnYet": "The burn command is not yet unlocked.", - "noParticipate": "To use this command, you must comment at least once per round to maintain active status. Users who become inactive for more than 2 days (4 rounds) will be kicked.", - "noRequestLeft": "You have used your alloted requests", - "notFound": "Cannot find user, the user is not playing in the game, or has been killed.", - "notPM": "Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", - "nmFmt": "Invalid username. Do not include the `u/` prefix", - "reviveUsed": "You have already used your abulity to revive.", - "role": "You cannot use this command in this role.", - "spec": "You are a spectator. You cannot use this command.", - "unkCmd": [ - [ - "Invalid Command. Type !help for a list of commands.\n\nNote: The game {}" - ], - [ - "has not yet started.", - "has already started.", - "has ended." - ] - ], - "unkPM": "Unknown Command. Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT)." - }, - "gameEnd": "The game has ended. [**Check the game thread to see who won**](https://reddit.com/r/{}/comments/{})\n\nThank you for playing!\n\nIf you don't want to keep your game flair, you can change it back by clicking on the community options button.", - "gamePause": "The game has been paused.\n\nPlease check the game thread more info.", - "gameStart": "The game has started.\n\nInvestigate everyone around you and help your team survive! Don't forget to introduce yourself.\n\nhttps://reddit.com/r/{}/comments/{}\n\nYou do not need to be present at all times to play. However, if you are inactive for more than 48 hours you will be kicked for inactivity.", - "getList": "Total players: {}\n\nDead: {}\n{}\n\nAlive: {}\n{}", - "getSts": [ - [ - "Current Stats:\n\nGame is {}.\nIt is {} on round {} (Cycle: {}).\n\nYour role is: {}\nYou are {}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* All roles can vote: {}\n* Vote anytime: {}\n* Revive: {}\n* Burn after cycle {}\n* Vote threshold: {}\n* Single vote after cycle {}\n* Max requests: {}\n* Kick inactive after {} cycles" - ], - [ - "not active", - "active", - "over" - ], - [ - "Disabled", - "Enabled" - ] - ], - "hitAlertEsc": " Watch out u/{}! A hit has been put on you!. \n\nYou can escape this hit, no matter how much is on your head, by correctly voting the person who put a hit on you.\n\nThis hit will expire after this cycle, cycle {}.", - "hitAlert": "Watch out u/{}! A hit has been put on you!. \n\nYou may try to convice others to change their vote or be killed!\n\nThis hit will expire after this cycle, cycle {}.", - "locateUser": "u/{} is located at {}", - "newGame": "Hello u/{}, a new game is starting.\n\nYour new role is: *{}*\n\nIf you wish to leave, type !leave. You cannot rejoin once the game has started.", - "removeUser": "You have left the game. You can rejoin before the game starts.", - "requestUser": "Your info request has been posted.", - "reviveUser": "You have revived {}!", - "revivedUser": "You have been revived by u/{}!\n\nGet back into the game and win!", - "showHelp": "List of available commands:\n* !burn: Exposes one of your teammates randomly for a 100% credible Intelligence Report. Can only be used once\n* !digup USERNAME: Gather intelligence on a user.\n* !help: Shows help.\n* !join: Join the game.\n* !leave: Leave the game. You cannot rejoin once the game has started.\n* !list: Show all players.\n* !locate USERNAME: Shows the location of the user.\n* !request USERNAME: Ask for intel on a player. Limited number of uses.\n* !rules: Shows the rules.\n* !revive USERNAME: Bring back one user back from the dead. Can only be used once.\n* !stats: Shows current number of players.\n* !vote USERNAME: Vote on which user to be eliminated.", - "showRules": "Rules:\n1. Each user is given a secret role. You cannot see each other’s roles. You may choose to bluff or try to be truthful. Introduce yourself at the beginning of the game to set the scene.\n2. You must investigate each other to determine who is on what side. You may work with each other outside of the game thread.\n3. During the Day, MI6 agents can investigate and kill users who they suspect are in The Twelve. During the Night, The Twelve can investigate and kill users who they suspect are in MI6. Each Cycle lasts 6 hours. 2 Day/Night rounds, 4 cycles per day.\n4. A user must receive at least 2 votes to be executed. Team members are not immune to each other. You may end up killing your own team members out of suspicion. Users who do not actively participate in the game thread may not use game commands.\n5. At the end of each cycle, an announcement will be made about how many people are alive and how many were killed.\n6.You must choose your allies carefully to seek out the enemy.", - "voteUser": "Your vote has been tallied. You can change your vote until the cycle ends." - }, - "roles": [ - [ - "ASSASSIN", - "HANDLER", - "OPERATIVE", - "ANALYST" - ], - { - "ASSASSIN": 0, - "HANDLER": 1, - "OPERATIVE": 2, - "ANALYST": 3 - } - ], - "sticky": { - "cycle": "It is now **{}** on Round {} (Cycle {}).\n\n* Alive: {}\n* MI6: {}\n* The Twelve: {}\n* Killed: {}\n* Total Players: {}\n\nGood Luck.", - "burnUser": "u/{} has burned their own member, u/{} for intelligence", - "end": "The game has ended! Thanks for playing!\n\n**{} WINS!**\n* Survivors: {}\n* Killed: {}\n\nYou can choose to keep your flairs or remove them by clicking the Edit flair button in the community info tab.", - "halt": "`Warning: HALT command recieved. Stopping processes.", - "pause": "The game is not active.\n\nUsers can join or leave by [private messaging](https://www.reddit.com/message/compose/?to=DozenIncBOT) me with !join or !leave.\n\n[**Send Command Here**](https://www.reddit.com/message/compose/?to=DozenIncBOT)", - "requestUser": "A request for intel on u/{} has been filed by u/{}.", - "reset": "The game has ended and is being reset. Commands are no longer being read.\n\nPlease wait for an announcement when the game has restarted.", - "restart": "The game has ended and is being restarted. Roles will be reassigned\n\nPlease wait for an announcement when the game has restarted.", - "revive": "A player was revived.", - "schdWarn": "Cycle ending in {} minutes!", - "start": "The game has started with {} players.\n\nIntroduce yourself to each other and seek out the enemy." - } -} diff --git a/strategy.md b/strategy.md index 3ed3037..aba28ae 100644 --- a/strategy.md +++ b/strategy.md @@ -7,15 +7,15 @@ While the game seems pretty simple in nature, there is much more at work than wh Intelligence can be gathered in five ways in this game. -1. `!digup`: The `digup` command will give an *Intelligence Report* on what a user's role is. However with any piece of intelligence, there is uncertainty to its reliability. *Assassins* and *Operatives* can use the `digup` command, but with greater unreliability. They must rely on *Handlers* and *Analysts* to aid them in obtaining reliable information. +1. `!digup`: The `digup` command will give an *Intelligence Report* on what a user's role is. However with any piece of intelligence, there is uncertainty to its reliability. Players with higher ranks will have increased accuracy. 2. `!locate`: The `locate` command gives the present location of a player. These locations have meaning tied to them based on the events of the Show. You may be able to determine what side someone is working for, but not their role, based on their location. -3. `!request`: The `request` command sends an anonymous request to the game thread for help obtaining intelligence on the user specified. *Anyone* can answer the request in the thread... *Anyone* could make up a report to throw other players off or to convince you to kill that person. +3. `!request`: The `request` command sends a request to the game thread for help obtaining intelligence on the user specified. *Anyone* can answer the request in the thread... *Anyone* could make up a report to throw other players off or to convince you to kill that person. 4. `!burn`: The `burn` command is the most effective and dangerous way to obtain information. It can only be used once and in the later stages of the game. This command will sacrifice one of your own members in exchange for 100% credible information about a member on the other team. There are severe consequences about this. By killing one of your own, you expose yourself to revenge and retribution. 5. Asking Directly: You can ask each other directly within the game thread or privately. Nothing is stopping them from lying to your face. ## Finding an Informant -A **critical** step in advancing through this game is finding an informant or even more than one. It is a very dangerous leap of faith trying to find someone you can tolerate to work with. That may require being a double agent and working with the enemy. *Assassins* and *Operatives* should definitely try to find a *Handler* or *Analyst* to get better intelligence. Having one more than one informant enables you to verify information is correct and eliminate those who may be feeding you bad info. +A **critical** step in advancing through this game is finding an informant or even more than one. It is a very dangerous leap of faith trying to find someone you can tolerate to work with. That may require being a double agent and working with the enemy. Having more than one informant enables you to verify information is correct and eliminate those who may be feeding you bad info. ## Going for the Kill