Last active
December 14, 2020 22:10
-
-
Save BaldarSilveraxe/30169b095929b7aa12a5 to your computer and use it in GitHub Desktop.
Roll20 SpeechBalloon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var SpeechBalloon = SpeechBalloon || (function(){ | |
'use strict'; | |
var version = 0.1, | |
schemaVersion = 0.4, | |
defaultShowLength = 4, // seconds | |
msPerSec = 1000, // for conversions.. no magic numbers! | |
checkStepRate = 1000, //ms = 1 second | |
checkInterval = false, | |
bustBalloon = function(pageObject) { | |
if(state.SpeechBalloon.bubbleShown) { | |
if (typeof(pageObject) != "undefined") { | |
var page = pageObject.get("_id"), | |
bubbleBorder = state.SpeechBalloon.pageGraphicMap[page].BorderId, | |
bubbleTail = state.SpeechBalloon.pageGraphicMap[page].TailId, | |
bubbleFill = state.SpeechBalloon.pageGraphicMap[page].FillId, | |
bubbleText = state.SpeechBalloon.pageGraphicMap[page].TextId, | |
hiddenState={ | |
layer: "gmlayer", | |
width: 35, | |
height: 35, | |
left: 35, | |
top: 35 | |
}; | |
getObj("graphic" , bubbleBorder).set( hiddenState ); | |
getObj("graphic" , bubbleTail).set( hiddenState ); | |
getObj("graphic" , bubbleFill).set( hiddenState ); | |
getObj("text" , bubbleText).set( hiddenState ); | |
state.SpeechBalloon.bubbleShown=false; | |
} | |
} | |
}, | |
checkBubbleDisplay = function() { | |
var nextBubble, newLastBubble, page, lastPage, token; | |
if(state.SpeechBalloon.validUntil < Date.now() ) { | |
if( state.SpeechBalloon.queue.length == 0 ) { | |
if ( state.lastBalloon != false ) { | |
bustBalloon(state.lastBalloon.page); | |
state.lastBalloon = false; | |
} | |
} else { | |
nextBubble=_.first(state.SpeechBalloon.queue); | |
newLastBubble = nextBubble; | |
state.SpeechBalloon.queue=_.rest(state.SpeechBalloon.queue); | |
page = nextBubble.page; | |
if ( state.lastBalloon != false ) { | |
lastPage = state.lastBalloon.page; | |
if ( page.id != lastPage.id ) { | |
bustBalloon(state.lastBalloon.page); | |
} | |
} else { | |
lastPage = false; | |
} | |
if (! page.get("archived") ) { | |
speechBalloon(nextBubble); | |
state.SpeechBalloon.validUntil = Date.now()+(nextBubble.duration*msPerSec); | |
state.lastBalloon = newLastBubble; | |
state.SpeechBalloon.bubbleShown = true; | |
} | |
} | |
} | |
}, | |
findOrCreateBubbleParts = function(thisMap,thisX,thisY) { | |
var bubbleBorder, bubbleTail,bubbleFill,bubbleText, | |
creationDefaults = { | |
_pageid: thisMap.id, | |
top: thisY, | |
left: thisX, | |
width: 70, | |
height: 70, | |
layer: "gmlayer" | |
}; | |
if( _.has(state.SpeechBalloon.pageGraphicMap, thisMap.id) ) { | |
bubbleBorder = getObj("graphic" , state.SpeechBalloon.pageGraphicMap[thisMap.id].BorderId); | |
bubbleTail = getObj("graphic" , state.SpeechBalloon.pageGraphicMap[thisMap.id].TailId); | |
bubbleFill = getObj("graphic" , state.SpeechBalloon.pageGraphicMap[thisMap.id].FillId); | |
bubbleText = getObj("text" , state.SpeechBalloon.pageGraphicMap[thisMap.id].TextId); | |
} | |
if ( ! bubbleBorder) { | |
bubbleBorder = fixNewObject(createObj("graphic", _.defaults({ | |
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/6565520/qJVbhBJQAw7FNDzBubKuNg/thumb.png?1417619659" | |
},creationDefaults))); | |
toFront(bubbleBorder); | |
} | |
if ( ! bubbleTail) { | |
bubbleTail = fixNewObject(createObj("graphic", _.defaults({ | |
width: 140, | |
height: 140, | |
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/6565493/BMPVhSPmlFaY_KyB7K8XHQ/thumb.png?1417619533" | |
},creationDefaults))); | |
toFront(bubbleTail); | |
} | |
if ( ! bubbleFill) { | |
bubbleFill = fixNewObject(createObj("graphic", _.defaults({ | |
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/6565524/yTHHF5NwFJcd0ddZ-9nyxg/thumb.png?1417619728" | |
},creationDefaults))); | |
toFront(bubbleFill); | |
} | |
if ( ! bubbleText) { | |
bubbleText = fixNewObject(createObj("text", _.defaults({ | |
text: "DoubleBubbleBumBubblesDouble", | |
font_size: 16, | |
color: "rgb(0,0,0)", | |
font_family: "Courier" | |
},creationDefaults))); | |
toFront(bubbleText); | |
} | |
state.SpeechBalloon.pageGraphicMap[thisMap.id]={ | |
BorderId: bubbleBorder.id, | |
TailId: bubbleTail.id, | |
FillId: bubbleFill.id, | |
TextId: bubbleText.id | |
}; | |
return { | |
bubbleTail: bubbleTail, | |
bubbleFill: bubbleFill, | |
bubbleBorder: bubbleBorder, | |
bubbleText: bubbleText | |
}; | |
}, | |
speechBalloon = function(nextBubble) { | |
var theseWords = nextBubble.says, whoSaid = nextBubble.token.get("name"), | |
thisMap = nextBubble.page, thisY = nextBubble.token.get("top"), | |
thisX = nextBubble.token.get("left"); | |
if (theseWords.indexOf("--show|") != 0) { | |
sendChat(whoSaid, theseWords); | |
theseWords = wordwrap(theseWords, 28, "\n"); | |
} else { | |
theseWords = theseWords.replace("--show|", ""); | |
theseWords = theseWords.replace(/~/g, " "); | |
theseWords = theseWords.replace(/::/g, "\n"); | |
} | |
var thisParagraph = theseWords, | |
lineCount = 1 + (thisParagraph.match(/\n/g)||[]).length, | |
approximateWidth = 286, | |
approximateHeight = (lineCount * 25) + 7, | |
xAdjust = ((thisX-(thisMap.get('width') * 35)) >=0) ? -1 : 1, | |
yAdjust = ((thisY-(thisMap.get('height') * 35)) >=0) ? -1 : 1, | |
leftTail = thisX + (105 * xAdjust), | |
topTail = thisY + (105 * yAdjust), | |
leftOffsetBubble = thisX + (210 * xAdjust), | |
topOffsetBubble = thisY + ((Math.floor(approximateHeight/2) + 105 < 159 ? 159 : Math.floor(approximateHeight/2) + 105) * yAdjust), | |
bubbleParts = findOrCreateBubbleParts(thisMap,thisX,thisY), | |
tailFlipH = (-1 !== xAdjust), | |
tailFlipV = (-1 !== yAdjust); | |
if (bubbleParts.bubbleBorder) { | |
bubbleParts.bubbleBorder.set({ | |
layer: "map", | |
width: approximateWidth + 6, | |
height: approximateHeight + 6, | |
top: topOffsetBubble, | |
left: leftOffsetBubble | |
}); | |
toFront(bubbleParts.bubbleBorder); | |
} | |
if (bubbleParts.bubbleTail) { | |
bubbleParts.bubbleTail.set({ | |
layer: "map", | |
width: 140, | |
height: 140, | |
top: topTail, | |
left: leftTail, | |
fliph: tailFlipH, | |
flipv: tailFlipV | |
}); | |
toFront(bubbleParts.bubbleTail); | |
} | |
if (bubbleParts.bubbleFill) { | |
bubbleParts.bubbleFill.set({ | |
layer: "map", | |
width: approximateWidth, | |
height: approximateHeight, | |
top: topOffsetBubble, | |
left: leftOffsetBubble | |
}); | |
toFront(bubbleParts.bubbleFill); | |
} | |
if (bubbleParts.bubbleText) { | |
bubbleParts.bubbleText.set({ | |
layer: "map", | |
text: thisParagraph, | |
top: topOffsetBubble, | |
left: leftOffsetBubble | |
}); | |
toFront(bubbleParts.bubbleText); | |
} | |
state.SpeechBalloon.bubbleShown=true; | |
}, | |
wordwrap = function( str, width, brk, cut ) { | |
brk = brk || '\n'; | |
width = width || 75; | |
cut = cut || false; | |
if (!str) { return str; } | |
var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)'); | |
return str.match( RegExp(regex, 'g') ).join( brk ); | |
}, | |
checkSelect = function(obj,type,command) { | |
if (obj === undefined || obj.length < 1) { | |
return false; | |
} | |
if (obj._type !== type) { | |
return false; | |
} | |
return true; | |
}, | |
handleInput = function(msg) { | |
if ( "api" !== msg.type ) {return; } | |
var args = msg.content.split(' '), | |
obj = _.first(msg.selected), | |
playerid = msg.playerid, | |
token, | |
thisY, | |
thisX; | |
switch(args.shift()) { | |
case "!makebubble": | |
if ( ! checkSelect(obj,"graphic") ) {return; } | |
state.SpeechBalloon.queue.push({ | |
token: getObj("graphic", obj._id), | |
page: getObj('page',getObj("graphic", obj._id).get('pageid')), | |
says: args.join(' '), | |
duration: defaultShowLength, | |
}); | |
return; | |
case "!bustBubble": | |
if ( ! checkSelect(obj,"graphic") ) {return; } | |
bustBalloon(getObj('page',getObj("graphic", obj._id).get('pageid'))); | |
return; | |
} | |
}, | |
checkInstall = function() { | |
if( ! _.has(state,'SpeechBalloon') || state.SpeechBalloon.version !== schemaVersion) { | |
log('SpeechBalloon: Resetting state'); | |
/* Default Settings stored in the state. */ | |
state.SpeechBalloon = { | |
version: schemaVersion, | |
pageGraphicMap: {}, | |
queue: [], | |
validUntil: 0, | |
bubbleShown: false | |
}; | |
} | |
if( ! _.has(state,'lastBalloon')) { | |
log('SpeechBalloon.lastBalloon: Resetting state'); | |
/* Default Settings stored in the state. */ | |
state.lastBalloon = false; | |
} | |
checkInterval = setInterval(checkBubbleDisplay,checkStepRate); | |
}, | |
fixNewObject = function(obj) { | |
var p = obj.changed._fbpath, | |
new_p = p.replace(/([^\/]*\/){4}/, "/"); | |
obj.fbpath = new_p; | |
return obj; | |
}, | |
registerEventHandlers = function() { | |
on('chat:message', handleInput); | |
}; | |
return { | |
CheckInstall: checkInstall, | |
RegisterEventHandlers: registerEventHandlers | |
}; | |
}()); | |
on("ready",function(){ | |
'use strict'; | |
SpeechBalloon.CheckInstall(); | |
SpeechBalloon.RegisterEventHandlers(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment