mIRC Home    About    Download    Register    News    Help

Print Thread
#266352 21/11/19 04:26 AM
Joined: Nov 2019
Posts: 2
N
Nimueh Offline OP
Bowl of petunias
OP Offline
Bowl of petunias
N
Joined: Nov 2019
Posts: 2
I'm very new to mIRC scripting. I've been searching around for something similar and haven't had any luck so far.

I'd like a script that'll return a random item from a list. i.e. !pick a, b, c, d, and it responds with a, b, c, or d, randomly. I've gotten to:

On *:TEXT:!pick *:#: {

And there I get stuck. I thought I should be using $gettok, but I can't seem to make that work. Ideally it would accept multi-word items that are separated by a comma. Could anyone help me out or point me in the right direction?

Nimueh #266355 21/11/19 05:27 PM
Joined: Jul 2006
Posts: 4,144
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,144
Inside on text, $1- is a space separated list of token, $2- is going to be your list of comma separated value.
You do have to use $gettok, with $2- as the input then, and you want to generate a random number from 1 to the total number of token (item in your list), you can get the total number of item in the list using $numtok
44 is the ascii number for comma (32 for space) so $numtok($2-,44) is how many items there is in the list specified in !pick.
You can use $rand (or just $r()) to get a random number between two numbers: $rand(1,$numtok($2-,44)) is going to be a random number between 1 and the number of item in the list.
All in all, you get $gettok($2-,$rand(1,$numtok($2-,44)),44) to get a random item in the list

Code
On *:TEXT:!pick *:#: {
msg $chan random item: $gettok($2-,$rand(1,$numtok($2-,44)),44)
}

The !pick * trigger could be improved as well; currently it triggers on "!pick " or anything not being a list of comma separated values.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Nimueh #266357 21/11/19 10:18 PM
Joined: Sep 2005
Posts: 2,881
H
Hoopy frood
Offline
Hoopy frood
H
Joined: Sep 2005
Posts: 2,881
Code
on *:text:!pick *:#:{
  msg # $gettok($2-,$rand(1,$numtok($2-,44)),44)
}


To help you understand how this works:

$2- is everything after !pick, so in your example $2- will contain "a, b, c, d"

$numtok($2-,44) - the "44" is the ASCII character code for a comma. This is telling the script to count how many "tokens" there are separated by a comma. The result in your example will be 4, because "a", "b", "c" and "d" are each a token separated by a comma.

$rand(1,$numtok($2-,44)) tells the script to generatea random number between 1 and the number of comma-separated tokens. In your example this will select a random number between 1 and 4.

This is then placed into a $gettok():

$gettok($2-,$rand(1,$numtok($2-,44)),44) - this tells the script to select a random comma-separated token. The first argument is the text you want to extract a token from (in this case - $2- - i.e. everything after "!pick"), the second argument is the number token you want to get (in this case a random number between 1 and the number of comma-separated tokens), and the final argument is the ASCII value for the character which separates the tokens (in this case - 44 - a comma).

If you can be bothered you might prefer to do something like this as it's more readable when you write a lot of code:

Code
on *:text:!pick *:#:{
  var %tokens = $2-, %randomnumber = $rand(1,$numtok(%tokens,44)), %randomtoken = $gettok(%tokens,%randomnumber,44)
  msg # %randomtoken
}


This uses variables with descriptive names to show you what each variable is being set to. When you return to a large complex script long after you have written it, it can assist you if you use variables with descriptive names throughout your code.

A different way of doing this is to just use parameter identifiers without bothering with $gettok:

Code
on *:text:!pick *:#:{
  tokenize 44 $2- 
  msg # $eval($ $+ $rand(1,$0),2)
}


This is a bit complicated to explain if you're new to scripting, but just showing you there are many methods to accomplish the same thing.

Hope that makes sense.

Last edited by hixxy; 21/11/19 10:24 PM.
hixxy #266362 23/11/19 12:24 AM
Joined: Nov 2019
Posts: 2
N
Nimueh Offline OP
Bowl of petunias
OP Offline
Bowl of petunias
N
Joined: Nov 2019
Posts: 2
Aaaah, thank you so much, hixxy and Wims! I was trying to use either $gettok or $rand and hadn't wrapped my head around nesting them like that. So first you have to tell it to number the items in the list, then to pick one of those at random, then to /msg the item associated with the number drawn. That makes a lot of sense.

hixxy, on the last one you had:
Code
on *:text:!pick *:#:{
  tokenize 44 $2- 
  msg # $eval($ $+ $rand(1,$0),2)
}

Could you elaborate a bit more on the $eval section of that? It's randomizing from 1-(number of tokens based on tokenize), then evaluating $(chosen random number) twice and messaging it to the channel? Why twice? and why do you put the $ in front of the randomized number, does that refer it back to the bit of text assigned to that number?



So say I then wanted to expand on this and add some variable text for before the picked item. I typed up the following, and it seems to be working. Would there be a "better practice" way of writing it though? It helps me a lot to see some different ways to approach the same thing, so thank you for including that hixxy smile
Code
on *:text:!pick *:#:{
  var %tokens = $2-, %randomnumber = $rand(1,$numtok(%tokens,44)), %randomtoken = $gettok(%tokens,%randomnumber,44)
  var %randomintro $rand(1,4) 
  if (%randomintro == 1) { /timer 1 1 /msg # Definitely %randomtoken } 
  if (%randomintro == 2) { /timer 1 1 /msg # Those are terrible choices, but go with %randomtoken } 
  if (%randomintro == 3) { /timer 1 1 /msg # Yeah, sorry, I can't condone any of those. Try something else later. } 
  if (%randomintro == 4) { /timer 1 1 /msg # Ehhhh. I guess %randomtoken } 

}


Last edited by Nimueh; 23/11/19 12:44 AM.
Nimueh #266381 25/11/19 08:21 PM
Joined: Sep 2005
Posts: 2,881
H
Hoopy frood
Offline
Hoopy frood
H
Joined: Sep 2005
Posts: 2,881
Hi,

I think you pretty much got it already but just to clarify:

$eval(..., N) allows you to evaluate "..." N times.

So $eval($ $+ $rand(1,$0),1) would only evaluate it once. That means it would return the literal text "$1" (assuming the $rand returned 1)

If you evaluate it a second time then it passes through a second time and returns whatever the $1 token is.

Your script contains an exploit as /timer evaluates everything twice. You should never pass unknown content to /timer without wrapping it in $unsafe() :

Code
 on *:text:!pick *:#:{
  var %tokens = $2-, %randomnumber = $rand(1,$numtok(%tokens,44)), %randomtoken = $gettok(%tokens,%randomnumber,44)
  var %randomintro $rand(1,4) 
  if (%randomintro == 1) { /timer 1 1 /msg # Definitely $unsafe(%randomtoken) } 
  if (%randomintro == 2) { /timer 1 1 /msg # Those are terrible choices, but go with $unsafe(%randomtoken) } 
  if (%randomintro == 3) { /timer 1 1 /msg # Yeah, sorry, I can't condone any of those. Try something else later. } 
  if (%randomintro == 4) { /timer 1 1 /msg # Ehhhh. I guess $unsafe(%randomtoken) } 

}


If you leave it as is then people will be execute commands remotely on your machine or try and read sensitive variables and identifiers.


Link Copied to Clipboard