natural_20 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +13 -0
- data/README.md +1 -0
- data/bin/nat20 +2 -1
- data/bin/nat20.cmd +0 -0
- data/char_classes/wizard.yml +89 -0
- data/characters/high_elf_mage.yml +27 -0
- data/fixtures/battle_sim_objects.yml +2 -2
- data/fixtures/high_elf_mage.yml +28 -0
- data/fixtures/large_map.yml +63 -0
- data/game.yml +2 -2
- data/items/equipment.yml +30 -0
- data/items/objects.yml +33 -29
- data/items/spells.yml +58 -0
- data/items/weapons.yml +78 -18
- data/lib/CHANGELOG.md +0 -0
- data/lib/natural_20.rb +9 -0
- data/lib/natural_20/actions/action.rb +2 -2
- data/lib/natural_20/actions/attack_action.rb +76 -67
- data/lib/natural_20/actions/concerns/action_damage.rb +3 -1
- data/lib/natural_20/actions/dash_action.rb +7 -10
- data/lib/natural_20/actions/disengage_action.rb +11 -12
- data/lib/natural_20/actions/dodge_action.rb +7 -8
- data/lib/natural_20/actions/escape_grapple_action.rb +16 -18
- data/lib/natural_20/actions/first_aid_action.rb +14 -16
- data/lib/natural_20/actions/grapple_action.rb +24 -28
- data/lib/natural_20/actions/ground_interact_action.rb +1 -3
- data/lib/natural_20/actions/help_action.rb +13 -16
- data/lib/natural_20/actions/hide_action.rb +7 -9
- data/lib/natural_20/actions/interact_action.rb +12 -14
- data/lib/natural_20/actions/look_action.rb +14 -15
- data/lib/natural_20/actions/move_action.rb +9 -9
- data/lib/natural_20/actions/multiattack_action.rb +8 -9
- data/lib/natural_20/actions/prone_action.rb +4 -6
- data/lib/natural_20/actions/short_rest_action.rb +7 -8
- data/lib/natural_20/actions/shove_action.rb +20 -24
- data/lib/natural_20/actions/spell_action.rb +89 -0
- data/lib/natural_20/actions/stand_action.rb +5 -7
- data/lib/natural_20/actions/use_item_action.rb +7 -9
- data/lib/natural_20/ai_controller/standard.rb +1 -1
- data/lib/natural_20/battle.rb +8 -3
- data/lib/natural_20/cli/action_ui.rb +180 -0
- data/lib/natural_20/cli/builder/fighter_builder.rb +1 -1
- data/lib/natural_20/cli/builder/rogue_builder.rb +10 -10
- data/lib/natural_20/cli/builder/wizard_builder.rb +77 -0
- data/lib/natural_20/cli/character_builder.rb +9 -4
- data/lib/natural_20/cli/commandline_ui.rb +55 -162
- data/lib/natural_20/cli/inventory_ui.rb +4 -0
- data/lib/natural_20/cli/map_renderer.rb +7 -1
- data/lib/natural_20/concerns/attack_helper.rb +53 -0
- data/lib/natural_20/concerns/entity.rb +170 -11
- data/lib/natural_20/concerns/fighter_actions/second_wind_action.rb +7 -9
- data/lib/natural_20/concerns/fighter_class.rb +2 -2
- data/lib/natural_20/concerns/spell_attack_helper.rb +33 -0
- data/lib/natural_20/concerns/wizard_class.rb +86 -0
- data/lib/natural_20/die_roll.rb +2 -2
- data/lib/natural_20/event_manager.rb +50 -44
- data/lib/natural_20/item_library/base_item.rb +1 -1
- data/lib/natural_20/npc.rb +4 -0
- data/lib/natural_20/player_character.rb +75 -12
- data/lib/natural_20/session.rb +14 -1
- data/lib/natural_20/spell_library/firebolt.rb +72 -0
- data/lib/natural_20/spell_library/mage_armor.rb +67 -0
- data/lib/natural_20/spell_library/mage_hand.rb +2 -0
- data/lib/natural_20/spell_library/magic_missile.rb +67 -0
- data/lib/natural_20/spell_library/shield.rb +69 -0
- data/lib/natural_20/spell_library/spell.rb +31 -0
- data/lib/natural_20/utils/weapons.rb +8 -6
- data/lib/natural_20/version.rb +1 -1
- data/locales/en.yml +44 -8
- data/maps/game_map.yml +12 -2
- metadata +22 -3
data/items/spells.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
---
|
2
|
+
firebolt:
|
3
|
+
base_damage: 1d10
|
4
|
+
casting_time: 1:action
|
5
|
+
components:
|
6
|
+
- verbal
|
7
|
+
- sematic
|
8
|
+
damage_increase:
|
9
|
+
- 5
|
10
|
+
- 11
|
11
|
+
- 17
|
12
|
+
damage_type: fire
|
13
|
+
description: You hurl a mote of fire at a creature or object within range. A flammable object hit by this spell ignites if it isn't being worn or carried.
|
14
|
+
duration: instant
|
15
|
+
level: 0
|
16
|
+
name: Firebolt
|
17
|
+
range: 120
|
18
|
+
school: evocation
|
19
|
+
spell_class: Natural20::Firebolt
|
20
|
+
type: ranged_attack
|
21
|
+
mage_armor:
|
22
|
+
casting_time: 1:action
|
23
|
+
components:
|
24
|
+
- verbal
|
25
|
+
- sematic
|
26
|
+
- material
|
27
|
+
description: You touch a willing creature who isn't wearing armor, and a protective magical force surrounds it until the spell ends. The target's base AC becomes 13 + its Dexterity modifier. The spell ends if the target dons armor or if you dismiss the spell as an action.
|
28
|
+
duration: 8h
|
29
|
+
level: 1
|
30
|
+
materials:
|
31
|
+
- cured_leather
|
32
|
+
name: Mage Armor
|
33
|
+
school: abjuration
|
34
|
+
spell_class: Natural20::MageArmor
|
35
|
+
type: buff
|
36
|
+
magic_missile:
|
37
|
+
casting_time: 1:action
|
38
|
+
damage_type: force
|
39
|
+
level: 1
|
40
|
+
name: Magic Missile
|
41
|
+
range: 120
|
42
|
+
school: evocation
|
43
|
+
description: You create three glowing darts of magical force. Each dart hits a creature of your choice that you can see within range.
|
44
|
+
spell_class: Natural20::MagicMissile
|
45
|
+
type: force
|
46
|
+
higher_level: true
|
47
|
+
shield:
|
48
|
+
casting_time: 1:reaction
|
49
|
+
level: 1
|
50
|
+
name: Shield
|
51
|
+
range: 0
|
52
|
+
duration: 1R
|
53
|
+
school: abjuration
|
54
|
+
spell_class: Natural20::Shield
|
55
|
+
components:
|
56
|
+
- verbal
|
57
|
+
- sematic
|
58
|
+
type: warding
|
data/items/weapons.yml
CHANGED
@@ -39,6 +39,66 @@ dagger:
|
|
39
39
|
range_max: 120
|
40
40
|
type: melee_attack
|
41
41
|
weight: 10
|
42
|
+
quarterstaff:
|
43
|
+
cost: 2sp
|
44
|
+
damage: 1d6
|
45
|
+
damage_2: 1d8
|
46
|
+
damage_type: bludgeoning
|
47
|
+
meta:
|
48
|
+
noise_source: 5
|
49
|
+
noise_target: 5
|
50
|
+
modifiers: null
|
51
|
+
name: Quarterstaff
|
52
|
+
proficiency_type:
|
53
|
+
- simple
|
54
|
+
properties:
|
55
|
+
- versatile
|
56
|
+
range: 5
|
57
|
+
subtype: weapon
|
58
|
+
type: melee_attack
|
59
|
+
weight: 4
|
60
|
+
sling:
|
61
|
+
ammo: pellet
|
62
|
+
cost: 1sp
|
63
|
+
damage: 1d4
|
64
|
+
damage_type: bludgeoning
|
65
|
+
meta:
|
66
|
+
noise_source: 5
|
67
|
+
noise_target: 5
|
68
|
+
modifiers: null
|
69
|
+
name: Sling
|
70
|
+
proficiency_type:
|
71
|
+
- simple
|
72
|
+
properties:
|
73
|
+
- ammunition
|
74
|
+
- ranged
|
75
|
+
range: 30
|
76
|
+
range_max: 120
|
77
|
+
subtype: weapon
|
78
|
+
type: ranged_attack
|
79
|
+
weight: 0
|
80
|
+
dart:
|
81
|
+
ammo: dart
|
82
|
+
cost: 2
|
83
|
+
damage: 1d4
|
84
|
+
damage_type: piercing
|
85
|
+
meta:
|
86
|
+
noise_source: 5
|
87
|
+
noise_target: 5
|
88
|
+
modifiers: null
|
89
|
+
name: Dart
|
90
|
+
proficiency_type:
|
91
|
+
- simple
|
92
|
+
properties:
|
93
|
+
- thrown
|
94
|
+
- finesse
|
95
|
+
range: 5
|
96
|
+
subtype: weapon
|
97
|
+
thrown:
|
98
|
+
range: 20
|
99
|
+
range_max: 60
|
100
|
+
type: ranged_attack
|
101
|
+
weight: 0.25
|
42
102
|
greatclub:
|
43
103
|
cost: 2sp
|
44
104
|
damage: 1d8
|
@@ -162,24 +222,6 @@ light_hammer:
|
|
162
222
|
range_max: 60
|
163
223
|
type: melee_attack
|
164
224
|
weight: 2
|
165
|
-
warhammer:
|
166
|
-
cost: 2
|
167
|
-
damage: 1d8
|
168
|
-
damage_2: 1d10
|
169
|
-
damage_type: bludgeoning
|
170
|
-
meta:
|
171
|
-
noise_source: 5
|
172
|
-
noise_target: 5
|
173
|
-
modifiers: null
|
174
|
-
name: Warhammer
|
175
|
-
proficiency_type:
|
176
|
-
- martial
|
177
|
-
properties:
|
178
|
-
- versatile
|
179
|
-
range: 5
|
180
|
-
subtype: weapon
|
181
|
-
type: melee_attack
|
182
|
-
weight: 2
|
183
225
|
longbow:
|
184
226
|
ammo: arrows
|
185
227
|
cost: 50
|
@@ -351,4 +393,22 @@ vicious_rapier:
|
|
351
393
|
rarity: very_rare
|
352
394
|
subtype: weapon
|
353
395
|
type: melee_attack
|
396
|
+
weight: 2
|
397
|
+
warhammer:
|
398
|
+
cost: 2
|
399
|
+
damage: 1d8
|
400
|
+
damage_2: 1d10
|
401
|
+
damage_type: bludgeoning
|
402
|
+
meta:
|
403
|
+
noise_source: 5
|
404
|
+
noise_target: 5
|
405
|
+
modifiers: null
|
406
|
+
name: Warhammer
|
407
|
+
proficiency_type:
|
408
|
+
- martial
|
409
|
+
properties:
|
410
|
+
- versatile
|
411
|
+
range: 5
|
412
|
+
subtype: weapon
|
413
|
+
type: melee_attack
|
354
414
|
weight: 2
|
data/lib/CHANGELOG.md
ADDED
File without changes
|
data/lib/natural_20.rb
CHANGED
@@ -9,6 +9,7 @@ require 'natural_20/concerns/lootable'
|
|
9
9
|
require 'natural_20/concerns/evaluator/entity_state_evaluator'
|
10
10
|
require 'natural_20/concerns/entity'
|
11
11
|
require 'natural_20/item_library/object'
|
12
|
+
require 'natural_20/concerns/attack_helper'
|
12
13
|
require 'natural_20/concerns/movement_helper'
|
13
14
|
require 'natural_20/utils/cover'
|
14
15
|
require 'natural_20/utils/weapons'
|
@@ -16,6 +17,7 @@ require 'natural_20/concerns/navigation'
|
|
16
17
|
require 'natural_20/actions/action'
|
17
18
|
require 'natural_20/concerns/fighter_class'
|
18
19
|
require 'natural_20/concerns/rogue_class'
|
20
|
+
require 'natural_20/concerns/wizard_class'
|
19
21
|
require 'natural_20/actions/concerns/action_damage'
|
20
22
|
require 'natural_20/actions/look_action'
|
21
23
|
require 'natural_20/actions/attack_action'
|
@@ -37,6 +39,13 @@ require 'natural_20/actions/escape_grapple_action'
|
|
37
39
|
require 'natural_20/actions/ground_interact_action'
|
38
40
|
require 'natural_20/actions/first_aid_action'
|
39
41
|
require 'natural_20/actions/shove_action'
|
42
|
+
require 'natural_20/concerns/spell_attack_helper'
|
43
|
+
require 'natural_20/spell_library/spell'
|
44
|
+
require 'natural_20/spell_library/mage_armor'
|
45
|
+
require 'natural_20/spell_library/firebolt'
|
46
|
+
require 'natural_20/spell_library/magic_missile'
|
47
|
+
require 'natural_20/spell_library/shield'
|
48
|
+
require 'natural_20/actions/spell_action'
|
40
49
|
require 'natural_20/battle'
|
41
50
|
require 'natural_20/utils/ray_tracer'
|
42
51
|
require 'natural_20/battle_map'
|
@@ -27,14 +27,14 @@ module Natural20
|
|
27
27
|
def validate
|
28
28
|
end
|
29
29
|
|
30
|
-
def apply!(battle); end
|
30
|
+
def self.apply!(battle, item); end
|
31
31
|
|
32
32
|
def resolve(session, map, opts = {}); end
|
33
33
|
|
34
34
|
protected
|
35
35
|
|
36
36
|
def t(k, options = {})
|
37
|
-
I18n.t(k, options)
|
37
|
+
I18n.t(k, **options)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -2,7 +2,8 @@
|
|
2
2
|
class AttackAction < Natural20::Action
|
3
3
|
include Natural20::Cover
|
4
4
|
include Natural20::Weapons
|
5
|
-
include Natural20::
|
5
|
+
include Natural20::AttackHelper
|
6
|
+
extend Natural20::ActionDamage
|
6
7
|
|
7
8
|
attr_accessor :target, :using, :npc_action, :as_reaction, :thrown, :second_hand
|
8
9
|
attr_reader :advantage_mod
|
@@ -31,7 +32,7 @@ class AttackAction < Natural20::Action
|
|
31
32
|
|
32
33
|
i18n_token = thrown ? 'action.attack_action_throw' : 'action.attack_action'
|
33
34
|
|
34
|
-
t(i18n_token, name: @action_type.to_s.humanize, weapon_name: weapon[:name], mod: attack_mod,
|
35
|
+
t(i18n_token, name: @action_type.to_s.humanize, weapon_name: weapon[:name], mod: attack_mod >= 0 ? "+#{attack_mod}" : attack_mod,
|
35
36
|
dmg: damage_modifier(@source, weapon, second_hand: second_hand))
|
36
37
|
end
|
37
38
|
end
|
@@ -70,76 +71,82 @@ class AttackAction < Natural20::Action
|
|
70
71
|
end
|
71
72
|
|
72
73
|
# @param battle [Natural20::Battle]
|
73
|
-
def apply!(battle)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
item[:source].deduct_item(item[:ammo], 1) if item[:ammo]
|
95
|
-
|
96
|
-
# hanle thrown items
|
97
|
-
if item[:thrown]
|
98
|
-
if item[:source].item_count(item[:weapon]).positive?
|
99
|
-
item[:source].deduct_item(item[:weapon], 1)
|
100
|
-
else
|
101
|
-
item[:source].unequip(item[:weapon], transfer_inventory: false)
|
102
|
-
end
|
74
|
+
def self.apply!(battle, item)
|
75
|
+
if item[:flavor]
|
76
|
+
Natural20::EventManager.received_event({ event: :flavor, source: item[:source], target: item[:target],
|
77
|
+
text: item[:flavor] })
|
78
|
+
end
|
79
|
+
case (item[:type])
|
80
|
+
when :prone
|
81
|
+
item[:source].prone!
|
82
|
+
when :damage
|
83
|
+
damage_event(item, battle)
|
84
|
+
consume_resource(battle, item)
|
85
|
+
when :miss
|
86
|
+
consume_resource(battle, item)
|
87
|
+
Natural20::EventManager.received_event({ attack_roll: item[:attack_roll],
|
88
|
+
attack_name: item[:attack_name],
|
89
|
+
advantage_mod: item[:advantage_mod],
|
90
|
+
as_reaction: !!item[:as_reaction],
|
91
|
+
adv_info: item[:adv_info],
|
92
|
+
source: item[:source], target: item[:target], event: :miss })
|
93
|
+
end
|
94
|
+
end
|
103
95
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
96
|
+
# @param battle [Natural20::Battle]
|
97
|
+
# @param item [Hash]
|
98
|
+
def self.consume_resource(battle, item)
|
99
|
+
# handle ammo
|
100
|
+
item[:source].deduct_item(item[:ammo], 1) if item[:ammo]
|
101
|
+
|
102
|
+
# hanle thrown items
|
103
|
+
if item[:thrown]
|
104
|
+
if item[:source].item_count(item[:weapon]).positive?
|
105
|
+
item[:source].deduct_item(item[:weapon], 1)
|
106
|
+
else
|
107
|
+
item[:source].unequip(item[:weapon], transfer_inventory: false)
|
111
108
|
end
|
112
109
|
|
113
|
-
if
|
114
|
-
|
115
|
-
elsif item[:second_hand]
|
116
|
-
battle.consume(item[:source], :bonus_action)
|
110
|
+
if item[:type] == :damage
|
111
|
+
item[:target].add_item(item[:weapon])
|
117
112
|
else
|
118
|
-
battle.
|
113
|
+
ground_pos = item[:battle].map.entity_or_object_pos(item[:target])
|
114
|
+
ground_object = item[:battle].map.objects_at(*ground_pos).detect { |o| o.is_a?(ItemLibrary::Ground) }
|
115
|
+
ground_object&.add_item(item[:weapon])
|
119
116
|
end
|
117
|
+
end
|
120
118
|
|
121
|
-
|
119
|
+
if item[:as_reaction]
|
120
|
+
battle.consume(item[:source], :reaction)
|
121
|
+
elsif item[:second_hand]
|
122
|
+
battle.consume(item[:source], :bonus_action)
|
123
|
+
else
|
124
|
+
battle.consume(item[:source], :action)
|
125
|
+
end
|
122
126
|
|
123
|
-
|
124
|
-
weapon = session.load_weapon(item[:weapon]) if item[:weapon]
|
127
|
+
item[:source].break_stealth!(battle)
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
else
|
129
|
-
battle.entity_state_for(item[:source])[:two_weapon] = nil
|
130
|
-
end
|
129
|
+
# handle two-weapon fighting
|
130
|
+
weapon = battle.session.load_weapon(item[:weapon]) if item[:weapon]
|
131
131
|
|
132
|
-
|
132
|
+
if weapon && weapon[:properties]&.include?('light') && !battle.two_weapon_attack?(item[:source]) && !item[:second_hand]
|
133
|
+
battle.entity_state_for(item[:source])[:two_weapon] = item[:weapon]
|
134
|
+
elsif battle.entity_state_for(item[:source])
|
135
|
+
battle.entity_state_for(item[:source])[:two_weapon] = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
# handle multiattacks
|
139
|
+
if battle.entity_state_for(item[:source])
|
133
140
|
battle.entity_state_for(item[:source])[:multiattack]&.each do |_group, attacks|
|
134
141
|
if attacks.include?(item[:attack_name])
|
135
142
|
attacks.delete(item[:attack_name])
|
136
143
|
item[:source].clear_multiattack!(battle) if attacks.empty?
|
137
144
|
end
|
138
145
|
end
|
139
|
-
|
140
|
-
# dismiss help actions
|
141
|
-
battle.dismiss_help_for(item[:target])
|
142
146
|
end
|
147
|
+
|
148
|
+
# dismiss help actions
|
149
|
+
battle.dismiss_help_for(item[:target])
|
143
150
|
end
|
144
151
|
|
145
152
|
def with_advantage?
|
@@ -172,7 +179,13 @@ class AttackAction < Natural20::Action
|
|
172
179
|
|
173
180
|
npc_action = @source.npc_actions.detect { |a| a[:name].downcase == using.downcase } if @source.npc? && using
|
174
181
|
|
175
|
-
if
|
182
|
+
if @source.npc?
|
183
|
+
|
184
|
+
if npc_action.nil?
|
185
|
+
npc_action = @source.properties[actions].detect do |action|
|
186
|
+
action[:name].downcase == using.to_s.downcase
|
187
|
+
end
|
188
|
+
end
|
176
189
|
weapon = npc_action
|
177
190
|
attack_name = npc_action[:name]
|
178
191
|
attack_mod = npc_action[:attack]
|
@@ -199,6 +212,8 @@ class AttackAction < Natural20::Action
|
|
199
212
|
|
200
213
|
# handle the lucky feat
|
201
214
|
attack_roll = attack_roll.reroll(lucky: true) if @source.class_feature?('lucky') && attack_roll.nat_1?
|
215
|
+
target_ac, _cover_ac = effective_ac(battle, target)
|
216
|
+
after_attack_roll_hook(battle, target, source, attack_roll, target_ac)
|
202
217
|
|
203
218
|
if @source.class_feature?('sneak_attack') && (weapon[:properties]&.include?('finesse') || weapon[:type] == 'ranged_attack') && (with_advantage? || battle.enemy_in_melee_range?(
|
204
219
|
target, [@source]
|
@@ -233,8 +248,8 @@ class AttackAction < Natural20::Action
|
|
233
248
|
elsif attack_roll.nat_1?
|
234
249
|
false
|
235
250
|
else
|
236
|
-
cover_ac_adjustments =
|
237
|
-
attack_roll.result >=
|
251
|
+
target_ac, cover_ac_adjustments = effective_ac(battle, target)
|
252
|
+
attack_roll.result >= target_ac
|
238
253
|
end
|
239
254
|
|
240
255
|
if hit
|
@@ -309,14 +324,6 @@ class AttackAction < Natural20::Action
|
|
309
324
|
self
|
310
325
|
end
|
311
326
|
|
312
|
-
# Computes cover armor class adjustment
|
313
|
-
# @param map [Natural20::BattleMap]
|
314
|
-
# @param target [Natural20::Entity]
|
315
|
-
# @return [Integer]
|
316
|
-
def calculate_cover_ac(map, target)
|
317
|
-
cover_calculation(map, @source, target)
|
318
|
-
end
|
319
|
-
|
320
327
|
protected
|
321
328
|
|
322
329
|
# determine eligibility for the 'Protection' fighting style
|
@@ -371,4 +378,6 @@ class TwoWeaponAttackAction < AttackAction
|
|
371
378
|
def label
|
372
379
|
"Bonus Action -> #{super}"
|
373
380
|
end
|
381
|
+
|
382
|
+
def self.apply!(battle, item); end
|
374
383
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Natural20::ActionDamage
|
2
2
|
def damage_event(item, battle)
|
3
|
-
Natural20::EventManager.received_event({ source: item[:source],
|
3
|
+
Natural20::EventManager.received_event({ source: item[:source],
|
4
|
+
attack_roll: item[:attack_roll],
|
5
|
+
target: item[:target], event: :attacked,
|
4
6
|
attack_name: item[:attack_name],
|
5
7
|
damage_type: item[:damage_type],
|
6
8
|
advantage_mod: item[:advantage_mod],
|
@@ -9,7 +9,7 @@ class DashAction < Natural20::Action
|
|
9
9
|
})
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.can?(entity, battle)
|
12
|
+
def self.can?(entity, battle, _options = {})
|
13
13
|
battle && entity.total_actions(battle).positive?
|
14
14
|
end
|
15
15
|
|
@@ -22,14 +22,11 @@ class DashAction < Natural20::Action
|
|
22
22
|
self
|
23
23
|
end
|
24
24
|
|
25
|
-
def apply!(battle)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
battle.entity_state_for(item[:source])[:movement] += item[:source].speed
|
31
|
-
end
|
32
|
-
|
25
|
+
def self.apply!(battle, item)
|
26
|
+
case item[:type]
|
27
|
+
when :dash
|
28
|
+
Natural20::EventManager.received_event({ source: item[:source], event: :dash })
|
29
|
+
battle.entity_state_for(item[:source])[:movement] += item[:source].speed
|
33
30
|
if as_bonus_action
|
34
31
|
battle.entity_state_for(item[:source])[:bonus_action] -= 1
|
35
32
|
else
|
@@ -40,7 +37,7 @@ class DashAction < Natural20::Action
|
|
40
37
|
end
|
41
38
|
|
42
39
|
class DashBonusAction < DashAction
|
43
|
-
def self.can?(entity, battle)
|
40
|
+
def self.can?(entity, battle, options = {})
|
44
41
|
battle && entity.class_feature?('cunning_action') && entity.total_bonus_actions(battle) > 0
|
45
42
|
end
|
46
43
|
end
|