Brandon Cornejo
5 years ago
commit
acb3621146
16 changed files with 833 additions and 0 deletions
-
15.gitignore
-
26acks/__init__.py
-
13acks/commands.py
-
10acks/models.py
-
184acks/npc/commands.py
-
23acks/npc/models.py
-
309acks/npc/npc_party.py
-
122acks/npc/templates/generate_npc_party.html
-
19acks/npc/views.py
-
29acks/templates/base.html
-
24acks/templates/handbook.html
-
11acks/templates/index.html
-
12acks/views.py
-
18requirements.txt
-
7start.py
-
11uwsgi.ini
@ -0,0 +1,15 @@ |
|||||
|
# Python |
||||
|
*.py[co] |
||||
|
|
||||
|
# Vim |
||||
|
*.swp |
||||
|
|
||||
|
# Virtualenv |
||||
|
bin |
||||
|
data |
||||
|
include |
||||
|
lib |
||||
|
lib64 |
||||
|
__pycache__ |
||||
|
share |
||||
|
pyvenv.cfg |
@ -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 |
@ -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() |
||||
|
|
@ -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) |
@ -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() |
@ -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 '<CharacterClass {0}>'.format(self.name) |
@ -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) |
@ -0,0 +1,122 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block title %}NPC Party Generation{% endblock %} |
||||
|
{% block content %} |
||||
|
<div> |
||||
|
<label for="base_level">Base level of party to generate: </label> |
||||
|
<input type="number" name="base_level" id="base_level" default="1"> |
||||
|
</div> |
||||
|
<div> |
||||
|
<button onclick="generateParty();">Generate</button> |
||||
|
</div> |
||||
|
|
||||
|
<br> |
||||
|
|
||||
|
{% if party %} |
||||
|
<h3>NPC Party of Size {{ party | length }}</h3> |
||||
|
|
||||
|
<div class="uk-grid-medium uk-grid-match" uk-grid> |
||||
|
{% for npc in party %} |
||||
|
<div class="acks-npc-card"> |
||||
|
<div class="uk-card uk-card-body uk-card-default"> |
||||
|
<h4 class="uk-card-title">{{ npc.guild }}</h4> |
||||
|
<div class="uk-card-badge uk-label">Level {{ npc.level }}</div> |
||||
|
<div class="uk-flex uk-flex-around uk-text-center uk-margin-bottom"> |
||||
|
<div> |
||||
|
<div>{{ npc.hp }}</div> |
||||
|
<div>HP</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.armour[2] }}</div> |
||||
|
<div>AC</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="uk-flex uk-flex-around stat-block"> |
||||
|
<div> |
||||
|
<div>{{ npc.str }}</div> |
||||
|
<div>Str</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.int }}</div> |
||||
|
<div>Int</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.wis }}</div> |
||||
|
<div>Wis</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.dex }}</div> |
||||
|
<div>Dex</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.con }}</div> |
||||
|
<div>Con</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div>{{ npc.chr }}</div> |
||||
|
<div>Chr</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<table class="uk-table uk-table-hover uk-table-small item-table"> |
||||
|
<thead> |
||||
|
<tr> <th>Name</th><th>Worth</th><th>Thr</th><th>Dmg</th> </tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr> |
||||
|
<td>{{ npc.melee[0] }}</td> |
||||
|
<td>{{ npc.melee[1] }}gp</td> |
||||
|
<td>0</td> |
||||
|
<td>{{ npc.melee[2] }}</td> |
||||
|
</tr> |
||||
|
{% if npc.ranged %} |
||||
|
<tr> |
||||
|
<td>{{ npc.ranged[0] }}</td> |
||||
|
<td>{{ npc.ranged[1] }}gp</td> |
||||
|
<td>0</td> |
||||
|
<td>{{ npc.ranged[2] }}</td> |
||||
|
</tr> |
||||
|
{% endif %} |
||||
|
<tr> |
||||
|
<td>{{ npc.armour[0] }}</td> |
||||
|
<td>{{ npc.armour[1] }}gp</td> |
||||
|
<td></td> |
||||
|
<td></td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
<br> |
||||
|
|
||||
|
<style> |
||||
|
table.item-table, table.item-table th { |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
div.stat-block > div { |
||||
|
text-align: center; |
||||
|
padding: 3px; |
||||
|
width: 26px; |
||||
|
} |
||||
|
div.stat-block > div > div:first-child { |
||||
|
font-weight: bold; |
||||
|
color: green; |
||||
|
} |
||||
|
div.stat-block > div > div:last-child { |
||||
|
font-weight: bold; |
||||
|
font-size: 12px; |
||||
|
color: #888; |
||||
|
} |
||||
|
div.acks-npc-card { |
||||
|
width: 370px; |
||||
|
} |
||||
|
</style> |
||||
|
<script type="text/javascript"> |
||||
|
function generateParty() { |
||||
|
let bl = document.querySelector('#base_level').value; |
||||
|
window.location = "/npcparty/" + bl.toString(); |
||||
|
} |
||||
|
</script> |
||||
|
{% endblock %} |
@ -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/<int:base_level>') |
||||
|
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) |
@ -0,0 +1,29 @@ |
|||||
|
<!doctype html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>{% block title %}{% endblock %} - Atr0phy ACKS</title> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" contents="width=device-width, initial-scale=1"> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/css/uikit.min.css" integrity="sha256-5YtK9j+Nl/245lAkSjrIs600d6edKTevi+3JYdjuHhY=" crossorigin="anonymous" /> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js" integrity="sha256-rhLALrRmAQVu/OxzVDpQaiHAEMxiRSN8h8RDydUEh2g=" crossorigin="anonymous"></script> |
||||
|
{% block head %} {% endblock %} |
||||
|
</head> |
||||
|
<body> |
||||
|
<nav class="uk-navbar-container" uk-navbar> |
||||
|
<div class="uk-navbar-left"> |
||||
|
<a href="" class="uk-navbar-item uk-logo">Atr0phy ACKS</a> |
||||
|
</div> |
||||
|
<div class="uk-navbar-center"> |
||||
|
<ul class="uk-navbar-nav"> |
||||
|
<li><a href="/handbook">Handbook</a></li> |
||||
|
<li class="uk-active"><a href="/npc/party">NPC Party</a></li> |
||||
|
<li><a href="">Treasure</a></li> |
||||
|
<li><a href="">Henchmen</a></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</nav> |
||||
|
<div class="uk-container"> |
||||
|
{% block content %}{% endblock %} |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,24 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block title %}ACKS Handbook{% endblock %} |
||||
|
{% block content %} |
||||
|
<div id="frame-container"> |
||||
|
<iframe id="handbook-frame" src="https://atr0phy.net/acks/handbook"/> |
||||
|
</div> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block head %} |
||||
|
<style> |
||||
|
#frame-container { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
height: 85vh; |
||||
|
flex-direction: column: |
||||
|
} |
||||
|
#handbook-frame { |
||||
|
flex-grow: 1; |
||||
|
border: none; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
</style> |
||||
|
{% endblock %} |
@ -0,0 +1,11 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block title %}ACKS Toolset Home{% endblock %} |
||||
|
{% block content %} |
||||
|
<div> |
||||
|
</div> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block head %} |
||||
|
<style> |
||||
|
</style> |
||||
|
{% endblock %} |
@ -0,0 +1,12 @@ |
|||||
|
from flask import current_app, Blueprint, render_template |
||||
|
|
||||
|
|
||||
|
default_views = Blueprint('default_views', __name__, url_prefix='/') |
||||
|
|
||||
|
@default_views.route('/') |
||||
|
def index(): |
||||
|
return render_template('index.html') |
||||
|
|
||||
|
@default_views.route('/handbook') |
||||
|
def handbook(): |
||||
|
return render_template('handbook.html') |
@ -0,0 +1,18 @@ |
|||||
|
ansi2html==1.5.2 |
||||
|
cryptography==1.7.1 |
||||
|
culour==0.1 |
||||
|
enum34==1.1.6 |
||||
|
idna==2.2 |
||||
|
ipaddress==1.0.17 |
||||
|
keyring==10.1 |
||||
|
keyrings.alt==1.3 |
||||
|
pudb==2018.1 |
||||
|
pyasn1==0.1.9 |
||||
|
pycrypto==2.6.1 |
||||
|
Pygments==2.3.1 |
||||
|
pygobject==3.22.0 |
||||
|
pyxdg==0.25 |
||||
|
SecretStorage==2.3.1 |
||||
|
six==1.12.0 |
||||
|
urwid==2.0.1 |
||||
|
virtualenv==16.6.1 |
@ -0,0 +1,7 @@ |
|||||
|
from acks import create_app |
||||
|
|
||||
|
|
||||
|
app = create_app() |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
app.run() |
@ -0,0 +1,11 @@ |
|||||
|
[uwsgi] |
||||
|
module = wsgi:application |
||||
|
|
||||
|
master = true |
||||
|
processes = 4 |
||||
|
|
||||
|
socket = ackstools.sock |
||||
|
chmod-scoket = 660 |
||||
|
vacuum = true |
||||
|
|
||||
|
die-on-term = true |
Write
Preview
Loading…
Cancel
Save
Reference in new issue