Skip to content

Instantly share code, notes, and snippets.

@shdwjk
Last active October 28, 2020 18:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shdwjk/d97377b90de4bb37195b to your computer and use it in GitHub Desktop.
Save shdwjk/d97377b90de4bb37195b to your computer and use it in GitHub Desktop.
Roll20 API: Betrayal at House on the Hill Card Swap Script
// GIST: https://gist.github.com/shdwjk/d97377b90de4bb37195b
var Betrayal = Betrayal || (function(){
var Tiles={
"Basement Landing": {
name: "Basement Landing",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482089/uhxEkm5S_TNzjP7NdCm4hg/thumb.png?1395454546",
where: [ "basement" ],
special: true,
exits: [ "north", "south", "east", "west", "Grand Staircase" ]
},
Foyer: {
name: "Foyer",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481568/33Z4mgMLtacoaxD3bfvLEg/thumb.png?1395450919",
where: [ "second" ],
special: true,
height: 3,
exits: [ "east", "west", "Upper Landing" ]
},
"Upper Landing": {
name: "Upper Landing",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481568/33Z4mgMLtacoaxD3bfvLEg/thumb.png?1395450919",
where: [ "second" ],
special: true,
exits: [ "north", "south", "east", "west" ]
},
Catacombs: {
name: "Catacombs",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4580991/gl3xOt673OgGCrKP7j2i8A/thumb.png?1404155845",
where: [ "basement" ],
omen: 1,
msg: "You can attempt a Sanity roll of 6+ to cross. If you fail, you stop moving.",
exits: [ "north", "south" ]
},
Chasm: {
name: "Chasm",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581000/d-S6Na-qKEznw7ZHClgU8Q/thumb.png?1404155934",
where: [ "basement" ],
msg: "You can attempt a Speed roll of 3+ to cross. If you fail, you stop moving.",
exits: [ "east", "west" ]
},
Crypt: {
name: "Crypt",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581048/uGD-12TsMWi8b1nrFKm4tg/thumb.png?1404156571",
where: [ "basement" ],
msg: "If you and end your turn here, take 1 point of mental damage.",
event: 1,
exits: [ "north" ]
},
"Furnace Room": {
name: "Furnace Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581050/ed7BEgwX8VMeg7OxcIEwgg/thumb.png?1404156601",
where: [ "basement" ],
msg: "If you end your turn here, take 1 point of physcial damage.",
omen: 1,
exits: [ "north", "south", "west" ]
},
Larder: {
name: "Larder",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581051/aPn5ZmmuNaOQk_9DA6BxiQ/thumb.png?1404156619",
where: [ "basement" ],
msg: "If you end your turn here, gain 1 Might.",
item: 1,
exits: [ "north", "south" ]
},
"Pentagram Chamber": {
name: "Pentagram Chamber",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581056/5OdTHh6syG1eVuwSFhV4Aw/thumb.png?1404156645",
where: [ "basement" ],
msg: "When exiting, you must attmpt a Knowledge roll of 4. If you fail, lose 1 Sanity.",
omen: 1,
exits: [ "east" ]
},
"Stairs From Basement": {
name: "Stairs From Basement",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482559/YOqQCVDc5dy4Ku4LSivGZQ/thumb.png?1395456642",
where: [ "basement" ],
exits: [ "south", "Foyer" ]
},
"Underground Lake": {
name: "Underground Lake",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482241/KkLJMdSFWPSvjoRG85l8Aw/thumb.png?1395455182",
where: [ "basement" ],
event: 1,
exits: [ "north", "east" ]
},
"Wine Cellar": {
name: "Wine Cellar",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581061/_z6JshBJbqrH-Af2AmY28A/thumb.png?1404156687",
where: [ "basement" ],
item: 1,
exits: [ "north", "south" ]
},
Ballroom: {
name: "Ballroom",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481956/DSRY8W1xavbIpg5zyz6xkg/thumb.png?1395453695",
where: [ "first" ],
event: 1,
exits: [ "north", "south", "east", "west" ]
},
"Coal Chute": {
name: "Coal Chute",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482083/9Wk244zl8FD-vSDwbKVpag/thumb.png?1395454500",
where: [ "first" ],
msg: "One way slide to Basement Landing",
exits: [ "north", "Basement Landing" ]
},
"Dining Room": {
name: "Dining Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482133/MtfbcOyJNnaogoaS34vxnQ/thumb.png?1395454851",
where: [ "first" ],
omen: 1,
exits: [ "north", "east" ]
},
Gardens: {
name: "Gardens",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481403/S-5dogo2G5Xl6usKDs466Q/thumb.png?1395449960",
where: [ "first" ],
event: 1,
exits: [ "north", "south" ]
},
Graveyard: {
name: "Graveyard",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481654/lAMNt7Me01LMkmNFOQLuFQ/thumb.png?1395451341",
where: [ "first" ],
msg: "When exiting, you must attempt a Sanity roll of 4+. If you fail, lose 1 Knowledge.",
event: 1,
exits: [ "south" ]
},
Patio: {
name: "Patio",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482017/0Gg6rfVaVWTxNOn5a7Ua3g/thumb.png?1395454016",
where: [ "first" ],
event: 1,
exits: [ "north", "south", "west" ]
},
"Abandoned Room": {
name: "Abandoned Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481508/pYDwGrR91OAVaHXojLvo1w/thumb.png?1395450567",
where: [ "basement", "first" ],
omen: 1,
exits: [ "north", "south", "east", "west" ]
},
Kitchen: {
name: "Kitchen",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481871/t9s9F4-Lg_PZqG8cQY12Rw/thumb.png?1395453077",
where: [ "basement", "first" ],
omen: 1,
exits: [ "north", "east" ]
},
Tower: {
name: "Tower",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581159/W7E3kxhstVyWqdqaxkDALQ/thumb.png?1404157089",
where: [ "basement", "first" ],
msg: "You can attempt a Might roll of 3+ to cross. If you fail, you stop moving.",
event: 1,
exits: [ "east", "west" ]
},
Bedroom: {
name: "Bedroom",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4580890/42K8p1fj833WnS75RCt53Q/thumb.png?1404155355",
where: [ "second" ],
event: 1,
exits: [ "east", "west" ]
},
Attic: {
name: "Attic",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482327/kC2-faavxi9yg_CgfahOCQ/thumb.png?1395455323",
where: [ "second" ],
msg: "When exiting, you must attempt a Speed roll of 3+. If you fail, lose 1 Might.",
event: 1,
exits: [ "south" ]
},
Balcony: {
name: "Balcony",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4580912/FWxHKnO1wkavOn0XZREpAQ/thumb.png?1404155571",
where: [ "second" ],
omen: 1,
exits: [ "north", "south" ]
},
Gallery: {
name: "Gallery",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482654/VkcQjCvDDOOYOGpO4R12pg/thumb.png?1395456996",
where: [ "second" ],
msg: "You can choose to fall to the Ballroom. If you do, take 1 die of physical damage.",
event: 1,
exits: [ "north", "south", "Ballroom" ]
},
"Master Bedroom": {
name: "Master Bedroom",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581149/5pIGCVGtiv01N1AwOhrdag/thumb.png?1404157062",
where: [ "second" ],
omen: 1,
exits: [ "north", "west" ]
},
Gymnasium: {
name: "Gymnasium",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482471/Rw43Y_j67ZKf9a9kNfJuJg/thumb.png?1395456390",
where: [ "basement", "second" ],
msg: "If you end your turn here, gain 1 Speed.",
omen: 1,
exits: [ "south", "east" ]
},
"Operating Laboratory": {
name: "Operating Laboratory",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482098/S0CyyeOjMgRdqW7WpajaUQ/thumb.png?1395454606",
where: [ "basement", "second" ],
event: 1,
exits: [ "south", "east" ]
},
"Research Laboratory": {
name: "Research Laboratory",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482410/aM3d6K05Dw001jjlFdsjpw/thumb.png?1395455961",
where: [ "basement", "second" ],
event: 1,
exits: [ "north", "south" ]
},
"Servants' Quarters": {
name: "Servants' Quarters",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481595/ItbjJs3QpXYTufDx-8IFcg/thumb.png?1395451146",
where: [ "basement", "second" ],
omen: 1,
exits: [ "north", "south", "east", "west" ]
},
Storeroom: {
name: "Storeroom",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482426/xEbFnPgmz22gJTrZOhck0w/thumb.png?1395456113",
where: [ "basement", "second" ],
item: 1,
exits: [ "north" ]
},
Vault: {
name: "Vault",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482445/D0TY-IkHlp6xfdsh-W4YUA/thumb.png?1395456254",
where: [ "basement", "second" ],
msg: "You can attempt a Knowledge roll of 6+ to open and empty the vault.",
event: 1,
item: 2,
exits: [ "north" ]
},
"Bloody Room": {
name: "Bloody Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481838/45fC0urFtD6ELI-S8VmLWw/thumb.png?1395452760",
where: [ "first", "second" ],
item: 1,
exits: [ "north", "south", "east", "west" ]
},
Chapel: {
name: "Chapel",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481572/N7K9cNIzvB-pSepf-gn5WA/thumb.png?1395450951",
where: [ "first", "second" ],
msg: "If you end your turn here, gain 1 Sanity.",
event: 1,
exits: [ "north" ]
},
"Charred Room": {
name: "Charred Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481940/7sUDmfRg4W0iR8jC_UcVpg/thumb.png?1395453543",
where: [ "first", "second" ],
omen: 1,
exits: [ "north", "south", "east", "west" ]
},
"Collapsed Room": {
name: "Collapsed Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3482069/jUrY2FCvrL5RD3AGoR-CCw/thumb.png?1395454391",
where: [ "first", "second" ],
msg: "You must attempt a Speed roll of 5+ to avoid falling. If you fail the roll, draw a basement tile and put it in play. You fall there and take 1 die of physical damage.",
exits: [ "north", "south", "east", "west", "basement"
]
},
Conservatory: {
name: "Conservatory",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481758/EZFM-IzvXgzK1Vu7nYqeVg/thumb.png?1395452105",
where: [ "first", "second" ],
event: 1,
exits: [ "north" ]
},
Library: {
name: "Library",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4581120/KeZwDV4t3psE-FSaAelDzQ/thumb.png?1404156837",
where: [ "first", "second" ],
msg: "If you end your turn here, gain 1 Knowledge.",
event: 1,
exits: [ "south", "west" ]
},
"Creaky Hallway": {
name: "Creaky Hallway",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481441/tzue7NZAC9fpL2iOs1AB6g/thumb.png?1395450196",
where: [ "basement", "first", "second" ],
exits: [ "north", "south", "east", "west" ]
},
"Dusty Hallway": {
name: "Dusty Hallway",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481999/5Rx0194RG3mJARMcDs_yDQ/thumb.png?1395453866",
where: [ "basement", "first", "second" ],
exits: [ "north", "south", "east", "west" ]
},
"Game Room": {
name: "Game Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481819/_s6Lf59VVExDWNHV_tZBDQ/thumb.png?1395452602",
where: [ "basement", "first", "second" ],
event: 1,
exits: [ "north", "south", "east" ]
},
"Junk Room": {
name: "Junk Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481692/JYJAN9CrAmnOrMfoorkH3g/thumb.png?1395451679",
where: [ "basement", "first", "second" ],
msg: "When exiting, you must attempt a Might roll of 3+. If you fail, lose 1 Speed.",
omen: 1,
exits: [ "north", "south", "east", "west" ]
},
"Mystic Elevator": {
name: "Mystic Elevator",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481714/nPSqHff6zh4hgKRwM7fNhg/thumb.png?1395451864",
where: [ "basement", "first", "second" ],
msg: "Roll 2 dice and move this room next to any open door on:"
+'<div style="padding-left:20px;"><b>4</b> Any floor</div>'
+'<div style="padding-left:20px;background:#cdcdb8;"><b>3</b> Upper level</div>'
+'<div style="padding-left:20px;"><b>2</b> Ground floor</div>'
+'<div style="padding-left:20px;background:#cdcdb8;"><b>1</b> Basement level</div>'
+'<div style="padding-left:20px;"><b>0</b> Basement level, then take 1 die of physical damage</div>',
exits: [ "north" ]
},
"Organ Room": {
name: "Organ Room",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481848/V8mRaHBbYlJHCEy9Xq9IZQ/thumb.png?1395452863",
where: [ "basement", "first", "second" ],
event: 1,
exits: [ "south", "west" ] }, "Statuary Corridor": {
name: "Statuary Corridor",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3481459/KsHYb3czjorho_97a0kWdg/thumb.png?1395450270",
where: [ "basement", "first", "second" ],
event: 1,
exits: [ "north", "south" ]
}
};
var Cards=[
{
name: "back",
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/3480889/WMoO3Y0rCSY5pJcIgtbAxg/med.jpg?1395446676"
},
{
name: "basement",
where: ['basement'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669446/aakzl3IqKyYmbo5z8FFdLg/med.jpg?1404842853"
},
{
name: "ground",
where: ['first'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669450/LXruXLDGWmcCZVbKWjybYQ/med.jpg?1404842868"
},
{
name: "basement-ground",
where: ['basement','first'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669458/yLGZR_LbtfV7-adVCAG6Vw/med.jpg?1404842920"
},
{
name: "upper",
where: ['second'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669462/GNDTpbcZbXW2H_c53d7DFg/med.jpg?1404842932"
},
{
name: "basement-upper",
where: ['basement','second'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669464/aJSCfW5s4pZ1y7z2eb65Vw/med.jpg?1404842942"
},
{
name: "ground-upper",
where: ['first','second'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669467/cNA1KUmS5eO3MZF2Jd2ArA/med.jpg?1404842953"
},
{
name: "basement-ground-upper",
where: ['basement','first','second'],
imgsrc: "https://s3.amazonaws.com/files.d20.io/images/4669473/Bno9_FKndGm-yCIfyRPdaQ/med.jpg?1404842962"
}
];
// Utility Function
var fixNewObject = fixNewObject || function(obj){
var p = obj.changed._fbpath;
var new_p = p.replace(/([^\/]*\/){4}/, "/");
obj.fbpath = new_p;
return obj;
};
var BetrayalIcons='https://s3.amazonaws.com/files.d20.io/images/4701899/icY-c69Ntz7nBKEHxQgK9A/med.png?1405046175';
var cardlookup={};
cardlookup.basement = 1;
cardlookup.first = 2;
cardlookup.second = 4;
var CardNumFromWhere = function(where) {
var n = 0;
_.each(where, function(w){
if(_.has(cardlookup,w)) {
n+=cardlookup[w];
}
});
return n;
};
var DeckID;
var Initialize = function() {
var Deck = findObjs({type:'deck',name:'Map Cards'})[0];
if(Deck){
DeckID=Deck.id;
}
else {
log('Could not find deck: Map Cards');
}
};
var HandleAddGraphic = function(obj) {
if('card' === obj.get('subtype'))
{
var card=getObj('card',obj.get('cardid'));
if(card && DeckID === card.get('deckid'))
{
var t=Tiles[card.get('name')];
var g = findObjs({
type: 'graphic',
pageid: obj.get('pageid'),
name: t.name,
imgsrc: t.imgsrc
})[0];
if(g){
g.set({
left: (Math.round((obj.get('left')/70),0)*70)-35,
top: (Math.round((obj.get('top')/70),0)*70)-35,
width: 210,
height: 210,
rotation: 0,
layer: 'objects'
});
} else {
g=fixNewObject(createObj('graphic',{
pageid: obj.get('pageid'),
imgsrc: t.imgsrc,
left: (Math.round((obj.get('left')/70),0)*70)-35,
top: (Math.round((obj.get('top')/70),0)*70)-35,
width: 210,
height: 210,
layer: 'objects',
name: t.name,
controlledby: 'all'
}));
}
toBack(g);
var MsgPart='',
IconPart='',
VaultPart='';
if(t.msg) {
MsgPart='<div style="padding: 8px 20px; color: #580000;font-family: \'Times New Roman\', Times, serif;">'
+t.msg
+'</div>';
}
if(t.omen) {
IconPart+='<div style="background:url('+BetrayalIcons+') 0 0; width:90px; height: 70px; float:right;"></div>';
}
if(t.event) {
IconPart+='<div style="background:url('+BetrayalIcons+') -90px 0; width:90px; height: 70px; float:right;"></div>';
}
if(1 === t.item) {
IconPart+='<div style="background:url('+BetrayalIcons+') -180px 0; width:90px; height: 70px; float:right;"></div>';
}
if(2 === t.item) {
VaultPart+='<div style="clear:both;"></div>';
VaultPart+='<div style="background:url('+BetrayalIcons+') -180px 0; width:90px; height: 70px; float:right;"></div>';
VaultPart+='<div style="background:url('+BetrayalIcons+') -180px 0; width:90px; height: 70px; float:right;"></div>';
}
sendChat('','/direct '
+'<div style="border: 2px solid; border-radius: 25px;box-shadow: 10px 10px 5px #888888;overflow: hidden;background: #F5F5DC;">'
+'<div style="font-family: \'Times New Roman\', Times, serif; background-color:#300000;color:#c0c0c0;font-weight: bold; padding: 8px 13px; font-size: 160%;">'
+'<img src="'+Cards[CardNumFromWhere(t.where)].imgsrc+'" style="z-index:1000;width:25px; height:25px;border:1px solid #777;float:right;" />'
+t.name
+'<div style="clear:both;"></div>'
+'</div>'
+IconPart
+MsgPart
+VaultPart
+'<div style="clear:both;"></div>'
+'</div>'
);
obj.set({
layer: 'gmlayer',
left: 140,
top: 140
});
}
}
};
var HandleInputs = function(msg) {
if (msg.type !== "api") {
return;
}
var who=getObj('player',msg.playerid).get('_displayname').split(' ')[0];
var tokenized = msg.content.split(" ");
var command = tokenized[0];
switch(command) {
case '!cleanup':
_.each(Tiles,function(t){
_.each(findObjs({
type: 'graphic',
name: t.name,
layer: 'objects'
}),function(g){
try {
g.set({
layer: 'gmlayer',
left: 140,
top: 350
});
} catch (e) {
log('ERROR: Couldn\'t move '+t.name+' card off the board.');
}
});
});
break;
// case '!bt-setup-deck':
// var deck = findObjs({type:'deck',name:'Map Cards'})[0];
// if(deck)
// {
// var deckCards=findObjs({type:'card',deckid:deck.id});
// _.each(Tiles,function(t){
// if(!t.special)
// {
// var c=deckCards.pop();
// if(c)
// {
// c.set({
// name: t.name,
// avatar: Cards[CardNumFromWhere(t.where)].imgsrc
// });
// }
// else
// {
// log('No card available for: '+t.name);
// }
// }
// });
// }
// break;
}
},
HandleChangeGraphic = function(obj,prev) {
if(Tiles[obj.get('name')]) {
toBack(obj);
}
};
var RegisterEventHandlers = function() {
on('chat:message', HandleInputs);
on('add:graphic', HandleAddGraphic);
on('change:graphic', HandleChangeGraphic);
};
return {
RegisterEventHandlers: RegisterEventHandlers,
Initialize: Initialize
};
}());
on('ready',function(){
Betrayal.Initialize();
Betrayal.RegisterEventHandlers();
});
@apsalari
Copy link

Hello! I was wondering what supporting structures or other code would be needed to get this operational in a Roll20 game.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment