tabletop 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  Gemfile.lock
2
2
  .DS_Store
3
- pkg/
3
+ pkg/
4
+ *.gem
data/README.markdown CHANGED
@@ -2,41 +2,141 @@
2
2
 
3
3
  Tabletop aims to provide a simple way of describing, automating and tracking the tools and tasks involved in "analog" games, determining results from the motions and properties of various dice and chips.
4
4
 
5
- Currently, you can roll dice with it.
5
+ Currently, you can create pools of dice, and rolls that compare them to different possible results.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  gem install tabletop
10
+
11
+ require 'tabletop'
10
12
 
11
- ## Usage
13
+ ## Dice
12
14
 
13
- Just `require 'tabletop'` and off you go! The easiest way to create a pool of dice is exactly the way you'd expect.
15
+ Dice are pretty straightforward. They've got a number of sides, set on instantiation (defaulting to 6), and a current value between that number and 1 inclusive, which can be set on instantiation, or directly. They can be rolled, which gives them a new random value.
14
16
 
15
- 3.d6 #=> [3 (d6), 3 (d6), 4 (d6)]
16
- 2.d10 + 1.d8 #=> [2 (d10), 6 (d10), 8 (d8)]
17
- 6.d17 #=> [8 (d17), 3 (d17), 7 (d17), 16 (d17), 11 (d17), 10 (d17)]
17
+ d6 = Die.new
18
+ d6.sides #=> 6
19
+ d6.value #=> 4
20
+ d6.roll
21
+ d6.value #=> 2
22
+
23
+ d8 = Die.new(8, 4)
24
+ d8.sides #=> 8
25
+ d8.to_s #=> "[3]/d8"
18
26
 
19
- Pools are arrays of Dice objects that have a few nice extra functions.
27
+ One fun special kind of die is a "Fudge Die". They are a special kind of three-sided die that have three possible values: -1, 0, or 1. Those are usually expressed as '-', ' ' and '+', though.
28
+
29
+ f = FudgeDie.new
30
+ f.sides #=> 3
31
+ f.value #=> 0
32
+ f.to_s #=> "[ ]"
33
+
34
+ ### Pools
35
+
36
+ Pools are essentially arrays of Dice objects with some extra helpful methods.
20
37
 
21
- d&d_strength = 3.d6.roll.sum #=> 13
22
- ore_character = 10.d10.sets #=> ["3x2", "2x8", "1x7", "1x6", "1x4", "1x3", "1x1"]
23
- cortex_result = (1.d8 + 2.d6 + 1.d4).highest(2).sum #=> 9
38
+ The _best_ way to create one is exactly the way you'd expect: the same old d-notation we've been using for decades. You can even combine them with `+`.
39
+
40
+ 3.d6 #=> [[3]/d6, [3]/d6, [4]/d6]
41
+ 2.d10 + 1.d8 #=> [[2]/d10, [6]/d10, [8]/d8]
24
42
 
25
- Dice are pretty straightforward.
43
+ You can also create them by passing Pool.new a literal array of dice, or (slightly more interesting) a string in die notation.
44
+
45
+ The methods are common operations you might do on a pool of dice: summing, counting sets, dropping the lowest or highest valued dice, dropping all _but_ the lowest or highest valued dice, even dropping any dice a specified list of values.
26
46
 
27
- d = Die.new
28
- d.sides #=> 6
29
- d.result #=> 4
30
- d.roll #=> "2 (d6)"
47
+ d&d = 3.d6.sum #=> 13
48
+ ore = 10.d10.sets #=> ["3x2", "2x8", "1x7", "1x6", "1x4", "1x3", "1x1"]
49
+ cortex = (1.d8 + 2.d6).drop([1]).highest(2).sum #=> 9
50
+ tsoy = (4.dF).drop_lowest.sum #=> 2
31
51
 
32
- ## Note on Patches/Pull Requests
52
+ You can also #roll an entire pool, or you can interact with individual dice in the array using array indices (`[]`).
53
+
54
+ When pools are compared to each other or to numbers with <=>, it's assumed you're actually interested in their sum. The same thing happens if you try to add a number to them.
55
+
56
+ d&d_alt = 4.d4 + 4 #=> 17
57
+ 1.d20 > 2.d10 #=> false
58
+
59
+ ### Rolls
60
+
61
+ Rolls are very much under construction, but they allow you to automate randomly determining results in a variety of ways.
62
+
63
+ Rolls have a lot of options. Let's start by taking an example from one of my favorite games, Apocalypse World.
64
+
65
+ >When you open your brain to the world’s psychic maelstrom, roll+weird. On a hit, the MC will tell you something new and interesting about the current situation, and might ask you a question or two; answer them. On a 10+, the MC will give you good detail. On a 7–9, the MC will give you an impression.
66
+
67
+ (In the parlance of the game, a "hit" is getting a 7 or higher on 2d6, plus a stat.)
68
+
69
+ Here's how I'd write it out in Tabletop.
70
+
71
+ cool = [-1, 0, 1, 2, 3].sample #=> get a random stat
72
+
73
+ open_brain = Roll.new(2.d6) {
74
+ modifier cool
75
+ at_least 7, "the MC will tell you something new and interesting about the current situation"
76
+ equals (7..9), "...but it's just an impression"
77
+ at_least 10, "...and it's a good detail"
78
+ }
79
+
80
+ Simple, right? `add` sets a value to be permanently added for the purposes of determining results. `at_least` and `equals` take an integer (or a range, in the case of `equals`) as their first parameter, and then one or more results to trigger if the pools result meets the stated condition.
81
+
82
+ Once they've been instantiated, Rolls have two important methods.
83
+
84
+ #### #roll
33
85
 
86
+ This method which re-rolls all the dice in the pool, and returns the Roll object. It can take an options hash as a parameter. Notably, one of the options is `:modifier`, which sets a temporary modifier for that roll only; it's cleared the next time `roll` is called.
87
+
88
+ bad_luck = -1
89
+ open_brain.roll(:modifier => bad_luck)
90
+
91
+ #### #effects
92
+
93
+ This method returns an array, based on the current state of the pool, and any conditions and modifiers. Here's what I can tell you about the Array:
94
+
95
+ * Its first element is the "result" of the current pool, which is by default the sum of the values of its dice, plus any static or per-roll modifiers.
96
+ * The second and subsequent elements are the results of any satisfied conditions.
97
+ * If no conditions are satisfied, then the second and final element of the array is `nil`
98
+
99
+ So, possible results for our cool AW roll:
100
+
101
+ open_brain.roll.effects #=> [4, nil]
102
+ open_brain.roll.effects #=> [8, "the MC will tell you something new and interesting about the current situation", "...but it's just an impression"]
103
+ roll, *effects = open_brain.roll.effects
104
+ puts roll #=> 10
105
+ puts effects #=> ["the MC will tell you something new and interesting about the current situation", "...and it's a good detail"]
106
+
107
+ Just these few functions already give enough functionality to do different kinds of rolls, but there's a lot more in store.
108
+
109
+ One last thing I'll briefly note is that Rolls can be nested.
110
+
111
+ rps = Roll.new(1.d3) {
112
+ equals 1, "rock"
113
+ equals 2, "paper"
114
+ equals 3, "scissors"
115
+ }
116
+ jkp = Roll.new(1.d3) {
117
+ equals 1, "guu"
118
+ equals 2, "choki"
119
+ equals 3, "paa"
120
+ }
121
+ fist_game = Roll.new(1.d2) {
122
+ equals 1, "Rock Paper Scissors", rps
123
+ equals 2, "JanKenPon", jkp
124
+ }
125
+ fist_game.roll.effects #=> [2, "JanKenPon", [1, "guu"]]
126
+
127
+ This can lead to some surprisingly sophisticated constructions. Remember that "tables" are really just a special case of a roll!
128
+
129
+ ## How to contribute
130
+
131
+ *First and most importantly*, any complaints or suggestions, *regardless of coding knowledge*, are *always welcome* at <nick.novitski@gmail.com>.
132
+
133
+ But, if you're feeling up to it, you can always do more. You probably already know the drill by this point.
134
+
34
135
  * Fork the project.
35
136
  * Create a topic branch
36
137
  * Make tests that describe your feature addition or bug fix.
37
138
  * Write code that passes those tests
38
- * Commit, without altering the rakefile or version.
39
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
139
+ * Commit, without altering the version.
40
140
  * Send me a pull request.
41
141
 
42
142
  ## Copyright
data/lib/tabletop/die.rb CHANGED
@@ -1,59 +1,62 @@
1
1
  module Tabletop
2
2
  class Die
3
3
  include Comparable
4
- attr_reader :sides, :result
5
- def initialize(sides=6, result=nil)
6
- if sides <= 0
4
+ attr_reader :sides, :value
5
+ def initialize(sides=6, init_value=nil)
6
+ if sides <= 1
7
7
  raise ArgumentError, "Die cannot have #{sides} sides"
8
8
  end
9
9
  unless sides.kind_of? Integer
10
10
  raise ArgumentError, "Parameter must be Integer, not #{sides.class}"
11
11
  end
12
12
  @sides = sides
13
- if result.nil?
14
- result = roll
13
+ if init_value.nil?
14
+ init_value = roll
15
15
  else
16
- raise ArgumentError unless valid_result?(result)
16
+ raise ArgumentError unless valid_value?(init_value)
17
17
  end
18
- @result = result
18
+ @value = init_value
19
19
  end
20
20
  def roll
21
- @result = rand(sides)+1
21
+ @value = rand(sides)+1
22
22
  end
23
- def inspect
24
- "#{@result} (d#{@sides})"
23
+
24
+ def to_s
25
+ "[#{value}]/d#{sides}"
25
26
  end
26
- def result=(new_result)
27
- raise ArgumentError unless valid_result?(new_result)
28
- @result = new_result
27
+
28
+ def value=(new_value)
29
+ raise ArgumentError unless valid_value?(new_value)
30
+ @value = new_value
29
31
  end
30
32
  def <=>(operand)
31
- @result <=> operand.to_int
33
+ @value <=> operand.to_int
32
34
  end
33
35
  def to_int
34
- @result
36
+ @value
35
37
  end
36
38
 
37
39
  protected
38
- def valid_result?(result)
39
- result > 0 and result <= @sides
40
+ def valid_value?(val)
41
+ val > 0 and val <= @sides
40
42
  end
41
43
  end
42
44
 
43
45
  class FudgeDie < Die
44
- def initialize(result = nil)
45
- super(3, result)
46
+ def initialize(init_value = nil)
47
+ super(3, init_value)
46
48
  end
47
49
  def roll
48
- @result = rand(sides)-1
49
- end
50
- def inspect
51
- "[#{['-', ' ', '+'][@result+1]}] (dF)"
50
+ @value = rand(sides)-1
52
51
  end
53
52
 
53
+ def to_s
54
+ "[#{['-', ' ', '+'][@value+1]}]"
55
+ end
56
+
54
57
  protected
55
- def valid_result?(result)
56
- [1,0,-1].include?(result)
58
+ def valid_value?(val)
59
+ [1,0,-1].include?(val)
57
60
  end
58
61
  end
59
62
  end
data/lib/tabletop/pool.rb CHANGED
@@ -35,8 +35,8 @@ module Tabletop
35
35
  sum <=> operand.to_int
36
36
  end
37
37
 
38
- def results
39
- map {|die| die.result}
38
+ def values
39
+ map {|die| die.value}
40
40
  end
41
41
  def dice
42
42
  fudge = nil
@@ -66,7 +66,7 @@ module Tabletop
66
66
  self
67
67
  end
68
68
  def sum
69
- inject(0) {|sum, d| sum + d.result}
69
+ inject(0) {|sum, d| sum + d.value}
70
70
  end
71
71
  def to_int
72
72
  sum
@@ -74,17 +74,15 @@ module Tabletop
74
74
  def sets
75
75
  result = {}
76
76
  each do |die|
77
- result[die.result] = count {|d| d.result == die.result}
77
+ result[die.value] = count {|d| d.value == die.value}
78
78
  end
79
79
  result.sort_by{|height, width| [width, height] }.collect {|i| i[1].to_s+"x"+i[0].to_s}.reverse
80
80
  end
81
81
  def highest(n=1)
82
- sorted = sort_by {|d| d.result}.reverse
83
- Pool.new(sorted.first(n))
82
+ Pool.new(sort.reverse.first(n))
84
83
  end
85
84
  def lowest(n=1)
86
- sorted = sort_by {|d| d.result}
87
- Pool.new(sorted.first(n))
85
+ Pool.new(sort.first(n))
88
86
  end
89
87
  def drop_highest(n=1)
90
88
  Pool.new(self-highest(n))
@@ -94,7 +92,7 @@ module Tabletop
94
92
  end
95
93
  def drop(to_drop)
96
94
  to_drop = [to_drop].flatten #turn it into an array if it isn't one.
97
- kept = reject{|die| to_drop.any?{|drop_value| die.result == drop_value }}
95
+ kept = reject{|die| to_drop.any?{|drop_value| die.value == drop_value }}
98
96
  return Pool.new(kept)
99
97
  end
100
98
 
@@ -104,9 +102,9 @@ module Tabletop
104
102
  new_pool =[]
105
103
  union.each do |die|
106
104
  if die.class == FudgeDie
107
- new_pool << FudgeDie.new(die.result)
105
+ new_pool << FudgeDie.new(die.value)
108
106
  else
109
- new_pool << Die.new(die.sides, die.result)
107
+ new_pool << Die.new(die.sides, die.value)
110
108
  end
111
109
  end
112
110
  Pool.new(new_pool)
@@ -0,0 +1,138 @@
1
+ require_relative 'pool'
2
+
3
+ module Tabletop
4
+
5
+ class Possibility
6
+ attr_reader :outcomes, :conditions
7
+
8
+ def initialize(outcomes, conditions)
9
+ @outcomes = outcomes
10
+ @conditions = conditions
11
+ end
12
+ end
13
+
14
+ class Roll
15
+ attr_reader :pool, :possibilities
16
+
17
+ def initialize(pool=nil, &block)
18
+ if pool
19
+ raise ArgumentError if pool.class != Tabletop::Pool
20
+ end
21
+ @pool = pool
22
+ @possibilities = []
23
+ @die_sides = nil
24
+ @static_modifier = 0
25
+ @roll_modifier = 0
26
+ @result_set = false
27
+ instance_eval(&block)
28
+ unless @result_set
29
+ set_result(:sum)
30
+ end
31
+ end
32
+
33
+ def effects
34
+ results = []
35
+
36
+ if @difficulty
37
+ results << "Success" if result >= @difficulty
38
+ end
39
+
40
+ @possibilities.each do |poss|
41
+ if meets?(poss)
42
+ poss.outcomes.each do |outcome|
43
+ if Roll === outcome
44
+ results << outcome.roll.effects
45
+ else
46
+ results << outcome
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ if results.empty?
54
+ results << nil
55
+ end
56
+
57
+ results.unshift(result)
58
+ end
59
+
60
+ def roll(opts={})
61
+ @roll_modifier = opts[:modifier] ? opts[:modifier] : 0
62
+ if @die_sides
63
+ if opts[:pool]
64
+ @pool = opts[:pool].dX(@die_sides)
65
+ else
66
+ raise ArgumentError
67
+ end
68
+ end
69
+ if opts[:difficulty]
70
+ @difficulty = opts[:difficulty]
71
+ end
72
+ @pool.roll
73
+ self
74
+ end
75
+
76
+ def meets?(p)
77
+ answer = true
78
+ if p.conditions[:>=]
79
+ if p.conditions[:>=] > sum
80
+ answer = false
81
+ end
82
+ end
83
+ if p.conditions[:==]
84
+ answer = false if p.conditions[:==] != sum
85
+ end
86
+ answer
87
+ end
88
+
89
+ def sum
90
+ @pool.sum + @static_modifier + @roll_modifier
91
+ end
92
+
93
+ # instance_eval methods
94
+
95
+ ## Possibility-creating methods
96
+ def at_least(value, *outcomes)
97
+ @possibilities << Possibility.new(outcomes, :>= => value)
98
+ end
99
+
100
+ def equals(values, *outcomes)
101
+ if values.class == Range
102
+ values.each do |val|
103
+ @possibilities << Possibility.new(outcomes, :== => val)
104
+ end
105
+ else
106
+ @possibilities << Possibility.new(outcomes, :== => values)
107
+ end
108
+ end
109
+
110
+ def set_result(symbol, args={})
111
+ if symbol == :count
112
+ @count_at_least = args[:at_least]
113
+ @count_doubles = args[:doubles]
114
+ def result
115
+ normal = @pool.count {|die| die.value >= @count_at_least}
116
+ extra = @count_doubles ? @pool.count {|die| die.value == @count_doubles} : 0
117
+ normal + extra
118
+ end
119
+ else
120
+ def result
121
+ sum
122
+ end
123
+ end
124
+ @result_set = true
125
+ end
126
+
127
+ # instance-variable-setting methods
128
+ def add(mod)
129
+ @static_modifier = mod
130
+ end
131
+
132
+ def sides(num_sides)
133
+ @die_sides = num_sides
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -1,3 +1,3 @@
1
1
  module Tabletop
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/tabletop.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require_relative 'fixnum'
2
2
  require_relative 'tabletop/die'
3
3
  require_relative 'tabletop/pool'
4
+ require_relative 'tabletop/roll'
data/spec/die_spec.rb CHANGED
@@ -2,187 +2,170 @@ require 'spec_helper'
2
2
 
3
3
  module Tabletop
4
4
  describe Die do
5
+
5
6
  before :each do
6
7
  @d6_2 = Die.new(6, 2)
7
8
  @d6_3 = Die.new(6, 3)
8
9
  end
10
+
9
11
  describe "#sides" do
10
12
  it "can be accessed" do
11
- d = Die.new(6)
12
- d.sides.should == 6
13
- d = Die.new(20)
14
- d.sides.should == 20
15
- d = Die.new(7)
16
- d.sides.should equal(7)
13
+ (2..10).each do |i|
14
+ Die.new(i).sides.should == i
15
+ end
17
16
  end
17
+
18
18
  it "is 6 by default" do
19
- d = Die.new
20
- d.sides.should equal(6)
19
+ Die.new.sides.should == 6
21
20
  end
22
- it "cannot be 0 or less" do
21
+
22
+ it "cannot be 1 or less" do
23
23
  lambda { Die.new(0) }.should raise_error(ArgumentError)
24
+ lambda { Die.new(1) }.should raise_error(ArgumentError)
24
25
  lambda { Die.new(-5) }.should raise_error(ArgumentError)
25
26
  end
27
+
26
28
  it "cannot be a non-integer" do
27
29
  lambda { Die.new(0.1) }.should raise_error(ArgumentError)
28
30
  lambda { Die.new(5.7694) }.should raise_error(ArgumentError)
29
31
  lambda { Die.new("foof") }.should raise_error(ArgumentError)
30
32
  end
31
33
  end
32
- describe "#result" do
33
- before :each do
34
- Random.srand(10)
35
- end
34
+
35
+ describe "#value" do
36
36
  it "should be random on instantiation by default" do
37
- d = Die.new
38
- d.result.should equal(2)
39
- d = Die.new(10)
40
- d.result.should equal(5)
41
- d = Die.new(50)
42
- d.result.should equal(16)
37
+ Random.srand(10)
38
+ Die.new.value.should == 2
39
+ Die.new(10).value.should == 5
40
+ Die.new(50).value.should == 16
43
41
  end
42
+
44
43
  it "can be set to a given value on instantiation" do
45
- Die.new(6, 5).result.should == 5
46
- Die.new(10, 2).result.should == 2
44
+ Die.new(6, 5).value.should == 5
45
+ Die.new(10, 2).value.should == 2
47
46
  end
47
+
48
48
  it "cannot be a non-integer" do
49
49
  lambda { Die.new(0.1) }.should raise_error(ArgumentError)
50
50
  lambda { Die.new(5.7694) }.should raise_error(ArgumentError)
51
51
  lambda { Die.new("foof") }.should raise_error(ArgumentError)
52
52
  end
53
53
  end
54
- describe "#result=" do
54
+
55
+ describe "#value=" do
55
56
  it "can only be set to an integer i, where 0 < i <= sides" do
56
57
  d = Die.new
57
- lambda { d.result = 0 }.should raise_error(ArgumentError)
58
- lambda { d.result = -5 }.should raise_error(ArgumentError)
59
- lambda { d.result = 7 }.should raise_error(ArgumentError)
58
+ lambda { d.value = 0 }.should raise_error(ArgumentError)
59
+ lambda { d.value = -5 }.should raise_error(ArgumentError)
60
+ lambda { d.value = 7 }.should raise_error(ArgumentError)
60
61
  d = Die.new(10)
61
- d.result = 7
62
- lambda { d.result = 22 }.should raise_error(ArgumentError)
62
+ d.value = 7
63
+ lambda { d.value = 22 }.should raise_error(ArgumentError)
63
64
  end
64
65
  end
66
+
65
67
  describe "#roll" do
66
68
  before(:each) do
67
69
  Random.srand(10)
68
70
  end
71
+
69
72
  context "six sides" do
70
- it "should return a random result between 1 and @sides" do
71
- d = Die.new
72
- #d.roll.should == 2 # This result gets swallowed by the init roll
73
- d.roll.should == 6
74
- d.roll.should == 5
75
- d.roll.should == 1
76
- end
77
- it "should alter the result appropriately" do
78
- d = Die.new
79
- #d.roll # Covered by the initial roll
80
- d.result.should == 2
81
- d.roll
82
- d.result.should == 6
83
- d.roll
84
- d.result.should == 5
85
- d.roll
86
- d.result.should == 1
73
+ before(:each) do
74
+ @d6 = Die.new #=> 2
87
75
  end
88
- end
89
- context "eleven sides" do
90
- it "should return a random result between 1 and @sides" do
91
- d = Die.new(11)
92
- # d.roll.should == 10 # This result gets swallowed by the init roll
93
- d.roll.should == 5
94
- d.roll.should == 1
95
- d.roll.should == 2
76
+
77
+ it "should return a random result between 1 and @sides" do
78
+ @d6.roll.should == 6
79
+ @d6.roll.should == 5
80
+ @d6.roll.should == 1
96
81
  end
97
- it "should alter the result appropriately" do
98
- d = Die.new(11)
99
- #d.roll # covered by the initial roll
100
- d.result.should == 10
101
- d.roll
102
- d.result.should == 5
103
- d.roll
104
- d.result.should == 1
105
- d.roll
106
- d.result.should == 2
82
+
83
+ it "should alter the value appropriately" do
84
+ 10.times do
85
+ @d6.roll.should == @d6.value
86
+ end
107
87
  end
108
88
  end
109
89
  end
110
- describe "#inspect" do
111
- before(:each) do
112
- Random.srand(10)
113
- end
114
- it "should be interesting" do
115
- Die.new.inspect.should == "2 (d6)"
116
- Die.new.inspect.should == "6 (d6)"
90
+
91
+ describe "#to_str" do
92
+ it "should tell you the die's value" do
93
+ 5.times do
94
+ d = Die.new(rand(10)+3)
95
+ "#{d}".should == "[#{d.value}]/d#{d.sides}"
96
+ end
117
97
  end
118
98
  end
99
+
119
100
  describe "#to_int" do
120
- it "returns the result" do
101
+ it "returns the value" do
121
102
  d = Die.new
122
- d.to_int.should == d.result
103
+ d.to_int.should == d.value
123
104
  end
124
105
  end
106
+
125
107
  describe "<=>" do
126
108
  it "compares numeric objects with the die's value" do
127
- (@d6_3 < 4).should be_true
128
- (@d6_3 < 2).should be_false
129
- (@d6_3 > 2).should be_true
130
- (@d6_3 > 4).should be_false
131
- (@d6_3 >= 3).should be_true
132
- (@d6_3 >= 10).should be_false
133
- (@d6_3 <= 3).should be_true
134
- (@d6_3 <= 2).should be_false
135
- (@d6_3 == 3).should be_true
136
- (@d6_3 == 6).should be_false
109
+ (1..10).each do |i|
110
+ (@d6_3 <=> i) == (3 <=> i)
111
+ end
137
112
  end
113
+
138
114
  it "compares dice with each other by value" do
139
- (@d6_3 > @d6_2).should be_true
140
- (@d6_3 < @d6_2).should be_false
141
- (@d6_2 < @d6_3).should be_true
142
- (@d6_2 > @d6_3).should be_false
143
- (@d6_3 == @d6_2).should be_false
115
+ (@d6_3 <=> @d6_2) == (3 <=> 2)
144
116
  end
145
117
  end
146
118
  end
119
+
147
120
  describe FudgeDie do
148
121
  before(:each) do
149
122
  Random.srand(10)
150
123
  @fudge = FudgeDie.new
151
124
  end
125
+
152
126
  describe "#sides" do
153
127
  it "is always 3" do
154
128
  @fudge.sides.should == 3
155
129
  end
156
130
  end
157
- describe "#result" do
131
+
132
+ describe "#value" do
158
133
  it "can be set on instantiation" do
159
- FudgeDie.new(1).result.should == 1
160
- FudgeDie.new(0).result.should == 0
161
- FudgeDie.new(-1).result.should == -1
134
+ FudgeDie.new(1).value.should == 1
135
+ FudgeDie.new(0).value.should == 0
136
+ FudgeDie.new(-1).value.should == -1
162
137
  end
138
+
163
139
  it "is randomly rolled if not set" do
164
- @fudge.result.should == 0
140
+ @fudge.value.should == 0
165
141
  end
142
+
166
143
  it "can only be one of either -1, 0, or 1" do
144
+ [-1, 0, 1].each do |v|
145
+ FudgeDie.new(v)
146
+ end
167
147
  lambda {FudgeDie.new(2)}.should raise_error(ArgumentError)
168
148
  lambda {FudgeDie.new(0.6)}.should raise_error(ArgumentError)
169
149
  lambda {FudgeDie.new("5")}.should raise_error(ArgumentError)
170
150
  end
171
151
  end
172
- describe "#result=" do
152
+
153
+ describe "#value=" do
173
154
  it "cannot be set to anything but -1, 0, or 1" do
174
- lambda {@fudge.result = 2}.should raise_error(ArgumentError)
175
- lambda {@fudge.result = 0.6}.should raise_error(ArgumentError)
176
- lambda {@fudge.result = "5"}.should raise_error(ArgumentError)
177
- @fudge.result = 1
178
- @fudge.result.should == 1
155
+ lambda {@fudge.value = 2}.should raise_error(ArgumentError)
156
+ lambda {@fudge.value = 0.6}.should raise_error(ArgumentError)
157
+ lambda {@fudge.value = "5"}.should raise_error(ArgumentError)
158
+ [-1, 0, 1].each do |v|
159
+ @fudge.value = v
160
+ end
179
161
  end
180
162
  end
181
- describe "#inspect" do
182
- it "should look like plusses, minuses and spaces" do
183
- FudgeDie.new(1).inspect.should == "[+] (dF)"
184
- FudgeDie.new(0).inspect.should == "[ ] (dF)"
185
- FudgeDie.new(-1).inspect.should == "[-] (dF)"
163
+
164
+ describe "#to_s" do
165
+ it "should return cute little dice with symbols" do
166
+ FudgeDie.new(1).to_s.should == "[+]"
167
+ FudgeDie.new(0).to_s.should == "[ ]"
168
+ FudgeDie.new(-1).to_s.should == "[-]"
186
169
  end
187
170
  end
188
171
  end
data/spec/fixnum_spec.rb CHANGED
@@ -8,6 +8,7 @@ module Tabletop
8
8
  4.d7.dice.should == ["4d7"]
9
9
  10.d100.class.should == Pool
10
10
  end
11
+
11
12
  it "shows up in respond_to?(:dN)" do
12
13
  1.respond_to?(:d50).should be_true
13
14
  end
data/spec/pool_spec.rb CHANGED
@@ -9,6 +9,7 @@ module Tabletop
9
9
  @mixed = Pool.new("2d10 d20")
10
10
  @fudge = Pool.new("3dF")
11
11
  end
12
+
12
13
  describe "#dice" do
13
14
  it "should return an array of dice notation" do
14
15
  @mixed.dice.should == ["2d10","d20"]
@@ -18,31 +19,36 @@ module Tabletop
18
19
  Pool.new("d20 2dF 2d10").dice.should == ["2d10","d20", "2dF"]
19
20
  end
20
21
  end
22
+
21
23
  describe "[]" do
22
24
  it "should access Die objects" do
23
25
  @d6[0].class.should == Die
24
26
  @fudge[0].class.should == FudgeDie
25
27
  end
26
28
  end
29
+
27
30
  describe "+" do
28
31
  it "should join Pools into new Pools" do
29
32
  (@mixed + @d17s).class == Pool
30
33
  (@d6 + @fudge).class == Pool
31
34
  end
35
+
32
36
  it "should persist die types" do
33
37
  (@d6 + @fudge)[1].class.should == FudgeDie
34
38
  end
39
+
35
40
  it "should join pools without rolling them" do
36
41
  merge = @d6 + @d17s
37
- merge.results.should == [2, 5, 16, 1, 17, 9]
42
+ merge.values.should == [2, 5, 16, 1, 17, 9]
38
43
  merge.roll
39
- merge.results.should == [4, 17, 5, 16, 12, 12]
44
+ merge.values.should == [4, 17, 5, 16, 12, 12]
40
45
  end
46
+
41
47
  it "creates genuinely new pools" do
42
48
  merge = @d6 + @d17s
43
49
  merge.roll
44
- @d6.results.should == [2]
45
- @d17s.results.should == [5, 16, 1, 17, 9]
50
+ @d6.values.should == [2]
51
+ @d17s.values.should == [5, 16, 1, 17, 9]
46
52
  end
47
53
 
48
54
  it "should alter #dice accordingly" do
@@ -54,69 +60,83 @@ module Tabletop
54
60
  (@d17s + @mixed).dice.should == ["2d10","5d17","d20"]
55
61
  (@mixed + @fudge).dice.should == ["2d10", "d20", "3dF"]
56
62
  end
63
+
57
64
  it "should understand adding a number as looking for a sum result" do
58
65
  (@d17s + 5).should == 53
59
66
  (@mixed + @d6 + 10).should == 34
60
67
  (@fudge + 3).should == 2
61
68
  end
69
+
62
70
  it "should add literal dice arrays as if they were pools" do
63
71
  g = @d6 + [Die.new(6,3), Die.new(10, 4)]
64
- g.results.should == [2, 3, 4]
72
+ g.values.should == [2, 3, 4]
65
73
  g.dice.should == ["2d6", "d10"]
66
74
  g.roll
67
- @d6.results.should == [2]
75
+ @d6.values.should == [2]
68
76
  end
77
+
69
78
  it "should reject adding anything else" do
70
79
  lambda {@d6 + "foof"}.should raise_error(ArgumentError)
71
80
  lambda {@d6 + [Die.new, Object.new]}.should raise_error(ArgumentError)
72
81
  end
73
82
  end
74
- describe "#results" do
83
+
84
+ describe "#values" do
75
85
  it "should be an array of random numbers" do
76
- @d6.results.should == [2]
77
- @d17s.results.should == [5, 16, 1, 17, 9]
78
- @mixed.results.should == [10, 1, 11]
86
+ @d6.values.should == [2]
87
+ @d17s.values.should == [5, 16, 1, 17, 9]
88
+ @mixed.values.should == [10, 1, 11]
79
89
  end
80
90
  end
91
+
81
92
  describe "#roll" do
82
93
  it "should return the Pool itself" do
83
94
  @d6.roll.length.should == @d6.length
84
95
  @d6.roll.class.should == @d6.class
85
96
  end
97
+
86
98
  it "should store the new values" do
87
99
  @d6.roll
88
- @d6.results.should == [4]
100
+ @d6.values.should == [4]
89
101
  @d17s.roll
90
- @d17s.results.should == [17, 5, 16, 12, 12]
102
+ @d17s.values.should == [17, 5, 16, 12, 12]
91
103
  @mixed.roll
92
- @mixed.results.should == [2, 9, 5]
104
+ @mixed.values.should == [2, 9, 5]
93
105
  end
106
+ it "can roll only dice below a certain value"
107
+ it "can roll only dice above a certain value"
108
+ it "can roll only dice equal to a certain value"
94
109
  end
110
+
95
111
  describe "#sum" do
96
112
  it "should sum the dice values" do
97
- @d6.sum.should == 2
98
- @d17s.sum.should == 48
99
- @mixed.sum.should == 22
100
- @fudge.sum.should == -1
113
+ 5.times do
114
+ p = 10.d6
115
+ p.sum.should == p.values.inject(:+)
116
+ end
101
117
  end
118
+
102
119
  it "should be aliased to #to_int" do
103
- @d6.to_int.should == @d6.sum
104
- @d17s.to_int.should == @d17s.sum
105
- @mixed.to_int.should == @mixed.sum
106
- @fudge.to_int.should == @fudge.sum
120
+ 5.times do
121
+ p = 10.d6
122
+ p.to_int.should == p.sum
123
+ end
107
124
  end
108
125
  end
126
+
109
127
  describe "<=>" do
110
128
  it "should compare the sums of different pools" do
111
129
  @d17s.should >= @d6
112
130
  @d6.should < Pool.new([Die.new(4, 4)])
113
131
  end
132
+
114
133
  it "should compare pools to numbers" do
115
134
  @d6.should < 10
116
135
  @d6.should == 2
117
136
  @d17s.should <= 49
118
137
  end
119
138
  end
139
+
120
140
  describe "#sets" do
121
141
  it "should list the sets, in order by height and width" do
122
142
  ore = Pool.new("10d10")
@@ -127,67 +147,78 @@ module Tabletop
127
147
  ore.sets.should == ["3x9", "2x8", "2x7", "1x10", "1x3", "1x1"]
128
148
  end
129
149
  end
150
+
130
151
  describe "#highest" do
131
152
  it "should return a pool of the highest-value die" do
132
153
  @d6.highest.class.should == Pool
133
- @d6.highest.results.should == [2]
134
- @d17s.highest.results.should == [17]
135
- @mixed.highest.results.should == [11]
154
+ @d6.highest.values.should == [2]
155
+ @d17s.highest.values.should == [17]
156
+ @mixed.highest.values.should == [11]
136
157
  end
158
+
137
159
  it "should return as many items as are specified" do
138
- @d6.highest(5).results.should == [2]
139
- @d17s.highest(3).results.should == [17, 16, 9]
140
- @mixed.highest(2).results.should == [11, 10]
160
+ @d6.highest(5).values.should == [2]
161
+ @d17s.highest(3).values.should == [17, 16, 9]
162
+ @mixed.highest(2).values.should == [11, 10]
141
163
  end
142
164
  end
165
+
143
166
  describe "#lowest" do
144
167
  it "should return a pool of the lowest-value die." do
145
- @d6.lowest.results.should == [2]
168
+ @d6.lowest.values.should == [2]
146
169
  @d17s.lowest.class.should == Pool
147
- @d17s.lowest.results.should == [1]
148
- @mixed.lowest.results.should == [1]
170
+ @d17s.lowest.values.should == [1]
171
+ @mixed.lowest.values.should == [1]
149
172
  end
173
+
150
174
  it "should return as many items as are specified" do
151
- @d6.lowest(5).results.should == [2]
152
- @d17s.lowest(3).results.should == [1, 5, 9]
153
- @mixed.lowest(2).results.should == [1, 10]
175
+ @d6.lowest(5).values.should == [2]
176
+ @d17s.lowest(3).values.should == [1, 5, 9]
177
+ @mixed.lowest(2).values.should == [1, 10]
154
178
  end
155
179
  end
180
+
156
181
  describe "#drop_highest" do
157
182
  it "should return a new pool missing the highest result" do
158
183
  p = @d17s.drop_highest
159
- p.results.should == [5, 16, 1, 9]
160
- @d17s.results.should == [5, 16, 1, 17, 9]
184
+ p.values.should == [5, 16, 1, 9]
185
+ @d17s.values.should == [5, 16, 1, 17, 9]
161
186
  end
187
+
162
188
  it "should drop as many items as are specified and are possible" do
163
189
  p = @d17s.drop_highest(2)
164
- p.results.should == [5, 1, 9]
190
+ p.values.should == [5, 1, 9]
165
191
  p = @d6.drop_highest(10)
166
- p.results.should == []
192
+ p.values.should == []
167
193
  end
168
194
  end
195
+
169
196
  describe "#drop_lowest" do
170
197
  it "should return a pool missing the lowest result" do
171
198
  p = @d17s.drop_lowest
172
- p.results.should == [5, 16, 17, 9]
173
- @d17s.results.should == [5, 16, 1, 17, 9]
199
+ p.values.should == [5, 16, 17, 9]
200
+ @d17s.values.should == [5, 16, 1, 17, 9]
174
201
  end
202
+
175
203
  it "should drop as many items as are specified" do
176
204
  p = @d17s.drop_lowest(2)
177
- p.results.should == [16, 17, 9]
205
+ p.values.should == [16, 17, 9]
178
206
  end
179
207
  end
208
+
180
209
  describe "#drop" do
181
210
  it "should drop any dice of the specified value" do
182
211
  ore = Pool.new("10d10")
183
- ore.results.should == [4, 1, 5, 7, 9, 2, 9, 5, 2, 4]
212
+ ore.values.should == [4, 1, 5, 7, 9, 2, 9, 5, 2, 4]
184
213
  at_least_two = ore.drop(1)
185
- at_least_two.results.should == [4, 5, 7, 9, 2, 9, 5, 2, 4]
214
+ at_least_two.values.should == [4, 5, 7, 9, 2, 9, 5, 2, 4]
186
215
  at_least_three = ore.drop([1,2])
187
- at_least_three.results.should == [4, 5, 7, 9, 9, 5, 4]
216
+ at_least_three.values.should == [4, 5, 7, 9, 9, 5, 4]
188
217
  end
189
218
  end
219
+
190
220
  context "pool has been emptied" do
191
221
  end
222
+
192
223
  end
193
224
  end
data/spec/roll_spec.rb ADDED
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ module Tabletop
4
+ describe Roll do
5
+
6
+ describe "#pool" do
7
+ it "accesses the roll's pool" do
8
+ d20 = Roll.new(1.d20) do
9
+ end
10
+ d20.pool.class.should == Pool
11
+ d20.pool.length.should == 1
12
+ d20.pool[0].sides.should == 20
13
+ end
14
+ end
15
+
16
+ context "when used as an attribute or skill roll" do
17
+
18
+ context "for Apocalypse World" do
19
+
20
+ it "can be used with a static difficulty and dice pool, and both static and dynamic modifiers" do
21
+ cool = 1
22
+ under_fire = Roll.new(2.d6) do
23
+ add cool
24
+ at_least 10, "You do it"
25
+ equals (7..9), "You flinch, hesitate, or stall"
26
+ end
27
+ 20.times do
28
+ mod = [1, 0, -1].sample
29
+ if mod != 0
30
+ under_fire.roll(:modifier => mod)
31
+ else
32
+ under_fire.roll
33
+ end
34
+ if under_fire.pool.sum + cool + mod >= 10
35
+ effect = "You do it"
36
+ elsif under_fire.pool.sum + cool + mod >= 7
37
+ effect = "You flinch, hesitate, or stall"
38
+ end
39
+ under_fire.effects.should == [under_fire.pool.sum + cool + mod, effect]
40
+ end
41
+ end
42
+ end
43
+
44
+ context "in Exalted" do
45
+ before :each do
46
+ @exalted = Roll.new do
47
+ set_result :count, :at_least=>7, :doubles=>10
48
+ sides 10
49
+ end
50
+ end
51
+
52
+ def count_successes(pool)
53
+ pool.count {|die| die.value >= 7 } + pool.count {|die| die.value == 10 }
54
+ end
55
+
56
+ it "can be instantiated without a complete pool" do
57
+ @exalted.roll(:pool=>6)
58
+ @exalted.pool.length.should == 6
59
+ @exalted.pool.each do |die|
60
+ die.sides.should == 10
61
+ end
62
+ @exalted.roll(:pool=>10)
63
+ @exalted.pool.length.should == 10
64
+ lambda {@exalted.roll}.should raise_error(ArgumentError)
65
+ end
66
+
67
+ it "can count successes" do
68
+ @exalted.roll(:pool=>10)
69
+ 10.times do
70
+ @exalted.effects.should == [count_successes(@exalted.pool), nil]
71
+ end
72
+ end
73
+
74
+ it "can determine success" do
75
+ (1..10).each do |i|
76
+ @exalted.roll(:pool=>6, :difficulty=>i)
77
+ effect = (count_successes(@exalted.pool) >= i) ? "Success" : nil
78
+ @exalted.effects.should == [count_successes(@exalted.pool), effect]
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+ end
85
+
86
+ context "when used like a table" do
87
+ it "can have nested results" do
88
+ rps = Roll.new(1.d3) {
89
+ equals 1, "rock"
90
+ equals 2, "paper"
91
+ equals 3, "scissors"
92
+ }
93
+ jkp = Roll.new(1.d3) {
94
+ equals 1, "guu"
95
+ equals 2, "choki"
96
+ equals 3, "paa"
97
+ }
98
+ fist_game = Roll.new(1.d2) {
99
+ equals 1, "Rock Paper Scissors", rps
100
+ equals 2, "JanKenPon", jkp
101
+ }
102
+ a, b, c = fist_game.roll.effects
103
+
104
+ [1,2].include?(a).should be_true
105
+
106
+ if a == 1
107
+ b.should == "Rock Paper Scissors"
108
+ else
109
+ b.should == "JanKenPon"
110
+ end
111
+
112
+ [1,2,3].include?(c[0]).should be_true
113
+
114
+ b[1].class.should == String
115
+
116
+ end
117
+ before :each do
118
+ ill_fortune = Roll.new(1.d10) do
119
+ equals 1, "Accident"
120
+ equals 2, "Maltreatment"
121
+ equals 3, "Disease"
122
+ equals 4, "Dropped"
123
+ equals 5, "Parental Loss"
124
+ equals 6, "Family Loss"
125
+ equals 7, "Torment"
126
+ equals 8, "Homeless"
127
+ equals 9, "Ghost"
128
+ equals 10, "Prying Eyes"
129
+ end
130
+ good_fortune = Roll.new(1.d10) do
131
+ equals 1, "Dreamer"
132
+ equals 2, "Childhood Patron"
133
+ equals 3, "Active Youth"
134
+ equals 4, "Apt Pupil"
135
+ equals 5, "Save a Life"
136
+ equals 6, "First Love"
137
+ equals 7, "Childhood Friend"
138
+ equals 8, "Heirloom"
139
+ equals 9, "Spirit Blessing"
140
+ equals 10, "Temple Assistant"
141
+ end
142
+ @childhood_event = Roll.new(1.d10) do
143
+ equals (1..4), "Roll on ill fortune table", ill_fortune
144
+ equals (5..8), "Roll on good fortune table", good_fortune
145
+ equals (9..10), "Roll on both ill and good fortune tables", ill_fortune, good_fortune
146
+ end
147
+ end
148
+
149
+ it "can compose multiple nested results" do
150
+ 20.times do
151
+ @childhood_event.roll
152
+ if @childhood_event.effects[0] >= 9
153
+ @childhood_event.effects.length.should == 4
154
+ else
155
+ @childhood_event.effects.length.should == 3
156
+ end
157
+ end
158
+ end
159
+
160
+
161
+ end
162
+
163
+ end
164
+ end
data/tabletop.gemspec CHANGED
@@ -20,8 +20,11 @@ Gem::Specification.new do |s|
20
20
  s.rubygems_version = '1.3.7'
21
21
  s.specification_version = 3
22
22
 
23
- s.files = `git ls-files`.split("\n")
24
- s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
23
+ ignores = File.readlines(".gitignore").grep(/\S+/).map {|s| s.chomp }
24
+ dotfiles = [".gitignore"]
25
+
26
+ s.files = Dir["**/*"].reject {|f| File.directory?(f) || ignores.any? {|i| File.fnmatch(i, f) } } + dotfiles
27
+ s.test_files = s.files.grep(/^spec\//)
25
28
  s.require_paths = ['lib']
26
29
 
27
30
  s.add_development_dependency 'rspec'
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabletop
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 1
9
- version: 0.0.1
4
+ prerelease:
5
+ version: 0.1.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Nick Novitski
@@ -14,73 +10,62 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-08-10 00:00:00 -07:00
18
- default_executable:
13
+ date: 2011-08-10 00:00:00 Z
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: rspec
22
- prerelease: false
23
17
  requirement: &id001 !ruby/object:Gem::Requirement
24
18
  none: false
25
19
  requirements:
26
20
  - - ">="
27
21
  - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
22
  version: "0"
31
23
  type: :development
24
+ prerelease: false
32
25
  version_requirements: *id001
33
26
  - !ruby/object:Gem::Dependency
34
27
  name: bundler
35
- prerelease: false
36
28
  requirement: &id002 !ruby/object:Gem::Requirement
37
29
  none: false
38
30
  requirements:
39
31
  - - ">="
40
32
  - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
33
  version: "0"
44
34
  type: :development
35
+ prerelease: false
45
36
  version_requirements: *id002
46
37
  - !ruby/object:Gem::Dependency
47
38
  name: bueller
48
- prerelease: false
49
39
  requirement: &id003 !ruby/object:Gem::Requirement
50
40
  none: false
51
41
  requirements:
52
42
  - - ">="
53
43
  - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
44
  version: "0"
57
45
  type: :development
46
+ prerelease: false
58
47
  version_requirements: *id003
59
48
  - !ruby/object:Gem::Dependency
60
49
  name: rake
61
- prerelease: false
62
50
  requirement: &id004 !ruby/object:Gem::Requirement
63
51
  none: false
64
52
  requirements:
65
53
  - - ">="
66
54
  - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
55
  version: "0"
70
56
  type: :development
57
+ prerelease: false
71
58
  version_requirements: *id004
72
59
  - !ruby/object:Gem::Dependency
73
60
  name: rdoc
74
- prerelease: false
75
61
  requirement: &id005 !ruby/object:Gem::Requirement
76
62
  none: false
77
63
  requirements:
78
64
  - - ">="
79
65
  - !ruby/object:Gem::Version
80
- segments:
81
- - 0
82
66
  version: "0"
83
67
  type: :development
68
+ prerelease: false
84
69
  version_requirements: *id005
85
70
  description: Tabletop aims to provide a simple way of describing, automating and tracking the tools and tasks involved in "analog" games, determining results from the motions and properties of various dice and chips.
86
71
  email: nicknovitski@gmail.com
@@ -92,22 +77,23 @@ extra_rdoc_files:
92
77
  - LICENSE
93
78
  - README.markdown
94
79
  files:
95
- - .gitignore
96
80
  - Gemfile
97
- - LICENSE
98
- - README.markdown
99
- - Rakefile
100
81
  - lib/fixnum.rb
101
- - lib/tabletop.rb
102
82
  - lib/tabletop/die.rb
103
83
  - lib/tabletop/pool.rb
84
+ - lib/tabletop/roll.rb
104
85
  - lib/tabletop/version.rb
86
+ - lib/tabletop.rb
87
+ - LICENSE
88
+ - Rakefile
89
+ - README.markdown
105
90
  - spec/die_spec.rb
106
91
  - spec/fixnum_spec.rb
107
92
  - spec/pool_spec.rb
93
+ - spec/roll_spec.rb
108
94
  - spec/spec_helper.rb
109
95
  - tabletop.gemspec
110
- has_rdoc: true
96
+ - .gitignore
111
97
  homepage: http://github.com/njay/tabletop
112
98
  licenses: []
113
99
 
@@ -121,6 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
107
  requirements:
122
108
  - - ">="
123
109
  - !ruby/object:Gem::Version
110
+ hash: -2668007910377914487
124
111
  segments:
125
112
  - 0
126
113
  version: "0"
@@ -129,15 +116,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
116
  requirements:
130
117
  - - ">="
131
118
  - !ruby/object:Gem::Version
132
- segments:
133
- - 1
134
- - 3
135
- - 7
136
119
  version: 1.3.7
137
120
  requirements: []
138
121
 
139
122
  rubyforge_project:
140
- rubygems_version: 1.3.7
123
+ rubygems_version: 1.8.7
141
124
  signing_key:
142
125
  specification_version: 3
143
126
  summary: A Ruby DSL for role-playing games
@@ -145,4 +128,5 @@ test_files:
145
128
  - spec/die_spec.rb
146
129
  - spec/fixnum_spec.rb
147
130
  - spec/pool_spec.rb
131
+ - spec/roll_spec.rb
148
132
  - spec/spec_helper.rb