nairda-roleplay 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+