refactored character and ability generation;stubbed out attack matrices

This commit is contained in:
Greg Gauthier 2024-06-23 18:30:13 +01:00
parent 49adedbab9
commit 1e862d3b61
5 changed files with 166 additions and 74 deletions

159
app.py
View File

@ -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)
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
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:
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
View 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]

View File

@ -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
View 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 = {}

View File

@ -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'
)