Mercurial > traipse_dev
comparison orpg/dieroller/dieroller.txt @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | bf799efe7a8a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 The New Dicing System: A Proposal for OpenRPG | |
2 ---------------------------------------------- | |
3 | |
4 The current dice system for OpenRPG has several limitations. Foremost | |
5 among these are the fact that adding a new, non-standard dicing mechanism | |
6 requires editing of the basic dice code. There are several secondary | |
7 limitations, such as the fact that while the dice system can handle math, | |
8 it cannot be used as a calculator -- it will not allow expressions that do | |
9 not involve dice. | |
10 | |
11 This proposal is for a new dicing system to replace the current one in | |
12 OpenRPG. Since the dicing system is something that users will interact | |
13 with frequently, a new system needs to be considered carefully. This | |
14 document attempts to describe the new dicing system so that such | |
15 consideration can be given to it. It is expected that this document will | |
16 grow and change as it is scrutinized. | |
17 | |
18 | |
19 Design goals for this dicing system: | |
20 | |
21 1. Should be easy for new users to get started with, based on knowing | |
22 standard RPG dice notation (NdX) and basic math. | |
23 | |
24 2. Should, as far as practical, maintain compatibility with existing | |
25 character sheets, etc., that use the current dice system. | |
26 | |
27 3. Should allow users to create new dice types and new ways of | |
28 counting dice. Ideally, this should not require programming, except | |
29 in exceptional cases. | |
30 | |
31 4. The dice system should be usable for doing basic math that does | |
32 not involve dice. | |
33 | |
34 5. The dice system should be able to handle most current RPG dicing | |
35 systems. | |
36 | |
37 Things this dicing system is designed to NOT do: | |
38 | |
39 1. Be a programming language. There are no facilities in it for | |
40 user input, output formatting, loops, if-then-else, or similar | |
41 things. If these are desired for something involving dice, an | |
42 appropriate node and nodehandler can be created. | |
43 | |
44 2. Handle all theoretically possible dicing systems without the | |
45 need for programming plugins. First off, this is impossible. | |
46 Second, even making an attempt to would require supporting | |
47 dicing methods that don't actually turn up in any real game. | |
48 | |
49 3. Handle floating-point math. I don't know of any systems that | |
50 use it in their dice schemes right now. If there are some, | |
51 we might have to consider adding it. | |
52 | |
53 | |
54 Syntax Specification | |
55 | |
56 What follows is a BNF specification for the proposed dicing system, with | |
57 explanatory text interleaved. At the end of this document is a copy of | |
58 the BNF with no explanations, for those who would like to look at it "all | |
59 together". Note that BNF describes only syntax, and not semantics; thus, | |
60 while anything generated with this grammar should be syntactically correct, | |
61 that doesn't mean it will make sense or be allowed. | |
62 | |
63 | |
64 dice string ::= <expression> | |
65 <expression> of <comparison> | <comparison> | |
66 | |
67 This is the top level. The major thing of note here is that comparisons | |
68 only occur at this level. This is intentional; the result of a comparison | |
69 is a boolean true/false flag rather than a number. Thus, it makes no | |
70 sense to allow people to perform further numerical operations on the | |
71 result of a comparison. Systems where dice are triggered by the results | |
72 of other dice are left for the realm of plugins. | |
73 | |
74 | |
75 comparison ::= <expression> <relation> <expression> | |
76 | |
77 expression ::= <factor> | <factor> <low-op> <factor> | |
78 | |
79 The separation into "low-op" and "high-op" of the operators is to allow | |
80 order of operations to be handled more easily. Syntactically, it's not | |
81 really necessary, but it should be helpful in implementation. | |
82 | |
83 | |
84 factor :: = <term> | <term> <high-op> <term> | | |
85 <multi-dice> | <multi-dice> <high-op> <term> | | |
86 <term> <high-op> <multi-dice> | |
87 | |
88 Here we start to hit some complication. The intent of the different | |
89 entries for multi-dice is that we don't want to allow things like | |
90 [3d6 each * 2d6 each]. We are *not* doing vector multiplication! | |
91 The "expression" level doesn't have any such limitation on syntax; | |
92 things like [3d6 each + 2d6 each] we'll have to either think of a | |
93 logical way to handle, or disallow on a semantic level. (Well... I | |
94 suppose it could be handled in the BNF, but I think it would get | |
95 kind of messy.) | |
96 | |
97 | |
98 term ::= <dice> | <unit> | |
99 | |
100 unit ::= <number> | ( <expression> ) | |
101 | |
102 Dice are not considered a unit. This means that things like [3d6d10] can't | |
103 be done without using parentheses. I consider that to be a win for | |
104 clarity. | |
105 | |
106 | |
107 dice ::= <unit>d<unit> | <unit>d<name> | <dice> <flag> | lastroll | |
108 | |
109 The <name> entry here allows for user-created dice (in the syntax, at | |
110 least...). | |
111 | |
112 | |
113 multi-dice ::= ( <dice>, <dice>+ ) | # (1d6,1d8) | |
114 <dice> each | # 3d6 each | |
115 ( <expression> of <expression> ) | # (3 of 2d6) | |
116 lastroll | # lastroll | |
117 <multi-dice> <flag> # (3 of 2d6) best 2 | |
118 | |
119 "lastroll" by itself can be either dice or multi-dice. I'm thinking that it | |
120 | |
121 should be whatever type the last roll was. | |
122 | |
123 | |
124 flag ::= reroll <condition> | # repeats | |
125 reroll <slice> | # once only | |
126 grow <condition> | # reroll and add | |
127 shrink <condition> | # reroll and subtract | |
128 drop <condition> | | |
129 drop <slice> | | |
130 take <condition> | | |
131 take <slice> | | |
132 <slice> | # implied "take" | |
133 <name> <condition> | # user-created | |
134 <name> # user-created | |
135 | |
136 Technically, we don't need both "drop" and "take" -- one implies the | |
137 other. However, having both should make the language easier to use. | |
138 | |
139 "reroll" will work differently depending on whether a condition or a | |
140 slice is given. If a condition is given, it will reroll until none of | |
141 the dice in the set meet the reroll condition (or until it hits a maximum | |
142 allowed number of rerolls). If a slice is given, it will reroll those | |
143 dice once. IMHO, this behavior makes the most sense. | |
144 | |
145 The <name> entries here are to allow for user-created flags. Note that | |
146 as I've specified things right now, a user-created flag can have a | |
147 condition, | |
148 but not a slice. That's mostly because I couldn't think of a case where | |
149 a slice would be useful... should we add it anyways? | |
150 | |
151 | |
152 slice ::= highest | lowest | highest <number> | lowest <number> | |
153 | |
154 "highest" and "lowest" without a number are equivalent to doing them with | |
155 1 as the number. This is to simplify things like [4d6 drop lowest]. | |
156 | |
157 | |
158 condition ::= <relation> <unit> | |
159 | |
160 This is for conditions on flags. Note that it can take a unit, so you could | |
161 | |
162 use dice in a condition; however, I think the unit should only be evaluated | |
163 | |
164 once, to make things faster. Anyone for repetitive evaluation? | |
165 | |
166 | |
167 low-op ::= + | - | min | max | |
168 | |
169 "min" takes two values and returns the highest of them, and "max" | |
170 returns the lowest of them. This might seem counterintuitive, but | |
171 it's meant to be used with dice, like so: | |
172 | |
173 3d6 min 8 - always returns 8 or higher | |
174 | |
175 3d6 max 15 - always returns 15 or lower | |
176 | |
177 I decided to put min and max as having the same precedence as + and -, | |
178 because if they had higher precedence, then: | |
179 | |
180 3d6+2 min 10 | |
181 | |
182 would be equivalent to 3d6+10. (It would take the max of 2 and 10, then | |
183 add that to 3d6). One problem that does arise here is with multiplication | |
184 and division: [1d6 min 5 * 2] will be equivalent to [1d6 min 10], since | |
185 multiplication has higher precedence. We may just want to warn people | |
186 that min and max can be screwy unless you parenthesize, unless someone can | |
187 think of a better way to handle them. | |
188 | |
189 | |
190 high-op ::= * | / | mod | |
191 | |
192 The / is integer division, of course, since we're doing integer math. | |
193 | |
194 | |
195 number ::= <digit>+ | -<digit>+ | |
196 | |
197 Positive and negative numbers are allowed. This means that, syntactically, | |
198 [-2d-4] is legal. Do we want to modify the BNF to disallow this, or handle | |
199 it on a semantic level? | |
200 | |
201 | |
202 name ::= <letter>[<letter>|<digit>]* | |
203 | |
204 We may want to expand to allow underscores and dashes in user-created names. | |
205 | |
206 | |
207 | |
208 letter ::= A-Z | a-z | |
209 | |
210 digit ::= 0-9 | |
211 | |
212 relation ::= < | > | <= | >= | => | =< | = | == | |
213 | |
214 | |
215 | |
216 Well, that's the BNF. Again, at the end is a copy without all the running | |
217 commentary. | |
218 | |
219 | |
220 Thoughts on Implementation: | |
221 | |
222 First, I think a sort of "dice library" of common functions needs to be | |
223 created. This would include rolling a set of dice, getting the highest | |
224 of a group of dice, growing and shrinking dice from a set based on | |
225 conditions, and so on. These functions should be available for use by | |
226 custom-written dice types. | |
227 | |
228 Next, that library should be used as a tool in implementing a dice-string | |
229 interpreter. That will require creating a parser for the dice-string | |
230 'language'. This could be either a custom-written parser, or possibly | |
231 one created with some of the Python parser generators. A custom-written | |
232 parser may take longer to do and be a bit more finicky to maintain, but | |
233 it would remove a dependency from the code. | |
234 | |
235 User-created flags and dice types could be supported in two ways: | |
236 | |
237 - First, by allowing users to specify strings in the dice language | |
238 that the flags/expressions would expand to -- basically, allowing | |
239 dice macros. | |
240 | |
241 - Second, by adding hooks for python modules to be associated with | |
242 user-created dice or flag types. This is likely to be the more | |
243 complicated of the two solutions, but it would also be more | |
244 flexible. | |
245 | |
246 Personally, I think both are desirable -- the first, so that | |
247 non-programming users can create simple die and flag types. The | |
248 second, because by design, there are some things this dice system | |
249 just won't do. | |
250 | |
251 | |
252 Further work needed: | |
253 | |
254 - specs for the "dice library" | |
255 | |
256 - specs on an interface for python modules meant to be dice and | |
257 flag types. | |
258 | |
259 ---------------------------------------------------------------- | |
260 | |
261 start ::= <expression> | | |
262 <comparison> | |
263 | |
264 comparison ::= <expression> <condition> | |
265 | |
266 expression ::= <term> | <term> <low-op> <factor> | |
267 | |
268 term ::= <factor> | <factor> <high-op> <unit> | |
269 | |
270 factor ::= <atom> | <dice_set> | |
271 | |
272 atom ::= <number> | ( <expression> ) | |
273 | |
274 dice_set ::= <dice> <dice_set>, <dice> | <expr> of <dice> | <dice> each | | |
275 lastroll | |
276 | |
277 dice ::= <atom>d<atom> | <atom>d<name> | <dice> <flag> | |
278 | |
279 flag ::= reroll <condition> | | |
280 reroll <slice> | | |
281 grow <condition> | | |
282 shrink <condition> | | |
283 drop <condition> | | |
284 drop <slice> | | |
285 take <condition> | | |
286 take <slice> | | |
287 <slice> | | |
288 <name> <condition> | | |
289 <name> <slice> | | |
290 <name> | |
291 | |
292 slice ::= highest | lowest | highest <number> | lowest <number> | |
293 | |
294 condition ::= <relation> <unit> | |
295 | |
296 low-op ::= + | - | |
297 | |
298 high-op ::= * | / | mod| max | min | |
299 | |
300 number ::= <digit>+ | -<digit>+ | |
301 | |
302 name ::= <letter>[<letter>|<digit>]* | |
303 | |
304 letter ::= A-Z | a-z | |
305 | |
306 digit ::= 0-9 | |
307 | |
308 relation ::= < | > | <= | >= | => | =< | = | == | |
309 |