From f32aa8a2f5ca43311649f9339d28c06c838bb3b8 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 7 Jul 2020 18:55:21 -0400 Subject: [PATCH 01/26] Add new roles #16 --- statements.json | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/statements.json b/statements.json index a67d5cd..21a343c 100644 --- a/statements.json +++ b/statements.json @@ -212,19 +212,35 @@ "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": [ + "teams": [ [ - "ASSASSIN", - "HANDLER", - "OPERATIVE", - "ANALYST" + [ + "TRAINEE", + "ASSASSIN", + "HANDLER", + "KEEPER" + ], + [ + "RECRUIT", + "ANALYST", + "OPERATIVE", + "SUPERVISOR" + ] ], - { - "ASSASSIN": 0, - "HANDLER": 1, - "OPERATIVE": 2, - "ANALYST": 3 - } + [ + { + "TRAINEE": 0, + "ASSASSIN": 1, + "HANDLER": 2, + "KEEPER": 3 + }, + { + "RECRUIT": 0, + "ANALYST": 1, + "OPERATIVE": 2, + "SUPERVISOR": 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.", From 59576dfbdb7549646852e623bd8b38be8c0d52be Mon Sep 17 00:00:00 2001 From: Miko Jimenez Date: Tue, 7 Jul 2020 19:16:50 -0400 Subject: [PATCH 02/26] Update README.md --- README.md | 69 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index da83ce6..24a56b7 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 invesitgation tools. +4. Vote out players who you suspect are the enemy. A player must recieve 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.| +|The Twelve|Keeper|4|Revive unloced. Burn does not annoucne who you are.| +|MI6|Recriuit|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.| +|MI6|Supervisor|4|Revive unloced. Burn does not annoucne 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 be changed until the Round ends.|1| +|!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** From 12901eec6282494b2ff9284376cd97c519d0a686 Mon Sep 17 00:00:00 2001 From: Miko Jimenez Date: Tue, 7 Jul 2020 19:19:20 -0400 Subject: [PATCH 03/26] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 24a56b7..adea9b2 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Play against other members to find out who amongst each other you can trust and 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 invesitgation tools. -4. Vote out players who you suspect are the enemy. A player must recieve 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. +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. @@ -33,11 +33,11 @@ Play against other members to find out who amongst each other you can trust and |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.| -|The Twelve|Keeper|4|Revive unloced. Burn does not annoucne who you are.| -|MI6|Recriuit|1|Access to digup (low accuracy), vote, and max 3 requests.| +|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.| -|MI6|Supervisor|4|Revive unloced. Burn does not annoucne who you are.| +|MI6|Supervisor|4|Revive unlocked. Burn does not announce who you are.| **Commands** From a8c4658229445fc0ee6804b9545e1d223c40fc3d Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 8 Jul 2020 00:43:50 -0400 Subject: [PATCH 04/26] Reformat database --- database.sql | 260 +++++++++++++++++++++++++++++---------------------- 1 file changed, 146 insertions(+), 114 deletions(-) diff --git a/database.sql b/database.sql index 2da7502..915a808 100644 --- a/database.sql +++ b/database.sql @@ -1,114 +1,146 @@ --- 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 +-- 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 IF NOT EXISTS `Reddit`.`Mafia` ( + `utc` INT NOT NULL, + `username` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, + `team` INT NOT NULL, + `tier` INT NOT NULL DEFAULT '0', + `alive` INT NOT NULL DEFAULT '1', + `diedOnCycle` INT NULL 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`)) +ENGINE = InnoDB +DEFAULT CHARACTER SET = 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; From 9913078cbe44815e43eac5287607897c6033a1a9 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 8 Jul 2020 00:52:13 -0400 Subject: [PATCH 05/26] Fixed rolecnt view script --- database.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database.sql b/database.sql index 915a808..3b3e11f 100644 --- a/database.sql +++ b/database.sql @@ -139,7 +139,7 @@ CREATE TABLE IF NOT EXISTS `reddit`.`rolecnt` (`team` INT, `count` INT); 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; +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; From b8603c2fe810e1f8955982e63371a4ad9c773e8d Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 8 Jul 2020 01:16:36 -0400 Subject: [PATCH 06/26] Update settings and strings --- settings.json | 39 ++++++++++++++--------- statements.json | 82 ++++++++++++++++++++++++------------------------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/settings.json b/settings.json index 32d72b3..916e517 100644 --- a/settings.json +++ b/settings.json @@ -2,33 +2,44 @@ "adminUsr": [ "*SELF*" ], - "allowAllVote": 1, - "allowBotBroadcast": 1, - "allowBurnAfter": 7, - "allowJoinUptTo": 1, - "allowRevive": 0, - "allowVoteAnyTime": 1, + "allowJoinUptTo": 2, "clock": { "hour1": 3, "hour2": 9 }, - "cmtThreshold": 0, + "codes": + { + "tier1": "123", + "tier2": "456", + "tier3": "789" + }, + "commands": { + "allowBotBroadcast": 1, + "burnAfter": 7, + "maxRequests": 3, + "reviveAfter": 1, + "unlockBurn": 2, + "unlockLocate": 2, + "unlockRevive": 3, + "useThreshold": 1, + "voteOneAfter": 11, + "voteThreshold": 2 + }, "flairID": { "alive": "", "dead": "" }, "kickAfter": 8, - "maxRequests": 3, - "praw": "DozenIncBOT", + "reddit": { + "praw": "", + "sub": "", + "targetPost": "" + }, "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 index 21a343c..3fb2ecc 100644 --- a/statements.json +++ b/statements.json @@ -1,4 +1,18 @@ { + "comments": { + "actions": { + "burnUser": "u/{} has burned their own member, u/{} for intelligence", + "requestUser": "A request for intel on u/{} has been filed by u/{}.", + "revive": "A player was revived.", + "schdWarn": "Round ending in {} minutes!" + }, + "spook": [ + + ], + "warn": { + + } + }, "deathMsg": [ "Stabbed in the heart", "Stabbed in the eye", @@ -158,17 +172,15 @@ ], "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.", + "notFound": "Cannot find that user, the user is not playing in the game, or the user been killed.\n\nNote: Usernames are case-sensitive.", "notPM": "Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", - "nmFmt": "Invalid username. Do not include the `u/` prefix", + "notUnlocked": "Command not authorized!.\n\nCrack the game codes to unlock this command.", + "nmFmt": "Invalid username.", "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": [ [ @@ -180,7 +192,8 @@ "has ended." ] ], - "unkPM": "Unknown Command. Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT)." + "unkPM": "Unknown Command. Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", + "wrongCode": "Access Denied" }, "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.", @@ -188,7 +201,7 @@ "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" + "Current Stats:\n\nGame is {}.\nRound {}.\n\nYou're on {}'s team.'\nYour role is {}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* Burn after cycle {}\n* Vote threshold: {}\n* Single vote after cycle {}\n* Max requests: {}\n* Kick inactive after {} cycles" ], [ "not active", @@ -201,58 +214,45 @@ ] ], "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 {}.", + "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 round, round {}.", "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.", + "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* !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." + "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 tallied. You can change your vote until the round ends." }, "teams": [ + [ + "The Twelve", + "MI6" + ], [ [ - "TRAINEE", - "ASSASSIN", - "HANDLER", - "KEEPER" + "Trainee", + "Assassin", + "Handler", + "Keeper" ], [ - "RECRUIT", - "ANALYST", - "OPERATIVE", - "SUPERVISOR" + "Recruit", + "Analyst", + "Operative", + "Supervisor" ] - ], - [ - { - "TRAINEE": 0, - "ASSASSIN": 1, - "HANDLER": 2, - "KEEPER": 3 - }, - { - "RECRUIT": 0, - "ANALYST": 1, - "OPERATIVE": 2, - "SUPERVISOR": 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.", + "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)", - "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!", + "reset": "The game has ended and is being reset. Commands are no longer being read.\n\nPlease wait for further information.", + "restart": "The game has ended and is being restarted. Teams will be reassigned\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." } } From b9022571ec3520c7fc81a93a857188878244fd33 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 8 Jul 2020 12:06:47 -0400 Subject: [PATCH 07/26] Clean slate --- Mafia.py | 643 ++------------------ save.json => data/save.json | 0 database.sql => init/database.sql | 0 settings.json => init/default_settings.json | 0 init/settings.json | 45 ++ statements.json => init/statements.json | 80 +-- 6 files changed, 105 insertions(+), 663 deletions(-) rename save.json => data/save.json (100%) rename database.sql => init/database.sql (100%) rename settings.json => init/default_settings.json (100%) create mode 100644 init/settings.json rename statements.json => init/statements.json (67%) diff --git a/Mafia.py b/Mafia.py index 565d4fa..9732e4f 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,11 +23,11 @@ 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 @@ -34,8 +35,8 @@ def main(): 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) @@ -82,13 +83,12 @@ def wrapper(*args, **kwargs): 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) @@ -134,16 +134,13 @@ def gameState(state): 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']) + 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) + startGame() elif ((setState == '2') and (silent == None)): endGame() @@ -153,420 +150,45 @@ def gameState(state): @log_commit def addUser(curPos): - con.execute(stm['preStm']['chkUsrState'],(item.author.name,)) - result = con.fetchall() - - 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 - - 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)] - - 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 @log_commit def removeUser(): - con.execute(stm['preStm']['leave'], (curCycle, item.author.name)) - item.reply(stm['reply']['removeUser']) - sub.flair.delete(item.author) - reddit.submission(id=cfg['targetPost']).reply(f'u/{item.author.name} has left.') + pass @log_commit 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']['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']['digupUser'], (name,)) - r = con.fetchall() - - 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, name, name)) - success = con.rowcount - 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']) + pass @log_commit 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,)) - 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']['chkBurn'], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['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() - - if (len(r) <= 0): - item.reply(stm['reply']['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)] - - 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)) + pass @log_commit 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)) - - if (cfg['allowRevive'] == 0): - item.reply(stm['reply']['err']['disallowRevive']) - 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() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['reviveUsed']) - return -1 - - con.execute(stm['preStm']['revive'][1], (name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - 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']) + pass @log_commit 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']['digupUser'], (name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - return -1 - - 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 - else: - role = stm['roles'][1][r[0][0]] - - 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']) + pass @log_commit def locateUser(): - pattern = re.search(r'^!locate\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - 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 - - 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']['locateUser'], (name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['notFound']) - return -1 - - item.reply(stm['reply']['locateUser'].format(name, r[0][0])) - else: - item.reply(stm['reply']['err']['nmFmt']) + pass @log_commit def requestUser(): - pattern = re.search(r'^!request\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' - - 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']['request'][0], (item.author.name,)) - r = con.fetchall() - - if (len(r) <= 0): - item.reply(stm['reply']['err']['noRequestLeft']) - return -1 - - con.execute(stm['preStm']['digupUser'], (name,)) - r = con.fetchall() - - if ((len(r) <= 0) or (r[0][1]) == 0): - item.reply(stm['reply']['err']['notFound']) - return -1 - - 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)) - else: - item.reply(stm['reply']['err']['nmFmt']) + pass @log_commit - def getList(): - dead = '' - alive = '' - deadNum = 0 - 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]}' - - deadNum += 1 - - con.execute(stm['preStm']['getList'][1]) - result = con.fetchall() - - for row in result: - alive += f'\n* u/{row[0]}' - aliveNum += 1 - - item.reply(stm['reply']['getList'].format(deadNum + aliveNum, deadNum, dead, aliveNum, alive)) + def unlockTier(): + pass @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() - - if (len(result) == 1): - role = result[0][0] - user = result[0][1] - else: - role = 'spectator' - - 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] - - 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'])) + pass @log_commit def showHelp(): @@ -577,171 +199,12 @@ 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 - - random.seed(time.time()) - - if (curCycle > cfg['voteOneAfter']): - threshold = 1 - else: - threshold = cfg['voteThreshold'] - - 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: - 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]) - sleep(0.2) - - con.execute(stm['preStm']['cycle']['removeInactive'], (cfg['kickAfter'],)) - con.execute(stm['preStm']['cycle']['getVotes']) - result = con.fetchall() - - for row in result: - con.execute(stm['preStm']['chkUsr'], (row[0],)) - role = con.fetchall() - 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])) - 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')) - 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') - - con.execute(stm['preStm']['cycle']['killPlayer'], (curCycle, threshold)) - 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']['cycle']['getRoleCnt']) - result = con.fetchall() - bad = result[0][0] - good = result[0][1] - - print(f'MI6 remaining: {good}') - print(f'The Twelve remaining: {bad}') - - con.execute(stm['preStm']['cycle']['getDead'], (threshold,)) - result = con.fetchall() - for row in result: - 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.' - - 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)) - con.execute(stm['preStm']['log'], (time.time(), row[0], 'Killed')) - print(f' > {target[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']) - 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)) + def startGame(): + comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['start']) 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) - 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): @@ -749,9 +212,15 @@ def endGame(): else: winner = 'The Twelve' - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['end'].format(winner, alive, killed)) + 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): + curCycle = round + save(state, curCycle, curPos) + return curCycle + @log_commit def broadcast(): if (cfg['allowBotBroadcast'] == 0): @@ -763,7 +232,7 @@ def broadcast(): if (item.author.name not in cfg['adminUsr']): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: broadcast')) - return + return -1 else: con.execute(stm['preStm']['getAll']) result = con.fetchall() @@ -778,39 +247,9 @@ 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 + return -1 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) - - 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) + # Re assign teams if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') print('REMOTE RESTART RECEIVED') @@ -823,7 +262,7 @@ 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 + return -1 else: con.execute('SELECT `username` FROM Mafia') result = con.fetchall() @@ -835,7 +274,7 @@ def reset(): 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 = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['reset']) comment.mod.distinguish(how='yes', sticky=True) save(0, 0, 0) @@ -850,9 +289,9 @@ 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 + return -1 else: - comment = reddit.submission(id=cfg['targetPost']).reply(stm['sticky']['halt']) + 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;') @@ -868,6 +307,8 @@ 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}') @@ -875,8 +316,6 @@ def halt(): print(f'curPos: {curPos}') print('______') - scheduleJobs() - while True: if (state == 1): schedule.run_pending() @@ -886,7 +325,7 @@ def halt(): if comment is None: break - if ((comment.submission.id == cfg['targetPost']) and (comment.id not in cache)): + if ((comment.submission.id == cfg['reddit']['targetPost']) and (comment.id not in cache)): if (len(cache) > 1000): cache = [] @@ -926,6 +365,8 @@ def halt(): locateUser() elif ((re.search(r'^!request', item.body)) and (state == 1)): requestUser() + elif ((re.search(r'^!unlock', item.body)) and (state == 1)): + unlockTier() elif ((re.search(r'^!list', item.body))): getList() elif (re.search(r'^!stats', item.body)): @@ -961,7 +402,7 @@ def halt(): con.close() def save(state, curCycle, curPos): - with open('save.json', 'r+') as jsonFile2: + with open('data/save.json', 'r+') as jsonFile2: tmp = json.load(jsonFile2) tmp['state'] = int(state) tmp['curCycle'] = int(curCycle) diff --git a/save.json b/data/save.json similarity index 100% rename from save.json rename to data/save.json diff --git a/database.sql b/init/database.sql similarity index 100% rename from database.sql rename to init/database.sql diff --git a/settings.json b/init/default_settings.json similarity index 100% rename from settings.json rename to init/default_settings.json diff --git a/init/settings.json b/init/settings.json new file mode 100644 index 0000000..916e517 --- /dev/null +++ b/init/settings.json @@ -0,0 +1,45 @@ +{ + "adminUsr": [ + "*SELF*" + ], + "allowJoinUptTo": 2, + "clock": { + "hour1": 3, + "hour2": 9 + }, + "codes": + { + "tier1": "123", + "tier2": "456", + "tier3": "789" + }, + "commands": { + "allowBotBroadcast": 1, + "burnAfter": 7, + "maxRequests": 3, + "reviveAfter": 1, + "unlockBurn": 2, + "unlockLocate": 2, + "unlockRevive": 3, + "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/statements.json b/init/statements.json similarity index 67% rename from statements.json rename to init/statements.json index 3fb2ecc..e065560 100644 --- a/statements.json +++ b/init/statements.json @@ -7,7 +7,7 @@ "schdWarn": "Round ending in {} minutes!" }, "spook": [ - + ], "warn": { @@ -83,66 +83,12 @@ ] ], "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);", + "addDummy": "INSERT IGNORE INTO Mafia (`utc`,`username`,`team`,`alive`,`inactive`) VALUES ('0', 'DozenIncBOT', 'DUMMY', '0','-999') ON DUPLICATE KEY UPDATE `username`=`username`,`role`='DUMMY', `alive`='0';", "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": { @@ -155,13 +101,23 @@ "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": [ + "digupUser": [ [ - "an Assassin", - "a Handler", - "an Operative", - "an Analyst" + "**Intelligence Report**\n\nu/{} is believed to be {} and is currently {}\n\n^(This information is believed to be {}% credible.)" + ], + [ + [ + "is a Trainee", + "is an Assassin", + "is a Handler", + "is a Keeper" + ], + [ + "is a Recruit", + "is an Analyst", + "is an Operative", + "is a Supervisor" + ] ], [ "deceased.", From a0e83b5aab8c5aa684e13ba4fbea46cc5f6a389b Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sat, 11 Jul 2020 04:04:51 -0400 Subject: [PATCH 08/26] Complete user join/leave and gameState 0 and 1 func. Cache PM replies. --- .gitignore | 1 + Mafia.py | 155 +++++++++++++++++++++++++++---------- data/save.json | 2 +- init/database.sql | 42 +++++----- init/default_settings.json | 3 +- init/settings.json | 15 ++-- init/statements.json | 73 +++++++++-------- 7 files changed, 188 insertions(+), 103 deletions(-) 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 9732e4f..dc73259 100644 --- a/Mafia.py +++ b/Mafia.py @@ -33,7 +33,6 @@ def main(): exceptCnt = 0 state = sve['state'] curCycle = sve['curCycle'] - curPos = sve['curPos'] reddit = praw.Reddit(cfg['reddit']['praw']) sub = reddit.subreddit(cfg['reddit']['sub']) @@ -44,7 +43,8 @@ def main(): pool = db.get_connection() con = pool.cursor(prepared=True) - cache = [] + idCache = [] + itemCache = {} lastCmd = '' def log_commit(func): @@ -121,42 +121,45 @@ def gameState(state): pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-s)?', item.body) setState = 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']) - sleep(0.2) - 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)): - startGame() + gameStart() elif ((setState == '2') and (silent == None)): - endGame() + 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): - curPos += 1 - save(state, curCycle, curPos) - return curPos + def addUser(): + con.execute(stm['preStm']['chkUsrState'],(item.author.name,)) + result = con.fetchall() + + if(len(result) > 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: + 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)) + + sub.flair.set(item.author, text=stm['flairs']['alive'].format(1), flair_template_id=cfg['flairID']['alive']) + item.reply(stm['reply']['addUser'].format(item.author.name)) + setItems(item.author.name, item) @log_commit def removeUser(): - pass + 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) + setItems(item.author.name, None) @log_commit def voteUser(): @@ -199,12 +202,44 @@ def showRules(): item.reply(stm['reply']['showRules']) @log_commit - def startGame(): - comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['start']) + def gameStart(): + con.execute(stm['preStm']['getPlaying']) + result = con.fetchall() + players = len(result) + curPos = 0 + + random.seed(time.time()) + random.shuffle(result) + + for row in result: + team = curPos % 2 + + random.seed(time.time()) + if team: + 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']['joinTeam'], (team, loc, row[0])) + getItems(row[0]).reply(stm['reply']['gameStart'].format(stm['teams'][0][team], loc, players, cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + 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) + sleep(reset) + + 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 endGame(): + def gameEnd(): if (good == bad): winner = 'NOBODY' elif (good > bad): @@ -218,15 +253,11 @@ def endGame(): @log_commit def cycle(curCycle): curCycle = round - save(state, curCycle, curPos) + save(state, curCycle) return curCycle @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) @@ -234,11 +265,24 @@ def broadcast(): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: broadcast')) return -1 else: + if (cfg['allowBotBroadcast'] == 0): + item.reply('Broadcast Disabled') + return + con.execute(stm['preStm']['getAll']) result = con.fetchall() - for row in result: - reddit.redditor(row[0]).message('Announcement', msg) + getItems(row[0]).reply(msg) + 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) + sleep(reset) + sleep(0.2) @log_commit @@ -313,7 +357,6 @@ def halt(): print(f'Database Connections: {len(conStat)}') print(f'state: {state}') print(f'curCycle: {curCycle} (Cycle: {curCycle + 1})') - print(f'curPos: {curPos}') print('______') while True: @@ -325,14 +368,14 @@ def halt(): if comment is None: break - if ((comment.submission.id == cfg['reddit']['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['error']['notPM']) - cache.append(comment.id) + idCache.append(comment.id) con.execute(stm['preStm']['comment'], (comment.author.name,)) con.execute('COMMIT;') @@ -349,8 +392,8 @@ 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)) and (state == 0)): + addUser() elif (re.search(r'^!leave', item.body)): removeUser() elif ((re.search(r'^!vote', item.body)) and (state == 1)): @@ -388,7 +431,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['error']['unkCmd'][0][0].format(stm['error']['unkCmd'][1][state])) item.mark_read() lastCmd = item.body.strip() @@ -401,16 +444,46 @@ def halt(): con.close() -def save(state, curCycle, curPos): +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): + try: + with open('data/items.pickle', 'rb') as itemsFile: + tmp = pickle.load(itemsFile) + + if v == None: + tmp.pop(k, None) + else: + tmp[k] = v + + pickle.dump(tmp, itemsFile) + except Exception as e: + tmp = {} + + if v == None: + tmp.pop(k, None) + else: + tmp[k] = v + + pickle.dump(tmp, open('data/items.pickle', 'wb')) + +def getItems(k): + try: + with open('data/items.pickle', 'rb') as itemsFile: + tmp = pickle.load(itemsFile) + return tmp[k] + except Exception as e: + tmp = {} + pickle.dump(tmp, open('data/items.pickle', 'wb')) + return None + def exit_gracefully(signum, frame): signal.signal(signal.SIGINT, original_sigint) diff --git a/data/save.json b/data/save.json index bc0bf34..f122f18 100644 --- a/data/save.json +++ b/data/save.json @@ -1 +1 @@ -{"state": 0, "curCycle": 0, "curPos": 0} +{"state": 1, "curCycle": 0} \ No newline at end of file diff --git a/init/database.sql b/init/database.sql index 3b3e11f..0b3088f 100644 --- a/init/database.sql +++ b/init/database.sql @@ -50,22 +50,22 @@ COLLATE = utf8_bin; -- ----------------------------------------------------- DROP TABLE IF EXISTS `Reddit`.`Mafia` ; -CREATE TABLE IF NOT EXISTS `Reddit`.`Mafia` ( - `utc` INT NOT NULL, - `username` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL, - `team` INT NOT NULL, - `tier` INT NOT NULL DEFAULT '0', - `alive` INT NOT NULL DEFAULT '1', - `diedOnCycle` INT NULL 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`)) -ENGINE = InnoDB -DEFAULT CHARACTER SET = utf8 -COLLATE = utf8_bin; +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; @@ -99,9 +99,9 @@ DELIMITER $$ USE `Reddit`$$ CREATE DEFINER=`root`@`localhost` PROCEDURE `role_cnt`() BEGIN -SELECT team,COUNT(*) as cnt -FROM Mafia -GROUP BY team +SELECT team,COUNT(*) as cnt +FROM Mafia +GROUP BY team ORDER BY team DESC; END$$ @@ -118,10 +118,10 @@ DELIMITER $$ USE `Reddit`$$ CREATE DEFINER=`root`@`localhost` PROCEDURE `role_cnt_alive`() BEGIN -SELECT team,COUNT(*) as cnt +SELECT team,COUNT(*) as cnt FROM Mafia WHERE alive=1 -GROUP BY team +GROUP BY team ORDER BY team DESC; END$$ diff --git a/init/default_settings.json b/init/default_settings.json index 916e517..f625424 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -2,7 +2,6 @@ "adminUsr": [ "*SELF*" ], - "allowJoinUptTo": 2, "clock": { "hour1": 3, "hour2": 9 @@ -17,7 +16,7 @@ "allowBotBroadcast": 1, "burnAfter": 7, "maxRequests": 3, - "reviveAfter": 1, + "reviveAfter": 11, "unlockBurn": 2, "unlockLocate": 2, "unlockRevive": 3, diff --git a/init/settings.json b/init/settings.json index 916e517..c7ad3a6 100644 --- a/init/settings.json +++ b/init/settings.json @@ -1,8 +1,9 @@ { "adminUsr": [ - "*SELF*" + "*SELF*", + "DozenIncBOT", + "goldenninjadragon" ], - "allowJoinUptTo": 2, "clock": { "hour1": 3, "hour2": 9 @@ -31,15 +32,15 @@ }, "kickAfter": 8, "reddit": { - "praw": "", - "sub": "", - "targetPost": "" + "praw": "DozenIncBOT", + "sub": "SomethingsNotRight", + "targetPost": "hoohm0" }, "sql": { "database": "Reddit", "host": "127.0.0.1", - "password": "", + "password": "684239715", "port": "3306", - "user": "" + "user": "root" } } diff --git a/init/statements.json b/init/statements.json index e065560..a96672d 100644 --- a/init/statements.json +++ b/init/statements.json @@ -1,7 +1,10 @@ { - "comments": { + "comment": { "actions": { + "addUser": "u/{} has joined", + "addExistingUser": "u/{} has rejoined", "burnUser": "u/{} has burned their own member, u/{} for intelligence", + "removeUser": "u/{} has left", "requestUser": "A request for intel on u/{} has been filed by u/{}.", "revive": "A player was revived.", "schdWarn": "Round ending in {} minutes!" @@ -45,6 +48,31 @@ "Chopped and blended", "Run over by train" ], + "error": { + "burnUsed": "You have already used your abulity to burn.", + "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 that user, the user is not playing in the game, or the user been killed.\n\nNote: Usernames are case-sensitive.", + "notPM": "Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", + "notUnlocked": "Command not authorized!.\n\nCrack the game codes to unlock this command.", + "nmFmt": "Invalid username.", + "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.\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).", + "wrongCode": "Access Denied" + }, "flairs": { "alive": "Mafia: Alive - Round {}", "dead": "{}: {} on Round {}", @@ -83,16 +111,24 @@ ] ], "preStm": { - "addDummy": "INSERT IGNORE INTO Mafia (`utc`,`username`,`team`,`alive`,`inactive`) VALUES ('0', 'DozenIncBOT', 'DUMMY', '0','-999') ON DUPLICATE KEY UPDATE `username`=`username`,`role`='DUMMY', `alive`='0';", + "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;", + "chkUsrState": "SELECT `team`,`tier`,`loc`,`alive`,`burn`,`revive`,`request` From Mafia WHERE `username`=%s", + "comment": "UPDATE Mafia SET `comment` = `comment` + 1 WHERE `username`=%s;", + "getAll": "SELECT `username` FROM Mafia WHERE ((`alive`=0 OR `alive`=1) AND NOT `username`='DozenIncBOT');", + "getPlaying": "SELECT `username` FROM Mafia WHERE (`alive`=1 AND NOT `username`='DozenIncBOT');", + "joinTeam": "UPDATE Mafia SET `team`=%s,`loc`=%s 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;", "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.", + "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 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": [ @@ -126,38 +162,12 @@ "not in the game." ] ], - "err": { - "burnUsed": "You have already used your abulity to burn.", - "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 that user, the user is not playing in the game, or the user been killed.\n\nNote: Usernames are case-sensitive.", - "notPM": "Please enter commands through [private message](https://www.reddit.com/message/compose/?to=DozenIncBOT).", - "notUnlocked": "Command not authorized!.\n\nCrack the game codes to unlock this command.", - "nmFmt": "Invalid username.", - "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.\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).", - "wrongCode": "Access Denied" - }, "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.", + "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! 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 {}.\nRound {}.\n\nYou're on {}'s team.'\nYour role is {}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* Burn after cycle {}\n* Vote threshold: {}\n* Single vote after cycle {}\n* Max requests: {}\n* Kick inactive after {} cycles" + "Current Stats:\n\nGame is {}.\nRound {}.\n\nYou're on {}'s team.'\nYour rank tier is {}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* Burn after cycle {}\n* Vote threshold: {}\n* Single vote after cycle {}\n* Max requests: {}\n* Kick inactive after {} cycles" ], [ "not active", @@ -206,6 +216,7 @@ "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 game has ended and is being restarted. Teams will be reassigned\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.", From 502245ec7fec3876b8281056a53502219090039a Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sat, 11 Jul 2020 14:49:41 -0400 Subject: [PATCH 09/26] Close #17 and completed admin functions --- Mafia.py | 99 ++++++++++++++++++++++++++++++-------------- data/save.json | 2 +- init/statements.json | 25 +++++++++-- 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/Mafia.py b/Mafia.py index dc73259..e96b1e9 100644 --- a/Mafia.py +++ b/Mafia.py @@ -118,7 +118,7 @@ def scheduleJobs(): @log_commit def gameState(state): - pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-s)?', item.body) + pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-[sS])?', item.body) setState = pattern.group(1) silent = pattern.group(2) @@ -215,23 +215,10 @@ def gameStart(): team = curPos % 2 random.seed(time.time()) - if team: - 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)] - + loc = stm['location'][team][random.randint(0, len(stm['location'][team]) - 1)] con.execute(stm['preStm']['joinTeam'], (team, loc, row[0])) getItems(row[0]).reply(stm['reply']['gameStart'].format(stm['teams'][0][team], loc, players, cfg['reddit']['sub'], cfg['reddit']['targetPost'])) - 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) - sleep(reset) - + rateLimit(reddit) curPos += 1 sleep(0.2) @@ -240,6 +227,50 @@ def gameStart(): @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'],)) + 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}') + + if (cfg['commands']['allowBotBroadcast'] == 1): + con.execute(stm['preStm']['getDead']) + result = con.fetchall() + + for row in result: + getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + rateLimit(reddit) + sleep(0.2) + + con.execute(stm['preStm']['cycle']['getAlive']) + result = con.fetchall() + + for row in result: + if (cfg['commands']['allowBotBroadcast'] == 1): + getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) + rateLimit(reddit) + + 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']) + result = con.fetchall() + bad = result[0][0] + good = result[0][1] + if (good == bad): winner = 'NOBODY' elif (good > bad): @@ -265,7 +296,7 @@ def broadcast(): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: broadcast')) return -1 else: - if (cfg['allowBotBroadcast'] == 0): + if (cfg['commands']['allowBotBroadcast'] == 0): item.reply('Broadcast Disabled') return @@ -273,16 +304,7 @@ def broadcast(): result = con.fetchall() for row in result: getItems(row[0]).reply(msg) - 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) - sleep(reset) - + rateLimit(reddit) sleep(0.2) @log_commit @@ -293,9 +315,14 @@ def restart(): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: restart')) return -1 else: - # Re assign teams + 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**') + if (item.author.name != '*SELF*'): item.reply('**Restarting Game**') print('REMOTE RESTART RECEIVED') con.close() os._exit(1) @@ -320,7 +347,8 @@ def 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, 0) + save(0, 0) + os.remove('data/items.pickle') if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') print('REMOTE RESET RECEIVED') @@ -444,6 +472,17 @@ def halt(): con.close() +def rateLimit(reddit): + 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) + sleep(reset) + def save(state, curCycle): with open('data/save.json', 'r+') as jsonFile2: tmp = json.load(jsonFile2) diff --git a/data/save.json b/data/save.json index f122f18..50745ad 100644 --- a/data/save.json +++ b/data/save.json @@ -1 +1 @@ -{"state": 1, "curCycle": 0} \ No newline at end of file +{"state": 2, "curCycle": 0} \ No newline at end of file diff --git a/init/statements.json b/init/statements.json index a96672d..d730ca0 100644 --- a/init/statements.json +++ b/init/statements.json @@ -116,8 +116,27 @@ "addExistingUser": "UPDATE Mafia SET `alive`=1,`request`=%s WHERE `username`=%s;", "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);" + }, "getAll": "SELECT `username` FROM Mafia WHERE ((`alive`=0 OR `alive`=1) AND NOT `username`='DozenIncBOT');", + "getDead": "SELECT `username`,`team` FROM Mafia WHERE `alive`=0;", "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;", "log": "INSERT IGNORE INTO Log (`utc`,`username`,`action`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `utc`=`utc`;", "main": [ @@ -125,6 +144,7 @@ "INSERT INTO Log (`utc`,`username`,`action`) VALUES (%s, '*SELF*', 'Game Initalized');" ], "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s 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);", "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `vote`=%s;" }, "reply": { @@ -163,7 +183,7 @@ ] ], "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! 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.", + "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": [ [ @@ -182,7 +202,6 @@ "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 round, round {}.", "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.", "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.", @@ -218,7 +237,7 @@ "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 game has ended and is being restarted. Teams will be reassigned\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." } From f4b6dd74c775d188456e694988259bd9cfcba580 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sat, 11 Jul 2020 22:03:56 -0400 Subject: [PATCH 10/26] Minor fixes --- Mafia.py | 6 +++++- data/save.json | 2 +- init/statements.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Mafia.py b/Mafia.py index e96b1e9..2f4373e 100644 --- a/Mafia.py +++ b/Mafia.py @@ -348,7 +348,11 @@ def reset(): comment = reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['sticky']['reset']) comment.mod.distinguish(how='yes', sticky=True) save(0, 0) - os.remove('data/items.pickle') + + try: + os.remove('data/items.pickle') + except: + pass if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') print('REMOTE RESET RECEIVED') diff --git a/data/save.json b/data/save.json index 50745ad..2d35f5b 100644 --- a/data/save.json +++ b/data/save.json @@ -1 +1 @@ -{"state": 2, "curCycle": 0} \ No newline at end of file +{"state": 0, "curCycle": 0} \ No newline at end of file diff --git a/init/statements.json b/init/statements.json index d730ca0..c5ddd88 100644 --- a/init/statements.json +++ b/init/statements.json @@ -233,7 +233,7 @@ ], "sticky": { "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.", + "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.", From 814b9c90599910b406e0c1f734b8b2c18fb562c7 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sun, 12 Jul 2020 11:32:38 -0400 Subject: [PATCH 11/26] Command error handling --- Mafia.py | 228 +++++++++++++++++++++++-------------- README.md | 4 +- init/default_settings.json | 1 + init/settings.json | 1 + init/statements.json | 21 ++-- 5 files changed, 155 insertions(+), 100 deletions(-) diff --git a/Mafia.py b/Mafia.py index 2f4373e..92c13f2 100644 --- a/Mafia.py +++ b/Mafia.py @@ -83,6 +83,44 @@ 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/)?([A-Za-z0-9_]{1,20})', item.body) + name = '' + + if (state == 0): + item.reply(stm['err']['notStarted']) + return -1 + + if pattern: + name = pattern.group(3) + else: + item.reply(stm['err']['nmFmt']) + return -1 + + try: + 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 + + con.execute(stm['preStm']['digupUser'], (name,)) + r = con.fetchall() + + if (len(r) <= 0): + item.reply(stm['err']['notFound']) + return -1 + + except mysql.connector.Error as e: + print(f'SQL EXCEPTION @ {func.__name__} : {args} - {kwargs}\n{e}') + con.close() + os._exit(-1) + return + return wrapper + def schdWarn(min=00): reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['schdWarn'].format(min)) print(f'Cycle Warning {min}') @@ -119,19 +157,19 @@ def scheduleJobs(): @log_commit def gameState(state): pattern = re.search(r'^!GAMESTATE\s([0-9]{1,1})(\s-[sS])?', item.body) - setState = pattern.group(1) + setState = int(pattern.group(1)) silent = pattern.group(2) 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: - if ((setState == '0') and (silent == None)): + 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)): + elif ((setState == 1) and (silent == None)): gameStart() - elif ((setState == '2') and (silent == None)): + elif ((setState == 2) and (silent == None)): gameEnd() if (item.author.name != '*SELF*'): item.reply(f'**gamestate changed to {setState}**') @@ -140,10 +178,14 @@ def gameState(state): @log_commit def addUser(): + if (state == 1): + item.reply(stm['err']['alreadyStarted']) + return -1 + con.execute(stm['preStm']['chkUsrState'],(item.author.name,)) - result = con.fetchall() + r = con.fetchall() - if(len(result) > 0): + 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: @@ -162,34 +204,42 @@ def removeUser(): setItems(item.author.name, None) @log_commit + @game_command def voteUser(): pass @log_commit + @game_command def burnUser(): pass @log_commit + @game_command def reviveUser(): pass @log_commit + @game_command def digupUser(): pass @log_commit + @game_command def locateUser(): pass @log_commit + @game_command def requestUser(): pass @log_commit + @game_command def unlockTier(): pass @log_commit + @game_command def getStats(): pass @@ -204,14 +254,14 @@ def showRules(): @log_commit def gameStart(): con.execute(stm['preStm']['getPlaying']) - result = con.fetchall() - players = len(result) + r = con.fetchall() + players = len(r) curPos = 0 random.seed(time.time()) - random.shuffle(result) + random.shuffle(r) - for row in result: + for row in r: team = curPos % 2 random.seed(time.time()) @@ -232,33 +282,33 @@ def gameEnd(): con.execute(stm['preStm']['cycle']['incrementInactive']) con.execute(stm['preStm']['cycle']['resetComment']) con.execute(stm['preStm']['cycle']['getInactive'], (cfg['kickAfter'],)) - result = con.fetchall() + r = con.fetchall() - for row in result: + 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']) - result = con.fetchall() - alive = result[0][0] - killed = result[0][1] + 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']) - result = con.fetchall() + r = con.fetchall() - for row in result: + for row in r: getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) rateLimit(reddit) sleep(0.2) con.execute(stm['preStm']['cycle']['getAlive']) - result = con.fetchall() + r = con.fetchall() - for row in result: + for row in r: if (cfg['commands']['allowBotBroadcast'] == 1): getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) rateLimit(reddit) @@ -267,9 +317,9 @@ def gameEnd(): sleep(0.2) con.execute(stm['preStm']['getWinner']) - result = con.fetchall() - bad = result[0][0] - good = result[0][1] + r = con.fetchall() + bad = r[0][0] + good = r[0][1] if (good == bad): winner = 'NOBODY' @@ -283,6 +333,14 @@ def gameEnd(): @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 + curCycle = round save(state, curCycle) return curCycle @@ -295,17 +353,17 @@ def broadcast(): 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 - else: - if (cfg['commands']['allowBotBroadcast'] == 0): - item.reply('Broadcast Disabled') - return - - con.execute(stm['preStm']['getAll']) - result = con.fetchall() - for row in result: - getItems(row[0]).reply(msg) - rateLimit(reddit) - sleep(0.2) + + if (cfg['commands']['allowBotBroadcast'] == 0): + item.reply('Broadcast Disabled') + return + + con.execute(stm['preStm']['getAll']) + r = con.fetchall() + for row in r: + getItems(row[0]).reply(msg) + rateLimit(reddit) + sleep(0.2) @log_commit def restart(): @@ -314,18 +372,18 @@ 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 -1 - else: - 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('**Restarting Game**') - print('REMOTE RESTART RECEIVED') - con.close() - os._exit(1) + + 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('**Restarting Game**') + print('REMOTE RESTART RECEIVED') + con.close() + os._exit(1) @log_commit def reset(): @@ -334,30 +392,30 @@ 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 -1 - else: - con.execute('SELECT `username` FROM Mafia') - result = con.fetchall() - 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['reddit']['targetPost']).reply(stm['sticky']['reset']) - comment.mod.distinguish(how='yes', sticky=True) - save(0, 0) + for row in r: + sub.flair.delete(row[0]) - try: - os.remove('data/items.pickle') - except: - pass + 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) - if (item.author.name != '*SELF*'): item.reply('**Resetting Game**') - print('REMOTE RESET RECEIVED') - con.close() - os._exit(1) + 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(): @@ -366,15 +424,15 @@ 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 -1 - else: - 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) + + 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) con.execute(stm['preStm']['main'][0]) con.execute(stm['preStm']['main'][1], (time.time(),)) @@ -405,7 +463,7 @@ def halt(): idCache = [] if(re.search(r'^!(join|leave|vote|digup|rules|help|stats)', comment.body)): - comment.reply(stm['error']['notPM']) + comment.reply(stm['err']['notPM']) idCache.append(comment.id) con.execute(stm['preStm']['comment'], (comment.author.name,)) @@ -424,23 +482,23 @@ def halt(): except: pass - if ((re.search(r'^!join', item.body)) and (state == 0)): + 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)) and (state == 1)): + elif (re.search(r'^!unlock', item.body)): unlockTier() elif ((re.search(r'^!list', item.body))): getList() @@ -452,7 +510,7 @@ def halt(): showRules() elif (re.search(r'^!GAMESTATE', item.body)): state = gameState(state) - elif ((re.search(r'^!CYCLE', item.body)) and (state == 1)): + elif (re.search(r'^!CYCLE', item.body)): cycle = cycle(curCycle) elif (re.search(r'^!BROADCAST', item.body)): broadcast() @@ -463,7 +521,7 @@ def halt(): elif (re.search(r'^!HALT', item.body)): halt() else: - item.reply(stm['error']['unkCmd'][0][0].format(stm['error']['unkCmd'][1][state])) + item.reply(stm['err']['unkCmd']) item.mark_read() lastCmd = item.body.strip() diff --git a/README.md b/README.md index adea9b2..e807106 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Play against other members to find out who amongst each other you can trust and **Commands** -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. +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|Unlock Tier| |:-|:-|:-| @@ -51,7 +51,7 @@ All commands must be sent privately to u/DozenIncBOT. To use investigative comma |!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 be changed until the Round ends.|1| +|!vote USERNAME|Vote on who to eliminate. Can be changed until the Round ends.|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| diff --git a/init/default_settings.json b/init/default_settings.json index f625424..6f0c808 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -20,6 +20,7 @@ "unlockBurn": 2, "unlockLocate": 2, "unlockRevive": 3, + "unlockVote": 1, "useThreshold": 1, "voteOneAfter": 11, "voteThreshold": 2 diff --git a/init/settings.json b/init/settings.json index c7ad3a6..3501ebf 100644 --- a/init/settings.json +++ b/init/settings.json @@ -22,6 +22,7 @@ "unlockBurn": 2, "unlockLocate": 2, "unlockRevive": 3, + "unlockVote": 1, "useThreshold": 1, "voteOneAfter": 11, "voteThreshold": 2 diff --git a/init/statements.json b/init/statements.json index c5ddd88..ed90f3d 100644 --- a/init/statements.json +++ b/init/statements.json @@ -48,28 +48,21 @@ "Chopped and blended", "Run over by train" ], - "error": { + "err": { + "alreadyStarted": "The game has already started.", "burnUsed": "You have already used your abulity to burn.", "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 that user, the user is not playing in the game, or the user been killed.\n\nNote: Usernames are case-sensitive.", + "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).", - "notUnlocked": "Command not authorized!.\n\nCrack the game codes to unlock this command.", + "notStarted": "The game has not started yet.", + "notUnlocked": "Command not authorized!.\n\nCrack more game codes to unlock this command.", "nmFmt": "Invalid username.", "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.\n\nNote: The game {}" - ], - [ - "has not yet started.", - "has already started.", - "has ended." - ] - ], + "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).", "wrongCode": "Access Denied" }, @@ -114,6 +107,7 @@ "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;", + "chkCmt": "SELECT `username` FROM Mafia WHERE (`username`=%s AND `comment`>=%s);", "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": { @@ -133,6 +127,7 @@ "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;", "getPlaying": "SELECT `username` FROM Mafia WHERE (`alive`=1 AND NOT `username`='DozenIncBOT');", From 3bb15f40fdb6c5e6788cd80489f4cb2e893b5372 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sun, 12 Jul 2020 12:24:37 -0400 Subject: [PATCH 12/26] Check user is not a spectator --- Mafia.py | 8 +++++++- init/statements.json | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Mafia.py b/Mafia.py index 92c13f2..9dddbb2 100644 --- a/Mafia.py +++ b/Mafia.py @@ -100,6 +100,13 @@ def wrapper(*args, **kwargs): 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() @@ -239,7 +246,6 @@ def unlockTier(): pass @log_commit - @game_command def getStats(): pass diff --git a/init/statements.json b/init/statements.json index ed90f3d..7597378 100644 --- a/init/statements.json +++ b/init/statements.json @@ -108,6 +108,7 @@ "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;", "chkCmt": "SELECT `username` FROM Mafia WHERE (`username`=%s AND `comment`>=%s);", + "chkUsr": "SELECT `username`,`team`,`tier` FROM Mafia WHERE (`username`=%s AND `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": { From ead424744b8fb49bc132b31062939c19d190f965 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sun, 12 Jul 2020 15:25:06 -0400 Subject: [PATCH 13/26] getStats command --- Mafia.py | 33 ++++++++++++++++++++++++++++++++- init/statements.json | 12 +++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/Mafia.py b/Mafia.py index 9dddbb2..8773c42 100644 --- a/Mafia.py +++ b/Mafia.py @@ -247,7 +247,38 @@ def unlockTier(): @log_commit def getStats(): - pass + team = 'The Spectators' + tier = 'Spectator' + loc = 'Nowhere' + status = 'not playing' + alive = 0 + killed = 0 + good = 0 + bad = 0 + + 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] + + 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], \ + 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(): diff --git a/init/statements.json b/init/statements.json index 7597378..a43a2ff 100644 --- a/init/statements.json +++ b/init/statements.json @@ -1,4 +1,10 @@ { + "alive": [ + "Dead", + "Alive", + "not playing", + "kicked for inactivity" + ], "comment": { "actions": { "addUser": "u/{} has joined", @@ -118,7 +124,7 @@ "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", + "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';", @@ -183,7 +189,7 @@ "getList": "Total players: {}\n\nDead: {}\n{}\n\nAlive: {}\n{}", "getSts": [ [ - "Current Stats:\n\nGame is {}.\nRound {}.\n\nYou're on {}'s team.'\nYour rank tier is {}\n\nAlive: {}\n* MI6: {}\n* The Twelve: {}\nKilled: {}\nTotal Players: {}\n\nGame Parameters\n* Burn after cycle {}\n* Vote threshold: {}\n* Single vote after cycle {}\n* Max requests: {}\n* Kick inactive after {} cycles" + "**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", @@ -195,7 +201,7 @@ "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 {}.", + "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 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!\n\nThis hit will expire after this round, round {}.", "locateUser": "u/{} is located at {}", "promote": "Code Accepted!\n\nYou have been promoted to {}.", From 52d75d79e971d0d5fd098aa01345995f77e11fed Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Sun, 12 Jul 2020 15:39:13 -0400 Subject: [PATCH 14/26] getList command --- Mafia.py | 23 +++++++++++++++++++++++ init/statements.json | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/Mafia.py b/Mafia.py index 8773c42..273a2f5 100644 --- a/Mafia.py +++ b/Mafia.py @@ -245,6 +245,29 @@ def requestUser(): def unlockTier(): pass + @log_commit + def getList(): + dead = '' + alive = '' + deadNum = 0 + aliveNum = 0 + + con.execute(stm['preStm']['getList'][0]) + r = con.fetchall() + + for row in r: + dead += f'\n* u/{row[0]}' + deadNum += 1 + + con.execute(stm['preStm']['getList'][1]) + r = con.fetchall() + + for row in r: + alive += f'\n* u/{row[0]}' + aliveNum += 1 + + item.reply(stm['reply']['getList'].format(deadNum + aliveNum, deadNum, dead, aliveNum, alive)) + @log_commit def getStats(): team = 'The Spectators' diff --git a/init/statements.json b/init/statements.json index a43a2ff..a0aca69 100644 --- a/init/statements.json +++ b/init/statements.json @@ -137,6 +137,10 @@ "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;", From 0564841943ad63357029a9e17a7a09c30e02444b Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 03:40:43 -0400 Subject: [PATCH 15/26] Command-Tier Hierarchy, Close #18, Close #19 --- Mafia.py | 50 ++++++++++++++++++++++++++++++++------ init/default_settings.json | 14 +++++------ init/settings.json | 12 ++++----- init/statements.json | 3 +++ 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Mafia.py b/Mafia.py index 273a2f5..4da95c9 100644 --- a/Mafia.py +++ b/Mafia.py @@ -213,37 +213,73 @@ def removeUser(): @log_commit @game_command def voteUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockVote']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def burnUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockBurn']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def reviveUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockRevive']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def digupUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] == 0): + pass + elif (r[0][0] == 1): + pass + elif (r[0][0] == 2): + pass + elif (r[0][0] == 3): + pass @log_commit @game_command def locateUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockLocate']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def requestUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockRequest']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def unlockTier(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() @log_commit def getList(): diff --git a/init/default_settings.json b/init/default_settings.json index 6f0c808..a0caec1 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -6,19 +6,19 @@ "hour1": 3, "hour2": 9 }, - "codes": - { - "tier1": "123", - "tier2": "456", - "tier3": "789" - }, + "codes": [ + "123", + "456", + "789" + ], "commands": { "allowBotBroadcast": 1, "burnAfter": 7, "maxRequests": 3, - "reviveAfter": 11, + "reviveAfter": 1, "unlockBurn": 2, "unlockLocate": 2, + "unlockRequest": 0, "unlockRevive": 3, "unlockVote": 1, "useThreshold": 1, diff --git a/init/settings.json b/init/settings.json index 3501ebf..04101c8 100644 --- a/init/settings.json +++ b/init/settings.json @@ -8,12 +8,11 @@ "hour1": 3, "hour2": 9 }, - "codes": - { - "tier1": "123", - "tier2": "456", - "tier3": "789" - }, + "codes": [ + "SENSATIONAL-CHOCHOLATE-PISTOLS", + "A7J-3LX-GZ1", + "1836-0322-0935" + ], "commands": { "allowBotBroadcast": 1, "burnAfter": 7, @@ -21,6 +20,7 @@ "reviveAfter": 1, "unlockBurn": 2, "unlockLocate": 2, + "unlockRequest": 0, "unlockRevive": 3, "unlockVote": 1, "useThreshold": 1, diff --git a/init/statements.json b/init/statements.json index a0aca69..4578ef1 100644 --- a/init/statements.json +++ b/init/statements.json @@ -151,6 +151,9 @@ ], "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s 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);", + "unlock": [ + "SELECT `tier` FROM Mafia WHERE `username`=%s;" + ], "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `vote`=%s;" }, "reply": { From f445959cafaeb35096a5186ff42a933d00337c7b Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 03:48:32 -0400 Subject: [PATCH 16/26] Command-Tier Hierarchy, Close #18, Close #16 --- Mafia.py | 50 ++++++++++++++++++++++++++++++++------ init/default_settings.json | 14 +++++------ init/settings.json | 12 ++++----- init/statements.json | 3 +++ 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Mafia.py b/Mafia.py index 273a2f5..4da95c9 100644 --- a/Mafia.py +++ b/Mafia.py @@ -213,37 +213,73 @@ def removeUser(): @log_commit @game_command def voteUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockVote']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def burnUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockBurn']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def reviveUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockRevive']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def digupUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] == 0): + pass + elif (r[0][0] == 1): + pass + elif (r[0][0] == 2): + pass + elif (r[0][0] == 3): + pass @log_commit @game_command def locateUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockLocate']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def requestUser(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() + + if (r[0][0] <= cfg['commands']['unlockRequest']): + item.reply(stm['err']['notUnlocked']) + return -1 @log_commit @game_command def unlockTier(): - pass + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) + r = con.fetchall() @log_commit def getList(): diff --git a/init/default_settings.json b/init/default_settings.json index 6f0c808..a0caec1 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -6,19 +6,19 @@ "hour1": 3, "hour2": 9 }, - "codes": - { - "tier1": "123", - "tier2": "456", - "tier3": "789" - }, + "codes": [ + "123", + "456", + "789" + ], "commands": { "allowBotBroadcast": 1, "burnAfter": 7, "maxRequests": 3, - "reviveAfter": 11, + "reviveAfter": 1, "unlockBurn": 2, "unlockLocate": 2, + "unlockRequest": 0, "unlockRevive": 3, "unlockVote": 1, "useThreshold": 1, diff --git a/init/settings.json b/init/settings.json index 3501ebf..04101c8 100644 --- a/init/settings.json +++ b/init/settings.json @@ -8,12 +8,11 @@ "hour1": 3, "hour2": 9 }, - "codes": - { - "tier1": "123", - "tier2": "456", - "tier3": "789" - }, + "codes": [ + "SENSATIONAL-CHOCHOLATE-PISTOLS", + "A7J-3LX-GZ1", + "1836-0322-0935" + ], "commands": { "allowBotBroadcast": 1, "burnAfter": 7, @@ -21,6 +20,7 @@ "reviveAfter": 1, "unlockBurn": 2, "unlockLocate": 2, + "unlockRequest": 0, "unlockRevive": 3, "unlockVote": 1, "useThreshold": 1, diff --git a/init/statements.json b/init/statements.json index a0aca69..4578ef1 100644 --- a/init/statements.json +++ b/init/statements.json @@ -151,6 +151,9 @@ ], "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s 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);", + "unlock": [ + "SELECT `tier` FROM Mafia WHERE `username`=%s;" + ], "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `vote`=%s;" }, "reply": { From 62f08eecbd519ac2eb9029d46366f0a2cf8b2d78 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 21:52:26 -0400 Subject: [PATCH 17/26] Implement unlock command and Close #19 --- Mafia.py | 64 +++++++++++++++++++++++++++++++------------- init/statements.json | 9 ++++--- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Mafia.py b/Mafia.py index 4da95c9..e9f8a16 100644 --- a/Mafia.py +++ b/Mafia.py @@ -61,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 = '' @@ -86,18 +86,20 @@ def wrapper(*args, **kwargs): def game_command(func): @functools.wraps(func) def wrapper(*args, **kwargs): - pattern = re.search(r'^!([a-z]{4,})\s(u/)?([A-Za-z0-9_]{1,20})', item.body) - name = '' + 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 pattern: - name = pattern.group(3) - else: - item.reply(stm['err']['nmFmt']) - 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,)) @@ -114,18 +116,21 @@ def wrapper(*args, **kwargs): item.reply(stm['err']['noParticipate']) return -1 - con.execute(stm['preStm']['digupUser'], (name,)) - r = con.fetchall() + 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 + 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 + return result return wrapper def schdWarn(min=00): @@ -216,7 +221,7 @@ def voteUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (r[0][0] <= cfg['commands']['unlockVote']): + if (r[0][0] < cfg['commands']['unlockVote']): item.reply(stm['err']['notUnlocked']) return -1 @@ -226,7 +231,7 @@ def burnUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (r[0][0] <= cfg['commands']['unlockBurn']): + if (r[0][0] < cfg['commands']['unlockBurn']): item.reply(stm['err']['notUnlocked']) return -1 @@ -236,7 +241,7 @@ def reviveUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (r[0][0] <= cfg['commands']['unlockRevive']): + if (r[0][0] < cfg['commands']['unlockRevive']): item.reply(stm['err']['notUnlocked']) return -1 @@ -261,7 +266,7 @@ def locateUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (r[0][0] <= cfg['commands']['unlockLocate']): + if (r[0][0] < cfg['commands']['unlockLocate']): item.reply(stm['err']['notUnlocked']) return -1 @@ -278,8 +283,31 @@ def requestUser(): @log_commit @game_command def unlockTier(): + pattern = re.search(r'^![a-z]{4,}\s(?:u/)?([\w\d\-]+)\s?$', item.body) + code = '' + + if pattern: + code = pattern.group(1) + else: + item.reply(stm['err']['impFmt']) + return -1 + con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() + tier = r[0][0] + team = r[0][1] + + if (tier > len(cfg['codes']) - 1): + item.reply(stm['err']['maxTier']) + return -1 + + if (cfg['codes'][tier] == code): + con.execute(stm['preStm']['unlock'][1], (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['err']['wrongCode']) + return -1 @log_commit def getList(): diff --git a/init/statements.json b/init/statements.json index 4578ef1..08a5830 100644 --- a/init/statements.json +++ b/init/statements.json @@ -10,6 +10,7 @@ "addUser": "u/{} has joined", "addExistingUser": "u/{} has rejoined", "burnUser": "u/{} has burned their own member, u/{} 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 u/{}.", "revive": "A player was revived.", @@ -57,6 +58,8 @@ "err": { "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", "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.", @@ -65,12 +68,11 @@ "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.", - "nmFmt": "Invalid username.", "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).", - "wrongCode": "Access Denied" + "wrongCode": "Access Denied. Try Again." }, "flairs": { "alive": "Mafia: Alive - Round {}", @@ -152,7 +154,8 @@ "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s 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);", "unlock": [ - "SELECT `tier` FROM Mafia WHERE `username`=%s;" + "SELECT `tier`,`team` FROM Mafia WHERE `username`=%s;", + "UPDATE Mafia SET `tier` = `tier` + 1 WHERE `username`=%s;" ], "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `vote`=%s;" }, From 6e38c0d098741034b35cafb1279c4e6986f838c2 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 22:11:00 -0400 Subject: [PATCH 18/26] Complete locate and request commands --- Mafia.py | 21 ++++++++++++++++++++- init/statements.json | 5 +++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Mafia.py b/Mafia.py index e9f8a16..51ff35f 100644 --- a/Mafia.py +++ b/Mafia.py @@ -270,16 +270,35 @@ def locateUser(): item.reply(stm['err']['notUnlocked']) 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() + + item.reply(stm['reply']['locateUser'].format(name, r[0][0])) + @log_commit @game_command def requestUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() - if (r[0][0] <= cfg['commands']['unlockRequest']): + if (r[0][0] < cfg['commands']['unlockRequest']): item.reply(stm['err']['notUnlocked']) return -1 + con.execute(stm['preStm']['request'][0], (item.author.name,)) + r = con.fetchall() + + 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) + con.execute(stm['preStm']['request'][1], (item.author.name,)) + item.reply(stm['reply']['requestUser']) + reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['requestUser'].format(pattern.group(1), item.author.name)) + @log_commit @game_command def unlockTier(): diff --git a/init/statements.json b/init/statements.json index 08a5830..23165b7 100644 --- a/init/statements.json +++ b/init/statements.json @@ -146,12 +146,17 @@ "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` 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);", "unlock": [ "SELECT `tier`,`team` FROM Mafia WHERE `username`=%s;", From 81ba4fa12c6553904781ae0a1f418b240c52461f Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 22:31:02 -0400 Subject: [PATCH 19/26] Replenish requests --- Mafia.py | 9 +++++++-- init/settings.json | 2 ++ init/statements.json | 8 +++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Mafia.py b/Mafia.py index 51ff35f..0ef1691 100644 --- a/Mafia.py +++ b/Mafia.py @@ -295,9 +295,9 @@ def requestUser(): return -1 pattern = re.search(r'^!request\s(?:u/)?([A-Za-z0-9_]{1,20})', item.body) - con.execute(stm['preStm']['request'][1], (item.author.name,)) item.reply(stm['reply']['requestUser']) - reddit.submission(id=cfg['reddit']['targetPost']).reply(stm['comment']['actions']['requestUser'].format(pattern.group(1), item.author.name)) + 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 @game_command @@ -322,6 +322,11 @@ def unlockTier(): if (cfg['codes'][tier] == code): con.execute(stm['preStm']['unlock'][1], (item.author.name,)) + + 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'])) + 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: diff --git a/init/settings.json b/init/settings.json index 04101c8..eab5749 100644 --- a/init/settings.json +++ b/init/settings.json @@ -15,6 +15,8 @@ ], "commands": { "allowBotBroadcast": 1, + "addRequests": 3, + "addRequestsOn": 1, "burnAfter": 7, "maxRequests": 3, "reviveAfter": 1, diff --git a/init/statements.json b/init/statements.json index 23165b7..7c8b871 100644 --- a/init/statements.json +++ b/init/statements.json @@ -12,7 +12,7 @@ "burnUser": "u/{} has burned their own member, u/{} 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 u/{}.", + "requestUser": "A request for intel on u/{} has been filed by {}.", "revive": "A player was revived.", "schdWarn": "Round ending in {} minutes!" }, @@ -154,17 +154,19 @@ ], "removeUser": "UPDATE Mafia SET `alive`=2,`diedOnCycle`=%s WHERE `username`=%s;", "request": [ - "SELECT `username` FROM Mafia WHERE `username`=%s AND `request`>0;", + "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);", "unlock": [ "SELECT `tier`,`team` FROM Mafia WHERE `username`=%s;", - "UPDATE Mafia SET `tier` = `tier` + 1 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 `vote`=%s;" }, "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 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.", From d4376b88037bc3669eee2f2a376c1d4a0eb5fa89 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Tue, 14 Jul 2020 23:06:54 -0400 Subject: [PATCH 20/26] Complete digup command --- Mafia.py | 36 ++++++++++++++++++++++++++++-------- init/statements.json | 40 ++++++++++++++++++++-------------------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/Mafia.py b/Mafia.py index 0ef1691..7292ba5 100644 --- a/Mafia.py +++ b/Mafia.py @@ -250,15 +250,35 @@ def reviveUser(): def digupUser(): con.execute(stm['preStm']['unlock'][0], (item.author.name,)) r = con.fetchall() + tier = r[0][0] - if (r[0][0] == 0): - pass - elif (r[0][0] == 1): - pass - elif (r[0][0] == 2): - pass - elif (r[0][0] == 3): - pass + 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() + + 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 (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['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'][0][0].format(pattern.group(1), role, stm['reply']['digupUser'][1][r[0][2]], cred)) @log_commit @game_command diff --git a/init/statements.json b/init/statements.json index 7c8b871..831064a 100644 --- a/init/statements.json +++ b/init/statements.json @@ -116,7 +116,7 @@ "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;", "chkCmt": "SELECT `username` FROM Mafia WHERE (`username`=%s AND `comment`>=%s);", - "chkUsr": "SELECT `username`,`team`,`tier` FROM Mafia WHERE (`username`=%s AND `alive`=1);", + "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": { @@ -178,27 +178,13 @@ ], "digupUser": [ [ - "**Intelligence Report**\n\nu/{} is believed to be {} and is currently {}\n\n^(This information is believed to be {}% credible.)" + "**Intelligence Report**\n\nu/{} is believed to be {} and is {}.\n\n^(This information is believed to be {}% credible.)" ], [ - [ - "is a Trainee", - "is an Assassin", - "is a Handler", - "is a Keeper" - ], - [ - "is a Recruit", - "is an Analyst", - "is an Operative", - "is a Supervisor" - ] - ], - [ - "deceased.", - "alive.", - "not in the game.", - "not in the game." + "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.", @@ -248,6 +234,20 @@ "Operative", "Supervisor" ] + ], + [ + [ + "a Trainee", + "an Assassin", + "a Handler", + "a Keeper" + ], + [ + "a Recruit", + "an Analyst", + "an Operative", + "a Supervisor" + ] ] ], "sticky": { From bc2d104b6c7fd941afa3078f0977d2366ddc3696 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 15 Jul 2020 00:58:32 -0400 Subject: [PATCH 21/26] Complete vote command --- Mafia.py | 22 ++++++++++++++++++++++ README.md | 6 +++--- init/default_settings.json | 3 +++ init/settings.json | 1 + init/statements.json | 9 +++++---- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Mafia.py b/Mafia.py index 7292ba5..557707a 100644 --- a/Mafia.py +++ b/Mafia.py @@ -225,6 +225,28 @@ def voteUser(): item.reply(stm['err']['notUnlocked']) 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() + + if ((len(r) <= 0) or (r[0][2]) != 1): + item.reply(stm['err']['notFound']) + return -1 + + con.execute(stm['preStm']['voteUser'], (item.author.name, target)) + success = con.rowcount + + if ((r[0][1] > cfg['commands']['escapeHit']) and (success > 0)): + getItems(target).reply(stm['reply']['hitAlertEsc'].format(target, curCycle + 1)) + item.reply(stm['reply']['voteUser']) + elif (success > 0): + getItems(target).reply(stm['reply']['hitAlert'].format(target, curCycle + 1)) + item.reply(stm['reply']['voteUser']) + else: + item.reply(stm['err']['voteUser']) + return -1 + @log_commit @game_command def burnUser(): diff --git a/README.md b/README.md index e807106..4793693 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ Play against other members to find out who amongst each other you can trust and |:-|:-|:-|:-| |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.| +|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.| +|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** @@ -51,7 +51,7 @@ All commands must be sent privately to u/DozenIncBOT. To use investigative comma |!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 be changed until the Round ends.|2| +|!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| diff --git a/init/default_settings.json b/init/default_settings.json index a0caec1..d219ebb 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -13,7 +13,10 @@ ], "commands": { "allowBotBroadcast": 1, + "addRequests": 3, + "addRequestsOn": 1, "burnAfter": 7, + "escapeHit": 1, "maxRequests": 3, "reviveAfter": 1, "unlockBurn": 2, diff --git a/init/settings.json b/init/settings.json index eab5749..3d099ca 100644 --- a/init/settings.json +++ b/init/settings.json @@ -18,6 +18,7 @@ "addRequests": 3, "addRequestsOn": 1, "burnAfter": 7, + "escapeHit": 1, "maxRequests": 3, "reviveAfter": 1, "unlockBurn": 2, diff --git a/init/statements.json b/init/statements.json index 831064a..146c4b1 100644 --- a/init/statements.json +++ b/init/statements.json @@ -72,6 +72,7 @@ "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": { @@ -163,7 +164,7 @@ "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 `vote`=%s;" + "voteUser": "INSERT INTO VoteCall (`username`, `vote`) VALUES(%s, %s) ON DUPLICATE KEY UPDATE `username`=`username`;" }, "reply": { "addRequests": "+{} Requests Added.", @@ -204,8 +205,8 @@ "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 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!\n\nThis hit will expire after this round, round {}.", + "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.", @@ -214,7 +215,7 @@ "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 tallied. You can change your vote until the round ends." + "voteUser": "Your vote has been locked in for this round." }, "teams": [ [ From 34be628782ae4dc91be5d54b8e86b1f3b40c2310 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 15 Jul 2020 10:44:27 -0400 Subject: [PATCH 22/26] Complete revive command, reworked items pickle, bot messaging --- Mafia.py | 111 +++++++++++++++++++++++++++---------------- init/statements.json | 8 ++++ 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/Mafia.py b/Mafia.py index 557707a..333877e 100644 --- a/Mafia.py +++ b/Mafia.py @@ -231,17 +231,17 @@ def voteUser(): r = con.fetchall() if ((len(r) <= 0) or (r[0][2]) != 1): - item.reply(stm['err']['notFound']) + item.reply(stm['err']['notAlive']) return -1 con.execute(stm['preStm']['voteUser'], (item.author.name, target)) success = con.rowcount if ((r[0][1] > cfg['commands']['escapeHit']) and (success > 0)): - getItems(target).reply(stm['reply']['hitAlertEsc'].format(target, curCycle + 1)) + sendMessage(target, stm['reply']['hitAlertEsc'].format(target, curCycle + 1)) item.reply(stm['reply']['voteUser']) elif (success > 0): - getItems(target).reply(stm['reply']['hitAlert'].format(target, curCycle + 1)) + sendMessage(target, stm['reply']['hitAlert'].format(target, curCycle + 1)) item.reply(stm['reply']['voteUser']) else: item.reply(stm['err']['voteUser']) @@ -257,6 +257,17 @@ def burnUser(): item.reply(stm['err']['notUnlocked']) return -1 + if (curCycle < cfg['allowBurnAfter']): + 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['err']['burnUsed']) + return -1 + @log_commit @game_command def reviveUser(): @@ -267,6 +278,29 @@ def reviveUser(): item.reply(stm['err']['notUnlocked']) return -1 + con.execute(stm['preStm']['revive'][0], (item.author.name,)) + r = con.fetchall() + + if (len(r) <= 0): + item.reply(stm['err']['reviveUsed']) + return -1 + + 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['err']['alive']) + return -1 + + 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(): @@ -457,8 +491,7 @@ def gameStart(): 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])) - getItems(row[0]).reply(stm['reply']['gameStart'].format(stm['teams'][0][team], loc, players, cfg['reddit']['sub'], cfg['reddit']['targetPost'])) - rateLimit(reddit) + sendMessage(row[0], stm['reply']['gameStart'].format(stm['teams'][0][team], loc, players, cfg['reddit']['sub'], cfg['reddit']['targetPost'])) curPos += 1 sleep(0.2) @@ -491,8 +524,7 @@ def gameEnd(): r = con.fetchall() for row in r: - getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) - rateLimit(reddit) + sendMessage(row[0], stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) sleep(0.2) con.execute(stm['preStm']['cycle']['getAlive']) @@ -500,8 +532,7 @@ def gameEnd(): for row in r: if (cfg['commands']['allowBotBroadcast'] == 1): - getItems(row[0]).reply(stm['reply']['gameEnd'].format(cfg['reddit']['sub'], cfg['reddit']['targetPost'])) - rateLimit(reddit) + 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) @@ -551,8 +582,7 @@ def broadcast(): con.execute(stm['preStm']['getAll']) r = con.fetchall() for row in r: - getItems(row[0]).reply(msg) - rateLimit(reddit) + sendMessage(row[0], msg) sleep(0.2) @log_commit @@ -624,6 +654,26 @@ def halt(): 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) + 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(),)) con.execute(stm['preStm']['addDummy']) @@ -724,17 +774,6 @@ def halt(): con.close() -def rateLimit(reddit): - 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) - sleep(reset) - def save(state, curCycle): with open('data/save.json', 'r+') as jsonFile2: tmp = json.load(jsonFile2) @@ -745,34 +784,24 @@ def save(state, curCycle): jsonFile2.truncate() def setItems(k, v): - try: + tmp = {} + + if os.path.getsize('data/items.pickle') > 0: + print('items.pickle not found. Creating a new one.') with open('data/items.pickle', 'rb') as itemsFile: tmp = pickle.load(itemsFile) - - if v == None: - tmp.pop(k, None) - else: - tmp[k] = v - - pickle.dump(tmp, itemsFile) - except Exception as e: - tmp = {} - - if v == None: - tmp.pop(k, None) - else: tmp[k] = v - pickle.dump(tmp, open('data/items.pickle', 'wb')) + with open('data/items.pickle', 'wb') as itemsFile: + pickle.dump(tmp, itemsFile) def getItems(k): - try: + if os.path.getsize('data/items.pickle') > 0: with open('data/items.pickle', 'rb') as itemsFile: tmp = pickle.load(itemsFile) return tmp[k] - except Exception as e: - tmp = {} - pickle.dump(tmp, open('data/items.pickle', 'wb')) + else: + print('items.pickle not found. WARNING') return None def exit_gracefully(signum, frame): diff --git a/init/statements.json b/init/statements.json index 146c4b1..4864133 100644 --- a/init/statements.json +++ b/init/statements.json @@ -56,6 +56,7 @@ "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.", @@ -64,6 +65,7 @@ "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.", @@ -159,6 +161,12 @@ "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;", From 0593dceb283197391a33a2ed1aca91efc4391eab Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 15 Jul 2020 20:09:39 -0400 Subject: [PATCH 23/26] Complete burn command, fixed items pickle --- Mafia.py | 35 ++++++++++++++++++++++++++++++++--- init/default_settings.json | 1 + init/settings.json | 1 + init/statements.json | 29 ++++++++++++++++++++--------- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/Mafia.py b/Mafia.py index 333877e..c3c0f2d 100644 --- a/Mafia.py +++ b/Mafia.py @@ -257,7 +257,7 @@ def burnUser(): item.reply(stm['err']['notUnlocked']) return -1 - if (curCycle < cfg['allowBurnAfter']): + if (curCycle < cfg['commands']['burnAfter']): item.reply(stm['err']['noBurnYet']) return -1 @@ -268,6 +268,33 @@ def burnUser(): item.reply(stm['err']['burnUsed']) return -1 + 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(toBurn) <= 0) or (len(toReport) <= 0)): + item.reply(stm['err']['noBurnLeft']) + return -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,)) + 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(): @@ -786,11 +813,13 @@ def save(state, curCycle): def setItems(k, v): tmp = {} - if os.path.getsize('data/items.pickle') > 0: - print('items.pickle not found. Creating a new one.') + 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) diff --git a/init/default_settings.json b/init/default_settings.json index d219ebb..cceface 100644 --- a/init/default_settings.json +++ b/init/default_settings.json @@ -16,6 +16,7 @@ "addRequests": 3, "addRequestsOn": 1, "burnAfter": 7, + "burnQuietly": 3, "escapeHit": 1, "maxRequests": 3, "reviveAfter": 1, diff --git a/init/settings.json b/init/settings.json index 3d099ca..ca5534e 100644 --- a/init/settings.json +++ b/init/settings.json @@ -18,6 +18,7 @@ "addRequests": 3, "addRequestsOn": 1, "burnAfter": 7, + "burnQuietly": 3, "escapeHit": 1, "maxRequests": 3, "reviveAfter": 1, diff --git a/init/statements.json b/init/statements.json index 4864133..aa70eb0 100644 --- a/init/statements.json +++ b/init/statements.json @@ -9,7 +9,8 @@ "actions": { "addUser": "u/{} has joined", "addExistingUser": "u/{} has rejoined", - "burnUser": "u/{} has burned their own member, u/{} for intelligence", + "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 {}.", @@ -36,18 +37,18 @@ "Stabbed by a pitchfork", "Run over while reversing", "Choked by an elevator", - "Fell off a building", - "Burnt while sleeping", + "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", - "Had a mysterious heart attack", + "Killed by a mysterious heart attack", "Axed in the back", "Throat slit", - "Killed by tiny chair", + "Killed by a tiny chair", "Run over by bus", "Paralysed by neurotoxin", "Chopped and boiled down", @@ -61,7 +62,7 @@ "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", + "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", @@ -79,7 +80,7 @@ }, "flairs": { "alive": "Mafia: Alive - Round {}", - "dead": "{}: {} on Round {}", + "dead": "Mafia: {} on Round {}", "survived": "{}: Survived to Round {}" }, "location": [ @@ -118,6 +119,15 @@ "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", @@ -177,8 +187,9 @@ "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 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.", + "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\nPlayers alive: {}\nPlayes killed:{}\nMI6 Agents Remaining: {}\nThe Twelve Remaining: {}\n\nHappy Hunting!", From 4cc2436b6d2c6797aee4a8f148b23531e7a55e83 Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 15 Jul 2020 22:10:12 -0400 Subject: [PATCH 24/26] Complete cycle function --- Mafia.py | 109 +++++++++++++++++++++++++++++++++++++++---- init/statements.json | 3 +- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/Mafia.py b/Mafia.py index c3c0f2d..13e1636 100644 --- a/Mafia.py +++ b/Mafia.py @@ -148,22 +148,22 @@ 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) print("Jobs Scheduled") @log_commit @@ -285,6 +285,8 @@ def burnUser(): deathMsg = random.randint(0,len(stm['deathMsg']) - 1) con.execute(stm['preStm']['burn'][4], (item.author.name,)) con.execute(stm['preStm']['burn'][5], (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])) @@ -465,10 +467,6 @@ def getStats(): tier = 'Spectator' loc = 'Nowhere' status = 'not playing' - alive = 0 - killed = 0 - good = 0 - bad = 0 con.execute(stm['preStm']['chkUsrState'], (item.author.name,)) r = con.fetchall() @@ -589,7 +587,98 @@ def cycle(curCycle): con.execute(stm['preStm']['log'], (item.created_utc, item.author.name, 'ATTEMPTED ADMIN COMMAND: cycle')) return -1 - curCycle = round + threshold = 1 + + if (curCycle > cfg['commands']['voteOneAfter']): + threshold = 1 + else: + threshold = cfg['commands']['voteThreshold'] + + 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: + con.execute(stm['preStm']['log'], (time.time(), row[0], 'Inactive Kick')) + sub.flair.delete(reddit.redditor(row[0])) + sendMessage(row[0], stm['reply']['cycle'][2]) + sleep(0.2) + + con.execute(stm['preStm']['cycle']['removeInactive'], (cfg['kickAfter'],)) + con.execute(stm['preStm']['cycle']['getVotes']) + result = con.fetchall() + + for row in result: + con.execute(stm['preStm']['chkUsr'], (row[0],)) + 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(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]): + con.execute(stm['preStm']['log'], (time.time(), row[0], f'{row[0]} Escaped')) + con.execute(stm['preStm']['cycle']['voteEscaped'], (row[0],)) + 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']) + result = con.fetchall() + alive = result[0][0] + killed = result[0][1] + + print(f'\nAlive: {alive} | Killed {killed}') + + con.execute(stm['preStm']['cycle']['getTeamCnt']) + result = con.fetchall() + bad = result[0][0] + good = result[0][1] + + 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 = '' + + for v in r: + killedMe += f'* u/{v[0]}\n' + + random.seed(time.time()) + n = random.randint(0,len(stm['deathMsg']) - 1) + 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' > {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(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['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 Round {curCycle + 2}**') + print(f'Moved to Round {curCycle + 1}') + curCycle += 1 save(state, curCycle) return curCycle @@ -778,7 +867,7 @@ def sendMessage(name, message): elif (re.search(r'^!GAMESTATE', item.body)): state = gameState(state) elif (re.search(r'^!CYCLE', item.body)): - cycle = cycle(curCycle) + curCycle = cycle(curCycle) elif (re.search(r'^!BROADCAST', item.body)): broadcast() elif (re.search(r'^!RESTART', item.body)): diff --git a/init/statements.json b/init/statements.json index aa70eb0..d5d983f 100644 --- a/init/statements.json +++ b/init/statements.json @@ -192,7 +192,7 @@ "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\nPlayers alive: {}\nPlayes killed:{}\nMI6 Agents Remaining: {}\nThe Twelve Remaining: {}\n\nHappy Hunting!", + "**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!" ], @@ -271,6 +271,7 @@ ] ], "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)", From 0e675cc6ce01608a2a6a9add30c7a84fea385f9b Mon Sep 17 00:00:00 2001 From: mikojimnz Date: Wed, 15 Jul 2020 23:09:06 -0400 Subject: [PATCH 25/26] Make random comments, Close #20 --- Mafia.py | 21 ++++++++++++++++- init/statements.json | 54 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Mafia.py b/Mafia.py index 13e1636..c83cb26 100644 --- a/Mafia.py +++ b/Mafia.py @@ -164,6 +164,8 @@ def scheduleJobs(): 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) + + schedule.every(1).to(3).hours.do(makeComment) print("Jobs Scheduled") @log_commit @@ -500,6 +502,23 @@ def showHelp(): def showRules(): item.reply(stm['reply']['showRules']) + @log_commit + 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']) @@ -626,7 +645,7 @@ def cycle(curCycle): for user in list: if (target[0][0] == user[0]): - con.execute(stm['preStm']['log'], (time.time(), row[0], f'{row[0]} Escaped')) + con.execute(stm['preStm']['log'], (time.time(), row[0], 'Escaped')) con.execute(stm['preStm']['cycle']['voteEscaped'], (row[0],)) sendMessage(row[0], stm['reply']['cycle'][3]) print(f' > {row[0]} escaped') diff --git a/init/statements.json b/init/statements.json index d5d983f..1763956 100644 --- a/init/statements.json +++ b/init/statements.json @@ -18,10 +18,60 @@ "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": [ From a1c2f700219966a8ef459a3a92379ad084babee4 Mon Sep 17 00:00:00 2001 From: Miko Jimenez Date: Wed, 15 Jul 2020 23:12:58 -0400 Subject: [PATCH 26/26] Update strategy.md --- strategy.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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