tormenta20 0.2.22 → 1.0.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/README.md +3 -3
- data/db/schema.sql +437 -6
- data/db/tormenta20.sqlite3 +0 -0
- data/src/ruby/tormenta20/concerns/livro_scoped.rb +26 -0
- data/src/ruby/tormenta20/models/acessorio_magico.rb +7 -10
- data/src/ruby/tormenta20/models/ameaca.rb +73 -0
- data/src/ruby/tormenta20/models/arma_magica_especifica.rb +32 -0
- data/src/ruby/tormenta20/models/armadura_magica_especifica.rb +35 -0
- data/src/ruby/tormenta20/models/artefato.rb +23 -0
- data/src/ruby/tormenta20/models/base.rb +15 -2
- data/src/ruby/tormenta20/models/base_tipo.rb +33 -0
- data/src/ruby/tormenta20/models/classe_variante.rb +41 -0
- data/src/ruby/tormenta20/models/comodo.rb +32 -0
- data/src/ruby/tormenta20/models/complicacao.rb +40 -0
- data/src/ruby/tormenta20/models/construcao_dominio.rb +39 -0
- data/src/ruby/tormenta20/models/distincao.rb +39 -0
- data/src/ruby/tormenta20/models/divindade.rb +14 -1
- data/src/ruby/tormenta20/models/encantamento.rb +6 -3
- data/src/ruby/tormenta20/models/esoterico_magico.rb +51 -0
- data/src/ruby/tormenta20/models/item_liturgico.rb +41 -0
- data/src/ruby/tormenta20/models/mobilia.rb +33 -0
- data/src/ruby/tormenta20/models/poder.rb +15 -0
- data/src/ruby/tormenta20/models/raca.rb +14 -1
- data/src/ruby/tormenta20/models/tabela.rb +33 -3
- data/src/ruby/tormenta20/rules/damage_step.rb +37 -0
- data/src/ruby/tormenta20/rules/spell_cost.rb +18 -0
- data/src/ruby/tormenta20/rules.rb +2 -0
- data/src/ruby/tormenta20/seeder.rb +229 -19
- data/src/ruby/tormenta20.rb +103 -1
- metadata +20 -4
|
@@ -48,6 +48,9 @@ module Tormenta20
|
|
|
48
48
|
poder_combate
|
|
49
49
|
poder_destino
|
|
50
50
|
poder_magia
|
|
51
|
+
poder_de_raca
|
|
52
|
+
poder_de_grupo
|
|
53
|
+
poder_distincao
|
|
51
54
|
].freeze
|
|
52
55
|
|
|
53
56
|
validates :id, presence: true, uniqueness: true
|
|
@@ -99,6 +102,17 @@ module Tormenta20
|
|
|
99
102
|
# @return [ActiveRecord::Relation<Poder>]
|
|
100
103
|
scope :by_deity, ->(deity_id) { where("json_extract(deities, '$') LIKE ?", "%#{deity_id}%") }
|
|
101
104
|
|
|
105
|
+
# @!method poderes_distincao
|
|
106
|
+
# Filter distinction powers.
|
|
107
|
+
# @return [ActiveRecord::Relation<Poder>]
|
|
108
|
+
scope :poderes_distincao, -> { where(type: "poder_distincao") }
|
|
109
|
+
|
|
110
|
+
# @!method by_distincao(distincao_id)
|
|
111
|
+
# Filter powers belonging to a specific distinction.
|
|
112
|
+
# @param distincao_id [String] Distinction ID
|
|
113
|
+
# @return [ActiveRecord::Relation<Poder>]
|
|
114
|
+
scope :by_distincao, ->(distincao_id) { where(distincao_id: distincao_id) }
|
|
115
|
+
|
|
102
116
|
# @!endgroup
|
|
103
117
|
|
|
104
118
|
# Convert power to a hash representation.
|
|
@@ -113,6 +127,7 @@ module Tormenta20
|
|
|
113
127
|
effects: effects,
|
|
114
128
|
prerequisites: prerequisites,
|
|
115
129
|
origin_id: origin_id,
|
|
130
|
+
distincao_id: distincao_id,
|
|
116
131
|
deities: deities
|
|
117
132
|
}.compact
|
|
118
133
|
end
|
|
@@ -28,6 +28,8 @@ module Tormenta20
|
|
|
28
28
|
# @return [Integer, nil] Range of special vision in metres, or +nil+ for normal vision
|
|
29
29
|
# @!attribute [rw] attribute_bonuses
|
|
30
30
|
# @return [Hash{String => Integer}] Map of attribute key to bonus value
|
|
31
|
+
# @!attribute [rw] chosen_attribute_bonus
|
|
32
|
+
# @return [Hash, nil] +{ count:, value:, exclude: }+ — "choose N attributes" pattern (Heróis de Arton); +nil+ for fixed-bonus races
|
|
31
33
|
# @!attribute [rw] skill_bonuses
|
|
32
34
|
# @return [Array] Skill bonus descriptors
|
|
33
35
|
# @!attribute [rw] racial_abilities
|
|
@@ -36,6 +38,13 @@ module Tormenta20
|
|
|
36
38
|
# @return [Integer] Number of abilities the player selects at character creation
|
|
37
39
|
# @!attribute [rw] available_chosen_abilities
|
|
38
40
|
# @return [Array] Pool of ability IDs to choose from
|
|
41
|
+
# @!attribute [rw] longevidade
|
|
42
|
+
# @return [String, nil] Lifespan multiplier (e.g. +"x2"+, +"x5"+, +"Normal"+); introduced in Heróis de Arton, absent for EJA races
|
|
43
|
+
# @!attribute [rw] devocao
|
|
44
|
+
# @return [Array<String>, nil] Deity IDs commonly devoted to by this race, or +nil+
|
|
45
|
+
# @!attribute [rw] ability_swap
|
|
46
|
+
# @return [Hash, nil] +{ "replaces" => id, "options" => [ids] }+ — a fixed racial ability
|
|
47
|
+
# that may be swapped for one of several variants (e.g. suraggel/Deuses de Arton); +nil+ when none exist
|
|
39
48
|
class Raca < Base
|
|
40
49
|
self.table_name = "racas"
|
|
41
50
|
|
|
@@ -84,10 +93,14 @@ module Tormenta20
|
|
|
84
93
|
vision: vision,
|
|
85
94
|
vision_range: vision_range,
|
|
86
95
|
attribute_bonuses: attribute_bonuses || {},
|
|
96
|
+
chosen_attribute_bonus: chosen_attribute_bonus,
|
|
87
97
|
skill_bonuses: skill_bonuses || [],
|
|
88
98
|
racial_abilities: racial_abilities || [],
|
|
89
99
|
chosen_abilities_amount: chosen_abilities_amount || 0,
|
|
90
|
-
available_chosen_abilities: available_chosen_abilities || []
|
|
100
|
+
available_chosen_abilities: available_chosen_abilities || [],
|
|
101
|
+
longevidade: longevidade,
|
|
102
|
+
devocao: devocao,
|
|
103
|
+
ability_swap: ability_swap
|
|
91
104
|
}.compact
|
|
92
105
|
end
|
|
93
106
|
end
|
|
@@ -13,7 +13,7 @@ module Tormenta20
|
|
|
13
13
|
# @example
|
|
14
14
|
# t = Tabela.find_by(id: "tesouros_por_nd")
|
|
15
15
|
# t.headers # => ["ND", "Tibares", ...]
|
|
16
|
-
# t.rows # => [
|
|
16
|
+
# t.rows # => [{ "ND" => "1", "Tibares" => "50", ... }, ...]
|
|
17
17
|
#
|
|
18
18
|
# @!attribute [rw] id
|
|
19
19
|
# @return [String] Unique identifier
|
|
@@ -24,7 +24,9 @@ module Tormenta20
|
|
|
24
24
|
# @!attribute [rw] headers
|
|
25
25
|
# @return [Array<String>] Column header labels
|
|
26
26
|
# @!attribute [rw] rows
|
|
27
|
-
# @return [Array<
|
|
27
|
+
# @return [Array<Hash>] Table rows, each a Hash keyed by header
|
|
28
|
+
# @!attribute [rw] dice
|
|
29
|
+
# @return [String, nil] Dice expression (e.g. +"1d100"+) if this table is rollable via {#roll}
|
|
28
30
|
class Tabela < Base
|
|
29
31
|
self.table_name = "tabelas"
|
|
30
32
|
|
|
@@ -37,9 +39,37 @@ module Tormenta20
|
|
|
37
39
|
name: name,
|
|
38
40
|
description: description,
|
|
39
41
|
headers: headers || [],
|
|
40
|
-
rows: rows || []
|
|
42
|
+
rows: rows || [],
|
|
43
|
+
dice: dice
|
|
41
44
|
}.compact
|
|
42
45
|
end
|
|
46
|
+
|
|
47
|
+
# @return [Boolean] true if this table has a +dice+ column set and can be rolled on
|
|
48
|
+
def sorteavel?
|
|
49
|
+
dice.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Rolls the table's dice and returns the matching row (a Hash keyed by header, same
|
|
53
|
+
# shape as {#rows} entries). Assumes the first header's column holds a range string
|
|
54
|
+
# (e.g. +"01-05"+) or a single value (e.g. +"06"+) that the roll falls within.
|
|
55
|
+
#
|
|
56
|
+
# @return [Hash, nil] the matching row, or +nil+ if no row's range matches
|
|
57
|
+
# @raise [RuntimeError] if the table has no +dice+ column set
|
|
58
|
+
def roll
|
|
59
|
+
raise "Tabela '#{id}' não é sorteável (sem coluna dice)" unless sorteavel?
|
|
60
|
+
|
|
61
|
+
faces = dice[/\d+\z/].to_i
|
|
62
|
+
result = rand(1..faces)
|
|
63
|
+
range_key = headers.first
|
|
64
|
+
rows.find { |r| self.class.in_range?(r[range_key], result) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Boolean] true if +value+ falls within +range_str+ (e.g. +"01-05"+ or +"06"+)
|
|
68
|
+
def self.in_range?(range_str, value)
|
|
69
|
+
bounds = range_str.to_s.split("-").map(&:to_i)
|
|
70
|
+
bounds << bounds.first if bounds.size == 1
|
|
71
|
+
value.between?(bounds.min, bounds.max)
|
|
72
|
+
end
|
|
43
73
|
end
|
|
44
74
|
end
|
|
45
75
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tormenta20
|
|
4
|
+
module Rules
|
|
5
|
+
# Damage step rules for weapon damage dice (Tormenta20 core rules, Tabela: Passos de Dano).
|
|
6
|
+
#
|
|
7
|
+
# Effects that increase or decrease weapon damage "by steps" move the damage die
|
|
8
|
+
# along a fixed progression, from -2 to +3 steps relative to the weapon's normal die.
|
|
9
|
+
module DamageStep
|
|
10
|
+
STEPS = %w[menos_2 menos_1 normal mais_1 mais_2 mais_3].freeze
|
|
11
|
+
|
|
12
|
+
TABLE = [
|
|
13
|
+
{ "menos_2" => "1", "menos_1" => "1d2", "normal" => "1d3", "mais_1" => "1d4", "mais_2" => "1d6", "mais_3" => "1d8" },
|
|
14
|
+
{ "menos_2" => "1d2", "menos_1" => "1d3", "normal" => "1d4", "mais_1" => "1d6", "mais_2" => "1d8", "mais_3" => "1d10" },
|
|
15
|
+
{ "menos_2" => "1d3", "menos_1" => "1d4", "normal" => "1d6", "mais_1" => "1d8", "mais_2" => "1d10", "mais_3" => "1d12" },
|
|
16
|
+
{ "menos_2" => "1d4", "menos_1" => "1d6", "normal" => "1d8", "mais_1" => "1d10", "mais_2" => "1d12", "mais_3" => "3d6" },
|
|
17
|
+
{ "menos_2" => "1d6", "menos_1" => "1d8", "normal" => "1d10", "mais_1" => "1d12", "mais_2" => "3d6", "mais_3" => "4d6" },
|
|
18
|
+
{ "menos_2" => "1d8", "menos_1" => "1d10", "normal" => "1d12", "mais_1" => "3d6", "mais_2" => "4d6", "mais_3" => "4d8" },
|
|
19
|
+
{ "menos_2" => "1d10", "menos_1" => "2d6", "normal" => "2d8", "mais_1" => "3d8", "mais_2" => "4d8", "mais_3" => "4d10" },
|
|
20
|
+
{ "menos_2" => "2d6", "menos_1" => "2d8", "normal" => "2d10", "mais_1" => "3d10", "mais_2" => "4d10", "mais_3" => "4d12" }
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
# Returns the damage die after shifting it a number of steps up or down.
|
|
24
|
+
#
|
|
25
|
+
# @param dice [String] the weapon's current normal damage die (e.g. "1d8")
|
|
26
|
+
# @param steps [Integer] steps to shift, positive (up) or negative (down);
|
|
27
|
+
# clamped to the table's range (-2 to +3)
|
|
28
|
+
# @return [String, nil] the resulting die, or nil if `dice` isn't a known normal damage die
|
|
29
|
+
def self.adjust(dice, steps)
|
|
30
|
+
row = TABLE.find { |r| r["normal"] == dice }
|
|
31
|
+
return nil unless row
|
|
32
|
+
|
|
33
|
+
row[STEPS[steps.clamp(-2, 3) + 2]]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tormenta20
|
|
4
|
+
module Rules
|
|
5
|
+
# Spell PM cost rules (Tormenta20 core rules, Tabela 4-1: Custo de Magias).
|
|
6
|
+
module SpellCost
|
|
7
|
+
COSTS_BY_CIRCLE = { 1 => 1, 2 => 3, 3 => 6, 4 => 10, 5 => 15 }.freeze
|
|
8
|
+
|
|
9
|
+
# Returns the base PM cost for a spell of the given circle.
|
|
10
|
+
#
|
|
11
|
+
# @param circle [String, Integer] the spell's circle (1-5)
|
|
12
|
+
# @return [Integer, nil] PM cost, or nil if the circle is unknown
|
|
13
|
+
def self.for_circle(circle)
|
|
14
|
+
COSTS_BY_CIRCLE[circle.to_i]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -12,23 +12,39 @@ module Tormenta20
|
|
|
12
12
|
@verbose = verbose
|
|
13
13
|
log "Seeding database..."
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
Thread.current[:tormenta20_seeding] = true
|
|
16
|
+
begin
|
|
17
|
+
seed_livros
|
|
18
|
+
seed_racas
|
|
19
|
+
seed_habilidades_de_raca
|
|
20
|
+
seed_origens
|
|
21
|
+
seed_poderes_habilidades_unicas
|
|
22
|
+
seed_divindades
|
|
23
|
+
seed_poderes_concedidos
|
|
24
|
+
seed_poderes_tormenta
|
|
25
|
+
seed_poderes_gerais
|
|
26
|
+
seed_classes
|
|
27
|
+
seed_habilidades_de_classe
|
|
28
|
+
seed_classes_variantes
|
|
29
|
+
seed_distincoes
|
|
30
|
+
seed_poderes_distincao
|
|
31
|
+
seed_complicacoes
|
|
32
|
+
seed_magias
|
|
33
|
+
seed_equipamentos
|
|
34
|
+
seed_itens_superiores
|
|
35
|
+
seed_regras
|
|
36
|
+
seed_condicoes
|
|
37
|
+
seed_pericias
|
|
38
|
+
seed_tabelas
|
|
39
|
+
seed_itens_magicos
|
|
40
|
+
seed_ameacas
|
|
41
|
+
seed_bases_tipos
|
|
42
|
+
seed_comodos
|
|
43
|
+
seed_mobilias
|
|
44
|
+
seed_indice_remissivo
|
|
45
|
+
ensure
|
|
46
|
+
Thread.current[:tormenta20_seeding] = false
|
|
47
|
+
end
|
|
32
48
|
|
|
33
49
|
log "Database seeded successfully!"
|
|
34
50
|
end
|
|
@@ -45,6 +61,41 @@ module Tormenta20
|
|
|
45
61
|
puts message if @verbose
|
|
46
62
|
end
|
|
47
63
|
|
|
64
|
+
def seed_livros
|
|
65
|
+
import_json_files(
|
|
66
|
+
"livros",
|
|
67
|
+
Models::Livro,
|
|
68
|
+
%i[id nome nome_curto]
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def seed_indice_remissivo
|
|
73
|
+
json_dir = File.join(JSON_BASE_PATH, "indice_remissivo")
|
|
74
|
+
return unless Dir.exist?(json_dir)
|
|
75
|
+
|
|
76
|
+
Dir.glob(File.join(json_dir, "*.json")).each do |file|
|
|
77
|
+
livro_id = File.basename(file, ".json")
|
|
78
|
+
entries = JSON.parse(File.read(file), symbolize_names: true)
|
|
79
|
+
next unless entries.is_a?(Array)
|
|
80
|
+
|
|
81
|
+
entries.each do |entry|
|
|
82
|
+
next unless entry[:termo] && entry[:pagina]
|
|
83
|
+
|
|
84
|
+
Models::IndiceRemissivo.new(
|
|
85
|
+
livro_id: livro_id,
|
|
86
|
+
termo: entry[:termo],
|
|
87
|
+
pagina: entry[:pagina],
|
|
88
|
+
tabela: entry[:tabela],
|
|
89
|
+
registro_id: entry[:registro_id]
|
|
90
|
+
).save!
|
|
91
|
+
rescue StandardError
|
|
92
|
+
next
|
|
93
|
+
end
|
|
94
|
+
rescue StandardError
|
|
95
|
+
next
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
48
99
|
def seed_racas
|
|
49
100
|
import_json_files(
|
|
50
101
|
"racas",
|
|
@@ -106,7 +157,8 @@ module Tormenta20
|
|
|
106
157
|
"deuses",
|
|
107
158
|
Models::Divindade,
|
|
108
159
|
%i[id name title description beliefs_objectives holy_symbol energy
|
|
109
|
-
preferred_weapon devotees granted_powers obligations_restrictions
|
|
160
|
+
preferred_weapon devotees granted_powers obligations_restrictions
|
|
161
|
+
rank natureza status_divino]
|
|
110
162
|
)
|
|
111
163
|
end
|
|
112
164
|
|
|
@@ -187,6 +239,82 @@ module Tormenta20
|
|
|
187
239
|
end
|
|
188
240
|
end
|
|
189
241
|
|
|
242
|
+
def seed_classes_variantes
|
|
243
|
+
import_json_files(
|
|
244
|
+
"classes_variantes",
|
|
245
|
+
Models::ClasseVariante,
|
|
246
|
+
%i[id name base_class_id description diffs]
|
|
247
|
+
)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def seed_distincoes
|
|
251
|
+
import_json_files(
|
|
252
|
+
"distincoes",
|
|
253
|
+
Models::Distincao,
|
|
254
|
+
%i[id name description admissao marca_nome marca_descricao nivel_minimo]
|
|
255
|
+
)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def seed_complicacoes
|
|
259
|
+
import_json_files(
|
|
260
|
+
"complicacoes",
|
|
261
|
+
Models::Complicacao,
|
|
262
|
+
%i[id name description categoria effects]
|
|
263
|
+
)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def seed_bases_tipos
|
|
267
|
+
import_json_files(
|
|
268
|
+
"bases_tipos",
|
|
269
|
+
Models::BaseTipo,
|
|
270
|
+
%i[id name description effects]
|
|
271
|
+
)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def seed_comodos
|
|
275
|
+
import_json_files(
|
|
276
|
+
"comodos",
|
|
277
|
+
Models::Comodo,
|
|
278
|
+
%i[id name description effects prerequisito]
|
|
279
|
+
)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def seed_mobilias
|
|
283
|
+
import_json_files(
|
|
284
|
+
"mobilias",
|
|
285
|
+
Models::Mobilia,
|
|
286
|
+
%i[id name description effects preco comodo_alvo]
|
|
287
|
+
)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def seed_poderes_distincao
|
|
291
|
+
base_dir = File.join(JSON_BASE_PATH, "poderes", "poderes_distincao")
|
|
292
|
+
return unless Dir.exist?(base_dir)
|
|
293
|
+
|
|
294
|
+
Dir.each_child(base_dir) do |distincao_dir|
|
|
295
|
+
distincao_path = File.join(base_dir, distincao_dir)
|
|
296
|
+
next unless File.directory?(distincao_path)
|
|
297
|
+
|
|
298
|
+
distincao_id = distincao_dir
|
|
299
|
+
|
|
300
|
+
Dir.glob(File.join(distincao_path, "*.json")).each do |file|
|
|
301
|
+
data = JSON.parse(File.read(file), symbolize_names: true)
|
|
302
|
+
next if data[:id].nil?
|
|
303
|
+
|
|
304
|
+
record = Models::Poder.find_or_initialize_by(id: data[:id])
|
|
305
|
+
record.name = data[:name] || data[:id].to_s.humanize
|
|
306
|
+
record.type = "poder_distincao"
|
|
307
|
+
record.distincao_id = distincao_id
|
|
308
|
+
record.description = data[:description]
|
|
309
|
+
record.effects = data[:effects] || []
|
|
310
|
+
record.prerequisites = data[:requirements] || data[:prerequisites] || []
|
|
311
|
+
record.save!
|
|
312
|
+
rescue StandardError
|
|
313
|
+
next
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
190
318
|
def seed_magias
|
|
191
319
|
json_dir = File.join(JSON_BASE_PATH, "magias")
|
|
192
320
|
return unless Dir.exist?(json_dir)
|
|
@@ -375,8 +503,90 @@ module Tormenta20
|
|
|
375
503
|
import_json_files(
|
|
376
504
|
"tabelas",
|
|
377
505
|
Models::Tabela,
|
|
378
|
-
%i[id name description headers rows]
|
|
506
|
+
%i[id name description headers rows dice]
|
|
507
|
+
)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def seed_itens_magicos
|
|
511
|
+
import_json_files(
|
|
512
|
+
"itens_magicos/armas_especificas",
|
|
513
|
+
Models::ArmaMagicaEspecifica,
|
|
514
|
+
%i[id name base_weapon preco description effects]
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
import_json_files(
|
|
518
|
+
"itens_magicos/armaduras_especificas",
|
|
519
|
+
Models::ArmaduraMagicaEspecifica,
|
|
520
|
+
%i[id name subtipo base_item preco description effects]
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
import_json_files(
|
|
524
|
+
"itens_magicos/itens_liturgicos",
|
|
525
|
+
Models::ItemLiturgico,
|
|
526
|
+
%i[id name deities subtipo base_item classificacao preco description effects]
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
import_json_files(
|
|
530
|
+
"itens_magicos/artefatos",
|
|
531
|
+
Models::Artefato,
|
|
532
|
+
%i[id name description effects]
|
|
379
533
|
)
|
|
534
|
+
|
|
535
|
+
import_json_files(
|
|
536
|
+
"itens_magicos/esotericos",
|
|
537
|
+
Models::EsotericoMagico,
|
|
538
|
+
%i[id name categoria preco roll_min roll_max description effects]
|
|
539
|
+
)
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def seed_ameacas
|
|
543
|
+
json_dir = File.join(JSON_BASE_PATH, "ameacas")
|
|
544
|
+
return unless Dir.exist?(json_dir)
|
|
545
|
+
|
|
546
|
+
Dir.glob(File.join(json_dir, "**", "*.json")).each do |file|
|
|
547
|
+
data = JSON.parse(File.read(file), symbolize_names: true)
|
|
548
|
+
next if data[:id].nil?
|
|
549
|
+
|
|
550
|
+
attrs = data[:atributos] || {}
|
|
551
|
+
record = Models::Ameaca.find_or_initialize_by(id: data[:id])
|
|
552
|
+
record.name = data[:name]
|
|
553
|
+
record.nd = data[:nd]
|
|
554
|
+
record.tipo = data[:tipo]
|
|
555
|
+
record.subtipo = data[:subtipo]
|
|
556
|
+
record.tamanho = data[:tamanho] || "médio"
|
|
557
|
+
record.grupo = data[:grupo]
|
|
558
|
+
record.pv = data[:pv]
|
|
559
|
+
record.defesa = data[:defesa]
|
|
560
|
+
record[:for] = attrs[:for]
|
|
561
|
+
record.des = attrs[:des]
|
|
562
|
+
record.con = attrs[:con]
|
|
563
|
+
record.int = attrs[:int]
|
|
564
|
+
record.sab = attrs[:sab]
|
|
565
|
+
record.car = attrs[:car]
|
|
566
|
+
record.iniciativa = data[:iniciativa]
|
|
567
|
+
record.deslocamento = data[:deslocamento]
|
|
568
|
+
record.salvaguardas = data[:salvaguardas] || {}
|
|
569
|
+
record.percepcao = data[:percepcao]
|
|
570
|
+
record.visao = data[:visao]
|
|
571
|
+
record.ataques = data[:ataques] || []
|
|
572
|
+
record.poderes_especiais = data[:poderes_especiais] || []
|
|
573
|
+
record.imunidades = data[:imunidades] || []
|
|
574
|
+
record.resistencias = data[:resistencias] || {}
|
|
575
|
+
record.vulnerabilidades = data[:vulnerabilidades] || []
|
|
576
|
+
record.reducao_de_dano = data[:reducao_de_dano]
|
|
577
|
+
record.cura_acelerada = data[:cura_acelerada]
|
|
578
|
+
record.resistencia_a_magia = data[:resistencia_a_magia]
|
|
579
|
+
record.pericias = data[:pericias] || {}
|
|
580
|
+
record.equipamento = data[:equipamento] || []
|
|
581
|
+
record.tesouro = data[:tesouro]
|
|
582
|
+
record.pm = data[:pm]
|
|
583
|
+
record.description = data[:description]
|
|
584
|
+
record.familiar = data[:familiar]
|
|
585
|
+
record.parceiro = data[:parceiro]
|
|
586
|
+
record.save!
|
|
587
|
+
rescue StandardError
|
|
588
|
+
next
|
|
589
|
+
end
|
|
380
590
|
end
|
|
381
591
|
|
|
382
592
|
def import_json_files(subdir, model, attrs, extra_attrs: {}, transform: nil)
|
data/src/ruby/tormenta20.rb
CHANGED
|
@@ -8,10 +8,11 @@ require_relative "tormenta20/database"
|
|
|
8
8
|
|
|
9
9
|
# Load concerns before models
|
|
10
10
|
require_relative "tormenta20/concerns/book_referenceable"
|
|
11
|
+
require_relative "tormenta20/concerns/livro_scoped"
|
|
11
12
|
|
|
12
13
|
# Load base model first, then other models
|
|
13
14
|
require_relative "tormenta20/models/base"
|
|
14
|
-
Dir["#{__dir__}/tormenta20/models/*.rb"].each { |file| require file unless
|
|
15
|
+
Dir["#{__dir__}/tormenta20/models/*.rb"].each { |file| require file unless File.basename(file) == "base.rb" }
|
|
15
16
|
|
|
16
17
|
# Load other modules
|
|
17
18
|
Dir["#{__dir__}/tormenta20/*.rb"].each { |file| require file unless file.include?("database") }
|
|
@@ -70,6 +71,16 @@ module Tormenta20
|
|
|
70
71
|
Models::Poder
|
|
71
72
|
end
|
|
72
73
|
|
|
74
|
+
# Access the Distincao (Distinction) model for querying distinctions.
|
|
75
|
+
#
|
|
76
|
+
# @return [Class<Models::Distincao>] The Distincao model class
|
|
77
|
+
# @example
|
|
78
|
+
# Tormenta20.distincoes.find("amazona")
|
|
79
|
+
# Tormenta20.poderes.by_distincao("amazona")
|
|
80
|
+
def distincoes
|
|
81
|
+
Models::Distincao
|
|
82
|
+
end
|
|
83
|
+
|
|
73
84
|
# Access the Divindade (Deity) model for querying deities.
|
|
74
85
|
#
|
|
75
86
|
# @return [Class<Models::Divindade>] The Divindade model class
|
|
@@ -249,6 +260,97 @@ module Tormenta20
|
|
|
249
260
|
Models::AcessorioMagico
|
|
250
261
|
end
|
|
251
262
|
|
|
263
|
+
# Access the EsotericoMagico (Magic Esoteric Implement) model for querying staffs,
|
|
264
|
+
# wands, holy symbols and other spellcasting foci.
|
|
265
|
+
#
|
|
266
|
+
# @return [Class<Models::EsotericoMagico>] The EsotericoMagico model class
|
|
267
|
+
# @example
|
|
268
|
+
# Tormenta20.esotericos.maiores
|
|
269
|
+
# Tormenta20.esotericos.find("cajado_do_poder")
|
|
270
|
+
def esotericos
|
|
271
|
+
Models::EsotericoMagico
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Access the Complicacao (Character Complication) model.
|
|
275
|
+
#
|
|
276
|
+
# @return [Class<Models::Complicacao>] The Complicacao model class
|
|
277
|
+
# @example
|
|
278
|
+
# Tormenta20.complicacoes.gerais
|
|
279
|
+
# Tormenta20.complicacoes.by_categoria("guerreiro")
|
|
280
|
+
def complicacoes
|
|
281
|
+
Models::Complicacao
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Access the BaseTipo (Headquarters Type) model.
|
|
285
|
+
# @return [Class<Models::BaseTipo>]
|
|
286
|
+
def bases_tipos
|
|
287
|
+
Models::BaseTipo
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Access the Comodo (Headquarters Room) model.
|
|
291
|
+
# @return [Class<Models::Comodo>]
|
|
292
|
+
def comodos
|
|
293
|
+
Models::Comodo
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Access the Mobilia (Headquarters Furniture) model.
|
|
297
|
+
# @return [Class<Models::Mobilia>]
|
|
298
|
+
def mobilias
|
|
299
|
+
Models::Mobilia
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Access the ConstrucaoDominio (Domain Building) model.
|
|
303
|
+
# @return [Class<Models::ConstrucaoDominio>]
|
|
304
|
+
def construcoes_dominio
|
|
305
|
+
Models::ConstrucaoDominio
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Access named specific magic weapons (Cap. 8, Tabela 8-9).
|
|
309
|
+
#
|
|
310
|
+
# @return [Class<Models::ArmaMagicaEspecifica>]
|
|
311
|
+
# @example
|
|
312
|
+
# Tormenta20.armas_magicas.order(:preco)
|
|
313
|
+
def armas_magicas
|
|
314
|
+
Models::ArmaMagicaEspecifica
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Access named specific magic armors and shields (Cap. 8, Tabela 8-11).
|
|
318
|
+
#
|
|
319
|
+
# @return [Class<Models::ArmaduraMagicaEspecifica>]
|
|
320
|
+
# @example
|
|
321
|
+
# Tormenta20.armaduras_magicas.escudos
|
|
322
|
+
def armaduras_magicas
|
|
323
|
+
Models::ArmaduraMagicaEspecifica
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Access liturgical items — named magic items tied to a specific deity
|
|
327
|
+
# (Deuses de Arton, Cap. 1).
|
|
328
|
+
#
|
|
329
|
+
# @return [Class<Models::ItemLiturgico>]
|
|
330
|
+
# @example
|
|
331
|
+
# Tormenta20.itens_liturgicos.by_deity("aharadak")
|
|
332
|
+
def itens_liturgicos
|
|
333
|
+
Models::ItemLiturgico
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Access artifacts — unique, extremely powerful magic items (Cap. 8, pp. 350–353).
|
|
337
|
+
#
|
|
338
|
+
# @return [Class<Models::Artefato>]
|
|
339
|
+
# @example
|
|
340
|
+
# Tormenta20.artefatos.all
|
|
341
|
+
def artefatos
|
|
342
|
+
Models::Artefato
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Access monster and enemy stat blocks (Cap. 7).
|
|
346
|
+
#
|
|
347
|
+
# @return [Class<Models::Ameaca>]
|
|
348
|
+
# @example
|
|
349
|
+
# Tormenta20.ameacas.dragoes.order(:nd)
|
|
350
|
+
def ameacas
|
|
351
|
+
Models::Ameaca
|
|
352
|
+
end
|
|
353
|
+
|
|
252
354
|
# @!endgroup
|
|
253
355
|
end
|
|
254
356
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tormenta20
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LuanGB
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -98,22 +98,36 @@ files:
|
|
|
98
98
|
- docs/ruby/regras.md
|
|
99
99
|
- src/ruby/tormenta20.rb
|
|
100
100
|
- src/ruby/tormenta20/concerns/book_referenceable.rb
|
|
101
|
+
- src/ruby/tormenta20/concerns/livro_scoped.rb
|
|
101
102
|
- src/ruby/tormenta20/database.rb
|
|
102
103
|
- src/ruby/tormenta20/models/acessorio_magico.rb
|
|
104
|
+
- src/ruby/tormenta20/models/ameaca.rb
|
|
103
105
|
- src/ruby/tormenta20/models/arma.rb
|
|
106
|
+
- src/ruby/tormenta20/models/arma_magica_especifica.rb
|
|
104
107
|
- src/ruby/tormenta20/models/armadura.rb
|
|
108
|
+
- src/ruby/tormenta20/models/armadura_magica_especifica.rb
|
|
109
|
+
- src/ruby/tormenta20/models/artefato.rb
|
|
105
110
|
- src/ruby/tormenta20/models/base.rb
|
|
111
|
+
- src/ruby/tormenta20/models/base_tipo.rb
|
|
106
112
|
- src/ruby/tormenta20/models/classe.rb
|
|
113
|
+
- src/ruby/tormenta20/models/classe_variante.rb
|
|
114
|
+
- src/ruby/tormenta20/models/comodo.rb
|
|
115
|
+
- src/ruby/tormenta20/models/complicacao.rb
|
|
107
116
|
- src/ruby/tormenta20/models/condicao.rb
|
|
117
|
+
- src/ruby/tormenta20/models/construcao_dominio.rb
|
|
118
|
+
- src/ruby/tormenta20/models/distincao.rb
|
|
108
119
|
- src/ruby/tormenta20/models/divindade.rb
|
|
109
120
|
- src/ruby/tormenta20/models/encantamento.rb
|
|
110
121
|
- src/ruby/tormenta20/models/escudo.rb
|
|
122
|
+
- src/ruby/tormenta20/models/esoterico_magico.rb
|
|
111
123
|
- src/ruby/tormenta20/models/indice_remissivo.rb
|
|
112
124
|
- src/ruby/tormenta20/models/item.rb
|
|
125
|
+
- src/ruby/tormenta20/models/item_liturgico.rb
|
|
113
126
|
- src/ruby/tormenta20/models/livro.rb
|
|
114
127
|
- src/ruby/tormenta20/models/magia.rb
|
|
115
128
|
- src/ruby/tormenta20/models/material_especial.rb
|
|
116
129
|
- src/ruby/tormenta20/models/melhoria.rb
|
|
130
|
+
- src/ruby/tormenta20/models/mobilia.rb
|
|
117
131
|
- src/ruby/tormenta20/models/origem.rb
|
|
118
132
|
- src/ruby/tormenta20/models/pericia.rb
|
|
119
133
|
- src/ruby/tormenta20/models/pocao.rb
|
|
@@ -122,14 +136,16 @@ files:
|
|
|
122
136
|
- src/ruby/tormenta20/models/regra.rb
|
|
123
137
|
- src/ruby/tormenta20/models/tabela.rb
|
|
124
138
|
- src/ruby/tormenta20/rules.rb
|
|
139
|
+
- src/ruby/tormenta20/rules/damage_step.rb
|
|
125
140
|
- src/ruby/tormenta20/rules/pm_cap.rb
|
|
141
|
+
- src/ruby/tormenta20/rules/spell_cost.rb
|
|
126
142
|
- src/ruby/tormenta20/seeder.rb
|
|
127
143
|
- src/ruby/tormenta20/version.rb
|
|
128
|
-
homepage: https://github.
|
|
144
|
+
homepage: https://yggdrasilgeeknetwork.github.io/tormenta20/
|
|
129
145
|
licenses:
|
|
130
146
|
- MIT
|
|
131
147
|
metadata:
|
|
132
|
-
homepage_uri: https://github.
|
|
148
|
+
homepage_uri: https://yggdrasilgeeknetwork.github.io/tormenta20/
|
|
133
149
|
source_code_uri: https://github.com/YggdrasilGeekNetwork/tormenta20
|
|
134
150
|
changelog_uri: https://github.com/YggdrasilGeekNetwork/tormenta20/blob/main/CHANGELOG.md
|
|
135
151
|
documentation_uri: https://rubydoc.info/gems/tormenta20
|