nairda-roleplay 0.1.1

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.
@@ -0,0 +1,16 @@
1
+ Roleplay
2
+ ========
3
+
4
+ Ever wanted to write some old school, kick-ass role-playing stuff in Ruby, but
5
+ never had enough support for doing it? Well, now you can!
6
+
7
+ Roleplay is a set of libraries helpful in wide variety of RPG development. In
8
+ the current state it contains:
9
+
10
+ * DSL for creating complex dice rolls (e.g. `13.d8 * 6 - 10.d20 + 2`). See
11
+ Roleplay::Roll for more.
12
+
13
+ COPYRIGHT
14
+ ---------
15
+
16
+ Copyright 2009 Adrian Pacała. See LICENSE for details.
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 1
@@ -0,0 +1,3 @@
1
+ require 'roleplay/core_ext'
2
+ require 'roleplay/error'
3
+ require 'roleplay/roll'
@@ -0,0 +1,3 @@
1
+ Dir[File.dirname(__FILE__) + '/core_ext/**/*.rb'].sort.each do |path|
2
+ require path
3
+ end
@@ -0,0 +1,9 @@
1
+ module Enumerable
2
+ ##
3
+ # Calculates sum of the collection.
4
+ #
5
+ # @return Object class depending on type of stored elements
6
+ def sum
7
+ inject(nil) { |sum, x| sum ? sum + x : x }
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ class Float
2
+ ##
3
+ # Rounds self to given number of decimal places.
4
+ #
5
+ # @param [Fixnum] n places to round to
6
+ def round_to(n)
7
+ (self * 10 ** n).round.to_f / 10 ** n
8
+ end
9
+
10
+ ##
11
+ # Rounds down self to given number of decimal places.
12
+ #
13
+ # @param [Fixnum] n places to ceil to
14
+ def ceil_to(n)
15
+ (self * 10 ** n).ceil.to_f / 10 ** n
16
+ end
17
+
18
+ ##
19
+ # Rounds up self to given number of decimal places.
20
+ #
21
+ # @param [Fixnum] n places to floor to
22
+ def floor_to(n)
23
+ (self * 10 ** n).floor.to_f / 10 ** n
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'inline'
2
+
3
+ module Kernel
4
+ inline do |builder|
5
+ builder.add_to_init 'srand(time(NULL));'
6
+ builder.c %{
7
+ VALUE random_list(int length, int minimum, int maximum)
8
+ {
9
+ int i;
10
+ int range = 1 + maximum - minimum;
11
+ VALUE list = rb_ary_new2(length);
12
+
13
+ for (i = 0; i < length; i++)
14
+ {
15
+ rb_ary_store(list, i, INT2NUM((rand() % range) + minimum));
16
+ }
17
+
18
+ return list;
19
+ }
20
+ }
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ module Roleplay
2
+ class Error < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,119 @@
1
+ module Roleplay
2
+ # Class for generating dice rolls, sprinkled with small DSL.
3
+ class Roll
4
+ class InvalidOperatorError < Error
5
+ end
6
+
7
+ # List of valid modifier operators.
8
+ OPERATORS = [:+, :-, :*, :/, :%, :**].freeze
9
+
10
+ # Number of dice to be rolled.
11
+ attr_accessor :count
12
+
13
+ # Type of die to be used in this particular roll.
14
+ attr_accessor :die
15
+
16
+ # Modifier chain.
17
+ attr_reader :modifiers
18
+
19
+ ##
20
+ # Creates new Roll instance.
21
+ #
22
+ # @param [Fixnum] count number of dice to be rolled
23
+ # @param [Fixnum] die type of die to be used
24
+ # @raise ArgumentError if given +count+ is a negative number
25
+ # @raise ArgumentError if given +die+ is a negative number
26
+ def initialize(count, die)
27
+ raise ArgumentError, "dice count can't be negative" if count < 0
28
+ raise ArgumentError, "die type can't be negative" if die < 0
29
+ @count = count
30
+ @die = die
31
+ @modifiers = []
32
+ end
33
+
34
+ ##
35
+ # Adds new modifier at the end of the current stack.
36
+ #
37
+ # @param [Symbol, String] operator modifier operator
38
+ # @param [Roll, Fixnum] value modifier value
39
+ # @return [Roll] self
40
+ # @raise InvalidOperatorError if given operator is not available for
41
+ # applying to the roll
42
+ def push_modifier(operator, value)
43
+ raise InvalidOperatorError unless
44
+ OPERATORS.include?(operator.to_sym)
45
+ @modifiers << [operator, value]
46
+ self
47
+ end
48
+
49
+ ##
50
+ # Applies all modifiers to given value.
51
+ #
52
+ # @param [Fixnum] base value to apply the modifiers to
53
+ # @param [Symbol, String] method name of the method to call on each
54
+ # modifying value before applying it to +base+
55
+ # @return [Fixnum] result of the calculation
56
+ def apply_modifiers(base, method)
57
+ method = method.to_sym
58
+
59
+ @modifiers.each do |mod|
60
+ value = mod[1].respond_to?(method) ? mod[1].send(method) : mod[1].to_i
61
+ base = base.send(mod[0], value)
62
+ end
63
+
64
+ base
65
+ end
66
+
67
+ ##
68
+ # Returns the lowest possible value of current roll (with modifiers).
69
+ #
70
+ # @return [Fixnum]
71
+ def minimum
72
+ apply_modifiers(@count, :minimum)
73
+ end
74
+
75
+ alias_method :min, :minimum
76
+
77
+ ##
78
+ # Returns the highest possible value of current roll (with modifiers).
79
+ #
80
+ # @return [Fixnum]
81
+ def maximum
82
+ apply_modifiers(@count * @die, :maximum)
83
+ end
84
+
85
+ alias_method :max, :maximum
86
+
87
+ ##
88
+ # Executes current roll and returns the result with applied modifiers.
89
+ #
90
+ # @yieldparam [Fixnum] result result of each die roll without modifiers
91
+ # @return [Fixnum] total result of the roll
92
+ def generate(&block)
93
+ results = random_list(@count, 1, @die).sum
94
+ results.each { |results| yield(results) } if block_given?
95
+ apply_modifiers(results, :generate)
96
+ end
97
+
98
+ private
99
+
100
+ ##
101
+ # This allows us to do the crazy DSL stuff.
102
+ #
103
+ # @raise NoMethodError if the missing method is not recognized as a valid
104
+ # modifier operator
105
+ # @see push_modifier
106
+ def method_missing(method, *args)
107
+ push_modifier(method, args[0])
108
+ rescue InvalidOperatorError
109
+ raise NoMethodError, method.to_s
110
+ end
111
+ end
112
+ end
113
+
114
+ class Integer
115
+ # More DSL magic!
116
+ [2, 3, 4, 6, 8, 10, 12, 20, 100].each do |sides|
117
+ define_method("d#{sides}") { Roleplay::Roll.new(self, sides) }
118
+ end
119
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ class EnumerableTest < Test::Unit::TestCase
4
+ should 'sum numeric values' do
5
+ assert_equal 6, [1, 2, 3].sum
6
+ end
7
+
8
+ should 'sum text values' do
9
+ assert_equal 'abc', %w(a b c).sum
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ class FloatTest < Test::Unit::TestCase
4
+ should 'round to specified decimal places' do
5
+ assert_equal 9.1, 9.11.round_to(1)
6
+ assert_equal 12.346, 12.34567.round_to(3)
7
+ end
8
+
9
+ should 'ceil to specified decimal places' do
10
+ assert_equal 9.2, 9.11.ceil_to(1)
11
+ assert_equal 12.346, 12.34567.ceil_to(3)
12
+ end
13
+
14
+ should 'floor to specified decimal places' do
15
+ assert_equal 9.1, 9.11.floor_to(1)
16
+ assert_equal 12.345, 12.34567.floor_to(3)
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ class KernelTest < Test::Unit::TestCase
4
+ should 'generate list of random values' do
5
+ values = random_list(10, 1, 100)
6
+ assert_instance_of Array, values
7
+ assert_equal 10, values.length
8
+ values.each { |value| assert value >= 1 && value <= 100 }
9
+ end
10
+ end
@@ -0,0 +1,138 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RollTest < Test::Unit::TestCase
4
+ include Roleplay
5
+
6
+ should 'properly alias methods' do
7
+ roll = Roll.new(1, 6)
8
+ assert_equal roll.minimum, roll.min
9
+ assert_equal roll.maximum, roll.max
10
+ end
11
+
12
+ context 'instantiation' do
13
+ should 'raise error on negative number of roll' do
14
+ assert_raise(ArgumentError) { Roll.new(-1, 6) }
15
+ end
16
+
17
+ should 'raise error on negative roll type' do
18
+ assert_raise(ArgumentError) { Roll.new(1, -6) }
19
+ end
20
+
21
+ should 'create a roll without modifiers' do
22
+ roll = Roll.new(3, 6)
23
+ assert roll
24
+ assert_equal 3, roll.count
25
+ assert_equal 6, roll.die
26
+ end
27
+
28
+ should 'create a roll with numeric modifiers' do
29
+ roll = Roll.new(5, 20)
30
+ roll * (3 + 4)
31
+ roll - 10
32
+ assert_equal 5, roll.count
33
+ assert_equal 20, roll.die
34
+ assert_equal [[:*, 7], [:-, 10]], roll.modifiers
35
+ end
36
+ end
37
+
38
+ context 'modifiers' do
39
+ should 'raise error on invalid modifier' do
40
+ roll = Roll.new(1, 6)
41
+
42
+ assert_raise(Roll::InvalidOperatorError) do
43
+ roll.push_modifier(:bad, 'modifier')
44
+ end
45
+ end
46
+
47
+ context 'stack' do
48
+ setup { @roll = Roll.new(1, 12) }
49
+
50
+ should 'append numeric modifiers' do
51
+ @roll.push_modifier :+, 1
52
+ @roll.push_modifier :/, (2 + 3)
53
+ @roll.push_modifier :*, ((4 * 5) - 6)
54
+ assert_equal [[:+, 1], [:/, 5], [:*, 14]], @roll.modifiers
55
+ end
56
+
57
+ should 'append roll modifiers' do
58
+ another_roll = Roll.new(5, 6)
59
+ @roll.push_modifier :+, another_roll
60
+ assert_equal :+, @roll.modifiers[0][0]
61
+ assert_instance_of Roll, @roll.modifiers[0][1]
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'minimum and maximum values of a roll' do
67
+ should 'without any modifiers' do
68
+ roll = Roll.new(5, 10)
69
+ assert_equal 5, roll.minimum
70
+ assert_equal 50, roll.maximum
71
+ end
72
+
73
+ should 'with numeric modifiers' do
74
+ roll = Roll.new(5, 10)
75
+ roll * ((12 + 24) / 3)
76
+ roll + 7
77
+ assert_equal 67, roll.minimum
78
+ assert_equal 607, roll.maximum
79
+ end
80
+
81
+ should 'with roll modifiers' do
82
+ roll = Roll.new(5, 10)
83
+ roll * Roll.new(1, 12)
84
+ roll - Roll.new(5, 6)
85
+ assert_equal 0, roll.minimum
86
+ assert_equal 570, roll.maximum
87
+ end
88
+ end
89
+
90
+ context 'result generation' do
91
+ should 'roll not using any modifiers' do
92
+ roll = Roll.new(3, 6)
93
+ result = roll.generate
94
+ assert result >= roll.minimum && result <= roll.maximum
95
+ end
96
+
97
+ should 'roll using numeric modifiers' do
98
+ roll = Roll.new(3, 6)
99
+ roll * 3
100
+ roll + 7
101
+ result = roll.generate
102
+ assert result >= roll.minimum && result <= roll.maximum
103
+ end
104
+
105
+ should 'roll using roll modifiers' do
106
+ roll = Roll.new(3, 6)
107
+ roll * Roll.new(1, 20)
108
+ roll + Roll.new(3, 12)
109
+ result = roll.generate
110
+ assert result >= roll.minimum && result <= roll.maximum
111
+ end
112
+ end
113
+
114
+ context 'DSL' do
115
+ context 'instantiation' do
116
+ should 'define integer methods for creating rolls' do
117
+ [2, 3, 4, 6, 8, 10, 12, 20, 100].each do |die|
118
+ assert_respond_to 1, "d#{die}"
119
+ end
120
+ end
121
+
122
+ should 'create roll with numeric modifiers' do
123
+ roll = 3.d6 * 3 - 5
124
+ assert_instance_of Roll, roll
125
+ assert_equal [[:*, 3], [:-, 5]], roll.modifiers
126
+ assert_equal 4, roll.minimum
127
+ assert_equal 49, roll.maximum
128
+ end
129
+
130
+ should 'create roll with other roll as modifier' do
131
+ roll = 3.d6 - 1 + 2.d10 * 2
132
+ assert_instance_of Roll, roll
133
+ assert_equal 6, roll.minimum
134
+ assert_equal 57, roll.maximum
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'mocha'
4
+ require 'shoulda'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+
8
+ require 'roleplay'
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nairda-roleplay
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - "Adrian Paca\xC5\x82a"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-28 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: RubyInline
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "3.8"
24
+ version:
25
+ description: Roleplay
26
+ email: adrian@zenbe.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README.md
35
+ - VERSION.yml
36
+ - lib/roleplay
37
+ - lib/roleplay/core_ext
38
+ - lib/roleplay/core_ext/enumerable.rb
39
+ - lib/roleplay/core_ext/float.rb
40
+ - lib/roleplay/core_ext/kernel.rb
41
+ - lib/roleplay/core_ext.rb
42
+ - lib/roleplay/error.rb
43
+ - lib/roleplay/roll.rb
44
+ - lib/roleplay.rb
45
+ - test/roleplay
46
+ - test/roleplay/core_ext
47
+ - test/roleplay/core_ext/enumerable_test.rb
48
+ - test/roleplay/core_ext/float_test.rb
49
+ - test/roleplay/core_ext/kernel_test.rb
50
+ - test/roleplay/roll_test.rb
51
+ - test/test_helper.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/nairda/roleplay
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --inline-source
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.2.0
76
+ signing_key:
77
+ specification_version: 2
78
+ summary: Roleplay
79
+ test_files: []
80
+