Skip to content

Commit b2809d2

Browse files
committed
Updated MonsterHitDice to v0.3.12
1 parent b850410 commit b2809d2

File tree

3 files changed

+257
-18
lines changed

3 files changed

+257
-18
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
// Github: https://github.com/shdwjk/Roll20API/blob/master/MonsterHitDice/MonsterHitDice.js
2+
// By: The Aaron, Arcane Scriptomancer
3+
// Contact: https://app.roll20.net/users/104025/the-aaron
4+
var API_Meta = API_Meta||{}; //eslint-disable-line no-var
5+
API_Meta.MonsterHitDice={offset:Number.MAX_SAFE_INTEGER,lineCount:-1};
6+
{try{throw new Error('');}catch(e){API_Meta.MonsterHitDice.offset=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-6);}}
7+
8+
var globalconfig = globalconfig || undefined; //eslint-disable-line no-var
9+
const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
10+
11+
const version = '0.3.12';
12+
API_Meta.MonsterHitDice.version = version;
13+
const lastUpdate = 1748112536;
14+
const schemaVersion = 0.3;
15+
16+
let tokenIds = [];
17+
18+
const checkGlobalConfig = () => {
19+
const s=state.MonsterHitDice;
20+
const g = (globalconfig && globalconfig.monsterhitdice);
21+
if(g && g.lastsaved && g.lastsaved > s.globalconfigCache.lastsaved){
22+
log(' > Updating from Global Config < ['+(new Date(g.lastsaved*1000))+']');
23+
s.config.bar = parseInt(g.Bar.match(/\d+/)[0]);
24+
switch(g.Sheet){
25+
case "DnD 5e - Community Contributed":
26+
s.config.hitDiceAttribute = 'npc_HP_hit_dice';
27+
s.config.findSRDFormula = false;
28+
s.config.HDis1eD8s = false;
29+
s.config.useConBonus = true;
30+
s.config.conBonusAttribute = 'npc_constitution';
31+
s.config.conBonusIsStat = true;
32+
break;
33+
34+
case "DnD 5e - Shaped v2":
35+
s.config.hitDiceAttribute = 'npc_hpformula';
36+
s.config.findSRDFormula = true;
37+
s.config.HDis1eD8s = false;
38+
s.config.useConBonus = false;
39+
s.config.conBonusAttribute = '';
40+
s.config.conBonusIsStat = false;
41+
break;
42+
43+
case "DnD 5e - OGL by roll20":
44+
s.config.hitDiceAttribute = 'npc_hpformula';
45+
s.config.findSRDFormula = false;
46+
s.config.HDis1eD8s = false;
47+
s.config.useConBonus = false;
48+
s.config.conBonusAttribute = '';
49+
s.config.conBonusIsStat = false;
50+
break;
51+
52+
case "Advanced 1st Edition":
53+
s.config.hitDiceAttribute = 'hitdice';
54+
s.config.findSRDFormula = false;
55+
s.config.HDis1eD8s = true;
56+
s.config.useConBonus = false;
57+
s.config.conBonusAttribute = '';
58+
s.config.conBonusIsStat = false;
59+
break;
60+
61+
62+
case "Custom - (Use settings below)":
63+
s.config.hitDiceAttribute = g['HitDice Attribute'];
64+
s.config.findSRDFormula = 'findSRDFormula' === g['SRD Embedded Formula'];
65+
s.config.HDis1eD8s = 'HDis1eD8s' === g['1st Edition HD in Attribute (d8)'];
66+
s.config.useConBonus = 'useSeparateCon' === g['Separate Constitution Modifier'];
67+
s.config.conBonusAttribute = g['Constitution Attribute'];
68+
s.config.conBonusIsStat = 'conIsStat' === g['Constitution is Stat'];
69+
break;
70+
}
71+
state.MonsterHitDice.globalconfigCache=globalconfig.monsterhitdice;
72+
}
73+
};
74+
75+
const checkInstall = () => {
76+
log('-=> MonsterHitDice v'+version+' <=- ['+(new Date(lastUpdate*1000))+']');
77+
78+
if( ! _.has(state,'MonsterHitDice') || state.MonsterHitDice.version !== schemaVersion) {
79+
log(' > Updating Schema to v'+schemaVersion+' <');
80+
switch(state.MonsterHitDice && state.MonsterHitDice.version) {
81+
82+
case 0.1:
83+
delete state.MonsterHitDice.globalConfigCache;
84+
state.MonsterHitDice.globalconfigCache = {lastsaved:0};
85+
86+
/* falls through */
87+
case 0.2:
88+
state.MonsterHitDice.config.findSRDFormula = state.MonsterHitDice.findSRDFormula;
89+
delete state.MonsterHitDice.findSRDFormula;
90+
91+
/* falls through */
92+
case 'UpdateSchemaVersion':
93+
state.MonsterHitDice.version = schemaVersion;
94+
break;
95+
96+
default:
97+
state.MonsterHitDice = {
98+
version: schemaVersion,
99+
globalconfigCache: {lastsaved:0},
100+
config: {
101+
bar: 3,
102+
hitDiceAttribute: 'npc_hpformula',
103+
findSRDFormula: false,
104+
HDis1eD8s: false,
105+
useConBonus: false,
106+
conBonusAttribute: '',
107+
conBonusIsStat: false
108+
}
109+
};
110+
}
111+
}
112+
checkGlobalConfig();
113+
};
114+
115+
const handleInput = (msg) => {
116+
117+
if (msg.type === "api" && /^!mhd(\b|$)/i.test(msg.content) && playerIsGM(msg.playerid) ) {
118+
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
119+
let count = 0;
120+
(msg.selected || [])
121+
.map(o=>getObj('graphic',o._id))
122+
.filter(g=>undefined !== g)
123+
.forEach( async o => {
124+
++count;
125+
tokenIds.push(o.id);
126+
await rollHitDice(o);
127+
})
128+
;
129+
sendChat('',`/w "${who}" Rolling hit dice for ${count} token(s).`);
130+
}
131+
};
132+
133+
const findSRDRoll = (txt) => {
134+
return txt.match(/\d+d\d+(\+\d+)?/)[0]||0;
135+
};
136+
137+
const buildHD1eExpression = (exp) => {
138+
let m = `${exp}`.match(/(\d+)([+-]\d+)?/);
139+
if(m){
140+
return `${m[1]}d8${ m[2] ? m[2] : ''}`;
141+
}
142+
return 0;
143+
};
144+
145+
const rollHitDice = async (obj) => {
146+
let sets = {};
147+
const bar = 'bar'+state.MonsterHitDice.config.bar;
148+
let conAttrib;
149+
let hdExpression = 0;
150+
let conExpression = 0;
151+
let bonus = 0;
152+
153+
if(_.contains(tokenIds,obj.id)){
154+
tokenIds=_.without(tokenIds,obj.id);
155+
156+
if( 'graphic' === obj.get('type') &&
157+
'token' === obj.get('subtype') &&
158+
'' !== obj.get('represents')
159+
) {
160+
if( obj && '' === obj.get(bar+'_link') ) {
161+
let hdHitDiceFormula = await getSheetItem(obj.get('represents'), state.MonsterHitDice.config.hitDiceAttribute);
162+
conAttrib = findObjs({
163+
_type: 'attribute',
164+
_characterid:obj.get('represents'),
165+
name: state.MonsterHitDice.config.conBonusAttribute
166+
})[0];
167+
168+
if( hdHitDiceFormula ) {
169+
hdExpression = state.MonsterHitDice.config.findSRDFormula
170+
? findSRDRoll(hdHitDiceFormula)
171+
: hdHitDiceFormula
172+
;
173+
174+
hdExpression = state.MonsterHitDice.config.HDis1eD8s
175+
? buildHD1eExpression(hdExpression)
176+
: hdExpression
177+
;
178+
if( state.MonsterHitDice.config.useConBonus && conAttrib ) {
179+
conExpression = state.MonsterHitDice.config.conBonusIsStat
180+
? Math.round((conAttrib.get('current')-10)/2)
181+
: conAttrib.get('current')
182+
;
183+
184+
bonus = conExpression * _.reduce(hdExpression.match(/(\d+)d\d+/g),(m,die) => {
185+
m+=parseInt(die.match(/(\d+)d\d+/)[1],10);
186+
return m;
187+
},0);
188+
}
189+
190+
sendChat('','/r '+hdExpression+'+'+bonus,(r) => {
191+
let hp=0;
192+
_.each(r,(subr) => {
193+
let val=JSON.parse(subr.content);
194+
if(_.has(val,'total'))
195+
{
196+
hp+=val.total;
197+
}
198+
});
199+
sets[bar+"_value"] = Math.max(hp,1);
200+
sets[bar+"_max"] = Math.max(hp,1);
201+
obj.set(sets);
202+
});
203+
}
204+
}
205+
}
206+
}
207+
};
208+
209+
const saveTokenId = (obj) => {
210+
tokenIds.push(obj.id);
211+
212+
setTimeout(((id) => {
213+
return async () => {
214+
let token=getObj('graphic',id);
215+
if(token){
216+
await rollHitDice(token);
217+
}
218+
};
219+
})(obj.id),100);
220+
};
221+
222+
223+
const registerEventHandlers = () => {
224+
on('chat:message', handleInput);
225+
on('add:graphic', saveTokenId);
226+
on('change:graphic', rollHitDice);
227+
};
228+
229+
230+
on('ready',() => {
231+
checkInstall();
232+
registerEventHandlers();
233+
});
234+
235+
236+
237+
return {
238+
/* public interface */
239+
};
240+
241+
})();
242+
243+
{try{throw new Error('');}catch(e){API_Meta.MonsterHitDice.lineCount=(parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/,'$1'),10)-API_Meta.MonsterHitDice.offset);}}

MonsterHitDice/MonsterHitDice.js

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ API_Meta.MonsterHitDice={offset:Number.MAX_SAFE_INTEGER,lineCount:-1};
88
var globalconfig = globalconfig || undefined; //eslint-disable-line no-var
99
const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
1010

11-
const version = '0.3.11';
11+
const version = '0.3.12';
1212
API_Meta.MonsterHitDice.version = version;
13-
const lastUpdate = 1680641500;
13+
const lastUpdate = 1748112536;
1414
const schemaVersion = 0.3;
1515

1616
let tokenIds = [];
@@ -120,10 +120,10 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
120120
(msg.selected || [])
121121
.map(o=>getObj('graphic',o._id))
122122
.filter(g=>undefined !== g)
123-
.forEach( o => {
123+
.forEach( async o => {
124124
++count;
125125
tokenIds.push(o.id);
126-
rollHitDice(o);
126+
await rollHitDice(o);
127127
})
128128
;
129129
sendChat('',`/w "${who}" Rolling hit dice for ${count} token(s).`);
@@ -142,10 +142,9 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
142142
return 0;
143143
};
144144

145-
const rollHitDice = (obj) => {
145+
const rollHitDice = async (obj) => {
146146
let sets = {};
147147
const bar = 'bar'+state.MonsterHitDice.config.bar;
148-
let hdAttrib;
149148
let conAttrib;
150149
let hdExpression = 0;
151150
let conExpression = 0;
@@ -159,21 +158,17 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
159158
'' !== obj.get('represents')
160159
) {
161160
if( obj && '' === obj.get(bar+'_link') ) {
162-
hdAttrib = findObjs({
163-
type: 'attribute',
164-
characterid: obj.get('represents'),
165-
name: state.MonsterHitDice.config.hitDiceAttribute
166-
})[0];
161+
let hdHitDiceFormula = await getSheetItem(obj.get('represents'), state.MonsterHitDice.config.hitDiceAttribute);
167162
conAttrib = findObjs({
168163
_type: 'attribute',
169164
_characterid:obj.get('represents'),
170165
name: state.MonsterHitDice.config.conBonusAttribute
171166
})[0];
172167

173-
if( hdAttrib ) {
168+
if( hdHitDiceFormula ) {
174169
hdExpression = state.MonsterHitDice.config.findSRDFormula
175-
? findSRDRoll(hdAttrib.get('current'))
176-
: hdAttrib.get('current')
170+
? findSRDRoll(hdHitDiceFormula)
171+
: hdHitDiceFormula
177172
;
178173

179174
hdExpression = state.MonsterHitDice.config.HDis1eD8s
@@ -215,10 +210,10 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
215210
tokenIds.push(obj.id);
216211

217212
setTimeout(((id) => {
218-
return () => {
213+
return async () => {
219214
let token=getObj('graphic',id);
220215
if(token){
221-
rollHitDice(token);
216+
await rollHitDice(token);
222217
}
223218
};
224219
})(obj.id),100);

MonsterHitDice/script.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "MonsterHitDice",
33
"script": "MonsterHitDice.js",
4-
"version": "0.3.11",
4+
"version": "0.3.12",
55
"description": "Automatically fills in the hit points for a characters dragged onto the table top.\r\rThe default token for the character needs to represent that creature but **should not** have the bar used for hit points linked to an attribute. Use the settings below to configure the script for how you calculate hit points in your game. There are several sheets for which the configurations are built in or you can use the more detailed settings. Details about each setting are included along with it.\r\r## Commands\r\r```\r!mhd\r```\r\rThis will reroll hitpoints for all selected tokens.",
66
"authors": "The Aaron",
77
"roll20userid": "104025",
@@ -82,6 +82,7 @@
8282
"conflicts": [],
8383
"previousversions": [
8484
"0.3.10",
85+
"0.3.11",
8586
"0.3.3",
8687
"0.3.4",
8788
"0.3.5",
@@ -90,4 +91,4 @@
9091
"0.3.8",
9192
"0.3.9"
9293
]
93-
}
94+
}

0 commit comments

Comments
 (0)