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 .
×
Create a free account

Array based on token name.

Is there a way to make a script load all tokens with a given name into an array so they can be manipulated? For example, build an array of all tokens named asteroid when I don't know how many asteroids there will be on a given map.
Ok, got this one solved, now to get my  script ro manipulate layers.
1656758880
David M.
Pro
API Scripter
Great! Setting the layer property of the graphic object is pretty straightforward. From the API Objects wiki , this is done with: obj.set("property", newvalue) or obj.set({property: newvalue, property2: newvalue2}) So moving each element in an array of graphic objects to the gmlayer could be done like this for example: tokArray.forEach (tok => {     tok.set("layer", "gmlayer"); });
I did try that.  It did not seem to move them.  Players could still see my asteroids zooming about
1656771524
David M.
Pro
API Scripter
Can you post your script so far?
1656847417

Edited 1656856165
on('ready', function(){          const PIXELS = 70          on('chat:message', function(msg){                  if(msg.type == 'api' && (playerIsGM(msg.playerid)))         {                          if(msg.content.indexOf('!Drift')==0 || msg.content.indexOf('!drift')==0)             {                                  asteroids = findObjs({ name:"Asteroid" }, {caseInsensitive: false});                                  page         = getObj("page",Campaign().get("playerpageid"));                 height       = page.get("height");                 heightString = height.toString();   //Only used for debugging                 width        = page.get("width");                 widthString  = width.toString();    //Only used for debugging                 driftY       = PIXELS;                 driftX       = PIXELS;                 interval     = 5;  //Theese give a drift of between -2 and 2 so there                 offset       = 3;  //is a more dynamic drift than just one block.                                 if (page.get('name').indexOf('Space')==0){                                          asteroids.forEach(function(asteroid){                                                  courseX = randomInteger(interval)-(offset);                         courseY = randomInteger(interval)-(offset);                                                  deltaX = driftX * courseX;                         deltaY = driftY * courseY;                                                  if (asteroid.get('top')+deltaY > height*PIXELS + PIXELS) {  //Above the map                             asteroid.set("top", height*PIXELS + PIXELS); //Stop it just off the map                             //asteroid.set("layer","gmlayer");  //Hide it                             //asteroid.set("top", 0)            //Move it to the bottom of the map                             //asteroid.set("layer","objects");  //Unhide it                              } else if (asteroid.get('top')+deltaY < 0 - PIXELS) {        //below the map                              asteroid.set("top", 0 - PIXELS);  //Stop it just off the map                             //asteroid.set("layer","gmlayer");    //Hide it                             //asteroid.set("top", height*PIXELS); //Move it tot he top ot the map                             //asteroid.set("layer","objects");    //Unhide it                              } else {                             //Forces the y coordinate into a square if it has slipped out                             newY = (parseInt((asteroid.get('top') + deltaY) / PIXELS) * PIXELS) + PIXELS / 2;                                                            asteroid.set("top", newY);                            }                                                                           if (asteroid.get('left')+deltaX > width * PIXELS + PIXELS) {  //Off the right side                                                          asteroid.set("left", width * PIXELS + PIXELS);  //Stop it just off the map                             //asteroid.set("layer","gmlayer");  //Hide it                             //asteroid.set("left", 0);          //Move it to the left side                             //asteroid.set("layer","objects");  //Unhide it                                                      } else if (asteroid.get('left') + deltaX < 0 - PIXELS) {       //Off the Left side                                                          asteroid.set("left", 0 - PIXELS);  //Stop it just off the map                             //asteroid.set("layer","gmlayer");      //Hide it                             //asteroid.set("left", width*PIXELS);   //Move it to the right side.                             //asteroid.set("layer","objects");      //Unhide it                                                      } else {                                                          //Forces the x coordinate into a square if it has slipped out                             newX = (parseInt((asteroid.get('left') + deltaX) / PIXELS) * PIXELS) + PIXELS / 2;                                                            asteroid.set("left", newX);                         }                                                      rotation = randomInteger(360);                             asteroid.set("rotation", rotation);                             //sendChat('Asteroid', "drifts " + deltaY + " x " + deltaX  );                                              })                 }                              //sendChat(asteroids.length + ' Asteroids', heightString*PIXELS + " x " + widthString*PIXELS );             }         }     }) }) When I had the commented out code in a player account could see off map asteroids zooming by in the background as they jumped accross the map to come in on the other side.  I altered the code to make them just stop at the edge of the map, but still would prefer the other solution.
1656858509

Edited 1656858555
AHHA!  I have it.  The asteroids were not spending enough time on the GM layer and so they were still getting rendered. (I believe.)  I left them on the GM layer for the rest of a cycle and then just moved them all back to the object layer at the start of the next drift.  Player accounts can no longer see them move!  
1656858891
David M.
Pro
API Scripter
Ah, great! I figured there was some asynchronous timing involved. I was about to suggest having the script spawn a new copy of the token object (and delete the old one) when a map-wrapping event would occur to give the illusion of "teleporting" to the other side. But, sounds like what you are doing would be simpler (and more importantly is already written, haha).
1656861219

Edited 1656861294
David M.
Pro
API Scripter
Ok, I was bored. If you're interested in the auto-wrapping using the respawn technique, this seems like it works. I used a dumbed-down version of functions from my SpawnDefaultToken script, including removing the async parts. If you needed to do anything with the newly spawned "newTok" object, you'd need to make the respawnToken function async and perform an "await" on the createObj line, but it didn't seem necessary in your case.  on('ready', function(){ const PIXELS = 70 on('chat:message', function(msg){ const getCleanImgsrc = function (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 respawnToken = function(tokenJSON, pageID, spawnX, spawnY, rotation) { let baseObj = JSON.parse(tokenJSON); //set new token properties baseObj.pageid = pageID; baseObj.left = spawnX; baseObj.top = spawnY; baseObj.rotation = rotation; baseObj.imgsrc = getCleanImgsrc(baseObj.imgsrc); //ensure that we're using the thumb.png newTok = createObj('graphic',baseObj); return; }; if(msg.type == 'api' && (playerIsGM(msg.playerid))) { if(msg.content.indexOf('!Drift')==0 || msg.content.indexOf('!drift')==0) { asteroids = findObjs({ name:"Asteroid" }, {caseInsensitive: false}); page = getObj("page",Campaign().get("playerpageid")); pageID = page.get("_id"); height = page.get("height"); heightString = height.toString(); //Only used for debugging width = page.get("width"); widthString = width.toString(); //Only used for debugging driftY = PIXELS; driftX = PIXELS; interval = 5; //Theese give a drift of between -2 and 2 so there offset = 3; //is a more dynamic drift than just one block. if (page.get('name').indexOf('Space')==0){ //boundary conditions maxX = width*PIXELS - PIXELS/2; minX = PIXELS/2; maxY = height*PIXELS - PIXELS/2; minY = PIXELS/2; asteroids.forEach(function(asteroid){ let respawn = false; let tokenJSON = JSON.stringify(asteroid); courseX = randomInteger(interval)-(offset); courseY = randomInteger(interval)-(offset); deltaX = driftX * courseX; deltaY = driftY * courseY; //new coords newX = (parseInt((asteroid.get('left') + deltaX) / PIXELS) * PIXELS) + PIXELS / 2; newY = (parseInt((asteroid.get('top') + deltaY) / PIXELS) * PIXELS) + PIXELS / 2; rotation = randomInteger(360); //if any one dimension is out of bounds, wrap token and force respawn if (newX > maxX) { newX = minX; respawn = true; } if (newX < minX) { newX = maxX; respawn = true; } if (newY > maxY) { newY = minY; respawn = true; } if (newY < minY) { newY = maxY; respawn = true; } if (respawn) { newTok = respawnToken(tokenJSON, pageID, newX, newY, rotation) asteroid.remove(); } else { asteroid.set({left:newX, top:newY, rotation:rotation}); } }) } } } }) }) Click for animated gif: