coop_al 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 940d2406792da127d6db1a622ff9fe6d7dfae655
|
4
|
+
data.tar.gz: 742e038d58588e7b58634201f6ae371f83fa2b47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 49ac99bf96894e7162ff25da3e4124511d4f2cce35d18131d610b674f8435327b9955bd13817326c2bd32885ac48ca44714df20960f61fd62669126648fbc4eb
|
7
|
+
data.tar.gz: fcb213c0563ecc6a93f03b9b4555650b4df458bf2a3ab8c51406f23a0ba20adc2095adb524798d06b3aa8363c56f9fa55dcd982da5b7042f392355b21cae40a9
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Coop - Adventurers League Character Log Generator
|
2
|
+
|
3
|
+
> "Reality is frequently inaccurate." -- Douglas Adams
|
4
|
+
|
5
|
+
Coop is a little tool that uses simple DSL-specified Dungeons and Dragons adventures to generate a log of pretend gameplay to support an Adventurers League character.
|
6
|
+
|
7
|
+
It includes SRD content, but nothing else. You'll have to supply your own copy of WoTC material.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
$> gem install coop_al
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
$> coop --help
|
16
|
+
coop [options] resource [resource...]
|
17
|
+
--path <path1>[,<path2>,...] Specify path to follow
|
18
|
+
--path-file <filename> Specify paths in a file, one per line
|
19
|
+
--no-loot Do not report loot
|
20
|
+
--no-xp Do not report accumulated XP
|
21
|
+
--no-paths Do not report available paths
|
22
|
+
--party-size n Total XP and treasure is divided by n [6]
|
23
|
+
--encounter-count n Encounters per session [10]
|
24
|
+
--end-date YYYY-MM-DD Most recent session [today]
|
25
|
+
--session-frequency n Sessions every n days [7]
|
26
|
+
--blackout-dates YYYY-MM-DD[,YYYY-MM-DD,...]
|
27
|
+
--skip-frequency n Chance of skipping week is 1 in n [never]
|
28
|
+
--srd Use included SRD file for monsters
|
29
|
+
--trace Print encounter details
|
30
|
+
--help Print this help
|
31
|
+
|
32
|
+
## Customization
|
33
|
+
|
34
|
+
Check out the examples provided.
|
35
|
+
|
36
|
+
### Bestiary
|
37
|
+
|
38
|
+
Create your own bestiary by providing a resource file in the form:
|
39
|
+
|
40
|
+
bestiary do
|
41
|
+
add :scary_monster, :cr1_2
|
42
|
+
add :scarier_monster, :cr17
|
43
|
+
end
|
44
|
+
|
45
|
+
### Adventures
|
46
|
+
|
47
|
+
Create your own adventures by providing a resource file in the form:
|
48
|
+
|
49
|
+
adventure :shortname, 'Adventure Name' do
|
50
|
+
entry :chapter_1
|
51
|
+
chapter :chapter_1, 'Chapter 1. Surrounding Area' do
|
52
|
+
5.times do
|
53
|
+
random 'Random Encounter' do
|
54
|
+
f(1..2) { monster :scary_monster }
|
55
|
+
f(3..20) { monsters '3d6', :scarier_monster }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
encounter 'Some old weak guy' do
|
59
|
+
npc :cr0
|
60
|
+
treasure 2000.gp + 400.pp
|
61
|
+
treasure 1000.gp, 'diamond'
|
62
|
+
item 'Vorpal sword'
|
63
|
+
end
|
64
|
+
encounter 'Bag of XP' do
|
65
|
+
xp 500
|
66
|
+
end
|
67
|
+
link_to :chapter_2
|
68
|
+
end
|
69
|
+
chapter :chapter_2, 'Chapter 2. The Caves' do
|
70
|
+
...
|
71
|
+
link_to_downtime
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
## Development
|
76
|
+
|
77
|
+
Coop is written in Ruby, and requires the [Tablescript gem](https://github.com/jamiehale/tablescript.rb).
|
78
|
+
|
79
|
+
### Tests
|
80
|
+
|
81
|
+
Such as they are...
|
82
|
+
|
83
|
+
$> rake spec
|
84
|
+
|
85
|
+
Coverage provided by simplecov.
|
86
|
+
|
87
|
+
### Rubocop
|
88
|
+
|
89
|
+
$> rake rubocop
|
data/Rakefile
ADDED
data/coop.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'coop_al/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'coop_al'
|
7
|
+
spec.version = CoopAl::VERSION
|
8
|
+
spec.authors = ['Jamie Hale']
|
9
|
+
spec.email = ['jamie@smallarmyofnerds.com']
|
10
|
+
spec.summary = 'Adventurers League Character Log Generator'
|
11
|
+
spec.description = 'Tool for automated character growth through predefined adventures'
|
12
|
+
spec.homepage = 'https://github.com/jamiehale/coop'
|
13
|
+
spec.license = 'GPL-3.0'
|
14
|
+
|
15
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
|
16
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = 'exe'
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
spec.add_dependency 'tablescript', '0.0.3'
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.14'
|
24
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.5'
|
26
|
+
spec.add_development_dependency 'cucumber', '~> 2.4'
|
27
|
+
spec.add_development_dependency 'simplecov', '~> 0.13'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.47'
|
29
|
+
end
|
data/examples/filler.rb
ADDED
data/examples/test.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
adventure :test, 'Simple Adventure' do
|
2
|
+
entry :chapter_1
|
3
|
+
chapter :chapter_1, 'Chapter 1' do
|
4
|
+
encounter '1. Entrance' do
|
5
|
+
monster :goblin
|
6
|
+
monsters 2, :orc
|
7
|
+
treasure '2d6*10'.gp
|
8
|
+
item 'Potion of healing'
|
9
|
+
end
|
10
|
+
link_to :chapter_2
|
11
|
+
link_to_downtime
|
12
|
+
end
|
13
|
+
chapter :chapter_2, 'Chapter 2' do
|
14
|
+
end
|
15
|
+
end
|
data/exe/coop
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tablescript'
|
4
|
+
require 'coop_al'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
def version
|
8
|
+
puts "Coop v#{CoopAl::VERSION} - \"Reality is frequently inaccurate.\""
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
def display_message(message)
|
13
|
+
puts
|
14
|
+
puts message
|
15
|
+
end
|
16
|
+
|
17
|
+
def usage(message = nil)
|
18
|
+
puts 'coop [options] resource [resource...]'
|
19
|
+
puts ' --path <path1>[,<path2>,...] Specify path to follow'
|
20
|
+
puts ' --path-file <filename> Specify paths in a file, one per line'
|
21
|
+
puts ' --no-loot Do not report loot'
|
22
|
+
puts ' --no-xp Do not report accumulated XP'
|
23
|
+
puts ' --no-paths Do not report available paths'
|
24
|
+
puts ' --party-size n Total XP and treasure is divided by n [6]'
|
25
|
+
puts ' --encounter-count n Encounters per session [10]'
|
26
|
+
puts ' --end-date YYYY-MM-DD Most recent session [today]'
|
27
|
+
puts ' --session-frequency n Sessions every n days [7]'
|
28
|
+
puts ' --blackout-dates YYYY-MM-DD[,YYYY-MM-DD,...]'
|
29
|
+
puts ' --skip-frequency n Chance of skipping week is 1 in n [never]'
|
30
|
+
puts ' --srd Use included SRD file for monsters'
|
31
|
+
puts ' --trace Print encounter details'
|
32
|
+
puts ' --help Print this help'
|
33
|
+
display_message(message) unless message.nil?
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
resource_files = []
|
38
|
+
paths = []
|
39
|
+
options = {
|
40
|
+
party_size: 6,
|
41
|
+
encounter_count: 10,
|
42
|
+
end_date: Date.today,
|
43
|
+
session_frequency: 7,
|
44
|
+
blackout_dates: []
|
45
|
+
}
|
46
|
+
until ARGV.empty?
|
47
|
+
parameter = ARGV.shift
|
48
|
+
case parameter
|
49
|
+
when '--help'
|
50
|
+
usage
|
51
|
+
when '--version'
|
52
|
+
version
|
53
|
+
when '--path'
|
54
|
+
usage unless paths.empty?
|
55
|
+
parameter = ARGV.shift
|
56
|
+
usage if parameter.nil?
|
57
|
+
paths = parameter.split(',').map { |p| CoopAl::Path.parse(p) }
|
58
|
+
when '--path-file'
|
59
|
+
usage unless paths.empty?
|
60
|
+
parameter = ARGV.shift
|
61
|
+
usage if parameter.nil?
|
62
|
+
File.open(parameter, 'r') do |f|
|
63
|
+
f.each_line do |line|
|
64
|
+
paths << CoopAl::Path.parse(line.strip)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
when '--no-loot'
|
68
|
+
options[:show_loot] = false
|
69
|
+
when '--no-xp'
|
70
|
+
options[:show_xp] = false
|
71
|
+
when '--no-paths'
|
72
|
+
options[:show_paths] = false
|
73
|
+
when '--party-size'
|
74
|
+
parameter = ARGV.shift
|
75
|
+
usage if parameter.nil?
|
76
|
+
options[:party_size] = parameter.to_i
|
77
|
+
when '--encounter-count'
|
78
|
+
parameter = ARGV.shift
|
79
|
+
usage if parameter.nil?
|
80
|
+
options[:encounter_count] = parameter.to_i
|
81
|
+
when '--end-date'
|
82
|
+
parameter = ARGV.shift
|
83
|
+
usage if parameter.nil?
|
84
|
+
options[:end_date] = Date.parse(parameter)
|
85
|
+
when '--session-frequency'
|
86
|
+
parameter = ARGV.shift
|
87
|
+
usage if parameter.nil?
|
88
|
+
options[:session_frequency] = parameter.to_i
|
89
|
+
when '--blackout-dates'
|
90
|
+
parameter = ARGV.shift
|
91
|
+
usage if parameter.nil?
|
92
|
+
options[:blackout_dates] = parameter.split(',').map { |d| Date.parse(d) }
|
93
|
+
when '--skip-frequency'
|
94
|
+
parameter = ARGV.shift
|
95
|
+
usage if parameter.nil?
|
96
|
+
options[:skip_frequency] = parameter.to_i
|
97
|
+
usage('Invalid skip frequency') if options[:skip_frequency] < 1
|
98
|
+
when '--srd'
|
99
|
+
resource_files << File.expand_path('../res/srd.rb', File.dirname(__FILE__))
|
100
|
+
when '--trace'
|
101
|
+
CoopAl::Trace.instance.tracing = true
|
102
|
+
else
|
103
|
+
resource_files << parameter
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
usage('No resources specified') if resource_files.empty?
|
108
|
+
begin
|
109
|
+
resource_files.each do |filename|
|
110
|
+
require filename
|
111
|
+
end
|
112
|
+
rescue StandardError => e
|
113
|
+
puts e
|
114
|
+
exit
|
115
|
+
end
|
116
|
+
|
117
|
+
date_generator = CoopAl::SessionDateGenerator.new(options)
|
118
|
+
log = CoopAl::SessionLog.new(date_generator, options)
|
119
|
+
|
120
|
+
state = CoopAl::State.new
|
121
|
+
follower = CoopAl::PathFollower.new(CoopAl::Library.instance, state)
|
122
|
+
begin
|
123
|
+
follower.follow(paths, log)
|
124
|
+
rescue StandardError => e
|
125
|
+
puts e
|
126
|
+
exit
|
127
|
+
end
|
128
|
+
|
129
|
+
CoopAl::StateReporter.new(state, CoopAl::Library.instance, options).report(STDOUT)
|
130
|
+
|
131
|
+
log.dump(STDOUT)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# Adventure
|
4
|
+
#
|
5
|
+
class Adventure
|
6
|
+
attr_reader :name, :description, :chapters
|
7
|
+
|
8
|
+
def initialize(name, description)
|
9
|
+
@name = name
|
10
|
+
@description = description
|
11
|
+
@entries = []
|
12
|
+
@chapters = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_entry(path)
|
16
|
+
@entries << path
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_chapter(chapter)
|
20
|
+
@chapters[chapter.name] = chapter
|
21
|
+
end
|
22
|
+
|
23
|
+
def all_chapter_names
|
24
|
+
@chapters.keys
|
25
|
+
end
|
26
|
+
|
27
|
+
def chapter_by_path(path)
|
28
|
+
@chapters[path.chapter]
|
29
|
+
end
|
30
|
+
|
31
|
+
def chapter_paths
|
32
|
+
@chapters.values.map(&:absolute_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def all_entries
|
36
|
+
@entries.map { |e| Path.absolute(@name, e) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def chapter?(name)
|
40
|
+
@chapters.key?(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def chapter(name)
|
44
|
+
raise "Chapter (#{name}) not found" unless @chapters.key?(name)
|
45
|
+
@chapters[name]
|
46
|
+
end
|
47
|
+
|
48
|
+
def full_name
|
49
|
+
@description
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# AdventureGenerator
|
4
|
+
#
|
5
|
+
class AdventureGenerator
|
6
|
+
attr_reader :adventure
|
7
|
+
|
8
|
+
def initialize(name, description, bestiary)
|
9
|
+
initialize_adventure(name, description)
|
10
|
+
@bestiary = bestiary
|
11
|
+
end
|
12
|
+
|
13
|
+
def entry(name)
|
14
|
+
@adventure.add_entry(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def chapter(name, description, &blk)
|
18
|
+
generator = ChapterGenerator.new(name, description, @adventure, @bestiary)
|
19
|
+
generator.instance_eval(&blk)
|
20
|
+
@adventure.add_chapter(generator.chapter)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def initialize_adventure(name, description)
|
26
|
+
if Library.instance.adventure?(name)
|
27
|
+
@adventure = Library.instance.adventure(name)
|
28
|
+
else
|
29
|
+
raise "Description required for adventure (#{name})" if description.nil?
|
30
|
+
@adventure = Adventure.new(name, description)
|
31
|
+
Library.instance.add_adventure(@adventure)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module CoopAl
|
4
|
+
##
|
5
|
+
# Bestiary
|
6
|
+
#
|
7
|
+
class Bestiary
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@monsters = {}
|
12
|
+
@xp_lookup = XpRewardTable.new
|
13
|
+
@loot_generator = LootGenerator.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def empty?
|
17
|
+
@monsters.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def add(monster)
|
21
|
+
@monsters[monster.id] = monster
|
22
|
+
end
|
23
|
+
|
24
|
+
def monster?(id)
|
25
|
+
@monsters.key?(id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def monster(id)
|
29
|
+
@monsters[id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def create(id, treasure, encounter)
|
33
|
+
raise "Invalid monster ID (#{id})" unless @monsters.key?(id)
|
34
|
+
monster = @monsters[id]
|
35
|
+
xp = calculate_xp(monster)
|
36
|
+
loot = generate_loot(monster, treasure)
|
37
|
+
Monster.new(id, xp, loot, encounter)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def calculate_xp(monster)
|
43
|
+
@xp_lookup[monster.cr]
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_loot(monster, treasure)
|
47
|
+
return @loot_generator.generate(monster.cr, monster.treasure) if treasure == :default
|
48
|
+
@loot_generator.generate(monster.cr, treasure)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# BestiaryPopulator
|
4
|
+
#
|
5
|
+
class BestiaryPopulator
|
6
|
+
def initialize(&blk)
|
7
|
+
instance_eval(&blk)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(id, cr, treasure = :individual)
|
11
|
+
Bestiary.instance.add(MonsterDefinition.new(id, cr, treasure))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# Chapter
|
4
|
+
#
|
5
|
+
class Chapter
|
6
|
+
attr_reader :name, :description, :encounters, :links
|
7
|
+
|
8
|
+
def initialize(name, description, adventure)
|
9
|
+
@name = name
|
10
|
+
@description = description
|
11
|
+
@adventure = adventure
|
12
|
+
@encounters = []
|
13
|
+
@links = []
|
14
|
+
@links_to_downtime = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def adventure_name
|
18
|
+
@adventure.description
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_encounter(encounter)
|
22
|
+
@encounters << encounter
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_link(path)
|
26
|
+
@links << path
|
27
|
+
end
|
28
|
+
|
29
|
+
def link_to_downtime
|
30
|
+
@links_to_downtime = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def links_to_downtime?
|
34
|
+
@links_to_downtime
|
35
|
+
end
|
36
|
+
|
37
|
+
def follow(state, log)
|
38
|
+
@encounters.each do |encounter|
|
39
|
+
encounter.run(state, log)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def absolute_path
|
44
|
+
Path.Absolute(@adventure.name, @name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def full_name
|
48
|
+
@adventure.full_name + ' - ' + @description
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module CoopAl
|
2
|
+
##
|
3
|
+
# ChapterGenerator
|
4
|
+
#
|
5
|
+
class ChapterGenerator
|
6
|
+
attr_reader :chapter
|
7
|
+
|
8
|
+
def initialize(name, description, adventure, bestiary)
|
9
|
+
@adventure = adventure
|
10
|
+
@chapter = Chapter.new(name, description, adventure)
|
11
|
+
@bestiary = bestiary
|
12
|
+
end
|
13
|
+
|
14
|
+
def encounter(name, &blk)
|
15
|
+
generator = EncounterGenerator.new(name, @chapter, @bestiary)
|
16
|
+
@chapter.add_encounter(generator.generate_encounter(&blk))
|
17
|
+
end
|
18
|
+
|
19
|
+
def random(name, &blk)
|
20
|
+
generator = RandomEncounterGenerator.new(name, @chapter, @bestiary)
|
21
|
+
@chapter.add_encounter(generator.generate_encounter(&blk))
|
22
|
+
end
|
23
|
+
|
24
|
+
def link_to(chapter)
|
25
|
+
@chapter.add_link(Path.absolute(@adventure.name, chapter))
|
26
|
+
end
|
27
|
+
|
28
|
+
def link_to_downtime
|
29
|
+
@chapter.link_to_downtime
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|