pfrpg_core 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +7 -0
- data/lib/pfrpg_core/affectable.rb +7 -0
- data/lib/pfrpg_core/bonus.rb +8 -0
- data/lib/pfrpg_core/bonuses.rb +57 -0
- data/lib/pfrpg_core/effect.rb +39 -0
- data/lib/pfrpg_core/effect_processor.rb +49 -0
- data/lib/pfrpg_core/feat_finder.rb +49 -0
- data/lib/pfrpg_core/filterable.rb +11 -0
- data/lib/pfrpg_core/level_parser.rb +34 -0
- data/lib/pfrpg_core/math_helper.rb +6 -0
- data/lib/pfrpg_core/null_object.rb +37 -0
- data/lib/pfrpg_core/prerequisite.rb +58 -0
- data/lib/pfrpg_core/quick_classed.rb +37 -0
- data/lib/pfrpg_core/version.rb +3 -0
- data/lib/pfrpg_core.rb +11 -0
- data/test/feat_totaler_test.rb +14 -0
- data/test/helper.rb +20 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 04e10d025ab0c0eabc6af56107b277194255e478
|
4
|
+
data.tar.gz: 7c2dfb7e770d7399d495ab5eae8aaedabcd97adc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f755c54bebcc8ede1c1cdcd7c5aa094b00de3f63e3e46d7cec2f40d6c97f7538fb5af38d6bfee79fc6763ef39c8e014c8e912536cb72bbcf479681f7ba85e97
|
7
|
+
data.tar.gz: a69a83f0f8d0e08596b5f2f49cd2fa94475862194449c6ba6d5af2765eff2c5ad1aed2b896866a7ff1e5f9623cc1370be5a36a3f765005951b78857605f31adb
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module PfrpgCore
|
2
|
+
class Bonuses
|
3
|
+
attr_reader :bonus_pool
|
4
|
+
def initialize
|
5
|
+
@bonus_pool = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def specials
|
9
|
+
['speed', 'damage_reduction', 'spell_resistance', 'class_skill']
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(key)
|
13
|
+
if specials.include? key
|
14
|
+
return self.send(key)
|
15
|
+
else
|
16
|
+
return NullObject.maybe(@bonus_pool[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def plus(key, value)
|
21
|
+
begin
|
22
|
+
v = MathHelper.is_number(value) ? value.to_i : value
|
23
|
+
if specials.include? key
|
24
|
+
if @bonus_pool[key]
|
25
|
+
@bonus_pool[key] << value
|
26
|
+
else
|
27
|
+
@bonus_pool[key] = [value]
|
28
|
+
end
|
29
|
+
elsif @bonus_pool[key]
|
30
|
+
@bonus_pool[key] += v
|
31
|
+
else
|
32
|
+
@bonus_pool[key] = v
|
33
|
+
end
|
34
|
+
rescue Exception => e
|
35
|
+
ap @bonus_pool
|
36
|
+
ap "Trying to add #{key}, #{value}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def speed
|
41
|
+
[ @bonus_pool['speed'] ].flatten
|
42
|
+
end
|
43
|
+
|
44
|
+
def class_skill
|
45
|
+
[ @bonus_pool['class_skill'] ].flatten
|
46
|
+
end
|
47
|
+
|
48
|
+
def damage_reduction
|
49
|
+
[ @bonus_pool['damage_reduction'] ].flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
def spell_resistance
|
53
|
+
[ @bonus_pool['spell_resistance'] ].flatten
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class PfrpgCore::Effect
|
2
|
+
attr_accessor :type, :key, :value, :affect
|
3
|
+
def initialize(type, key, value, affect=nil)
|
4
|
+
# standard effect proc; add a value
|
5
|
+
basic = Proc.new do |character, attribute, value|
|
6
|
+
character.bonuses.plus(attribute, value)
|
7
|
+
end
|
8
|
+
affect ||= basic
|
9
|
+
@type = type
|
10
|
+
@key = key
|
11
|
+
@value = value
|
12
|
+
@affect = affect
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.load(effects_string)
|
16
|
+
return effects_string if effects_string.instance_of? Array
|
17
|
+
return [ effects_string ] if effects_string.instance_of? PfrpgCore::Effect
|
18
|
+
return [] if effects_string.nil? || effects_string.empty?
|
19
|
+
unless effects_string.instance_of? String
|
20
|
+
ap "Error effect: "
|
21
|
+
ap effects_string
|
22
|
+
end
|
23
|
+
raise Exception unless effects_string.instance_of? String
|
24
|
+
effects_string.split(";").map { |effect| parse_effect(effect) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse_effect(string)
|
28
|
+
p = string.split(":")
|
29
|
+
type = p[0]
|
30
|
+
key = p[1]
|
31
|
+
value = p[2]
|
32
|
+
PfrpgCore::Effect.new(type, key, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def apply(character)
|
36
|
+
@affect.call(character, @key, @value)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module PfrpgCore
|
2
|
+
class EffectProcessor
|
3
|
+
attr_reader :character, :effects
|
4
|
+
def initialize(character, effects)
|
5
|
+
@character = character
|
6
|
+
@effects = effects
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_effects
|
10
|
+
final = []
|
11
|
+
no_stacking = effects_hash(@effects)
|
12
|
+
no_stacking.keys.each do |key|
|
13
|
+
if Tables::Bonus.stackable?(key) || Tables::Bonus.special?(key)
|
14
|
+
final << no_stacking[key]
|
15
|
+
else
|
16
|
+
final << find_max(no_stacking[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
return final.flatten
|
20
|
+
end
|
21
|
+
|
22
|
+
def effects_hash(effects)
|
23
|
+
hash = {}
|
24
|
+
effects.each do |effect|
|
25
|
+
if hash[effect.key] == nil
|
26
|
+
hash[effect.key] = []
|
27
|
+
end
|
28
|
+
hash[effect.key] << effect
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_max(effects)
|
34
|
+
max = nil
|
35
|
+
effects.each do |e|
|
36
|
+
if max == nil || is_larger(e.value, max.value)
|
37
|
+
max = e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return max
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_larger(a, b)
|
44
|
+
int_a = MathHelper.is_number(a) ? a.to_i : -999
|
45
|
+
int_b = MathHelper.is_number(b) ? b.to_i : -999
|
46
|
+
int_a > int_b
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module PfrpgCore
|
2
|
+
class FeatFinder
|
3
|
+
attr_reader :entity, :feats
|
4
|
+
def initialize(entity, feats)
|
5
|
+
@entity = entity
|
6
|
+
@feats = feats
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_feats
|
10
|
+
feats = @feats
|
11
|
+
feats = filter_feats_by_owned(feats, entity)
|
12
|
+
feats = filter_feats_by_prereq(feats, entity)
|
13
|
+
return feats
|
14
|
+
end
|
15
|
+
|
16
|
+
def filter_feats_by_owned(feats, entity)
|
17
|
+
owned_feats = entity.feats
|
18
|
+
feats.select do |f|
|
19
|
+
repeat_list.include?(f.name) ||
|
20
|
+
doesnt_include_feat(owned_feats, f)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def doesnt_include_feat(feats, feat)
|
25
|
+
!(feats.find { |x| x.name == feat.name })
|
26
|
+
end
|
27
|
+
|
28
|
+
def filter_feats_by_prereq(feats, entity)
|
29
|
+
feats.select do |f|
|
30
|
+
prereq_check(entity, f)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def prereq_check(entity, feat)
|
35
|
+
prereqs = Prerequisite.load(feat.prereq_code)
|
36
|
+
prereqs.all? { |x| x.match(entity) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def repeat_list
|
40
|
+
[
|
41
|
+
'Exotic Weapon Proficiency',
|
42
|
+
'Martial Weapon Proficiency',
|
43
|
+
'Weapon Focus',
|
44
|
+
'Spell Focus',
|
45
|
+
'Custom Feat'
|
46
|
+
]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module PfrpgCore
|
2
|
+
class LevelParser
|
3
|
+
attr_reader :level_string, :levels
|
4
|
+
def initialize(level_string)
|
5
|
+
@level_string = level_string
|
6
|
+
@levels = parse
|
7
|
+
end
|
8
|
+
|
9
|
+
def total
|
10
|
+
return @levels.values.inject(0) { |sum, l| sum + l }
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse
|
14
|
+
levels = {}
|
15
|
+
splits = @level_string.split(';')
|
16
|
+
raise Exception if splits[0].empty?
|
17
|
+
|
18
|
+
splits.each do |s|
|
19
|
+
level = s.split(':')[1].to_i
|
20
|
+
hc = s.split(':')[0]
|
21
|
+
raise Exception if (hc.empty?)
|
22
|
+
levels[hc] = level
|
23
|
+
end
|
24
|
+
return levels
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid_total_level
|
28
|
+
return total <= 20
|
29
|
+
rescue Exception
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class PfrpgCore::NullObject < Numeric
|
2
|
+
def to_a; []; end
|
3
|
+
def to_s; ""; end
|
4
|
+
def to_str; ""; end
|
5
|
+
def to_f; 0.0; end
|
6
|
+
def to_i; 0; end
|
7
|
+
|
8
|
+
def empty?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_json(options={})
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(*args, &block)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.maybe(value)
|
21
|
+
case value
|
22
|
+
when nil then NullObject.new
|
23
|
+
else value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def +(other)
|
28
|
+
case other
|
29
|
+
when String
|
30
|
+
to_s + other
|
31
|
+
when Fixnum
|
32
|
+
to_i + other
|
33
|
+
when Float
|
34
|
+
to_f + other
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module PfrpgCore
|
2
|
+
class Prerequisite
|
3
|
+
|
4
|
+
def initialize(attribute, value, matcher=nil)
|
5
|
+
default_matcher = Proc.new do |character, attribute, value|
|
6
|
+
true
|
7
|
+
end
|
8
|
+
@attribute = attribute
|
9
|
+
@value = value
|
10
|
+
@matcher = matcher || default_matcher
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.load(prereq_string)
|
14
|
+
begin
|
15
|
+
prereqs = []
|
16
|
+
p = prereq_string.split(";")
|
17
|
+
p.each { |x| prereqs << parse_prereq(x) }
|
18
|
+
prereqs
|
19
|
+
rescue Exception
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_prereq(string)
|
25
|
+
p = string.split(":")
|
26
|
+
type = p[0]
|
27
|
+
attribute = p[1]
|
28
|
+
value = p[2]
|
29
|
+
case type
|
30
|
+
when "class"
|
31
|
+
Prerequisite::ClassPrereq.new(attribute, value)
|
32
|
+
when "attribute"
|
33
|
+
Prerequisite::AttributePrereq.new(attribute, value)
|
34
|
+
when "alignment"
|
35
|
+
Prerequisite::AlignmentPrereq.new(attribute, value)
|
36
|
+
when "feat"
|
37
|
+
Prerequisite::FeatPrereq.new(attribute, value)
|
38
|
+
when "skill"
|
39
|
+
Prerequisite::SkillPrereq.new(attribute, value)
|
40
|
+
when "class_feature"
|
41
|
+
Prerequisite::HeroclassFeaturePrereq.new(attribute, value)
|
42
|
+
when "combat"
|
43
|
+
Prerequisite::BabPrereq.new(attribute, value)
|
44
|
+
when "language"
|
45
|
+
Prerequisite::LanguagePrereq.new(attribute, value)
|
46
|
+
when "misc"
|
47
|
+
Prerequisite::MiscPrereq.new(attribute, value)
|
48
|
+
else
|
49
|
+
Prerequisite.new(attribute, value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def match(character)
|
54
|
+
@matcher.call(character, @attribute, @value)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# basic class math. classes must provide latest_levels method
|
2
|
+
# with a map of heroclass name & level
|
3
|
+
module PfrpgCore
|
4
|
+
module QuickClassed
|
5
|
+
def get_class_level(heroclass)
|
6
|
+
l = latest_levels[heroclass.name]
|
7
|
+
l ||= 0
|
8
|
+
return l
|
9
|
+
end
|
10
|
+
|
11
|
+
def explode_levels
|
12
|
+
# TODO: implement me
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_total_level
|
17
|
+
latest_levels.keys.inject(0) do |key, sum|
|
18
|
+
sum = sum + latest_levels[key]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def hit_dice
|
23
|
+
get_total_level
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_caster_level
|
27
|
+
# TODO constantize somewhere better
|
28
|
+
caster_classes = ['Bard', 'Cleric', 'Druid', 'Paladin', 'Ranger', 'Sorcerer', 'Wizard']
|
29
|
+
caster_levels = []
|
30
|
+
latest_levels.keys.each do |key|
|
31
|
+
caster_levels << latest_levels[key] if caster_classes.include? key
|
32
|
+
end
|
33
|
+
ek_level = get_class_level(Heroclass.by_name('Eldritch Knight'))
|
34
|
+
return (caster_levels.max + ek_level) || 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/pfrpg_core.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'pfrpg_core/effect'
|
2
|
+
require 'pfrpg_core/effect_processor'
|
3
|
+
require 'pfrpg_core/math_helper'
|
4
|
+
require 'pfrpg_core/null_object'
|
5
|
+
|
6
|
+
Dir[File.expand_path(File.join(File.dirname(File.absolute_path(__FILE__)), 'pfrpg_core/')) + "/**/*.rb"].each do |file|
|
7
|
+
require file
|
8
|
+
end
|
9
|
+
|
10
|
+
module PfrpgCore
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test/helper'
|
3
|
+
|
4
|
+
class FeatFinderTest < Minitest::Test
|
5
|
+
|
6
|
+
def test_filter_feats_by_owned
|
7
|
+
e = PsuedoEntity.new
|
8
|
+
feats = [ PsuedoFeat.new('Feat1') ]
|
9
|
+
finder = FeatFinder.new(e, feats)
|
10
|
+
assert finder.find_feats.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class Helper
|
2
|
+
|
3
|
+
PsuedoFeat = Struct.new(:name) do
|
4
|
+
def prereq_code
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class PsuedoEntity
|
10
|
+
attr_accessor :feats
|
11
|
+
def initialize(feats = nil)
|
12
|
+
@feats = feats
|
13
|
+
@feats ||= default_feats
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_feats
|
17
|
+
[ PsuedoFeat.new('Feat1') ]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pfrpg_core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jordan OMara
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.1.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.1.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: core
|
42
|
+
email:
|
43
|
+
- jordan@herosheets.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- Rakefile
|
49
|
+
- lib/pfrpg_core.rb
|
50
|
+
- lib/pfrpg_core/affectable.rb
|
51
|
+
- lib/pfrpg_core/bonus.rb
|
52
|
+
- lib/pfrpg_core/bonuses.rb
|
53
|
+
- lib/pfrpg_core/effect.rb
|
54
|
+
- lib/pfrpg_core/effect_processor.rb
|
55
|
+
- lib/pfrpg_core/feat_finder.rb
|
56
|
+
- lib/pfrpg_core/filterable.rb
|
57
|
+
- lib/pfrpg_core/level_parser.rb
|
58
|
+
- lib/pfrpg_core/math_helper.rb
|
59
|
+
- lib/pfrpg_core/null_object.rb
|
60
|
+
- lib/pfrpg_core/prerequisite.rb
|
61
|
+
- lib/pfrpg_core/quick_classed.rb
|
62
|
+
- lib/pfrpg_core/version.rb
|
63
|
+
- test/feat_totaler_test.rb
|
64
|
+
- test/helper.rb
|
65
|
+
homepage: http://herosheets.com
|
66
|
+
licenses: []
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 2.2.2
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: PFRPG core
|
88
|
+
test_files:
|
89
|
+
- test/feat_totaler_test.rb
|
90
|
+
- test/helper.rb
|