diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000..84ed64d Binary files /dev/null and b/__pycache__/app.cpython-312.pyc differ diff --git a/__pycache__/ose.cpython-312.pyc b/__pycache__/ose.cpython-312.pyc new file mode 100644 index 0000000..bc4aa9a Binary files /dev/null and b/__pycache__/ose.cpython-312.pyc differ diff --git a/app.py b/app.py new file mode 100644 index 0000000..26f379e --- /dev/null +++ b/app.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3 + +from ose import * +from flask import Flask, render_template + +app = Flask(__name__) + +@app.route('/') +def index(): + htmlBody = returnSheets('test') + return render_template("sheet.html", htmlBody=htmlBody) diff --git a/main.py b/main.py index a9ed162..36c1f85 100755 --- a/main.py +++ b/main.py @@ -3,22 +3,22 @@ import random armor= { 'None' : 9, 'Leather' : 7, 'Leather, Shield' : 6, 'Chain' : 5, 'Chain, Shield' : 4, 'Plate' : 3, 'Plate, Shield' : 2 } weapons = [ - { 'name' : 'battle axe', 'type' : 'melee', 'damage-dice' : 8}, - { 'name' : 'crossbow', 'type' : 'missle', 'damage-dice' : 6, 'ammo' : '20 bolts'}, - { 'name' : 'hand axe', 'type' : 'melee', 'damage-dice' : 6 }, - { 'name' : 'mace', 'type' : 'melee', 'damage-dice' : 6 , 'traits' : [ 'blunt' ] }, - { 'name' : 'pole arm', 'type' : 'melee', 'damage-dice' : 10 }, - { 'name' : 'short bow', 'type' : 'missle', 'damage-dice' : 6, 'ammo' : '20 arrows'}, - { 'name' : 'short sword', 'type' : 'melee', 'damage-dice' : 6 }, - { 'name' : 'silver dagger', 'type' : 'melee', 'damage-dice' : 4 }, - { 'name' : 'sling', 'type' : 'missle', 'damage-dice' : 4, 'ammo' : '20 stones', 'traits' : [ 'blunt' ] }, - { 'name' : 'staff', 'type' : 'melee', 'damage-dice' : 4 , 'traits' : [ 'blunt', 'slow' ] }, - { 'name' : 'spear', 'type' : 'melee', 'damage-dice' : 6 }, - { 'name' : 'sword', 'type' : 'melee', 'damage-dice' : 8 }, - { 'name' : 'war hammer', 'type' : 'melee', 'damage-dice' : 6 , 'traits' : [ 'blunt' ] } + { 'name' : 'battle axe', 'damage-dice' : 8, 'traits' : [ 'melee', 'slow', 'two-handed' ] }, + { 'name' : 'club', 'damage-dice' : 4, 'traits' : [ 'melee', 'blunt' ] }, + { 'name' : 'crossbow', 'damage-dice' : 6, 'traits' : [ 'missile', 'reload','slow','two-handed'], 'ammo' : '20 bolts'}, + { 'name' : 'hand axe', 'damage-dice' : 6, 'traits' : [ 'melee', 'missile'] }, + { 'name' : 'mace', 'damage-dice' : 6, 'traits' : [ 'melee', 'blunt' ] }, + { 'name' : 'pole arm', 'damage-dice' : 10, 'traits' : [ 'melee', 'brace', 'slow', 'two-handed' ] }, + { 'name' : 'short bow', 'damage-dice' : 6, 'traits' : [ 'missile', 'two-handed' ], 'ammo' : '20 arrows'}, + { 'name' : 'short sword', 'damage-dice' : 6, 'traits' : [ 'melee' ] }, + { 'name' : 'silver dagger','damage-dice' : 4, 'traits' : [ 'melee', 'missile' ] }, + { 'name' : 'sling', 'damage-dice' : 4, 'traits' : [ 'missile', 'blunt' ], 'ammo' : '20 stones'}, + { 'name' : 'staff', 'damage-dice' : 4, 'traits' : [ 'melee', 'blunt', 'slow', 'two-handed' ] }, + { 'name' : 'spear', 'damage-dice' : 6, 'traits' : [ 'melee', 'missile', 'brace' ] }, + { 'name' : 'sword', 'damage-dice' : 8, 'traits' : [ 'melee' ] }, + { 'name' : 'war hammer', 'damage-dice' : 6, 'traits' : [ 'melee', 'blunt' ] } ] - # Player Character Classes class Adventurer: def __init__(self, level=1, attributes={}) -> None: @@ -35,8 +35,15 @@ class Adventurer: self.torches = roll_dice(1,6) self.rations = roll_dice(1,6) self.equipment = [ 'backpack', 'tinderbox', 'waterskin' ] - self.weapons = [] - self.armor = [] + # all armor, individual classes may have overrides + self.possible_armor = list(armor.keys()) + # all weapons, individual classes may have overrides + self.possible_weapons = weapons + self.possible_melee_weapons = list(filter(lambda d: 'melee' in d['traits'], weapons)) + self.possible_missile_weapons = list(filter(lambda d: 'missile' in d['traits'], weapons)) + # each character should get 1 melee and 1 random (missle or melee) + self.weapons = [ random.choice(self.possible_melee_weapons), random.choice(self.possible_weapons) ] + self.armor = random.choice(self.possible_armor) def __str__(self): return f"{self.player_class}" @@ -53,8 +60,8 @@ class Adventurer: sheet.append('{0: <26}'.format(f"| Rations: {self.rations}")) sheet.append('{0: <26}'.format(f"| Armor: {self.armor}")) sheet.append('{0: <26}'.format(f"| Weapons:")) - sheet.append('{0: <26}'.format(f"| {self.weapons[0]}")) - sheet.append('{0: <26}'.format(f"| {self.weapons[1]}")) + sheet.append('{0: <26}'.format(f"| {self.weapons[0]['name'].title()}")) + sheet.append('{0: <26}'.format(f"| {self.weapons[1]['name'].title()}")) return sheet def get_attributes(self): @@ -78,9 +85,7 @@ class Fighter(Adventurer): Adventurer.__init__(self, level, attributes) self.player_class = "fighter" self.hp = roll_dice(self.level, 8) - self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] class MagicUser(Adventurer): prime_requisite = "intelligence" @@ -89,9 +94,10 @@ class MagicUser(Adventurer): Adventurer.__init__(self, level, attributes) self.player_class = "magic user" self.hp = roll_dice(self.level, 4) - self.armor = random.choice(list(armor.keys())) + self.armor = "None" self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] + self.weapons = [ list(filter(lambda d: 'silver dagger' in d['name'],weapons))[0], { "name" : "" } ] + class Cleric(Adventurer): prime_requisite = "wisdom" @@ -102,7 +108,10 @@ class Cleric(Adventurer): self.hp = roll_dice(self.level, 6) self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] + # clerics can only wield blunt weapons + self.possible_melee_weapons = list(filter(lambda d: 'blunt' in d['traits'] and 'melee' in d['traits'], weapons)) + self.possible_weapons = list(filter(lambda d: 'blunt' in d['traits'], weapons)) + self.weapons = [ random.choice(self.possible_melee_weapons), random.choice(self.possible_weapons) ] class Thief(Adventurer): prime_requisite = "dexterity" @@ -113,7 +122,6 @@ class Thief(Adventurer): self.hp = roll_dice(self.level, 4) self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] class Dwarf(Adventurer): prime_requisite = "strength" @@ -124,7 +132,6 @@ class Dwarf(Adventurer): self.hp = roll_dice(self.level, 8) self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] class Elf(Adventurer): prime_requisite = "intellgence" @@ -135,7 +142,6 @@ class Elf(Adventurer): self.hp = roll_dice(self.level, 6) self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] class Halfling(Adventurer): prime_requisite = "dexterity" @@ -146,7 +152,6 @@ class Halfling(Adventurer): self.hp = roll_dice(self.level, 6) self.armor = random.choice(list(armor.keys())) self.ac = armor[self.armor] - self.weapons = [ "sword", "dagger" ] # Player Class Selector class ClassSelector(): diff --git a/ose.py b/ose.py new file mode 100755 index 0000000..d767a88 --- /dev/null +++ b/ose.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 +import random + +armor= { 'None' : 9, 'Leather' : 7, 'Leather, Shield' : 6, 'Chain' : 5, 'Chain, Shield' : 4, 'Plate' : 3, 'Plate, Shield' : 2 } +weapons = [ + { 'name' : 'battle axe', 'damage-dice' : 8, 'traits' : [ 'melee', 'slow', 'two-handed' ] }, + { 'name' : 'club', 'damage-dice' : 4, 'traits' : [ 'melee', 'blunt' ] }, + { 'name' : 'crossbow', 'damage-dice' : 6, 'traits' : [ 'missile', 'reload','slow','two-handed'], 'ammo' : '20 bolts'}, + { 'name' : 'hand axe', 'damage-dice' : 6, 'traits' : [ 'melee', 'missile'] }, + { 'name' : 'mace', 'damage-dice' : 6, 'traits' : [ 'melee', 'blunt' ] }, + { 'name' : 'pole arm', 'damage-dice' : 10, 'traits' : [ 'melee', 'brace', 'slow', 'two-handed' ] }, + { 'name' : 'short bow', 'damage-dice' : 6, 'traits' : [ 'missile', 'two-handed' ], 'ammo' : '20 arrows'}, + { 'name' : 'short sword', 'damage-dice' : 6, 'traits' : [ 'melee' ] }, + { 'name' : 'silver dagger','damage-dice' : 4, 'traits' : [ 'melee', 'missile' ] }, + { 'name' : 'sling', 'damage-dice' : 4, 'traits' : [ 'missile', 'blunt' ], 'ammo' : '20 stones'}, + { 'name' : 'staff', 'damage-dice' : 4, 'traits' : [ 'melee', 'blunt', 'slow', 'two-handed' ] }, + { 'name' : 'spear', 'damage-dice' : 6, 'traits' : [ 'melee', 'missile', 'brace' ] }, + { 'name' : 'sword', 'damage-dice' : 8, 'traits' : [ 'melee' ] }, + { 'name' : 'war hammer', 'damage-dice' : 6, 'traits' : [ 'melee', 'blunt' ] } +] + +# Player Character Classes +class Adventurer: + def __init__(self, level=1, attributes={}) -> None: + # using a get() method to pull an attribute else use a default value, https://python-academy.org/en/handbook/get + self.player_class = None + self.level = level + self.strength = attributes.get('strength', roll_dice(3,6)) + self.intelligence = attributes.get('intelligence', roll_dice(3,6)) + self.wisdom = attributes.get('wisdom', roll_dice(3,6)) + self.dexterity = attributes.get('dexterity', roll_dice(3,6)) + self.constitution = attributes.get('constitution', roll_dice(3,6)) + self.charisma = attributes.get('charisma', roll_dice(3,6)) + self.hp = 1 + self.torches = roll_dice(1,6) + self.rations = roll_dice(1,6) + self.equipment = [ 'backpack', 'tinderbox', 'waterskin' ] + # all armor, individual classes may have overrides + self.possible_armor = list(armor.keys()) + # all weapons, individual classes may have overrides + self.possible_weapons = weapons + self.possible_melee_weapons = list(filter(lambda d: 'melee' in d['traits'], weapons)) + self.possible_missile_weapons = list(filter(lambda d: 'missile' in d['traits'], weapons)) + # each character should get 1 melee and 1 random (missle or melee) + self.weapons = [ random.choice(self.possible_melee_weapons), random.choice(self.possible_weapons) ] + self.armor = random.choice(self.possible_armor) + + def __str__(self): + return f"{self.player_class}" + + def character_sheet(self): + sheet = [] + sheet.append('{0: <26}'.format(f"| {self.player_class.title()} - Level {self.level}")) + for key, val in self.get_attributes().items(): + key_string = "| " + '{0:12}'.format(f"{key}").capitalize() + f" {val}" + sheet += ['{0: <26}'.format(key_string)] + sheet.append('| ----------------------- ') + sheet.append('{0: <26}'.format(f"| HP: {self.hp} AC: {self.ac}")) + sheet.append('{0: <26}'.format(f"| Torches: {self.torches}")) + sheet.append('{0: <26}'.format(f"| Rations: {self.rations}")) + sheet.append('{0: <26}'.format(f"| Armor: {self.armor}")) + sheet.append('{0: <26}'.format(f"| Weapons:")) + sheet.append('{0: <26}'.format(f"| {self.weapons[0]['name'].title()}")) + sheet.append('{0: <26}'.format(f"| {self.weapons[1]['name'].title()}")) + return sheet + + def get_attributes(self): + attribute_list = ['strength', 'intelligence', 'wisdom', 'dexterity', 'constitution', 'charisma'] + return {k: self.__dict__[k] for k in attribute_list} + + def get_best_prime_attribute(self): + attribute_list = [ 'strength', 'intelligence', 'wisdom', 'dexterity' ] + prime_attributes = {k: self.__dict__[k] for k in attribute_list} + # return highest, found this at https://stackoverflow.com/a/280156 + return max(prime_attributes, key=prime_attributes.get) + + def roll_equipment(self): + print("testing!") + + +class Fighter(Adventurer): + prime_requisite = "strength" + requirements = None + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "fighter" + self.hp = roll_dice(self.level, 8) + self.ac = armor[self.armor] + +class MagicUser(Adventurer): + prime_requisite = "intelligence" + requirements = None + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "magic user" + self.hp = roll_dice(self.level, 4) + self.armor = "None" + self.ac = armor[self.armor] + self.weapons = [ list(filter(lambda d: 'silver dagger' in d['name'],weapons))[0], { "name" : "" } ] + + +class Cleric(Adventurer): + prime_requisite = "wisdom" + requirements = None + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "cleric" + self.hp = roll_dice(self.level, 6) + self.armor = random.choice(list(armor.keys())) + self.ac = armor[self.armor] + # clerics can only wield blunt weapons + self.possible_melee_weapons = list(filter(lambda d: 'blunt' in d['traits'] and 'melee' in d['traits'], weapons)) + self.possible_weapons = list(filter(lambda d: 'blunt' in d['traits'], weapons)) + self.weapons = [ random.choice(self.possible_melee_weapons), random.choice(self.possible_weapons) ] + +class Thief(Adventurer): + prime_requisite = "dexterity" + requirements = None + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "thief" + self.hp = roll_dice(self.level, 4) + self.armor = random.choice(list(armor.keys())) + self.ac = armor[self.armor] + +class Dwarf(Adventurer): + prime_requisite = "strength" + requirements = {'constitution' : 9 } + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "dwarf" + self.hp = roll_dice(self.level, 8) + self.armor = random.choice(list(armor.keys())) + self.ac = armor[self.armor] + +class Elf(Adventurer): + prime_requisite = "intellgence" + requirements = {'intelligence' : 9 } + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "elf" + self.hp = roll_dice(self.level, 6) + self.armor = random.choice(list(armor.keys())) + self.ac = armor[self.armor] + +class Halfling(Adventurer): + prime_requisite = "dexterity" + requirements = {'constitution' : 9, 'dexterity' : 9 } + def __init__(self, level, attributes={}) -> None: + Adventurer.__init__(self, level, attributes) + self.player_class = "halfling" + self.hp = roll_dice(self.level, 6) + self.armor = random.choice(list(armor.keys())) + self.ac = armor[self.armor] + +# Player Class Selector +class ClassSelector(): + def __init__(self, player: Adventurer) -> None: + self.player = player + # https://stackoverflow.com/questions/3862310/how-to-find-all-the-subclasses-of-a-class-given-its-name + # pull classes that do not have requirements + self.available_classes = [cls for cls in Adventurer.__subclasses__() if not cls.requirements] + # pull classes that do have requirements + self.classes_with_reqs = [cls for cls in Adventurer.__subclasses__() if cls.requirements] + # run function to randomly select an adventurer class + self.selected_class = self.selection() + + def return_class_by_best_attribute(self): + # for adventurer classes in available classes, return the one where that classes' prime requisite is equal to the players best attribute + return [adv_class for adv_class in self.available_classes if adv_class.prime_requisite == self.player.get_best_prime_attribute()][0] + + def return_classes_with_requirements(self): + p_attrs = self.player.get_attributes() + possible_classes = [] + for c in self.classes_with_reqs: + match_count = 0 + for r in c.requirements: + if p_attrs[r] >= c.requirements[r]: + match_count += 1 + if match_count >= len(c.requirements): + possible_classes.append(c) + return possible_classes + + def selection(self): + best_prime_attribute = self.player.get_best_prime_attribute() + # create an array of possible player classes, add the best choice per player's best core attributes + possible_classes = [ self.return_class_by_best_attribute() ] + possible_classes += self.return_classes_with_requirements() + # randomly select class + selected_class = random.choice(possible_classes) + return selected_class + +class PartyGenerator(): + def __init__(self, party_size=4) -> None: + self.size = party_size + self.adventurers = [] + self.adventurer_types = [] + + def gen_party(self): + while len(self.adventurers) < self.size: + new_player = Adventurer() + attempts = 0 + while new_player.player_class not in self.adventurer_types: + attempts += 1 + selected_class = ClassSelector(new_player).selection() + new_player = selected_class(new_player.level, new_player.get_attributes()) + # i couldnt randomly generate a scenario where a character couldn't be added, but it seems possible, so this is the hard cut off + if (new_player.player_class not in self.adventurer_types) or (attempts > 10): + self.adventurers.append(new_player) + self.adventurer_types.append(new_player.player_class) + + def get_character_sheets(self): + sheet_string = "" + for i in range(15): + for j in range(len(self.adventurers)): + adv = self.adventurers[j] + sheet_string += adv.character_sheet()[i] + sheet_string += '|\n' + return sheet_string + + def __str__(self): + return f"{self.adventurers}" + +# functions +def roll_dice(count, sides): + return sum(random.randint(1,sides) for _ in range(count)) + +def returnSheets(foo): + print('foo') + new_party = PartyGenerator() + new_party.gen_party() + return new_party.get_character_sheets() + +def main(): + sheet_string = returnSheets(foo) + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..980a7fc --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +flash diff --git a/templates/sheet.html b/templates/sheet.html new file mode 100644 index 0000000..588a46e --- /dev/null +++ b/templates/sheet.html @@ -0,0 +1,27 @@ + + + + + +
++
{{htmlBody}}
+
+