Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×

Creating a First Person Dungeon using Rollable Tables

Greetings Code Wizards, I'm attempting to create a first person dungeon experience in roll20 as a project to learn Java. So far, I've been able to stand on the shoulders of others and cobble together some code that will track translation and rotation values when changed (see code below). My issue is two fold, I'm having trouble changing the side of a token from a rollable table via the API. I've tried sendChat for "token mod" and from what I've read It requires a user to submit the command and also have the token selected. The other issue is that I need it to work with a named token rather than whats selected. So I humbly ask, would any of you masters of the code arts know of a solution? (here's the debug UI I made) //Purpose of script: To store the location information of players in a 2D plane, including rotation. //This is the base to have a simple first person dungeon expereience // create var to contain Translation X Values if( ! state.mapTranslationX ) {     state.mapTranslationX = {             version: 1.0,             config: {                 color1: '#ff0000',                 color2: '#0000ff'             },             count: 0         }; } // Create var to contain Rotation Values if( ! state.mapRotation ) {     state.mapRotation = {             version: 1.0,             config: {                 color1: '#ff0000',                 color2: '#0000ff'             },             count: 0         }; } // Once code is working, will add Translation Y (though it really should be X and the other Y...) //activate functions using chat command for macro ease on("chat:message", function(msg) {     if (msg.type == "api" && msg.content.indexOf("!MoveMapScript") == 0){         var args = msg.content.split(/\s+/);         var direction = args[1].toLowerCase();         switch(direction){             case "forward":                 forward();                 break;             case "backward":                 backward();                 break;             case "right":                 right();                 break;             case "left":                 left();                 break;         }         //sendChat("API",`Did the if statement`);     } }); function forward(){     sendChat("GOD", 'Started Forward');     sendChat('FORWARD', (++state.mapTranslationX.count)+' times!'     );     //Use Token Mod to change side of token in rollable table.     sendChat('', "!token-mod --set currentside|+"); } function backward(){     sendChat("GOD", 'Started Backward');     //Use Token Mod to change side of token in rollable table.     sendChat('', "!token-mod --set currentside|-");     sendChat('BACKWARD', (--state.mapTranslationX.count)+' times!'     ); } function right(){     sendChat("GOD", 'Started Right')     if (state.mapRotation.count <= 3){         sendChat('RIGHT', (++state.mapRotation.count)+' times!'     );     } else {         sendChat('RIGHT JUMP TO 1', (state.mapRotation.count = 1)+' times!'     );     };      } function left(){     sendChat("GOD", 'Started Left')     if (state.mapRotation.count >= 2){         sendChat('LEFT', (--state.mapRotation.count)+' times!'     );     } else {         sendChat('LEFT JUMP TO 4', (state.mapRotation.count = 4)+' times!'     );     };      } The way it would work is that I have a series of rollable tokens for the three rings shown in the image. One for the ceiling, one for the floor, one for front facing wall, and finally two for the sides. The tables would cycle depending on the x, y, and rot values. As far as the test right now Im just trying to get progression down a hallway and the ability to turn around. Thank you!
1643081901
The Aaron
Roll20 Production Team
API Scripter
I would suggest just changing the current side for the graphic in the API, rather than relying on TokenMod.  If you wanted to use TokenMod, you could pass it the graphic's id with --ids and pass it a player Id to use with --api-as: !token-mod --set currentside|2 --api-as -Jksomeplayerid --ids -kJsometokenid To do it from the API you can grab the sides entry from the token and split it into urls like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const getCleanImgsrc = (imgsrc) => { let parts = imgsrc.match( /(.*\/images\/.*)(thumb|med|original|max)([^?]*)(\?[^?]+)?$/ ); if (parts) { return parts[ 1 ]+ 'thumb' +parts[ 3 ]+(parts[ 4 ]?parts[ 4 ]: ` ?${ Math .round( Math .random()* 9999999 )} ` ); } return ; }; const setTokenSide = (token, side) => { let sides = token.get( 'sides' ).split( /\|/ ).map( decodeURIComponent ).map(getCleanImgsrc); side = Math .min(sides.length- 1 , Math .max( 0 , side)); if (sides[side]){ token.set({ currentSide: side, imgsrc: sides[side] }); } else { log( ` ERROR: "${token.get('name')}" (id: ${token.id}) does not have a user image at index ${side}! ` ); } }; Then just call the above functions like: setTokenSide(someToken,2); Note: I didn't test the setTokenSide() function, I just extracted it from the way TokenMod does it, so it's possible there's an error.  Be sure to monitor the log when you try it out.  Minor note: you're learning Javascript, not Java.  Javascript and Java have very little to do with one another other than the name and a c-like syntax.
I tried my hand at a First Person view run with a group of buddies for almost a year (ended just recently) Here is what I did (below is my test area). The larger map is my GM map, I monitored all players as they moved around. The smaller map is the player's view (the rollable table itself), so each player had their own scene with just that smaller map. Their player token and view represented the character. I made a quick character sheet seen on the right that takes the id of the character and fetches it the respective objects Sample of what I did. The code is a mess because it was more of an experiment. As there are a number of restrictions on how I coded it. Basically, they were really moving the token around the GM map but they could only see their view change based on certain conditions. Command tied to character sheet         <button class='sheet-leftButton' type='roll' value='!left @{character_id}' title='Move Left'>             Left         </button> Taking said command else if (msg.content.indexOf("!left ") !== -1) { myId = msg.content.replace("!left ", ""); characterFacing = findObjs({_type: 'attribute', name:'Facing', _characterid:myId}); token = findObjs({type:'graphic', layer:'objects', represents:myId}); view = findObjs({type:'graphic', layer:'map', represents:myId}); DungeonCrawlerFP.Move('Left', characterFacing, token, view); } Then moving of the token itself. It was just incrementing/decrementing the row/column depending on the direction they were facing and then which way they intended to move as well as rotating the token (for my viewing pleasure) var facing = characterFacing[0].get('current'); var rowPosition = (token[0].get('top')+35)/70-1; var columnPosition = (token[0].get('left')-35)/70; var tokenMapPosition = [rowPosition, columnPosition]; var cannotMove = DungeonCrawlerFP.CheckMove(tokenMapPosition, direction, facing, token[0].get('name')); After their token moved. I just used switch-case (quite messy) to change the player's view to the face of the rollable table based on the direction they are now facing and a tile map (that outlined the GM map, a 2-dimensional array that contained set characters that represented a face) For example, if they were approaching a Left T Intersection (on the tile map) but facing South, it would show the Right T Intersection (like in the screenshot) faces[0] = 4 Way Intersection faces[1] = Dead End faces[2] = Front T Intersection faces[3] = Left Open faces[4] = Left Open Corner faces[5] = Horizontal Hall faces[6] = Left T Intersection faces[7] = Left Turn faces[8] = Open faces[9] = Right Open faces[10] = Right Open Corner faces[11] = Right T Intersection faces[12] = Right Turn faces[13] = Vertical Hall Tile-map that outlined the screenshot ['-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-'], ['-B-', 'URO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', '-DO', 'ULO', '-B-'], ['-B-', '-RO', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-LO', '-B-'], ['-B-', '-RO', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-O-', '-LO', '-B-'], ['-B-', '-RO', '-O-', '-UO', '-UO', '-UO', '-UO', '-O-', '-UO', '-O-', '-O-', '-O-', '-O-', '-UO', '-UO', '-UO', '-UO', '-O-', '-UO', '-UO', '-O-', '-UO', '-UO', 'LLO', '-B-'], ['-B-', '-RO', '-LO', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-RO', '-O-', '-UO', '-LO', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-'], ['-B-', 'LRO', 'LLO', '-B-', '-DE', '-UT', '-HH', 'LLC', '-B-', 'LRO', 'LLO', '-B-', '-RO', '-DO', '-DO', '-DO', '-HH', '-LT', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-RO', '-O-', '-O-', '-LO', '-B-', '-RO', '-DO', '-DO', '-O-', '-DO', '-DO', 'ULO', '-B-'], ['-B-', 'URC', '-HH', '-HH', '-HH', '-DT', '-HH', '-HH', '-UT', '-HH', '-HH', '-HH', '-UO', '-UO', '-UO', '-LO', '-B-', '-RO', '-UO', '-UO', '-UO', '-UO', '-UO', '-LO', '-B-'], ['-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-DE', '-B-', '-DE', '-HH', '-UT', '-HH', '-HH', 'LLC', '-B-', '-DE', '-HH', '-UT', '-HH', '-HH', 'LLC', '-B-', 'LRC', '-HH', '-UT', '-HH', '-HH', '-HH', '-LT', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-DE', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', 'URO', '-DO', 'ULO', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', 'LRC', '-HH', '-HH', '-HH', '-LT', '-B-', '-B-', 'URO', '-DO', 'ULO', '-B-', '-VH', '-B-', '-RO', '-O-', '-LO', '-B-', '-B-', '-RT', '-HH', '-HH', '-HH', '-LT', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-RO', '-O-', '-LO', '-B-', '-VH', '-B-', '-RO', '-O-', '-LO', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-RO', '-O-', '-LO', '-B-', '-VH', '-B-', '-RO', '-O-', '-LO', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-RO', '-O-', '-LO', '-B-', '-VH', '-B-', '-RO', '-O-', '-LO', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', 'LRO', '-UO', '-LO', '-B-', '-VH', '-B-', '-RO', '-UO', 'LLO', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-VH', '-B-', '-VH', '-B-', '-B-', '-B-', '-B-', '-VH', '-B-', '-B-', '-B-', '-VH', '-B-'], ['-B-', '-DE', '-HH', '-HH', '-HH', '-DT', '-HH', '-HH', '-HH', '-HH', '-O-', '-DO', '-O-', '-DO', '-O-', '-HH', '-HH', '-HH', '-HH', '-DT', '-HH', '-HH', '-HH', 'LLC', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-RO', '-O-', '-O-', '-O-', '-LO', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-'], ['-B-', '-B-', '-B-', '-B-', 'URO', '-DO', '-HH', '-HH', '-HH', '-HH', '-O-', '-O-', '-O-', '-O-', '-O-', '-HH', '-HH', '-HH', '-HH', '-DO', 'ULO', '-B-', '-B-', '-B-', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-RO', '-LO', '-B-', '-B-', '-B-', '-B-', '-RO', '-O-', '-O-', '-O-', '-LO', '-B-', '-B-', '-B-', '-B-', '-RO', '-LO', '-B-', '-B-', '-B-', '-B-'], ['-B-', '-B-', '-B-', '-B-', 'LRO', 'LLO', '-B-', '-B-', '-B-', '-B-', 'LRO', '-UO', '-UO', '-UO', 'LLO', '-B-', '-B-', '-B-', '-B-', 'LRO', 'LLO', '-B-', '-B-', '-B-', '-B-'], ['-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-', '-B-']