coop_al 1.0.1
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 +7 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +9 -0
- data/Gemfile +3 -0
- data/README.md +89 -0
- data/Rakefile +10 -0
- data/coop.gemspec +29 -0
- data/examples/filler.rb +9 -0
- data/examples/test.rb +15 -0
- data/exe/coop +131 -0
- data/lib/coop_al/adventure.rb +52 -0
- data/lib/coop_al/adventure_generator.rb +35 -0
- data/lib/coop_al/bestiary.rb +51 -0
- data/lib/coop_al/bestiary_generator.rb +3 -0
- data/lib/coop_al/bestiary_populator.rb +14 -0
- data/lib/coop_al/chapter.rb +51 -0
- data/lib/coop_al/chapter_generator.rb +32 -0
- data/lib/coop_al/encounter.rb +148 -0
- data/lib/coop_al/encounter_generator.rb +67 -0
- data/lib/coop_al/exception.rb +7 -0
- data/lib/coop_al/item.rb +30 -0
- data/lib/coop_al/library.rb +54 -0
- data/lib/coop_al/library_generator.rb +4 -0
- data/lib/coop_al/loot.rb +49 -0
- data/lib/coop_al/loot_generator.rb +42 -0
- data/lib/coop_al/monster.rb +19 -0
- data/lib/coop_al/monster_definition.rb +18 -0
- data/lib/coop_al/path.rb +65 -0
- data/lib/coop_al/path_follower.rb +34 -0
- data/lib/coop_al/random_encounter.rb +30 -0
- data/lib/coop_al/random_encounter_generator.rb +37 -0
- data/lib/coop_al/session.rb +55 -0
- data/lib/coop_al/session_date_generator.rb +43 -0
- data/lib/coop_al/session_encounter.rb +76 -0
- data/lib/coop_al/session_log.rb +51 -0
- data/lib/coop_al/state.rb +85 -0
- data/lib/coop_al/state_reporter.rb +72 -0
- data/lib/coop_al/trace.rb +29 -0
- data/lib/coop_al/treasure.rb +21 -0
- data/lib/coop_al/treasure_tables.rb +28 -0
- data/lib/coop_al/value.rb +167 -0
- data/lib/coop_al/version.rb +3 -0
- data/lib/coop_al/xp.rb +86 -0
- data/lib/coop_al.rb +34 -0
- data/res/srd.rb +400 -0
- metadata +188 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# SessionDateGenerator
|
4
|
+
#
|
5
|
+
class SessionDateGenerator
|
6
|
+
def initialize(options)
|
7
|
+
@next_date = options[:end_date]
|
8
|
+
@session_frequency = options[:session_frequency]
|
9
|
+
@skip_frequency = options[:skip_frequency]
|
10
|
+
@sessions = []
|
11
|
+
@blackout_dates = options[:blackout_dates]
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_session
|
15
|
+
@sessions.push(@next_date)
|
16
|
+
advance_next_date
|
17
|
+
end
|
18
|
+
|
19
|
+
def session(number)
|
20
|
+
@sessions[-number]
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def advance_next_date
|
26
|
+
loop do
|
27
|
+
@next_date -= @session_frequency
|
28
|
+
break if ok?(@next_date)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def ok?(date)
|
33
|
+
return false if @blackout_dates.include?(date)
|
34
|
+
return true if @skip_frequency.nil?
|
35
|
+
return false if roll_dice("d#{@skip_frequency}") == 1
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def blackout?(date)
|
40
|
+
@blackout_dates.include?(date)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# SessionEncounter
|
4
|
+
#
|
5
|
+
class SessionEncounter
|
6
|
+
attr_reader :xp, :treasure
|
7
|
+
def initialize(name, monsters, xp, treasure, items)
|
8
|
+
@name = name
|
9
|
+
@monster_counts = monster_counts(monsters)
|
10
|
+
@monsters = monsters.uniq.sort
|
11
|
+
@xp = xp
|
12
|
+
@treasure = treasure
|
13
|
+
@items = items
|
14
|
+
end
|
15
|
+
|
16
|
+
def counts?
|
17
|
+
@xp.nonzero?
|
18
|
+
end
|
19
|
+
|
20
|
+
def dump(s)
|
21
|
+
s.puts "Encounter: #{@name}"
|
22
|
+
s.puts " Monsters: #{monsters_s}"
|
23
|
+
s.puts " XP: #{@xp}"
|
24
|
+
s.puts " Treasure: #{@treasure}" unless @treasure.zero?
|
25
|
+
s.puts " Items: #{items_s}" unless @items.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def monster_counts(monsters)
|
31
|
+
results = {}
|
32
|
+
monsters.each do |m|
|
33
|
+
if results.key?(m)
|
34
|
+
results[m] += 1
|
35
|
+
else
|
36
|
+
results[m] = 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
results
|
40
|
+
end
|
41
|
+
|
42
|
+
def monsters_s
|
43
|
+
@monsters.map { |m| pluralize(m, @monster_counts[m]) }.join(', ')
|
44
|
+
end
|
45
|
+
|
46
|
+
def pluralize(monster, count)
|
47
|
+
return monster if count == 1
|
48
|
+
"#{monster} (#{count})"
|
49
|
+
end
|
50
|
+
|
51
|
+
def items_s
|
52
|
+
@items.map(&:to_s).join(', ')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Downtime
|
58
|
+
#
|
59
|
+
class Downtime
|
60
|
+
def xp
|
61
|
+
0
|
62
|
+
end
|
63
|
+
|
64
|
+
def treasure
|
65
|
+
Value.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def counts?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def dump(s)
|
73
|
+
s.puts 'Downtime'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# SessionLog
|
4
|
+
#
|
5
|
+
class SessionLog
|
6
|
+
def initialize(date_generator, options)
|
7
|
+
@date_generator = date_generator
|
8
|
+
@encounter_count = options.key?(:encounter_count) ? options[:encounter_count] : 10
|
9
|
+
@party_size = options.key?(:party_size) ? options[:party_size] : 6
|
10
|
+
@dm_name = options.key?(:dm_name) ? options[:dm_name] : 'Cameron'
|
11
|
+
@accumulated_xp = 0
|
12
|
+
@accumulated_treasure = Value.new
|
13
|
+
@sessions = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def record_encounter(adventure_name, encounter_name, monsters, xp, loot)
|
17
|
+
ensure_active_session(adventure_name)
|
18
|
+
@accumulated_xp += xp / @party_size
|
19
|
+
@accumulated_treasure += loot.treasure_value / @party_size
|
20
|
+
active_session.add_encounter(SessionEncounter.new(encounter_name, monsters, xp / @party_size, loot.treasure_value / @party_size, loot.items.dup))
|
21
|
+
end
|
22
|
+
|
23
|
+
def record_downtime(adventure_name)
|
24
|
+
ensure_active_session(adventure_name)
|
25
|
+
active_session.add_encounter(Downtime.new)
|
26
|
+
end
|
27
|
+
|
28
|
+
def dump(s)
|
29
|
+
@sessions.each { |e| e.dump(s) }
|
30
|
+
s.puts "Session Count: #{@sessions.size}"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def ensure_active_session(adventure_name)
|
36
|
+
start_new_session(adventure_name) if @sessions.empty? || active_session.done?
|
37
|
+
end
|
38
|
+
|
39
|
+
def active_session
|
40
|
+
@sessions.last
|
41
|
+
end
|
42
|
+
|
43
|
+
def start_new_session(adventure_name)
|
44
|
+
@sessions.push(Session.new(session_number, @date_generator, adventure_name, @dm_name, @accumulated_xp, @accumulated_treasure.dup, @encounter_count))
|
45
|
+
end
|
46
|
+
|
47
|
+
def session_number
|
48
|
+
@sessions.size + 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# State
|
4
|
+
#
|
5
|
+
class State
|
6
|
+
attr_reader :xp, :loot, :items
|
7
|
+
attr_accessor :current_path
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@path_stack = [Path.root]
|
11
|
+
@xp = 0
|
12
|
+
@loot = Loot.empty
|
13
|
+
@visited_paths = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_path
|
17
|
+
@path_stack.last
|
18
|
+
end
|
19
|
+
|
20
|
+
def path_depth
|
21
|
+
@path_stack.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def in_downtime?
|
25
|
+
current_path.root?
|
26
|
+
end
|
27
|
+
|
28
|
+
def available_paths(library)
|
29
|
+
all_available_paths(library).select { |p| !@visited_paths.include?(p) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_available_paths(library)
|
33
|
+
if path_depth == 1
|
34
|
+
if in_downtime?
|
35
|
+
library.all_entries
|
36
|
+
else
|
37
|
+
chapter = library.resolve(current_path)
|
38
|
+
chapter.links + downtime_if_available(chapter)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
chapter = library.resolve(@path_stack[0])
|
42
|
+
library.all_entries + chapter.links + downtime_if_available(chapter)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def downtime_if_available(chapter)
|
47
|
+
return [Path.root] if chapter.links_to_downtime? && !in_downtime?
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
|
51
|
+
def apply_path(path)
|
52
|
+
if path_depth == 1
|
53
|
+
if path.root?
|
54
|
+
@path_stack.push(path)
|
55
|
+
else
|
56
|
+
@path_stack = [current_path + path]
|
57
|
+
@visited_paths << current_path
|
58
|
+
end
|
59
|
+
else
|
60
|
+
@path_stack = [path]
|
61
|
+
@visited_paths << path
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_xp(xp)
|
66
|
+
@xp += xp
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_loot(loot)
|
70
|
+
@loot += loot
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_items(items)
|
74
|
+
@items.concat(items)
|
75
|
+
end
|
76
|
+
|
77
|
+
def treasure_value
|
78
|
+
@treasure.inject(Value.new) { |a, e| a + e.value }
|
79
|
+
end
|
80
|
+
|
81
|
+
def history_includes?(path)
|
82
|
+
@visited_paths.include?(path)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# StateReporter
|
4
|
+
#
|
5
|
+
class StateReporter
|
6
|
+
def initialize(state, library, options = {})
|
7
|
+
@state = state
|
8
|
+
@library = library
|
9
|
+
@party_size = options.key?(:party_size) ? options[:party_size] : 6
|
10
|
+
@show_xp = options.key?(:show_xp) ? options[:show_xp] : true
|
11
|
+
@show_loot = options.key?(:show_loot) ? options[:show_loot] : true
|
12
|
+
@show_paths = options.key?(:show_paths) ? options[:show_paths] : true
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(s)
|
16
|
+
report_xp(s) if @show_xp
|
17
|
+
report_loot(s) if @show_loot
|
18
|
+
report_paths(s) if @show_paths
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def report_xp(s)
|
24
|
+
s.puts "Character Level: #{character_level} (#{character_xp} XP - #{@state.xp} XP total)"
|
25
|
+
end
|
26
|
+
|
27
|
+
def character_xp
|
28
|
+
@state.xp / @party_size
|
29
|
+
end
|
30
|
+
|
31
|
+
def character_level
|
32
|
+
Coop::XpRequirementTable.new.level_from_xp(character_xp)
|
33
|
+
end
|
34
|
+
|
35
|
+
def report_loot(s)
|
36
|
+
report_treasure(s)
|
37
|
+
report_items(s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def report_treasure(s)
|
41
|
+
return if @state.loot.treasures.empty?
|
42
|
+
s.puts "Treasure: #{character_treasure} (#{@state.loot.treasure_value} total)"
|
43
|
+
end
|
44
|
+
|
45
|
+
def report_items(s)
|
46
|
+
items = @state.loot.items
|
47
|
+
return if items.empty?
|
48
|
+
s.puts 'Items:'
|
49
|
+
s.puts items.map { |item| " #{item.description_with_origin}" }
|
50
|
+
end
|
51
|
+
|
52
|
+
def character_treasure
|
53
|
+
@state.loot.treasure_value / @party_size
|
54
|
+
end
|
55
|
+
|
56
|
+
def report_paths(s)
|
57
|
+
s.puts 'Paths:'
|
58
|
+
if available_paths.empty?
|
59
|
+
s.puts ' None'
|
60
|
+
else
|
61
|
+
s.puts available_paths.map { |p| " #{p}" }.join("\n")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def available_paths
|
66
|
+
@state.available_paths(@library).map do |p|
|
67
|
+
return ['Downtime'] if p.root?
|
68
|
+
"#{@library.resolve(p).description} (#{p})"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module CoopAl
|
4
|
+
##
|
5
|
+
# Trace
|
6
|
+
#
|
7
|
+
class Trace
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
attr_writer :tracing, :stream
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@tracing = false
|
14
|
+
@stream = STDOUT
|
15
|
+
end
|
16
|
+
|
17
|
+
def info(s)
|
18
|
+
@stream.puts(s) if @tracing
|
19
|
+
end
|
20
|
+
|
21
|
+
def warn(s)
|
22
|
+
@stream.puts("[WARNING] #{s}") if @tracing
|
23
|
+
end
|
24
|
+
|
25
|
+
def error(s)
|
26
|
+
@stream.puts("[ERROR] #{s}") if @tracing
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# Treasure
|
4
|
+
#
|
5
|
+
class Treasure
|
6
|
+
attr_reader :value
|
7
|
+
|
8
|
+
def initialize(value, description = nil)
|
9
|
+
@value = value
|
10
|
+
@description = description
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
if @description.nil?
|
15
|
+
"coins (#{@value})"
|
16
|
+
else
|
17
|
+
"#{@description} (#{@value})"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
table :individual_treasure_cr_0_4 do
|
2
|
+
f(1..30) { '5d6'.cp }
|
3
|
+
f(31..60) { '4d6'.sp }
|
4
|
+
f(61..70) { '3d6'.ep }
|
5
|
+
f(71..95) { '3d6'.gp }
|
6
|
+
f(96..100) { '1d6'.pp }
|
7
|
+
end
|
8
|
+
|
9
|
+
table :individual_treasure_cr_5_10 do
|
10
|
+
f(1..30) { '4d6*100'.cp + '1d6*10'.ep }
|
11
|
+
f(31..60) { '6d6*10'.sp + '2d6*10'.gp }
|
12
|
+
f(61..70) { '3d6*10'.ep + '2d6*10'.gp }
|
13
|
+
f(71..95) { '4d6*10'.gp }
|
14
|
+
f(96..100) { '2d6*10'.gp + '3d6'.pp }
|
15
|
+
end
|
16
|
+
|
17
|
+
table :individual_treasure_cr_11_16 do
|
18
|
+
f(1..20) { '4d6*100'.sp + '1d6*100'.gp }
|
19
|
+
f(21..35) { '1d6*100'.ep + '1d6*100'.gp }
|
20
|
+
f(36..75) { '2d6*100'.gp + '1d6*10'.pp }
|
21
|
+
f(76..100) { '2d6*100'.gp + '2d6*10'.pp }
|
22
|
+
end
|
23
|
+
|
24
|
+
table :individual_treasure_cr_17_ do
|
25
|
+
f(1..15) { '2d6*1000'.ep + '8d6*100'.gp }
|
26
|
+
f(16..55) { '1d6*1000'.gp + '1d6*100'.pp }
|
27
|
+
f(56..100) { '1d6*1000'.gp + '2d6*100'.pp }
|
28
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# Value
|
4
|
+
#
|
5
|
+
class Value
|
6
|
+
attr_reader :platinum, :electrum, :gold, :silver, :copper
|
7
|
+
|
8
|
+
def initialize(amounts = {})
|
9
|
+
@platinum = amounts[:platinum] || 0
|
10
|
+
@electrum = amounts[:electrum] || 0
|
11
|
+
@gold = amounts[:gold] || 0
|
12
|
+
@silver = amounts[:silver] || 0
|
13
|
+
@copper = amounts[:copper] || 0
|
14
|
+
normalize
|
15
|
+
end
|
16
|
+
|
17
|
+
alias pp platinum
|
18
|
+
alias ep electrum
|
19
|
+
alias gp gold
|
20
|
+
alias sp silver
|
21
|
+
alias cp copper
|
22
|
+
|
23
|
+
def zero?
|
24
|
+
raw_value.zero?
|
25
|
+
end
|
26
|
+
|
27
|
+
def nonzero?
|
28
|
+
!zero?
|
29
|
+
end
|
30
|
+
|
31
|
+
def raw_value
|
32
|
+
@platinum * 10 + @gold + @silver / 10.0 + @copper / 100.0 + @electrum / 2.0
|
33
|
+
end
|
34
|
+
|
35
|
+
def normalize_from(value)
|
36
|
+
@platinum = 0
|
37
|
+
@electrum = 0
|
38
|
+
@gold = value.floor
|
39
|
+
value -= @gold
|
40
|
+
value *= 10
|
41
|
+
@silver = value.floor
|
42
|
+
value -= @silver
|
43
|
+
value *= 10
|
44
|
+
@copper = value.floor
|
45
|
+
end
|
46
|
+
|
47
|
+
def normalize
|
48
|
+
normalize_from(raw_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def +(other)
|
52
|
+
@platinum += other.pp
|
53
|
+
@electrum += other.ep
|
54
|
+
@gold += other.gp
|
55
|
+
@silver += other.sp
|
56
|
+
@copper += other.cp
|
57
|
+
normalize
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def *(other)
|
62
|
+
normalize_from(raw_value * other)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def /(other)
|
67
|
+
normalize_from(raw_value / other)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.platinum(amount)
|
72
|
+
Value.new(platinum: amount)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.gold(amount)
|
76
|
+
Value.new(gold: amount)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.silver(amount)
|
80
|
+
Value.new(silver: amount)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.copper(amount)
|
84
|
+
Value.new(copper: amount)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.electrum(amount)
|
88
|
+
Value.new(electrum: amount)
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_a
|
92
|
+
[@platinum, @electrum, @gold, @silver, @copper]
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
[
|
97
|
+
[@platinum, 'pp'],
|
98
|
+
[@gold, 'gp'],
|
99
|
+
[@silver, 'sp'],
|
100
|
+
[@copper, 'cp'],
|
101
|
+
[@electrum, 'ep']
|
102
|
+
].select { |v| v[0].nonzero? }.map { |v| "#{v[0]}#{v[1]}" }.join(', ')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Integer monkey-patch
|
109
|
+
#
|
110
|
+
class Integer
|
111
|
+
def platinum
|
112
|
+
Coop::Value.platinum(to_i)
|
113
|
+
end
|
114
|
+
|
115
|
+
def gold
|
116
|
+
Coop::Value.gold(to_i)
|
117
|
+
end
|
118
|
+
|
119
|
+
def silver
|
120
|
+
Coop::Value.silver(to_i)
|
121
|
+
end
|
122
|
+
|
123
|
+
def copper
|
124
|
+
Coop::Value.copper(to_i)
|
125
|
+
end
|
126
|
+
|
127
|
+
def electrum
|
128
|
+
Coop::Value.electrum(to_i)
|
129
|
+
end
|
130
|
+
|
131
|
+
alias gp gold
|
132
|
+
alias sp silver
|
133
|
+
alias cp copper
|
134
|
+
alias pp platinum
|
135
|
+
alias ep electrum
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# String monkey-patch
|
140
|
+
#
|
141
|
+
class String
|
142
|
+
def platinum
|
143
|
+
Coop::Value.platinum(roll_dice(self))
|
144
|
+
end
|
145
|
+
|
146
|
+
def gold
|
147
|
+
Coop::Value.gold(roll_dice(self))
|
148
|
+
end
|
149
|
+
|
150
|
+
def silver
|
151
|
+
Coop::Value.silver(roll_dice(self))
|
152
|
+
end
|
153
|
+
|
154
|
+
def copper
|
155
|
+
Coop::Value.copper(roll_dice(self))
|
156
|
+
end
|
157
|
+
|
158
|
+
def electrum
|
159
|
+
Coop::Value.electrum(roll_dice(self))
|
160
|
+
end
|
161
|
+
|
162
|
+
alias gp gold
|
163
|
+
alias sp silver
|
164
|
+
alias cp copper
|
165
|
+
alias pp platinum
|
166
|
+
alias ep electrum
|
167
|
+
end
|
data/lib/coop_al/xp.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# XpRewardTable
|
4
|
+
#
|
5
|
+
class XpRewardTable
|
6
|
+
def initialize
|
7
|
+
@xp_by_cr = {
|
8
|
+
cr0: 10,
|
9
|
+
cr1_8: 25,
|
10
|
+
cr1_4: 50,
|
11
|
+
cr1_2: 100,
|
12
|
+
cr1: 200,
|
13
|
+
cr2: 450,
|
14
|
+
cr3: 700,
|
15
|
+
cr4: 1_100,
|
16
|
+
cr5: 1_800,
|
17
|
+
cr6: 2_300,
|
18
|
+
cr7: 2_900,
|
19
|
+
cr8: 3_900,
|
20
|
+
cr9: 5_000,
|
21
|
+
cr10: 5_900,
|
22
|
+
cr11: 7_200,
|
23
|
+
cr12: 8_400,
|
24
|
+
cr13: 10_000,
|
25
|
+
cr14: 11_500,
|
26
|
+
cr15: 13_000,
|
27
|
+
cr16: 15_000,
|
28
|
+
cr17: 18_000,
|
29
|
+
cr18: 20_000,
|
30
|
+
cr19: 22_000,
|
31
|
+
cr20: 25_000,
|
32
|
+
cr21: 33_000,
|
33
|
+
cr22: 41_000,
|
34
|
+
cr23: 50_000,
|
35
|
+
cr24: 62_000,
|
36
|
+
cr25: 75_000,
|
37
|
+
cr26: 90_000,
|
38
|
+
cr27: 105_000,
|
39
|
+
cr28: 120_000,
|
40
|
+
cr29: 135_000,
|
41
|
+
cr30: 155_000
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def [](cr)
|
46
|
+
@xp_by_cr[cr]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# XpRequirementTable
|
52
|
+
#
|
53
|
+
class XpRequirementTable
|
54
|
+
def initialize
|
55
|
+
@xp_by_level = {
|
56
|
+
1 => 0,
|
57
|
+
2 => 300,
|
58
|
+
3 => 900,
|
59
|
+
4 => 2_700,
|
60
|
+
5 => 6_500,
|
61
|
+
6 => 14_000,
|
62
|
+
7 => 23_000,
|
63
|
+
8 => 34_000,
|
64
|
+
9 => 48_000,
|
65
|
+
10 => 64_000,
|
66
|
+
11 => 85_000,
|
67
|
+
12 => 100_000,
|
68
|
+
13 => 120_000,
|
69
|
+
14 => 140_000,
|
70
|
+
15 => 165_000,
|
71
|
+
16 => 195_000,
|
72
|
+
17 => 225_000,
|
73
|
+
18 => 265_000,
|
74
|
+
19 => 305_000,
|
75
|
+
20 => 355_000
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def level_from_xp(xp)
|
80
|
+
20.downto(1) do |i|
|
81
|
+
return i if xp >= @xp_by_level[i]
|
82
|
+
end
|
83
|
+
raise 'Invalid xp value (#{xp})'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/coop_al.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'tablescript'
|
2
|
+
require 'coop_al/treasure_tables'
|
3
|
+
require 'coop_al/trace'
|
4
|
+
require 'coop_al/version'
|
5
|
+
require 'coop_al/exception'
|
6
|
+
require 'coop_al/monster_definition'
|
7
|
+
require 'coop_al/loot_generator'
|
8
|
+
require 'coop_al/bestiary'
|
9
|
+
require 'coop_al/treasure'
|
10
|
+
require 'coop_al/value'
|
11
|
+
require 'coop_al/path'
|
12
|
+
require 'coop_al/state'
|
13
|
+
require 'coop_al/chapter'
|
14
|
+
require 'coop_al/monster'
|
15
|
+
require 'coop_al/item'
|
16
|
+
require 'coop_al/encounter'
|
17
|
+
require 'coop_al/random_encounter'
|
18
|
+
require 'coop_al/library_generator'
|
19
|
+
require 'coop_al/random_encounter_generator'
|
20
|
+
require 'coop_al/encounter_generator'
|
21
|
+
require 'coop_al/chapter_generator'
|
22
|
+
require 'coop_al/path_follower'
|
23
|
+
require 'coop_al/session_encounter'
|
24
|
+
require 'coop_al/session_date_generator'
|
25
|
+
require 'coop_al/session'
|
26
|
+
require 'coop_al/session_log'
|
27
|
+
require 'coop_al/xp'
|
28
|
+
require 'coop_al/adventure'
|
29
|
+
require 'coop_al/adventure_generator'
|
30
|
+
require 'coop_al/library'
|
31
|
+
require 'coop_al/loot'
|
32
|
+
require 'coop_al/state_reporter'
|
33
|
+
require 'coop_al/bestiary_populator'
|
34
|
+
require 'coop_al/bestiary_generator'
|