commit acb36211461f344cc65b418eb6b86bcb0a991ceb Author: Brandon Cornejo Date: Mon Dec 2 17:13:29 2019 -0600 Beginning to add DB backend diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afcc81a --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Python +*.py[co] + +# Vim +*.swp + +# Virtualenv +bin +data +include +lib +lib64 +__pycache__ +share +pyvenv.cfg diff --git a/acks/__init__.py b/acks/__init__.py new file mode 100644 index 0000000..67bc997 --- /dev/null +++ b/acks/__init__.py @@ -0,0 +1,26 @@ +from flask import Flask + +def create_app(): + app = Flask(__name__) + + # Prep the database + from acks.models import db + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../data/acks.db' + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + db.init_app(app) + + # Load our views + from acks.views import default_views + app.register_blueprint(default_views) + + from acks.npc.views import npc_views + app.register_blueprint(npc_views) + + # Load our CLI commands + from acks.commands import default_cli + app.cli.add_command(default_cli) + + from acks.npc.commands import npc_cli + app.cli.add_command(npc_cli) + + return app diff --git a/acks/commands.py b/acks/commands.py new file mode 100644 index 0000000..cb59d0f --- /dev/null +++ b/acks/commands.py @@ -0,0 +1,13 @@ +import click +from flask.cli import AppGroup + +from acks.models import db + +default_cli = AppGroup('acks') + +@default_cli.command('initdb') +def initialize_database(): + from acks import models + from acks.npc import models + db.create_all() + diff --git a/acks/models.py b/acks/models.py new file mode 100644 index 0000000..878f0a3 --- /dev/null +++ b/acks/models.py @@ -0,0 +1,10 @@ +from flask_sqlalchemy import SQLAlchemy + + +db = SQLAlchemy() + +class BaseModel(db.Model): + __abstract__ = True + + id = db.Column(db.Integer, primary_key=True) + created_at = db.Column(db.DateTime) diff --git a/acks/npc/commands.py b/acks/npc/commands.py new file mode 100644 index 0000000..e2f0007 --- /dev/null +++ b/acks/npc/commands.py @@ -0,0 +1,184 @@ +import click +from flask.cli import AppGroup + +from ..models import db + + +npc_cli = AppGroup('npc') + +@npc_cli.command('create classes') +def create_classes(): + from .models import CharacterClass + + classes = [] + + classes.append(CharacterClass( + name = 'Elven Nightblade', + bucket = 'Demi-Human', + prime_requisite = 'D+I', + hit_die_size = 6, + maximum_level = 11, + armour_modifier = -4, + melee_light = 1, + melee_medium = 2, + melee_heavy = 0, + ranged_light = 0, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Elven Spellsword', + bucket = 'Demi-Human', + prime_requisite = 'S+I', + hit_die_size = 6, + maximum_level = 10, + armour_modifier = -4, + melee_light = 0, + melee_medium = 1, + melee_heavy = 0, + ranged_light = 0, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Explorer', + bucket = 'Campaign', + prime_requisite = 'S+D', + hit_die_size = 6, + maximum_level = 14, + armour_modifier = -3, + melee_light = 1, + melee_medium = 1, + melee_heavy = 0, + ranged_light = 0, + ranged_heavy = 1 + )) + + classes.append(CharacterClass( + name = 'Bladedancer', + bucket = 'Campaign', + prime_requisite = 'W+D', + hit_die_size = 6, + maximum_level = 14, + armour_modifier = -2, + melee_light = 0, + melee_medium = 1, + melee_heavy = 0, + ranged_light = 0, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Cleric', + bucket = 'Core', + prime_requisite = 'WIS', + hit_die_size = 6, + maximum_level = 14, + armour_modifier = 0, + melee_light = 1, + melee_medium = 3, + melee_heavy = 1, + ranged_light = 1, + ranged_heavy = 3 + )) + + classes.append(CharacterClass( + name = 'Fighter', + bucket = 'Core', + prime_requisite = 'STR', + hit_die_size = 8, + maximum_level = 14, + armour_modifier = 1, + melee_light = 1, + melee_medium = 4, + melee_heavy = 1, + ranged_light = 1, + ranged_heavy = 1 + )) + + classes.append(CharacterClass( + name = 'Thief', + bucket = 'Core', + prime_requisite = 'DEX', + hit_die_size = 4, + maximum_level = 14, + armour_modifier = -6, + melee_light = 1, + melee_medium = 1, + melee_heavy = 0, + ranged_light = 1, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Mage', + bucket = 'Core', + prime_requisite = 'INT', + hit_die_size = 4, + maximum_level = 14, + armour_modifier = -8, + melee_light = 1, + melee_medium = 0, + melee_heavy = 0, + ranged_light = 0, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Assassin', + bucket = 'Campaign', + prime_requisite = 'S+D', + hit_die_size = 6, + maximum_level = 14, + armour_modifier = -6, + melee_light = 1, + melee_medium = 2, + melee_heavy = 0, + ranged_light = 1, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Bard', + bucket = 'Campaign', + prime_requisite = 'D+H', + hit_die_size = 6, + maximum_level = 14, + armour_modifier = -3, + melee_light = 1, + melee_medium = 2, + melee_heavy = 0, + ranged_light = 1, + ranged_heavy = 0 + )) + + classes.append(CharacterClass( + name = 'Dwarven Vaultguard', + bucket = 'Demi-Human', + prime_requisite = 'STR', + hit_die_size = 8, + maximum_level = 13, + armour_modifier = -1, + melee_light = 0, + melee_medium = 3, + melee_heavy = 1, + ranged_light = 1, + ranged_heavy = 1 + )) + + classes.append(CharacterClass( + name = 'Dwarven Craftpriest', + bucket = 'Demi-Human', + prime_requisite = 'WIS', + hit_die_size = 6, + maximum_level = 10, + armour_modifier = -2, + melee_light = 0, + melee_medium = 1, + melee_heavy = 0, + ranged_light = 1, + ranged_heavy = 0 + )) + + db.session.bulk_save_objects(classes) + db.session.commit() diff --git a/acks/npc/models.py b/acks/npc/models.py new file mode 100644 index 0000000..6052e0f --- /dev/null +++ b/acks/npc/models.py @@ -0,0 +1,23 @@ +from flask_sqlalchemy import SQLAlchemy +from ..models import db, BaseModel + + +class CharacterClass(BaseModel): + __tablename__ = 'character_class' + + name = db.Column(db.String(50), unique=True, nullable=False) + bucket = db.Column(db.String(50)) + + prime_requisite = db.Column(db.String(3)) + hit_die_size = db.Column(db.Integer) + maximum_level = db.Column(db.Integer) + + armour_modifier = db.Column(db.Integer) + melee_light = db.Column(db.Integer) + melee_medium = db.Column(db.Integer) + melee_heavy = db.Column(db.Integer) + ranged_light = db.Column(db.Integer) + ranged_heavy = db.Column(db.Integer) + + def __repr__(self): + return ''.format(self.name) diff --git a/acks/npc/npc_party.py b/acks/npc/npc_party.py new file mode 100644 index 0000000..e08474e --- /dev/null +++ b/acks/npc/npc_party.py @@ -0,0 +1,309 @@ +from random import randint + + +def number_encountered(): + return (randint(1, 4) + 2) + +def npc_class(): + roll = (randint(1, 6) + randint(1, 6) + randint(1, 6)) + if roll == 3 or roll == 4: + return 'Elven Nightblade' + elif roll == 5: + return 'Elven Spellsword' + elif roll == 6: + return 'Explorer' + elif roll == 7: + return 'Bladedancer' + elif roll == 8: + return 'Cleric' + elif roll == 9 or roll == 10 or roll == 11: + return 'Fighter' + elif roll == 12: + return 'Thief' + elif roll == 13: + return 'Mage' + elif roll == 14: + return 'Assassin' + elif roll == 15: + return 'Bard' + elif roll == 16: + return 'Dwarven Vaultguard' + elif roll == 17 or roll == 18: + return 'Dwarven Craftpriest' + +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(): + return [(randint(1, 6) + randint(1, 6) + randint(1, 6)) for x in range(0,6)] + +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 + + +npc_class_data = { + 'Elven Nightblade': { + 'hd': [1, 6], + 'armour': -4, + 'melee': [0, 2, 1], + 'ranged': [0, 0, 1] + }, + + 'Elven Spellsword': { + 'hd': [1, 6], + 'armour': -4, + 'melee': [0, 1, 0], + 'ranged': [0, 0, 1] + }, + + 'Explorer': { + 'hd': [1, 6], + 'armour': -3, + 'melee': [0, 1, 1], + 'ranged': [0, 1, 2] + }, + + 'Bladedancer': { + 'hd': [1, 6], + 'armour': -2, + 'melee': [0, 1, 0], + 'ranged': [0, 0, 1] + }, + + 'Cleric': { + 'hd': [1, 6], + 'armour': 0, + 'melee': [1, 3, 1], + 'ranged': [1, 3, 4] + }, + + 'Fighter': { + 'hd': [1, 8], + 'armour': 1, + 'melee': [1, 4, 1], + 'ranged': [1, 1, 4], + }, + + 'Thief': { + 'hd': [1, 4], + 'armour': -6, + 'melee': [0, 1, 1], + 'ranged': [1, 0, 6] + }, + + 'Mage': { + 'hd': [1, 4], + 'armour': -8, + 'melee': [0, 0, 1], + 'ranged': [0, 0, 1] + }, + + 'Assassin': { + 'hd': [1, 6], + 'armour': -6, + 'melee': [0, 2, 1], + 'ranged': [1, 0, 5] + }, + + 'Bard': { + 'hd': [1, 6], + 'armour': -3, + 'melee': [0, 2, 1], + 'ranged': [1, 0, 4] + }, + + 'Dwarven Vaultguard': { + 'hd': [1, 8], + 'armour': -1, + 'melee': [1, 3, 0], + 'ranged': [1, 1, 6] + }, + + 'Dwarven Craftpriest': { + 'hd': [1, 6], + 'armour': -2, + 'melee': [0, 1, 0], + 'ranged': [1, 0, 5] + } +} + +npc_armour_list = [ + ['Clothing Only', 0, 0], + ['Hide and Fur Armour', 10, 1], + ['Leather Armour', 20, 2], + ['Ring Mail Armour', 30, 3], + ['Scale Mail Armour', 30, 3], + ['Chain Mail Armour', 40, 4], + ['Banded Plate', 50, 5], + ['Lamellar Armour', 50, 5], + ['Plate Armour', 60, 6], +] + +npc_melee_weapons_data = { + 'light': [ + ['Club', 1, '1d4'], + ['Dagger', 3, '1d4'], + ['Sap', 1, '1d4'], + ['Staff (1h)', 1, '1d4'], + ['Staff (2h)', 1, '1d6'], + ['Whip', 5, '1d2'] + ], + 'medium': [ + ['Battle Axe (1h)', 7, '1d6'], + ['Battle Axe (2h)', 7, '1d8'], + ['Hand Axe', 4, '1d6'], + ['Flail (1h)', 5, '1d6'], + ['Flail (2h)', 5, '1d8'], + ['Mace (1h)', 5, '1d6'], + ['Mace (2h)', 5, '1d8'], + ['War Hammer (1h)', 5, '1d6'], + ['War Hammer (2h)', 5, '1d8'], + ['Spear (1h)', 3, '1d6'], + ['Spear (2h)', 3, '1d8'], + ['Short Sword', 7, '1d6'], + ['Sword (1h)', 10, '1d6'], + ['Sword (2h)', 10, '1d8'] + ], + 'heavy': [ + ['Great Axe (2h)', 10, '1d10'], + ['Morning Star (2h)', 10, '1d10'], + ['Pole Arm (2h)', 7, '1d10'], + ['Two-Handed Sword (2h)', 15, '1d10'] + ] +} + +npc_ranged_weapons_data = { + 'light': [ + ['Crossbow', 30, '1d6'], + ['Shortbow', 3, '1d6'], + ['Javelin', 1, '1d6'], + ], + 'heavy': [ + ['Arbalest', 50, '1d8'], + ['Composite Bow', 40, '1d6'], + ['Longbow', 7, '1d6'], + ] +} + +def select_melee_weapon(guild): + melee = npc_class_data[guild]['melee'] + weapons = [] + for x in range(0, melee[0]): + weapons.extend(npc_melee_weapons_data['heavy']) + for x in range(0, melee[1]): + weapons.extend(npc_melee_weapons_data['medium']) + for x in range(0, melee[2]): + weapons.extend(npc_melee_weapons_data['light']) + + selection = randint(0, len(weapons) - 1) + return weapons[selection] + +def select_ranged_weapon(guild): + ranged = npc_class_data[guild]['ranged'] + weapons = [] + for x in range(0, ranged[0]): + weapons.extend(npc_ranged_weapons_data['light']) + for x in range(0, ranged[1]): + weapons.extend(npc_ranged_weapons_data['heavy']) + for x in range(0, ranged[2]): + weapons.append(None) + + selection = randint(0, len(weapons) - 1) + return weapons[selection] + +def generate_npc(base_level): + attributes = npc_abilities() + + npc = {} + npc['guild'] = npc_class() + npc['level'] = npc_baselevel(base_level) + npc['str'] = attributes[0] + npc['int'] = attributes[1] + npc['wis'] = attributes[2] + npc['dex'] = attributes[3] + npc['con'] = attributes[4] + npc['chr'] = attributes[5] + + npc['hp'] = 0 + conmod = attribute_mod(npc['con']) + for x in range(0, npc['level']): + hitdice = [randint(1, npc_class_data[npc['guild']]['hd'][1]) for x in range(0, npc_class_data[npc['guild']]['hd'][0])] + for die in hitdice: + die += conmod + if die < 1: + die = 1 + npc['hp'] += die + + armourval = randint(0, len(npc_armour_list) - 1) + npc_class_data[npc['guild']]['armour'] + if armourval < 0: + armourval = 0 + if armourval > len(npc_armour_list) - 1: + armourval = len(npc_armour_list) - 1 + npc['armour'] = npc_armour_list[armourval] + npc['melee'] = select_melee_weapon(npc['guild']) + npc['ranged'] = select_ranged_weapon(npc['guild']) + + return npc + +def create_party(base_level): + party_size = number_encountered() + return [generate_npc(base_level) for x in range(0, party_size)] + +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'][2], npc['armour'][0], npc['armour'][1])) + print('{:^16} - {:^10} - {:^10} - {:^10}'.format('Weapon', 'Gold', 'Throw Mod', 'Damage')) + print('-------------------------------------------------------') + print('{:^16} | {:^10} | {:^10} | {:^10}'.format(npc['melee'][0], npc['melee'][1], 0, npc['melee'][2])) + if npc['ranged']: + print('{:^16} | {:^10} | {:^10} | {:^10}'.format(npc['ranged'][0], npc['ranged'][1], 0, npc['ranged'][2])) + print('\n') + + for npc in party: + print_npc(npc) + + +if __name__ == '__main__': + party = create_party(2) + print_party(party) diff --git a/acks/npc/templates/generate_npc_party.html b/acks/npc/templates/generate_npc_party.html new file mode 100644 index 0000000..fea902c --- /dev/null +++ b/acks/npc/templates/generate_npc_party.html @@ -0,0 +1,122 @@ +{% extends "base.html" %} +{% block title %}NPC Party Generation{% endblock %} +{% block content %} +
+ + +
+
+ +
+ +
+ +{% if party %} +

NPC Party of Size {{ party | length }}

+ +
+ {% for npc in party %} +
+
+

{{ npc.guild }}

+
Level {{ npc.level }}
+
+
+
{{ npc.hp }}
+
HP
+
+
+
{{ npc.armour[2] }}
+
AC
+
+
+
+
+
{{ npc.str }}
+
Str
+
+
+
{{ npc.int }}
+
Int
+
+
+
{{ npc.wis }}
+
Wis
+
+
+
{{ npc.dex }}
+
Dex
+
+
+
{{ npc.con }}
+
Con
+
+
+
{{ npc.chr }}
+
Chr
+
+
+ + + + + + + + + + + + {% if npc.ranged %} + + + + + + + {% endif %} + + + + + + + +
NameWorthThrDmg
{{ npc.melee[0] }}{{ npc.melee[1] }}gp0{{ npc.melee[2] }}
{{ npc.ranged[0] }}{{ npc.ranged[1] }}gp0{{ npc.ranged[2] }}
{{ npc.armour[0] }}{{ npc.armour[1] }}gp
+
+
+ {% endfor %} +
+{% endif %} + +
+ + + +{% endblock %} diff --git a/acks/npc/views.py b/acks/npc/views.py new file mode 100644 index 0000000..729efa7 --- /dev/null +++ b/acks/npc/views.py @@ -0,0 +1,19 @@ +from flask import current_app, Blueprint, render_template + +from .npc_party import create_party + + +npc_views = Blueprint( + 'npc_views', + __name__, + template_folder='templates', + url_prefix='/npc' +) + +@npc_views.route('/party') +@npc_views.route('/party/') +def generate_npc_party(base_level=None): + party = None + if base_level: + party = create_party(base_level) + return render_template('generate_npc_party.html', party=party) diff --git a/acks/templates/base.html b/acks/templates/base.html new file mode 100644 index 0000000..52841f6 --- /dev/null +++ b/acks/templates/base.html @@ -0,0 +1,29 @@ + + + + {% block title %}{% endblock %} - Atr0phy ACKS + + + + + {% block head %} {% endblock %} + + + +
+ {% block content %}{% endblock %} +
+ + diff --git a/acks/templates/handbook.html b/acks/templates/handbook.html new file mode 100644 index 0000000..d912fff --- /dev/null +++ b/acks/templates/handbook.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% block title %}ACKS Handbook{% endblock %} +{% block content %} +
+