def get_character_class(self, classname=None): """ We determine character class based on your prime attribute. """ if classname: return characterclass.CLASS_BY_NAME[classname] if self.demihumans and d(100) < 50: # sorted attributes (excluding charisma) attributes = sorted(self.attributes[:5], reverse=True, key=operator.itemgetter(1)) if not (self.thieves and 'DEX' == attributes[0][0] and d(100) < 80): # We randomly test because there is overlap in what could # succeed and we want each to be equally likely in the long # run. tests = [_is_dwarf, _is_halfling, _is_elf] random.shuffle(tests) for t in tests: result, c = t(self.INT, self.CON, self.DEX, self.STR) if result: return c # You're playing a human! index = 4 if self.thieves else 3 prime_attribute, _ = sorted(self.attributes[:index], reverse=True, key=operator.itemgetter(1))[0] return characterclass.PRIME_REQUISITE[prime_attribute]
def get_background(self): backgrounds = [ ("Poulticer", "mortar and pestle, dagger, mystery potion (you know what it doesn't do), oil flask, chalk"), ("Slaughterer", "heavy cleaver, half-chain, a string of fine sausage, twine"), ("Fungus Picker", "two different kinds of mushrooms, club, sling, rabbuck-hide gloves, lamp, oil flask"), ("Pickler", "pickle cask with delicious pickles, spice-rack, trident, wading boots"), ("Charcoal Burner", "Iron-banded broom, knife, sooty rags, mastic, crampons"), ("Purloiner", "hammer and spike, off-hand daggers, 50' rope, clothes with hidden pockets, a golden ring (stolen)"), ("Hunter", "crossbow OR bow, quiver, skinning-knife, leather jack, axe, brace of smoked frog"), ("Noble", "sword and shield and full chain OR pistolet and powderhorn and chain shirt, off-hand dagger, map to 'inheritance', a fine cape and mantle, laudanum OR signet ring"), ("Mendicant", "begging bowl, smart pet, reed flute, staff OR club"), ("Scribe", "mace, robes, runestones, oil-lamp, lard-pot, vellum, brush and ink"), ("Porter", "fists, club, auroch-hide armour, a porter's basket"), ("Timberfeller", "great-axe, knife, raspberry aquavit, sling, 50' rope"), ("Plumber", "gluepot, throwing hammer, weather-proof overalls"), ("Hayseed", "axe OR pitchfork OR threshing flail, dirk, harmonium OR great-kazoo, chewing weed, three torches"), ("House-guard", "shield, spear, misericorde, half-chain, club, 50' rope"), ("Fisher", "fishing pole and hook, gutting knife, 2 throwing spears, eel-hide armour, 3 torches, a smoked eel"), ("Barber", "bonesaw, steggar, clamps, bloody rags, leechjar OR pendulum"), ("Scroll-Runner", "running shoes, jerky, 50' rope, emberhorn, dagger, news-scroll, farseeing glass"), ("Paramour", "woodblock erotica OR book of poems, sword, perfume (as lamp-oil), locket OR prophylactics, bow and quiver"), ("Guild-Partisan", "great-weapon, mancatcher, dagger, hauberk with party armband, guild news-scroll, a set of trade tools (dyer, tanner, weaver, napier, builder, etc.)"), ("Bondsman", "waraxe OR crossbow and quiver and club, mail shirt, shield, saexe, gift-ring"), ("Apiarist", "chainmail, goggles, club, bellows, smokebomb, honeycomb"), ("Sailor", "axe OR cat, off-hand marlinspike, scrimshaw, shield OR leather armour, lodestone"), ("Bellman", "hookspear, chainmail shirt, shield, handbell, truncheon, 3 torches"), ("Smith", "warhammer OR sword, off-hand hammer, chainmail OR leather armour and shield, anvil, crucible"), ("Janissary", "harquebus, powderhorn, chainmail shirt, sword, shield, contract"), ("Seer", "silver dagger, cage of finches, brazier"), ("Ursar", "mancatcher, 20' chain, club, hide armour, hand drum"), ("Merchant", "fine clothes, guilder's chain, mace OR axe, a servant with a bale of trade goods"), ("Wolfs-head", "waraxe, caltrops, leather armour, crossbow, quiver, writ of blood price"), ("Therapist", "flail, shield, pendulum, meditation cushion, oil-lamp, oil-pot"), ("Skald", "harp OR scroll of epic poetry, off-hand dagger, sword OR bow and quiver, collection plate"), ("Drover", "studded leather, whip, club, brand, firehorn, heavy gloves, throwing axe"), ("Judicial Functionary", "great-weapon, leather jack, hooded cloak, hanging rope OR tongs, manacles and keys"), ("Wildling", "fists, moss and furs, 'lucky' stone, shillelagh"), ("Mercenary", "great-weapon OR waraxe and shield, dirk, ringed leathers, bow and quiver, totem"), ] background, equipment = random.choice(backgrounds) equipment = equipment.split(', ') bonus_equipment, silver = random.choice([ (["fists", "a half-empty bottle", "a turnip"], lambda: dice.d(6)), (["nullwater", "a white conch"], lambda: dice.xdy(3, 6)), (["3 flasks of oil", "a hammer", "iron spikes"], lambda: 0), (["quill and ink", "incense"], lambda: 0), (["a hex scroll", "a pine sprig"], lambda: dice.d(6) * 10), (["sword and scabbard OR waraxe OR warhammer"], lambda: 0), ]) equipment += bonus_equipment equipment.append("%d SP" % silver()) # process the equipment list down to a finite list of stuff final_equipment = [] for e in equipment: items = random.choice(e.split(' OR ')).split(' and ') final_equipment.append(items) return background, ", ".join(list(itertools.chain(*final_equipment)))
def get_name(self, colour): roll = d(100) if roll > 65: return None adjective = random.choice(Leader.ADJECTIVES) noun = random.choice(Leader.NOUNS) description = random.choice(Leader.DESCRIPTIONS) used_adjective = False try: description = description.format(adjective=adjective) used_adjective = True except KeyError: pass try: description = description.format(colour=colour) except KeyError: pass roll = d(12) if roll <= 3: name = [adjective, noun] elif roll <= 7: if not used_adjective: name = [adjective, noun, description] else: name = [noun, description] else: name = [noun, description] if not name[0] in ['He', 'Her', 'It', 'She', 'Lady']: name = ['the'] + name return ' '. join(name)
def scorching_ray(caster, slot, *targets): assert slot > 1 assert caster.slots[slot] > 0 assert len(targets) <= slot + 1 for target in targets: target.HP -= d(6) + d(6) caster.slots[slot] -= 1
def __init__(self, wizard_name: str, school_name: str): self.name = wizard_name self.school = MagicSchool(school_name) self.offense = d(6) + self.school.modifiers["Offense"] self.defense = d(6) + self.school.modifiers["Defense"] self.accuracy = d(6) + self.school.modifiers["Accuracy"] self.health = dice(3, 6) self.wand = Wand()
def get_population(self, kind): # TODO: Figure out actual distribution. These are pretty close. if kind == 'Village': return xdy(5,95) + 25 elif kind == 'Castle': return xdy(2,50) elif kind == 'Citadel': return d(100) + d(50) else: return xdy(5,16) + d(10) + 10
def initialize_equipment(self): """ Every starts with 3 items, and 3 slots for more items. You can also start with weapons and armour (combat equipment) that will increase your burden. """ self.equipment = list(random.choice(self.BACKPACKS)) + ['...', '...', '...'] self.weapons = random.sample(self.WEAPONS, dice.d(3) - 1) self.armour = random.sample(self.ARMOUR, dice.d(3) - 1) self.burden += len(self.weapons) + len(self.armour)
def get_wild_talent(self): # TODO: what frequency do I actually want here? if d(6) != 1: return talent_roll = self.WIS - d(20) if talent_roll < 0: save_bonus = abs(talent_roll) / 2 if save_bonus: return "+%d to saves vs. psionic attacks" % save_bonus else: return None else: return characterclass.WILD_TALENTS[talent_roll]
def initialize_rituals(self): """ Players start play with upto 3 rituals. Each ritual you know increases your ruin by 1. """ self.rituals = random.sample(self.RITUALS, dice.d(4) - 1) self.ruin += len(self.rituals)
def get_hp(self): """ LotFP characters have a minimum number of HP. """ hp = d(self.hit_die) + self.get_bonus(*self.attributes[characterclass.CON]) hp = max(hp, characterclass.LOTFP['min_hp'][self.character_class['name']]) return hp
def get_hp(self): """ Determine HP based on hit dice and CON modifiers. Note: this value may be negative and that is handled by the caller. """ return d(self.hit_die) + self.get_bonus( *self.attributes[characterclass.CON])
def _get_features(self): self.body = random.choice(Spawn.FORMS) roll = d(16) if roll >= 15: colours = random.sample(colour.COLOURS[1:], d(3) + 1) colours = ', '.join(colours[:-1]) + ' and ' + colours[-1] self.colour = colours else: self.colour = colour.colour() self.hide = random.choice(Spawn.HIDES) self.eyes = d(8) - 1 if self.eyes == 0: self.eyes = 'no' elif self.eyes == 7: self.eyes = 'multiple/insectile' self.mouth = random.choice(Spawn.MOUTHS)
def get_level(self): roll = d(100) if roll <= 1: return "1st" elif roll <= 5: return "2nd" elif roll <= 13: return "3rd" elif roll <= 26: return "4th" elif roll <= 42: return "5th" elif roll <= 58: return "6th" elif roll <= 73: return "7th" elif roll <= 83: return "8th" elif roll <= 91: return "9th" elif roll <= 96: return "10th" elif roll <= 99: return "11th" else: return random.choice(["12th", "12th", "12th", "13th", "13th", "14th", "15th", "16th"])
def magic_missile(caster, slot, *targets): assert caster.slots[slot] > 0 assert len(targets) <= slot + 2 assert slot > 0 for target in targets: target.HP -= d(4) + 1 caster.slots[slot] -= 1
def __init__(self, d, n=1): self.d = d self.n = n self.original = dice.d(d, n, total=False) self.rolls = list( self.original ) # the `list()` ensures that the list is copied and it's not a reference
def _get_features(self): roll = d(10) if roll > 7: self.eyes = d(8) - 1 if self.eyes == 0: self.eyes = 'no' elif self.eyes == 7: self.eyes = 'multiple/insectile' elif roll > 4: self.eyes = 'glowing', else: self.eyes = 2 if d(10) > 7: self.mouth = random.choice(Dinosaur.MOUTHS) if self.eyes == 2: self.mouth = self.mouth.capitalize()
def _get_powers(self): roll = d(100) if roll <= 84: return [] if roll == 100: return random.sample(Spawn.POWERS, 2) else: return [random.choice(Spawn.POWERS)]
def _get_powers(self): roll = d(100) if roll <= 25: return [] if roll == 100: return random.sample(Dinosaur.POWERS, 2) else: return [random.choice(Dinosaur.POWERS)]
def _get_alignment(self): roll = d(8) if roll <= 6: return 'Chaotic' elif roll == 7: return 'Neutral [intelligent]' else: return 'Neutral [unintelligent]'
def get_alignment(self): roll = d(100) if roll <= 50: return "Neutral" elif roll <= 80: return "Chaotic" else: return "Lawful"
def get_class(self, kind): roll = d(100) if roll <= 1: return "Spawn of Shub-Niggurath" elif roll <= 77: return "Fighter" if kind != "Monastery" else "Sorcerer" else: return "Sorcerer" if kind != "Monastery" else "Fighter"
def _get_immunities(self): roll = d(20) if roll <= 10: return [] elif roll == 20: return random.sample(Spawn.IMMUNITIES, 2) else: return [random.choice(Spawn.IMMUNITIES)]
def __init__(self, *args, **kwargs): super(Character, self).__init__(*args, **kwargs) # Attributes self.skill = dice.d(3) + 3 self.stamina = dice.xdy(2, 6) + 12 self.luck = dice.d(6) + 6 self.appearance = self.get_appearance() # Pick a Background background = random.choice(self.BACKGROUNDS) self.background = background['name'][3:] self.description = background['description'] self.special = background['special'] # Pick one of the "ORs" for possessions when picking equipment self.equipment = [ random.choice(equipment.split(' OR ')) for equipment in background['possessions'] ] + [ # Add default equipment 'Knife', 'Lantern and a flask of oil', 'Rucksack', '6 provisions', '%d silver pennies' % dice.xdy(2,6), ] # Turn random spells into actual spells when picking skills self.skills = [ skill.replace('Random (Table 5)', random.choice(self.MAGIC_SPELLS)) for skill in background['skills'] ] # Fix some gender issues if 'Female' in self.appearance and self.background == 'Lonesome King': self.background = 'Lonesome Queen' elif self.background == 'Rhino-Man': self.appearance = self.appearance.replace('Female, ', '') self.appearance = self.appearance.replace('Male, ', '') elif self.background == 'Parchment Witch': self.appearance = self.appearance.replace('Male', 'Female')
def get_kind(self): roll = d(100) if roll <= 2: return "Monastery" elif roll <= 20: return "Castle" elif roll <= 43: return "Citadel" else: return "Village"
def racechoice(self): i = d(1,4) if i[0] == 1: return "Human" elif i[0] == 2: return "Wood Elf" elif i[0] == 3: return "Dwarf" elif i[0] == 4: return "Halfling"
def __init__(self, *args, **kwargs): super(Character, self).__init__(*args, **kwargs) # Attributes self.skill = dice.d(3) + 3 self.stamina = dice.xdy(2, 6) + 12 self.luck = dice.d(6) + 6 self.appearance = self.get_appearance() # Pick a Background background = random.choice(self.BACKGROUNDS) self.background = background['name'][3:] self.description = background['description'] self.special = background['special'] # Pick one of the "ORs" for possessions when picking equipment self.equipment = [ random.choice(equipment.split(' OR ')) for equipment in background['possessions'] ] + [ # Add default equipment 'Knife', 'Lantern and a flask of oil', 'Rucksack', '6 provisions', '%d silver pennies' % dice.xdy(2, 6), ] # Turn random spells into actual spells when picking skills self.skills = [ skill.replace('Random (Table 5)', random.choice(self.MAGIC_SPELLS)) for skill in background['skills'] ] # Fix some gender issues if 'Female' in self.appearance and self.background == 'Lonesome King': self.background = 'Lonesome Queen' elif self.background == 'Rhino-Man': self.appearance = self.appearance.replace('Female, ', '') self.appearance = self.appearance.replace('Male, ', '') elif self.background == 'Parchment Witch': self.appearance = self.appearance.replace('Male', 'Female')
def test(self): """ ПРОВЕРКА УДАЧИ: в некоторых местах тебе будет предложено ИСПЫТАТЬ УДАЧУ. Кинь один кубик: если полученное число будет меньше твоей или равно УДАЧЕ, значит тебе повезло, если больше – не повезло. После каждой проверки удача уменьшается на 1. :return: """ result = d(1, 6) <= self.value return result
def __init__(self): self.unique = d(20) != 20 if not self.unique: self.number = self._get_number_appearing() self.ac = self._get_armor_class() self.move = self._get_movement() self.hd = self._get_hd() self.alignment = self._get_alignment() self._get_features() self.powers = self._get_powers() self.immunities = self._get_immunities()
def fight(self, enemy): """ БИТВЫ: 1. Во время битвы кинь один кубик и прибавь полученное число к своей СИЛЕ. Это твоя СИЛА УДАРА. 2. Кинь кубик, и выпавшее число прибавь к СИЛЕ противника. Это его СИЛА УДАРА. 3. Сравнит значения. Если твоя сила удара больше, ты отнимаешь от ВЫНОСЛИВОСТИ противника число, равное твоему УРОНУ. 4. Повторяй пункты 1 – 3 до полной победы или поражения. :param enemy: :return: """ while self.stamina.value > 0 and enemy.stamina.value > 0: player_attack = d(1, 6) + self.strength.value enemy_attack = d(1, 6) + enemy.strength.value if player_attack > enemy_attack: enemy.get_wound(self.damage) elif enemy_attack > player_attack: self.get_wound(enemy.damage)
def improvement(message): match = re.match(r"^\s*(?P<skill>\d+)\s*(?:!?\s*(?P<reason>.*))?$", message) if match: skill = int(match.group('skill')) reason = match.group('reason') or "" try: total, tens, units = dice.coc.d100() # skill_desc = f"\"{reason}\" with value of {skill}" if reason else f"{skill}" # description = f"Improving {skill_desc}:\n\n" title = f"Improving: {reason}" if reason else None description = "" color = None if total > skill or total > 95: description += f"**Improvement succeeded!** *(rolled {total})*\n" color = C_CRITICAL_SUCCESS increase = dice.d(10) new_skill = skill + increase description += f"New skill value: **{new_skill}** *(increased by {increase})*\n" # check for sanity gain if new_skill >= 90 and skill < 90: sanity_gain = dice.d(6, times=2) description += f"\nYou also **gained {sanity_gain} sanity** from increasing your skill beyond 90%!" else: description += f"**Improvement failed** *({total})*\n" color = C_FAILURE return {'title': title, 'description': description, 'color': color} except dice.DiceError as error: return error.message else: return { 'title': "Improvement Command Usage:", 'description': mini_help_message }
def attrib(): all_dice = [] for index in range(0, 4): all_dice += [dice.d(6)] print(f"Dice: {all_dice}") print(f"Min: {min(all_dice)}") print(f"Sum: {sum(all_dice)}") print(f"Actual: {sum(all_dice) - min(all_dice)}") return sum(all_dice) - min(all_dice)
def monster_description(self): desc = [] if self.eyes != 2: desc.append('%s eyes, ' % self.eyes.capitalize()) desc.append('%s' % self.mouth) if d(10) > 5: desc.append(', ') desc.append(random.choice(Dinosaur.BODY_FEATURES)) desc = ''.join(desc) if desc.strip(): desc = desc + '.' return desc
def getChance(wildernessType, hours=1): import dice try: for h in range(hours): w = WILDERNESS[wildernessType] r = dice.d(1, 100) enc = (r <= w["chance"]) logging.debug("Hour: %d\tChance: %d\tRoll: %d\t%s" % (h, w["chance"], r, ["No encounter", "Encounter!"][enc])) if enc: break return h, enc except (IndexError): raise ValueError
def __init__(self): roll = d(20) if 1 <= roll <= 7: weapon = 'Pistol' elif 8 <= roll <= 13: weapon = 'Rifle' elif 14 <= roll <= 17: weapon = 'Bazooka' elif 18 <= roll <= 19: weapon = 'Canon' else: weapon = 'Tank' self.weapon = weapon self.range = Weapon.TYPE[weapon]['range'] self.damage = Weapon.TYPE[weapon]['damage'] self.charges = Weapon.TYPE[weapon]['charges'] self.pattern = random.choice(Weapon.PROJECTION_PATTERN) roll = d(10) if 1 <= roll <= 6: self.projection_type = random.choice(Weapon.ELECTROMAGNETIC) elif 7 <= roll <= 9: self.projection_type = random.choice(Weapon.SPECTRAL) + " spectral energy" else: self.projection_type = None self.special = random.choice(Weapon.SPECIAL) if '/' in self.special: self.special = random.choice(self.special.split('/')) if self.projection_type == 'Cosmic Radiation': self.damage += 2 elif self.projection_type == 'Gamma Radiation': self.damage += 1 self.element = random.choice(Weapon.ELEMENT)
def make_random(count): weird_gen = weird.WierdGenerator() random_hexes = [] for i in range(count): roll = dice.d(100) if roll <= 40: random_hexes.append(weird_gen.weird()) elif roll <= 70: random_hexes.append(settlement.Settlement()) elif roll <= 83: random_hexes.append(spawn.Spawn()) elif roll <= 88: random_hexes.append(dinosaur.Dinosaur()) else: random_hexes.append(monster.Monster()) return render_template("random.html", hexes=random_hexes, count=int(len(random_hexes)/2))
def generate_attributes(self): attributes = { a.lower(): int(math.ceil(1.0 * dice.d(10) / 2.0)) for a in self.ATTRIBUTES } if self.role == "Victim": attributes["calm"] = max(attributes["calm"], 4) elif self.role == "Problem": attributes["calm"] = max(attributes["calm"], 3) elif self.role == "Investigator": attributes["cash"] = max(attributes["cash"], 3) elif self.role == "Friend": attribute = random.choice(["perception", "calm"]) attributes[attribute] = attributes[attribute] + 1 self.attributes = attributes
def _get_number_appearing(self): roll = d(20) if roll <= 5: return d(2) elif roll <= 9: return d(3) elif roll <= 12: return d(4) elif roll <= 15: return d(6) elif roll <= 17: return d(8) elif roll <= 19: return d(10) else: return xdy(2,6)
def _get_hd(self): roll = d(20) if roll <= 3: return 1 elif roll <= 6: return 2 elif roll <= 9: return 3 elif roll <= 11: return 4 elif roll <= 13: return 5 elif roll <= 15: return 6 elif roll <= 17: return 7 else: return roll - 10
def _get_armor_class(self): roll = d(20) if roll <= 4: return 12 elif roll <= 8: return 13 elif roll <= 11: return 14 elif roll <= 13: return 15 elif roll <= 15: return 16 elif roll <= 17: return 17 elif roll <= 19: return 19 else: return 20
def get_character_class(self, classname=None): """ We randomly check for demihuman status, which needs to reroll stats, then determine character class based on your prime attribute. """ classNum = d(20) if classname: return characterclass.CLASS_BY_NAME[classname] if classNum < 5: # sorted attributes (excluding charisma) attributes = sorted(self.attributes[:5], reverse=True, key=operator.itemgetter(1)) # You're playing a human! index = 4 if self.thieves else 3 prime_attribute, _ = sorted(self.attributes[:index], reverse=True, key=operator.itemgetter(1))[0] return characterclass.PRIME_REQUISITE[prime_attribute] elif classNum=5 return characterclass.FROGLING elif classNum=4 return characterclass.FLYINGMONKEY elif classNum=3 return characterclass.MERROWMAN elif classNum=2 return characterclass.DRAUGR elif classNum=1 return characterclass.PASSENGER
def _get_movement_rate(self): """ Return movement rate in feet. """ roll = d(20) if roll == 1: return 30 elif roll <= 3: return 60 elif roll <= 7: return 90 elif roll <= 12: return 120 elif roll <= 15: return 150 elif roll <= 17: return 180 elif roll <= 19: return 210 else: return 240
def _get_movement(self): """ Determine type of movement: flying, swimming, etc. """ roll = d(20) if roll <= 9: move_type = ['land'] elif roll <= 12: move_type = ['land', 'fly'] elif roll <= 15: move_type = ['land', 'swim'] elif roll <= 17: move_type = ['swimming only'] elif roll <= 19: move_type = ['land', 'fly', 'swim'] else: move_type = [] moves = [(mt, self._get_movement_rate()) for mt in move_type] if not moves: return "None" elif len(moves) == 1 and moves[0][0] == 'land': return "%s" % moves[0][1] else: return " / ".join("%s [%s]" % (d, m) for m, d in moves)
def __call__(self): return d(6) + self.bonus
def get_background(self): backgrounds = [ ("Poulticer", "mortar and pestle, dagger, mystery potion (you know what it doesn't do), oil flask, chalk" ), ("Slaughterer", "heavy cleaver, half-chain, a string of fine sausage, twine"), ("Fungus Picker", "two different kinds of mushrooms, club, sling, rabbuck-hide gloves, lamp, oil flask" ), ("Pickler", "pickle cask with delicious pickles, spice-rack, trident, wading boots" ), ("Charcoal Burner", "Iron-banded broom, knife, sooty rags, mastic, crampons"), ("Purloiner", "hammer and spike, off-hand daggers, 50' rope, clothes with hidden pockets, a golden ring (stolen)" ), ("Hunter", "crossbow OR bow, quiver, skinning-knife, leather jack, axe, brace of smoked frog" ), ("Noble", "sword and shield and full chain OR pistolet and powderhorn and chain shirt, off-hand dagger, map to 'inheritance', a fine cape and mantle, laudanum OR signet ring" ), ("Mendicant", "begging bowl, smart pet, reed flute, staff OR club"), ("Scribe", "mace, robes, runestones, oil-lamp, lard-pot, vellum, brush and ink" ), ("Porter", "fists, club, auroch-hide armour, a porter's basket"), ("Timberfeller", "great-axe, knife, raspberry aquavit, sling, 50' rope"), ("Plumber", "gluepot, throwing hammer, weather-proof overalls"), ("Hayseed", "axe OR pitchfork OR threshing flail, dirk, harmonium OR great-kazoo, chewing weed, three torches" ), ("House-guard", "shield, spear, misericorde, half-chain, club, 50' rope"), ("Fisher", "fishing pole and hook, gutting knife, 2 throwing spears, eel-hide armour, 3 torches, a smoked eel" ), ("Barber", "bonesaw, steggar, clamps, bloody rags, leechjar OR pendulum"), ("Scroll-Runner", "running shoes, jerky, 50' rope, emberhorn, dagger, news-scroll, farseeing glass" ), ("Paramour", "woodblock erotica OR book of poems, sword, perfume (as lamp-oil), locket OR prophylactics, bow and quiver" ), ("Guild-Partisan", "great-weapon, mancatcher, dagger, hauberk with party armband, guild news-scroll, a set of trade tools (dyer, tanner, weaver, napier, builder, etc.)" ), ("Bondsman", "waraxe OR crossbow and quiver and club, mail shirt, shield, saexe, gift-ring" ), ("Apiarist", "chainmail, goggles, club, bellows, smokebomb, honeycomb"), ("Sailor", "axe OR cat, off-hand marlinspike, scrimshaw, shield OR leather armour, lodestone" ), ("Bellman", "hookspear, chainmail shirt, shield, handbell, truncheon, 3 torches" ), ("Smith", "warhammer OR sword, off-hand hammer, chainmail OR leather armour and shield, anvil, crucible" ), ("Janissary", "harquebus, powderhorn, chainmail shirt, sword, shield, contract" ), ("Seer", "silver dagger, cage of finches, brazier"), ("Ursar", "mancatcher, 20' chain, club, hide armour, hand drum"), ("Merchant", "fine clothes, guilder's chain, mace OR axe, a servant with a bale of trade goods" ), ("Wolfs-head", "waraxe, caltrops, leather armour, crossbow, quiver, writ of blood price" ), ("Therapist", "flail, shield, pendulum, meditation cushion, oil-lamp, oil-pot"), ("Skald", "harp OR scroll of epic poetry, off-hand dagger, sword OR bow and quiver, collection plate" ), ("Drover", "studded leather, whip, club, brand, firehorn, heavy gloves, throwing axe" ), ("Judicial Functionary", "great-weapon, leather jack, hooded cloak, hanging rope OR tongs, manacles and keys" ), ("Wildling", "fists, moss and furs, 'lucky' stone, shillelagh"), ("Mercenary", "great-weapon OR waraxe and shield, dirk, ringed leathers, bow and quiver, totem" ), ] background, equipment = random.choice(backgrounds) equipment = equipment.split(', ') bonus_equipment, silver = random.choice([ (["fists", "a half-empty bottle", "a turnip"], lambda: dice.d(6)), (["nullwater", "a white conch"], lambda: dice.xdy(3, 6)), (["3 flasks of oil", "a hammer", "iron spikes"], lambda: 0), (["quill and ink", "incense"], lambda: 0), (["a hex scroll", "a pine sprig"], lambda: dice.d(6) * 10), (["sword and scabbard OR waraxe OR warhammer"], lambda: 0), ]) equipment += bonus_equipment equipment.append("%d SP" % silver()) # process the equipment list down to a finite list of stuff final_equipment = [] for e in equipment: items = random.choice(e.split(' OR ')).split(' and ') final_equipment.append(items) return background, ", ".join(list(itertools.chain(*final_equipment)))
def roll(cls): return d(1, 6)
def roll(message): dice_pattern = r"(white|w|green|g|red|r|yellow|y|blue|b|human|h|occupation|o|insight|insanity|i|failure|f|\s+)" match = re.match( r"^\s*(?P<dice>" + dice_pattern + r"*)(?:!\s*(?P<reason>.*))?$", message) match_insight = re.match(r"^\s*(?P<insight>\d)\s*(?:!\s*(?P<reason>.*))?$", message) if match_insight: target = int(match_insight.group('insight')) roll = dice.d(6) print(roll) if roll > target: if target == 5: title = "You understand... *everything*" description = "You understand the full horror behind the Universe and leave everyday life behind." else: title = "Increase Insight by one" description = f"You rolled a {roll}" else: title = "No change" description = f"You rolled a {roll}" color = 0x9947eb return {'title': title, 'description': description, 'color': color} elif match and match.group('dice') and len(message.strip()) > 0: split = list(filter(None, re.split(dice_pattern, match.group('dice')))) print(split) #for brevity def count(data, l): return sum([data.count(s) for s in l]) white_n = count(split, ['white', 'w', 'human', 'h', 'occupation', 'o']) green_n = count(split, ['green', 'g', 'insight', 'insanity', 'i']) red_n = count(split, ['red', 'r', 'failure', 'f']) yellow_n = count(split, ['yellow', 'y']) blue_n = count(split, ['blue', 'b']) try: # don't do success level checks and just output a dice roll number white_d6 = dice.d(6, times=white_n, total=False) green_d6 = dice.d(6, times=green_n, total=False) red_d6 = dice.d(6, times=red_n, total=False) yellow_d6 = dice.d(6, times=yellow_n, total=False) blue_d6 = dice.d(6, times=blue_n, total=False) if white_n > 20 or green_n > 20 or red_n > 20 or yellow_n > 20 or blue_n > 20: raise dice.DiceError( "Azathoth curses you for using too many dice!") # Interpretation # quick helper function def highest(l): return max(l) if len(l) > 0 else 0 if yellow_n > 0 or blue_n > 0: title = "Custom" color = 0x202225 elif highest(red_d6) > highest(white_d6 + green_d6): title = "Failure!" color = C_FAILURE_DISADV else: title, color = { 6: ("More than you wanted!", C_CRITICAL_SUCCESS), 5: ("Success, and...", C_SUCCESS_ADV), 4: ("Success", C_SUCCESS), 3: ("Partial Success", C_SUCCESS_DISADV), 2: ("Partial Success, but...", C_FAILURE_ADV), 1: ("*Juuuust* Barely", C_FAILURE), }[highest(white_d6 + green_d6)] def format_dice_list(l): if len(l) == 0: return "" elif len(l) == 1: return f"**{l[0]}**" else: return f"**{l[0]}**, {', '.join(map(str, l[1:]))}" description = "" if white_n > 0: description += f":white_circle: {format_dice_list(sorted(white_d6, reverse=True))}\n" if green_n > 0: description += f":green_circle: {format_dice_list(sorted(green_d6, reverse=True))}\n" if red_n > 0: description += f":red_circle: {format_dice_list(sorted(red_d6, reverse=True))}\n" if yellow_n > 0 or blue_n > 0: description += "\n" if yellow_n > 0: description += f":yellow_circle: {format_dice_list(sorted(yellow_d6, reverse=True))}\n" if blue_n > 0: description += f":blue_circle: {format_dice_list(sorted(blue_d6, reverse=True))}\n" if highest(green_d6) > highest(white_d6): description += f"\n**!Please make an Insight Roll!**\n" if match.group('reason'): description += f"\n**Reason**: {match.group('reason')}" return {'title': title, 'description': description, 'color': color} except dice.DiceError as error: return error.message else: return "Incorrect syntax"
def fire_bolt(caster, target): target.HP -= sum(d(10) for i in range(floor(caster.level / 5) + 1))
def ray_of_frost(caster, target): if d(20) + caster.spellattack >= target.AC: target.HP -= d(8) target.speed -= 10
def four_dee_six(): roll = [sum(sorted(dice.d(6) for _ in xrange(4))[1:]) for _ in range(6)] return render_template("4d6.html", roll=roll)
def get_hp(self): """ Determine HP based on hit dice and CON modifiers. Note: this value may be negative and that is handled by the caller. """ return d(self.hit_die) + self.get_bonus(*self.attributes[characterclass.CON])
def poison_spray(caster, target): target.HP -= d(10) target.poisoned = True
def false_life(caster, slot): assert caster.slots[slot] > 0 assert slot > 0 caster.THP += d(4) + 4 + 5 * (slot - 1)
def roll_attribute(self): """ 4d6 drop the lowest """ return sum(sorted(d(6) for _ in range(4))[1:])
def __init__(self, name=None): self.gender = random.choice(["male", "female"]) self.name = name if name else Character.generate_name( gender=self.gender) self.STR = dice.d(6, 3) * 5 self.CON = dice.d(6, 3) * 5 self.DEX = dice.d(6, 3) * 5 self.SIZ = (dice.d(6, 2) + 6) * 5 self.INT = (dice.d(6, 2) + 6) * 5 self.POW = dice.d(6, 3) * 5 self.APP = dice.d(6, 3) * 5 self.EDU = (dice.d(6, 2) + 6) * 5 self.age = 15 + dice.d(6, 2) + min(dice.d(30, 3, total=False)) self.luck = dice.d(6, 3) * 5 self.sanity = self.POW self.hp = math.floor((self.SIZ + self.CON) / 10) if self.DEX < self.SIZ and self.STR < self.SIZ: self.move_rate = 7 elif self.DEX > self.SIZ and self.STR > self.SIZ: self.move_rate = 9 else: self.move_rate = 8 if self.STR + self.SIZ < 65: self.damage_bonus = "-2" self.build = -2 elif self.STR + self.SIZ < 85: self.damage_bonus = "-1" self.build = -1 elif self.STR + self.SIZ < 125: self.damage_bonus = "0" self.build = 0 elif self.STR + self.SIZ < 165: self.damage_bonus = "+1d4" self.build = 1 else: self.damage_bonus = "+1d6" self.build = 2 self.occupation = self.generate_occupation() #TODO: calculate credit reating based on occupation self.credit_rating = 0
def __init__(self): self.core = choice(self.cores) self.wood = choice(self.woods) self.bonus = d(6)