You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

190 lines
5.6 KiB

import requests
from math import floor, ceil
from random import randint, choice, shuffle
from .models import (
CharacterClass,
EquipmentArmour,
EquipmentRangedWeapon,
EquipmentMeleeWeapon,
CharacterNPC
)
def number_encountered():
return (randint(1, 4) + 2)
def npc_class(excluded_buckets):
if excluded_buckets:
classes = [c for cls in CharacterClass.query.filter(CharacterClass.bucket.notin_(excluded_buckets)).all() for c in ([cls] * cls.frequency_modifier)]
else:
classes = [c for cls in CharacterClass.query.all() for c in ([cls] * cls.frequency_modifier)]
return choice(classes)
def npc_alignment():
roll = randint(1, 6)
if roll == 1 or roll == 2:
return 'Lawful'
elif roll == 3 or roll == 4 or roll == 5:
return 'Neutral'
elif roll == 6:
return 'Chaotic'
def npc_baselevel(base_level):
roll = randint(1, 6)
mod = 0
if roll == 1:
mod = -2
elif roll == 2:
mod = -1
elif roll == 3 or roll == 4:
mod = 0
elif roll == 5:
mod = 1
elif roll == 6:
mod = 2
base_level += mod
if base_level < 1:
base_level = 1
return base_level
def npc_abilities():
ability_list = ['strength', 'intelligence', 'wisdom', 'dexterity', 'constitution', 'charisma']
abilities = [(randint(1, 6) + randint(1, 6) + randint(1, 6)) for x in range(0,6)]
return zip(ability_list, abilities)
def attribute_mod(atr):
mod = 0
if atr <= 3: mod = -3
if atr >= 4 and atr <= 5: mod = -2
if atr >= 6 and atr <= 8: mod = -1
if atr >= 9 and atr <= 12: mod = 0
if atr >= 13 and atr <= 15: mod = 1
if atr >= 16 and atr <= 17: mod = 2
if atr >= 18: mod = 3
return mod
def select_melee_weapon(guild, data):
weapons = []
for x in range(0, guild.melee_heavy):
weapons.extend(data['melee']['heavy'])
for x in range(0, guild.melee_medium):
weapons.extend(data['melee']['medium'])
for x in range(0, guild.melee_light):
weapons.extend(data['melee']['light'])
selection = randint(0, len(weapons) - 1)
return weapons[selection]
def select_ranged_weapon(guild, data):
weapons = []
for x in range(0, guild.ranged_light):
weapons.extend(data['ranged']['light'])
for x in range(0, guild.ranged_heavy):
weapons.extend(data['ranged']['heavy'])
if not weapons:
return None
selection = randint(0, len(weapons) - 1)
return weapons[selection]
def calc_hp(conmod, hit_die_size, level):
hp = 0
hitdice = [randint(1, hit_die_size) for x in range(0, level)]
for die in hitdice:
die += conmod
if die < 1:
die = 1
hp += die
return hp
def calc_armour(armour_mod, armours):
armourval = randint(0, len(armours) - 1) + armour_mod
if armourval < 0:
armourval = 0
if armourval > len(armours) - 1:
armourval = len(armours) - 1
return armours[armourval]
def generate_npc(base_level, data):
npc = CharacterNPC()
npc.guild = npc_class(['Demi-Human'])
npc.level = npc_baselevel(base_level)
npc.alignment = npc_alignment()
abilities = npc_abilities()
npc.update(npc_abilities())
npc.hit_points = calc_hp(attribute_mod(npc.constitution), npc.guild.hit_die_size, npc.level)
npc.armour = calc_armour(npc.guild.armour_modifier, data['armours'])
npc.melee = select_melee_weapon(npc.guild, data)
npc.ranged = select_ranged_weapon(npc.guild, data)
return npc
def name_party(party):
male_names = requests.get(
'http://names.drycodes.com/{}'.format(ceil(len(party))),
params={'nameOptions': 'boy_names', 'separator': 'space'}
).json()
female_names = requests.get(
'http://names.drycodes.com/{}'.format(floor(len(party))),
params={'nameOptions': 'girl_names', 'separator': 'space'}
).json()
names = female_names + male_names
shuffle(names)
for i in range(0, len(party)):
party[i].name = names[i]
return party
def create_party(base_level):
data = {
'armours': EquipmentArmour.query.all(),
'ranged': {
'light': EquipmentRangedWeapon.query.filter_by(bucket='Light').all(),
'heavy': EquipmentRangedWeapon.query.filter_by(bucket='Heavy').all()
},
'melee': {
'light': EquipmentMeleeWeapon.query.filter_by(bucket='Light').all(),
'medium': EquipmentMeleeWeapon.query.filter_by(bucket='Medium').all(),
'heavy': EquipmentMeleeWeapon.query.filter_by(bucket='Heavy').all()
},
}
return name_party([generate_npc(base_level, data) for x in range(0, number_encountered())])
def print_party(party):
def print_npc(npc):
print('Level {0} NPC, {1}, {2} HP'.format(npc.level, npc.guild, npc.hp))
print('{0} Str, {1} Int, {2} Wis, {3} Dex, {4} Con, {5} Chr'.format(
npc.str, npc.int, npc.wis,
npc.dex, npc.con, npc.chr
))
print('Armour Class: {0} - {1}, {2}gp'.format(npc.armour.name, npc.armour.ac_mod, npc.armour.gp_value))
print('{:^16} - {:^10} - {:^10} - {:^10}'.format('Weapon', 'Gold', 'Throw Mod', 'Damage'))
print('-------------------------------------------------------')
print('{:^16} | {:^10} | {:^10} | {:^10}'.format(npc.melee.name, 0, npc.melee.damage_die))
if npc['ranged']:
print('{:^16} | {:^10} | {:^10} | {:^10}'.format(npc.ranged.name, 0, npc.melee.damage_die))
print('\n')
for npc in party:
print_npc(npc)
if __name__ == '__main__':
party = create_party(2)
print_party(party)