refactored character and ability generation;stubbed out attack matrices
This commit is contained in:
parent
49adedbab9
commit
1e862d3b61
159
app.py
159
app.py
@ -3,11 +3,12 @@ from flask_cors import CORS
|
|||||||
from flask_restx import Api, Resource
|
from flask_restx import Api, Resource
|
||||||
|
|
||||||
from models import dice_model, ability_model, hp_model, character_model, encounter_model, ma_model
|
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 encounters import EncounterTable
|
||||||
from mentattack import MentalAttackMatrix
|
from mentattack import MentalAttackMatrix
|
||||||
from mutations import Mutations
|
from mutations import Mutations
|
||||||
|
from cybermods import CyberMods
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ character = api.namespace('character', description='Character operations')
|
|||||||
encounter = api.namespace('encounter', description='Encounter operations')
|
encounter = api.namespace('encounter', description='Encounter operations')
|
||||||
|
|
||||||
ability_model = ability.model('Ability', ability_model)
|
ability_model = ability.model('Ability', ability_model)
|
||||||
# TODO: Add ability schema
|
ability_schema = AbilitySchema()
|
||||||
|
|
||||||
hp_model = hp.model('HP', hp_model)
|
hp_model = hp.model('HP', hp_model)
|
||||||
# TODO: Add hitpoint schema
|
# TODO: Add hitpoint schema
|
||||||
@ -65,12 +66,14 @@ class RollAbility(Resource):
|
|||||||
@ability.expect(ability_model)
|
@ability.expect(ability_model)
|
||||||
def post(self):
|
def post(self):
|
||||||
data = api.payload
|
data = api.payload
|
||||||
|
errors = ability_schema.validate(data)
|
||||||
|
if errors:
|
||||||
|
return errors, 400
|
||||||
|
|
||||||
chartype = data.get('chartype')
|
chartype = data.get('chartype')
|
||||||
if chartype == 'human':
|
attribute = data.get('ability')
|
||||||
geometry = 8
|
|
||||||
else:
|
return roll_ability_scores(chartype, attribute), 200
|
||||||
geometry = 6
|
|
||||||
return roll_dices(4, geometry, True), 200
|
|
||||||
|
|
||||||
|
|
||||||
@api.route('/roll/hp', methods=['POST'])
|
@api.route('/roll/hp', methods=['POST'])
|
||||||
@ -180,24 +183,22 @@ class GenerateCharacter(Resource):
|
|||||||
if errors:
|
if errors:
|
||||||
return errors, 400
|
return errors, 400
|
||||||
chartype = data.get('chartype')
|
chartype = data.get('chartype')
|
||||||
char_emphasis = data.get('emphasis')
|
|
||||||
|
|
||||||
character_sheet = {}
|
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':
|
if chartype == 'humanoid' or chartype == 'mutant':
|
||||||
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':
|
|
||||||
character_sheet['mutations'] = (
|
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
|
return character_sheet, 200
|
||||||
@ -234,43 +235,30 @@ def roll_dices(dice_count, dice_sides, discard_lowest):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def roll_ability_scores(chartype):
|
def roll_ability_scores(chartype, attribute=None):
|
||||||
if chartype == 'human':
|
if attribute is None or attribute == "all":
|
||||||
geometry = 8
|
ability_list = ['p-strength', 'm-strength', 'constitution', 'dexterity', 'charisma', 'intelligence']
|
||||||
else:
|
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 = {}
|
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':
|
for abil in ability_list:
|
||||||
ability_list = ['m-strength', 'intelligence', 'charisma',
|
if ((chartype == 'human') and
|
||||||
'constitution', 'dexterity', 'p-strength']
|
((abil == 'intelligence') or
|
||||||
for ab in ability_list:
|
(abil == 'charisma') or
|
||||||
max_score = max(scores)
|
(abil == 'constitution'))):
|
||||||
ability_scores[ab] = max_score
|
roll = roll_dices(4, 6, False) # humans are special
|
||||||
scores.remove(max_score)
|
if (abil == 'constitution') and roll["result"] > 18:
|
||||||
|
roll["capped"] = True
|
||||||
else:
|
roll["result"] = 18
|
||||||
ability_list = ['p-strength', 'constitution', 'dexterity',
|
if (abil == 'intelligence' or abil == 'charisma') and roll["result"] > 21:
|
||||||
'charisma', 'intelligence', 'm-strength']
|
roll["capped"] = True
|
||||||
random.shuffle(scores)
|
roll["result"] = 21
|
||||||
for ab, score in zip(ability_list, scores):
|
ability_scores[abil] = roll["result"]
|
||||||
ability_scores[ab] = score
|
else:
|
||||||
|
roll = roll_dices(4, 6, True) # nothing else is special
|
||||||
|
ability_scores[abil] = roll["result"]
|
||||||
|
|
||||||
return ability_scores
|
return ability_scores
|
||||||
|
|
||||||
@ -283,6 +271,57 @@ def roll_hp(chartype, conscore):
|
|||||||
return roll_dices(conscore, geometry, False).get('result')
|
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):
|
def roll_mutations(conscore, intscore):
|
||||||
"""
|
"""
|
||||||
:param conscore: modifier for physical mutation determination
|
:param conscore: modifier for physical mutation determination
|
||||||
@ -301,8 +340,7 @@ def roll_mutations(conscore, intscore):
|
|||||||
for _ in range(mental_mutations_cnt):
|
for _ in range(mental_mutations_cnt):
|
||||||
mscore = roll_dices(1, 100, False).get('result') + intscore
|
mscore = roll_dices(1, 100, False).get('result') + intscore
|
||||||
if mscore in mental_mutations_scores:
|
if mscore in mental_mutations_scores:
|
||||||
mscore = mscore - 3
|
mscore = roll_dices(1, 100, False).get('result') + intscore
|
||||||
|
|
||||||
if mscore > 100:
|
if mscore > 100:
|
||||||
mscore = 100
|
mscore = 100
|
||||||
mental_mutations_scores.append(mscore)
|
mental_mutations_scores.append(mscore)
|
||||||
@ -310,8 +348,7 @@ def roll_mutations(conscore, intscore):
|
|||||||
for _ in range(physical_mutations_cnt):
|
for _ in range(physical_mutations_cnt):
|
||||||
pscore = roll_dices(1, 100, False).get('result') + conscore
|
pscore = roll_dices(1, 100, False).get('result') + conscore
|
||||||
if pscore in physical_mutations_scores:
|
if pscore in physical_mutations_scores:
|
||||||
pscore = pscore - 3
|
pscore = roll_dices(1, 100, False).get('result') + conscore
|
||||||
|
|
||||||
if pscore > 100:
|
if pscore > 100:
|
||||||
pscore = 100
|
pscore = 100
|
||||||
physical_mutations_scores.append(pscore)
|
physical_mutations_scores.append(pscore)
|
||||||
@ -335,5 +372,11 @@ def roll_mutations(conscore, intscore):
|
|||||||
return mutations_table
|
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__':
|
if __name__ == '__main__':
|
||||||
app.run()
|
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
|
# Common fields
|
||||||
chartype_field = fields.String(
|
chartype_field = fields.String(
|
||||||
required=False, default="human",
|
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
|
||||||
dice_model = {
|
dice_model = {
|
||||||
@ -14,7 +14,8 @@ dice_model = {
|
|||||||
|
|
||||||
# Ability model
|
# Ability 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
|
# Hp model
|
||||||
@ -31,10 +32,6 @@ ma_model = {
|
|||||||
|
|
||||||
character_model = {
|
character_model = {
|
||||||
'chartype': chartype_field,
|
'chartype': chartype_field,
|
||||||
'emphasis': fields.String(
|
|
||||||
required=False,
|
|
||||||
default="random",
|
|
||||||
description='The attribute emphasis of your character. Choices: "physical", "mental", "random"')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
encounter_model = {
|
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
|
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):
|
class DiceSchema(Schema):
|
||||||
quantity = fields.Int(required=True, validate=validate.Range(min=1), description='The number of dice to roll')
|
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):
|
class CharacterSchema(Schema):
|
||||||
chartype = fields.String(
|
chartype = chartype_field
|
||||||
required=True,
|
|
||||||
validate=validate.OneOf(["human", "mutant", "android", "robot"]),
|
|
||||||
description='The characters type of being'
|
class AbilitySchema(Schema):
|
||||||
)
|
chartype = chartype_field
|
||||||
emphasis = fields.String(
|
ability = fields.String(
|
||||||
required=True,
|
required=False,
|
||||||
validate=validate.OneOf(["physical", "mental", "random"]),
|
default="generic",
|
||||||
description='Valid inputs: physical, mental, random'
|
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),
|
validate=validate.Range(min=-100, max=100),
|
||||||
description='Roll modifier for mental attack'
|
description='Roll modifier for mental attack'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user