dd-next-encounters 1.1.0 → 2.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/lib/data/by_xp_encounters.rb +98 -0
- data/lib/dd-next-encounters.rb +1 -1
- data/lib/encounters/encounter.rb +10 -24
- data/lib/encounters/encounters.rb +49 -0
- data/lib/monsters/monsters_manual.rb +5 -0
- metadata +3 -2
- data/lib/encounters/lair.rb +0 -89
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81432605b653b3616f9acc427638896697691231
|
4
|
+
data.tar.gz: 02a49e223b7c371b08c297457ccd37b08baafe09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bf840020f10799efa1f07609fc56ff85bba9117ec0b80209b80a0df7de683b05ea08ee5f3a9a03dff36a5a7d2d76d935b44b199556be2234f5a9b938a18ea4c
|
7
|
+
data.tar.gz: 82f17b66c9fc860e21798757acdfe18e24e0779b197fafb64f2347f9e2c0346ff6954a66100d05b68192ce3995cea548c8b32dc220a468a576af5008cdb747cd
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module ByXpEncounters
|
2
|
+
BY_XP_ENCOUNTERS =
|
3
|
+
{50=>
|
4
|
+
[{:amount=>1, :monster_key=>:skeleton}, {:amount=>1, :monster_key=>:goblin}],
|
5
|
+
150=>
|
6
|
+
[{:amount=>2, :monster_key=>:skeleton}, {:amount=>2, :monster_key=>:goblin}],
|
7
|
+
300=>
|
8
|
+
[{:amount=>3, :monster_key=>:skeleton},
|
9
|
+
{:amount=>2, :monster_key=>:shadow},
|
10
|
+
{:amount=>3, :monster_key=>:goblin},
|
11
|
+
{:amount=>2, :monster_key=>:hobgoblin},
|
12
|
+
{:amount=>2, :monster_key=>:orc}],
|
13
|
+
400=>
|
14
|
+
[{:amount=>4, :monster_key=>:skeleton}, {:amount=>4, :monster_key=>:goblin}],
|
15
|
+
500=>
|
16
|
+
[{:amount=>5, :monster_key=>:skeleton}, {:amount=>5, :monster_key=>:goblin}],
|
17
|
+
600=>
|
18
|
+
[{:amount=>6, :monster_key=>:skeleton},
|
19
|
+
{:amount=>2, :monster_key=>:ghoul},
|
20
|
+
{:amount=>3, :monster_key=>:shadow},
|
21
|
+
{:amount=>2, :monster_key=>:specter},
|
22
|
+
{:amount=>6, :monster_key=>:goblin},
|
23
|
+
{:amount=>3, :monster_key=>:hobgoblin},
|
24
|
+
{:amount=>2, :monster_key=>:bugbear},
|
25
|
+
{:amount=>3, :monster_key=>:orc}],
|
26
|
+
200=>
|
27
|
+
[{:amount=>1, :monster_key=>:ghoul},
|
28
|
+
{:amount=>1, :monster_key=>:specter},
|
29
|
+
{:amount=>1, :monster_key=>:bugbear}],
|
30
|
+
1200=>
|
31
|
+
[{:amount=>3, :monster_key=>:ghoul},
|
32
|
+
{:amount=>6, :monster_key=>:shadow},
|
33
|
+
{:amount=>3, :monster_key=>:specter},
|
34
|
+
{:amount=>6, :monster_key=>:hobgoblin},
|
35
|
+
{:amount=>3, :monster_key=>:bugbear},
|
36
|
+
{:amount=>6, :monster_key=>:orc}],
|
37
|
+
1600=>
|
38
|
+
[{:amount=>4, :monster_key=>:ghoul},
|
39
|
+
{:amount=>4, :monster_key=>:specter},
|
40
|
+
{:amount=>4, :monster_key=>:bugbear}],
|
41
|
+
2000=>
|
42
|
+
[{:amount=>5, :monster_key=>:ghoul},
|
43
|
+
{:amount=>5, :monster_key=>:specter},
|
44
|
+
{:amount=>5, :monster_key=>:bugbear}],
|
45
|
+
2400=>
|
46
|
+
[{:amount=>6, :monster_key=>:ghoul},
|
47
|
+
{:amount=>6, :monster_key=>:specter},
|
48
|
+
{:amount=>6, :monster_key=>:bugbear}],
|
49
|
+
100=>
|
50
|
+
[{:amount=>1, :monster_key=>:shadow},
|
51
|
+
{:amount=>1, :monster_key=>:hobgoblin},
|
52
|
+
{:amount=>1, :monster_key=>:orc}],
|
53
|
+
800=>
|
54
|
+
[{:amount=>4, :monster_key=>:shadow},
|
55
|
+
{:amount=>4, :monster_key=>:hobgoblin},
|
56
|
+
{:amount=>4, :monster_key=>:orc}],
|
57
|
+
1000=>
|
58
|
+
[{:amount=>5, :monster_key=>:shadow},
|
59
|
+
{:amount=>5, :monster_key=>:hobgoblin},
|
60
|
+
{:amount=>5, :monster_key=>:orc}],
|
61
|
+
450=>
|
62
|
+
[{:amount=>1, :monster_key=>:ghast},
|
63
|
+
{:amount=>1, :monster_key=>:minotaur_skeleton}],
|
64
|
+
1350=>
|
65
|
+
[{:amount=>2, :monster_key=>:ghast},
|
66
|
+
{:amount=>2, :monster_key=>:minotaur_skeleton}],
|
67
|
+
2700=>
|
68
|
+
[{:amount=>3, :monster_key=>:ghast},
|
69
|
+
{:amount=>3, :monster_key=>:minotaur_skeleton}],
|
70
|
+
3600=>
|
71
|
+
[{:amount=>4, :monster_key=>:ghast},
|
72
|
+
{:amount=>4, :monster_key=>:minotaur_skeleton}],
|
73
|
+
4500=>
|
74
|
+
[{:amount=>5, :monster_key=>:ghast},
|
75
|
+
{:amount=>5, :monster_key=>:minotaur_skeleton}],
|
76
|
+
5400=>
|
77
|
+
[{:amount=>6, :monster_key=>:ghast},
|
78
|
+
{:amount=>6, :monster_key=>:minotaur_skeleton},
|
79
|
+
{:amount=>2, :monster_key=>:vampire_spawn}],
|
80
|
+
700=>[{:amount=>1, :monster_key=>:mummy}],
|
81
|
+
2100=>[{:amount=>2, :monster_key=>:mummy}],
|
82
|
+
4200=>[{:amount=>3, :monster_key=>:mummy}],
|
83
|
+
13000=>
|
84
|
+
[{:amount=>1, :monster_key=>:mummy_lord},
|
85
|
+
{:amount=>1, :monster_key=>:vampire_spellcaster},
|
86
|
+
{:amount=>1, :monster_key=>:vampire_warrior}],
|
87
|
+
10000=>[{:amount=>1, :monster_key=>:vampire}],
|
88
|
+
30000=>[{:amount=>2, :monster_key=>:vampire}],
|
89
|
+
60000=>[{:amount=>3, :monster_key=>:vampire}],
|
90
|
+
1800=>[{:amount=>1, :monster_key=>:vampire_spawn}],
|
91
|
+
10800=>[{:amount=>3, :monster_key=>:vampire_spawn}],
|
92
|
+
39000=>
|
93
|
+
[{:amount=>2, :monster_key=>:vampire_spellcaster},
|
94
|
+
{:amount=>2, :monster_key=>:vampire_warrior}],
|
95
|
+
78000=>
|
96
|
+
[{:amount=>3, :monster_key=>:vampire_spellcaster},
|
97
|
+
{:amount=>3, :monster_key=>:vampire_warrior}]}
|
98
|
+
end
|
data/lib/dd-next-encounters.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require_relative 'monsters/monsters_manual'
|
2
|
-
require_relative 'encounters/
|
2
|
+
require_relative 'encounters/encounters'
|
data/lib/encounters/encounter.rb
CHANGED
@@ -1,37 +1,23 @@
|
|
1
1
|
class Encounter
|
2
2
|
|
3
|
-
def initialize(
|
4
|
-
@
|
5
|
-
@
|
3
|
+
def initialize( monster, amount )
|
4
|
+
@monster = monster
|
5
|
+
@amount = amount
|
6
|
+
# @party_xp_level = party_xp_level
|
6
7
|
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
raise "monster can't be nil : #{monster.inspect}" unless monster
|
11
|
-
if can_add_monster?( monster )
|
12
|
-
@monsters << monster
|
13
|
-
return true
|
14
|
-
end
|
15
|
-
false
|
16
|
-
end
|
17
|
-
|
18
|
-
def can_add_monster?( monster )
|
19
|
-
encounter_value( @monsters + [ monster ] ) <= @party_xp_level
|
9
|
+
def to_s
|
10
|
+
"#{@amount} #{@monster.name}"
|
20
11
|
end
|
21
12
|
|
22
|
-
def
|
23
|
-
@
|
13
|
+
def encounter_xp_value
|
14
|
+
1.upto(@amount).map{ @monster.xp_value }.reduce(&:+) * get_encounter_multiplier
|
24
15
|
end
|
25
16
|
|
26
17
|
private
|
27
18
|
|
28
|
-
def
|
29
|
-
|
30
|
-
encounter.map{ |e| e.xp_value }.reduce(&:+) * get_encounter_multiplier( encounter )
|
31
|
-
end
|
32
|
-
|
33
|
-
def get_encounter_multiplier( encounter )
|
34
|
-
count = encounter.count
|
19
|
+
def get_encounter_multiplier
|
20
|
+
count = @amount
|
35
21
|
mul = 1
|
36
22
|
mul = 1.5 if count >= 2
|
37
23
|
mul = 2 if count >= 3
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative '../data/by_xp_encounters'
|
2
|
+
require_relative '../data/xp_difficulty_table'
|
3
|
+
require_relative '../../lib/monsters/monsters_manual'
|
4
|
+
require_relative 'encounter'
|
5
|
+
|
6
|
+
class Encounters
|
7
|
+
|
8
|
+
include ByXpEncounters
|
9
|
+
include XpDifficultyTable
|
10
|
+
AVAILABLE_ENCOUNTER_LEVEL = REVERSED_XP_DIFFICULTY_TABLE.keys
|
11
|
+
@@by_xp_encounters = nil
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@monster_manual = MonstersManual.new
|
15
|
+
@monster_manual.load
|
16
|
+
@by_xp_encounters = {}
|
17
|
+
BY_XP_ENCOUNTERS.each do |k, v|
|
18
|
+
@by_xp_encounters[ k ] = v.map{ |e| Encounter.new( @monster_manual.get( e[:monster_key] ), e[:amount] ) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# encounter_level : :easy, :medium, :hard, :deadly
|
23
|
+
def get_party_encounter( encounter_level, *hero_level )
|
24
|
+
raise 'Empty party is not valid. Please provide at least one hero' if hero_level.empty?
|
25
|
+
|
26
|
+
raise "Bad encounter level : #{encounter_level.inspect}. Available encounter level : #{AVAILABLE_ENCOUNTER_LEVEL.inspect}" unless AVAILABLE_ENCOUNTER_LEVEL.include?( encounter_level )
|
27
|
+
raise 'Party too weak. Minimum 3 members' if hero_level.count < 3
|
28
|
+
|
29
|
+
hero_level.each do |level|
|
30
|
+
raise "Hero level should be an integer currently : #{level.class.to_s}" unless level.class == Integer
|
31
|
+
raise "Bad hero level : #{level}. Should be between 1 .. 20" if level < 1 || level > 20
|
32
|
+
end
|
33
|
+
|
34
|
+
party_xp_level = hero_level.map{ |hl| XP_DIFFICULTY_TABLE[hl][encounter_level] }.reduce(&:+)
|
35
|
+
|
36
|
+
get_encounter( party_xp_level*0.6, party_xp_level*1.2 )
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def get_encounter( min_xp, max_xp )
|
42
|
+
raise 'Encounters not loaded' unless @by_xp_encounters
|
43
|
+
encounters = @by_xp_encounters.map{ |k_value, encounters| encounters if k_value <= max_xp && k_value >= min_xp }
|
44
|
+
encounters = encounters.compact.flatten
|
45
|
+
# p encounters.map{ |e| e.to_s }
|
46
|
+
encounters.sample
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dd-next-encounters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cédric Zuger
|
@@ -31,11 +31,12 @@ extensions: []
|
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
33
|
- README.md
|
34
|
+
- lib/data/by_xp_encounters.rb
|
34
35
|
- lib/data/monsters_manual_content.rb
|
35
36
|
- lib/data/xp_difficulty_table.rb
|
36
37
|
- lib/dd-next-encounters.rb
|
37
38
|
- lib/encounters/encounter.rb
|
38
|
-
- lib/encounters/
|
39
|
+
- lib/encounters/encounters.rb
|
39
40
|
- lib/monsters/monster.rb
|
40
41
|
- lib/monsters/monsters_group.rb
|
41
42
|
- lib/monsters/monsters_manual.rb
|
data/lib/encounters/lair.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require_relative 'encounter'
|
2
|
-
require_relative '../data/xp_difficulty_table'
|
3
|
-
|
4
|
-
class Lair
|
5
|
-
|
6
|
-
include XpDifficultyTable
|
7
|
-
|
8
|
-
AVAILABLE_ENCOUNTER_LEVEL = REVERSED_XP_DIFFICULTY_TABLE.keys
|
9
|
-
|
10
|
-
def initialize( *encounters_types )
|
11
|
-
@monster_manual = MonstersManual.new
|
12
|
-
@monsters = nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def read_manuals
|
16
|
-
read_monster_manual
|
17
|
-
end
|
18
|
-
|
19
|
-
def print_summary
|
20
|
-
p @monster_manual.sources
|
21
|
-
puts
|
22
|
-
p @monster_manual.types
|
23
|
-
puts
|
24
|
-
end
|
25
|
-
|
26
|
-
def groups
|
27
|
-
@monster_manual.validate_loaded
|
28
|
-
@monster_manual.groups.keys
|
29
|
-
end
|
30
|
-
|
31
|
-
# encounter_level : :easy, :medium, :hard, :deadly
|
32
|
-
def get_encounter( encounter_level, *hero_level )
|
33
|
-
raise 'Empty party is not valid. Please provide at least one hero' if hero_level.empty?
|
34
|
-
@monster_manual.validate_loaded
|
35
|
-
|
36
|
-
raise "Bad encounter level : #{encounter_level.inspect}. Available encounter level : #{AVAILABLE_ENCOUNTER_LEVEL.inspect}" unless AVAILABLE_ENCOUNTER_LEVEL.include?( encounter_level )
|
37
|
-
raise 'Party too weak. Minimum 3 members' if hero_level.count < 3
|
38
|
-
|
39
|
-
hero_level.each do |level|
|
40
|
-
raise "Hero level should be an integer currently : #{level.class.to_s}" unless level.class == Integer
|
41
|
-
raise "Bad hero level : #{level}. Should be between 1 .. 20" if level < 1 || level > 20
|
42
|
-
end
|
43
|
-
|
44
|
-
party_xp_level = hero_level.map{ |hl| XP_DIFFICULTY_TABLE[hl][encounter_level] }.reduce(&:+)
|
45
|
-
one_sixth_party_xp_level = party_xp_level / 6
|
46
|
-
|
47
|
-
candidate_monsters = @monster_manual.select( sources: [ 'Basic Rules', 'Monster Manual' ], types: %w( Undead Fiend Giant Humanoid ) )
|
48
|
-
candidate_monsters = candidate_monsters.reject{ |m| m.xp_value > party_xp_level || m.xp_value < one_sixth_party_xp_level }
|
49
|
-
|
50
|
-
choosed_monster = candidate_monsters.sample
|
51
|
-
monsters_amount = ( party_xp_level / choosed_monster.xp_value ).floor
|
52
|
-
|
53
|
-
encounter = Encounter.new( party_xp_level )
|
54
|
-
1.upto(monsters_amount).each do
|
55
|
-
# p encounter
|
56
|
-
break unless encounter.add_monster_while_possible( choosed_monster )
|
57
|
-
end
|
58
|
-
|
59
|
-
encounter
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def read_monster_manual
|
65
|
-
@monster_manual.load
|
66
|
-
# validate_encounters_types
|
67
|
-
|
68
|
-
@monsters = @monster_manual.select( sources: [ 'Basic Rules', 'Monster Manual' ] )
|
69
|
-
|
70
|
-
# @encounters_types.each do |encounter_type|
|
71
|
-
# @encounters[encounter_type] ||= { troops: [], bosses: [] }
|
72
|
-
# @encounters[encounter_type][:troops] = @monster_manual.groups[encounter_type]&.troops
|
73
|
-
# @encounters[encounter_type][:bosses] = @monster_manual.groups[encounter_type]&.bosses
|
74
|
-
# end
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
# def validate_encounters_types
|
80
|
-
# @encounters_types.each do |encounter_type|
|
81
|
-
# unless @monster_manual.groups.include?( encounter_type )
|
82
|
-
# raise "Bad lair type : #{encounter_type.inspect}" + ". Available lairs types : #{@monster_manual.groups.keys}"
|
83
|
-
# end
|
84
|
-
# end
|
85
|
-
# @encounters_types = @monster_manual.groups.keys if @encounters_types.empty?
|
86
|
-
# end
|
87
|
-
|
88
|
-
end
|
89
|
-
|