|
|
{% extends "base.html" %} {% set active_page = "npcparty" %}
{% block title %}NPC Party Generation{% endblock %} {% block content %} <div class="uk-flex uk-flex-center uk-margin-bottom uk-margin-top"> <h1 class="uk-text-center"><strong>Legends of Palisma</strong>NPC Party Generator</h1> </div> <div class="uk-flex uk-flex-bottom uk-flex-center uk-margin-large-bottom"> <div> <label for="base_level">Base level of party to generate: </label> <input type="number" name="base_level" id="base_level" class="uk-input" value="{{ base_level if base_level else 1 }}" min="0" max="14"> </div> <div class="uk-margin-left"> <button class="uk-button uk-button-primary" onclick="generateParty();">Generate</button> </div> </div>
<hr class="uk-divider-icon">
{% if party %} <div class="uk-flex uk-flex-between uk-margin-large-top"> <h3 class="uk-display-inline-block">NPC Party of Size {{ party | length }} </h3> <div class="uk-text-right uk-display-inline-block"> <a class="uk-button uk-button-small uk-button-secondary uk-border-rounded" onclick="showExportModal();">Roll20 Export</a> </div> </div>
<div class="uk-grid-medium uk-grid-match uk-flex-center" uk-grid> {% for npc in party %} <div class="acks-npc-card"> <div class="uk-card uk-card-body uk-card-default uk-box-shadow-hover-large"> <h4 class="uk-card-title uk-margin-small-top">{{ npc.name }}</h4> <div class="uk-card-badge uk-label uk-label-primary">{{ npc.guild.name }}</div> <div class="uk-flex uk-flex-around uk-text-center uk-margin-bottom"> <div> <div class="uk-text-bold">Level</div> <div>{{ npc.level }}</div> </div> <div> <div class="uk-text-bold">HP</div> <div>{{ npc.hp }}</div> </div> <div> <div class="uk-text-bold">AC</div> <div>{{ npc.armour.ac_mod }}</div> </div> </div> <div class="uk-flex uk-flex-around stat-block"> <div> <div title="{{ npc.str_mod }}">{{ npc.str }}</div> <div title="{{ npc.str_mod }}">Str</div> </div> <div> <div title="{{ npc.int_mod }}">{{ npc.int }}</div> <div title="{{ npc.int_mod }}">Int</div> </div> <div> <div title="{{ npc.wis_mod }}">{{ npc.wis }}</div> <div title="{{ npc.wis_mod }}">Wis</div> </div> <div> <div title="{{ npc.dex_mod }}">{{ npc.dex }}</div> <div title="{{ npc.dex_mod }}">Dex</div> </div> <div> <div title="{{ npc.con_mod }}">{{ npc.con }}</div> <div title="{{ npc.con_mod }}">Con</div> </div> <div> <div title="{{ npc.chr_mod }}">{{ npc.chr }}</div> <div title="{{ npc.chr_mod }}">Chr</div> </div> </div> <hr class="uk-divider-small uk-text-center"> <div class="uk-flex uk-flex-around uk-text-center uk-margin-bottom save-block uk-margin-top"> <div> <div title="Petrification & Paralysis">{{ npc.save_pp }}</div> <div title="Petrification & Paralysis">P & P</div> </div> <div> <div title="Poison & Death">{{ npc.save_pd }}</div> <div title="Poison & Death">P & D</div> </div> <div> <div title="Blast & Breath">{{ npc.save_bb }}</div> <div title="Blast & Breath">B & B</div> </div> <div> <div title="Staffs & Wands">{{ npc.save_sw }}</div> <div title="Staffs & Wands">S & W</div> </div> <div> <div title="Spells">{{ npc.save_sp }}</div> <div title="Spells">Spells</div> </div> </div> <ul uk-tab> <li class="uk-active"><a href="">Equipment</a></li> <li {% if not npc.is_divine_spellcaster and not npc.is_arcane_spellcaster %}class="uk-disabled"{% endif %}><a href="">Spells</a></li> </ul> <ul class="uk-switcher uk-margin"> <li> <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.name }}</td> <td>{{ npc.melee.gp_value }}gp</td> <td>{{ npc.attack_throw }}</td> <td>{{ npc.melee.damage_die }}</td> </tr> {% if npc.ranged %} <tr> <td>{{ npc.ranged.name }}</td> <td>{{ npc.ranged.gp_value }}gp</td> <td>{{ npc.attack_throw }}</td> <td>{{ npc.ranged.damage_die }}</td> </tr> {% endif %} <tr> <td>{{ npc.armour.name }}</td> <td>{{ npc.armour.gp_value }}gp</td> <td></td> <td></td> </tr> </tbody> </table> </li> <li> <table class="uk-table uk-table-hover uk-table-small spell-table"> <thead> <tr> <th>Name</th><th>Range</th><th>Duration</th><th>Level</th> </tr> </thead> <tbody> {% for level in npc.spell_list() %} {% for spell in npc.spell_list()[level] %} <tr> <td data-spell-id="{{ spell.id }}" onclick="showSpellModal();">{{ spell.name }}</td> <td>{{ spell.range }}</td> <td>{{ spell.duration }}</td> <td>{{ spell.level_for(npc) }}</td> </tr> {% endfor %} {% endfor %} </tbody> </table> </li> </ul> </div> </div> {% endfor %} </div> {% else %} <div class="uk-grid-medium uk-grid-match uk-flex-center" uk-grid> </div> {% endif %}
<div id="spell-modal" uk-modal> <div class="uk-modal-dialog uk-margin-auto-vertical"> <button class="uk-modal-close-default" type="button" uk-close></button> <div class="uk-modal-header"> <h2 class="uk-modal-title"><span id="spell-modal-title">{Spell Title}</h2> </div> <div class="uk-modal-body"> <ul> <li>Range: <span id="spell-modal-range">{Spell Range}</span></li> <li>Duration: <span id="spell-modal-duration">{Spell Duration}</span></li> <li><span id="spell-modal-school">{Spell School}</span></li> </ul> <p id="spell-modal-desc">{Spell Description}</p> </div> </div> </div>
<div id="party-export-modal" uk-modal> <div class="uk-modal-dialog uk-margin-auto-vertical"> <button class="uk-modal-close-default" type="button" uk-close></button> <div class="uk-modal-header"> <h2 class="uk-modal-title">Roll20 Export</h2> </div> <div class="uk-modal-body"> <div class="uk-margin"> <h5>Characters to Export:</h5> <div id="pe_selects" class="uk-grid-small uk-grid uk-child-width-auto"> {% if party %} {% for npc in party %} <label><input class="uk-checkbox" type="checkbox" name="ch{{ loop.index }}" onchange="prepareSelectiveExport();" checked> {{ npc.name }}</label> {% endfor %} {% endif %} </div> <div class="uk-margin uk-align-right"> <div class="uk-button-group"> <button id="pe_none" class="uk-button uk-button-small uk-button-default" onclick="partyExportToggle();">None</button> <button id="pe_all" class="uk-button uk-button-small uk-button-secondary" onclick="partyExportToggle();">All</button> </div> </div> </div> <textarea id="party-export-show" class="uk-textarea uk-text-small" rows="10"></textarea> <textarea id="party-export-data" class="uk-textarea uk-hidden"></textarea> </div> <div class="uk-modal-footer uk-text-right"> <button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button> <button class="uk-button uk-button-primary" type="button" onclick="exportParty();">Copy</button> </div> </div> </div>
<br>
<style> table.item-table, table.item-table th, table.spell-table, table.spell-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.save-block > div > div:first-child { font-weight: bold; color: purple; } div.save-block > div > div:last-child { font-weight: bold; font-size: 12px; color: #888; } div.acks-npc-card { width: 400px; } h1 strong { display: block; font-size: 50%; opacity: 0.65; } </style> <script type="text/javascript"> var party = [];
function generateParty() { let bl = document.querySelector('#base_level').value; if(bl < 0) { bl = 0; } if(bl > 14) { bl = 14; } window.location = "/npc/party/" + bl.toString(); }
function showSpellModal() { spells = new Set(); {% if party %} {% for npc in party %} {% for level in npc.spell_list() %} {% for spell in npc.spell_list()[level] %} spells.add({{ spell.roll20_format | tojson }}); {% endfor %} {% endfor %} {% endfor %} {% endif %}
var modal_spell, spell_id = event.target.dataset.spellId; for(var spell of spells) { if(spell.id == spell_id) { modal_spell = spell } }
// Fill in spell details document.querySelector('#spell-modal-title').innerText = modal_spell.name; document.querySelector('#spell-modal-desc').innerText = atob(modal_spell.description);
if(spell.range) { document.querySelector('#spell-modal-range').innerText = modal_spell.range; }
if(spell.duration) { document.querySelector('#spell-modal-duration').innerText = modal_spell.duration; }
var school = ''; if(modal_spell.is_arcane) { school += 'Arcane ' + modal_spell.arcane + ' '; } if(modal_spell.is_divine) { school += 'Divine ' + modal_spell.divine + ' '; } document.querySelector('#spell-modal-school').innerText = school;
UIkit.modal(document.querySelector('#spell-modal')).show(); }
function showExportModal() { {% if party %} {% for npc in party %} party.push(JSON.parse('{{ npc.roll20_format | tojson }}')); {% endfor %} {% endif %}
for(let cb of document.querySelectorAll('#pe_selects > label > input')) { cb.checked = true; }
prepareSelectiveExport(); UIkit.modal(document.querySelector('#party-export-modal')).show(); }
function prepareSelectiveExport() { var selected_party = []; var checkboxes = document.querySelectorAll('#pe_selects > label > input'); for(let [i, cb] of checkboxes.entries()) { if(cb.checked) { selected_party.push(party[i]); } }
document.querySelector('#party-export-data').value = "!acksimport " + JSON.stringify(selected_party); document.querySelector('#party-export-show').value = JSON.stringify(selected_party, undefined, 2); }
function exportParty() { let party_data = document.querySelector('#party-export-data') party_data.classList.remove('uk-hidden');
party_data.select(); document.execCommand("copy");
party_data.classList.add('uk-hidden'); UIkit.modal(document.querySelector('#party-export-modal')).hide(); }
function partyExportToggle() { var checkboxes = document.querySelectorAll('#pe_selects > label > input'); for(let cb of checkboxes) { if(event.target.id === "pe_none") { cb.checked = false; } if(event.target.id === "pe_all") { cb.checked = true; } }
prepareSelectiveExport(); } </script> {% endblock %}
|