pfrpg_core 0.0.2 → 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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +23 -0
  3. data/Rakefile +1 -1
  4. data/lib/pfrpg_core/attack.rb +66 -0
  5. data/lib/pfrpg_core/attributes.rb +113 -0
  6. data/lib/pfrpg_core/avatar_url.rb +15 -0
  7. data/lib/pfrpg_core/bonus.rb +1 -1
  8. data/lib/pfrpg_core/character.rb +83 -0
  9. data/lib/pfrpg_core/class_feature.rb +31 -0
  10. data/lib/pfrpg_core/combat.rb +60 -0
  11. data/lib/pfrpg_core/demographics.rb +30 -0
  12. data/lib/pfrpg_core/derived/combat_bonuses.rb +78 -0
  13. data/lib/pfrpg_core/derived/defense.rb +29 -0
  14. data/lib/pfrpg_core/derived/magic.rb +145 -0
  15. data/lib/pfrpg_core/derived/misc.rb +114 -0
  16. data/lib/pfrpg_core/derived/offense.rb +49 -0
  17. data/lib/pfrpg_core/derived.rb +10 -0
  18. data/lib/pfrpg_core/effect_processor.rb +1 -1
  19. data/lib/pfrpg_core/effect_totaler.rb +29 -0
  20. data/lib/pfrpg_core/equipment_totaler.rb +14 -0
  21. data/lib/pfrpg_core/feat.rb +27 -0
  22. data/lib/pfrpg_core/feat_totaler.rb +61 -0
  23. data/lib/pfrpg_core/feature_duplicator.rb +26 -0
  24. data/lib/pfrpg_core/feature_totaler.rb +86 -0
  25. data/lib/pfrpg_core/filterable.rb +1 -1
  26. data/lib/pfrpg_core/filters/filter.rb +14 -0
  27. data/lib/pfrpg_core/filters/proficiency_mod.rb +34 -0
  28. data/lib/pfrpg_core/filters/prowess_mod.rb +20 -0
  29. data/lib/pfrpg_core/filters/ranged_attack_mod.rb +28 -0
  30. data/lib/pfrpg_core/filters/skill_focus_mod.rb +25 -0
  31. data/lib/pfrpg_core/filters/strength_mod.rb +21 -0
  32. data/lib/pfrpg_core/filters/weapon_finesse_mod.rb +24 -0
  33. data/lib/pfrpg_core/filters/weapon_focus_mod.rb +23 -0
  34. data/lib/pfrpg_core/filters/weapon_mastery_mod.rb +23 -0
  35. data/lib/pfrpg_core/filters/weapon_specialization_mod.rb +22 -0
  36. data/lib/pfrpg_core/filters/weapon_training_mod.rb +22 -0
  37. data/lib/pfrpg_core/inventory.rb +62 -0
  38. data/lib/pfrpg_core/item.rb +42 -0
  39. data/lib/pfrpg_core/level.rb +14 -0
  40. data/lib/pfrpg_core/level_parser.rb +9 -1
  41. data/lib/pfrpg_core/macros/macro.rb +62 -0
  42. data/lib/pfrpg_core/macros/manyshot_macro.rb +12 -0
  43. data/lib/pfrpg_core/macros/power_attack_macro.rb +12 -0
  44. data/lib/pfrpg_core/macros/rapid_shot_macro.rb +12 -0
  45. data/lib/pfrpg_core/macros/sneak_attack_macro.rb +33 -0
  46. data/lib/pfrpg_core/macros/vital_strike_macro.rb +12 -0
  47. data/lib/pfrpg_core/null_object.rb +31 -29
  48. data/lib/pfrpg_core/saving_throws.rb +43 -0
  49. data/lib/pfrpg_core/skills.rb +141 -0
  50. data/lib/pfrpg_core/specializer.rb +48 -0
  51. data/lib/pfrpg_core/spell.rb +37 -0
  52. data/lib/pfrpg_core/spell_books.rb +36 -0
  53. data/lib/pfrpg_core/spells_per_level.rb +53 -0
  54. data/lib/pfrpg_core/version.rb +1 -1
  55. data/lib/pfrpg_core/weapon_training_calculator.rb +36 -0
  56. data/lib/pfrpg_core.rb +13 -2
  57. data/test/alignment_test.rb +30 -0
  58. data/test/attributes_test.rb +50 -0
  59. data/test/bonus_test.rb +29 -0
  60. data/test/feat_totaler_test.rb +24 -7
  61. data/test/helper.rb +1 -1
  62. data/test/levels_test.rb +19 -0
  63. data/test/misc_test.rb +78 -0
  64. data/test/saves_test.rb +54 -0
  65. data/test/skills_test.rb +93 -0
  66. data/test/test_helper.rb +78 -0
  67. metadata +66 -35
  68. data/lib/pfrpg_core/affectable.rb +0 -7
  69. data/lib/pfrpg_core/effect.rb +0 -39
  70. data/lib/pfrpg_core/prerequisite.rb +0 -58
  71. data/lib/pfrpg_core/quick_classed.rb +0 -37
@@ -0,0 +1,145 @@
1
+ module PfrpgCore
2
+ module Derived
3
+ module Magic
4
+ class PfrpgCore::InvalidClassException < Exception; end
5
+ class PfrpgCore::SpellNotFoundException < Exception; end
6
+ class PfrpgCore::TooManySpellsException < Exception; end
7
+ class PfrpgCore::InvalidSpellException < Exception; end
8
+ class PfrpgCore::TooLowAttributeException < Exception; end
9
+
10
+ def spells_per_level(class_name, latest=nil)
11
+ latest ||= self.latest_levels
12
+ level = latest.find { |x| x.class_name == class_name }
13
+ return empty_spells unless level
14
+ return empty_spells if(['Paladin', 'Ranger'].include?(class_name) && level.class_number < 4)
15
+ base = level.heroclass.spells_per_day(level.class_number)
16
+ bonuses = PfrpgTables::Tables::Spells::SpellsPerDay.bonus(attr_mod(class_name))
17
+ total = []
18
+ for i in 0..9 do
19
+ total[i] = base[i] + bonuses[i]
20
+ end
21
+ total = filter_for_max_attribute(class_name, total)
22
+ total = filter_for_high_level(level.class_number, total)
23
+ return total
24
+ end
25
+
26
+ # you can only cast spells up to ($SPELLS_ATTRIBUTE - 10)th level
27
+ def filter_for_max_attribute(class_name, total)
28
+ max_spell_level = attr_static(class_name) - 10
29
+ return filter(total, max_spell_level)
30
+ end
31
+
32
+ def filter_for_high_level(level, total)
33
+ max_spell_level = ((level + 1)/2).floor
34
+ return filter(total, max_spell_level)
35
+ end
36
+
37
+ def filter(array, max)
38
+ for i in (max+1)..9 do
39
+ array[i] = 0
40
+ end
41
+ return array
42
+ end
43
+
44
+ def empty_spells
45
+ [0,0,0,0,0,0,0,0,0,0]
46
+ end
47
+
48
+ def known_sorcerer_spells
49
+ spells = []
50
+ sorc = class_features.select { |x| x.type == 'SorcererSpells' }
51
+ sorc.each do |x|
52
+ x.special.each do |spell|
53
+ spells << spell
54
+ end
55
+ end
56
+ return spells
57
+ end
58
+
59
+ def bloodline
60
+ class_features.find { |x| x.type == 'Bloodline' }
61
+ end
62
+
63
+ def arcane_school
64
+ class_features.find { |x| x.type == 'ArcaneSchool' }
65
+ end
66
+
67
+ def can_arcane?
68
+ arcane_classes = ['Bard', 'Sorcerer', 'Wizard']
69
+ return latest_levels.find { |x| arcane_classes.include? x.class_name }
70
+ end
71
+
72
+ def can_divine?
73
+ divine = false
74
+ latest_levels.each do |level|
75
+ if ['Cleric', 'Druid'].include? level.class_name
76
+ divine = true
77
+ elsif (['Paladin', 'Ranger'].include? level.class_name) && (level.class_number >= 4)
78
+ divine = true
79
+ end
80
+ end
81
+ return divine
82
+ end
83
+
84
+ def gets_familiar?
85
+ (class_features.find { |x| x.feature_type == 'Arcane Bond' && x.ability_name == 'Familiar' }) != nil
86
+ end
87
+
88
+ def gets_companion?
89
+ (class_features.find { |x| x.feature_type == 'Nature Bond' && x.ability_name == 'Animal Companion' }) != nil
90
+ end
91
+
92
+ def valid_spell?(spell, class_name, level, spellbooks)
93
+ return has_class?(class_name) &&
94
+ appropriate_level?(spell, class_name, level) &&
95
+ spell_fits?(class_name, level, spellbooks)
96
+ end
97
+
98
+ private
99
+
100
+ def attr_static(class_name)
101
+ heroclass = PfrpgClasses::Heroclass.by_name(class_name)
102
+ attr = heroclass.spells_bonus_attr
103
+ return self.attributes.send("modified_#{attr}")
104
+ end
105
+
106
+ def attr_mod(class_name)
107
+ heroclass = PfrpgClasses::Heroclass.by_name(class_name)
108
+ attr = heroclass.spells_bonus_attr
109
+ return self.attributes.send("#{attr}_mod")
110
+ end
111
+
112
+
113
+ def has_class?(class_name)
114
+ latest_levels.each do |l|
115
+ return true if l.class_name == class_name
116
+ end
117
+ raise InvalidClassException
118
+ end
119
+
120
+ def spell_fits?(class_name, level, spellbooks)
121
+ max_spells = spells_per_level(class_name, latest_levels)[level]
122
+ if spellbooks[class_name] == nil || spellbooks[class_name][level] == nil
123
+ return true
124
+ end
125
+ raise TooManySpellsException unless spellbooks[class_name][level].size < max_spells
126
+ return true
127
+ end
128
+
129
+ def appropriate_level?(spell, class_name, level)
130
+ begin
131
+ spell_level = spell.send(class_name.downcase)
132
+ raise InvalidSpellException if spell_level == 'NULL'
133
+ spell_level_for_class = spell.send(class_name.downcase).to_i
134
+ raise InvalidSpellException if spell_level_for_class > level
135
+ raise TooLowSpellException if (attr_static(class_name)-10) < spell_level_for_class
136
+ return true
137
+ catch Exception
138
+ raise InvalidSpellException
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,114 @@
1
+ module PfrpgCore
2
+ module Derived
3
+ module Misc
4
+
5
+ def level_string
6
+ str = "#{@alignment} :"
7
+ @levels.each do |l|
8
+ str += "#{l.name}/#{l.rank}"
9
+ str += "*" if l.favored
10
+ end
11
+ str
12
+ end
13
+
14
+ def initiative
15
+ initiative = 0
16
+ initiative += @attributes.dex_mod
17
+ initiative += get_bonus("initiative").to_i
18
+ return initiative
19
+ end
20
+
21
+ def speed
22
+ base_speed = NullObject.maybe(@race).speed || 0
23
+ base_speed += parse_speed_bonuses(get_bonus("speed"))
24
+ base_speed -= armor_speed_penalty
25
+ speeds = {}
26
+ ['land','fly','climb','swim'].each do |type|
27
+ speeds["#{type}_speed"] = calc_speed(type, base_speed)
28
+ end
29
+ speeds['speed'] = speeds['land_speed']
30
+ return speeds
31
+ end
32
+
33
+ def calc_speed(speed_type, base)
34
+ base + get_bonus("#{speed_type}_speed")
35
+ end
36
+
37
+ def parse_speed_bonuses(speed_bonuses)
38
+ speed_bonus = 0
39
+ speed_bonuses.each do |s|
40
+ speed_bonus += s.to_i if MathHelper.is_number(s)
41
+ end
42
+ speed_bonus
43
+ end
44
+
45
+ def hit_points
46
+ hp = @character.hit_points
47
+ # TODO : potentially move off this method when multiple hp affect stats exist
48
+ if (@feats.find { |x| x.name == 'Toughness' })
49
+ hp += 3
50
+ if (total_level > 3)
51
+ hp += total_level - 3
52
+ end
53
+ end
54
+ return hp
55
+ end
56
+
57
+ def size
58
+ return @race.size if @race
59
+ return nil
60
+ end
61
+
62
+ def total_level
63
+ @levels.inject(0) {|sum, x| sum = sum + x.rank }
64
+ end
65
+
66
+ def hit_die
67
+ total_level
68
+ end
69
+
70
+ def get_class_level(heroclass)
71
+ l = latest_levels.find { |x| x.class_name[heroclass.name] }
72
+ if l
73
+ return l.class_number
74
+ else
75
+ return 0
76
+ end
77
+ end
78
+
79
+ def explode_levels
80
+ # TODO: implement me
81
+ []
82
+ end
83
+
84
+ def hit_dice
85
+ hit_die
86
+ end
87
+
88
+ def get_caster_level
89
+ # TODO constantize somewhere better
90
+ caster_classes = ['Bard', 'Cleric', 'Druid', 'Paladin', 'Ranger', 'Sorcerer', 'Wizard']
91
+ caster_levels = latest_levels.select { |x| caster_classes.include? x.class_name }
92
+ max_caster_level = caster_levels.map { |x| x.class_number }.max || 0
93
+ ek_level = get_class_level(PfrpgClasses::Heroclass.by_name('Eldritch Knight'))
94
+ return (max_caster_level + ek_level) || 0
95
+ end
96
+
97
+ def misc_json
98
+ {
99
+ :initiative => initiative,
100
+ :alignment => @alignment,
101
+ :speed => speed,
102
+ :hit_points => hit_points,
103
+ :feats => @feats,
104
+ :class_features => @class_features,
105
+ :levels => @levels,
106
+ :total_level => @total_level,
107
+ :size => size,
108
+ :level_string => level_string,
109
+ :temporary => @character.temp_values
110
+ }
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,49 @@
1
+ module PfrpgCore
2
+ module Derived
3
+ module Offense
4
+ def combat_maneuver_bonus
5
+ base = str_bonus + bab - size_modifier
6
+ misc = character.get_bonus('cmb').to_i
7
+ base += misc
8
+ return base
9
+ end
10
+
11
+ def attack_filters
12
+ standard_filters = [
13
+ PfrpgCore::Filters::StrengthMod.new(character),
14
+ PfrpgCore::Filters::WeaponFinesseMod.new(character),
15
+ PfrpgCore::Filters::RangedAttackMod.new(character),
16
+ PfrpgCore::Filters::WeaponFocusMod.new(character),
17
+ PfrpgCore::Filters::WeaponSpecializationMod.new(character),
18
+ PfrpgCore::Filters::ProficiencyMod.new(character)
19
+ ]
20
+ standard_filters << character.get_attack_filters
21
+ standard_filters.flatten
22
+ end
23
+
24
+ def attacks
25
+ macros = Macro.find_available(character)
26
+
27
+ atk = character.inventory.equipped_weapons(character.levels).collect do |w|
28
+ Attack.new({ :weapon_name => w.get_best_name,
29
+ :range => w.range,
30
+ :weight_class => w.weight_class,
31
+ :damage => w.damage,
32
+ :weapon_type => w.weapon_type,
33
+ :critical_range => w.critical_range,
34
+ :critical_dmg => w.critical_dmg,
35
+ :bonus => w.bonus,
36
+ :strength_bonus => str_bonus,
37
+ :bab => bab,
38
+ :size => character.race.size,
39
+ :filters => attack_filters,
40
+ :filter_str => [],
41
+ :weapon => w,
42
+ :macros => macros.select { |m| m.applies_to? w }
43
+ })
44
+ end
45
+ return atk
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ module PfrpgCore
2
+ module Derived
3
+ end
4
+ end
5
+
6
+ require 'pfrpg_core/derived/defense'
7
+ require 'pfrpg_core/derived/offense'
8
+ require 'pfrpg_core/derived/combat_bonuses'
9
+ require 'pfrpg_core/derived/magic'
10
+ require 'pfrpg_core/derived/misc'
@@ -10,7 +10,7 @@ module PfrpgCore
10
10
  final = []
11
11
  no_stacking = effects_hash(@effects)
12
12
  no_stacking.keys.each do |key|
13
- if Tables::Bonus.stackable?(key) || Tables::Bonus.special?(key)
13
+ if PfrpgTables::Tables::Bonus.stackable?(key) || PfrpgTables::Tables::Bonus.special?(key)
14
14
  final << no_stacking[key]
15
15
  else
16
16
  final << find_max(no_stacking[key])
@@ -0,0 +1,29 @@
1
+ module PfrpgCore
2
+ class EffectTotaler
3
+ attr_reader :character
4
+ def initialize(character)
5
+ @character = character
6
+ end
7
+
8
+ def effects
9
+ effects = []
10
+ [
11
+ NullObject.maybe(@character.feats),
12
+ NullObject.maybe(@character.inventory.equipment),
13
+ NullObject.maybe(@character.race).traits,
14
+ NullObject.maybe(@character.class_features)
15
+ ].each do |r|
16
+ r.each do |x|
17
+ effects << x.get_effects
18
+ end
19
+ end
20
+ # TODO : calculate level based effects
21
+ NullObject.maybe(@character.explode_levels).each do |l|
22
+ l.class_features.each do |x|
23
+ effects << x.get_effects
24
+ end
25
+ end
26
+ return effects.flatten
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module PfrpgTables
2
+ class EquipmentTotaler
3
+ attr_reader :entity, :levels
4
+ def initialize(entity)
5
+ @entity = entity
6
+ @levels = PfrpgCore::LevelParser.new(entity.level)
7
+ end
8
+
9
+ def total
10
+ return 1000
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module PfrpgCore
2
+ class Feat
3
+ include PfrpgUtility::Affectable
4
+ attr_reader :name, :description, :effects, :prereqs,
5
+ :special, :type, :source
6
+
7
+ def initialize(params)
8
+ @name = params[:name]
9
+ @description = params[:description]
10
+ @effects = params[:effects] || []
11
+ @prereqs = params[:prereqs] || []
12
+ @special = params[:special]
13
+ @type = params[:type]
14
+ @source = params[:source]
15
+ end
16
+
17
+ def as_json(options={})
18
+ {
19
+ name: @name,
20
+ description: @description,
21
+ special: @special,
22
+ type: @type,
23
+ source: @source
24
+ }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ module PfrpgTables
2
+ class FeatTotaler
3
+ attr_reader :entity, :levels
4
+ def initialize(entity)
5
+ @entity = entity
6
+ @levels = PfrpgCore::LevelParser.new(entity.level)
7
+ end
8
+
9
+ def total
10
+ return level_granted + race_granted + feature_granted + choice_granted
11
+ end
12
+
13
+ def level_granted
14
+ i = (1..levels.total).inject(0) do |sum, x|
15
+ choices = PfrpgTables::Tables::LevelTable.for_level(x)[:choices]
16
+ sum = sum + (choices.select { |c| choice_is_feat(c) }).size
17
+ end
18
+ return i
19
+ end
20
+
21
+ def race_granted
22
+ i = entity.race.bonus_choices.inject(0) do |sum, x|
23
+ sum = sum + 1 if choice_is_feat(x)
24
+ end
25
+ return i
26
+ end
27
+
28
+ def feature_granted
29
+ i = entity.class_features.inject(0) do |sum, x|
30
+ if x.respond_to? 'granted_choice'
31
+ choices = [x.granted_choice].flatten
32
+ sum += (choices.select { |c| choice_is_feat(c) }).size
33
+ end
34
+ end
35
+ return i || 0
36
+ end
37
+
38
+ def choice_granted
39
+ choices = []
40
+ lvls = @levels.parse
41
+ lvls.keys.each do |hc|
42
+ clazz = PfrpgClasses::Heroclass.by_name(hc)
43
+ level = lvls[hc]
44
+ (1..level).each do |l|
45
+ clazz.bonuses_for_level(l)[:choices].each do |choice|
46
+ if (choice_is_feat(choice))
47
+ choice.npc_id = entity.id
48
+ choices << choice
49
+ end
50
+ end
51
+ end
52
+ end
53
+ @choose_features = choices.flatten.size
54
+ end
55
+
56
+ def choice_is_feat(choice)
57
+ choice.class.to_s['Feat'] != nil
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ class PfrpgCore::FeatureDuplicator
2
+
3
+ def self.dupe_words
4
+ ['Sneak Attack', 'Channel Energy', 'Damage Reduction', 'Trap Sense']
5
+ end
6
+
7
+ # filter things with multiple bonuses, like sneak attack and channel energy
8
+ def self.filter_duplicates(features)
9
+ dupe_words.each do |w|
10
+ features = features - smallest(features, w)
11
+ end
12
+ features
13
+ end
14
+
15
+ def self.smallest(features, phrase)
16
+ smallest = features.select { |x| x.name[phrase] != nil }
17
+ return [] if (smallest.empty? || smallest.size == 1)
18
+ smallest.sort_by! { |x| parse_number(x.name) }
19
+ smallest[0..smallest.size-2]
20
+ end
21
+
22
+ # of the form, 'Sneak Attack (10d6)'
23
+ def self.parse_number(description)
24
+ (description.split('d6')[0].split(' ').last.split('(')[1]).to_i
25
+ end
26
+ end
@@ -0,0 +1,86 @@
1
+ module PfrpgTables
2
+ class FeatureTotaler
3
+ attr_reader :entity, :levels
4
+ def initialize(entity)
5
+ @entity = entity
6
+ @levels = PfrpgCore::LevelParser.new(entity.level)
7
+ @base_features = []
8
+ @choose_features = []
9
+ parse_features
10
+ end
11
+
12
+ def get_base_features
13
+ @base_features
14
+ end
15
+
16
+ def get_choose_features
17
+ @choose_features
18
+ end
19
+
20
+ def parse_features
21
+ choices = []
22
+ lvls = levels.parse
23
+ lvls.keys.each do |hc|
24
+ clazz = PfrpgClasses::Heroclass.by_name(hc)
25
+ level = lvls[hc]
26
+ (1..level).each do |l|
27
+ class_features = clazz.bonuses_for_level(l)[:granted_features]
28
+ class_features.each do |x|
29
+ ap "Creating granted feature:"
30
+ ap "\t#{x} (#{hc})"
31
+ @base_features << ClassFeature.granted_feature(x, hc)
32
+ end
33
+ clazz.bonuses_for_level(l)[:choices].each do |choice|
34
+ if !(choice_is_feat(choice))
35
+ choice.npc_id = entity.id
36
+ choices << flatten_options(choice)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ @choose_features = choices.flatten
42
+ end
43
+
44
+ def flatten_options(feature_choice)
45
+ ap "feature chioce:"
46
+ ap feature_choice.choices[:options][0]
47
+ if feature_choice.choices[:options][0].respond_to? 'name'
48
+ new_options = feature_choice.choices[:options].map { |x| x.name }
49
+ ap "New options:"
50
+ ap new_options
51
+ feature_choice.choices[:options] = new_options
52
+ end
53
+ return feature_choice
54
+ end
55
+
56
+ def level_granted
57
+ i = (1..levels.total).inject(0) do |sum, x|
58
+ choices = PfrpgTables::Tables::LevelTable.for_level(x)[:choices]
59
+ sum = sum + (choices.select { |c| choice_is_feat(c) }).size
60
+ end
61
+ return i
62
+ end
63
+
64
+ def race_granted
65
+ race = entity.race
66
+ i = race.bonus_choices.inject(0) do |sum, x|
67
+ sum = sum + 1 if choice_is_feat(x)
68
+ end
69
+ return i
70
+ end
71
+
72
+ def feature_granted
73
+ i = entity.class_features.inject(0) do |sum, x|
74
+ choices = x.bonus_choices
75
+ sum += (choices.select { |c| choice_is_feat(c) }).size
76
+ end
77
+ return i
78
+ end
79
+
80
+ def choice_is_feat(choice)
81
+ choice.class.to_s['Feat'] != nil
82
+ end
83
+
84
+ end
85
+ end
86
+
@@ -4,7 +4,7 @@ module PfrpgCore::Filterable
4
4
  begin
5
5
  self.filter_str << "Filtering #{f.class}"
6
6
  f.filter(self)
7
- rescue Exception => e
7
+ rescue Exception
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,14 @@
1
+ module PfrpgCore
2
+ module Filters
3
+ end
4
+ end
5
+
6
+ require_relative './weapon_training_mod.rb'
7
+ require_relative './weapon_specialization_mod.rb'
8
+ require_relative './weapon_finesse_mod.rb'
9
+ require_relative './strength_mod.rb'
10
+ require_relative './proficiency_mod.rb'
11
+ require_relative './prowess_mod.rb'
12
+ require_relative './weapon_focus_mod.rb'
13
+ require_relative './weapon_mastery_mod.rb'
14
+ require_relative './ranged_attack_mod.rb'
@@ -0,0 +1,34 @@
1
+ module PfrpgCore
2
+ module Filters
3
+ class ProficiencyMod
4
+ attr_reader :character
5
+ def initialize(character)
6
+ @character = character
7
+ end
8
+
9
+ def filter(attack)
10
+ proficiency = PfrpgCore::Specializer.new(character)
11
+ unless proficiency.is_proficient_in_weapon? attack.weapon
12
+ modify_for_weapon(attack)
13
+ end
14
+ armor = character.inventory.armor_and_shield
15
+ armor.each do |a|
16
+ unless proficiency.is_proficient_in_armor? a
17
+ modify_for_armor(attack, a)
18
+ end
19
+ end
20
+ end
21
+
22
+ def modify_for_weapon(attack)
23
+ attack.filter_str << 'Not proficient with weapon, -4 atk'
24
+ attack.other_bonus -= 4
25
+ end
26
+
27
+ def modify_for_armor(attack, armor)
28
+ attack.filter_str << "Not proficient with armor: #{armor.name}"
29
+ # armor check penalties are negative
30
+ attack.other_bonus += NullObject.maybe(armor.armor_check_penalty)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ module PfrpgCore
2
+ class Filters::ProwessMod
3
+ attr_reader :character
4
+ def initialize(character)
5
+ @character = character
6
+ end
7
+
8
+ def filter(skill)
9
+ if (skill.name.downcase == 'intimidate')
10
+ feat = character.char_feats.select { |x| x.pathfinder_feat.name == 'Intimidating Prowess' }
11
+ modify_skill_for_prowess(skill) if feat
12
+ end
13
+ end
14
+
15
+ def modify_skill_for_prowess(skill)
16
+ skill.misc_bonus += character.attributes.str_mod
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,28 @@
1
+ module PfrpgCore
2
+ module Filters
3
+ class RangedAttackMod
4
+ attr_reader :character
5
+ def initialize(character)
6
+ @character = character
7
+ end
8
+
9
+ def filter(attack)
10
+ unless character.feats.find { |x| x.name == 'Weapon Finesse' }
11
+ modify_attack_for_ranged_attack(attack, character.attributes.dex_mod, character.attributes.str_mod)
12
+ end
13
+ end
14
+
15
+ def modify_attack_for_ranged_attack(attack, dex, str)
16
+ begin
17
+ ranged = attack.range.to_i
18
+ if !(ranged == nil || ranged == '' || ranged == 0)
19
+ attack.filter_str << "Range Bonus: -#{dex}, +#{str}"
20
+ attack.other_bonus += dex
21
+ attack.other_bonus -= str
22
+ end
23
+ rescue Exception => e
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end