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/lib/natural_20/session.rb
CHANGED
@@ -15,6 +15,11 @@ module Natural20
|
|
15
15
|
@session
|
16
16
|
end
|
17
17
|
|
18
|
+
# @param session [Natural20::Session]
|
19
|
+
def self.set_session(session)
|
20
|
+
@session = session
|
21
|
+
end
|
22
|
+
|
18
23
|
def initialize(root_path = nil)
|
19
24
|
@root_path = root_path.presence || '.'
|
20
25
|
@session_state = {}
|
@@ -23,6 +28,7 @@ module Natural20
|
|
23
28
|
@objects = {}
|
24
29
|
@thing = {}
|
25
30
|
@char_classes = {}
|
31
|
+
@spells = {}
|
26
32
|
@settings = {
|
27
33
|
manual_dice_roll: false
|
28
34
|
}
|
@@ -124,6 +130,13 @@ module Natural20
|
|
124
130
|
end.to_h
|
125
131
|
end
|
126
132
|
|
133
|
+
def load_spell(spell)
|
134
|
+
@spells[spell.to_sym] ||= begin
|
135
|
+
spells = YAML.load_file(File.join(@root_path, 'items', "spells.yml")).deep_symbolize_keys!
|
136
|
+
spells[spell.to_sym].merge(id: spell)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
127
140
|
def load_class(klass)
|
128
141
|
@char_classes[klass.to_sym] ||= begin
|
129
142
|
YAML.load_file(File.join(@root_path, 'char_classes', "#{klass}.yml")).deep_symbolize_keys!
|
@@ -162,7 +175,7 @@ module Natural20
|
|
162
175
|
end
|
163
176
|
|
164
177
|
def t(token, options = {})
|
165
|
-
I18n.t(token, options)
|
178
|
+
I18n.t(token, **options)
|
166
179
|
end
|
167
180
|
end
|
168
181
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Natural20::Firebolt < Natural20::Spell
|
2
|
+
include Natural20::Cover
|
3
|
+
include Natural20::Weapons
|
4
|
+
include Natural20::SpellAttackHelper
|
5
|
+
|
6
|
+
def build_map(action)
|
7
|
+
OpenStruct.new({
|
8
|
+
param: [
|
9
|
+
{
|
10
|
+
type: :select_target,
|
11
|
+
num: 1,
|
12
|
+
range: @properties[:range],
|
13
|
+
target_types: %i[enemies]
|
14
|
+
}
|
15
|
+
],
|
16
|
+
next: lambda { |target|
|
17
|
+
action.target = target
|
18
|
+
OpenStruct.new({
|
19
|
+
param: nil,
|
20
|
+
next: lambda {
|
21
|
+
action
|
22
|
+
}
|
23
|
+
})
|
24
|
+
}
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param entity [Natural20::Entity]
|
29
|
+
# @param battle [Natrual20::Battle]
|
30
|
+
# @param spell_action [Natural20::SpellAction]
|
31
|
+
def resolve(entity, battle, spell_action)
|
32
|
+
target = spell_action.target
|
33
|
+
|
34
|
+
hit, attack_roll, advantage_mod, cover_ac_adjustments = evaluate_spell_attack(battle, entity, target, @properties)
|
35
|
+
|
36
|
+
if hit
|
37
|
+
level = 1
|
38
|
+
level += 1 if entity.level >= 5
|
39
|
+
level += 1 if entity.level >= 11
|
40
|
+
level += 1 if entity.level >= 17
|
41
|
+
|
42
|
+
damage_roll = Natural20::DieRoll.roll("#{level}d10", crit: attack_roll.nat_20?, battle: battle, entity: entity,
|
43
|
+
description: t('dice_roll.spells.firebolt'))
|
44
|
+
[{
|
45
|
+
source: entity,
|
46
|
+
target: target,
|
47
|
+
attack_name: t('spell.firebolt'),
|
48
|
+
damage_type: @properties[:damage_type],
|
49
|
+
attack_roll: attack_roll,
|
50
|
+
damage_roll: damage_roll,
|
51
|
+
advantage_mod: advantage_mod,
|
52
|
+
damage: damage_roll,
|
53
|
+
cover_ac: cover_ac_adjustments,
|
54
|
+
type: :spell_damage,
|
55
|
+
spell: @properties
|
56
|
+
}]
|
57
|
+
else
|
58
|
+
[{
|
59
|
+
type: :spell_miss,
|
60
|
+
source: entity,
|
61
|
+
target: target,
|
62
|
+
attack_name: t('spell.firebolt'),
|
63
|
+
damage_type: @properties[:damage_type],
|
64
|
+
attack_roll: attack_roll,
|
65
|
+
damage_roll: damage_roll,
|
66
|
+
advantage_mod: advantage_mod,
|
67
|
+
cover_ac: cover_ac_adjustments,
|
68
|
+
spell: @properties
|
69
|
+
}]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Natural20::MageArmor < Natural20::Spell
|
2
|
+
def build_map(action)
|
3
|
+
OpenStruct.new({
|
4
|
+
param: [
|
5
|
+
{
|
6
|
+
type: :select_target,
|
7
|
+
num: 1,
|
8
|
+
range: 5,
|
9
|
+
target_types: %i[allies self]
|
10
|
+
}
|
11
|
+
],
|
12
|
+
next: lambda { |target|
|
13
|
+
action.target = target
|
14
|
+
OpenStruct.new({
|
15
|
+
param: nil,
|
16
|
+
next: lambda {
|
17
|
+
action
|
18
|
+
}
|
19
|
+
})
|
20
|
+
}
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate!(action)
|
25
|
+
@errors.clear
|
26
|
+
@errors << :wearing_armor if action.target.wearing_armor?
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.apply!(battle, item)
|
30
|
+
case item[:type]
|
31
|
+
when :mage_armor
|
32
|
+
|
33
|
+
item[:source].add_casted_effect({ target: item[:target], effect: item[:effect], expiration: battle.session.game_time + 8.hours.to_i })
|
34
|
+
item[:target].register_effect(:ac_override, self, effect: item[:effect], source: item[:source],
|
35
|
+
duration: 8.hours.to_i)
|
36
|
+
item[:target].register_event_hook(:equip, self, effect: item[:effect], effect: item[:effect],
|
37
|
+
source: item[:source],
|
38
|
+
duration: 8.hours.to_i)
|
39
|
+
Natural20::EventManager.received_event(event: :spell_buf, spell: item[:effect], source: item[:source],
|
40
|
+
target: item[:target])
|
41
|
+
SpellAction.consume_resource(battle, item)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param entity [Natural20::Entity]
|
46
|
+
# @param effect [Object]
|
47
|
+
def self.ac_override(entity, _effect)
|
48
|
+
13 + entity.dex_mod
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.equip(entity, opts = {})
|
52
|
+
entity.dismiss_effect!(opts[:effect]) if entity.wearing_armor?
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param entity [Natural20::Entity]
|
56
|
+
# @param battle [Natrual20::Battle]
|
57
|
+
# @param spell_action [Natural20::SpellAction]
|
58
|
+
def resolve(_entity, _battle, spell_action)
|
59
|
+
[{
|
60
|
+
type: :mage_armor,
|
61
|
+
target: spell_action.target,
|
62
|
+
source: spell_action.source,
|
63
|
+
effect: self,
|
64
|
+
spell: @properties
|
65
|
+
}]
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Natural20::MagicMissile < Natural20::Spell
|
2
|
+
include Natural20::Cover
|
3
|
+
include Natural20::Weapons
|
4
|
+
include Natural20::AttackHelper
|
5
|
+
|
6
|
+
def build_map(action)
|
7
|
+
cast_level = action.at_level || 1
|
8
|
+
darts = 3 + (cast_level - 1)
|
9
|
+
|
10
|
+
OpenStruct.new({
|
11
|
+
param: [
|
12
|
+
{
|
13
|
+
type: :select_target,
|
14
|
+
num: darts,
|
15
|
+
range: @properties[:range],
|
16
|
+
target_types: %i[enemies]
|
17
|
+
}
|
18
|
+
],
|
19
|
+
next: lambda { |target|
|
20
|
+
action.target = target
|
21
|
+
OpenStruct.new({
|
22
|
+
param: nil,
|
23
|
+
next: lambda {
|
24
|
+
action
|
25
|
+
}
|
26
|
+
})
|
27
|
+
}
|
28
|
+
})
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param entity [Natural20::Entity]
|
32
|
+
# @param battle [Natrual20::Battle]
|
33
|
+
# @param spell_action [Natural20::SpellAction]
|
34
|
+
def resolve(entity, battle, spell_action)
|
35
|
+
targets = spell_action.target
|
36
|
+
|
37
|
+
targets.map do |target|
|
38
|
+
after_attack_roll_hook(battle, target,
|
39
|
+
entity, nil, nil, spell: @properties)
|
40
|
+
|
41
|
+
if target.has_spell_effect?(:shield)
|
42
|
+
{
|
43
|
+
source: entity,
|
44
|
+
target: target,
|
45
|
+
attack_name: t('spell.magic_missile'),
|
46
|
+
damage_type: @properties[:damage_type],
|
47
|
+
type: :spell_miss,
|
48
|
+
spell: @properties
|
49
|
+
}
|
50
|
+
else
|
51
|
+
damage_roll = Natural20::DieRoll.roll('1d4+1', battle: battle, entity: entity,
|
52
|
+
description: t('dice_roll.spells.magic_missile'))
|
53
|
+
|
54
|
+
{
|
55
|
+
source: entity,
|
56
|
+
target: target,
|
57
|
+
attack_name: t('spell.magic_missile'),
|
58
|
+
damage_type: @properties[:damage_type],
|
59
|
+
damage_roll: damage_roll,
|
60
|
+
damage: damage_roll,
|
61
|
+
type: :spell_damage,
|
62
|
+
spell: @properties
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Natural20::Shield < Natural20::Spell
|
2
|
+
def build_map(action)
|
3
|
+
OpenStruct.new({
|
4
|
+
param: nil,
|
5
|
+
next: lambda {
|
6
|
+
action
|
7
|
+
}
|
8
|
+
})
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.apply!(battle, item)
|
12
|
+
case item[:type]
|
13
|
+
when :shield
|
14
|
+
|
15
|
+
item[:source].add_casted_effect(effect: item[:effect])
|
16
|
+
item[:target].register_effect(:ac_bonus, self, effect: item[:effect], source: item[:source],
|
17
|
+
duration: 8.hours.to_i)
|
18
|
+
|
19
|
+
item[:target].register_event_hook(:start_of_turn, self, effect: item[:effect], effect: item[:effect],
|
20
|
+
source: item[:source])
|
21
|
+
Natural20::EventManager.received_event(event: :spell_buf, spell: item[:effect], source: item[:source],
|
22
|
+
target: item[:source])
|
23
|
+
SpellAction.consume_resource(battle, item)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param entity [Natural20::Entity]
|
28
|
+
# @param effect [Object]
|
29
|
+
def self.ac_bonus(_entity, _effect)
|
30
|
+
5
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.start_of_turn(entity, opts = {})
|
34
|
+
entity.dismiss_effect!(opts[:effect])
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param battle [Natural20::Battle]
|
38
|
+
# @param entity [Natural20::Entity]
|
39
|
+
# @param attacker [Natural20::Entity]
|
40
|
+
# @param attack_roll [Natural20::DieRoll]
|
41
|
+
# @return [Array<Array<Hash>,Symbol>]
|
42
|
+
def self.after_attack_roll(battle, entity, _attacker, attack_roll, effective_ac, opts = {})
|
43
|
+
spell = battle.session.load_spell('shield')
|
44
|
+
if attack_roll.nil? || attack_roll.result.between?(entity.armor_class, effective_ac + 4)
|
45
|
+
[[{
|
46
|
+
type: :shield,
|
47
|
+
target: entity,
|
48
|
+
source: entity,
|
49
|
+
effect: Natural20::Shield.new(entity, 'shield', spell),
|
50
|
+
spell: spell
|
51
|
+
}], false]
|
52
|
+
else
|
53
|
+
[[], false]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param entity [Natural20::Entity]
|
58
|
+
# @param battle [Natrual20::Battle]
|
59
|
+
# @param spell_action [Natural20::SpellAction]
|
60
|
+
def resolve(_entity, _battle, spell_action)
|
61
|
+
[{
|
62
|
+
type: :shield,
|
63
|
+
target: spell_action.source,
|
64
|
+
source: spell_action.source,
|
65
|
+
effect: self,
|
66
|
+
spell: @properties
|
67
|
+
}]
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Natural20::Spell
|
2
|
+
attr_accessor :errors
|
3
|
+
attr_reader :properties, :source
|
4
|
+
|
5
|
+
def initialize(source, spell_name, details)
|
6
|
+
@name = spell_name
|
7
|
+
@properties = details
|
8
|
+
@source = source
|
9
|
+
@errors = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def label
|
13
|
+
t(:"spell.#{@name}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def id
|
17
|
+
@properties[:id]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.apply!(battle, item); end
|
21
|
+
|
22
|
+
def validate!(_action)
|
23
|
+
@errors.clear
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def t(token, options = {})
|
29
|
+
I18n.t(token, **options)
|
30
|
+
end
|
31
|
+
end
|
@@ -30,10 +30,10 @@ module Natural20::Weapons
|
|
30
30
|
disadvantage << :armor_proficiency unless source.proficient_with_equipped_armor?
|
31
31
|
advantage << :squeezed if target.squeezed?
|
32
32
|
advantage << :being_helped if battle.help_with?(target)
|
33
|
-
disadvantage << :target_long_range if battle.map && battle.map.distance(source, target,
|
34
|
-
|
33
|
+
disadvantage << :target_long_range if battle.map && weapon && battle.map.distance(source, target,
|
34
|
+
entity_1_pos: source_pos) > weapon[:range]
|
35
35
|
|
36
|
-
if weapon[:type] == 'ranged_attack' && battle.map
|
36
|
+
if weapon && weapon[:type] == 'ranged_attack' && battle.map
|
37
37
|
disadvantage << :ranged_with_enemy_in_melee if battle.enemy_in_melee_range?(source, source_pos: source_pos)
|
38
38
|
disadvantage << :target_is_prone_range if target.prone?
|
39
39
|
end
|
@@ -43,8 +43,10 @@ module Natural20::Weapons
|
|
43
43
|
advantage << :pack_tactics
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
|
46
|
+
if weapon && weapon[:properties]&.include?('heavy') && source.size == :small
|
47
|
+
disadvantage << :small_creature_using_heavy
|
48
|
+
end
|
49
|
+
advantage << :target_is_prone if weapon && weapon[:type] == 'melee_attack' && target.prone?
|
48
50
|
|
49
51
|
advantage << :unseen_attacker if battle.map && !battle.can_see?(target, source, entity_2_pos: source_pos)
|
50
52
|
disadvantage << :invisible_attacker if battle.map && !battle.can_see?(source, target, entity_1_pos: source_pos)
|
@@ -73,6 +75,6 @@ module Natural20::Weapons
|
|
73
75
|
damage_mod += 2
|
74
76
|
end
|
75
77
|
|
76
|
-
"#{damage_roll}+#{damage_mod}"
|
78
|
+
"#{damage_roll}#{damage_mod >= 0 ? "+#{damage_mod}" : damage_mod}"
|
77
79
|
end
|
78
80
|
end
|
data/lib/natural_20/version.rb
CHANGED
data/locales/en.yml
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
---
|
2
2
|
en:
|
3
3
|
action:
|
4
|
-
|
5
|
-
|
4
|
+
arcane_recovery: Arcane Recovery for %{name}
|
5
|
+
attack_action: '%{name} with %{weapon_name} -> Hit: %{mod} Dmg: %{dmg}'
|
6
|
+
attack_action_throw: '%{name} with %{weapon_name} (Throw) -> Hit: %{mod} Dmg: %{dmg}'
|
6
7
|
dash: Dash
|
7
8
|
dash_bonus: Bonus Action -> Dash
|
8
9
|
disengage: Disengage
|
@@ -26,10 +27,14 @@ en:
|
|
26
27
|
push: Shove (Push Away)
|
27
28
|
short_rest: Short Rest
|
28
29
|
shove: Shove (Knock Prone)
|
30
|
+
spell: Spellcasting
|
31
|
+
spell_choice: '%{spell} (%{level})'
|
29
32
|
stand: Stand Up
|
30
33
|
use_item: Use Item
|
34
|
+
waive_arcane_recovery: Skip Arcane Recovery
|
31
35
|
attack_status:
|
32
36
|
being_helped: Being being_helped
|
37
|
+
invisible_attacker: Target is hidden/invisible
|
33
38
|
prone: Target Prone
|
34
39
|
ranged_with_enemy_in_melee: Ranged weapon with enemy in melee range
|
35
40
|
small_creature_using_heavy: Heavy weapon used by small creature
|
@@ -42,8 +47,6 @@ en:
|
|
42
47
|
back: Back
|
43
48
|
battle_end: Battle ended in %{num} rounds
|
44
49
|
battle_simulator: Battle Simulator
|
45
|
-
map_description: 'Battle Map (%{width}x%{length}) %{feet_per_grid}ft per square, pov %{pov}:'
|
46
|
-
character_action_prompt: '%{name} (%{token}) will'
|
47
50
|
builder:
|
48
51
|
ability_score:
|
49
52
|
fixed: Fixed ability score 15, 14, 13, 12, 10, 8
|
@@ -84,21 +87,22 @@ en:
|
|
84
87
|
select_starting_weapon: Select a starting weapon
|
85
88
|
select_starting_weapon_2: Select second weapon set
|
86
89
|
select_languages: Select languages
|
87
|
-
select_race: Please select a race
|
88
|
-
select_skill: null
|
89
|
-
select_subrace: Please select a sub-race
|
90
|
+
select_race: Please select a racetargets.first -race
|
90
91
|
skill:
|
91
92
|
acrobatics: Acrobatics
|
92
93
|
animal_handling: Animal Handling
|
94
|
+
arcana: Arcana
|
93
95
|
athletics: Athletics
|
94
96
|
deception: Deception
|
95
97
|
history: History
|
96
98
|
insight: Insight
|
97
99
|
intimidation: Intimidation
|
98
100
|
investigation: Investigation
|
101
|
+
medicine: Medicine
|
99
102
|
perception: Perception
|
100
103
|
performance: Performance
|
101
104
|
persuasion: Persuasion
|
105
|
+
religion: Religion
|
102
106
|
sleight_of_hand: Sleight of Hand
|
103
107
|
stealth: Stealth
|
104
108
|
survival: Survival
|
@@ -111,6 +115,14 @@ en:
|
|
111
115
|
masons_tools: Mason's Tools
|
112
116
|
smiths_tools: Smith's Tools
|
113
117
|
wis: Select Wisdom ability score
|
118
|
+
wizard:
|
119
|
+
select_cantrip: Select Cantrip
|
120
|
+
select_prepared_spells: Select prepared spells
|
121
|
+
select_skill: Select a wizard skill
|
122
|
+
select_spells: Select starting spells in your spellbook
|
123
|
+
select_starting_weapon: Select starting weapon
|
124
|
+
select_starting_weapon_2: Select starting equipment
|
125
|
+
character_action_prompt: '%{name} (%{token}) will'
|
114
126
|
character_builder: Character Builder ...
|
115
127
|
character_sheet:
|
116
128
|
ac: 'AC: %{ac}'
|
@@ -121,12 +133,14 @@ en:
|
|
121
133
|
languages: 'Languages:'
|
122
134
|
level: 'Level: %{level}'
|
123
135
|
name: 'Name: %{name}'
|
136
|
+
proficiency_bonus: 'Proficiency Bonus: +%{bonus}'
|
124
137
|
race: 'Race: %{race}'
|
125
138
|
skill_mod: '%{prefix} %{skill} %{bonus}'
|
126
139
|
skills: Skills
|
127
140
|
speed: 'Speed: %{speed}ft.'
|
141
|
+
spell_attack: 'Spell Attack: +%{spell_attack}'
|
128
142
|
subrace: 'Subrace: %{race}'
|
129
|
-
character_status_line: 'HP: %{hp}/%{max_hp} actions: %{total_actions} bonus action: %{bonus_action}, movement: %{available_movement} ft. statuses: %{statuses}'
|
143
|
+
character_status_line: 'AC: %{ac} HP: %{hp}/%{max_hp} actions: %{total_actions} bonus action: %{bonus_action}, movement: %{available_movement} ft. statuses: %{statuses}'
|
130
144
|
dead_goblin_items: Dead Goblin's items
|
131
145
|
dice_roll:
|
132
146
|
ability_score: 'Rolling for ability score #%{roll_num}'
|
@@ -151,12 +165,15 @@ en:
|
|
151
165
|
second_wind: Roll for second wind hp gain
|
152
166
|
sneak_attack: Roll for sneak attack damage
|
153
167
|
special_weapon_damage: Roll for special weapon additional damage
|
168
|
+
spells:
|
169
|
+
firebolt: Roll for Firebot spell damage
|
154
170
|
stealth: Rolling for stealth check
|
155
171
|
strength_check: Roll for strength (skill check)
|
156
172
|
thieves_tools: Roll for thieves tools (skill check)
|
157
173
|
wisdom_check: Roll for wisdom check
|
158
174
|
dice_roller: Dice Roller
|
159
175
|
drop: Drop Item
|
176
|
+
effect_line: '%{effect_name} (%{source})'
|
160
177
|
end_turn: '%{name}: End turn.'
|
161
178
|
engine_title: Welcome to Wizards and Goblins (DnD 5e Adventure Engine)
|
162
179
|
entity:
|
@@ -203,6 +220,7 @@ en:
|
|
203
220
|
shove_failure: '%{source_roll} < %{target_roll}. ${source} tried but failed to shove %{target} 5ft away'
|
204
221
|
shove_success: '%{source_roll} >= %{target_roll}. ${source} shoves %{target} 5ft away'
|
205
222
|
something: (something)
|
223
|
+
spell_buff: '%{source} casts %{spell} on %{target}.'
|
206
224
|
status:
|
207
225
|
prone: '%{name} is now prone.'
|
208
226
|
stand: '%{name} stands up.'
|
@@ -232,18 +250,22 @@ en:
|
|
232
250
|
thieves_cant: Thieves Cant
|
233
251
|
undercommon: Undercommon
|
234
252
|
manual_target: Target object using the map
|
253
|
+
map_description: 'Battle Map (%{width}x%{length}) %{feet_per_grid}ft per square, pov %{pov}:'
|
235
254
|
missing_game: missing game.yml in the current folder
|
236
255
|
multiple_target_prompt: Multiple targets at location(s) please select specific targets
|
256
|
+
multiple_targets: 'Total Targets: %{total_targets}'
|
237
257
|
'no': 'No'
|
238
258
|
object:
|
239
259
|
Arrows: Arrows
|
240
260
|
ItemLibrary::Chest:
|
241
261
|
loot: Retreive Contents
|
242
262
|
Wooden door key: Wooden Door Key
|
263
|
+
arcane_focus: Arcane Focus
|
243
264
|
chain_mail: Chain Mail
|
244
265
|
chest:
|
245
266
|
lock: clink. chest is now locked
|
246
267
|
unlock: Ka-chink! chest is now unlocked
|
268
|
+
component_pouch: Component Pouch
|
247
269
|
door:
|
248
270
|
door_blocked: (door is blocked)
|
249
271
|
key_required: (missing key)
|
@@ -278,6 +300,7 @@ en:
|
|
278
300
|
longbow: Longbow
|
279
301
|
longbow_and_arrows: Longbow and Arrows
|
280
302
|
longsword: Longsword
|
303
|
+
quarterstaff: Quarterstaff
|
281
304
|
rapier: Rapier
|
282
305
|
scimitar: Scimitar
|
283
306
|
shortbow: Shortbow
|
@@ -303,6 +326,19 @@ en:
|
|
303
326
|
select_npcs: Select NPCs
|
304
327
|
select_party_member: Select Party Member %{index}
|
305
328
|
skip_hit_die: Skip Hit Die
|
329
|
+
spell:
|
330
|
+
firebolt: Firebolt
|
331
|
+
mage_armor: Mage Armor
|
332
|
+
magic_missile: Magic Missile
|
333
|
+
shield: Shield
|
334
|
+
spell_level: Recover Spell Level %{level}
|
335
|
+
spell_level_slots: 'level %{level}: %{slots}'
|
336
|
+
spell_slots: Spell Slots
|
337
|
+
spells:
|
338
|
+
disabled:
|
339
|
+
no_action: '- No more actions'
|
340
|
+
no_bonus_action: '- No more bonus actions'
|
341
|
+
no_spell_slot: '- No more spell slots'
|
306
342
|
tpk: The entire party has fallen. Game Over!
|
307
343
|
unequip: Unequip
|
308
344
|
validation:
|