refactored character and ability generation;stubbed out attack matrices
This commit is contained in:
		
							parent
							
								
									49adedbab9
								
							
						
					
					
						commit
						1e862d3b61
					
				
							
								
								
									
										157
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								app.py
									
									
									
									
									
								
							@ -3,11 +3,12 @@ from flask_cors import CORS
 | 
			
		||||
from flask_restx import Api, Resource
 | 
			
		||||
 | 
			
		||||
from models import dice_model, ability_model, hp_model, character_model, encounter_model, ma_model
 | 
			
		||||
from schemas import DiceSchema, CharacterSchema, EncounterSchema, MentalAttackSchema
 | 
			
		||||
from schemas import DiceSchema, CharacterSchema, EncounterSchema, MentalAttackSchema, AbilitySchema
 | 
			
		||||
 | 
			
		||||
from encounters import EncounterTable
 | 
			
		||||
from mentattack import MentalAttackMatrix
 | 
			
		||||
from mutations import Mutations
 | 
			
		||||
from cybermods import CyberMods
 | 
			
		||||
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
@ -26,7 +27,7 @@ character = api.namespace('character', description='Character operations')
 | 
			
		||||
encounter = api.namespace('encounter', description='Encounter operations')
 | 
			
		||||
 | 
			
		||||
ability_model = ability.model('Ability', ability_model)
 | 
			
		||||
# TODO: Add ability schema
 | 
			
		||||
ability_schema = AbilitySchema()
 | 
			
		||||
 | 
			
		||||
hp_model = hp.model('HP', hp_model)
 | 
			
		||||
# TODO: Add hitpoint schema
 | 
			
		||||
@ -65,12 +66,14 @@ class RollAbility(Resource):
 | 
			
		||||
    @ability.expect(ability_model)
 | 
			
		||||
    def post(self):
 | 
			
		||||
        data = api.payload
 | 
			
		||||
        errors = ability_schema.validate(data)
 | 
			
		||||
        if errors:
 | 
			
		||||
            return errors, 400
 | 
			
		||||
 | 
			
		||||
        chartype = data.get('chartype')
 | 
			
		||||
        if chartype == 'human':
 | 
			
		||||
            geometry = 8
 | 
			
		||||
        else:
 | 
			
		||||
            geometry = 6
 | 
			
		||||
        return roll_dices(4, geometry, True), 200
 | 
			
		||||
        attribute = data.get('ability')
 | 
			
		||||
 | 
			
		||||
        return roll_ability_scores(chartype, attribute), 200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api.route('/roll/hp', methods=['POST'])
 | 
			
		||||
@ -180,24 +183,22 @@ class GenerateCharacter(Resource):
 | 
			
		||||
        if errors:
 | 
			
		||||
            return errors, 400
 | 
			
		||||
        chartype = data.get('chartype')
 | 
			
		||||
        char_emphasis = data.get('emphasis')
 | 
			
		||||
 | 
			
		||||
        character_sheet = {}
 | 
			
		||||
        ability_scores = roll_ability_scores(chartype)
 | 
			
		||||
        character_sheet['abilities'] = ability_scores
 | 
			
		||||
        character_sheet['hp'] = roll_hp(chartype, ability_scores['constitution'])
 | 
			
		||||
        character_sheet['gold'] = roll_dices(4, 4, False).get('result') * 10
 | 
			
		||||
        character_sheet['domar'] = roll_dices(2, 4, False).get('result') * 5
 | 
			
		||||
 | 
			
		||||
        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')
 | 
			
		||||
 | 
			
		||||
        if chartype == 'mutant':
 | 
			
		||||
        if chartype == 'humanoid' or chartype == 'mutant':
 | 
			
		||||
            character_sheet['mutations'] = (
 | 
			
		||||
                roll_mutations(assigned_abilities['constitution'], assigned_abilities['intelligence'])
 | 
			
		||||
                roll_mutations(ability_scores['constitution'], ability_scores['intelligence'])
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        if chartype == 'cyborg':
 | 
			
		||||
            character_sheet['cybermods'] = (
 | 
			
		||||
                roll_cybermods()
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        return character_sheet, 200
 | 
			
		||||
@ -234,43 +235,30 @@ def roll_dices(dice_count, dice_sides, discard_lowest):
 | 
			
		||||
    return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def roll_ability_scores(chartype):
 | 
			
		||||
    if chartype == 'human':
 | 
			
		||||
        geometry = 8
 | 
			
		||||
def roll_ability_scores(chartype, attribute=None):
 | 
			
		||||
    if attribute is None or attribute == "all":
 | 
			
		||||
        ability_list = ['p-strength', 'm-strength', 'constitution', 'dexterity', 'charisma', 'intelligence']
 | 
			
		||||
    else:
 | 
			
		||||
        geometry = 6
 | 
			
		||||
        ability_list = [attribute]
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    for abil in ability_list:
 | 
			
		||||
        if ((chartype == 'human') and
 | 
			
		||||
                ((abil == 'intelligence') or
 | 
			
		||||
                 (abil == 'charisma') or
 | 
			
		||||
                 (abil == 'constitution'))):
 | 
			
		||||
            roll = roll_dices(4, 6, False)  # humans are special
 | 
			
		||||
            if (abil == 'constitution') and roll["result"] > 18:
 | 
			
		||||
                roll["capped"] = True
 | 
			
		||||
                roll["result"] = 18
 | 
			
		||||
            if (abil == 'intelligence' or abil == 'charisma') and roll["result"] > 21:
 | 
			
		||||
                roll["capped"] = True
 | 
			
		||||
                roll["result"] = 21
 | 
			
		||||
            ability_scores[abil] = roll["result"]
 | 
			
		||||
        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
 | 
			
		||||
            roll = roll_dices(4, 6, True)  # nothing else is special
 | 
			
		||||
            ability_scores[abil] = roll["result"]
 | 
			
		||||
 | 
			
		||||
    return ability_scores
 | 
			
		||||
 | 
			
		||||
@ -283,6 +271,57 @@ def roll_hp(chartype, conscore):
 | 
			
		||||
    return roll_dices(conscore, geometry, False).get('result')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def roll_cybermods():
 | 
			
		||||
    """
 | 
			
		||||
    Cybermods are similar to mutations, except that they are artificial changes to the body,
 | 
			
		||||
    where mutations are 'natural' changes to the body. Fewer cybermods are possible than with
 | 
			
		||||
    mutations. So, you make one roll of 1d4, and then parse up the score between the two
 | 
			
		||||
    types of mods, as you see fit. If no emphasis is specified, the score will be split as evenly
 | 
			
		||||
    as possible. If the score is 1, then a physical mod will be the default.
 | 
			
		||||
    :return: table of cybermods (in json format)
 | 
			
		||||
    """
 | 
			
		||||
    cybermods_table = {}
 | 
			
		||||
 | 
			
		||||
    cybermods_count = roll_dices(1, 4, False)["result"]
 | 
			
		||||
    phys_cnt = split_number(cybermods_count)[0]
 | 
			
		||||
    ment_cnt = split_number(cybermods_count)[1]
 | 
			
		||||
 | 
			
		||||
    mental_cybermods_scores = []
 | 
			
		||||
    physical_cybermods_scores = []
 | 
			
		||||
 | 
			
		||||
    for _ in range(ment_cnt):
 | 
			
		||||
        mscore = roll_dices(1, 10, False).get('result')
 | 
			
		||||
        if mscore in mental_cybermods_scores:
 | 
			
		||||
            mscore = roll_dices(1, 10, False).get('result')
 | 
			
		||||
        mental_cybermods_scores.append(mscore)
 | 
			
		||||
 | 
			
		||||
    for _ in range(phys_cnt):
 | 
			
		||||
        pscore = roll_dices(1, 10, False).get('result')
 | 
			
		||||
        if pscore in physical_cybermods_scores:
 | 
			
		||||
            pscore = roll_dices(1, 10, False).get('result')
 | 
			
		||||
        physical_cybermods_scores.append(pscore)
 | 
			
		||||
 | 
			
		||||
    cyb = CyberMods()
 | 
			
		||||
    mcyb = []
 | 
			
		||||
    pcyb = []
 | 
			
		||||
 | 
			
		||||
    for score in mental_cybermods_scores:
 | 
			
		||||
        modification = cyb.get_mental_cybermod(score)
 | 
			
		||||
        mcyb.append(modification)
 | 
			
		||||
 | 
			
		||||
    if len(mcyb) != 0:
 | 
			
		||||
        cybermods_table['mental'] = mcyb
 | 
			
		||||
 | 
			
		||||
    for score in physical_cybermods_scores:
 | 
			
		||||
        modification = cyb.get_physical_cybermod(score)
 | 
			
		||||
        pcyb.append(modification)
 | 
			
		||||
 | 
			
		||||
    if len(pcyb) != 0:
 | 
			
		||||
        cybermods_table['physical'] = pcyb
 | 
			
		||||
 | 
			
		||||
    return cybermods_table
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def roll_mutations(conscore, intscore):
 | 
			
		||||
    """
 | 
			
		||||
    :param conscore: modifier for physical mutation determination
 | 
			
		||||
@ -301,8 +340,7 @@ def roll_mutations(conscore, intscore):
 | 
			
		||||
    for _ in range(mental_mutations_cnt):
 | 
			
		||||
        mscore = roll_dices(1, 100, False).get('result') + intscore
 | 
			
		||||
        if mscore in mental_mutations_scores:
 | 
			
		||||
            mscore = mscore - 3
 | 
			
		||||
 | 
			
		||||
            mscore = roll_dices(1, 100, False).get('result') + intscore
 | 
			
		||||
        if mscore > 100:
 | 
			
		||||
            mscore = 100
 | 
			
		||||
        mental_mutations_scores.append(mscore)
 | 
			
		||||
@ -310,8 +348,7 @@ def roll_mutations(conscore, intscore):
 | 
			
		||||
    for _ in range(physical_mutations_cnt):
 | 
			
		||||
        pscore = roll_dices(1, 100, False).get('result') + conscore
 | 
			
		||||
        if pscore in physical_mutations_scores:
 | 
			
		||||
            pscore = pscore - 3
 | 
			
		||||
 | 
			
		||||
            pscore = roll_dices(1, 100, False).get('result') + conscore
 | 
			
		||||
        if pscore > 100:
 | 
			
		||||
            pscore = 100
 | 
			
		||||
        physical_mutations_scores.append(pscore)
 | 
			
		||||
@ -335,5 +372,11 @@ def roll_mutations(conscore, intscore):
 | 
			
		||||
    return mutations_table
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def split_number(n):
 | 
			
		||||
    first_split = n // 2  # this will split the number in two equal parts, if it is even
 | 
			
		||||
    second_split = n % 2 + first_split  # this will add one to one part if the number is odd
 | 
			
		||||
    return first_split, second_split
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    app.run()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								cybermods.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								cybermods.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
import pandas as pd
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyberMods(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.raw_cybermods_table = {
 | 
			
		||||
            'Score': list(range(1, 11)),
 | 
			
		||||
            'Physical': ['Replacement Limb', 'Replacement Sense Organ', 'Attribute Enhancement',
 | 
			
		||||
                         'Additional Limb', 'Additional Sense Organ', 'Attachment Interface',
 | 
			
		||||
                         'Energy Emitter', 'Energy Absorption', 'Nano-tech Collective', 'YOU INVENT ONE'],
 | 
			
		||||
            'Mental': ['Replacement Brain', 'Transmitter', 'Receiver', 'Energy Detection', 'Knowledge Base',
 | 
			
		||||
                       'Pacify Android', 'Control Machine', 'Tech Recognition', 'Fabrication', 'YOU INVENT ONE']
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.cybermods_table = pd.DataFrame(self.raw_cybermods_table)
 | 
			
		||||
 | 
			
		||||
    def get_physical_cybermod(self, score):
 | 
			
		||||
        cybermod = self.cybermods_table.loc[self.cybermods_table['Score'] == score, 'Physical']
 | 
			
		||||
        return cybermod.iloc[0] if not cybermod.empty else None
 | 
			
		||||
 | 
			
		||||
    def get_mental_cybermod(self, score):
 | 
			
		||||
        cybermod = self.cybermods_table.loc[self.cybermods_table['Score'] == score, 'Mental']
 | 
			
		||||
        return cybermod.iloc[0] if not cybermod.empty else None
 | 
			
		||||
 | 
			
		||||
    def get_table_shape(self):
 | 
			
		||||
        return self.cybermods_table.shape
 | 
			
		||||
 | 
			
		||||
    def get_table_row_count(self):
 | 
			
		||||
        return self.cybermods_table.shape[0]
 | 
			
		||||
 | 
			
		||||
    def get_table_column_count(self):
 | 
			
		||||
        return self.cybermods_table.shape[1]
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ from flask_restx import fields
 | 
			
		||||
# Common fields
 | 
			
		||||
chartype_field = fields.String(
 | 
			
		||||
    required=False, default="human",
 | 
			
		||||
    description='Character type. Allowed values: "human", "mutant", "android", "robot"')
 | 
			
		||||
    description='Character type. Allowed values: "human", "humanoid", "mutant", "cyborg", "android"')
 | 
			
		||||
 | 
			
		||||
# Dice model
 | 
			
		||||
dice_model = {
 | 
			
		||||
@ -14,7 +14,8 @@ dice_model = {
 | 
			
		||||
 | 
			
		||||
# Ability model
 | 
			
		||||
ability_model = {
 | 
			
		||||
    'chartype': chartype_field
 | 
			
		||||
    'chartype': chartype_field,
 | 
			
		||||
    'ability': fields.String(required=False, description='The ability to roll. Not required. Defaults "generic"'),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Hp model
 | 
			
		||||
@ -31,10 +32,6 @@ ma_model = {
 | 
			
		||||
 | 
			
		||||
character_model = {
 | 
			
		||||
    'chartype': chartype_field,
 | 
			
		||||
    'emphasis': fields.String(
 | 
			
		||||
        required=False,
 | 
			
		||||
        default="random",
 | 
			
		||||
        description='The attribute emphasis of your character. Choices: "physical", "mental", "random"')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
encounter_model = {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								physattack.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								physattack.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
import pandas as pd
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WeaponClassAttackMatrix:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        data = {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HitDiceAttackMatrix:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        data = {}
 | 
			
		||||
							
								
								
									
										27
									
								
								schemas.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								schemas.py
									
									
									
									
									
								
							@ -1,5 +1,11 @@
 | 
			
		||||
from marshmallow import Schema, fields, validate
 | 
			
		||||
 | 
			
		||||
chartype_field = fields.String(
 | 
			
		||||
    required=True,
 | 
			
		||||
    validate=validate.OneOf(["human", "humanoid", "mutant", "cyborg", "android"]),
 | 
			
		||||
    description='The characters type of being'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DiceSchema(Schema):
 | 
			
		||||
    quantity = fields.Int(required=True, validate=validate.Range(min=1), description='The number of dice to roll')
 | 
			
		||||
@ -8,15 +14,17 @@ class DiceSchema(Schema):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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'
 | 
			
		||||
    chartype = chartype_field
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AbilitySchema(Schema):
 | 
			
		||||
    chartype = chartype_field
 | 
			
		||||
    ability = fields.String(
 | 
			
		||||
        required=False,
 | 
			
		||||
        default="generic",
 | 
			
		||||
        validate=validate.OneOf(
 | 
			
		||||
            ["m-strength", "p-strength", "intelligence", "charisma", "constitution", "dexterity", "all"]),
 | 
			
		||||
        description='One of the six character attributes from the character sheet'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -45,4 +53,3 @@ class MentalAttackSchema(Schema):
 | 
			
		||||
        validate=validate.Range(min=-100, max=100),
 | 
			
		||||
        description='Roll modifier for mental attack'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user