diff --git a/acks/npc/models.py b/acks/npc/models.py
index f059170..5114706 100644
--- a/acks/npc/models.py
+++ b/acks/npc/models.py
@@ -111,6 +111,10 @@ class Spell(BaseModel):
def is_arcane(self):
return bool(self.arcane and self.arcane > 0)
+ @property
+ def dom_id(self):
+ return self.name.lower().replace("*", "").replace("'", "").replace(",", "").replace(" ", "_")
+
@property
def roll20_format(self):
spell_dict = {
diff --git a/acks/npc/npc_party.py b/acks/npc/npc_party.py
index 8367747..c805c9d 100644
--- a/acks/npc/npc_party.py
+++ b/acks/npc/npc_party.py
@@ -127,18 +127,20 @@ def calc_armour(armour_mod, armours):
armourval = len(armours) - 1
return armours[armourval]
-def generate_npc(base_level, data):
+def generate_npc(base_level, data, guild_id=False):
npc = CharacterNPC()
- npc.guild = npc_class(['Demi-Human'])
+ if not guild_id:
+ npc.guild = npc_class(['Demi-Human'])
+ else:
+ npc.guild = CharacterClass.query.filter_by(id=guild_id).first()
+
npc.level = npc_baselevel(base_level)
if npc.level > npc.guild.maximum_level:
npc.level = npc.guild.maximum_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'])
@@ -194,7 +196,7 @@ def name_party(party):
return party
-def create_party(base_level):
+def load_db_data():
data = {
'armours': EquipmentArmour.query.all(),
'ranged': {
@@ -224,6 +226,16 @@ def create_party(base_level):
spells.extend(data['spells']['divine'][spell.divine])
data['spells']['divine'][spell.divine] = spells
+ return data
+
+def create_npc(base_level, guild_id):
+ data = load_db_data()
+ if guild_id:
+ return name_party([generate_npc(base_level, data, guild_id=guild_id)])[0]
+ return name_party([generate_npc(base_level, data)])[0]
+
+def create_party(base_level):
+ data = load_db_data()
return name_party([generate_npc(base_level, data) for x in range(0, number_encountered())])
def print_party(party):
diff --git a/acks/npc/templates/generate_single_npc.html b/acks/npc/templates/generate_single_npc.html
new file mode 100644
index 0000000..210d8e8
--- /dev/null
+++ b/acks/npc/templates/generate_single_npc.html
@@ -0,0 +1,350 @@
+{% extends "base.html" %}
+{% set active_page = "npcsingle" %}
+
+{% block title %}Single NPC Generation{% endblock %}
+{% block content %}
+
+
Adventurer Conqueror King NPC Generator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% if npc %}
+
+
+
+
+
{{ npc.name }}
+
{{ npc.guild.name }}
+
+
+
Level
+
{{ npc.level }}
+
+
+
+
AC
+
{{ npc.armour.ac_mod }}
+
+
+
+
+
+
+
{{ npc.save_pp }}
+
P & P
+
+
+
{{ npc.save_pd }}
+
P & D
+
+
+
{{ npc.save_bb }}
+
B & B
+
+
+
{{ npc.save_sw }}
+
S & W
+
+
+
{{ npc.save_sp }}
+
Spells
+
+
+
+
+ -
+
+
+ Name | Worth | Thr | Dmg |
+
+
+
+ {{ npc.melee.name }} |
+ {{ npc.melee.gp_value }}gp |
+ {{ npc.attack_throw }} |
+ {{ npc.melee.damage_die }} |
+
+ {% if npc.ranged %}
+
+ {{ npc.ranged.name }} |
+ {{ npc.ranged.gp_value }}gp |
+ {{ npc.attack_throw }} |
+ {{ npc.ranged.damage_die }} |
+
+ {% endif %}
+
+ {{ npc.armour.name }} |
+ {{ npc.armour.gp_value }}gp |
+ |
+ |
+
+
+
+
+ -
+
+
+ Name | Range | Duration | Level |
+
+
+ {% for level in npc.spell_list() %}
+ {% for spell in npc.spell_list()[level] %}
+
+ {{ spell.name }} |
+ {{ spell.range }} |
+ {{ spell.duration }} |
+ {{ spell.level_for(npc) }} |
+
+ {% endfor %}
+ {% endfor %}
+
+
+
+
+
+
+
+{% endif %}
+
+
+
+
+
+
+
+ - Range: {Spell Range}
+ - Duration: {Spell Duration}
+ - {Spell School}
+
+
{Spell Description}
+
+
+
+
+
+
+
+
+
+
+
Characters to Export:
+
+ {% if npc %}
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/acks/npc/templates/spell_list.html b/acks/npc/templates/spell_list.html
index 249a3a2..d5728b5 100644
--- a/acks/npc/templates/spell_list.html
+++ b/acks/npc/templates/spell_list.html
@@ -6,13 +6,29 @@
Adventurer Conqueror King Spell List
+
@@ -21,7 +37,7 @@
{% if spells %}
{% for spell in spells %}
-
+
{% endif %}
+
+{% endblock %}
diff --git a/acks/views.py b/acks/views.py
index e3efbc4..2f8eb57 100644
--- a/acks/views.py
+++ b/acks/views.py
@@ -11,3 +11,7 @@ def index():
@default_views.route('/handbook')
def handbook():
return render_template('handbook.html')
+
+@default_views.route('/worldmap')
+def worldmap():
+ return render_template('worldmap.html')
diff --git a/roll20/hit_dice.js b/roll20/hit_dice.js
new file mode 100644
index 0000000..0777769
--- /dev/null
+++ b/roll20/hit_dice.js
@@ -0,0 +1,117 @@
+var HitDice = HitDice || (function() {
+ 'use strict';
+
+ var tokenIds = [],
+ configure = function() {
+ if(!state.HitDice) {
+ state.HitDice = {
+ version: 0.1,
+ config: {
+ bar: 3,
+ hitDiceAttribute: 'npc_hitdice',
+ }
+ };
+ }
+ },
+ handleInput = function(msg) {
+ if (msg.type === "api" && /^!mhd(\b|$)/i.test(msg.content) && playerIsGM(msg.playerid) ) {
+ let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
+ let count = 0;
+ // WUSSALLTHISTHEN
+ (msg.selected || [])
+ .map(o=>getObj('graphic',o._id))
+ .filter(g=>undefined !== g)
+ .forEach( o => {
+ ++count;
+ tokenIds.push(o.id);
+ rollHitDice(o);
+ })
+ ;
+ sendChat('',`/w "${who}" Rolling hit dice for ${count} token(s).`);
+ }
+ },
+ findRoll = function(txt){
+ return txt.match(/\d+d\d+(\+\d+)?/)[0] || 0;
+ },
+
+ rollHitDice = function(obj) {
+ var sets = {},
+ bar = 'bar'+state.HitDice.config.bar,
+ hdAttrib,
+ hdExpression = 0,
+ bonus = 0
+ ;
+
+ if(_.contains(tokenIds,obj.id)){
+ tokenIds=_.without(tokenIds,obj.id);
+
+ if('graphic' === obj.get('type') &&
+ 'token' === obj.get('subtype') &&
+ '' !== obj.get('represents')
+ ) {
+ if( obj && '' === obj.get(bar+'_link') ) {
+ hdAttrib = findObjs({
+ type: 'attribute',
+ characterid: obj.get('represents'),
+ name: state.HitDice.config.hitDiceAttribute
+ })[0];
+
+ if( hdAttrib ) {
+ //sendChat('', 'HERE WE ARE');
+ //log(hdAttrib);
+
+ hdExpression = findRoll(hdAttrib.get('current'));
+ sendChat('','/r '+hdExpression+'+'+bonus,function(r){
+ var hp=0;
+ _.each(r,function(subr){
+ var val=JSON.parse(subr.content);
+ if(_.has(val,'total'))
+ {
+ hp+=val.total;
+ }
+ });
+ sets[bar+"_value"] = hp||1;
+ sets[bar+"_max"] = hp||1;
+ obj.set(sets);
+ });
+ }
+ }
+ }
+ }
+ },
+
+ saveTokenId = function(obj){
+ tokenIds.push(obj.id);
+
+ setTimeout((function(id){
+ return function(){
+ var token=getObj('graphic',id);
+ if(token){
+ rollHitDice(token);
+ }
+ };
+ }(obj.id)),100);
+ },
+
+
+ registerEventHandlers = function() {
+ on('chat:message', handleInput);
+ on('add:graphic', saveTokenId);
+ on('change:graphic', rollHitDice);
+ };
+
+ return {
+ configure: configure,
+ RegisterEventHandlers: registerEventHandlers
+ };
+
+}());
+
+on('ready',function() {
+ 'use strict';
+
+ HitDice.configure();
+ HitDice.RegisterEventHandlers();
+});
+
+