pfrpg_core 0.0.2 → 0.1.1

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