Skip to content

Commit 82cbf29

Browse files
committed
Updated MonsterHitDice to v0.3.13
1 parent c6d1b9a commit 82cbf29

File tree

3 files changed

+266
-12
lines changed

3 files changed

+266
-12
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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.13';
12+
API_Meta.MonsterHitDice.version = version;
13+
const lastUpdate = 1748794696;
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( o => {
124+
++count;
125+
tokenIds.push(o.id);
126+
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 = (obj) => {
146+
let sets = {};
147+
const bar = 'bar'+state.MonsterHitDice.config.bar;
148+
let hdAttrib;
149+
let conAttrib;
150+
let hdExpression = 0;
151+
let conExpression = 0;
152+
let bonus = 0;
153+
154+
if(_.contains(tokenIds,obj.id)){
155+
tokenIds=_.without(tokenIds,obj.id);
156+
157+
if( 'graphic' === obj.get('type') &&
158+
'token' === obj.get('subtype') &&
159+
'' !== obj.get('represents')
160+
) {
161+
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];
167+
conAttrib = findObjs({
168+
_type: 'attribute',
169+
_characterid:obj.get('represents'),
170+
name: state.MonsterHitDice.config.conBonusAttribute
171+
})[0];
172+
173+
if( hdAttrib ) {
174+
hdExpression = state.MonsterHitDice.config.findSRDFormula
175+
? findSRDRoll(hdAttrib.get('current'))
176+
: hdAttrib.get('current')
177+
;
178+
179+
hdExpression = state.MonsterHitDice.config.HDis1eD8s
180+
? buildHD1eExpression(hdExpression)
181+
: hdExpression
182+
;
183+
if( state.MonsterHitDice.config.useConBonus && conAttrib ) {
184+
conExpression = state.MonsterHitDice.config.conBonusIsStat
185+
? Math.round((conAttrib.get('current')-10)/2)
186+
: conAttrib.get('current')
187+
;
188+
189+
bonus = conExpression * _.reduce(hdExpression.match(/(\d+)d\d+/g),(m,die) => {
190+
m+=parseInt(die.match(/(\d+)d\d+/)[1],10);
191+
return m;
192+
},0);
193+
}
194+
195+
sendChat('','/r '+hdExpression+'+'+bonus,(r) => {
196+
let hp=0;
197+
_.each(r,(subr) => {
198+
let val=JSON.parse(subr.content);
199+
if(_.has(val,'total'))
200+
{
201+
hp+=val.total;
202+
}
203+
});
204+
sets[bar+"_value"] = Math.max(hp,1);
205+
sets[bar+"_max"] = Math.max(hp,1);
206+
obj.set(sets);
207+
});
208+
}
209+
}
210+
}
211+
}
212+
};
213+
214+
const saveTokenId = (obj) => {
215+
tokenIds.push(obj.id);
216+
217+
setTimeout(((id) => {
218+
return () => {
219+
let token=getObj('graphic',id);
220+
if(token){
221+
rollHitDice(token);
222+
}
223+
};
224+
})(obj.id),100);
225+
};
226+
227+
228+
const registerEventHandlers = () => {
229+
on('chat:message', handleInput);
230+
on('add:graphic', saveTokenId);
231+
on('change:graphic', rollHitDice);
232+
};
233+
234+
235+
on('ready',() => {
236+
checkInstall();
237+
registerEventHandlers();
238+
});
239+
240+
241+
242+
return {
243+
/* public interface */
244+
};
245+
246+
})();
247+
248+
{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: 16 additions & 11 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.12';
11+
const version = '0.3.13';
1212
API_Meta.MonsterHitDice.version = version;
13-
const lastUpdate = 1748112536;
13+
const lastUpdate = 1748794696;
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( async o => {
123+
.forEach( o => {
124124
++count;
125125
tokenIds.push(o.id);
126-
await rollHitDice(o);
126+
rollHitDice(o);
127127
})
128128
;
129129
sendChat('',`/w "${who}" Rolling hit dice for ${count} token(s).`);
@@ -142,9 +142,10 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
142142
return 0;
143143
};
144144

145-
const rollHitDice = async (obj) => {
145+
const rollHitDice = (obj) => {
146146
let sets = {};
147147
const bar = 'bar'+state.MonsterHitDice.config.bar;
148+
let hdAttrib;
148149
let conAttrib;
149150
let hdExpression = 0;
150151
let conExpression = 0;
@@ -158,17 +159,21 @@ const MonsterHitDice = (() => { // eslint-disable-line no-unused-vars
158159
'' !== obj.get('represents')
159160
) {
160161
if( obj && '' === obj.get(bar+'_link') ) {
161-
let hdHitDiceFormula = await getSheetItem(obj.get('represents'), state.MonsterHitDice.config.hitDiceAttribute);
162+
hdAttrib = findObjs({
163+
type: 'attribute',
164+
characterid: obj.get('represents'),
165+
name: state.MonsterHitDice.config.hitDiceAttribute
166+
})[0];
162167
conAttrib = findObjs({
163168
_type: 'attribute',
164169
_characterid:obj.get('represents'),
165170
name: state.MonsterHitDice.config.conBonusAttribute
166171
})[0];
167172

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

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

212217
setTimeout(((id) => {
213-
return async () => {
218+
return () => {
214219
let token=getObj('graphic',id);
215220
if(token){
216-
await rollHitDice(token);
221+
rollHitDice(token);
217222
}
218223
};
219224
})(obj.id),100);

MonsterHitDice/script.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "MonsterHitDice",
33
"script": "MonsterHitDice.js",
4-
"version": "0.3.12",
4+
"version": "0.3.13",
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",
@@ -83,6 +83,7 @@
8383
"previousversions": [
8484
"0.3.10",
8585
"0.3.11",
86+
"0.3.12",
8687
"0.3.3",
8788
"0.3.4",
8889
"0.3.5",

0 commit comments

Comments
 (0)