|
|
|
|
|
|
|
|
beg = ["a","e","i","o","u","ba","be","bi","bo","bu","by","y","da","de","di","do","du","dy","fa","fi","fo","fe","fu","ga","ge","gi","go","gu","ka","ke","ki","ko","ku","ky","ma","me","mi","mo","mu","na","ne","ni","no","nu","pa","pe","pi","po","pu","ra","re","ri","ro","ru","ry","sa","se","si","so","su","ta","te","ti","to","tu","ty","wa","we","wi","wo","wy","za","ze","zi","zo","zu","zy"] |
|
|
beg = ["a","e","i","o","u","ba","be","bi","bo","bu","by","y","da","de","di","do","du","dy","fa","fi","fo","fe","fu","ga","ge","gi","go","gu","ka","ke","ki","ko","ku","ky","ma","me","mi","mo","mu","na","ne","ni","no","nu","pa","pe","pi","po","pu","ra","re","ri","ro","ru","ry","sa","se","si","so","su","ta","te","ti","to","tu","ty","wa","we","wi","wo","wy","za","ze","zi","zo","zu","zy"] |
|
|
mid = beg + ["l","x","n","r"] |
|
|
mid = beg + ["l","x","n","r"] |
|
|
|
|
|
|
|
|
def gen_name(length=None, minimum=3, maximum=9): |
|
|
|
|
|
|
|
|
def binarize(num, l=None): |
|
|
|
|
|
r = bin(num)[2:] |
|
|
|
|
|
try: |
|
|
|
|
|
l = int(l) |
|
|
|
|
|
except: |
|
|
|
|
|
l = None |
|
|
|
|
|
if l != None: |
|
|
|
|
|
while len(r) < l: |
|
|
|
|
|
r = "0" + r |
|
|
|
|
|
return r |
|
|
|
|
|
|
|
|
|
|
|
def gen_name(length=None, minimum=3): |
|
|
|
|
|
maximum = 8 |
|
|
if length == None: |
|
|
if length == None: |
|
|
lgt = r.randint(minimum,maximum) |
|
|
lgt = r.randint(minimum,maximum) |
|
|
else: |
|
|
else: |
|
|
|
|
|
if length > maximum: |
|
|
|
|
|
length = maximum |
|
|
|
|
|
print("Maximum name length is 8.") |
|
|
lgt = length |
|
|
lgt = length |
|
|
morae = [] |
|
|
morae = [] |
|
|
while len("".join(morae)) < lgt: |
|
|
while len("".join(morae)) < lgt: |
|
|
|
|
|
|
|
|
self.loc_desc = Plot.loc1[r.randint(0, len(Plot.loc1)-1)] |
|
|
self.loc_desc = Plot.loc1[r.randint(0, len(Plot.loc1)-1)] |
|
|
self.locIndex = r.randint(0, len(Plot.loc2)-1) |
|
|
self.locIndex = r.randint(0, len(Plot.loc2)-1) |
|
|
if self.locIndex == len(Plot.loc2) - 1: |
|
|
if self.locIndex == len(Plot.loc2) - 1: |
|
|
self.location = "battlefield on " |
|
|
|
|
|
|
|
|
self.battlefield = 1 |
|
|
self.locIndex = r.randint(0, len(Plot.loc2)-2) |
|
|
self.locIndex = r.randint(0, len(Plot.loc2)-2) |
|
|
self.mainLocation = Plot.loc2[self.locIndex] |
|
|
|
|
|
if self.mainLocation[0].lower() in ["a","e","i","o","u"]: |
|
|
|
|
|
self.location += "an " |
|
|
|
|
|
|
|
|
self.location = Plot.loc2[self.locIndex] |
|
|
|
|
|
if self.location[0].lower() in ["a","e","i","o","u"]: |
|
|
|
|
|
self.locart = 1 |
|
|
else: |
|
|
else: |
|
|
self.location += "a " |
|
|
|
|
|
self.location += self.mainLocation |
|
|
|
|
|
|
|
|
self.locart = 0 |
|
|
else: |
|
|
else: |
|
|
self.location = Plot.loc2[self.locIndex] |
|
|
self.location = Plot.loc2[self.locIndex] |
|
|
|
|
|
self.battlefield = 0 |
|
|
|
|
|
self.locart = 0 |
|
|
self.missIndex = r.randint(0, len(Plot.miss)-1) |
|
|
self.missIndex = r.randint(0, len(Plot.miss)-1) |
|
|
self.oops = r.randint(1,12) |
|
|
self.oops = r.randint(1,12) |
|
|
self.mission = "" |
|
|
|
|
|
if self.oops == 12: |
|
|
if self.oops == 12: |
|
|
self.mission += "...well, they weren't paying attention, so don't tell them, but they're supposed " |
|
|
|
|
|
self.mission += Plot.miss[r.randint(0, len(Plot.miss)-1)] + "!" |
|
|
|
|
|
|
|
|
self.oops = 1 |
|
|
|
|
|
else: |
|
|
|
|
|
self.oops = 0 |
|
|
|
|
|
self.mission = Plot.miss[r.randint(0, len(Plot.miss)-1)] |
|
|
self.probIndex = r.randint(0, len(Plot.prob)-1) |
|
|
self.probIndex = r.randint(0, len(Plot.prob)-1) |
|
|
self.problem = Plot.prob[self.probIndex] |
|
|
self.problem = Plot.prob[self.probIndex] |
|
|
self.secProblem = None |
|
|
self.secProblem = None |
|
|
self.thirdProblem = None |
|
|
self.thirdProblem = None |
|
|
if self.problem["id"] in [1,2]: |
|
|
|
|
|
self.problem["name"] += " led by " + gen_name() |
|
|
|
|
|
if self.problem["id"] in [4,7,8,10]: |
|
|
|
|
|
self.problem["name"] += " named " + gen_name(minimum=5, maximum=12) |
|
|
|
|
|
|
|
|
self.problem["name"] = gen_name() |
|
|
if self.problem["id"] == 3: |
|
|
if self.problem["id"] == 3: |
|
|
self.secProblem = {"name": "Parasites", "shortname": "parasites", "stats": [3,4,2,3]} |
|
|
self.secProblem = {"name": "Parasites", "shortname": "parasites", "stats": [3,4,2,3]} |
|
|
if self.problem["id"] == 10: |
|
|
if self.problem["id"] == 10: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Character: |
|
|
class Character: |
|
|
GADGETS = [ {"name": "Awesome Dagger of Sneak(?) Attacks", "description": "Yell 'Sneak Attack!' to count a mixed-success Body attack as a success.", "reusable": True}, |
|
|
|
|
|
{"name": "Button of Uselessness", "description": f"This large, red button can be stuck onto any flat surface, horizontal, vertical, or otherwise. A short time after it has been placed, any character (friend or foe) nearby must succeed a Brains roll to avoid pressing the button. Pressing the button does nothing, but this action takes the place of anything that might otherwise be done during an Event if the Brains roll is failed. The button can be pressed {r.randint(1,6)} times before it breaks and no longer compels others to press it.", "reusable": False}, |
|
|
|
|
|
{"name": "Encyclopedia of Stuff I Totally Knew", "description": "Add 2 points to the target number of any uncontested Brains roll, or 1 point to the target number of a contested Brains roll.", "reusable": True}, |
|
|
|
|
|
{"name": "Medkit", "description": "Make a Brains/Order roll to restore 2 lost Body points, or 1 on a Mixed Success. If the character has medical training, restored Body points may be doubled.", "reusable": False}, |
|
|
|
|
|
{"name": "Potion of Healing", "description": "Restore 1 lost Body point. Using counts as an Event but no roll is needed unless it’s contested.", "reusable": False}, |
|
|
|
|
|
{"name": "Tinfoil Helm of Shielding", "description": "Count any Brains damage as a mixed success. If you take Body damage, roll 1d6; on a 6, the Helm is useless until you take a nap.", "reusable": True}, |
|
|
|
|
|
{"name": "Handy Toothbrush", "description": "Scrub the Space Gunk off whatever object you're interacting with to turn a mixed Order success to make that object work into a full success.", "reusable": True}, |
|
|
|
|
|
{"name": "Jar of ... Something", "description": "Throw it (Body/Chaos) at another character to make them spend an Event cleaning it off, or throw it at the floor to make a ten-foot circle of difficult terrain.", "reusable": False}, |
|
|
|
|
|
{"name": "Pocket Sand!", "description": "Yell 'Pocket Sand!' to count a successful Body attack against you as a mixed success.", "reusable": False}, |
|
|
|
|
|
{"name": "The Fabulous Grappling Hook", "description": "As an Event, instantly move 50 feet in any direction. (Make sure you have 50 feet available to move in or take 1 Body damage when you arrive short of that.)", "reusable": True}, |
|
|
|
|
|
{"name": "Pocket Accordion", "description": "Make a Brains/Order or Brains/Chaos roll. On a success, any nearby opponent has -1 Brains during their next event. On a failure, everybody nearby, including you, has -1 Brains on their next event.", "reusable": True}, |
|
|
|
|
|
{"name": "Cloak of Adsorption", "description": "The cloak starts out white. Whenever you are the target of a successful attack, the cloak becomes the color of whatever hit you. If your cloak is already the same color as whatever hit you, the attack becomes a mixed success and the cloak turns black and can no longer absorb colors. The cloak becomes white again after a nap.", "reusable": True}, |
|
|
|
|
|
{"name": "Cloak of Absorption", "description": "The cloak starts out white. You can remove the cloak and lay it over difficult terrain to make it easy terrain; if the terrain is difficult because the ground is wet, the cloak becomes wet and the ground in that area becomes dry. The cloak dries out after a nap.", "reusable": True}, |
|
|
|
|
|
{"name": "Cloak of Desorption", "description": "The cloak starts out black. As an Event, you can cause a gas to evaporate from the cloak, leaving it a dingy gray and healing 1 Body to anyone within ten feet of you. The cloak becomes black again after a nap.", "reusable": True}, |
|
|
|
|
|
{"name": "Huge Goggles", "description": "If you take Body damage, roll 1d6; on a 6, the lenses of the Goggles break until you take a nap.", "reusable": True}, |
|
|
|
|
|
|
|
|
GADGETS = [ {"id": 0, "name": "Awesome Dagger of Sneak(?) Attacks", "description": "Yell 'Sneak Attack!' to count a mixed-success Body attack as a success.", "reusable": True}, |
|
|
|
|
|
{"id": 1, "name": "Button of Uselessness", "description": f"This large, red button can be stuck onto any flat surface, horizontal, vertical, or otherwise. A short time after it has been placed, any character (friend or foe) nearby must succeed a Brains roll to avoid pressing the button. Pressing the button does nothing, but this action takes the place of anything that might otherwise be done during an Event if the Brains roll is failed. The button can be pressed {r.randint(1,6)} times before it breaks and no longer compels others to press it.", "reusable": False}, |
|
|
|
|
|
{"id": 2, "name": "Encyclopedia of Stuff I Totally Knew", "description": "Add 2 points to the target number of any uncontested Brains roll, or 1 point to the target number of a contested Brains roll.", "reusable": True}, |
|
|
|
|
|
{"id": 3, "name": "Medkit", "description": "Make a Brains/Order roll to restore 2 lost Body points, or 1 on a Mixed Success. If the character has medical training, restored Body points may be doubled.", "reusable": False}, |
|
|
|
|
|
{"id": 4, "name": "Potion of Healing", "description": "Restore 1 lost Body point. Using counts as an Event but no roll is needed unless it’s contested.", "reusable": False}, |
|
|
|
|
|
{"id": 5, "name": "Tinfoil Helm of Shielding", "description": "Count any Brains damage as a mixed success. If you take Body damage, roll 1d6; on a 6, the Helm is useless until you take a nap.", "reusable": True}, |
|
|
|
|
|
{"id": 6, "name": "Handy Toothbrush", "description": "Scrub the Space Gunk off whatever object you're interacting with to turn a mixed Order success to make that object work into a full success.", "reusable": True}, |
|
|
|
|
|
{"id": 7, "name": "Jar of ... Something", "description": "Throw it (Body/Chaos) at another character to make them spend an Event cleaning it off, or throw it at the floor to make a ten-foot circle of difficult terrain.", "reusable": False}, |
|
|
|
|
|
{"id": 8, "name": "Pocket Sand!", "description": "Yell 'Pocket Sand!' to count a successful Body attack against you as a mixed success.", "reusable": False}, |
|
|
|
|
|
{"id": 9, "name": "The Fabulous Grappling Hook", "description": "As an Event, instantly move 50 feet in any direction. (Make sure you have 50 feet available to move in or take 1 Body damage when you arrive short of that.)", "reusable": True}, |
|
|
|
|
|
{"id": 10, "name": "Pocket Accordion", "description": "Make a Brains/Order or Brains/Chaos roll. On a success, any nearby opponent has -1 Brains during their next event. On a failure, everybody nearby, including you, has -1 Brains on their next event.", "reusable": True}, |
|
|
|
|
|
{"id": 11, "name": "Cloak of Adsorption", "description": "The cloak starts out white. Whenever you are the target of a successful attack, the cloak becomes the color of whatever hit you. If your cloak is already the same color as whatever hit you, the attack becomes a mixed success and the cloak turns black and can no longer absorb colors. The cloak becomes white again after a nap.", "reusable": True}, |
|
|
|
|
|
{"id": 12, "name": "Cloak of Absorption", "description": "The cloak starts out white. You can remove the cloak and lay it over difficult terrain to make it easy terrain; if the terrain is difficult because the ground is wet, the cloak becomes wet and the ground in that area becomes dry. The cloak dries out after a nap.", "reusable": True}, |
|
|
|
|
|
{"id": 13, "name": "Cloak of Desorption", "description": "The cloak starts out black. As an Event, you can cause a gas to evaporate from the cloak, leaving it a dingy gray and healing 1 Body to anyone within ten feet of you. The cloak becomes black again after a nap.", "reusable": True}, |
|
|
|
|
|
{"id": 14, "name": "Cloak of Food Portions", "description": "Wearing this cloak causes it to flare out at the base, making the wearer resemble a pyramid. In conversations regarding food the wearer can add +2 to Brains rolls when trying to convince others to alter their diets. This can be done once per nap. Considering how many large things tend to snack on kobolds, this has been found to actually be quite useful.", "reusable": True}, |
|
|
|
|
|
{"id": 15, "name": "Huge Goggles", "description": "If you take Body damage, roll 1d6; on a 6, the lenses of the Goggles break until you take a nap.", "reusable": True}, |
|
|
|
|
|
] |
|
|
|
|
|
CAREERS = [ {"id": 0, "name": "Soldier/Guard"}, |
|
|
|
|
|
{"id": 1, "name": "Pilot"}, |
|
|
|
|
|
{"id": 2, "name": "Medic"}, |
|
|
|
|
|
{"id": 3, "name": "Mechanic"}, |
|
|
|
|
|
{"id": 4, "name": "Politician"}, |
|
|
|
|
|
{"id": 5, "name": "Spellcaster"}, |
|
|
|
|
|
{"id": 6, "name": "Performer"}, |
|
|
|
|
|
{"id": 7, "name": "Historian"}, |
|
|
|
|
|
{"id": 8, "name": "Spy"}, |
|
|
|
|
|
{"id": 9, "name": "Cook"}, |
|
|
|
|
|
{"id": 10, "name": "Cartographer"}, |
|
|
|
|
|
{"id": 11, "name": "Inventor"}, |
|
|
|
|
|
{"id": 12, "name": "Merchant"} |
|
|
] |
|
|
] |
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
def __init__(self): |
|
|
|
|
|
|
|
|
self.stats = stats |
|
|
self.stats = stats |
|
|
|
|
|
|
|
|
def gen_career(self): |
|
|
def gen_career(self): |
|
|
self.career = r.choice(["Soldier/Guard","Pilot","Medic","Mechanic","Politician","Spellcaster","Performer","Historian","Spy","Cook","Cartographer","Inventor","Merchant"]) |
|
|
|
|
|
|
|
|
self.career = r.choice(Character.CAREERS) |
|
|
|
|
|
|
|
|
def gen_gadget(self): |
|
|
def gen_gadget(self): |
|
|
self.gadget = r.choice(Character.GADGETS) |
|
|
self.gadget = r.choice(Character.GADGETS) |
|
|
|
|
|
|
|
|
f"<div class='kobold'>\n" |
|
|
f"<div class='kobold'>\n" |
|
|
f" <span class='koboldid'>\n" |
|
|
f" <span class='koboldid'>\n" |
|
|
f" <span class='koboldname'>{self.name}</span><br>\n" |
|
|
f" <span class='koboldname'>{self.name}</span><br>\n" |
|
|
f" <span class='koboldcareer'>Kobold {self.career}</span>\n" |
|
|
|
|
|
|
|
|
f" <span class='koboldcareer'>Kobold {self.career.name}</span>\n" |
|
|
f" </span>\n" |
|
|
f" </span>\n" |
|
|
f" <br>\n" |
|
|
f" <br>\n" |
|
|
f" <span class='koboldstats'>\n" |
|
|
f" <span class='koboldstats'>\n" |
|
|
|
|
|
|
|
|
print(f"Gadget: {self.gadget['name']} ({self.gadget['description']}{'- Reusable' if self.gadget['reusable'] else ''})") |
|
|
print(f"Gadget: {self.gadget['name']} ({self.gadget['description']}{'- Reusable' if self.gadget['reusable'] else ''})") |
|
|
|
|
|
|
|
|
class Ship: |
|
|
class Ship: |
|
|
def __init__(self): |
|
|
|
|
|
self.name1 = r.choice(["Red","Orange","Yellow","Green","Blue","Violet","Dark","Light","Frenzied","Maniacal","Ancient"]) |
|
|
|
|
|
self.name2 = r.choice(["Moon","Comet","Star","Saber","World-Eater","Dancer","Looter","Phlogiston","Fireball","Mecha","Raptor"]) |
|
|
|
|
|
self.gqual = r.choice(["is stealthy & unarmored","is speedy & unarmored","is maneuverable & unarmored","is always repairable","is self-repairing","is flamboyant & speedy","is slow & armored","is flamboyant & armored","is hard to maneuver & armored","has Too Many Weapons!","has a prototype hyperdrive"]) |
|
|
|
|
|
self.bqual = r.choice(["has an annoying AI","has inconveniently crossed circuits","has an unpredictable power source","drifts to the right","is haunted","was recently 'found' so the kobolds are unused to it","is too cold","has a constant odd smell","its interior design... changes","its water pressure shifts between slow drip and power wash","it leaves a visible smoke trail"]) |
|
|
|
|
|
|
|
|
NAME1 = ["Red","Orange","Yellow","Green","Blue","Violet","Dark","Light","Frenzied","Maniacal","Ancient"] |
|
|
|
|
|
NAME2 = ["Moon","Comet","Star","Saber","World-Eater","Dancer","Looter","Phlogiston","Fireball","Mecha","Raptor"] |
|
|
|
|
|
GQUAL = ["is stealthy & unarmored","is speedy & unarmored","is maneuverable & unarmored","is always repairable","is self-repairing","is flamboyant & speedy","is slow & armored","is flamboyant & armored","is hard to maneuver & armored","has Too Many Weapons!","has a prototype hyperdrive"] |
|
|
|
|
|
BQUAL = ["has an annoying AI","has inconveniently crossed circuits","has an unpredictable power source","drifts to the right","is haunted","was recently 'found' so the kobolds are unused to it","is too cold","has a constant odd smell","its interior design... changes","its water pressure shifts between slow drip and power wash","it leaves a visible smoke trail"] |
|
|
|
|
|
def __init__(self, name1=None, name2=None, gqual = None, bqual = None): |
|
|
|
|
|
self.name1 = name1 if name1 != None else r.choice(Ship.NAME1) |
|
|
|
|
|
self.name2 = name2 if name2 != None else r.choice(Ship.NAME2) |
|
|
|
|
|
self.gqual = gqual if gqual != None else r.choice(Ship.GQUAL) |
|
|
|
|
|
self.bqual = bqual if bqual != None else r.choice(Ship.BQUAL) |
|
|
self.fullname = f"{self.name1} {self.name2}" |
|
|
self.fullname = f"{self.name1} {self.name2}" |
|
|
|
|
|
|
|
|
def print(self, html=False): |
|
|
def print(self, html=False): |
|
|
|
|
|
|
|
|
print(shipText) |
|
|
print(shipText) |
|
|
|
|
|
|
|
|
class Campaign: |
|
|
class Campaign: |
|
|
def __init__(self, n=None, makeChars=True): |
|
|
|
|
|
n = 6 if n == None else n |
|
|
|
|
|
self.ship = Ship() |
|
|
|
|
|
self.params = Plot() |
|
|
|
|
|
if makeChars: |
|
|
|
|
|
self.characters = [] |
|
|
|
|
|
for _ in range(n): |
|
|
|
|
|
c = Character() |
|
|
|
|
|
c.generate() |
|
|
|
|
|
self.characters.append(c) |
|
|
|
|
|
self.art = "an" if self.params.loc_desc[0] in ["a","e","i","o","u"] else "a" |
|
|
|
|
|
|
|
|
ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?- " |
|
|
|
|
|
NAMELETS = ['a', 'e', 'i', 'o', 'u', 'b', 'y', 'd', 'f', 'g', 'k', 'm', 'n', 'p', 'r', 's', 't', 'w', 'z', 'l', 'x'] |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, n=None, makeChars=True, fromPW=False, pw=None): |
|
|
|
|
|
if fromPW == True: |
|
|
|
|
|
self.ship = None |
|
|
|
|
|
self.params. = None |
|
|
|
|
|
self.characters = None |
|
|
|
|
|
self.art = None |
|
|
|
|
|
self.decode_key(pw) |
|
|
|
|
|
else: |
|
|
|
|
|
n = 6 if n == None else n |
|
|
|
|
|
self.ship = Ship() |
|
|
|
|
|
self.params = Plot() |
|
|
|
|
|
self.params.problem["fullname"] = "" |
|
|
|
|
|
if self.params.problem["id"] in [1,2]: |
|
|
|
|
|
self.params.problem["fullname"] += " led by " + self.params.problem["name"] |
|
|
|
|
|
if self.params.problem["id"] in [4,7,8,10]: |
|
|
|
|
|
self.params.problem["fullname"] += " named " + self.params.problem["name"] |
|
|
|
|
|
if makeChars: |
|
|
|
|
|
self.characters = [] |
|
|
|
|
|
for _ in range(n): |
|
|
|
|
|
c = Character() |
|
|
|
|
|
c.generate() |
|
|
|
|
|
self.characters.append(c) |
|
|
|
|
|
self.art = "an" if self.params.loc_desc[0] in ["a","e","i","o","u"] else "a" |
|
|
|
|
|
|
|
|
|
|
|
def generate_key(self): |
|
|
|
|
|
""" |
|
|
|
|
|
"PACKTA CTICS! ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- -------" should generate the Season 3 Pack Tactics crew. |
|
|
|
|
|
"JUSTIN BAILEY" and "NARPAS SWORD" should do something too. |
|
|
|
|
|
Key is analphanumeric string generated from a bitfield |
|
|
|
|
|
Bitfield is: |
|
|
|
|
|
Location 1: 7 bits |
|
|
|
|
|
Location 2: 7 bits |
|
|
|
|
|
Location Battlefield: 1 bit |
|
|
|
|
|
Mission: 7 bits |
|
|
|
|
|
Oops: 1 bit |
|
|
|
|
|
Problem 1: 7 bits |
|
|
|
|
|
Problem 1 name: 40 bits |
|
|
|
|
|
Problem 2: 7 bits |
|
|
|
|
|
Ship name 1: 7 bits |
|
|
|
|
|
Ship name 2: 7 bits |
|
|
|
|
|
Ship gqual: 7 bits |
|
|
|
|
|
Ship bqual: 7 bits |
|
|
|
|
|
Character 1 name: 40 bits |
|
|
|
|
|
Character 1 career: 7 bits |
|
|
|
|
|
Character 1 order: 3 bits |
|
|
|
|
|
Character 1 chaos: 3 bits |
|
|
|
|
|
Character 1 body: 3 bits |
|
|
|
|
|
Character 1 brain: 3 bits |
|
|
|
|
|
Character 1 gadget: 7 bits |
|
|
|
|
|
Character 2 name: 40 bits |
|
|
|
|
|
Character 2 career: 7 bits |
|
|
|
|
|
Character 2 order: 3 bits |
|
|
|
|
|
Character 2 chaos: 3 bits |
|
|
|
|
|
Character 2 body: 3 bits |
|
|
|
|
|
Character 2 brain: 3 bits |
|
|
|
|
|
Character 2 gadget: 7 bits |
|
|
|
|
|
Character 3 name: 40 bits |
|
|
|
|
|
Character 3 career: 7 bits |
|
|
|
|
|
Character 3 order: 3 bits |
|
|
|
|
|
Character 3 chaos: 3 bits |
|
|
|
|
|
Character 3 body: 3 bits |
|
|
|
|
|
Character 3 brain: 3 bits |
|
|
|
|
|
Character 3 gadget: 7 bits |
|
|
|
|
|
Character 4 name: 40 bits |
|
|
|
|
|
Character 4 career: 7 bits |
|
|
|
|
|
Character 4 order: 3 bits |
|
|
|
|
|
Character 4 chaos: 3 bits |
|
|
|
|
|
Character 4 body: 3 bits |
|
|
|
|
|
Character 4 brain: 3 bits |
|
|
|
|
|
Character 4 gadget: 7 bits |
|
|
|
|
|
Character 5 name: 40 bits |
|
|
|
|
|
Character 5 career: 7 bits |
|
|
|
|
|
Character 5 order: 3 bits |
|
|
|
|
|
Character 5 chaos: 3 bits |
|
|
|
|
|
Character 5 body: 3 bits |
|
|
|
|
|
Character 5 brain: 3 bits |
|
|
|
|
|
Character 5 gadget: 7 bits |
|
|
|
|
|
Character 6 name: 40 bits |
|
|
|
|
|
Character 6 career: 7 bits |
|
|
|
|
|
Character 6 order: 3 bits |
|
|
|
|
|
Character 6 chaos: 3 bits |
|
|
|
|
|
Character 6 body: 3 bits |
|
|
|
|
|
Character 6 brain: 3 bits |
|
|
|
|
|
Character 6 gadget: 7 bits |
|
|
|
|
|
104 for campaign |
|
|
|
|
|
396 for characters |
|
|
|
|
|
total 501 |
|
|
|
|
|
11 remaining |
|
|
|
|
|
""" |
|
|
|
|
|
self.key = "" |
|
|
|
|
|
l1 = bin(Plot.loc1.index(self.params.loc_desc))[2:] |
|
|
|
|
|
l2 = bin(Plot.loc2.index(self.params.location))[2:] |
|
|
|
|
|
lb = bin(self.params.battlefield)[2:] |
|
|
|
|
|
op = bin(self.params.oops)[2:] |
|
|
|
|
|
ms = bin(Plot.miss.index(self.params.mission))[2:] |
|
|
|
|
|
pb1 = bin(self.params.probIndex)[2:] |
|
|
|
|
|
if self.params.probIndex == 10: |
|
|
|
|
|
pb2 = bin(self.params.secProbIndex)[2:] |
|
|
|
|
|
else: |
|
|
|
|
|
pb2 = bin(127)[2:] |
|
|
|
|
|
pbname = "".join([bin(Campaign.NAMELETS.index(x.lower()))[2:] for x in self.params.problem["name"]]) |
|
|
|
|
|
n1 = bin(Ship.NAME1.index(self.ship.name1))[2:] |
|
|
|
|
|
n2 = bin(Ship.NAME2.index(self.ship.name2))[2:] |
|
|
|
|
|
gq = bin(Ship.GQUAL.index(self.ship.gqual))[2:] |
|
|
|
|
|
bq = bin(Ship.BQUAL.index(self.ship.bqual))[2:] |
|
|
|
|
|
chars = {} |
|
|
|
|
|
i = 0 |
|
|
|
|
|
for chct in self.characters: |
|
|
|
|
|
chars[i] = { |
|
|
|
|
|
"name": "".join([bin(Campaign.NAMELETS.index(x.lower()))[2:] for x in chct.name]), |
|
|
|
|
|
"career": bin(chct.career["id"])[2:], |
|
|
|
|
|
"order": bin(chct.stats[0])[2:], |
|
|
|
|
|
"chaos": bin(chct.stats[1])[2:], |
|
|
|
|
|
"body": bin(chct.stats[2])[2:], |
|
|
|
|
|
"brains": bin(chct.stats[3])[2:], |
|
|
|
|
|
"gadget": bin(chct.gadget["id"])[2:] |
|
|
|
|
|
} |
|
|
|
|
|
i += 1 |
|
|
|
|
|
# print(chars) |
|
|
|
|
|
while len(l1) < 7: |
|
|
|
|
|
l1 = "0" + l1 |
|
|
|
|
|
# print(f"Len(l1) = {len(l1)}") |
|
|
|
|
|
while len(l2) < 7: |
|
|
|
|
|
l2 = "0" + l2 |
|
|
|
|
|
# print(f"Len(l2) = {len(l2)}") |
|
|
|
|
|
while len(ms) < 7: |
|
|
|
|
|
ms = "0" + ms |
|
|
|
|
|
# print(f"Len(ms) = {len(ms)}") |
|
|
|
|
|
while len(pb1) < 7: |
|
|
|
|
|
pb1 = "0" + pb1 |
|
|
|
|
|
# print(f"Len(pb1) = {len(pb1)}") |
|
|
|
|
|
while len(pb2) < 7: |
|
|
|
|
|
pb2 = "0" + pb2 |
|
|
|
|
|
# print(f"Len(pb2) = {len(pb2)}") |
|
|
|
|
|
while len(pbname) < 40: |
|
|
|
|
|
pbname = "0" + pbname |
|
|
|
|
|
# print(f"Len(pbname) = {len(pbname)}") |
|
|
|
|
|
while len(n1) < 7: |
|
|
|
|
|
n1 = "0" + n1 |
|
|
|
|
|
# print(f"Len(n1) = {len(n1)}") |
|
|
|
|
|
while len(n2) < 7: |
|
|
|
|
|
n2 = "0" + n2 |
|
|
|
|
|
# print(f"Len(n2) = {len(n2)}") |
|
|
|
|
|
while len(gq) < 7: |
|
|
|
|
|
gq = "0" + gq |
|
|
|
|
|
# print(f"Len(gq) = {len(gq)}") |
|
|
|
|
|
while len(bq) < 7: |
|
|
|
|
|
bq = "0" + bq |
|
|
|
|
|
# print(f"Len(bq) = {len(bq)}") |
|
|
|
|
|
self.key += l1 + l2 + lb + op + ms + pb1 + pb2 + pbname + n1 + n2 + gq + bq |
|
|
|
|
|
for k,chct in chars.items(): |
|
|
|
|
|
while len(chct["name"]) < 40: |
|
|
|
|
|
chct["name"] = "0" + chct["name"] |
|
|
|
|
|
# print(f"Len(chct.name) = {len(chct['name'])}") |
|
|
|
|
|
while len(chct["career"]) < 7: |
|
|
|
|
|
chct["career"] = "0" + chct["career"] |
|
|
|
|
|
# print(f"Len(chct.career) = {len(chct['career'])}") |
|
|
|
|
|
while len(chct["order"]) < 3: |
|
|
|
|
|
chct["order"] = "0" + chct["order"] |
|
|
|
|
|
# print(f"Len(chct.order) = {len(chct['order'])}") |
|
|
|
|
|
while len(chct["chaos"]) < 3: |
|
|
|
|
|
chct["chaos"] = "0" + chct["chaos"] |
|
|
|
|
|
# print(f"Len(chct.chaos) = {len(chct['chaos'])}") |
|
|
|
|
|
while len(chct["body"]) < 3: |
|
|
|
|
|
chct["body"] = "0" + chct["body"] |
|
|
|
|
|
# print(f"Len(chct.body) = {len(chct['body'])}") |
|
|
|
|
|
while len(chct["brains"]) < 3: |
|
|
|
|
|
chct["brains"] = "0" + chct["brains"] |
|
|
|
|
|
# print(f"Len(chct.brains) = {len(chct['brains'])}") |
|
|
|
|
|
while len(chct["gadget"]) < 7: |
|
|
|
|
|
chct["gadget"] = "0" + chct["gadget"] |
|
|
|
|
|
# print(f"Len(chct.gadget) = {len(chct['gadget'])}") |
|
|
|
|
|
self.key += chct["name"] + chct["career"] + chct["order"] + chct["chaos"] + chct["body"] + chct["brains"] + chct["gadget"] |
|
|
|
|
|
# print(len(self.key)) |
|
|
|
|
|
while len(self.key) < 509: |
|
|
|
|
|
self.key = self.key + "0" |
|
|
|
|
|
# print(len(self.key)) |
|
|
|
|
|
self.okey = "" |
|
|
|
|
|
letters = [] |
|
|
|
|
|
letter = [] |
|
|
|
|
|
for bit in self.key: |
|
|
|
|
|
letter.append(bit) |
|
|
|
|
|
if len(letter) == 6: |
|
|
|
|
|
letters.append(Campaign.ALPHABET[int("".join(letter),2)]) |
|
|
|
|
|
letter = [] |
|
|
|
|
|
words = [] |
|
|
|
|
|
word = [] |
|
|
|
|
|
for lt in letters: |
|
|
|
|
|
word.append(lt) |
|
|
|
|
|
if len(word) == 6: |
|
|
|
|
|
words.append("".join(word)) |
|
|
|
|
|
word = [] |
|
|
|
|
|
words.append("".join(word)) |
|
|
|
|
|
self.password = " ".join(words) |
|
|
|
|
|
# print(self.password) |
|
|
|
|
|
return self.password |
|
|
|
|
|
|
|
|
|
|
|
def decode_key(self, pw): |
|
|
|
|
|
""" |
|
|
|
|
|
Repeating this here for the sake of convenience. |
|
|
|
|
|
Location 1: 7 bits |
|
|
|
|
|
Location 2: 7 bits |
|
|
|
|
|
Location Battlefield: 1 bit |
|
|
|
|
|
Mission: 7 bits |
|
|
|
|
|
Oops: 1 bit |
|
|
|
|
|
Problem 1: 7 bits |
|
|
|
|
|
Problem 1 name: 40 bits |
|
|
|
|
|
Problem 2: 7 bits |
|
|
|
|
|
Ship name 1: 7 bits |
|
|
|
|
|
Ship name 2: 7 bits |
|
|
|
|
|
Ship gqual: 7 bits |
|
|
|
|
|
Ship bqual: 7 bits |
|
|
|
|
|
Character 1 name: 40 bits |
|
|
|
|
|
Character 1 career: 7 bits |
|
|
|
|
|
Character 1 order: 3 bits |
|
|
|
|
|
Character 1 chaos: 3 bits |
|
|
|
|
|
Character 1 body: 3 bits |
|
|
|
|
|
Character 1 brain: 3 bits |
|
|
|
|
|
Character 1 gadget: 7 bits |
|
|
|
|
|
Character 2 name: 40 bits |
|
|
|
|
|
Character 2 career: 7 bits |
|
|
|
|
|
Character 2 order: 3 bits |
|
|
|
|
|
Character 2 chaos: 3 bits |
|
|
|
|
|
Character 2 body: 3 bits |
|
|
|
|
|
Character 2 brain: 3 bits |
|
|
|
|
|
Character 2 gadget: 7 bits |
|
|
|
|
|
Character 3 name: 40 bits |
|
|
|
|
|
Character 3 career: 7 bits |
|
|
|
|
|
Character 3 order: 3 bits |
|
|
|
|
|
Character 3 chaos: 3 bits |
|
|
|
|
|
Character 3 body: 3 bits |
|
|
|
|
|
Character 3 brain: 3 bits |
|
|
|
|
|
Character 3 gadget: 7 bits |
|
|
|
|
|
Character 4 name: 40 bits |
|
|
|
|
|
Character 4 career: 7 bits |
|
|
|
|
|
Character 4 order: 3 bits |
|
|
|
|
|
Character 4 chaos: 3 bits |
|
|
|
|
|
Character 4 body: 3 bits |
|
|
|
|
|
Character 4 brain: 3 bits |
|
|
|
|
|
Character 4 gadget: 7 bits |
|
|
|
|
|
Character 5 name: 40 bits |
|
|
|
|
|
Character 5 career: 7 bits |
|
|
|
|
|
Character 5 order: 3 bits |
|
|
|
|
|
Character 5 chaos: 3 bits |
|
|
|
|
|
Character 5 body: 3 bits |
|
|
|
|
|
Character 5 brain: 3 bits |
|
|
|
|
|
Character 5 gadget: 7 bits |
|
|
|
|
|
Character 6 name: 40 bits |
|
|
|
|
|
Character 6 career: 7 bits |
|
|
|
|
|
Character 6 order: 3 bits |
|
|
|
|
|
Character 6 chaos: 3 bits |
|
|
|
|
|
Character 6 body: 3 bits |
|
|
|
|
|
Character 6 brain: 3 bits |
|
|
|
|
|
Character 6 gadget: 7 bits |
|
|
|
|
|
""" |
|
|
|
|
|
densePwd = pw.replace(" ", "") |
|
|
|
|
|
if densePwd == "PACKTACTICS!------------------------------------------------------------------------------------": |
|
|
|
|
|
# Create a campaign featuring the Season 3 Pack Tactics crew. |
|
|
|
|
|
return |
|
|
|
|
|
elif densePwd == "JUSTINBAILEY------------------------------------------------------------------------------------": |
|
|
|
|
|
# Create a random campaign, but everyone's Gadget is a leotard that somehow is also an environment suit |
|
|
|
|
|
return |
|
|
|
|
|
elif densePwd == "NARPASSWORD------------------------------------------------------------------------------------": |
|
|
|
|
|
# Create a random campaign, but all the kobolds' stats are set to 6 |
|
|
|
|
|
return |
|
|
|
|
|
numPwd = [] |
|
|
|
|
|
for c in densePwd: |
|
|
|
|
|
numPwd.append(Campaign.ALPHABET.index(c)) |
|
|
|
|
|
bitPwd = [bin(x).replace("0b","") for x in numPwd] |
|
|
|
|
|
longBitPwd = [] |
|
|
|
|
|
for word in bitPwd: |
|
|
|
|
|
longword = word |
|
|
|
|
|
while len(longword) < 6: |
|
|
|
|
|
longword = "0" + longword |
|
|
|
|
|
longBitPwd.append(longword) |
|
|
|
|
|
self.newBitfield = "".join(longBitPwd) |
|
|
|
|
|
print(self.newBitfield) |
|
|
|
|
|
return self.newBitfield |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_params(self, endc=" ", html=False): |
|
|
def print_params(self, endc=" ", html=False): |
|
|
|
|
|
print(len(Plot.miss)) |
|
|
st = ["Order:", "Chaos:", "Brains:", "Body:"] |
|
|
st = ["Order:", "Chaos:", "Brains:", "Body:"] |
|
|
cst = ", ".join([" ".join(y) for y in list(zip(st, [str(x) for x in self.params.problem["stats"]]))]) |
|
|
cst = ", ".join([" ".join(y) for y in list(zip(st, [str(x) for x in self.params.problem["stats"]]))]) |
|
|
|
|
|
if self.params.oops == 1: |
|
|
|
|
|
oops = "...well, they weren't paying attention, so don't tell them, but they're supposed " |
|
|
|
|
|
else: |
|
|
|
|
|
oops = "" |
|
|
|
|
|
location = oops + self.params.location |
|
|
lines = [ |
|
|
lines = [ |
|
|
f"The Kobolds of the {self.ship.fullname}", |
|
|
f"The Kobolds of the {self.ship.fullname}", |
|
|
f"have been sent out to {self.art} {self.params.loc_desc} {self.params.location}", |
|
|
|
|
|
|
|
|
f"have been sent out to {self.art} {self.params.loc_desc} {location}!", |
|
|
f"in order {self.params.mission}", |
|
|
f"in order {self.params.mission}", |
|
|
f"but they're challenged by {self.params.fullProblem}!", |
|
|
f"but they're challenged by {self.params.fullProblem}!", |
|
|
f"The stats of the {self.params.problem['shortname']}", |
|
|
f"The stats of the {self.params.problem['shortname']}", |
|
|
|
|
|
|
|
|
f"<div id='themission' class='firstrow'>\n" |
|
|
f"<div id='themission' class='firstrow'>\n" |
|
|
f" <span class='head'>The Mission</span>\n" |
|
|
f" <span class='head'>The Mission</span>\n" |
|
|
f" <span id='missionloc'>\n" |
|
|
f" <span id='missionloc'>\n" |
|
|
f" The kobolds have been sent to {self.art} {self.params.loc_desc} {self.params.location}\n" |
|
|
|
|
|
|
|
|
f" The kobolds have been sent to {self.art} {self.params.loc_desc} {self.params.location}!\n" |
|
|
f" </span><br>\n" |
|
|
f" </span><br>\n" |
|
|
f" <span id='missiontarget'>\n" |
|
|
f" <span id='missiontarget'>\n" |
|
|
f" in order {self.params.mission}\n" |
|
|
f" in order {self.params.mission}\n" |
|
|
|
|
|
|
|
|
if html: |
|
|
if html: |
|
|
print(f"</div>\n<br clear='all'>\n") |
|
|
print(f"</div>\n<br clear='all'>\n") |
|
|
|
|
|
|
|
|
|
|
|
def decode(self, pwd): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
class Password: |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
if __name__ == "__main__": |
|
|
parser = argparse.ArgumentParser() |
|
|
parser = argparse.ArgumentParser() |
|
|
group = parser.add_mutually_exclusive_group() |
|
|
group = parser.add_mutually_exclusive_group() |
|
|
|
|
|
|
|
|
group.add_argument("-n", "--names", help="print N kobolds without stat blocks", nargs="?", const=1, type=int, metavar="N") |
|
|
group.add_argument("-n", "--names", help="print N kobolds without stat blocks", nargs="?", const=1, type=int, metavar="N") |
|
|
group.add_argument("-p", "--params", help="print only the parameters of a campaign", action="store_true") |
|
|
group.add_argument("-p", "--params", help="print only the parameters of a campaign", action="store_true") |
|
|
group.add_argument("-s", "--ship", help="print only the ship name and description", action="store_true") |
|
|
group.add_argument("-s", "--ship", help="print only the ship name and description", action="store_true") |
|
|
|
|
|
group.add_argument("-pw", "--password", help="print the campaign defined by the submitted password", type=str, nargs="?", const=1, metavar="PW") |
|
|
parser.add_argument("--html", help="print in HTML instead of plain text", action="store_true") |
|
|
parser.add_argument("--html", help="print in HTML instead of plain text", action="store_true") |
|
|
args = parser.parse_args() |
|
|
args = parser.parse_args() |
|
|
# print(args) |
|
|
# print(args) |
|
|
html = True if args.html else False |
|
|
html = True if args.html else False |
|
|
if args.campaign: |
|
|
|
|
|
|
|
|
if args.password: |
|
|
|
|
|
pw = Password(args.password) |
|
|
|
|
|
# print(pw.newBitfield) |
|
|
|
|
|
cmp = Campaign(fromPW = True) |
|
|
|
|
|
cmp.decode(pw) |
|
|
|
|
|
elif args.campaign: |
|
|
cmp = Campaign(args.campaign) |
|
|
cmp = Campaign(args.campaign) |
|
|
cmp.print_params(html=html) |
|
|
cmp.print_params(html=html) |
|
|
cmp.print_chars(html=html) |
|
|
cmp.print_chars(html=html) |
|
|
|
|
|
print(cmp.generate_key()) |
|
|
elif args.params: |
|
|
elif args.params: |
|
|
cmp = Campaign(makeChars=False) |
|
|
cmp = Campaign(makeChars=False) |
|
|
cmp.print_params(html=html) |
|
|
cmp.print_params(html=html) |