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.
- data/README.md +16 -0
- data/VERSION.yml +4 -0
- data/lib/roleplay.rb +3 -0
- data/lib/roleplay/core_ext.rb +3 -0
- data/lib/roleplay/core_ext/enumerable.rb +9 -0
- data/lib/roleplay/core_ext/float.rb +25 -0
- data/lib/roleplay/core_ext/kernel.rb +22 -0
- data/lib/roleplay/error.rb +4 -0
- data/lib/roleplay/roll.rb +119 -0
- data/test/roleplay/core_ext/enumerable_test.rb +11 -0
- data/test/roleplay/core_ext/float_test.rb +18 -0
- data/test/roleplay/core_ext/kernel_test.rb +10 -0
- data/test/roleplay/roll_test.rb +138 -0
- data/test/test_helper.rb +8 -0
- metadata +80 -0
data/README.md
ADDED
|
@@ -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.
|
data/VERSION.yml
ADDED
data/lib/roleplay.rb
ADDED
|
@@ -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,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,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
|
data/test/test_helper.rb
ADDED
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
|
+
|