From 796aac4d807bf081e4d3a961ccaec80be69006f2 Mon Sep 17 00:00:00 2001 From: Greg Gauthier Date: Sat, 22 Jun 2024 14:22:39 +0100 Subject: [PATCH] add simple character stats generator --- app.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++++----- models.py | 13 +++++- 2 files changed, 117 insertions(+), 11 deletions(-) diff --git a/app.py b/app.py index ab38793..7b1ce98 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,7 @@ from flask import Flask -from flask_restx import Api, Resource, fields +from flask_restx import Api, Resource from marshmallow import Schema, fields, validate -from models import dice_model, ability_model, hp_model +from models import dice_model, ability_model, hp_model, character_model import random app = Flask(__name__) @@ -12,10 +12,12 @@ api = Api(app, version='1.0', title='Gamma World Dice', description='Rolled Dice dice = api.namespace('dice', description='Dice operations') ability = api.namespace('ability', description='Ability operations') hp = api.namespace('hp', description='HP operations') +character = api.namespace('character', description='Character operations') dice_model = dice.model('Dice', dice_model) ability_model = ability.model('Ability', ability_model) hp_model = hp.model('HP', hp_model) +character_model = character.model('Character', character_model) class DiceSchema(Schema): @@ -27,6 +29,22 @@ class DiceSchema(Schema): dice_schema = DiceSchema() +class CharacterSchema(Schema): + chartype = fields.String( + required=True, + validate=validate.OneOf(["human", "mutant", "android", "robot"]), + description='The characters type of being' + ) + emphasis = fields.String( + required=True, + validate=validate.OneOf(["physical", "mental", "random"]), + description='Valid inputs: physical, mental, random' + ) + + +character_schema = CharacterSchema() + + @api.route('/roll/dice', methods=['POST']) class RollDice(Resource): @dice.expect(dice_model) @@ -72,16 +90,48 @@ class RollHP(Resource): return roll_dices(conscore, geometry, False), 200 +@api.route('/roll/tohit', methods=['GET']) +class RollToHit(Resource): + def get(self): + return roll_dices(1, 20, False), 200 + + @api.route('/roll/chance', methods=['GET']) class RollChance(Resource): def get(self): return roll_dices(1, 100, False), 200 -@api.route('/roll/tohit', methods=['GET']) -class RollToHit(Resource): +@api.route('/coinflip', methods=['GET']) +class RollCoinflip(Resource): def get(self): - return roll_dices(1, 20, False), 200 + return random.choice(['Heads', 'Tails']), 200 + + +@api.route('/character/generate') +class GenerateCharacter(Resource): + @character.expect(character_model) + def post(self): + data = api.payload + errors = character_schema.validate(data) + if errors: + return errors, 400 + chartype = data.get('chartype') + char_emphasis = data.get('emphasis') + + character_sheet = {} + + if chartype == 'human': + geometry = 8 + else: + geometry = 6 + scores = roll_ability_scores(chartype) + assigned_abilities = assign_ability_scores(scores, char_emphasis) + character_sheet['abilities'] = assigned_abilities + character_sheet['hp'] = roll_hp(chartype, assigned_abilities['constitution']) + character_sheet['gold'] = roll_dices(4, 4, False).get('result') + character_sheet['domar'] = roll_dices(2, 4, False).get('result') + return character_sheet, 200 def roll_dices(dice_count, dice_sides, discard_lowest): @@ -94,17 +144,17 @@ def roll_dices(dice_count, dice_sides, discard_lowest): roll_results.remove(min(roll_results)) if discarded: - net_dice_count = dice_count -1 - mnemonic = str(dice_count)+"(-1)d"+str(dice_sides) + net_dice_count = dice_count - 1 + mnemonic = str(dice_count) + "(-1)d" + str(dice_sides) else: - mnemonic = str(dice_count)+'d'+str(dice_sides) + mnemonic = str(dice_count) + 'd' + str(dice_sides) net_dice_count = dice_count result = { 'dice-set': { 'mnemonic': mnemonic, 'min-roll': net_dice_count, - 'max-roll': dice_sides*net_dice_count + 'max-roll': dice_sides * net_dice_count }, 'rolls': roll_results, 'result': sum(roll_results) @@ -115,5 +165,52 @@ def roll_dices(dice_count, dice_sides, discard_lowest): return result +def roll_ability_scores(chartype): + if chartype == 'human': + geometry = 8 + else: + geometry = 6 + + scores = [] + for _ in range(6): + scores.append(roll_dices(4, geometry, True)['result']) + + return scores + + +def assign_ability_scores(scores, char_emphasis): + ability_scores = {} + if char_emphasis == 'physical': + ability_list = ['p-strength', 'constitution', 'dexterity', + 'charisma', 'intelligence', 'm-strength'] + for ab in ability_list: + max_score = max(scores) + ability_scores[ab] = max_score + scores.remove(max_score) + + elif char_emphasis == 'mental': + ability_list = ['m-strength', 'intelligence', 'charisma', + 'constitution', 'dexterity', 'p-strength'] + for ab in ability_list: + max_score = max(scores) + ability_scores[ab] = max_score + scores.remove(max_score) + + else: + ability_list = ['p-strength', 'constitution', 'dexterity', + 'charisma', 'intelligence', 'm-strength'] + random.shuffle(scores) + for ab, score in zip(ability_list, scores): + ability_scores[ab] = score + + return ability_scores + +def roll_hp(chartype, conscore): + if chartype == 'human': + geometry = 8 + else: + geometry = 6 + return roll_dices(conscore, geometry, False).get('result') + if __name__ == '__main__': app.run() diff --git a/models.py b/models.py index 37ab988..245e099 100644 --- a/models.py +++ b/models.py @@ -1,8 +1,9 @@ from flask_restx import fields # Common fields -chartype_field = fields.String(required=False, default="human", description='Character type. Allowed values: "human", ' - '"mutant", "android", "robot"') +chartype_field = fields.String( + required=False, default="human", + description='Character type. Allowed values: "human", "mutant", "android", "robot"') # Dice model dice_model = { @@ -21,3 +22,11 @@ hp_model = { 'chartype': chartype_field, 'conscore': fields.Integer(required=True, description='Conscore') } + +character_model = { + 'chartype': chartype_field, + 'emphasis': fields.String( + required=False, + default="random", + description='The attribute emphasis of your character. Choices: "physical", "mental", "random"') +}