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

Dynamic switch between selected and target

1632406338
.Hell
Sheet Author
Hey everyone, Is it possible to check if a token is selected and if not ask for a target? Thanks for your help.
1632408303
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Not without the API. What are you trying to accomplish? There might be other methods.
1632409027
.Hell
Sheet Author
I want to integrade a button into a charactersheet that first checks if a token is selected to grab the attributes from it and if this is not the case prompts the user to select a target.
1632411084
Andreas J.
Forum Champion
Sheet Author
Translator
Don't think this is possible.
1632413565
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Sigh, if &{noerror} suppressed the "no selected token" error message, we could do this with the new roll parsing feature.
1633413423

Edited 1633413470
Oosh
Sheet Author
API Scripter
A bit late to the party here, but the first trick in the startRoll() thread should be able to achieve this. Replace the getQuery() function with a getSelected() function - same basic idea but grab the inline label from a fake roll containing {{charid=[[0[@{selected|character_id}]]] }} If the contents doesn't match a UUID regex string, there's no valid character selected and you can use @{target} calls when you construct your main roll. I'm not 100% sure what would be returned in the startRoll() object when there's nothing selected - the whole thing might be undefined - but there should be some non-crashy way of distinguishing a successful ID grab from an error, even if you have to resort to a try{}catch{} block. I think it should work, anyway....
1633452059

Edited 1633454098
.Hell
Sheet Author
Oosh said: A bit late to the party here, but the first trick in the startRoll() thread should be able to achieve this. Replace the getQuery() function with a getSelected() function - same basic idea but grab the inline label from a fake roll containing {{charid=[[0[@{selected|character_id}]]] }} If the contents doesn't match a UUID regex string, there's no valid character selected and you can use @{target} calls when you construct your main roll. I'm not 100% sure what would be returned in the startRoll() object when there's nothing selected - the whole thing might be undefined - but there should be some non-crashy way of distinguishing a successful ID grab from an error, even if you have to resort to a try{}catch{} block. I think it should work, anyway.... Nice idea, but if I try it that way all I get is this chat output: You attempted to use a roll command looking for the value of a selected token, but no tokens are selected. const getSelected = async () => { const rxGrab = /^0\[(.*)\]\s*$/; try { let rollBase = `! {{charid=[[0[@{selected|character_id}]]] }}`, // just a [[0]] roll with an inline tag queryRoll = await startRoll(rollBase); queryResponse = (queryRoll.results.charid.expression.match(rxGrab) || [])[1]; console.log(queryResponse); finishRoll(queryRoll.rollId); // you can just let this time out if you want - we're done with it }catch(error) { console.log("undefined"); return undefined; } return queryResponse; };
1633489681

Edited 1633508068
Oosh
Sheet Author
API Scripter
Ah, roger that. I see the problem now, Roll20 never returns anything from the startRoll() when there's a @{selected} error, so the await becomes blocking. There is a way around that, though whether or not you consider it useful is another matter :) If we still call startRoll() as async, but don't await the result, we can manually wait for a certain amount of time to see if it returns anything. Having a manual timer in here would be a real issue for a super important roll, but the worst case here on a failure is that the player needs to manually select instead of the sheet automatically using the {selected}. I did a very quick test to make sure this worked, and 50ms seemed to be about right for the timeout - ymmv of course, and you might want a big error margin. Anyways, here's the code: // Promisified setTimeout const   aTimeout  =  async  ( ms )  =>   new   Promise ( res   =>   setTimeout (()  =>  { res ()},  ms )); const   getSelected  =  async  ()  =>  {      const   rxGrab  =  / ^ 0 \[ ( . * ) \] \s * $ / ;      let   rollBase  =  `! {{charid=[[0[@{selected|character_id}]]] }}` ;      let   selectedRoll ,  selectedResponse ;      startRoll ( rollBase ). then ( v => selectedRoll = v );      // Manually wait for a result with an async timeout      console . log ( `Start timeout` );      await   aTimeout ( 50 );      console . log ( `Leave timeout` );      // Process result if the .then() block above has had time to finish      if  ( selectedRoll ) {          selectedResponse  = ( selectedRoll . results . charid . expression . match ( rxGrab ) || [])[ 1 ];          console . log ( selectedResponse );          finishRoll ( selectedRoll.rollId );     }  else   console . log  ( `Nothing selected...` );      return   selectedResponse ; }; const   testRoll  =  async  ()  =>  {      let   val  =  await   getSelected ();      if  ( val )  console . log ( `Proceeding with {selected} roll` );      else   console . log ( `Proceeding with {target} roll` ); } on ( 'clicked:reptest' ,  testRoll ); Pretty similar setup, except the await is removed from the startRoll, and we use a .then() block to unwrap the promise if it returns anything. We don't even get the benefit of startRoll's 5 second timer here as far as I can tell - Roll20 doesn't give us peanuts if the {selected} roll fails. So feed whatever number you want into the timeout block, the code will then proceed and if the .then() has executed during the timeout, we'll have a selectedRoll to process, otherwise undefined. The rest of your code can continue as usual. Now that I look at it, if I was going to use this trick in a few places it would be a nice place to use Promise.race() ... Oh, and this does nothing for the Roll20 "nothing selected" error - it only appears for the player clicking the button, but I don't think you can suppress it without a CSS extension like Stylus.