natural_20 0.1.1 → 0.2.0
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.
- 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:
|