mScriptBox Tutorial
$read without repeat

Written by pyretta{S}
Published with permission.

Table Of Contents

  1. Introduction
  2. The Main Script
  3. Improvements

1. Introduction  Back to Top

Okay, so you've got a bot, and put together some random funstuff... funny autogreets, a quote generator, insults, an 8ball (shudder), or some such... but all those non scripting ppl in your channel keep complaining when lines repeat and the spinning bottle points at the same person for the third time. And you're tired of explaining 'it's RANDOM, that means sometimes it will REPEAT.' Makes you want to test if those random kick msgs repeat too...

2. The Main Script  Back to Top

We can, however, read lines from a text file in random order, without repeating any lines till all have been used. To do this, instead of using the automatic random line selection of $read, we pick our own random line number to be read and put that number in a token string.

Hint: Open your mIRC help file and read the Token Identifier section to see how they work if you're not already familiar with them, they're handy or alternately read the Token Tutorial

Then, before using a line, we check to see if that line's number is already in the token string... if it is, we pick another~:o}
The command for calling it is /norepeat <textfile.ext>

alias norepeat {
  VAR %da.file = $$1
  ;first, set %da.file (da text file, to be exact). we use $$1 
  ;so the script will halt without that parameter, since it's 
  ;needed if the rest is to work, and we make it a local variable to 
  ;so we don't have to worry about unsetting later

  ;set the label for the goto loop

  VAR %da.line = $rand(1, $lines(%da.file))
  ;randomly select a line number between 1 and the number of lines in the file

  IF ($istok(%norepeat,%da.line,32)) { GOTO loop }
  ;if the selected line # exists as a token in the string in %norepeat, or
  ;in other words has already been read, goto loop and pick a new one. 
  ;no need to set %norepeat first, if it's empty the if will be evaluated 
  ;as $false and that's just as it should be~:o}

  SET %norepeat $addtok(%norepeat,%da.line,32)
  ;now we add the line just read to the token string, our list of what's been
  ;read already. this is the only variable we're not making local, since it 
  ;needs to have a 'memory' of what's been used before

  IF ($numtok(%norepeat,32) = $lines(%da.file)) { UNSET %norepeat }
  ;if the number of tokens in the string (number of lines read) = the number 
  ;of lines in the file, we empty the token string, so the fun can begin all 
  ;over again~:o}

  msg $chan $read -l $+ %da.line %da.file
  ;the selected line is msgd to the channel. 

3. Improvements  Back to Top

Now, that's all very well and good if your bot is responding with a witty saying to an on *:TEXT:whatever:#: event, but what if you want to use it in a variety of ways?
You want to do random auto actions, for instance? And have them work in a query window, too?

We need a way to specify where the msg gets sent, and whether it should be a msg or an action.

So... we'll make a couple of switches, -m for msg, -d for action (d for the describe command). And we'll allow for an optional third parameter to specify where this action or msg should go, with a default of $chan. Our command syntax will now look like this:

/norepeat -dm textfile [#channelname/nick]

The < > indicates a required parameter, the [ ] denotes an optional one, and of course if the file is in your mircdir, you only need the filename.

Now our first couple of lines...

alias norepeat {
  VAR %da.file = $$1

...need to be changed so the variable is set to $$2, because of the new command structure we have.

alias norepeat {
  VAR %da.file = $$2
  VAR %da.line = $rand(1, $lines(%da.file) )
  IF ($istok(%norepeat,%da.line,32)) { GOTO loop }
  SET %norepeat $addtok(%norepeat,%da.line,32)
  IF ($numtok(%norepeat,32) = $lines(%da.file)) { UNSET %norepeat }
Everything up till here can stay the same. Now we add the new features:
IF ($3) { VAR %da.chan = $3}
  ;if you specified a channel or nick, puts it in the variable

  ELSE { VAR %da.chan = $chan }
  ;if no channel/nick specified, puts the default value $chan in the variable

  IF ($$1 == -d) { .describe %da.chan $read -l $+ %da.line %da.file }
  ;if the -d switch was used, send the line to the appropriate channel
  ;or nick as an action.  We use $$1 because if no switch is used and
  ;we let the script continue, the file to be searched would be the
  ;first parameter instead of the second, and we need it to be the second~:o}

  IF ($$1 == -m) { msg %da.chan $read -l $+ %da.line %da.file }
  ;otherwise, send it as a msg

Now there's still one use this doesn't work for... what if we don't want to send the random line to a channel, but instead use it in a script? Maybe you want to test those random kicks after all... we'll add one more switch, -s. For use in a remote script, it would be nice for this to work as an identifier that returns the random line that was selected, but the identifier won't accept parameters the way our alias does. So we simply have the -s switch set the line into a variable, and then we can call that variable from whatever script we like. The final lines of /norepeat now look like this:

  IF ($$1 == -d) { .describe %da.chan $read -l $+ %da.line %da.file  }
  IF ($$1 == -m) { msg %da.chan $read -l $+ %da.line %da.file }
  ELSE { SET -u60 %da.readline $read -l $+ %da.line %da.file }
  ;again building variable cleanup into it, this time with set -u. We can't use
  ;VAR %var = $read etc. because once the alias has finished parsing that variable
  ;won't exist any longer and so can't be called from the main script.