namelessjon-exalted 0.1.0
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/LICENSE +20 -0
- data/README +10 -0
- data/Rakefile +47 -0
- data/VERSION.yml +4 -0
- data/lib/exalted/character.rb +126 -0
- data/lib/exalted/stat.rb +80 -0
- data/lib/exalted/stat_block.rb +60 -0
- data/lib/exalted/stat_set.rb +119 -0
- data/lib/exalted.rb +10 -0
- metadata +70 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Jonathan Stott
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
begin
|
4
|
+
gem('mislav-hanna')
|
5
|
+
require 'hanna/rdoctask'
|
6
|
+
rescue
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
end
|
9
|
+
require 'rcov/rcovtask'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |s|
|
14
|
+
s.name = "exalted"
|
15
|
+
s.summary = "Classes to help with Exalted"
|
16
|
+
s.email = "jonathan.stott@gmail.com"
|
17
|
+
s.homepage = "http://github.com/namelessjon/exalted"
|
18
|
+
s.description = "Classes to help with characters for Exalted, the RPG by WW."
|
19
|
+
s.authors = ["Jonathan Stott"]
|
20
|
+
s.add_dependency('extlib', '~> 0.9.9')
|
21
|
+
s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
|
22
|
+
end
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::TestTask.new do |t|
|
28
|
+
t.libs << 'lib'
|
29
|
+
t.pattern = 'spec/**/*_spec.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
rdoc.rdoc_dir = 'rdoc'
|
35
|
+
rdoc.title = 'exalted'
|
36
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
40
|
+
|
41
|
+
Rcov::RcovTask.new do |t|
|
42
|
+
t.libs << 'spec'
|
43
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
44
|
+
t.verbose = true
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default => :rcov
|
data/VERSION.yml
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# character.rb
|
3
|
+
# Jonathan D. Stott <jonathan.stott@gmail.com>
|
4
|
+
|
5
|
+
module Exalted
|
6
|
+
|
7
|
+
ATTRIBUTES = [
|
8
|
+
['physical', %w{strength dexterity stamina}],
|
9
|
+
['social', %w{charisma manipulation appearance}],
|
10
|
+
['mental', %w{perception intelligence wits}]
|
11
|
+
]
|
12
|
+
|
13
|
+
ABILITIES = {
|
14
|
+
'DB1e' => [
|
15
|
+
['air', %w{linguistics lore occult thrown stealth} ],
|
16
|
+
['earth', %w{awareness craft endurance martial_arts resistance}],
|
17
|
+
['fire', %w{athletics dodge melee presence socialize}],
|
18
|
+
['water', %w{brawl bureaucracy investigation larceny sail}],
|
19
|
+
['wood', %w{archery medicine performance ride survival}]
|
20
|
+
],
|
21
|
+
'DB2e' => [
|
22
|
+
['air', %w{linguistics lore occult thrown stealth} ],
|
23
|
+
['earth', %w{awareness craft integrity resistance war}],
|
24
|
+
['fire', %w{athletics dodge melee presence socialize}],
|
25
|
+
['water', %w{martial_arts bureaucracy investigation larceny sail}],
|
26
|
+
['wood', %w{archery medicine performance ride survival}]
|
27
|
+
],
|
28
|
+
'S1e' => [
|
29
|
+
['dawn', %w{archery brawl martial_arts melee thrown}],
|
30
|
+
['zenith', %w{endurance performance presence resistance survival }],
|
31
|
+
['twilight', %w{craft investigation lore medicine occult}],
|
32
|
+
['night', %w{athletics awareness dodge larceny stealth}],
|
33
|
+
['eclipse', %w{bureaucracy linguistics ride sail socialize}]
|
34
|
+
]
|
35
|
+
|
36
|
+
}
|
37
|
+
|
38
|
+
class Character
|
39
|
+
attr_reader :name, :caste, :type, :languages, :attributes, :abilities
|
40
|
+
|
41
|
+
# Creates a new Character
|
42
|
+
#
|
43
|
+
# This method expects a hash, with the following keys
|
44
|
+
#
|
45
|
+
# name:: The character's name
|
46
|
+
# caste:: The character's caste (optional, see also aspect)
|
47
|
+
# aspect:: The character's aspect (optional, see also caste)
|
48
|
+
# type:: The Exalted type. Currently DB1e or DB2e or S1e
|
49
|
+
# languages:: The languages spoken by the character (Array)
|
50
|
+
# abilities:: A hash of 'ability => rating' pairs
|
51
|
+
# attributes:: A hash of 'attribute => rating' pairs
|
52
|
+
# favoured:: An array of the character's favoured abilities
|
53
|
+
def initialize(opts = {})
|
54
|
+
@opts = opts.to_mash
|
55
|
+
|
56
|
+
|
57
|
+
set_basics
|
58
|
+
|
59
|
+
set_attributes
|
60
|
+
|
61
|
+
set_abilities
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def set_basics
|
67
|
+
@name = @opts[:name]
|
68
|
+
@caste = @opts[:caste] || @opts[:aspect]
|
69
|
+
@type = @opts[:type]
|
70
|
+
@languages = @opts[:languages] || []
|
71
|
+
end
|
72
|
+
|
73
|
+
# sets up the attributes for the character
|
74
|
+
def set_attributes
|
75
|
+
# save the raw stuff for ease of reference
|
76
|
+
@raw_attributes = @opts[:attributes]
|
77
|
+
|
78
|
+
# create a new attributes set
|
79
|
+
@attributes = StatBlock.new(:attributes, ATTRIBUTES)
|
80
|
+
|
81
|
+
# setup the attributes set.
|
82
|
+
@raw_attributes.each do |name, rating|
|
83
|
+
@attributes[name].rating = rating
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# sets up the abilities used
|
89
|
+
def set_abilities
|
90
|
+
# save the raw stuff for ease of reference
|
91
|
+
@raw_abilities = @opts[:abilities]
|
92
|
+
@favoureds = @opts[:favoured] || []
|
93
|
+
@specialities = @opts[:specialities] || {}
|
94
|
+
|
95
|
+
# create a new attributes set
|
96
|
+
if ABILITIES[self.type]
|
97
|
+
@abilities = StatBlock.new(:abilities, ABILITIES[self.type])
|
98
|
+
else
|
99
|
+
raise ArgumentError, "I don't know about '#{self.type}' Exalted."
|
100
|
+
end
|
101
|
+
|
102
|
+
# setup the attributes set.
|
103
|
+
@raw_abilities.each do |name, rating|
|
104
|
+
@abilities[name].rating = rating
|
105
|
+
end
|
106
|
+
|
107
|
+
# setup the caste abilities
|
108
|
+
if @abilities[self.caste]
|
109
|
+
@abilities[self.caste].caste = true
|
110
|
+
end
|
111
|
+
|
112
|
+
# set favoureds!
|
113
|
+
@favoureds.each do |a|
|
114
|
+
@abilities[a].favoured = true
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add specialities
|
118
|
+
@specialities.each do |ability, specs|
|
119
|
+
# want a flat array of specs.
|
120
|
+
specs = [specs].flatten
|
121
|
+
@abilities[ability].specialities = specs
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/exalted/stat.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# A Stat object holds all the information about an Exalted stat. This includes
|
2
|
+
# the name, rating, whether it is favoured, or caste and any specialities it
|
3
|
+
# might have.
|
4
|
+
class Exalted::Stat
|
5
|
+
# the stat's name
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
# the stat's rating
|
9
|
+
attr_accessor :rating
|
10
|
+
|
11
|
+
# specialities the stat has
|
12
|
+
attr_accessor :specialities
|
13
|
+
|
14
|
+
# set the favoured status
|
15
|
+
attr_writer :favoured
|
16
|
+
|
17
|
+
# set the caste status
|
18
|
+
attr_writer :caste
|
19
|
+
|
20
|
+
|
21
|
+
# Creates a new stat.
|
22
|
+
#
|
23
|
+
# Options include
|
24
|
+
# favoured:: sets the favoured status of the stat
|
25
|
+
# caste:: sets the caste status of the set
|
26
|
+
# specialities:: Adds specialities to the set
|
27
|
+
# specs:: see specialities
|
28
|
+
def initialize(name, rating = 0, opts={})
|
29
|
+
if Hash === rating
|
30
|
+
opts = rating
|
31
|
+
rating = 0
|
32
|
+
end
|
33
|
+
|
34
|
+
@name = name.downcase.to_sym
|
35
|
+
@rating = rating
|
36
|
+
@favoured = opts.delete(:favoured) || false
|
37
|
+
@caste = opts.delete(:caste) || false
|
38
|
+
specialities = opts.delete(:specialities) || opts.delete(:specs) || []
|
39
|
+
@specialities = specialities.sort
|
40
|
+
end
|
41
|
+
|
42
|
+
# Is the stat favoured?
|
43
|
+
def favoured?
|
44
|
+
(@favoured) ? true : false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Is the stat a caste ability?
|
48
|
+
def caste?
|
49
|
+
(@caste) ? true : false
|
50
|
+
end
|
51
|
+
|
52
|
+
# :nodoc:
|
53
|
+
def eql?(o)
|
54
|
+
return false unless o.is_a?(Exalted::Stat)
|
55
|
+
return false unless self.rating == o.rating
|
56
|
+
return false unless self.favoured? == o.favoured?
|
57
|
+
return false unless self.caste? == o.caste?
|
58
|
+
return false unless self.specialities == o.specialities
|
59
|
+
return true if self.name.eql?(o.name)
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def ==(o)
|
64
|
+
case o
|
65
|
+
when String
|
66
|
+
return true if self.name.to_s == o.downcase
|
67
|
+
when Symbol
|
68
|
+
return true if self.name == o
|
69
|
+
when Exalted::Stat
|
70
|
+
return self.eql?(o)
|
71
|
+
else
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# :nodoc:
|
77
|
+
def inspect
|
78
|
+
"#<Stat:#{@name}:#{rating}:#{@caste || @favoured}:#{@specialities.map {|s| "'#{s}'"}.join(",")}>"
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Exalted
|
2
|
+
# A StatBlock holds several related StatSets, representing a character's
|
3
|
+
# Attributes or Abilities and similar groups of stats.
|
4
|
+
class StatBlock
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
# the name of the statblock
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# stat_sets in the block
|
11
|
+
attr_reader :stat_sets
|
12
|
+
|
13
|
+
# Create a new StatBlock
|
14
|
+
#
|
15
|
+
# The StatBlock is initialized with a name, e.g 'Attributes'
|
16
|
+
# and an array of tuples consisting of the arguments to a StatSet.new call
|
17
|
+
# @stats = [
|
18
|
+
# ['air', %w{linguistics lore occult thrown stealth}],
|
19
|
+
# ...,
|
20
|
+
# ['wood', %w{archery medicine performance ride survival}]
|
21
|
+
# ]
|
22
|
+
# @stat_block = StatBlock.new('abilities', @stats)
|
23
|
+
#
|
24
|
+
def initialize(name, stats)
|
25
|
+
@name = name
|
26
|
+
@stat_sets = []
|
27
|
+
stats.each do |name, abilities|
|
28
|
+
@stat_sets << StatSet.new(name, abilities)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def [](name)
|
34
|
+
# first, check for stat sets
|
35
|
+
stat_set = self.detect {|s| s == name }
|
36
|
+
if stat_set
|
37
|
+
return stat_set
|
38
|
+
else
|
39
|
+
@stat_sets.each do |stat_set|
|
40
|
+
if (stat_set.include?(name))
|
41
|
+
return stat_set[name]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# yields each StatSet in turn to the block.
|
49
|
+
def each
|
50
|
+
@stat_sets.each { |ss| yield ss }
|
51
|
+
end
|
52
|
+
|
53
|
+
# yields each StatSet with stats with a non-zero rating inside to the block, in turn.
|
54
|
+
def each_rated
|
55
|
+
self.each do |ss|
|
56
|
+
yield ss if ss.detect { |s| s.rating > 0 }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Exalted
|
2
|
+
# A StatSet holds a group of related Stats, such as those comprising an
|
3
|
+
# caste or aspect ability grouping. The Set has a name, and a record of the
|
4
|
+
# Stats within it.
|
5
|
+
#
|
6
|
+
# # create a new stat set
|
7
|
+
# @stat_set = StatSet.new('fire', %w{athletics dodge melee presence socialize})
|
8
|
+
#
|
9
|
+
# # access the dodge stat
|
10
|
+
# @stat_set['dodge']
|
11
|
+
# # => #<Stat:dodge:0:false:>
|
12
|
+
#
|
13
|
+
class StatSet
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
# name of the stat set, typically the caste or aspect.
|
17
|
+
attr_reader :name
|
18
|
+
|
19
|
+
# names of the stats in the set
|
20
|
+
attr_reader :stat_names
|
21
|
+
|
22
|
+
# the stats themselves
|
23
|
+
attr_reader :stats
|
24
|
+
|
25
|
+
# is this a set of caste abilities?
|
26
|
+
attr_reader :caste
|
27
|
+
|
28
|
+
def initialize(name, stats)
|
29
|
+
@name = name.to_sym
|
30
|
+
@stat_names = stats
|
31
|
+
@caste = false
|
32
|
+
|
33
|
+
create_stats
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"#<StatSet:#{name}:#{caste}:[#{stats.map {|s| s.inspect }.join(', ')}]>"
|
38
|
+
end
|
39
|
+
|
40
|
+
# hash style access to a Stat, based on the Stat's name.
|
41
|
+
def [](stat_name)
|
42
|
+
self.detect { |stat| stat == stat_name }
|
43
|
+
end
|
44
|
+
|
45
|
+
# yields each stat which has a non-zero rating in turn
|
46
|
+
def each
|
47
|
+
@stats.each do |stat|
|
48
|
+
yield stat
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# yields only stats with a non-zero rating
|
53
|
+
def each_rated
|
54
|
+
self.each do |stat|
|
55
|
+
yield stat if stat.rating > 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# assign caste status to all stats in the set at once.
|
60
|
+
def caste=(caste)
|
61
|
+
if @caste != caste
|
62
|
+
@stats.each do |stat|
|
63
|
+
stat.caste = caste
|
64
|
+
end
|
65
|
+
@caste = caste
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# boolean accessor for if this is a caste stat set or no.
|
70
|
+
def caste?
|
71
|
+
(self.caste) ? true : false
|
72
|
+
end
|
73
|
+
|
74
|
+
# returns the number of stats in the set.
|
75
|
+
#
|
76
|
+
# If called as #size(false), only returns the number of stats with a non-zero
|
77
|
+
# rating
|
78
|
+
def size(all=true)
|
79
|
+
if all
|
80
|
+
@stats.size
|
81
|
+
else
|
82
|
+
@stats.find_all {|s| s.rating > 0 }.size
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def ==(o)
|
87
|
+
case o
|
88
|
+
when String
|
89
|
+
return self.name.to_s == o
|
90
|
+
when Symbol
|
91
|
+
return self.name == o
|
92
|
+
when StatSet
|
93
|
+
return (self == o.name) && (self.stat_names == o.stat_names)
|
94
|
+
else
|
95
|
+
return false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def eql?(o)
|
100
|
+
return false unless o.is_a?(StatSet)
|
101
|
+
return false unless self.name.eql?(o.name)
|
102
|
+
return false unless self.stat_names.eql?(o.stat_names)
|
103
|
+
# detect for stats sharing the same name being not equal.
|
104
|
+
stats_not_eql = self.stat_names.detect { |n| !(self[n].eql?(o[n])) }
|
105
|
+
# if we have a stat that is not equal, we can return false
|
106
|
+
# otherwise, it appears we must return true!
|
107
|
+
return (stats_not_eql) ? false : true
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
def create_stats
|
113
|
+
@stats = []
|
114
|
+
@stat_names.each do |name|
|
115
|
+
@stats << Stat.new(name)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/exalted.rb
ADDED
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: namelessjon-exalted
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Stott
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-27 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: extlib
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.9
|
23
|
+
version:
|
24
|
+
description: Classes to help with characters for Exalted, the RPG by WW
|
25
|
+
email: jonathan.stott@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- LICENSE
|
34
|
+
- README
|
35
|
+
- VERSION.yml
|
36
|
+
- Rakefile
|
37
|
+
- lib/exalted
|
38
|
+
- lib/exalted/stat_set.rb
|
39
|
+
- lib/exalted/stat_block.rb
|
40
|
+
- lib/exalted/stat.rb
|
41
|
+
- lib/exalted/character.rb
|
42
|
+
- lib/exalted.rb
|
43
|
+
has_rdoc: false
|
44
|
+
homepage: http://github.com/namelessjon/exalted
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.2.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: Classes to help with Exalted
|
69
|
+
test_files: []
|
70
|
+
|