rpg_tools 1.0.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +58 -0
- data/Rakefile +3 -0
- data/lib/rpg_tools/coin.rb +32 -0
- data/lib/rpg_tools/dice/bag.rb +65 -0
- data/lib/rpg_tools/dice/base.rb +52 -0
- data/lib/rpg_tools/dice/fudge.rb +15 -0
- data/lib/rpg_tools/dice/numerical.rb +9 -0
- data/lib/rpg_tools/dice/percentile.rb +15 -0
- data/lib/rpg_tools/dice/utils/modifier_calculator.rb +53 -0
- data/lib/rpg_tools/dice/utils/parser.rb +46 -0
- data/lib/rpg_tools/dice.rb +8 -0
- data/lib/rpg_tools/playing_card_deck.rb +64 -0
- data/lib/rpg_tools.rb +10 -0
- data/rpg_tools.gemspec +16 -0
- data/spec/coin_spec.rb +8 -0
- data/spec/dice/bag_spec.rb +59 -0
- data/spec/dice/base_spec.rb +96 -0
- data/spec/dice/fudge_spec.rb +22 -0
- data/spec/dice/numerical_spec.rb +16 -0
- data/spec/dice/percentile_spec.rb +30 -0
- data/spec/dice/utils/modifier_calculator_spec.rb +96 -0
- data/spec/dice/utils/parser_spec.rb +28 -0
- data/spec/playing_card_deck_spec.rb +28 -0
- data/spec/spec_helper.rb +13 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0316fd1f6aea96942849150e125d95ea05a96411
|
4
|
+
data.tar.gz: 47f8012ecda7a42111f22a6bac44d65b5bb9016c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 556a6f049b6cbc5139c7ce4e56afd80efe981041534bfca5fb6a0fbfcdec5fb14efed10a477d3900c8b322f2121c2c2042cfa35e9817ff413fe12a48581ae0dc
|
7
|
+
data.tar.gz: 47dcde8a0c5227093b35e8c421e3a2958eff4beee3c94e21a94be3dd8ff1500a808e2c313dfcec4834d85cce1b8b6a8fe6367a6e56f2047eb70a46093ab67d14
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Yohan Piron
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
rpg_tools [](https://gemnasium.com/Yinfei/rpg_tools) 
|
2
|
+
=======
|
3
|
+
|
4
|
+
A gem that gives you tools for your RPGs : dices, coins and playing cards !
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
### Coins
|
9
|
+
|
10
|
+
`RpgTools::Coin.new`
|
11
|
+
|
12
|
+
* The `flip` method set its value to a `heads` or `tails` string.
|
13
|
+
|
14
|
+
### Dices
|
15
|
+
|
16
|
+
`RpgTools.roll_dice(arg)` <i>(`arg` is case insensitive)</i>.
|
17
|
+
|
18
|
+
This returns a plain integer result based on the `arg` parameter.
|
19
|
+
|
20
|
+
* It can be a stardard dice like `"1dX"` for a X sided dice.
|
21
|
+
|
22
|
+
* It can be a fudge dice `"df"` : a three sided dice (-1, 0, +1).
|
23
|
+
|
24
|
+
* It can also be a percentile dice `"d%"` : a ten sided dice (from 10 to 100).
|
25
|
+
|
26
|
+
You can also add multiple chained modifiers like "+X", "-X", "*X" or "/X", to alter the roll result. `RpgTools.roll_dice("4d6+2")` will create 4 6-sided dices, roll them and add 2 to the sum of the roll result.
|
27
|
+
|
28
|
+
You can also manipulate all those dice types as objects :
|
29
|
+
|
30
|
+
* `RpgTools::Dice::Numerical`
|
31
|
+
* `RpgTools::Dice::Fudge`
|
32
|
+
* `RpgTools::Dice::Percentile`
|
33
|
+
|
34
|
+
All those classes take two args: a mandatory side number and an optional modifier.
|
35
|
+
They respond to the `.roll` or `.roll!` methods to update their `value` to the result of the roll.
|
36
|
+
|
37
|
+
`RpgTools::Dice::Numerical.new(6, '+4').roll` will roll a six sided dice and add 4 to the roll result.
|
38
|
+
|
39
|
+
### Dice Bags
|
40
|
+
|
41
|
+
`RpgTools::Dice::Bag.new(arg)` <i>(`arg` is case insensitive)</i>.
|
42
|
+
|
43
|
+
* It works the same way `RpgTools.roll_dice` does but will give you a `RpgTools::Dice::Bag` object instead of a plain integer. `RpgTools::Dice::Bag.new("4d6-2")` will create a bag of four 6 sided dices with a -2 modifier to the sum of all rolls.
|
44
|
+
|
45
|
+
### Playing card deck
|
46
|
+
`RpgTools::PlayingCardDeck.new(arg)` <i>(`arg` can only be 32 or 52)</i>.
|
47
|
+
|
48
|
+
* The `card` method returns a card of a 32 or 52 cards deck + 2 jokers, depending
|
49
|
+
of `arg` value.
|
50
|
+
* The `hand` method return an array of 5 `card` calls.
|
51
|
+
|
52
|
+
## Contributing
|
53
|
+
|
54
|
+
1. Fork it
|
55
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
56
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
57
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
58
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module RpgTools
|
2
|
+
class Coin
|
3
|
+
attr_accessor :value, :flips, :heads, :tails
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@value, @flips, @heads, @tails = nil, 0, 0, 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def flip
|
10
|
+
@flips += 1
|
11
|
+
@value = rand(2) == 1 ? 'Heads' : 'Tails'
|
12
|
+
save_result
|
13
|
+
@value
|
14
|
+
end
|
15
|
+
alias_method :flip!, :flip
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def save_result
|
20
|
+
@heads += 1 if heads?
|
21
|
+
@tails += 1 if tails?
|
22
|
+
end
|
23
|
+
|
24
|
+
def heads?
|
25
|
+
@value == 'Heads'
|
26
|
+
end
|
27
|
+
|
28
|
+
def tails?
|
29
|
+
@value == 'Tails'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RpgTools
|
2
|
+
module Dice
|
3
|
+
class Bag
|
4
|
+
NOTATIONS ||= {
|
5
|
+
'D' => Numerical,
|
6
|
+
'D%' => Percentile,
|
7
|
+
'DF' => Fudge
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
attr_accessor :dice_hash, :content, :modifiers, :value
|
11
|
+
|
12
|
+
def initialize(base)
|
13
|
+
@dice_hash = Utils::Parser.new(base).handle
|
14
|
+
@content = []
|
15
|
+
@modifiers = dice_hash[:modifiers]
|
16
|
+
@value = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def roll
|
20
|
+
invalid_dice! if dice_klass.nil?
|
21
|
+
|
22
|
+
fill_bag!
|
23
|
+
|
24
|
+
roll_bag_content!
|
25
|
+
|
26
|
+
return @total if modifiers.empty?
|
27
|
+
|
28
|
+
@total = Utils::ModifierCalculator.new(@total, modifiers).recalculate
|
29
|
+
end
|
30
|
+
alias roll! roll
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def fill_bag!
|
35
|
+
quantity.times { @content << dice_klass.new(sides) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def roll_bag_content!
|
39
|
+
@content.map(&:roll)
|
40
|
+
|
41
|
+
@total = @content.map(&:value).inject(0, :+)
|
42
|
+
end
|
43
|
+
|
44
|
+
def dice_klass
|
45
|
+
NOTATIONS[type]
|
46
|
+
end
|
47
|
+
|
48
|
+
def type
|
49
|
+
dice_hash[:type]
|
50
|
+
end
|
51
|
+
|
52
|
+
def sides
|
53
|
+
dice_hash[:sides]
|
54
|
+
end
|
55
|
+
|
56
|
+
def quantity
|
57
|
+
dice_hash[:quantity]
|
58
|
+
end
|
59
|
+
|
60
|
+
def invalid_dice!
|
61
|
+
raise ArgumentError, 'Unsupported dice type.'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RpgTools
|
2
|
+
module Dice
|
3
|
+
class Base
|
4
|
+
attr_accessor :sides, :modifiers, :value, :rolls
|
5
|
+
|
6
|
+
def initialize(sides = 0, modifiers = '')
|
7
|
+
@sides = sides.zero? ? sides_count : sides
|
8
|
+
@modifiers = modifiers
|
9
|
+
@value = 0
|
10
|
+
@rolls = 0
|
11
|
+
|
12
|
+
check_sides
|
13
|
+
end
|
14
|
+
|
15
|
+
def roll
|
16
|
+
@rolls += 1
|
17
|
+
|
18
|
+
@value = perform_roll
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def perform_roll
|
24
|
+
return roll_calculation if @modifiers.empty?
|
25
|
+
|
26
|
+
roll_with_modifiers
|
27
|
+
end
|
28
|
+
|
29
|
+
def roll_with_modifiers
|
30
|
+
Utils::ModifierCalculator.new(roll_calculation, @modifiers).recalculate
|
31
|
+
end
|
32
|
+
|
33
|
+
def roll_calculation
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def sides_count
|
38
|
+
0
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_sides
|
42
|
+
if not_enough_sides
|
43
|
+
raise ArgumentError, 'Your dice must have at least three sides.'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def not_enough_sides
|
48
|
+
@sides < 3
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RpgTools
|
2
|
+
module Dice
|
3
|
+
module Utils
|
4
|
+
class ModifierCalculator
|
5
|
+
attr_accessor :total, :modifiers
|
6
|
+
|
7
|
+
def initialize(total, modifiers)
|
8
|
+
@total = total
|
9
|
+
@modifiers = modifiers
|
10
|
+
|
11
|
+
unprocessable_modifiers if malformed_modifiers?
|
12
|
+
end
|
13
|
+
|
14
|
+
def recalculate
|
15
|
+
modifier_operations.each do |operator, value|
|
16
|
+
@total = @total.send(operator, value.to_i)
|
17
|
+
end
|
18
|
+
|
19
|
+
@total
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def modifier_operations
|
25
|
+
@modifiers.scan(/(\D)(\d+)/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def unprocessable_modifiers
|
29
|
+
raise ArgumentError,
|
30
|
+
'Modifiers require both an operator and a numerical value.'
|
31
|
+
end
|
32
|
+
|
33
|
+
def malformed_modifiers?
|
34
|
+
no_operator_at_modifier_beginning? ||
|
35
|
+
no_number_at_modifier_end? ||
|
36
|
+
multiple_successive_operators?
|
37
|
+
end
|
38
|
+
|
39
|
+
def no_operator_at_modifier_beginning?
|
40
|
+
@modifiers.match(/^\D/).nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def no_number_at_modifier_end?
|
44
|
+
@modifiers.match(/\d+$/).nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def multiple_successive_operators?
|
48
|
+
!@modifiers.match(/\d?([^0-9]{2,})\d?$/).nil?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RpgTools
|
2
|
+
module Dice
|
3
|
+
module Utils
|
4
|
+
class Parser
|
5
|
+
attr_reader :dice
|
6
|
+
|
7
|
+
def initialize(dice)
|
8
|
+
@dice = dice.upcase.match(/^(\d+)([A-Z%]+)(\d*)(.*)$/)
|
9
|
+
|
10
|
+
quantity_error! if @dice.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def handle
|
14
|
+
{
|
15
|
+
quantity: quantity,
|
16
|
+
type: type,
|
17
|
+
sides: sides,
|
18
|
+
modifiers: modifiers
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def quantity
|
25
|
+
@dice[1].to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
@dice[2]
|
30
|
+
end
|
31
|
+
|
32
|
+
def sides
|
33
|
+
@dice[3].to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def modifiers
|
37
|
+
@dice[4]
|
38
|
+
end
|
39
|
+
|
40
|
+
def quantity_error!
|
41
|
+
raise ArgumentError, 'You must specify a dice quantity.'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RpgTools
|
2
|
+
class PlayingCardDeck
|
3
|
+
attr_accessor :type, :card_picks, :value
|
4
|
+
|
5
|
+
def initialize(type)
|
6
|
+
@type = type
|
7
|
+
type_check
|
8
|
+
@card_picks = 0
|
9
|
+
@value = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def card
|
13
|
+
@card_picks += 1
|
14
|
+
|
15
|
+
@value =
|
16
|
+
if @type == 52
|
17
|
+
joker_picked? ? 'Joker' : standard_card
|
18
|
+
else
|
19
|
+
standard_card
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def hand
|
24
|
+
[].tap do |hand|
|
25
|
+
until hand.count == 5
|
26
|
+
card = standard_card
|
27
|
+
|
28
|
+
unless hand.include?(card) || hand.count('Joker') == 2
|
29
|
+
hand << card
|
30
|
+
@card_picks += 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def type_check
|
39
|
+
unless [32, 52].include?(@type)
|
40
|
+
raise ArgumentError.new('A playing card deck contains 32 or 52 cards only.')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def joker_picked?
|
45
|
+
[0, 1].include?((0..54).to_a.sample(1).first)
|
46
|
+
end
|
47
|
+
|
48
|
+
def number
|
49
|
+
if @type == 32
|
50
|
+
[(7..10).to_a, 'Jack', 'Queen', 'King'].flatten.sample(1)
|
51
|
+
else
|
52
|
+
[(1..10).to_a, 'Jack', 'Queen', 'King'].flatten.sample(1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def color
|
57
|
+
['Clubs', 'Hearts', 'Diamonds', 'Spades'].sample(1)
|
58
|
+
end
|
59
|
+
|
60
|
+
def standard_card
|
61
|
+
@value = [number, color].join(' of ')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/rpg_tools.rb
ADDED
data/rpg_tools.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{rpg_tools}
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.author = 'Yohan Piron'
|
5
|
+
s.email = 'yinfei84@gmail.com'
|
6
|
+
s.date = '2015-08-03'
|
7
|
+
s.summary = 'rpg_tools is a toolbox for tabletop games and RPGs'
|
8
|
+
s.description = 'rpg_tools gives you tools for your RPGs : dices, coins, cards...'
|
9
|
+
s.homepage = 'https://github.com/Yinfei/rpg_tools.git'
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.test_files = s.files.grep(%r{^(spec)/})
|
13
|
+
s.require_paths = ['lib']
|
14
|
+
s.add_development_dependency 'rake', '~> 10.4'
|
15
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
16
|
+
end
|
data/spec/coin_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Bag do
|
5
|
+
describe '#roll' do
|
6
|
+
it "doesn't roll a dice without quantity" do
|
7
|
+
expect { described_class.new('d10').roll }.to raise_error(ArgumentError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "doesn't roll a 'd0' dice" do
|
11
|
+
expect { described_class.new('1d0').roll }.to raise_error(ArgumentError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "doesn't roll a 'd1' dice" do
|
15
|
+
expect { described_class.new('1d1').roll }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "doesn't roll a 'd2' dice" do
|
19
|
+
expect { described_class.new('1d2').roll }.to raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'rolls fudge dices' do
|
23
|
+
expect { described_class.new('1df').roll }.not_to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it "rolls a dice may the 'd' char be capitalized or not" do
|
27
|
+
expect { described_class.new('1d6').roll }.not_to raise_error
|
28
|
+
expect { described_class.new('1D6').roll }.not_to raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it "rolls a dice may the 'f' char be capitalized or not" do
|
32
|
+
expect { described_class.new('1dF').roll }.not_to raise_error
|
33
|
+
expect { described_class.new('1Df').roll }.not_to raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'rolls a dice with a bonus' do
|
37
|
+
expect { described_class.new('1d6+2').roll }.not_to raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'rolls a dice with a malus' do
|
41
|
+
expect { described_class.new('1D6-2').roll }.not_to raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'rolls a dice with a multiple modifiers' do
|
45
|
+
expect { described_class.new('1D6-2+4/8').roll }.not_to raise_error
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not roll a dice with bad modifiers' do
|
49
|
+
expect { described_class.new('1D6-+2').roll }.to raise_error(ArgumentError)
|
50
|
+
expect { described_class.new('1D6-+2+').roll }.to raise_error(ArgumentError)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "doesn't roll very odd dices" do
|
54
|
+
expect { described_class.new('1dDOGE').roll }.to raise_error(ArgumentError)
|
55
|
+
expect { described_class.new('1dfoo').roll }.to raise_error(ArgumentError)
|
56
|
+
expect { described_class.new('1foobarbaz').roll }.to raise_error(ArgumentError)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Base do
|
5
|
+
let(:dice) { described_class.new(10) }
|
6
|
+
let(:dice_with_modifier) { described_class.new(10, '+2') }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'creates a basic dice' do
|
10
|
+
expect { described_class.new(10) }.not_to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'creates a basic dice with a modifier' do
|
14
|
+
expect { described_class.new(10, '+2') }.not_to raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'falls back on sides_count method if no sides arg is provided' do
|
18
|
+
allow_any_instance_of(described_class).to receive(:sides_count).and_return(7)
|
19
|
+
|
20
|
+
new_dice = described_class.new
|
21
|
+
|
22
|
+
expect(new_dice.sides).to eq(7)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#roll' do
|
27
|
+
before do
|
28
|
+
allow(dice).to receive(:roll_calculation).and_return(10)
|
29
|
+
allow(dice_with_modifier).to receive(:roll_calculation).and_return(10)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'no modifier' do
|
33
|
+
it 'returns an integer based on a basic roll calculation' do
|
34
|
+
expect(dice.roll).to eq(10)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not call the #roll_with_modifiers method' do
|
38
|
+
expect(dice).not_to receive(:roll_with_modifiers)
|
39
|
+
|
40
|
+
dice.roll
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'modifier present' do
|
45
|
+
it 'returns an integer based on a roll calulation plus modifier applied' do
|
46
|
+
expect(dice_with_modifier.roll).to eq(12)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'calls the #roll_with_modifiers method' do
|
50
|
+
expect(dice_with_modifier).to receive(:roll_with_modifiers)
|
51
|
+
|
52
|
+
dice_with_modifier.roll
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'updates a dice value attribute' do
|
57
|
+
dice.roll
|
58
|
+
|
59
|
+
expect(dice.value).to eq(10)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'increments to dice roll count' do
|
63
|
+
dice.roll
|
64
|
+
|
65
|
+
expect(dice.rolls).to eq(1)
|
66
|
+
|
67
|
+
dice.roll
|
68
|
+
|
69
|
+
expect(dice.rolls).to eq(2)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#sides_count' do
|
74
|
+
it 'returns zero' do
|
75
|
+
expect(dice.send(:sides_count)).to eq(0)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#roll_calculation' do
|
80
|
+
it 'raises a NotImplementedError' do
|
81
|
+
expect { dice.send(:roll_calculation) }.to raise_error(NotImplementedError)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'not_enough_sides' do
|
86
|
+
it 'returns true if dice sides is less than three' do
|
87
|
+
dice.sides = 2
|
88
|
+
|
89
|
+
expect(dice.send(:not_enough_sides)).to be(true)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns false otherwise' do
|
93
|
+
expect(dice.send(:not_enough_sides)).to be(false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Fudge do
|
5
|
+
let(:dice) { described_class.new }
|
6
|
+
|
7
|
+
describe '#roll_calculation' do
|
8
|
+
it 'rolls a value between -1 and 1' do
|
9
|
+
10.times do
|
10
|
+
dice.roll
|
11
|
+
|
12
|
+
expect(dice.value.between?(-1, 1)).to be(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#sides_count' do
|
18
|
+
it 'returns 3' do
|
19
|
+
expect(dice.send(:sides_count)).to eq(3)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Numerical do
|
5
|
+
let(:dice) { described_class.new(10) }
|
6
|
+
|
7
|
+
describe '#roll_calculation' do
|
8
|
+
it 'rolls a value between 1 and the sides value' do
|
9
|
+
10.times do
|
10
|
+
dice.roll
|
11
|
+
|
12
|
+
expect(dice.value.between?(1, dice.sides)).to be(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Percentile do
|
5
|
+
let(:dice) { described_class.new }
|
6
|
+
|
7
|
+
describe '#roll_calculation' do
|
8
|
+
it 'rolls a value between 10 and 100' do
|
9
|
+
10.times do
|
10
|
+
dice.roll
|
11
|
+
|
12
|
+
expect(dice.value.between?(10, 100)).to be(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'rolls only round values' do
|
17
|
+
10.times do
|
18
|
+
dice.roll
|
19
|
+
|
20
|
+
expect(dice.value[-1]).to eq(0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#sides_count' do
|
26
|
+
it 'returns 10' do
|
27
|
+
expect(dice.send(:sides_count)).to eq(10)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Utils::ModifierCalculator do
|
5
|
+
let(:dice) { described_class.new(10, '+1') }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
it 'raises an error for malformed modifiers' do
|
9
|
+
expect { described_class.new(10, '+3+') }.to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not otherwise' do
|
13
|
+
expect { described_class.new(10, '+5-3/10') }.not_to raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#recalculate' do
|
18
|
+
it 'applies a simple modifier to the total attribute' do
|
19
|
+
dice = described_class.new(10, '+5')
|
20
|
+
|
21
|
+
dice.recalculate
|
22
|
+
|
23
|
+
expect(dice.total).to eq(15)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'applies multiple modifiers to the total attribute' do
|
27
|
+
dice = described_class.new(10, '+5-1/2')
|
28
|
+
|
29
|
+
dice.recalculate
|
30
|
+
|
31
|
+
expect(dice.total).to eq(7)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#malformed_modifiers?' do
|
36
|
+
it 'returns true if there is not operator at modifiers beginning' do
|
37
|
+
dice.modifiers = '4'
|
38
|
+
|
39
|
+
expect(dice.send(:malformed_modifiers?)).to be(true)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns true if there is no number at modifiers end' do
|
43
|
+
dice.modifiers = '+3-'
|
44
|
+
|
45
|
+
expect(dice.send(:malformed_modifiers?)).to be(true)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns true if multiple succesive operators are present in the modifiers' do
|
49
|
+
dice.modifiers = '+-3'
|
50
|
+
|
51
|
+
expect(dice.send(:malformed_modifiers?)).to be(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns false otherwise' do
|
55
|
+
dice.modifiers = '+4-5/8'
|
56
|
+
|
57
|
+
expect(dice.send(:malformed_modifiers?)).to be(false)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#no_operator_at_modifier_beginning?' do
|
62
|
+
it 'returns true if there is not operator at modifiers beginning' do
|
63
|
+
dice.modifiers = '4'
|
64
|
+
|
65
|
+
expect(dice.send(:no_operator_at_modifier_beginning?)).to be(true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returs false otherwise' do
|
69
|
+
expect(dice.send(:no_operator_at_modifier_beginning?)).to be(false)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#no_number_at_modifier_end?' do
|
74
|
+
it 'returns true if there is no number at modifiers end' do
|
75
|
+
dice.modifiers = '+3-'
|
76
|
+
|
77
|
+
expect(dice.send(:no_number_at_modifier_end?)).to be(true)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returs false otherwise' do
|
81
|
+
expect(dice.send(:no_number_at_modifier_end?)).to be(false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#multiple_successive_operators?' do
|
86
|
+
it 'returns true if multiple succesive operators are present in the modifiers' do
|
87
|
+
dice.modifiers = '+-3'
|
88
|
+
|
89
|
+
expect(dice.send(:multiple_successive_operators?)).to be(true)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returs false otherwise' do
|
93
|
+
expect(dice.send(:multiple_successive_operators?)).to be(false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::Dice::Utils::Parser do
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'raises an error when no matching pattern is found' do
|
7
|
+
expect { described_class.new('DOGE') }.to raise_error(ArgumentError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'does not otherwise' do
|
11
|
+
expect { described_class.new('1DF') }.not_to raise_error
|
12
|
+
expect { described_class.new('1D10') }.not_to raise_error
|
13
|
+
expect { described_class.new('1D10+12') }.not_to raise_error
|
14
|
+
expect { described_class.new('1D%') }.not_to raise_error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#handle' do
|
19
|
+
it 'builds a hash based on a matching pattern' do
|
20
|
+
hash = described_class.new('3DF+4').handle
|
21
|
+
|
22
|
+
expect(hash[:quantity]).to eq(3)
|
23
|
+
expect(hash[:type]).to eq('DF')
|
24
|
+
expect(hash[:sides]).to eq(0)
|
25
|
+
expect(hash[:modifiers]).to eq('+4')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rpg_tools'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe RpgTools::PlayingCardDeck do
|
5
|
+
it 'must return a card name' do
|
6
|
+
expect(described_class.new(32).card).not_to eq(true)
|
7
|
+
expect(described_class.new(32).card).not_to eq(false)
|
8
|
+
expect(described_class.new(32).card).not_to eq(nil)
|
9
|
+
expect(described_class.new(52).card).not_to eq(true)
|
10
|
+
expect(described_class.new(52).card).not_to eq(false)
|
11
|
+
expect(described_class.new(52).card).not_to eq(nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'must return 5 cards for a full hand' do
|
15
|
+
expect(described_class.new(32).hand.count).to eq(5)
|
16
|
+
expect(described_class.new(52).hand.count).to eq(5)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can't pick the same card twice" do
|
20
|
+
expect(described_class.new(32).hand.uniq.count).to eq(5)
|
21
|
+
expect(described_class.new(52).hand.uniq.count).to eq(5)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can't use anything else than a 32 or 52 cards deck" do
|
25
|
+
expect { described_class.new(42) }.to raise_error(ArgumentError)
|
26
|
+
expect { described_class.new(666) }.to raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.color = true
|
3
|
+
config.tty = true
|
4
|
+
config.formatter = :documentation
|
5
|
+
|
6
|
+
config.mock_with :rspec do |c|
|
7
|
+
c.syntax = [:should, :expect]
|
8
|
+
end
|
9
|
+
|
10
|
+
config.expect_with :rspec do |c|
|
11
|
+
c.syntax = [:should, :expect]
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rpg_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yohan Piron
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10.4'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
description: 'rpg_tools gives you tools for your RPGs : dices, coins, cards...'
|
42
|
+
email: yinfei84@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- LICENSE
|
48
|
+
- README.md
|
49
|
+
- Rakefile
|
50
|
+
- lib/rpg_tools.rb
|
51
|
+
- lib/rpg_tools/coin.rb
|
52
|
+
- lib/rpg_tools/dice.rb
|
53
|
+
- lib/rpg_tools/dice/bag.rb
|
54
|
+
- lib/rpg_tools/dice/base.rb
|
55
|
+
- lib/rpg_tools/dice/fudge.rb
|
56
|
+
- lib/rpg_tools/dice/numerical.rb
|
57
|
+
- lib/rpg_tools/dice/percentile.rb
|
58
|
+
- lib/rpg_tools/dice/utils/modifier_calculator.rb
|
59
|
+
- lib/rpg_tools/dice/utils/parser.rb
|
60
|
+
- lib/rpg_tools/playing_card_deck.rb
|
61
|
+
- rpg_tools.gemspec
|
62
|
+
- spec/coin_spec.rb
|
63
|
+
- spec/dice/bag_spec.rb
|
64
|
+
- spec/dice/base_spec.rb
|
65
|
+
- spec/dice/fudge_spec.rb
|
66
|
+
- spec/dice/numerical_spec.rb
|
67
|
+
- spec/dice/percentile_spec.rb
|
68
|
+
- spec/dice/utils/modifier_calculator_spec.rb
|
69
|
+
- spec/dice/utils/parser_spec.rb
|
70
|
+
- spec/playing_card_deck_spec.rb
|
71
|
+
- spec/spec_helper.rb
|
72
|
+
homepage: https://github.com/Yinfei/rpg_tools.git
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.6.8
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: rpg_tools is a toolbox for tabletop games and RPGs
|
96
|
+
test_files:
|
97
|
+
- spec/coin_spec.rb
|
98
|
+
- spec/dice/bag_spec.rb
|
99
|
+
- spec/dice/base_spec.rb
|
100
|
+
- spec/dice/fudge_spec.rb
|
101
|
+
- spec/dice/numerical_spec.rb
|
102
|
+
- spec/dice/percentile_spec.rb
|
103
|
+
- spec/dice/utils/modifier_calculator_spec.rb
|
104
|
+
- spec/dice/utils/parser_spec.rb
|
105
|
+
- spec/playing_card_deck_spec.rb
|
106
|
+
- spec/spec_helper.rb
|