nerd_dice 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/main.yml +67 -0
- data/.rubocop.yml +114 -0
- data/CHANGELOG.md +76 -2
- data/Gemfile +2 -2
- data/Gemfile.lock +54 -32
- data/README.md +372 -5
- data/bin/generate_checksums +13 -0
- data/bin/nerd_dice_benchmark +322 -0
- data/certs/msducheminjr.pem +26 -0
- data/checksum/nerd_dice-0.1.0.gem.sha256 +1 -0
- data/checksum/nerd_dice-0.1.0.gem.sha512 +1 -0
- data/checksum/nerd_dice-0.1.1.gem.sha256 +1 -0
- data/checksum/nerd_dice-0.1.1.gem.sha512 +1 -0
- data/checksum/nerd_dice-0.2.0.gem.sha256 +1 -0
- data/checksum/nerd_dice-0.2.0.gem.sha512 +1 -0
- data/checksum/nerd_dice-0.3.0.gem.sha256 +1 -0
- data/checksum/nerd_dice-0.3.0.gem.sha512 +1 -0
- data/lib/nerd_dice/class_methods/configure.rb +50 -0
- data/lib/nerd_dice/class_methods/execute_die_roll.rb +47 -0
- data/lib/nerd_dice/class_methods/harvest_totals.rb +40 -0
- data/lib/nerd_dice/class_methods/refresh_seed.rb +83 -0
- data/lib/nerd_dice/class_methods/roll_ability_scores.rb +73 -0
- data/lib/nerd_dice/class_methods/roll_dice.rb +45 -0
- data/lib/nerd_dice/class_methods/total_ability_scores.rb +52 -0
- data/lib/nerd_dice/class_methods/total_dice.rb +44 -0
- data/lib/nerd_dice/class_methods.rb +30 -0
- data/lib/nerd_dice/configuration.rb +91 -0
- data/lib/nerd_dice/convenience_methods.rb +279 -0
- data/lib/nerd_dice/dice_set.rb +166 -0
- data/lib/nerd_dice/die.rb +51 -0
- data/lib/nerd_dice/sets_randomization_technique.rb +19 -0
- data/lib/nerd_dice/version.rb +1 -1
- data/lib/nerd_dice.rb +15 -33
- data/nerd_dice.gemspec +12 -7
- data.tar.gz.sig +0 -0
- metadata +97 -21
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -6
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
+
[](https://coveralls.io/github/statelesscode/nerd_dice?branch=master)
|
2
|
+

|
3
|
+
[](https://codeclimate.com/github/statelesscode/nerd_dice/maintainability)
|
1
4
|
# NerdDice
|
2
5
|
Nerd dice allows you to roll polyhedral dice and add bonuses as you would in a tabletop roleplaying game. You can choose to roll multiple dice and keep a specified number of dice such as rolling 4d6 and dropping the lowest for ability scores or rolling with advantage and disadvantage if those mechanics exist in your game.
|
3
6
|
|
7
|
+
## Educational Videos By Stateless Code
|
8
|
+
The end-to-end process of developing this gem has been captured as [instructional videos](https://www.youtube.com/playlist?list=PL9kkbu1kLUeOnUtMpAnJOCtHdThx1Efkt). The videos are in a one-take style so that the mistakes along the way have troubleshooting and the concepts used to develop the gem are explained as they are covered.
|
9
|
+
|
4
10
|
## Installation
|
5
11
|
|
6
12
|
Add this line to your application's Gemfile:
|
@@ -18,18 +24,379 @@ Or install it yourself as:
|
|
18
24
|
$ gem install nerd_dice
|
19
25
|
|
20
26
|
## Usage
|
27
|
+
After the gem is installed, you can require it as you would any other gem.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'nerd_dice'
|
31
|
+
```
|
32
|
+
|
33
|
+
### Module methods or a dynamic method_missing DSL
|
34
|
+
There are two main patterns for using NerdDice in your project. You can invoke the module-level methods like `NerdDice.total_dice` or you can include the `NerdDice::ConvenienceMethods` module to your class \(or IRB \). Once mixed in, you can dynamically invoke methods like `roll_d20_with_advantage` or `total_3d8_plus5`. See the [Convenience Methods Mixin](#convenience-methods-mixin) section for usage details.
|
35
|
+
|
36
|
+
### Configuration
|
37
|
+
You can customize the behavior of NerdDice via a configuration block as below or by assigning an individual property via the ```NerdDice.configuration.property = value``` syntax \(where ```property``` is the config property and ```value``` is the value you want to assign\)\. The available configuration options as well as their defaults, if applicable, are listed in the example configuration block below:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
NerdDice.configure do | config|
|
41
|
+
|
42
|
+
# number of ability scores to place in an ability score array
|
43
|
+
config.ability_score_array_size = 6 # must duck-type to positive Integer
|
44
|
+
|
45
|
+
# number of sides for each ability score Die
|
46
|
+
config.ability_score_number_of_sides = 6 # must duck-type to positive Integer
|
47
|
+
|
48
|
+
# total number of dice rolled for each ability score
|
49
|
+
config.ability_score_dice_rolled = 4 # must duck-type to positive Integer
|
50
|
+
|
51
|
+
# highest(n) dice from the total number of dice rolled
|
52
|
+
# that are included in the ability scoretotal
|
53
|
+
#
|
54
|
+
# CANNOT EXCEED ability_score_dice_rolled see Note below
|
55
|
+
config.ability_score_dice_kept = 3 # must duck-type to positive Integer
|
56
|
+
|
57
|
+
# randomization technique options are:
|
58
|
+
# :securerandom => Uses SecureRandom.rand(). Good entropy, medium speed.
|
59
|
+
# :random_rand => Uses Random.rand(). Class method. Poor entropy, fastest speed.
|
60
|
+
# (Seed is shared with other processes. Too predictable)
|
61
|
+
# :random_object => Uses Random.new() and calls rand()
|
62
|
+
# Medium entropy, fastest speed. (Performs the best under speed benchmark)
|
63
|
+
# :randomized =>
|
64
|
+
# Uses a random choice of the :securerandom, :rand, and :random_new_interval options above
|
65
|
+
config.randomization_technique = :random_object # fast with independent seed
|
66
|
+
|
67
|
+
# Number of iterations to use on a generator before refreshing the seed
|
68
|
+
# 1 very slow and heavy pressure on processor and memory but very high entropy
|
69
|
+
# 1000 would refresh the object every 1000 times you call rand()
|
70
|
+
config.refresh_seed_interval = nil # don't refresh the seed
|
71
|
+
# Background and foreground die colors are string values.
|
72
|
+
# By default these correspond to the constants in the class
|
73
|
+
# Defaults: DEFAULT_BACKGROUND_COLOR = "#0000DD" DEFAULT_FOREGROUND_COLOR = "#DDDDDD"
|
74
|
+
# It is recommended but not enforced that these should be valid CSS color property attributes
|
75
|
+
config.die_background_color = "red"
|
76
|
+
config.die_foreground_color = "#000"
|
77
|
+
end
|
78
|
+
```
|
79
|
+
**Note:** You cannot set `ability_score_dice_kept` greater than `ability_score_dice_rolled`. If you try to set `ability_score_dice_kept` higher than `ability_score_dice_rolled`, an error will be raised. If you set `ability_score_dice_rolled` _lower_ than the existing value of `ability_score_dice_kept`, no error will be thrown, but `ability_score_dice_kept` will be _**modified**_ to match `ability_score_dice_rolled` and a warning will be printed.
|
80
|
+
|
21
81
|
### Rolling a number of dice and adding a bonus
|
82
|
+
You can use two different methods to roll dice. The `total_dice` method returns an `Integer` representing the total of the dice plus any applicable bonuses. The `total_dice` method does not support chaining additional methods like `highest`, `lowest`, `with_advantage`, `with_disadvantage`. The `roll_dice` method returns a `DiceSet` collection object, and allows for chaining the methods mentioned above and iterating over the individual `Die` objects. `NerdDice.roll_dice.total` and `NerdDice.total_dice` are roughly equivalent.
|
83
|
+
|
22
84
|
```ruby
|
23
85
|
# roll a single d4
|
24
|
-
NerdDice.total_dice(4) # =>
|
86
|
+
NerdDice.total_dice(4) # => Integer: between 1-4
|
87
|
+
NerdDice.roll_dice(4) # => DiceSet: with one 4-sided Die with a value between 1-4
|
88
|
+
NerdDice.roll_dice(4).total # => Integer: between 1-4
|
25
89
|
|
26
90
|
# roll 3d6
|
27
|
-
NerdDice.total_dice(6, 3) =>
|
91
|
+
NerdDice.total_dice(6, 3) # => Integer: total of three 6-sided dice
|
92
|
+
NerdDice.roll_dice(6, 3) # => DiceSet: three 6-sided Die objects, each with values between 1-6
|
93
|
+
NerdDice.roll_dice(6, 3).total # => Integer: total of three 6-sided dice
|
28
94
|
|
29
95
|
# roll a d20 and add 5 to the value
|
30
|
-
NerdDice.total_dice(20,
|
96
|
+
NerdDice.total_dice(20, bonus: 5) # => Integer: roll a d20 and add the bonus to the total
|
97
|
+
NerdDice.roll_dice(20, bonus: 5) # => DiceSet: one 20-sided Die and bonus of 5
|
98
|
+
NerdDice.roll_dice(20, bonus: 5).total # => Integer: roll a d20 and add the bonus to the total
|
99
|
+
|
100
|
+
# without changing the config at the module level
|
101
|
+
# roll a d20 and overide the configured randomization_technique one time
|
102
|
+
NerdDice.total_dice(20, randomization_technique: :randomized) # => Integer
|
103
|
+
# roll a d20 and overide the configured randomization_technique for the DiceSet
|
104
|
+
# object will persist on the DiceSet object for subsequent rerolls
|
105
|
+
NerdDice.roll_dice(20, randomization_technique: :randomized) # => DiceSet with :randomized
|
106
|
+
```
|
107
|
+
__NOTE:__ If provided, the bonus must respond to `:to_i` or an `ArgumentError` will be raised
|
108
|
+
|
109
|
+
### Taking actions on the dice as objects using the DiceSet object
|
110
|
+
The `NerdDice.roll_dice` method or the `NerdDice::DiceSet.new` methods return a collection object with an array of one or more `Die` objects. There are properties on both the `DiceSet` object and the `Die` object. Applicable properties are cascaded from the `DiceSet` to the `Die` objects in the collection by default.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# These are equivalent. Both return a NerdDice::DiceSet
|
114
|
+
dice_set = NerdDice.roll_dice(6, 3, bonus: 2, randomization_technique: :randomized,
|
115
|
+
damage_type: 'psychic', foreground_color: '#FFF', background_color: '#0FF')
|
116
|
+
|
117
|
+
dice_set = NerdDice::DiceSet.new(6, 3, bonus: 2, randomization_technique: :randomized,
|
118
|
+
damage_type: 'psychic', foreground_color: '#FFF', background_color: '#0FF')
|
119
|
+
|
120
|
+
```
|
121
|
+
#### Available options for NerdDice::DiceSet objects
|
122
|
+
There are a number of options that can be provided when initializing a `NerdDice::DiceSet` object after specifying the mandatory number of sides and the optional number of dice \(default: 1\). The list below provides the options and indicates whether they are cascaded to the Die objects in the collection.
|
123
|
+
* `bonus` \(Duck-type Integer, _default: 0_\): Bonus or penalty to apply to the total after all dice are rolled. _**Not applied** to Die objects_
|
124
|
+
* `randomization_technique` \(Symbol, _default: nil_\): Randomization technique override to use for the `DiceSet`. If `nil` it will use the value in `NerdDice.configuration`. _**Applied** to Die objects by default with ability to modify_
|
125
|
+
* `damage_type` \(String, _default: nil_\): Optional string indicating the damage type associated with the dice for systems where it is relevant. _**Applied** to Die objects by default with ability to modify_
|
126
|
+
* `foreground_color` \(String, _default: `NerdDice.configuration.die_foreground_color`_\): Intended foreground color to apply to the dice in the `DiceSet`. Should be a valid CSS color but is not validated or enforced and doesn\'t currently have any real functionality associated with it. _**Applied** to Die objects by default with ability to modify_
|
127
|
+
* `background_color` \(String, _default: `NerdDice.configuration.die_background_color`_\): Intended background color to apply to the dice in the `DiceSet`. Should be a valid CSS color but is not validated or enforced and doesn\'t currently have any real functionality associated with it. _**Applied** to Die objects by default with ability to modify_
|
128
|
+
|
129
|
+
#### Properties of individual Die objects
|
130
|
+
When initialized from a `DiceSet` object most of the properties of the `Die` object are inherited from the `DiceSet` object. In addition, there is an `is_included_in_total` public attribute that can be set to indicate whether the value of that particular die should be included in the total for its parent `DiceSet`. This property always starts out as true when the `Die` is initialized, but can be set to false.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
# six sided die
|
134
|
+
die = NerdDice::Die.new(6, randomization_technique: :randomized, damage_type: 'psychic',
|
135
|
+
foreground_color: '#FFF', background_color: '#0FF')
|
136
|
+
die.is_included_in_total # => true
|
137
|
+
die.included_in_total? # => true
|
138
|
+
die.is_included_in_total = false
|
139
|
+
die.included_in_total? # => false
|
140
|
+
|
141
|
+
# value property
|
142
|
+
die.value # => Integer between 1 and number_of_sides
|
143
|
+
|
144
|
+
# Rolls/rerolls the Die, sets value to the result of the roll, and returns the new value
|
145
|
+
die.roll # => Integer.
|
146
|
+
```
|
147
|
+
#### Iterating through dice in a DiceSet
|
148
|
+
The `DiceSet` class mixes in the `Enumerable` module and the `Die` object mixes in the `Comparable` module. This allows you to iterate over the dice in the collection. The `sort` method on the dice will return the die objects in ascending value from lowest to highest.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
dice_set = NerdDice.roll_dice(6, 3) # => NerdDice::DiceSet
|
152
|
+
dice_set.dice => Array of Die objects
|
153
|
+
dice_set.length # => 3. (dice_set.dice.length)
|
154
|
+
dice_set[0] # => NerdDice::Die (first element of dice array)
|
155
|
+
# take actions on each die
|
156
|
+
dice_set.each do |die|
|
157
|
+
# print the current value
|
158
|
+
puts "Die value before reroll is #{die.value}"
|
159
|
+
# set the foreground_color of the die
|
160
|
+
die.foreground_color = ["gray", "#FF0000#", "#d9d9d9", "green"].shuffle.first
|
161
|
+
# reroll the die
|
162
|
+
die.roll
|
163
|
+
# print the new value
|
164
|
+
puts "Die value after reroll is #{die.value}"
|
165
|
+
# do other things
|
166
|
+
end
|
167
|
+
```
|
168
|
+
#### Methods and method chaining on the DiceSet
|
169
|
+
Since the DiceSet is an object, you can call methods that operate on the result returned and allow for things like the 5e advantage/disadvantage mechanic, the ability to re-roll all of the dice in the `DiceSet`, or to mark them all as included in the total.
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
##############################################
|
173
|
+
# highest/with_advantage and lowest/with_disadvantage methods
|
174
|
+
# assuming 4d6 with values of [1, 3, 4, 6]
|
175
|
+
##############################################
|
176
|
+
dice_set = NerdDice.roll_dice(6, 4)
|
177
|
+
|
178
|
+
# the 6, 4, and 3 will have is_included_in_total true while the 1 has it false
|
179
|
+
# Returns the existing DiceSet object with the changes made to dice inclusion
|
180
|
+
dice_set.highest(3) # => DiceSet
|
181
|
+
dice_set.with_advantage(3) # => DiceSet (Alias of highest method)
|
182
|
+
|
183
|
+
# calling total after highest/with_advantage for this DiceSet
|
184
|
+
dice_set.total # => 13
|
185
|
+
|
186
|
+
# same DiceSet using lowest.
|
187
|
+
# The 1, 3, and 4 will have is_included_in_total true while the 6 has it false
|
188
|
+
dice_set.lowest(3) # => DiceSet
|
189
|
+
dice_set.with_disadvantage(3) # => DiceSet (Alias of lowest method)
|
190
|
+
|
191
|
+
# calling total after lowest/with_disadvantage for this DiceSet
|
192
|
+
dice_set.total # => 8
|
193
|
+
|
194
|
+
# you can chain these methods (assumes the same seed as the above examples)
|
195
|
+
NerdDice.roll_dice(6, 4).with_advantage(3).total # => 13
|
196
|
+
NerdDice.roll_dice(6, 4).lowest(3).total # => 8
|
197
|
+
|
198
|
+
# reroll_all! method
|
199
|
+
dice_set = NerdDice.roll_dice(6, 4)
|
200
|
+
# rerolls each of the Die objects in the collection and re-includes them in the total
|
201
|
+
dice_set.reroll_all!
|
202
|
+
|
203
|
+
# include_all_dice! method
|
204
|
+
dice_set.include_all_dice! # resets is_included_in_total to true for all Die objects
|
205
|
+
```
|
206
|
+
|
207
|
+
### Rolling Ability Scores
|
208
|
+
You can call `roll_ability_scores` or `total_ability_scores` to get back an array of `DiceSet` objects or `Integer` objects, respectively. The `total_ability_scores` method calls `total` on each `DiceSet` and returns those numbers with one value per ability score. The `Configuration` object defaults to 6 ability scores using a methodology of __4d6 drop the lowest__ by default.
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
# return an array of DiceSet objects including info about the discarded dice
|
212
|
+
#
|
213
|
+
NerdDice.roll_ability_scores
|
214
|
+
#=> [DiceSet0, DiceSet1, ...]
|
215
|
+
# => DiceSet0 hash representation { total: 12, dice: [
|
216
|
+
# {value: 2, is_included_in_total: true},
|
217
|
+
# {value: 6, is_included_in_total: true},
|
218
|
+
# {value: 4, is_included_in_total: true},
|
219
|
+
# {value: 1, is_included_in_total: false}
|
220
|
+
# ]}
|
221
|
+
# if you want to get back DiceSet objects that you can interact with
|
222
|
+
|
223
|
+
# just return an array of totaled ability scores
|
224
|
+
NerdDice.total_ability_scores
|
225
|
+
#=> [12, 14, 13, 15, 10, 8]
|
226
|
+
```
|
227
|
+
|
228
|
+
Both methods can be called without arguments to use the values specified in `NerdDice.configuration` or passed a set of options.
|
229
|
+
```ruby
|
230
|
+
|
231
|
+
# total_dice and roll_dice take the same set of options
|
232
|
+
NerdDice.roll_ability_scores(
|
233
|
+
ability_score_array_size: 7,
|
234
|
+
ability_score_number_of_sides: 8,
|
235
|
+
ability_score_dice_rolled: 5,
|
236
|
+
ability_score_dice_kept: 4,
|
237
|
+
randomization_technique: :randomized,
|
238
|
+
foreground_color: "#FF0000",
|
239
|
+
background_color: "#FFFFFF"
|
240
|
+
)
|
241
|
+
# => [DiceSet0, DiceSet1, ...] with 7 ability scores that each roll 5d8 dropping the lowest
|
242
|
+
# or if called with total_ability_scores
|
243
|
+
# => [27, 17, 21, 17, 23, 13, 27]
|
244
|
+
```
|
245
|
+
**Note:** If you try to call this method with `ability_score_dice_kept` greater than `ability_score_dice_rolled` an error will be raised.
|
246
|
+
|
247
|
+
### Manually setting or refreshing the random generator seed
|
248
|
+
For randomization techniques other than `:securerandom` you can manually set or refresh the generator's seed by calling the `refresh_seed!` method. This is automatically called at the interval specified in `NerdDice.configuration.refresh_seed_interval` if it is not nil.
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
# no arguments, will refresh the seed for the configured generator(s) only
|
252
|
+
NerdDice.refresh_seed! # => hash with old seed(s) or nil if :securerandom
|
253
|
+
|
254
|
+
# OPTIONS:
|
255
|
+
# randomization_technique (Symbol) => NerdDice::RANDOMIZATION_TECHNIQUES
|
256
|
+
# random_rand_seed (Integer) => Seed to set for Random
|
257
|
+
# random_object_seed (Integer) => Seed to set for new Random object
|
258
|
+
NerdDice.refresh_seed!(randomization_technique: :randomized,
|
259
|
+
random_rand_seed: 1337,
|
260
|
+
random_object_seed: 24601)
|
261
|
+
```
|
262
|
+
__NOTE:__ Ability to specify a seed is primarily provided for testing purposes. This makes all random numbers generated _transparently deterministic_ and should not be used if you want behavior approximating randomness.
|
263
|
+
|
264
|
+
### Utility Methods
|
265
|
+
|
266
|
+
#### Harvesting Totals from DiceSets
|
267
|
+
The `harvest_totals` method take any collection of objects where each element responds to `total` and return an array of the results of the total method.
|
268
|
+
```ruby
|
269
|
+
ability_score_array = NerdDice.roll_ability_scores
|
270
|
+
# => Array of 6 DiceSet objects
|
271
|
+
|
272
|
+
# Arguments:
|
273
|
+
# collection (Enumerable) a collection where each element responds to total
|
274
|
+
#
|
275
|
+
# Return (Array) => Data type of each element will be whatever is returned by total method
|
276
|
+
totals_array = NerdDice.harvest_totals(totals_array)
|
277
|
+
# => [15, 14, 13, 12, 10, 8]
|
278
|
+
# yes, it just happened to be the standard array by amazing coincidence
|
279
|
+
```
|
280
|
+
<a name="convenience-methods-mixin"></a>
|
281
|
+
### Convenience Methods Mixin
|
282
|
+
NerdDice provides an optional mixin `NerdDice::ConvenienceMethods` that uses Ruby\'s `method_missing` metaprogramming pattern to allow you to roll any number of dice with bonuses and/or the advantage/disadvantage mechanic by dynamically responding to methods that you type that match the `roll_` or `total_` pattern.
|
283
|
+
|
284
|
+
#### Considerations for ConvenienceMethods
|
285
|
+
Before mixing in this method with a class, be aware of other `method_missing` gems that you are also mixing into your project and be sure to write robust tests. We have sought to use `method_missing` in a responsible manner that delegates back to the default implementation using `super` if the method does not match the `ConvenienceMethods` pattern, but there is no guarantee that other gems included in your project are doing the same. If you run into problems with the `ConvenienceMethods` module interacting with other `method_missing` gems, everything that the `ConvenienceMethods` module does can be replicated using the module\-level methods described above or by calling the convenience method on `NerdDice`.
|
286
|
+
|
287
|
+
Once a particular method has been called, it will define that method so that the next time it will invoke the method directly instead of traversing up the call stack for `method_missing`, which improves performance. The method will remain defined for the duration of the Ruby interpreter process.
|
288
|
+
|
289
|
+
#### Calling ConvenienceMethods as NerdDice class methods
|
290
|
+
NerdDice extends the `ConvenienceMethods` module into the top-level module as class methods, so you can call the methods on the NerdDice module without needing to worry about the implications of extending it into your own class.
|
291
|
+
```ruby
|
292
|
+
require 'nerd_dice'
|
293
|
+
# works with all the examples and patterns below
|
294
|
+
NerdDice.roll_3d6_lowest2_minus1
|
295
|
+
NerdDice.total_d20_with_advantage_p6
|
296
|
+
```
|
297
|
+
|
298
|
+
#### Mixing in the ConvenienceMethods module
|
299
|
+
To mix the NerdDice DSL into your class, make sure the gem is required if not already and then use `include NerdDice::ConvenienceMethods` as shown below:
|
300
|
+
```ruby
|
301
|
+
# example of a class that mixes in NerdDice::ConvenienceMethods
|
302
|
+
require 'nerd_dice'
|
303
|
+
class Monster
|
304
|
+
include NerdDice::ConvenienceMethods
|
305
|
+
|
306
|
+
# hard-coding probably not the best solution
|
307
|
+
# but gives you an idea how to mix in to a simple class
|
308
|
+
def hits_the_monster
|
309
|
+
# using the ConvenienceMethods version
|
310
|
+
total_d20_plus5 >= @armor_class ? "hit" : "miss"
|
311
|
+
end
|
312
|
+
|
313
|
+
def initialize(armor_class=16)
|
314
|
+
@armor_class = armor_class
|
315
|
+
end
|
316
|
+
end
|
317
|
+
```
|
318
|
+
To mix in the module as class methods, you can use `extend NerdDice::ConvenienceMethods`
|
319
|
+
```ruby
|
320
|
+
# example of a class that mixes in NerdDice::ConvenienceMethods
|
321
|
+
require 'nerd_dice'
|
322
|
+
class OtherClass
|
323
|
+
extend NerdDice::ConvenienceMethods
|
324
|
+
end
|
325
|
+
OtherClass.roll_3d6_lowest2_minus1 # returns NerdDice::DiceSet
|
326
|
+
```
|
327
|
+
|
328
|
+
#### ConvenienceMethods usage examples
|
329
|
+
Any invocation of `NerdDice.roll_dice` and `NerdDice.total_dice` can be duplicated using the `NerdDice::ConvenienceMethods` mixin. Here are some examples of what you can do with the return types and equivalent methods in the comments:
|
330
|
+
|
331
|
+
* `roll_dNN` and `total_dNN` roll one die
|
332
|
+
```ruby
|
333
|
+
roll_d20 # => DiceSet: NerdDice.roll_dice(20)
|
334
|
+
roll_d8 # => DiceSet: NerdDice.roll_dice(8)
|
335
|
+
roll_d1000 # => DiceSet: NerdDice.roll_dice(1000)
|
336
|
+
total_d20 # => Integer NerdDice.total_dice(20)
|
337
|
+
total_d8 # => Integer NerdDice.total_dice(8)
|
338
|
+
total_d1000 # => Integer NerdDice.total_dice(1000)
|
339
|
+
```
|
340
|
+
* `roll_NNdNN` and `total_NNdNN` roll specified quantity of dice
|
341
|
+
```ruby
|
342
|
+
roll_2d20 # => DiceSet: NerdDice.roll_dice(20, 2)
|
343
|
+
roll_3d8 # => DiceSet: NerdDice.roll_dice(8, 3)
|
344
|
+
roll_22d1000 # => DiceSet: NerdDice.roll_dice(1000, 22)
|
345
|
+
total_2d20 # => Integer NerdDice.total_dice(20, 2)
|
346
|
+
total_3d8 # => Integer NerdDice.total_dice(8, 3)
|
347
|
+
total_22d1000 # => Integer NerdDice.total_dice(1000, 22)
|
348
|
+
```
|
349
|
+
* Keyword arguments are passed on to `roll_dice`/`total_dice` method
|
350
|
+
```ruby
|
351
|
+
roll_2d20 foreground_color: "blue" # => DiceSet: NerdDice.roll_dice(20, 2, foreground_color: "blue")
|
352
|
+
|
353
|
+
total_d12 randomization_technique: :randomized
|
354
|
+
# => Integer NerdDice.total_dice(12, randomization_technique: :randomized)
|
355
|
+
total_22d1000 randomization_technique: :random_rand
|
356
|
+
# => Integer NerdDice.total_dice(1000, 22, randomization_technique: :random_rand)
|
357
|
+
|
358
|
+
roll_4d6_with_advantage3 background_color: 'blue'
|
359
|
+
# => DiceSet: NerdDice.roll_dice(4, 3, background_color: 'blue').highest(3)
|
360
|
+
total_4d6_with_advantage3 randomization_technique: :random_rand
|
361
|
+
# => Integer: NerdDice.roll_dice(4, 3, randomization_technique: :random_rand).highest(3).total
|
362
|
+
```
|
363
|
+
* Positive and negative bonuses can be used with `plus` (alias `p`) or `minus` (alias `m`)
|
364
|
+
```ruby
|
365
|
+
roll_d20_plus6 # => DiceSet: NerdDice.roll_dice(20, bonus: 6)
|
366
|
+
total_3d8_p2 # => Integer: NerdDice.total_dice(8, 3, bonus: 2)
|
367
|
+
total_d20_minus5 # => Integer: NerdDice.total_dice(20, bonus: -6)
|
368
|
+
roll_3d8_m3 # => DiceSet: NerdDice.roll_dice(8, 3, bonus: -3)
|
369
|
+
```
|
370
|
+
* `_with_advantageN` or `highestN` roll with advantage
|
371
|
+
* `_with_disadvantageN` or `lowestN` roll with disadvantage
|
372
|
+
* Calling `roll_dNN_with_advantage` \(and variants\) rolls 2 dice and keeps one
|
373
|
+
```ruby
|
374
|
+
# equivalent
|
375
|
+
roll_3d8_with_advantage1
|
376
|
+
roll_3d8_highest1
|
377
|
+
# => DiceSet: NerdDice.roll_dice(8, 3).with_advantage(1)
|
378
|
+
|
379
|
+
# calls roll_dice and total to return an integer
|
380
|
+
total_3d8_with_advantage1
|
381
|
+
total_3d8_highest1
|
382
|
+
# => Integer: NerdDice.roll_dice(8, 3).with_advantage(1).total
|
383
|
+
|
384
|
+
# rolls two dice in this case
|
385
|
+
# equal to roll_2d20_with_advantage but more natural
|
386
|
+
roll_d20_with_advantage # => DiceSet: NerdDice.roll_dice(20, 2).with_advantage(1)
|
387
|
+
# equal to total_2d20_with_advantage but more natural
|
388
|
+
total_d20_with_advantage # => Integer: NerdDice.roll_dice(20, 2).with_advantage(1).total
|
389
|
+
```
|
390
|
+
#### ConvenienceMethods error handling
|
391
|
+
* If you try to call with a plus and a minus, an Exception is raised
|
392
|
+
* If you call with a bonus and a keyword argument and they don't match, an Exception is raised
|
393
|
+
* Any combination not expressly allowed or matched will call `super` on `method_missing`
|
394
|
+
```ruby
|
395
|
+
roll_3d8_plus3_m2 # will raise NameError using super method_missing
|
396
|
+
roll_3d8_plus3 bonus: 1 # will raise NerdDice::Error with message about "Bonus integrity failure"
|
397
|
+
roll_d20_with_advantage_lowest # will raise NameError using super method_missing
|
398
|
+
total_4d6_lowest3_highest2 # will raise NameError using super method_missing
|
31
399
|
```
|
32
|
-
__NOTE:__ If provided, the bonus must be an ```Integer``` or it will be ignored
|
33
400
|
|
34
401
|
## Development
|
35
402
|
|
@@ -44,4 +411,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/statel
|
|
44
411
|
|
45
412
|
## Unlicense, License, and Copyright
|
46
413
|
|
47
|
-
The
|
414
|
+
The project is dual-licensed under the [MIT](https://opensource.org/licenses/MIT) license and the [UNLICENSE](https://unlicense.org/) \(with strong preference toward the UNLICENSE\)\. The content is released under [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/) \(no rights reserved\). You are free to include it in its original form or modified with or without additional modification in your own project\.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "digest/sha2"
|
5
|
+
|
6
|
+
version = ARGV[0]
|
7
|
+
built_gem_path = "pkg/nerd_dice-#{version}.gem"
|
8
|
+
checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
|
9
|
+
checksum_path = "checksum/nerd_dice-#{version}.gem.sha512"
|
10
|
+
File.open(checksum_path, "w") { |f| f.write(checksum) }
|
11
|
+
sha256 = Digest::SHA256.new.hexdigest(File.read(built_gem_path))
|
12
|
+
checksum_256_path = "checksum/nerd_dice-#{version}.gem.sha256"
|
13
|
+
File.open(checksum_256_path, "w") { |f| f.write(sha256) }
|