rpg_tools 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Dependency Status](https://gemnasium.com/Yinfei/rpg_tools.svg)](https://gemnasium.com/Yinfei/rpg_tools) ![](https://circleci.com/gh/Yinfei/rpg_tools.svg?&style=shield&circle-token=f5153100f0a56438602b915cf95d80f1e6e0edca)
|
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
|