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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tormenta20
|
|
4
|
+
module Concerns
|
|
5
|
+
# Mixin that gives any gem model with a +livro_id+ column access to its
|
|
6
|
+
# source book and a scope to filter by it.
|
|
7
|
+
#
|
|
8
|
+
# Distinct from {BookReferenceable}: that concern looks up a record's page
|
|
9
|
+
# number via the (sparse) printed índice remissivo, while +livro_id+ is
|
|
10
|
+
# the authoritative "book this record was published in" column, present
|
|
11
|
+
# on every content table and defaulting to +"t20_eja"+.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# Tormenta20.classes.do_livro("t20_eja").all
|
|
15
|
+
# Tormenta20.classes.first.livro.nome_curto # => "T20 - EJA"
|
|
16
|
+
module LivroScoped
|
|
17
|
+
extend ActiveSupport::Concern
|
|
18
|
+
|
|
19
|
+
included do
|
|
20
|
+
belongs_to :livro, class_name: "Tormenta20::Models::Livro", foreign_key: "livro_id", optional: true
|
|
21
|
+
|
|
22
|
+
scope :do_livro, ->(livro_id) { where(livro_id: livro_id) }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -8,7 +8,7 @@ module Tormenta20
|
|
|
8
8
|
#
|
|
9
9
|
# @example
|
|
10
10
|
# AcessorioMagico.menores.all
|
|
11
|
-
# AcessorioMagico.find_by(id: "anel_de_protecao").
|
|
11
|
+
# AcessorioMagico.find_by(id: "anel_de_protecao").effects
|
|
12
12
|
#
|
|
13
13
|
# @!attribute [rw] id
|
|
14
14
|
# @return [String] Unique identifier
|
|
@@ -39,15 +39,12 @@ module Tormenta20
|
|
|
39
39
|
scope :maiores, -> { where(categoria: "maior") }
|
|
40
40
|
# @!endgroup
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
raw.is_a?(Hash) ? raw : JSON.parse(raw)
|
|
49
|
-
rescue JSON::ParserError
|
|
50
|
-
{}
|
|
42
|
+
def to_h
|
|
43
|
+
{
|
|
44
|
+
id: id, name: name, categoria: categoria, preco: preco,
|
|
45
|
+
roll_min: roll_min, roll_max: roll_max,
|
|
46
|
+
description: description, effects: effects
|
|
47
|
+
}.compact
|
|
51
48
|
end
|
|
52
49
|
end
|
|
53
50
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Monster and enemy stat blocks from Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# Tormenta20.ameacas.where(grupo: "masmorras").order(:nd)
|
|
11
|
+
# Tormenta20.ameacas.find("basilisco")
|
|
12
|
+
class Ameaca < Base
|
|
13
|
+
self.table_name = "ameacas"
|
|
14
|
+
|
|
15
|
+
validates :id, presence: true, uniqueness: true
|
|
16
|
+
validates :name, presence: true
|
|
17
|
+
validates :nd, presence: true
|
|
18
|
+
validates :grupo, presence: true
|
|
19
|
+
|
|
20
|
+
scope :by_grupo, ->(g) { where(grupo: g) }
|
|
21
|
+
scope :by_nd, ->(n) { where(nd: n) }
|
|
22
|
+
scope :masmorras, -> { where(grupo: "masmorras") }
|
|
23
|
+
scope :ermos, -> { where(grupo: "ermos") }
|
|
24
|
+
scope :puristas, -> { where(grupo: "puristas") }
|
|
25
|
+
scope :reino_dos_mortos, -> { where(grupo: "reino_dos_mortos") }
|
|
26
|
+
scope :duyshidakk, -> { where(grupo: "duyshidakk") }
|
|
27
|
+
scope :sszzaazitas, -> { where(grupo: "sszzaazitas") }
|
|
28
|
+
scope :trolls_nobres, -> { where(grupo: "trolls_nobres") }
|
|
29
|
+
scope :dragoes, -> { where(grupo: "dragoes") }
|
|
30
|
+
scope :tormenta, -> { where(grupo: "tormenta") }
|
|
31
|
+
scope :avatares, -> { where(grupo: "avatares") }
|
|
32
|
+
|
|
33
|
+
def atributos
|
|
34
|
+
{ for: self[:for], des: des, con: con, int: self[:int], sab: sab, car: car }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_h
|
|
38
|
+
{
|
|
39
|
+
id: id,
|
|
40
|
+
name: name,
|
|
41
|
+
nd: nd,
|
|
42
|
+
tipo: tipo,
|
|
43
|
+
subtipo: subtipo,
|
|
44
|
+
tamanho: tamanho,
|
|
45
|
+
grupo: grupo,
|
|
46
|
+
pv: pv,
|
|
47
|
+
defesa: defesa,
|
|
48
|
+
atributos: atributos,
|
|
49
|
+
iniciativa: iniciativa,
|
|
50
|
+
deslocamento: deslocamento,
|
|
51
|
+
salvaguardas: salvaguardas,
|
|
52
|
+
percepcao: percepcao,
|
|
53
|
+
visao: visao,
|
|
54
|
+
ataques: ataques,
|
|
55
|
+
poderes_especiais: poderes_especiais,
|
|
56
|
+
imunidades: imunidades,
|
|
57
|
+
resistencias: resistencias,
|
|
58
|
+
vulnerabilidades: vulnerabilidades,
|
|
59
|
+
reducao_de_dano: reducao_de_dano,
|
|
60
|
+
cura_acelerada: cura_acelerada,
|
|
61
|
+
resistencia_a_magia: resistencia_a_magia,
|
|
62
|
+
pericias: pericias,
|
|
63
|
+
equipamento: equipamento,
|
|
64
|
+
tesouro: tesouro,
|
|
65
|
+
pm: pm,
|
|
66
|
+
description: description,
|
|
67
|
+
familiar: familiar,
|
|
68
|
+
parceiro: parceiro
|
|
69
|
+
}.compact
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Named specific magic weapons from Tormenta20 (Cap. 8, Tabela 8-9).
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# Tormenta20.armas_magicas.find("cajado_do_poder")
|
|
11
|
+
# Tormenta20.armas_magicas.order(:preco)
|
|
12
|
+
class ArmaMagicaEspecifica < Base
|
|
13
|
+
self.table_name = "armas_magicas_especificas"
|
|
14
|
+
|
|
15
|
+
validates :id, presence: true, uniqueness: true
|
|
16
|
+
validates :name, presence: true
|
|
17
|
+
|
|
18
|
+
scope :by_base, ->(w) { where(base_weapon: w) }
|
|
19
|
+
|
|
20
|
+
def to_h
|
|
21
|
+
{
|
|
22
|
+
id: id,
|
|
23
|
+
name: name,
|
|
24
|
+
base_weapon: base_weapon,
|
|
25
|
+
preco: preco,
|
|
26
|
+
description: description,
|
|
27
|
+
effects: effects
|
|
28
|
+
}.compact
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Named specific magic armors and shields from Tormenta20 (Cap. 8, Tabela 8-11).
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# Tormenta20.armaduras_magicas.where(subtipo: "escudo")
|
|
11
|
+
# Tormenta20.armaduras_magicas.find("cota_elfica")
|
|
12
|
+
class ArmaduraMagicaEspecifica < Base
|
|
13
|
+
self.table_name = "armaduras_magicas_especificas"
|
|
14
|
+
|
|
15
|
+
validates :id, presence: true, uniqueness: true
|
|
16
|
+
validates :name, presence: true
|
|
17
|
+
validates :subtipo, inclusion: { in: %w[armadura escudo] }
|
|
18
|
+
|
|
19
|
+
scope :armaduras, -> { where(subtipo: "armadura") }
|
|
20
|
+
scope :escudos, -> { where(subtipo: "escudo") }
|
|
21
|
+
|
|
22
|
+
def to_h
|
|
23
|
+
{
|
|
24
|
+
id: id,
|
|
25
|
+
name: name,
|
|
26
|
+
subtipo: subtipo,
|
|
27
|
+
base_item: base_item,
|
|
28
|
+
preco: preco,
|
|
29
|
+
description: description,
|
|
30
|
+
effects: effects
|
|
31
|
+
}.compact
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Artifacts — unique, extremely powerful magic items from Tormenta20 (Cap. 8, pp. 350–353).
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# Tormenta20.artefatos.all
|
|
11
|
+
# Tormenta20.artefatos.find("espada_deus")
|
|
12
|
+
class Artefato < Base
|
|
13
|
+
self.table_name = "artefatos"
|
|
14
|
+
|
|
15
|
+
validates :id, presence: true, uniqueness: true
|
|
16
|
+
validates :name, presence: true
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
{ id: id, name: name, description: description, effects: effects }.compact
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -13,12 +13,15 @@ module Tormenta20
|
|
|
13
13
|
#
|
|
14
14
|
# Every concrete model adds {Concerns::BookReferenceable}, which provides
|
|
15
15
|
# the {Concerns::BookReferenceable#book_reference} method for sourcebook
|
|
16
|
-
# page lookup
|
|
16
|
+
# page lookup, and {Concerns::LivroScoped}, which provides the +livro+
|
|
17
|
+
# association and +.do_livro+ scope for filtering by source book.
|
|
17
18
|
#
|
|
18
19
|
# @abstract Subclass and set +table_name+ to create a new model
|
|
19
20
|
#
|
|
20
21
|
# @!attribute [rw] id
|
|
21
22
|
# @return [String] Unique string identifier (e.g. +"guerreiro"+, +"espada_longa"+)
|
|
23
|
+
# @!attribute [rw] livro_id
|
|
24
|
+
# @return [String] Slug of the sourcebook this record was published in (default +"t20_eja"+)
|
|
22
25
|
# @!attribute [r] created_at
|
|
23
26
|
# @return [Time] Record creation timestamp
|
|
24
27
|
# @!attribute [r] updated_at
|
|
@@ -27,6 +30,7 @@ module Tormenta20
|
|
|
27
30
|
self.abstract_class = true
|
|
28
31
|
|
|
29
32
|
include Concerns::BookReferenceable
|
|
33
|
+
include Concerns::LivroScoped
|
|
30
34
|
|
|
31
35
|
# Raised when any write operation is attempted on the Tormenta20 database.
|
|
32
36
|
# The database is read-only by design — it ships as pre-built data.
|
|
@@ -38,8 +42,17 @@ module Tormenta20
|
|
|
38
42
|
|
|
39
43
|
# @!group Read-only enforcement
|
|
40
44
|
|
|
45
|
+
class << self
|
|
46
|
+
# @return [Boolean] true while {Tormenta20::Seeder} is populating a fresh database.
|
|
47
|
+
# Internal escape hatch: seeding is a legitimate write path, distinct from a
|
|
48
|
+
# consumer of the built gem mutating data.
|
|
49
|
+
def seeding?
|
|
50
|
+
Thread.current[:tormenta20_seeding] == true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
41
54
|
def readonly?
|
|
42
|
-
|
|
55
|
+
!self.class.seeding?
|
|
43
56
|
end
|
|
44
57
|
|
|
45
58
|
def destroy
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# A Tipo de Base (headquarters type) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# Represents the physical nature of a group's headquarters (Esconderijo,
|
|
10
|
+
# Fortificação, Móvel, Residência, Centro de Poder, Empreendimento) and the
|
|
11
|
+
# passive bonuses it grants its residents. Only catalog data lives here — an
|
|
12
|
+
# actual base built by a group (with a chosen type, porte, cômodos, and
|
|
13
|
+
# mobílias) is campaign state, not gem content.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# Tormenta20.bases_tipos.find("fortificacao")
|
|
17
|
+
class BaseTipo < Base
|
|
18
|
+
self.table_name = "bases_tipos"
|
|
19
|
+
|
|
20
|
+
validates :id, presence: true, uniqueness: true
|
|
21
|
+
validates :name, presence: true
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
{
|
|
25
|
+
id: id,
|
|
26
|
+
name: name,
|
|
27
|
+
description: description,
|
|
28
|
+
effects: effects || []
|
|
29
|
+
}.compact
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Model representing a Classe Variante (variant class) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# A variant class is a specialized version of a base class (e.g. Duelista
|
|
10
|
+
# is a Bucaneiro variant). It is stored as a diff over the base class: the
|
|
11
|
+
# +diffs+ array lists, per level, which base-class abilities are removed
|
|
12
|
+
# and which new ones are added. Consumers must resolve the diff against
|
|
13
|
+
# the base {Classe} record to build the final character sheet.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# variante = Tormenta20.classes_variantes.find("duelista")
|
|
17
|
+
# variante.base_classe #=> the Bucaneiro Classe record
|
|
18
|
+
# variante.diffs #=> [{ "nivel" => 1, "remove" => [...], "adiciona" => [...] }, ...]
|
|
19
|
+
class ClasseVariante < Base
|
|
20
|
+
self.table_name = "classes_variantes"
|
|
21
|
+
|
|
22
|
+
belongs_to :base_classe, class_name: "Tormenta20::Models::Classe", foreign_key: "base_class_id"
|
|
23
|
+
|
|
24
|
+
validates :id, presence: true, uniqueness: true
|
|
25
|
+
validates :name, presence: true
|
|
26
|
+
validates :base_class_id, presence: true
|
|
27
|
+
|
|
28
|
+
scope :by_base, ->(class_id) { where(base_class_id: class_id) }
|
|
29
|
+
|
|
30
|
+
def to_h
|
|
31
|
+
{
|
|
32
|
+
id: id,
|
|
33
|
+
name: name,
|
|
34
|
+
base_class_id: base_class_id,
|
|
35
|
+
description: description,
|
|
36
|
+
diffs: diffs
|
|
37
|
+
}.compact
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# A Cômodo (headquarters room) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# A catalog of rooms a group can build inside their base, each granting a
|
|
10
|
+
# passive bonus to residents. Some have a +prerequisito+ (e.g. another cômodo,
|
|
11
|
+
# or a minimum porte). Only catalog data lives here — see {BaseTipo}.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# Tormenta20.comodos.find("biblioteca")
|
|
15
|
+
class Comodo < Base
|
|
16
|
+
self.table_name = "comodos"
|
|
17
|
+
|
|
18
|
+
validates :id, presence: true, uniqueness: true
|
|
19
|
+
validates :name, presence: true
|
|
20
|
+
|
|
21
|
+
def to_h
|
|
22
|
+
{
|
|
23
|
+
id: id,
|
|
24
|
+
name: name,
|
|
25
|
+
description: description,
|
|
26
|
+
effects: effects || [],
|
|
27
|
+
prerequisito: prerequisito
|
|
28
|
+
}.compact
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# A Complicação (character complication) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# Chosen at character creation: the player accepts a mechanical drawback ({#effects})
|
|
10
|
+
# in exchange for freely picking any one general power whose prerequisites they meet
|
|
11
|
+
# (not a fixed grant tied to the complication — the gem doesn't model that choice,
|
|
12
|
+
# it belongs to the consumer's character-creation flow). +categoria+ is +"geral"+ for
|
|
13
|
+
# complications any character can take, or a class id (e.g. +"guerreiro"+) for
|
|
14
|
+
# complications specific to that class.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# Tormenta20.complicacoes.gerais
|
|
18
|
+
# Tormenta20.complicacoes.by_categoria("guerreiro")
|
|
19
|
+
class Complicacao < Base
|
|
20
|
+
self.table_name = "complicacoes"
|
|
21
|
+
|
|
22
|
+
validates :id, presence: true, uniqueness: true
|
|
23
|
+
validates :name, presence: true
|
|
24
|
+
validates :categoria, presence: true
|
|
25
|
+
|
|
26
|
+
scope :gerais, -> { where(categoria: "geral") }
|
|
27
|
+
scope :by_categoria, ->(categoria) { where(categoria: categoria) }
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
id: id,
|
|
32
|
+
name: name,
|
|
33
|
+
description: description,
|
|
34
|
+
categoria: categoria,
|
|
35
|
+
effects: effects || []
|
|
36
|
+
}.compact
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# A Construção de Domínio (domain building) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# A catalog of buildings a regent can erect in their domain (Cap. 4 "Domínios"),
|
|
10
|
+
# each with a cost in Lingotes de Ouro (LO) and a mechanical benefit. Only catalog
|
|
11
|
+
# data lives here — an actual domain's characteristics (level, corte, popularidade,
|
|
12
|
+
# buildings erected) are campaign state, not gem content. See also {BaseTipo} for
|
|
13
|
+
# the analogous pattern applied to group headquarters.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# Tormenta20.construcoes_dominio.by_categoria("religiao")
|
|
17
|
+
class ConstrucaoDominio < Base
|
|
18
|
+
self.table_name = "construcoes_dominio"
|
|
19
|
+
|
|
20
|
+
validates :id, presence: true, uniqueness: true
|
|
21
|
+
validates :name, presence: true
|
|
22
|
+
validates :categoria, presence: true, inclusion: { in: %w[nobreza guerra enganacao religiao misticismo] }
|
|
23
|
+
|
|
24
|
+
scope :by_categoria, ->(categoria) { where(categoria: categoria) }
|
|
25
|
+
|
|
26
|
+
def to_h
|
|
27
|
+
{
|
|
28
|
+
id: id,
|
|
29
|
+
name: name,
|
|
30
|
+
description: description,
|
|
31
|
+
categoria: categoria,
|
|
32
|
+
custo: custo,
|
|
33
|
+
effects: effects || [],
|
|
34
|
+
prerequisito: prerequisito
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Model representing a Distinção in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# A distinction ties a character to an organization, philosophy, or people
|
|
10
|
+
# of Arton. It has three parts: admissão (narrative requirement), marca
|
|
11
|
+
# (an ability granted automatically on admission), and a set of exclusive
|
|
12
|
+
# powers. The powers themselves live in {Poder} (+type: "poder_distincao"+,
|
|
13
|
+
# +distincao_id+ pointing back here) — not duplicated on this model.
|
|
14
|
+
#
|
|
15
|
+
# @example Find a distinction and its powers
|
|
16
|
+
# Tormenta20.distincoes.find("cavaleiro_do_corvo")
|
|
17
|
+
# Tormenta20.poderes.where(distincao_id: "cavaleiro_do_corvo")
|
|
18
|
+
class Distincao < Base
|
|
19
|
+
self.table_name = "distincoes"
|
|
20
|
+
|
|
21
|
+
has_many :poderes, class_name: "Tormenta20::Models::Poder"
|
|
22
|
+
|
|
23
|
+
validates :id, presence: true, uniqueness: true
|
|
24
|
+
validates :name, presence: true
|
|
25
|
+
|
|
26
|
+
def to_h
|
|
27
|
+
{
|
|
28
|
+
id: id,
|
|
29
|
+
name: name,
|
|
30
|
+
description: description,
|
|
31
|
+
admissao: admissao,
|
|
32
|
+
marca_nome: marca_nome,
|
|
33
|
+
marca_descricao: marca_descricao,
|
|
34
|
+
nivel_minimo: nivel_minimo
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -59,6 +59,16 @@ module Tormenta20
|
|
|
59
59
|
# @return [ActiveRecord::Relation<Divindade>]
|
|
60
60
|
scope :by_energy, ->(e) { where(energy: e) }
|
|
61
61
|
|
|
62
|
+
# @!method maiores
|
|
63
|
+
# Filter major (greater) deities.
|
|
64
|
+
# @return [ActiveRecord::Relation<Divindade>]
|
|
65
|
+
scope :maiores, -> { where(rank: "maior") }
|
|
66
|
+
|
|
67
|
+
# @!method menores
|
|
68
|
+
# Filter minor (lesser) deities (Deuses de Arton, Cap. 3).
|
|
69
|
+
# @return [ActiveRecord::Relation<Divindade>]
|
|
70
|
+
scope :menores, -> { where(rank: "menor") }
|
|
71
|
+
|
|
62
72
|
# @!endgroup
|
|
63
73
|
|
|
64
74
|
# Get races that typically worship this deity.
|
|
@@ -90,7 +100,10 @@ module Tormenta20
|
|
|
90
100
|
preferred_weapon: preferred_weapon,
|
|
91
101
|
devotees: devotees,
|
|
92
102
|
granted_powers: granted_powers,
|
|
93
|
-
obligations_restrictions: obligations_restrictions
|
|
103
|
+
obligations_restrictions: obligations_restrictions,
|
|
104
|
+
rank: rank,
|
|
105
|
+
natureza: natureza,
|
|
106
|
+
status_divino: status_divino
|
|
94
107
|
}.compact
|
|
95
108
|
end
|
|
96
109
|
end
|
|
@@ -21,11 +21,13 @@ module Tormenta20
|
|
|
21
21
|
|
|
22
22
|
validates :id, presence: true, uniqueness: true
|
|
23
23
|
validates :name, presence: true
|
|
24
|
-
validates :categoria, presence: true, inclusion: { in: %w[arma
|
|
24
|
+
validates :categoria, presence: true, inclusion: { in: %w[arma armadura esoterico acessorio] }
|
|
25
25
|
|
|
26
26
|
scope :armas, -> { where(categoria: "arma") }
|
|
27
|
-
scope :armaduras_escudos, -> { where(categoria: "
|
|
27
|
+
scope :armaduras_escudos, -> { where(categoria: "armadura") }
|
|
28
28
|
scope :escudo_only, -> { where(escudo_only: true) }
|
|
29
|
+
scope :maldicoes, -> { where(maldicao: true) }
|
|
30
|
+
scope :nao_maldicoes, -> { where(maldicao: [false, nil]) }
|
|
29
31
|
|
|
30
32
|
def to_h
|
|
31
33
|
{
|
|
@@ -35,8 +37,9 @@ module Tormenta20
|
|
|
35
37
|
categoria: categoria,
|
|
36
38
|
escudo_only: escudo_only == 1,
|
|
37
39
|
conta_como_dois: conta_como_dois == 1,
|
|
40
|
+
maldicao: maldicao == 1,
|
|
38
41
|
prerequisitos: prerequisitos,
|
|
39
|
-
|
|
42
|
+
effects: effects
|
|
40
43
|
}.compact
|
|
41
44
|
end
|
|
42
45
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Magic esoteric implements (staffs, wands, holy symbols) used by spellcasters.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# EsotericoMagico.menores.all
|
|
11
|
+
# EsotericoMagico.find_by(id: "cajado_do_poder").effects
|
|
12
|
+
#
|
|
13
|
+
# @!attribute [rw] id
|
|
14
|
+
# @return [String] Unique identifier
|
|
15
|
+
# @!attribute [rw] name
|
|
16
|
+
# @return [String] Item name
|
|
17
|
+
# @!attribute [rw] categoria
|
|
18
|
+
# @return [String] Power tier: +"menor"+, +"medio"+, or +"maior"+
|
|
19
|
+
# @!attribute [rw] preco
|
|
20
|
+
# @return [Integer, nil] Price in tibares
|
|
21
|
+
# @!attribute [rw] roll_min
|
|
22
|
+
# @return [Integer, nil] Minimum roll on random loot table
|
|
23
|
+
# @!attribute [rw] roll_max
|
|
24
|
+
# @return [Integer, nil] Maximum roll on random loot table
|
|
25
|
+
# @!attribute [rw] description
|
|
26
|
+
# @return [String, nil] Item description
|
|
27
|
+
class EsotericoMagico < Base
|
|
28
|
+
self.table_name = "esotericos_magicos"
|
|
29
|
+
|
|
30
|
+
# @!group Scopes
|
|
31
|
+
# @!method menores
|
|
32
|
+
# @return [ActiveRecord::Relation] Minor-tier esoterics
|
|
33
|
+
scope :menores, -> { where(categoria: "menor") }
|
|
34
|
+
# @!method medios
|
|
35
|
+
# @return [ActiveRecord::Relation] Medium-tier esoterics
|
|
36
|
+
scope :medios, -> { where(categoria: "medio") }
|
|
37
|
+
# @!method maiores
|
|
38
|
+
# @return [ActiveRecord::Relation] Major-tier esoterics
|
|
39
|
+
scope :maiores, -> { where(categoria: "maior") }
|
|
40
|
+
# @!endgroup
|
|
41
|
+
|
|
42
|
+
def to_h
|
|
43
|
+
{
|
|
44
|
+
id: id, name: name, categoria: categoria, preco: preco,
|
|
45
|
+
roll_min: roll_min, roll_max: roll_max,
|
|
46
|
+
description: description, effects: effects
|
|
47
|
+
}.compact
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# Named magic item tied to a specific deity (Deuses de Arton, Cap. 1).
|
|
8
|
+
#
|
|
9
|
+
# Liturgical items (weapons, armors or accessories) only reach their full
|
|
10
|
+
# potential — or only work at all — in the hands of a devotee of the
|
|
11
|
+
# associated deity. They can span multiple item categories, so `deities`
|
|
12
|
+
# is a JSON array instead of a rigid foreign key.
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# Tormenta20.itens_liturgicos.find("cilicio_vivo")
|
|
16
|
+
# Tormenta20.itens_liturgicos.by_deity("aharadak")
|
|
17
|
+
class ItemLiturgico < Base
|
|
18
|
+
self.table_name = "itens_liturgicos"
|
|
19
|
+
|
|
20
|
+
validates :id, presence: true, uniqueness: true
|
|
21
|
+
validates :name, presence: true
|
|
22
|
+
|
|
23
|
+
scope :by_deity, ->(deity_id) { where("json_extract(deities, '$') LIKE ?", "%#{deity_id}%") }
|
|
24
|
+
scope :by_subtipo, ->(s) { where(subtipo: s) }
|
|
25
|
+
|
|
26
|
+
def to_h
|
|
27
|
+
{
|
|
28
|
+
id: id,
|
|
29
|
+
name: name,
|
|
30
|
+
deities: deities,
|
|
31
|
+
subtipo: subtipo,
|
|
32
|
+
base_item: base_item,
|
|
33
|
+
classificacao: classificacao,
|
|
34
|
+
preco: preco,
|
|
35
|
+
description: description,
|
|
36
|
+
effects: effects
|
|
37
|
+
}.compact
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Tormenta20
|
|
6
|
+
module Models
|
|
7
|
+
# A Mobília (headquarters furniture) in Tormenta20.
|
|
8
|
+
#
|
|
9
|
+
# A catalog of furniture items that can be installed in a {Comodo} to grant an
|
|
10
|
+
# additional bonus. Some are restricted to a specific cômodo (+comodo_alvo+).
|
|
11
|
+
# Only catalog data lives here — see {BaseTipo}.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# Tormenta20.mobilias.find("bar")
|
|
15
|
+
class Mobilia < Base
|
|
16
|
+
self.table_name = "mobilias"
|
|
17
|
+
|
|
18
|
+
validates :id, presence: true, uniqueness: true
|
|
19
|
+
validates :name, presence: true
|
|
20
|
+
|
|
21
|
+
def to_h
|
|
22
|
+
{
|
|
23
|
+
id: id,
|
|
24
|
+
name: name,
|
|
25
|
+
description: description,
|
|
26
|
+
effects: effects || [],
|
|
27
|
+
preco: preco,
|
|
28
|
+
comodo_alvo: comodo_alvo
|
|
29
|
+
}.compact
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|