Brandon Cornejo
4 years ago
11 changed files with 350 additions and 3 deletions
-
3acks/__init__.py
-
61acks/quest/commands.py
-
85acks/quest/quest_manager.py
-
86acks/quest/templates/quest_detail.html
-
39acks/quest/templates/quest_list.html
-
71acks/quest/views.py
-
BINacks/static/PalismaContinent.png
-
1acks/templates/base.html
-
2acks/templates/handbook.html
-
3acks/templates/index.html
-
2acks/templates/treasure.html
@ -0,0 +1,61 @@ |
|||||
|
import click |
||||
|
from flask.cli import AppGroup |
||||
|
|
||||
|
from ..models import db |
||||
|
|
||||
|
|
||||
|
npc_cli = AppGroup('npc') |
||||
|
|
||||
|
@npc_cli.command('populate') |
||||
|
def populate_npc_database(): |
||||
|
import csv |
||||
|
from .models import ( |
||||
|
CharacterClass, |
||||
|
ClassLevelProgression, |
||||
|
EquipmentArmour, |
||||
|
EquipmentRangedWeapon, |
||||
|
EquipmentMeleeWeapon, |
||||
|
Spell |
||||
|
) |
||||
|
|
||||
|
def load_csv_data(file_name, cls): |
||||
|
rows = [] |
||||
|
with open('acks/npc/data/{}'.format(file_name), newline='') as data: |
||||
|
reader = csv.DictReader(data) |
||||
|
for row in reader: |
||||
|
rows.append(cls(**row)) |
||||
|
return rows |
||||
|
|
||||
|
# Character Classes |
||||
|
db.session.bulk_save_objects(load_csv_data('default_classes.csv', CharacterClass)) |
||||
|
|
||||
|
# Equipment Armour |
||||
|
db.session.bulk_save_objects(load_csv_data('default_armours.csv', EquipmentArmour)) |
||||
|
|
||||
|
# Ranged Weapons |
||||
|
db.session.bulk_save_objects(load_csv_data('default_ranged.csv', EquipmentRangedWeapon)) |
||||
|
|
||||
|
# Melee Weapons |
||||
|
melee_weps = load_csv_data('default_melee.csv', EquipmentMeleeWeapon) |
||||
|
for wep in melee_weps: |
||||
|
wep.two_handed = (wep.two_handed == 'True') |
||||
|
db.session.bulk_save_objects(melee_weps) |
||||
|
|
||||
|
# Level Progressions |
||||
|
progressions = load_csv_data('default_progression.csv', ClassLevelProgression) |
||||
|
classes = {c.name: c.id for c in CharacterClass.query.all()} |
||||
|
for prog in progressions: |
||||
|
prog.guild_id = classes[prog.guild_id] |
||||
|
db.session.bulk_save_objects(progressions) |
||||
|
|
||||
|
# Spells |
||||
|
spells = load_csv_data('default_spells.csv', Spell) |
||||
|
for spell in spells: |
||||
|
if spell.arcane == '': |
||||
|
spell.arcane = 0 |
||||
|
if spell.divine == '': |
||||
|
spell.divine = 0 |
||||
|
spell.description = spell.description.strip() |
||||
|
db.session.bulk_save_objects(spells) |
||||
|
|
||||
|
db.session.commit() |
@ -0,0 +1,85 @@ |
|||||
|
from io import BytesIO |
||||
|
from pathlib import Path |
||||
|
from zipfile import ZipFile |
||||
|
|
||||
|
FS_ROOT = '/srv/www/atr0phy.net/acks/quests' |
||||
|
URL_ROOT = 'https://atr0phy.net/acks/quests' |
||||
|
IMG_EXTENSIONS = ('png', 'jpg', 'jpeg') |
||||
|
|
||||
|
def load_quests(): |
||||
|
quest_list = {} |
||||
|
|
||||
|
fs = Path(FS_ROOT) |
||||
|
for e in fs.iterdir(): |
||||
|
if not e.is_dir(): |
||||
|
continue |
||||
|
|
||||
|
# Each directory correlates to a level group |
||||
|
quest_level_url_name = e.name.replace('Level', '').replace('-', '').replace(' ', '') |
||||
|
|
||||
|
# Gather quests under each level |
||||
|
quest_list[quest_level_url_name] = load_quest_level_directory(e) |
||||
|
return quest_list |
||||
|
|
||||
|
def load_quest_level_directory(qdir): |
||||
|
this_level = [] |
||||
|
for e in qdir.iterdir(): |
||||
|
if not e.is_dir(): |
||||
|
continue |
||||
|
|
||||
|
# Each directory is a quest for this level |
||||
|
this_level.append(e.name) |
||||
|
return this_level |
||||
|
|
||||
|
def get_quest_details(level, quest_name): |
||||
|
level_range = str(level) |
||||
|
folder_name = "Level {0} - {1}".format(level_range[0], level_range[1]) |
||||
|
|
||||
|
quest_path = "{}/{}/{}".format(FS_ROOT, folder_name, quest_name) |
||||
|
fs = Path(quest_path) |
||||
|
|
||||
|
if not fs.exists() or not fs.is_dir(): |
||||
|
print('EXITING {}'.format(fs)) |
||||
|
return None |
||||
|
|
||||
|
quest = {} |
||||
|
quest['name'] = fs.name |
||||
|
quest['download'] = (level, quest_name) |
||||
|
quest['assets'] = [] |
||||
|
|
||||
|
def urlify(path): |
||||
|
return {'display': path.name, 'url': path.as_posix().replace(FS_ROOT, URL_ROOT)} |
||||
|
|
||||
|
for e in fs.iterdir(): |
||||
|
if e.name.endswith(IMG_EXTENSIONS): |
||||
|
quest['assets'].append(urlify(e)) |
||||
|
elif e.name == 'info.html': |
||||
|
quest['info'] = urlify(e) |
||||
|
elif e.name == 'tsv.txt': |
||||
|
quest['tsv'] = urlify(e) |
||||
|
|
||||
|
print("Quest: {}".format(quest)) |
||||
|
return quest |
||||
|
|
||||
|
def get_quest_archive(level, quest_name): |
||||
|
level_range = str(level) |
||||
|
folder_name = "Level {0} - {1}".format(level_range[0], level_range[1]) |
||||
|
|
||||
|
quest_path = "{}/{}/{}".format(FS_ROOT, folder_name, quest_name) |
||||
|
fs = Path(quest_path) |
||||
|
|
||||
|
if not fs.exists() or not fs.is_dir(): |
||||
|
print('EXITING {}'.format(fs)) |
||||
|
return None |
||||
|
|
||||
|
file_path_list = [] |
||||
|
for e in fs.iterdir(): |
||||
|
file_path_list.append((e.as_posix(), e.name)) |
||||
|
|
||||
|
archive_mem = BytesIO() |
||||
|
with ZipFile(archive_mem, 'w') as archive: |
||||
|
for f in file_path_list: |
||||
|
archive.write(f[0], f[1]) |
||||
|
archive_mem.seek(0) |
||||
|
|
||||
|
return archive_mem |
@ -0,0 +1,86 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% set active_page = "quest_detail" %} |
||||
|
|
||||
|
|
||||
|
{% block title %}ACKS Quest Detail{% endblock %} |
||||
|
{% block content %} |
||||
|
<div class="uk-flex uk-flex-center uk-margin-bottom uk-margin-top"> |
||||
|
<h1 class="uk-text-center"><strong>Adventurer Conqueror King</strong>Quest Detail</h1> |
||||
|
</div> |
||||
|
{% if quest %} |
||||
|
<div class="uk-container uk-container-small"> |
||||
|
<div class="uk-text-center uk-margin-large"> |
||||
|
<h1 class="uk-heading-xlarge">{{ quest['name'] }}</h1> |
||||
|
</div> |
||||
|
<div class="uk-flex uk-flex-center uk-margin-large-bottom"> |
||||
|
<a href="{{ quest['info']['url'] }}" class="uk-button uk-button-default" target="_blank">Info Window</a> |
||||
|
{% if quest['tsv'] %} |
||||
|
<a href="{{ quest['tsv']['url'] }}" class="uk-button uk-button-default">TSV File</a> |
||||
|
{% endif %} |
||||
|
<a href="{{ url_for('quest_manager.quest_download', level=quest['download'][0], quest_name=quest['download'][1]) }}" class="uk-button uk-button-default" target="_blank">Download</a> |
||||
|
</div> |
||||
|
<ul uk-accordion="multiple: true"> |
||||
|
<li> |
||||
|
<a class="uk-accordion-title" href="#">Information</a> |
||||
|
<div class="uk-accordion-content"> |
||||
|
<h3 class="uk-text-center">Quest Info</h3> |
||||
|
<div id="frame-container"> |
||||
|
<iframe id="quest-frame" src="{{ quest['info']['url'] }}"></iframe> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
<li class="uk-open"> |
||||
|
<a class="uk-accordion-title" href="#">Assets</a> |
||||
|
<div class="uk-accordion-content"> |
||||
|
<h3 class="uk-text-center">Quest Assets</h3> |
||||
|
<div uk-slideshow="animation: push"> |
||||
|
<ul class="uk-slideshow-nav uk-dotnav uk-flex-center uk-margin"></ul> |
||||
|
<div class="uk-position-relative uk-visible-toggle uk-light" tabindex="-1"> |
||||
|
<ul class="uk-slideshow-items" uk-lightbox> |
||||
|
{% for a in quest['assets'] %} |
||||
|
<li> |
||||
|
<a href="{{ a['url'] }}"><img src="{{ a['url'] }}" alt="" width="800" uk-cover></a> |
||||
|
<div class="uk-overlay uk-overlay-primary uk-position-bottom uk-text-center uk-transition-slide-bottom"> |
||||
|
<h3 class="uk-margin-remove">{{ a['display'] }}</h3> |
||||
|
</div> |
||||
|
</li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
</div> |
||||
|
<ul class="uk-slideshow-nav uk-dotnav uk-flex-center uk-margin"></ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block head %} |
||||
|
<style> |
||||
|
#asset-view img { |
||||
|
max-width: 300px; |
||||
|
max-height: 500px; |
||||
|
} |
||||
|
#frame-container { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
height: 85vh; |
||||
|
flex-direction: column: |
||||
|
} |
||||
|
#quest-frame { |
||||
|
flex-grow: 1; |
||||
|
border: none; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
h1 strong { |
||||
|
display: block; |
||||
|
font-size: 50%; |
||||
|
opacity: 0.65; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<script> |
||||
|
</script> |
||||
|
{% endblock %} |
@ -0,0 +1,39 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% set active_page = "quest_list" %} |
||||
|
|
||||
|
|
||||
|
{% block title %}ACKS Quest List{% endblock %} |
||||
|
{% block content %} |
||||
|
<div class="uk-flex uk-flex-center uk-margin-bottom uk-margin-top"> |
||||
|
<h1 class="uk-text-center"><strong>Adventurer Conqueror King</strong>Quest Board (Internal)</h1> |
||||
|
</div> |
||||
|
{% if quest_map %} |
||||
|
<div class="uk-flex uk-flex-bottom uk-flex-center uk-margin-large-bottom"> |
||||
|
<ul class="uk-list"> |
||||
|
{% for level, quests in quest_map.items() | sort(attribute=0) %} |
||||
|
<li> |
||||
|
<strong>Level {{ level[0] }} - {{ level[1] }}</strong> |
||||
|
<ul class="uk-list"> |
||||
|
{% for quest in quests %} |
||||
|
<li><a href="{{ url_for('quest_manager.quest_detail', level=level, quest_name=quest) }}">{{ quest }}</a></li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
</li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block head %} |
||||
|
<style> |
||||
|
h1 strong { |
||||
|
display: block; |
||||
|
font-size: 50%; |
||||
|
opacity: 0.65; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<script> |
||||
|
</script> |
||||
|
{% endblock %} |
@ -0,0 +1,71 @@ |
|||||
|
from flask import ( |
||||
|
request, |
||||
|
jsonify, |
||||
|
current_app, |
||||
|
render_template, |
||||
|
send_file, |
||||
|
Blueprint |
||||
|
) |
||||
|
|
||||
|
from .quest_manager import ( |
||||
|
load_quests, |
||||
|
get_quest_details, |
||||
|
get_quest_archive |
||||
|
) |
||||
|
|
||||
|
|
||||
|
quest_views = Blueprint( |
||||
|
'quest_manager', |
||||
|
__name__, |
||||
|
template_folder='templates', |
||||
|
url_prefix='/quest' |
||||
|
) |
||||
|
|
||||
|
@quest_views.route('/list') |
||||
|
def quest_list(): |
||||
|
quests = load_quests() |
||||
|
return render_template('quest_list.html', quest_map=quests) |
||||
|
|
||||
|
@quest_views.route('/detail/<int:level>/<string:quest_name>') |
||||
|
def quest_detail(level, quest_name): |
||||
|
quest = get_quest_details(level, quest_name) |
||||
|
return render_template('quest_detail.html', quest=quest) |
||||
|
|
||||
|
@quest_views.route('/detail/<int:level>/<string:quest_name>/download') |
||||
|
def quest_download(level, quest_name): |
||||
|
archive = get_quest_archive(level, quest_name) |
||||
|
return send_file(archive, attachment_filename="acks_{0}.zip".format(quest_name), as_attachment=True) |
||||
|
|
||||
|
|
||||
|
''' |
||||
|
@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) |
||||
|
|
||||
|
# If asked for JSON, return the party, otherwise render HTML template |
||||
|
if request.args.get('format', 'html') == 'json': |
||||
|
return jsonify([npc.roll20_format for npc in party]) |
||||
|
return render_template('generate_npc_party.html', party=party, base_level=base_level) |
||||
|
|
||||
|
@npc_views.route('/single') |
||||
|
@npc_views.route('/single/<int:base_level>/<int:guild_id>') |
||||
|
def generate_single_npc(base_level=None, guild_id=0): |
||||
|
guilds = CharacterClass.query.filter(CharacterClass.bucket.notin_(['Demi-Human'])).all() |
||||
|
|
||||
|
npc = None |
||||
|
if base_level: |
||||
|
npc = create_npc(base_level, guild_id) |
||||
|
|
||||
|
# If asked for JSON, return the npc, otherwise render HTML template |
||||
|
if request.args.get('format', 'html') == 'json': |
||||
|
return jsonify(npc) |
||||
|
return render_template('generate_single_npc.html', npc=npc, base_level=base_level, guilds=guilds, guild_id=guild_id) |
||||
|
|
||||
|
@npc_views.route('/spells') |
||||
|
def spell_list(): |
||||
|
spells = Spell.query.all() |
||||
|
return render_template('spell_list.html', spells=spells) |
||||
|
''' |
Before Width: 1385 | Height: 1603 | Size: 3.1 MiB After Width: 2969 | Height: 3436 | Size: 4.4 MiB |
Write
Preview
Loading…
Cancel
Save
Reference in new issue