dd-next-encounters 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
-