JJMumblebot burning wheel plugin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
burningdice/burningdice.py

380 lines
21 KiB

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 v1 (content string, name string UNIQUE)")
init.execute("CREATE TABLE IF NOT EXISTS v2 (content string, name string UNIQUE)")
init.execute("CREATE TABLE IF NOT EXISTS v3 (content string, 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_volley(self, data):
all_data = data.message.strip().split()
try:
v = int(all_data[1])
if (v == 1):
volley = "v1"
elif (v == 2):
volley = "v2"
elif (v == 3):
volley = "v3"
else:
gs.gui_service.quick_gui("Format: !volley # script actions",
text_type='header', box_align='left')
return
script = str(all_data[2:])
init_db = sqlite3.connect('init.db')
cur = init_db.cursor()
cur.execute("INSERT INTO " + volley + " values (?,?) ON CONFLICT(name) DO UPDATE SET content=\"" + script + "\"", (str(script),str(gs.mumble_inst.users[data.actor]['name'])))
init_db.commit()
init_db.close()
gs.gui_service.quick_gui(str(gs.mumble_inst.users[data.actor]['name']) + " has scripted volley " + str(v), text_type='header', box_align='left')
return
except IndexError:
gs.gui_service.quick_gui("Format: !volley # script_actions",
text_type='header', box_align='left')
return
def cmd_npcvolley(self, data):
all_data = data.message.strip().split()
try:
v = int(all_data[1])
if (v == 1):
volley = "v1"
elif (v == 2):
volley = "v2"
elif (v == 3):
volley = "v3"
else:
gs.gui_service.quick_gui("Format: !npcvolley # name script_actions",
text_type='header', box_align='left')
return
script = str(all_data[3:])
init_db = sqlite3.connect('init.db')
cur = init_db.cursor()
cur.execute("INSERT INTO " + volley + " values (?,?) ON CONFLICT(name) DO UPDATE SET content=\"" + script + "\"", (str(script),str(all_data[2])))
init_db.commit()
init_db.close()
gs.gui_service.quick_gui(str(gs.mumble_inst.users[data.actor]['name']) + " has scripted volley " + str(v), text_type='header', box_align='left')
return
except IndexError:
gs.gui_service.quick_gui("Format: !volley # name script_actions",
text_type='header', box_align='left')
return
def reveal_actions(self,volleynum):
volley = "v" + str(volleynum)
init_db = sqlite3.connect('init.db')
cur = init_db.cursor()
cur.execute("SELECT * from " + volley + " ORDER BY name DESC")
ret_text = "Volley " + str(volleynum) + "<br>"
for row in cur:
ret_text += str(row[1]) + ": " + row[0] + "<br>"
init_db.close()
gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left')
return
def cmd_revealv1(self, data):
self.reveal_actions(1)
return
def cmd_revealv2(self, data):
self.reveal_actions(2)
return
def cmd_revealv3(self, data):
self.reveal_actions(3)
return
def whoscript(self,volleynum):
volley = "v" + str(volleynum)
init_db = sqlite3.connect('init.db')
cur = init_db.cursor()
cur.execute("SELECT * from " + volley + " ORDER BY name DESC")
ret_text = "Volley " + str(volleynum) + "<br>"
for row in cur:
ret_text += str(row[1]) + "<br>"
init_db.close()
gs.gui_service.quick_gui(ret_text, text_type='header', box_align='left')
return
def cmd_scriptedv1(self, data):
self.whoscript(1)
return
def cmd_scriptedv2(self, data):
self.whoscript(2)
return
def cmd_scriptedv3(self, data):
self.whoscript(3)
return
def cmd_scripted(self, data):
self.whoscript(1)
self.whoscript(2)
self.whoscript(3)
return
def clear_volley(self, volleynum):
self.del_volley(volleynum, "ThisNonceWillNeverBeUsedAsAName");
def del_volley(self, volleynum, name):
volley = "v" + str(volleynum)
init_db = sqlite3.connect('init.db')
init = init_db.cursor()
if (name == "ThisNonceWillNeverBeUsedAsAName"):
init.execute("DROP TABLE " + volley)
init_db.commit()
init.execute("CREATE TABLE IF NOT EXISTS " + volley + " (content string, name string UNIQUE)")
gs.gui_service.quick_gui("Purged all for " + volley, text_type='header', box_align='left')
else:
dbname = "\'" + name + "\'"
init.execute("DELETE FROM " + volley + " where name LIKE " + dbname);
gs.gui_service.quick_gui("Removed " + name + " from volley " + volley, text_type='header', box_align='left')
init_db.commit()
init_db.close()
def cmd_clearv1(self, data):
self.clear_volley(1)
return
def cmd_clearv2(self, data):
self.clear_volley(2)
return
def cmd_clearv3(self, data):
self.clear_volley(3)
return
def cmd_unscript(self,data):
all_data = data.message.strip().split()
if(len(all_data) == 2):
self.del_volley(1,all_data[1])
self.del_volley(2,all_data[1])
self.del_volley(3,all_data[1])
else:
self.del_volley(int(all_data[2]),all_data[1])
return
def cmd_bw(self, data):
all_data = data.message.strip().split()
try:
shade = all_data[1][0]
if shade == "B" or shade == "b":
size = 4
number_of_dice = int(all_data[1][1:])
elif shade == "G" or shade == "g":
size = 3
number_of_dice = int(all_data[1][1:])
elif shade == "W" or shade == "w":
size = 2
number_of_dice = int(all_data[1][1:])
else:
number_of_dice = int(all_data[1])
size = 4
astrodice = 0
if len(all_data) > 2:
if all_data[2] == "a" or all_data[2] == "A":
astrodice = 1
elif all_data[2] == "aa" or all_data[2] == "AA":
astrodice = 2
ret_text = "<br><font color='red'>Die Pool:</font><br>"
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 >= size:
successes = successes + 1
if this_die == 1:
ones = ones + 1
if astrodice > 0:
ret_text += f"<br>Astrology:<br>"
astrosplosions = 0;
for i in range(astrodice):
this_die = random.randint(1,6)
if i == 0:
ret_text += f"{this_die}"
else:
ret_text += f", {this_die}"
if this_die >= size:
successes = successes + 1
if this_die == 6:
astrosplosions = astrosplosions + 1
if this_die == 1:
new_die = random.randint(1,6)
ret_text += f", <font color=\"red\">{new_die}</font>"
if new_die < size:
successes = successes - 1
i = 0
while i < astrosplosions:
if i == 0:
ret_text += f", {this_die}, "
else:
ret_text += f", {this_die}"
if this_die >= size:
successes = successes + 1
if this_die == 1:
ones = ones + 1
if this_die == 6:
astrosplosions += 1
i = i + 1
ret_text += f"<br>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: !bw # [a][a]",
text_type='header', box_align='left')
return
def cmd_bwo(self, data):
all_data = data.message.strip().split()
try:
shade = all_data[1][0]
if shade == "B" or shade == "b":
size = 4
number_of_dice = int(all_data[1][1:])
elif shade == "G" or shade == "g":
size = 3
number_of_dice = int(all_data[1][1:])
elif shade == "W" or shade == "w":
size = 2
number_of_dice = int(all_data[1][1:])
else:
number_of_dice = int(all_data[1])
size = 4
astrodice = 0
if len(all_data) > 2:
if all_data[2] == "a" or all_data[2] == "A":
astrodice = 1
elif all_data[2] == "aa" or all_data[2] == "AA":
astrodice = 2
ret_text = "<br><font color='red'>Die Pool:</font><br>"
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 >= size:
successes = successes + 1
if this_die == 1:
ones = ones + 1
if this_die == 6:
number_of_dice += 1
explosions = explosions + 1
i = i + 1
if astrodice > 0:
ret_text += f"<br>Astrology:<br>"
astrosplosions = 0;
for i in range(astrodice):
this_die = random.randint(1,6)
if i == 0:
ret_text += f"{this_die}"
else:
ret_text += f", {this_die}"
if this_die >= size:
successes = successes + 1
if this_die == 6:
astrosplosions = astrosplosions + 1
if this_die == 1:
new_die = random.randint(1,6)
ret_text += f", <font color=\"red\">{new_die}</font>"
if new_die < size:
successes = successes - 1
i = 0
while i < astrosplosions:
if i == 0:
ret_text += f", {this_die}, "
else:
ret_text += f", {this_die}"
if this_die >= size:
successes = successes + 1
if this_die == 1:
ones = ones + 1
if this_die == 6:
astrosplosions += 1
ret_text += f"<br>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("!bwo # [a][a]",
text_type='header', box_align='left')
return
def cmd_advancement(self, data):
gs.gui_service.quick_gui("<table style=\"border:1px solid white\"><tr> <th></th> <th>Routine</th> <th>Difficult</th> <th>Challenging </th></tr> <tr> <td>1D</td> <td>Ob1 *</td> <td>Ob 1*</td> <td>Ob 2+ </td></tr> <tr> <td>2D</td> <td>Ob1</td> <td>Ob 2</td> <td>Ob 3+ </td></tr> <tr> <td>3D</td> <td>Ob1-2</td> <td>Ob 3</td> <td>Ob 4+ </td></tr> <tr> <td>4D</td> <td>Ob1-2</td> <td>Ob 3-4</td> <td>Ob 5+ </td></tr> <tr> <td>5D</td> <td>Ob1-3</td> <td>Ob 4-5</td> <td>Ob 6+ </td></tr> <tr> <td>6D</td> <td>Ob1-4</td> <td>Ob 5-6</td> <td>Ob 7+ </td></tr> <tr> <td>7D</td> <td>Ob1-4</td> <td>Ob 5-7</td> <td>Ob 8+ </td></tr> <tr> <td>8D</td> <td>Ob1-5</td> <td>Ob 6-8</td> <td>Ob 9+ </td></tr><tr><td>9D</td> <td>Ob1-6</td> <td>Ob 7-9</td> <td>Ob 10+ </td></tr> <tr> <td>10D</td> <td>Ob1-7</td> <td>Ob 8-10</td> <td>Ob 11+ </td></tr> <tr> <td>11D</td> <td>Ob1-8</td> <td>Ob 9-11</td> <td>Ob 12+ </td></tr> <tr> <td>12D</td> <td>Ob1-9</td> <td>Ob 10-12</td> <td>Ob 13+ </td></tr> <tr> <td>13D</td> <td>Ob1-10</td> <td>Ob 11-13</td> <td>Ob 14+ </td></tr> <tr> <td>14D</td> <td>Ob1-11</td> <td>Ob 12-14</td> <td>Ob 15+ </td></tr> <tr> <td>15D</td> <td>Ob1-12</td> <td>Ob 13-15</td> <td>Ob 16+ </td></tr> <tr> <td>16D</td> <td>Ob1-13</td> <td>Ob 14-16</td> <td>Ob 17+ </td></tr> <tr> <td>17D</td> <td>Ob1-14</td> <td>Ob 15-17</td> <td>Ob 18+ </td></tr> <tr> <td>18D</td> <td>Ob1-15</td> <td>Ob 16-18</td> <td>Ob 19+ </td></tr> </table>", text_type='header', box_align='left')
return
def cmd_prayers(self, data):
gs.gui_service.quick_gui("<table><tr><th>Ob</th><th>Effect</th></tr><tr><td>2</td><td>Boon: Open end any one ability for the rest of the scene.</td></tr><tr><td>3</td><td>Blessing: Add +1D to one health, steel, stat, or skill test (duration Intent)</td></tr><tr><td>3</td><td>Curse: Add +1 Ob to a single Ability for a single target, for a scene.</td></tr><tr><td>4</td><td>Aid: Add +1D plus an additional +1D per margain of success (maximum +3D) to any stat, skill, health, or steel test. You may cast this at the beginning of the scene and save it until needed, but must pick the stat/skill/whatever at casting time.</td></tr><tr><td>4-6</td><td>Hinderance: Immobalize a foe for a number of Fight actions equal to half your Faith. Base Ob is 4 and +1 per additional Foe.</td></tr><tr><td>5</td><td>Guidance: You can find the correct path. Literally or metaphorically.</td></tr><tr><td>5</td><td>Minor Miracle: When it is dark, we pray for light. When sorcerers chant, we pray their spells be broken. When the Blade is snapped, we pray that it be made whole. When blood ebbs from the wound, we pray that it be closed.</td></tr><tr><td>5</td><td>Purification: With the touch of a hand, drive out rot and lesser Evil Spirirts (Strength/Will B5 or lower).</td></tr><tr><td>6</td><td>Consecration: A lengthy prayer. Bar Spirits and Daemons whose Will is less than the user\'s Faith.</td></tr><tr><td>7</td><td>Inspiration: Reveal what the priest wishes to know to them. Also often what they did not intend to learn.</td></tr><tr><td>8</td><td>Intercession: Bring the devotee from danger. Or bring the danger from the devotee.</td></tr><tr><td>10</td><td>Miracle: When all hope is lost, when the cataclysm has come, we pray for the divine to manifest and save us. This is the big one - the column of scouring fire, the parting of the seas, the raging storm that destroys the fleet.</td></tr></table>", text_type='header', box_align='left')
return
def cmd_secondsight(self, data):
gs.gui_service.quick_gui("<table><tr><td>Ob 1</td><td>high power magic (major miracles, Mjolnir, the Burning Wheel, Ob 10 spells, Strength 10 spirits, etc.)</td></tr><tr><td>Ob 5</td><td>moderately-powered magic (minor miracles, Ob 5 spells, a risen corpse, the Belt of Flying, Dragon Slaying Sword, Spirit Weapons, Strength 5-spirits)</td></tr><tr><td>Ob 8</td><td>low power magic (Red Spectacles, Bless/Curse, Ob 2 spells, Strength 2 spirits etc.)</td></tr></table>", text_type='header', box_align='left')
return
def cmd_touchofages(self, data):
gs.gui_service.quick_gui("<table><tr><td>Ob 1</td><td>Type/name of object</td></tr><tr><td>Ob 2</td><td>Age of object</td></tr><tr><td>Ob 3</td><td>Length of the time the object has been in its current location</td></tr><tr><td>Ob 4</td><td>Recent events surrounding the object that left physical evidence</td></tr><tr><td>Ob 5</td><td>Recent events that left no physical mark</td></tr><tr><td>Ob 6</td><td>Past events that left their mark</td></tr><tr><td>Ob 7</td><td>Past events that left no mark</td></tr></table>", text_type='header', box_align='left')
return
def cmd_aurareading(self, data):
gs.gui_service.quick_gui("<table><tr><td>Detecting if the subject is alive, dead, from this plane or another</td><td>Ob 1</td></tr><tr><td>Reading an aura trait</td><td>Ob 1</td></tr><tr><td>Reading mood</td><td>Ob 2</td></tr><tr><td>Seeing a character trait</td><td>Ob 3</td></tr><tr><td>Seeing a die or call-on trait</td><td>Ob 4</td></tr><tr><td>Sensing a person's intent</td><td>Ob 4</td></tr><tr><td>Seeing an Instinct</td><td>Ob 6</td></tr><tr><td>Seeing a Belief</td><td>Ob 7</td></tr><tr><td>Seeing a character's past</td><td>Ob 8</td></tr><tr><td>Seeing a character's future</td><td>Ob 9</td></tr><tr><td>Reading an object to see if it is magical or mundane</td><td>Ob 1</td></tr><tr><td>Reading a school of magic</td><td>Ob 2</td></tr><tr><td>Deciphering a facet of a spell or enchantment</td><td>Ob 3</td></tr><tr><td>Naming a spell as it is being cast</td><td>Ob 6</td></tr><tr><td>Detecting the presence and nature of a spirit</td><td>Ob 10 - strength</td></tr></table>", text_type='header', box_align='left')
return
def cmd_sessionend(self, data):
gs.gui_service.quick_gui("<table> <tbody><tr> <th>Name</th> <th>Earns/Type</th> <th>Description </th></tr> <tr> <td>Belief</td> <td>1 <i>Fate</i></td> <td>Driving the game forward with a Belief </td></tr> <tr> <td>Instinct</td> <td>1 <i>Fate</i></td> <td>Playing an Instinct makes the character's life difficult </td></tr> <tr> <td>Trait</td> <td>1 <i>Fate</i></td> <td>Invoking a trait that sends the story in an unforeseen direction </td></tr> <tr> <td>Humour</td> <td>1 <i>Fate</i></td> <td>For an in-character game-stopper </td></tr> <tr> <td>Right Skill, Right Time</td> <td>1 <i>Fate</i></td> <td>For having a skill to make the story go </td></tr> <tr> <td>Embodiment</td> <td>1 <i>Persona</i></td> <td>For really good or distinctive roleplaying </td></tr> <tr> <td>Moldbreaker</td> <td>1 <i>Persona</i></td> <td>For going beyond the bounds of the character </td></tr> <tr> <td>Workhorse</td> <td>1 <i>Persona</i></td> <td>For doing all the work of the scenario </td></tr> <tr> <td>MVP</td> <td>1 <i>Persona</i></td> <td>For being the crucial element of success </td></tr> <tr> <td>Personal Goals</td> <td>1 <i>Persona</i></td> <td>Revenge, triumph, seduction, victory </td></tr> <tr> <td>Greater Goals</td> <td>1 <i>Deeds</i></td> <td>Accomplishing goals bigger than you! </td></tr> <tr> <td>Beyond the Call</td> <td>1 <i>Deeds</i></td> <td>Helping, no matter the cost </td></tr></tbody></table>", text_type='header', box_align='left')
def cmd_obs(self, data):
gs.gui_service.quick_gui("<table> <tr><td>Ob 1</td><td>A simple act done with litttle thought</td></tr> <tr><td>Ob 2</td><td>An act performed routinely at your job</td></tr> <tr><td>Ob 3</td><td>An act you can accomplish if you concentrate</td></tr> <tr><td>Ob 4</td><td>A risky act</td></tr> <tr><td>Ob 5</td><td>An act that requires expertise</td></tr> <tr><td>Ob 6</td><td>An act that requires a heroic effort</td></tr> <tr><td>Ob 7</td><td>An improbable feat</td></tr> <tr><td>Ob 8</td><td>An act requiring preternatural ability or a lot of help</td></tr> <tr><td>Ob 9</td><td>An act deemed nearly impossible</td></tr> <tr><td>Ob 10</td><td>A miracle</td></tr> </table>", text_type='header', box_align='left')