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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f992cf10c5edcaa924babaa9bee59310ae429d74
4
- data.tar.gz: f0a0fa06edd5e12fb568f0678418767778e6dc57
3
+ metadata.gz: 81432605b653b3616f9acc427638896697691231
4
+ data.tar.gz: 02a49e223b7c371b08c297457ccd37b08baafe09
5
5
  SHA512:
6
- metadata.gz: 6cf3569a96c494e17fb77d80fb440756f9576643a5b6c62714d0635a486db93b980f0d63dd72652d788f33c05a5aaf4bf2cab90a447900c883161bcc6dd6d19e
7
- data.tar.gz: 5df39fb670702c48932914959b0773876d2f274beed956896e700ecfb95e9e10fab66aaebc5e7cb54b776aa2f9549c8c0b887cc648b285d9143df6081cdbd5f9
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
@@ -1,2 +1,2 @@
1
1
  require_relative 'monsters/monsters_manual'
2
- require_relative 'encounters/lair'
2
+ require_relative 'encounters/encounters'
@@ -1,37 +1,23 @@
1
1
  class Encounter
2
2
 
3
- def initialize( party_xp_level )
4
- @monsters = []
5
- @party_xp_level = party_xp_level
3
+ def initialize( monster, amount )
4
+ @monster = monster
5
+ @amount = amount
6
+ # @party_xp_level = party_xp_level
6
7
  end
7
8
 
8
- # Return true or false. Monster added or not
9
- def add_monster_while_possible(monster )
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 to_s
23
- @monsters.group_by {|i| i.key}.map{ |_, v| "#{v.count} #{v.first.name}"}.join( ', ' )
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 encounter_value( encounter )
29
- raise "Encounter should not contain nil values : #{encounter.inspect}" if encounter.compact != encounter
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
@@ -55,6 +55,11 @@ class MonstersManual
55
55
  end
56
56
  end
57
57
 
58
+ # Retrieve a monster by its monster key
59
+ def get( monster_key )
60
+ @monsters[ monster_key ]
61
+ end
62
+
58
63
  def sources
59
64
  @sources.keys.sort
60
65
  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: 1.1.0
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/lair.rb
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
@@ -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
-