from JJMumbleBot.lib.plugin_template import PluginBase from JJMumbleBot.lib.utils.plugin_utils import PluginUtilityService from JJMumbleBot.lib.utils.logging_utils import log from JJMumbleBot.lib.utils.print_utils import PrintMode from JJMumbleBot.settings import global_settings as gs from JJMumbleBot.lib.resources.strings import * import os import random import sqlite3 class Plugin(PluginBase): def __init__(self): super().__init__() from json import loads self.plugin_name = os.path.basename(__file__).rsplit('.')[0] self.metadata = PluginUtilityService.process_metadata(f'plugins/extensions/{self.plugin_name}') self.plugin_cmds = loads(self.metadata.get(C_PLUGIN_INFO, P_PLUGIN_CMDS)) init_db = sqlite3.connect('init.db') init = init_db.cursor() init.execute("CREATE TABLE IF NOT EXISTS inits (dice int, bonus int, total int, name string UNIQUE)") init_db.commit() init_db.close() self.is_running = True log( INFO, f"{self.metadata[C_PLUGIN_INFO][P_PLUGIN_NAME]} v{self.metadata[C_PLUGIN_INFO][P_PLUGIN_VERS]} Plugin Initialized.", origin=L_STARTUP, print_mode=PrintMode.REG_PRINT.value ) def quit(self): self.is_running = False log( INFO, f"Exiting {self.plugin_name} plugin...", origin=L_SHUTDOWN, print_mode=PrintMode.REG_PRINT.value ) def stop(self): if self.is_running: self.quit() def start(self): if not self.is_running: self.__init__() def cmd_addinit(self,data): all_data = data.message.strip().split() try: number_of_dice = int(all_data[1]) init_bonus = int(all_data[2]) character_name = str(all_data[3]) init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("INSERT INTO inits values (?,?,?,?) ON CONFLICT(name) DO UPDATE SET dice=" + str(number_of_dice) + ", bonus=" + str(init_bonus), (number_of_dice, init_bonus, 0, character_name)) init_db.commit() init_db.close() gs.gui_service.quick_gui("Added init for: " + character_name, text_type='header', box_align='left') except IndexError: gs.gui_service.quick_gui("Format: !addinit #dice #bonus $name", text_type='header', box_align='left') return def cmd_listinit(self,data): try: init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("SELECT * from inits ORDER BY total DESC") ret_text = "" for row in cur: ret_text += str(row[3]) + ": " + str(row[2]) + "
" init_db.close() gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') except IndexError: gs.gui_service.quick_gui("Format: !listinit", text_type='header', box_align='left') return def cmd_listinitpools(self,data): try: init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("SELECT * from inits ORDER BY total DESC") ret_text = "" for row in cur: ret_text += str(row[3]) + ": " + str(row[0]) + "d6+" + str(row[1]) + "
" init_db.close() gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') except IndexError: gs.gui_service.quick_gui("Format: !listinitpools", text_type='header', box_align='left') return def cmd_initpass(self, data): try: init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("SELECT * from inits ORDER BY total DESC") init = init_db.cursor() ret_text = "" for row in cur: new_init = int(row[2])-10 if(new_init <= 0): new_init = 0 init.execute("UPDATE inits SET total = :result WHERE name = :name", {"result": new_init, "name": row[3]}) ret_text += str(row[3]) + ": " + str(new_init) + "
" init_db.commit() init_db.close() gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') except IndexError: gs.gui_service.quick_gui("Format: !initpass", text_type='header', box_align='left') return def cmd_interupt(self, data): all_data = data.message.strip().split() try: name = str(all_data[1]) subtract = int(all_data[2]) init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("SELECT * from inits WHERE name = :name", {"name": name}) for row in cur: new_init = int(row[2])-subtract if(new_init < 0): gs.gui_service.quick_gui("Cannot take action, not enought init", text_type='header', box_align='left') else: cur.execute("UPDATE inits SET total = :result WHERE name = :name", {"result": new_init, "name": name}) gs.gui_service.quick_gui(name + ": " + str(new_init), text_type='header', box_align='left') init_db.commit() init_db.close() except IndexError: gs.gui_service.quick_gui("Can only subtract init from a name in the list of inits, try !listinit to confirm spellings", text_type='header', box_align='left') return def cmd_delinit(self, data): all_data = data.message.strip().split() try: name = str(all_data[1]) init_db = sqlite3.connect('init.db') cur = init_db.cursor() cur.execute("DELETE from inits WHERE name = :name", {"name": name}) init_db.commit() init_db.close() gs.gui_service.quick_gui("Deleted init for: " + name + " (if they exist)", text_type='header', box_align='left') except IndexError: gs.gui_service.quick_gui("Can only remove init from a name in the list of inits, try !listinit to confirm spellings", text_type='header', box_align='left') return def cmd_clearinit(self, data): init_db = sqlite3.connect('init.db') init = init_db.cursor() init.execute("DROP TABLE inits") init_db.commit() init.execute("CREATE TABLE inits (dice int, bonus int, total int, name string UNIQUE)") init_db.commit() init_db.close() gs.gui_service.quick_gui("Purged the Init DB", text_type='header', box_align='left') def cmd_rollinit(self, data): try: init_db = sqlite3.connect('init.db') cur = init_db.cursor() init = init_db.cursor() cur.execute("SELECT * from inits") ret_text = "" for row in cur.fetchall(): ret_text += str(row) number_of_dice = int(row[0]) init_bonus = int(row[1]) ret_text = "
Init For " + str(row[3]) + ":
" result = 0 for i in range(number_of_dice): random.seed(int.from_bytes(os.urandom(8), byteorder="big")) this_die = random.randint(1,6) result = result + this_die ret_text += f"{this_die} + " result = result + init_bonus init.execute("UPDATE inits SET total = :result WHERE name = :name", {"result": result, "name": row[3]}) ret_text += f" {init_bonus}
{result}" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') init_db.commit() init_db.close() return except IndexError: gs.gui_service.quick_gui("Format: !rollinit", text_type='header', box_align='left') return def cmd_srun(self, data): all_data = data.message.strip().split() try: number_of_dice = int(all_data[1]) ret_text = "
Die Pool:
" successes = 0 ones = 0 for i in range(number_of_dice): random.seed(int.from_bytes(os.urandom(8), byteorder="big")) this_die = random.randint(1,6) if i == 0: ret_text += f"{this_die}" else: ret_text += f", {this_die}" if this_die > 4: successes = successes + 1 if this_die == 1: ones = ones + 1 ret_text += f"
Successes: {successes} , Ones: {ones}" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') return except IndexError: gs.gui_service.quick_gui("Format: !srun #", text_type='header', box_align='left') return def cmd_preedge(self, data): all_data = data.message.strip().split() try: number_of_dice = int(all_data[1]) ret_text = "
Die Pool:
" successes = 0 ones = 0 explosions = 0 i = 0 while i < number_of_dice: random.seed(int.from_bytes(os.urandom(8), byteorder="big")) this_die = random.randint(1,6) if i == 0: ret_text += f"{this_die}" else: ret_text += f", {this_die}" if this_die > 4: successes = successes + 1 if this_die == 1: ones = ones + 1 if this_die == 6: i = i-1 explosions = explosions + 1 if i < 1: ret_text +=f", " i = i + 1 ret_text += f"
Successes: {successes} , Ones: {ones} , Explosions: {explosions}" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left') return except IndexError: gs.gui_service.quick_gui("Format: !preedge #", text_type='header', box_align='left') return def cmd_assensing(self, data): ret_text = "
ASSENSING TABLE
HITSINFORMATION GAINED
0None
1The general state of the subject’s health (healthy, injured, ill, etc.). The subject’s general emotional state or impression (happy, sad, angry, etc.). Whether the subject is mundane or Awakened.
2The presence and location of cyberware implants. The class of a magical subject (fire elemental, manipulation spell, power focus, curse ritual, and so on). If you have seen the subject’s aura before, you may recognize it, regardless of physical disguises or alterations
3The presence and location of alphaware cyber implants. Whether the subject’s Essence and Magic are higher, lower, or equal to your own. Whether the subject’s Force is higher, lower, or equal to your Magic. A general diagnosis for any maladies (diseases or toxins) the subject suffers. Any astral signatures present on the subject.
4The presence and location of bioware implants and betaware cyber implants. The exact Essence, Magic, and Force of the subject. The general cause of any astral signature (combat spell, alchemical combat spell, air spirit, and so on).
5+The presence and location of deltaware implants, gene treatments, and nanotech. An accurate diagnosis of any disease or toxins which afflict the subject. The fact that a subject is a technomancer.
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center') def cmd_delivery(self, data): ret_text = "
DELIVERY TIMES TABLE
GEAR COST DELIVERY TIME
Up to 100¥ 6 hours
101¥ to 1,000¥ 1 day
1,000¥ to 10,000¥ 2 days
10,001 to 100,000¥ 1 week
More than 100,000¥ 1 month
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center') def cmd_concealability(self, data): ret_text = "
CONCEALABILITY MODIFIERS *Applies to observer
MODIFIER* EXAMPLE ITEMS
–6 RFID tag, bug slap patch, microdrone, contact lenses
–4 Hold-out pistol, monowhip, ammo clip, credstick, chips/softs, sequencer/passkey, autopicker, lockpick set, commlink, glasses
–2 Light pistol, knife, sap, minidrone, microgrenade, flash-pak, jammer, cyberdeck, rigger command console
0 Heavy pistol, machine pistol with folding stock collapsed, grenade, goggles, ammo belt/drum, club, extendable baton (collapsed)
+2 SMG, machine pistol with folding stock extended, medkit, small drone, extendable baton (extended), stun baton
+4 Sword, sawed-off shotgun, bullpup assault rifle
+6 Katana, monosword, shotgun, assault rifle, sport rifle, crossbow
+8 Sniper rifle, bow, grenade launcher, medium drone
+10/Forget about it Machine gun, rocket launcher, missile launcher, staff, claymore, metahuman body
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center') def cmd_perception_mods(self, data): ret_text = "
PERCEPTION TEST MODIFIERS
SITUATION DICE POOL MODIFIER
Perceiver is distracted -2
Perciever is specifically looking/listening for it +3
Object/sound not in immediate vicinity -2
Object/sound far away -3
Object/sound stands out in some way +2
Interfering sight/odor/sound -2
Perceiver has active enhancements + Rating
Visibility and Light Environmental Factors (Above)
PERCEPTION THRESHOLDS
ITEM/EVENT IS: THRESHOLD EXAMPLES
Obvious 1 Neon sign, running crowd, yelling, gunfire
Normal 2 Street sign, pedestrian, conversation, silenced gunfire
Obscured/Small/Muffled 3 Item dropped under table, contact lens, whispering
Hidden/Micro/Silent 4 Secret door, needle in haystack, subvocal speech
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center') def cmd_environmental(self, data): ret_text = "
ENVIRONMENTAL
VISIBILITY LIGHT / GLARE WIND RANGE MODIFIER
Clear Full Light / No Glare None / Light Breeze Short 0
Light Rain / Fog / Smoke Partial Light / Weak Glare Light Winds / Light Breeze Medium -1
Moderate Rain / Fog / Smoke Dim Light / Moderate Glare Moderate Winds / Light Breeze Long -3
Heavy Rain / Fog / Smoke Total Darkness/ Blinding Glare Strong Winds / Light Breeze Extreme -6
Combination of two or more conditions at the -6 level row -10
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center') def cmd_hosts(self, data): ret_text = "
SAMPLE HOST RATINGS
EXAMPLESRATING
Personal sites, pirate archives, public education1-2
Low-end commercial, private business, public libraries, small policlubs3-4
Social media, small colleges and universities, local police, international policlubs5-6
Matrix games, local corporate hosts, large universities, low-level government7-8
Affluent groups, regional corporate hosts, major government, secure sites9-10
Megacorporate headquarters, military command, clandestine head office11-12
" gs.gui_service.quick_gui(ret_text, text_type='header', box_align='center')