Assembla home | Assembla project page
 

root/trunk/Phergie/Plugin/Dice.php

Revision 242, 5.7 kB (checked in by Slynderdale, 6 months ago)

Fixed a couple tiny bugs in Dice and PHP

Line 
1 <?php
2
3 /**
4  * Checks incoming requests for dice/roll requests and processes the message for
5  * the dice arguments and reponds with a message containing the dice results.
6  */
7 class Phergie_Plugin_Dice extends Phergie_Plugin_Abstract_Command
8 {
9
10     /**
11      * Whether or not to allow parsing of expressions
12      *
13      * @var bool
14      */
15     protected $allowExpressions = true;
16
17     /**
18      * An array containing the max values for the given dice iterations, number
19      * of dice and sides.
20      *
21      * @var array
22      */
23     protected $max = array(
24         'total' => 20,
25         'dice' => 100,
26         'sides' => 100
27     );
28
29     /**
30      * Holds the allowed characters and operators
31      *
32      * @var array
33      */
34     protected $allowed = array
35     (
36         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
37         '+', '-', '/', '*', ' ', '<<', '>>', '%', '&', '^', '|', '~'
38     );
39
40
41     /**
42      * Processes a request to perform a calculations on an expression.
43      *
44      * @param string $expr Expression to evaluate
45      * @return void
46      */
47     protected function processExpression($expr)
48     {
49         // Clean up the expression
50         $expr = str_replace('\\', '/', preg_replace('/\s/', '', $expr));
51
52         // Parse equation
53         $out = '';
54         $ptr = 1;
55         while (strlen($expr) > 0) {
56             $substr = substr($expr, 0, $ptr);
57             // Allowed string
58             if (array_search($substr, $this->allowed) !== false) {
59                 $out .= $substr;
60                 $expr = substr($expr, $ptr);
61                 $ptr = 0;
62             // Parse error if we've consumed the entire equation without finding anything valid
63             } elseif ($ptr >= strlen($expr)) {
64                 return null;
65             } else {
66                 $ptr++;
67             }
68         }
69         $res = @eval('return ' . $out . ';');
70         if ($res === false) {
71             return null;
72         } else {
73             return $res;
74         }
75     }
76
77     /**
78      * Processes a request to perform dice rolls from a given message as well as
79      * prcessessing an optional expression that gets added to the final dice
80      * tota;
81      * Dice Syntax: [<number>[#| ]]<dice>d<sides>[[+|-]<expresion>]
82      *
83      * @param string $message Message to processes
84      * @return void
85      */
86     protected function processDice($message, $recursive = false)
87     {
88         $message = trim($message);
89         if (!empty($message)) {
90             if (preg_match('{^(?:([0-9]+)[\#|:|\s])?(?:([0-9]+)[\s|d])?(?:[\s|d]?([0-9]+))(?:([+\*-])([^\s]*))?(.*)?$}ix', $message, $m)) {
91                 $numDice = ($m[1] < 1 ? 1 : ($m[1] > $this->max['total'] ? $this->max['total'] : $m[1]));
92                 $dice = ($m[2] < 1 ? 1 : ($m[2] > $this->max['dice'] ? $this->max['dice'] : $m[2]));
93                 $sides = ($m[3] < 1 ? 1 : ($m[4] > $this->max['sides'] ? $this->max['sides'] : $m[3]));
94                 $operator = trim($m[4]);
95                 $expression = ((isset($m[5]) && !empty($m[5])) ? trim($m[5]) : '0');
96                 $description = rtrim(trim($m[6]), '+-/*<>%&^|~');
97                 $diceMessage = ($numDice > 1 ? $numDice . '#' : '') . $dice . 'd' . $sides . (!empty($operator) && !empty($expression) ? $operator . $expression : '');
98
99                 $bonus = 0;
100                 if (!empty($expression) && $this->allowExpressions) {
101                     $expression = preg_replace('/((?:[0-9]+)?d[0-9]+(?:[+\*-][^\s]+)?)/e', '$this->processDice("\\1", true)', $expression);
102                     $bonus = $this->processExpression($expression);
103                     if (is_null($bonus)) {
104                         return ($recursive ? null : 'Error while processing the dice expression.');
105                     }
106                 }
107
108                 $output = array();
109                 for ($i = 0; $i < $numDice; $i++) {
110                     $total = 0;
111                     for ($d = 0; $d < $dice; $d++) {
112                         $total += mt_rand(1, $sides);
113                         switch ($operator) {
114                             case '+': $total += $bonus; break;
115                             case '-': $total -= $bonus; break;
116                             case '*': $total *= $bonus; break;
117                         }
118                     }
119                     $output[] = $total;
120                 }
121                 return ($recursive ? implode('+', $output) : 'Rolls a ' . $diceMessage . (!empty($description) ? ' ' . $description : '') . ' and gets ' . implode(', ', $output) . '.');
122             }
123         }
124         return false;
125     }
126
127     /**
128      * Forwards the dice/roll commands onto a central handler.
129      *
130      * @return void
131      */
132     public function onDoRoll($message)
133     {
134         $source = $this->event->getSource();
135         $target = $this->event->getNick();
136
137         if ($result = $this->processDice($message)) {
138             $this->doPrivmsg($source, $target . ': ' . $result);
139         }
140     }
141
142     /**
143      * Forwards the dice/roll commands onto a central handler.
144      *
145      * @return void
146      */
147     public function onDoDice($message)
148     {
149         $source = $this->event->getSource();
150         $target = $this->event->getNick();
151
152         if ($result = $this->processDice($message)) {
153             $this->doPrivmsg($source, $target . ': ' . $result);
154         }
155     }
156
157     /**
158      * Proccesses incoming CTCP request for the CTCP request DICE or ROLL and
159      * returns the dice results.
160      *
161      * @return void
162      */
163     public function onCtcp()
164     {
165         $source = $this->event->getSource();
166         $ctcp = strtoupper($this->event->getArgument(1));
167         list($ctcp, $message) = array_pad(explode(' ', $ctcp, 2), 2, null);
168
169         if (($ctcp == 'DICE' || $ctcp == 'ROLL') and $result = $this->processDice($message)) {
170             $this->doCtcpReply($source, $ctcp, $result);
171         }
172     }
173 }
174
Note: See TracBrowser for help on using the browser.