All pastes #1287600 Raw Edit

mIRC Script for D6 System

public text v1 · immutable
#1287600 ·published 2008-12-17 12:15 UTC
rendered paste body
/*
********************************************************************************
mIRC Script for the D6 System
by Jeremy T. Gibson
********************************************************************************

This script is designed to provide a simple "!d6" function which takes a
sentence and reads any and all dice codes and pips from that statement.  It
then converts all of the numbers into a single dice throw, which it rolls
automatically.

The dice thrower deliberately does not roll any dice other than six-sided dice.
This is because the snippet is designed for West End Games' D6 System, which has
very specific rules on how the dice work.

If the first die (the wild die, marked with an asterisk) comes up as a 6, it
automatically adds the bonus throws to the total.

It also uses the standard complication rule for throwing a 1 on the wild die: if
throwing a 6 on 1D, a complication occurs -- otherwise a standard penalty occurs
equal to subtracting the wild die (1) and the highest die already thrown.

It matches all strings of the following formats:

1 - adds one pip
+1 - adds one pip
-1 - subtracts one pip

P1 - adds one pip
P+1 - adds one pip
P-1 - subtracts one pip

1D - adds three pips (1D)
+1D - adds three pips (1D)
-1D - subtracts three pips (1D)
(D can be uppercase or lowercase, and can be followed by a 6 (which is ignored))

1D+1 - adds four pips (1D+1)
1D-1 - adds two pips (0D+2)
+1D+1 - adds four pips (1D+1)
+1D-1 - adds two pips (0D+2)
-1D+1 - subtracts four pips (1D+1)
-1D-1 - subtracts two pips (0D+2)

Each die is worth three pips, and pips are always converted into dice if it is
possible to do so.  Adding 1D+1 plus 2D+2 comes to a total of 4D, not 3D+3!

"Bonus ranks" can also be added.  Unlike pips, these are added/subtracted
directly to/from the final total.  Just don't forget that you MUST use either
a leading B or a leading R to denote a bonus; otherwise it's assumed it's a
pip!

B1 - adds one bonus
B+1 - adds one bonus
B-1 - subtracts one bonus

R1 - adds one bonus
R+1 - adds one bonus
R-1 - subtracts one bonus

Example: !d6 5D+1 2D +1 +1 R+10
Parses: 5D+1, 2D, +2 pips, +10 bonus
Resulting roll: 8D+10.

********************************************************************************

Here is a mock sample of the script's use and output:

#OOC <Plae-Yer> !d6 Okay, I'm shooting my blaster at him. I have 5D+1 to hit...
#OOC <D6Bot> (Plae-Yer) Your 5D+1 roll comes to: 21 [3*,6,5,1,5]+1
#OOC <Djee-Em> That's good enough for me, and he wasn't dodging, either... Roll
         for damage!
#OOC <Plae-Yer> !d6 Smack that bugger with 5D!
#OOC <D6Bot> (Plae-Yer) Your 5D roll comes to: 17 [3*,5,6,2,1]
#OOC <Djee-Em> Even if he had armour, that guy doesn't have much of a chance, so
         I'm not gonna bother rolling.
#RP <Djee-Em> ACTION: The blaster strikes the bounty hunter square in the chest.
         He slumps over pathetically, a smoking ruin where his internal organs
         should be.
#RP <Plae-Yer> May the Force be with you. ::spits in the bounty hunter's eye::
#OOC <Djee-Em> LOL!  Should that count as a Dark Side Point? ;-)

********************************************************************************

Here are all of the functions you can use:

(In a public channel)
!d6 [sentence]
    Totals all of the dice codes in the sentence and causes the bot/script owner
    to say them out loud.
!privd6 [sentence]
    Totals all of the dice codes in the sentence and obviously shares the
    sentence itself in the channel, but sends the results to you via a notice.
    Generally only the gamemaster should use this command.

(In a query window to the bot/script owner -- even if you are the script owner!)
!d6 [sentence]
    Totals all of the dice codes in the sentence and returns the results in the
    private window, with no redundant echoing if talking to yourself!

********************************************************************************

Known issues:

* All punctuation on either side of the dice codes in a string is ignored now,
  with the unfortunate exception of the bonus pips ("P+10", "+2", "-8", etc.).
  Any pip bonus or penalty which includes *leading* punctuation will not be
  parsed (e.g., "!d6 ...+10" will produce no results).  Trailing punctuation is
  acceptable ("!d6 5D +10..." will properly parse as 8D+1).

* Periodically, whenever a match is not found for a string that looks like a
  dice string, mIRC will interpret the "0" of "return 0" in the $pipsgained proc
  as a command for whatever reason, producing "unknown command: 0" in mIRC's
  status window.  The reason this is so strange is because the value is clearly
  being assigned to the %pips variable, so there's no way it should be
  evaluating as a command.  I am convinced this is a bug with mIRC.

********************************************************************************
*/

alias d6 {
  ;Ignore if not provided enough messages
  if ( $0 == 0 ) {
    return
  }

  var %i = 0
  %d6.piptotal = 0
  %d6.bonus = 0

  var %matches = 0

  ;Loop through every parameter, checking to see if that parameter contains a die
  ; code.
  :d6loopstart
  inc %i
  var %param = $gettok($1-, %i, 32)

  var %match = $regex(%param, \b[BPRbpr]?[\+\-]?\d+[Dd]?6?[\+\-]?\d*\b )
  if ( %match == 1 ) {
    ;/echo Matched param %i $+ !
    var %pips = $pipsgained(%param)
    
    ;/echo DBG: matched %param with value of %pips
    if ( %pips != 0 ) {
      %d6.piptotal = $calc(%d6.piptotal + %pips)
      inc %matches
    }
    else {
      var %bonuses = $bonus(%param)
      if ( %bonuses > 0 ) {
        %d6.bonus = $calc(%d6.bonus + %bonuses)
        inc %matches
      }
    }
  }
  if ( %i < $0 ) goto d6loopstart

  if ( %matches == 0 ) {
    $reportmsg( ( $+ $nick $+ ) Um... there were no dice there. )
    halt
  }

  if ( %d6.piptotal <= 0 && %d6.bonus <= 0 ) {
    $reportmsg( ( $+ $nick $+ ) Total is less than 0D!  Automatic failure! )
    halt
  }
  elseif ( %d6.piptotal > 150 ) {
    ;Sanity check
    $reportmsg( ( $+ $nick $+ ) You're kidding $+ $chr(44) right? )
    halt
  }

  $rolld6( %d6.piptotal )

  $reportmsg( ( $+ $nick $+ ) Your %d6.string roll comes to: %d6.total $&
      %d6.results $+ %d6.bonus )

  var %complication = 0

  if ( %d6.wild == 6 ) {
    $rollwild()
    %d6.total = %d6.total + %d6.wildtotal
    $reportmsg( ( $+ $nick $+ ) The wild die gives you a bonus of $&
        %d6.wildtotal %d6.wildresults $+ !  Final score is %d6.total $+ ! )
  }
  elseif ( %d6.wild == 1 ) {
    if ( $rollforcomplication() ) {
      $reportmsg( ( $+ $nick $+ ) Uh oh!  There's a complication! )
    }
    else {
      var %penalty
      %penalty = $calc(%d6.highroll + 1)
      if ( %penalty <= 1 ) halt
      %d6.total = %d6.total - %penalty
      $reportmsg( ( $+ $nick $+ ) Uh oh!  There's a %penalty point penalty! $&
          ...Final score is %d6.total $+ ! )
    }
  }
}

alias bonus {
  var %string = $1

  ;Check as a positive rank bonus:
  var %match = $regex(bonus, $1, \b[BRbr]\+?(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a positive rank bonus
    return $regml(bonus, 1)
  }
  
  ;Check as a negative rank bonus:
  var %match = $regex(penalty, $1, \b[BRbr]\-(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a negative rank penalty
    return $regml(penalty, 1)
  }
}

alias pipsgained {
  var %string = $1

  ;Check as a positive dice bonus with additional pips:
  var %match = $regex(posdicewithpips, %string, \b\+?(\d+)[Dd]6?([\+|\-])(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a positive number of dice with a bonus/penalty
    var %dice = $regml(posdicewithpips, 1)
    var %operand = $regml(posdicewithpips, 2)
    var %pips = $regml(posdicewithpips, 3)

    ;Operand is a plus symbol?
    if ( %operand == $chr(43) ) {
      var %piptotal = $calc( [ %dice * 3 ] + %pips)
      return %piptotal
    }
    else {
      var %piptotal = $calc( [ %dice * 3 ] - %pips)
      return %piptotal
    }
  } ;end if %match != 0

  ;Check as a negative dice bonus with additional pips:
  var %match = $regex(negdicewithpips, %string, \b\-(\d+)[Dd]6?([\+|\-])(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a negative number of dice with a bonus/penalty
    var %dice = $regml(negdicewithpips, 1)
    var %operand = $regml(negdicewithpips, 2)
    var %pips = $regml(negdicewithpips, 3)

    ;Operand is a plus symbol?
    if ( %operand == $chr(43) ) {
      var %piptotal = $calc( [ %dice * -3 ] - %pips)
      return %piptotal
    }
    else {
      var %piptotal = $calc( [ %dice * -3 ] + %pips)
      return %piptotal
    }
  } ;end if %match != 0

  ;Check as a positive dice bonus:
  var %match = $regex(posdice, %string, \b\+?(\d+)[Dd]6?\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a positive number of dice
    return $calc($regml(posdice, 1) * 3)
  }

  ;Check as a negative dice penalty:
  var %match = $regex(negdice, %string, \b\-(\d+)[Dd]6?\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a negative number of dice
    return $calc($regml(negdice, 1) * -3)
  }

  ;Check as a positive pip bonus:
  var %match = $regex(bonus, %string, ^[Pp]?\+?(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a positive bonus
    return $regml(bonus, 1)
  }

  ;Check as a negative pip penalty:
  %match = $regex(penalty, %string, ^[Pp]?\-(\d+)\b )
  if ( %match == 1 ) {
    ;/echo DBG: $1 matched a negative penalty
    return $calc( 0 - $regml(penalty, 1) )
  }

  if ( %match == 0 ) {
    /echo DBG: No match found for $1!
    return 0
  }
}


alias rolld6 {
  var %fp = $1 / 3
  var %dice = $int(%fp)
  var %bonus = $1 % 3
  %bonus = $calc(%bonus + %d6.bonus)

  %d6.string = %dice $+ D
  if ( %bonus != 0 ) { %d6.string = %d6.string $+ $chr(43) $+ %bonus }

  unset %d6.total
  unset %d6.results
  unset %d6.wildtotal
  unset %d6.bonus

  %d6.highroll = 0
  %d6.wild = 0
  %d6.results = $chr(91)

  if ( %dice > 0 ) {
    ;/msg $chan DBG: rolling wild die
    %d6.wild = $rand(1,6)
    %d6.results = %d6.results $+ %d6.wild $+ $chr(42)
    %d6.total = %d6.wild

    ;/msg $chan DBG: finished wild die with ( %d6.wild %d6.results %d6.total %i )

    var %i = 1

    if ( %dice < 2 ) goto cancel
    :nextd6
    inc %i ;i should be 2 now

    ;/msg $chan DBG: rolling die %i

    var %roll = $rand(1,6)
    if ( %roll > %d6.highroll ) {
      %d6.highroll = %roll
    }

    %d6.results = %d6.results $+ $chr(44)
    %d6.results = %d6.results $+ %roll
    %d6.total = %d6.total + %roll

    if ( %i < %dice ) goto nextd6
    
    :cancel

    ;/msg $chan DBG: completed goto loop with %i (of %dice $+ )

  } ;end if %dice > 0

  %d6.results = %d6.results $+ $chr(93)

  if ( %bonus > 0 ) {
    %d6.bonus = $chr(43) $+ %bonus
    %d6.total = %d6.total + %bonus
  }
}

/*
If the /d6 procedure determines that the wild die has come up as a 6, then this
procedure is called to roll the bonus di(c)e.

There are two variables that are computed here: %d6.wildresults is a text string
consisting of an opening bracket, a series of comma-separated numbers, and a
closing bracket; %d6.wildtotal is a single integer that is the total of all of
the numbers in the brackets.
*/
alias rollwild {
  ;This acts as a "do-while".

  ;Roll the first bonus!
  var %roll = $rand(1,6)

  ;Instantiate: an opening bracket and the rolled number as a string...
  %d6.wildresults = $chr(91) $+ %roll
  ;...And the rolled number by itself as an integer.
  %d6.wildtotal = %roll

  ;If the first bonus came up as a six,
  ; loop until we come up with a roll that isn't a 6.
  while ( %roll == 6 ) {
    %roll = $rand(1,6)

    ;Append a comma and the roll to the results string.
    %d6.wildresults = %d6.wildresults $+ $chr(44) $+ %roll

    ;Add the the number to the total integer.
    %d6.wildtotal = %d6.wildtotal + %roll
  }

  ;Append the final closing bracket.
  %d6.wildresults = %d6.wildresults $+ $chr(93)
}

/*
This makes a simple roll to check to see whether a complication occurs,
returning "1" to mean "yes" or "0" to mean "no".  This value is checked by the
calling function (/d6) and a message is reported if the value is 1.
*/
alias rollforcomplication {
  if ( $rand(1,6) == 6 ) {
    return 1
  }
  return 0
}

/*
This script controls the "privacy codes" that the event handlers use.  Though it
should be obvious from reading the function itself, here is the extended
description.

Privacy 0 (default): Message is spoken aloud in the channel it was seen in.
Privacy 1 (private): Message is sent as a private message to the triggerer.
Privacy 2 (notice):  Message is sent as a private notice to the triggerer.
Privacy 3 (self):    Message is echoed to the window for the script owner only.
*/
alias reportmsg {
    if ( %d6.private == 3 ) /echo -t # %p $1-
    elseif ( %d6.private == 2 ) /notice $nick $1-
    elseif ( %d6.private == 1 ) /msg $nick $1-
    else /msg $chan $1-
}

; === EVENT HANDLERS ===

;Receiving an open statement -- say the result
on *:TEXT:!d6 *:#:{
  if ( %d6.enabled != 1 ) {
    /halt
  }
  %d6.private = 0
  /d6 $2-
  %unset %d6.private
}

;Receiving a private statement said publicly -- send the result as a notice
on *:TEXT:!privd6 *:#:{
  if ( %d6.enabled != 1 ) {
    /halt
  }
  %d6.private = 2
  /d6 $2-
  %unset %d6.private
}

;Receiving a statement in a private message -- send the result as a private message
on *:TEXT:!d6 *:?:{
  if ( %d6.enabled != 1 ) {
    /halt
  }
  %d6.private = 1
  /d6 $2-
  %unset %d6.private
}

;Receiving a direct notice  -- send a notice back
on *:NOTICE:!d6 *:#:{
  if ( %d6.enabled != 1 ) {
    /halt
  }
  %d6.private = 2
  /d6 $2-
  %unset %d6.private
}
on *:NOTICE:!privd6 *:#:{
  if ( %d6.enabled != 1 ) {
    /halt
  }
  %d6.private = 2
  /d6 $2-
  %unset %d6.private
}

;Using !d6 when in a channel -- say what was typed and share result
on *:INPUT:#:{
  if ($1 == !d6) {
    %d6.private = 0
    /say !d6 $2-
    /d6 $2-
    %unset %d6.private
    /halt
  }
}

;Using !privd6 when in a channel -- say what was typed and echo result to myself
on *:INPUT:#:{
  if ($1 == !privd6) {
    %d6.private = 3
    /say !d6 $2-
    /d6 $2-
    %unset %d6.private
    /halt
  }
}

;Using !d6 in a private window -- echo what was typed and echo result (no double-feedback)
on *:INPUT:?:{
  if ($1 == !d6) {
    %d6.private = 3
    $reportmsg( ( $+ $nick $+ ) !d6 $2- )
    /d6 $2-
    unset %d6.private
    /halt
  }
}