astromapper 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ module Astromapper
2
+ module Builder
3
+ class Sector < Astromapper::Builder::Base
4
+ def constitute
5
+ @volumes = []
6
+ 40.times do |r|
7
+ 32.times do |c|
8
+ next unless has_system?
9
+ v = Volume.new(c+1,r+1)
10
+ @volumes << v unless v.empty?
11
+ end
12
+ end
13
+ self
14
+ end
15
+ def has_system?
16
+ case
17
+ when config['density'] == 'extra_galactic' then (1.d100 <= 1)
18
+ when config['density'] == 'rift' then (1.d100 <= 3)
19
+ when config['density'] == 'sparse' then (1.d100 <= 17)
20
+ when config['density'] == 'scattered' then (1.d100 <= 33)
21
+ when config['density'] == 'dense' then (1.d100 <= 66)
22
+ when config['density'] == 'cluster' then (1.d100 <= 83)
23
+ when config['density'] == 'core' then (1.d100 <= 91)
24
+ else (d100 <= 50) # Standard
25
+ end
26
+ end
27
+ def to_file
28
+ file = Astromapper.output_file('sector')
29
+ File.open(file,'w').write(@volumes.map{|v| v.to_ascii}.join("\n"))
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,198 @@
1
+ module Astromapper
2
+ module Builder
3
+ class Star < Astromapper::Builder::Base
4
+ attr_accessor :star_size, :mass, :bode_constant, :biozone, :type_dm, :size_dm, :orbits, :primary, :orbit, :id, :volume, :world, :companions
5
+ # @@stars = {}
6
+ STAR_CHART = {
7
+ #type => 0)example, 1)temp, 2)lux, 3)mass, 4)radius
8
+ 'B0' => ['Becrux', 30000, 16000, 16.0, 5.70],
9
+ 'B2' => ['Spica', 22000, 8300, 10.5, 5.10],
10
+ 'B5' => ['Achernar', 15000, 750, 5.40, 3.70],
11
+ 'B8' => ['Rigel', 12500, 130, 3.50, 2.70],
12
+ 'A0' => ['Sirius A', 9500, 63, 2.60, 2.30],
13
+ 'A2' => ['Fomalhaut', 9000, 40, 2.20, 2.00],
14
+ 'A5' => ['Altair', 8700, 24, 1.90, 1.80],
15
+ 'F0' => ['Gamma Virginis', 7400, 9.0, 1.60, 1.50],
16
+ 'F2' => ['.', 7100, 6.3, 1.50, 1.30],
17
+ 'F5' => ['Procyon A', 6400, 4.0, 1.35, 1.20],
18
+ 'G0' => ['Alpha Centauri A', 5900, 1.45, 1.08, 1.05],
19
+ 'G2' => ['The Sun', 5800, 1.00, 1.00, 1.00],
20
+ 'G5' => ['Mu Cassiopeiae', 5600, 0.70, 0.95, 0.91],
21
+ 'G8' => ['Tau Ceti', 5300, 0.44, 0.85, 0.87],
22
+ 'K0' => ['Pollux', 5100, 0.36, 0.83, 0.83],
23
+ 'K2' => ['Epsilon Eridani', 4830, 0.28, 0.78, 0.79],
24
+ 'K5' => ['Alpha Centauri B', 4370, 0.18, 0.68, 0.74],
25
+ 'M0' => ['Gliese 185', 3670, 0.075, 0.47, 0.63],
26
+ 'M2' => ['Lalande 21185', 3400, 0.03, 0.33, 0.36],
27
+ 'M4' => ['Ross 128', 3200, 0.0005, 0.20, 0.21],
28
+ 'M6' => ['Wolf 359', 3000, 0.0002, 0.10, 0.12]
29
+ }
30
+ INNER_LIMIT = {
31
+ 'O' => [ 16, 13, 10 ],
32
+ 'B' => [ 10, 6.3, 5.0, 4.0, 3.8, 0.6, 0],
33
+ 'A' => [ 4, 1, 0.4, 0, 0, 0, 0],
34
+ 'F' => [ 4, 1, 0.3, 0.1, 0, 0, 0],
35
+ 'G' => [ 3.1, 1, 0.3, 0.1, 0, 0, 0],
36
+ 'K' => [ 2.5, 1, 0.3, 0.1, 0, 0, 0],
37
+ 'M' => [ 2, 1, 0.3, 0.1, 0, 0, 0],
38
+ 'D' => [ 0 ],
39
+ }
40
+ BIOZONE = {
41
+ 'O' => [ [790,1190], [630,950], [500,750] ],
42
+ 'B' => [ [500,700], [320,480], [250,375], [200,300], [180,270], [30,45] ],
43
+ 'A' => [ [200,300], [50,75], [20,30], [5.0,7.5], [4.0,6.0], [3.1,4.7] ],
44
+ 'F' => [ [200,300], [50,75], [13,19], [2.5,3.7], [2.0,3.0], [1.6,2.4], [0.5,0.8] ],
45
+ 'G' => [ [200,300], [50,75], [13,19], [2.5,3.7], [2.0,3.0], [1.6,2.4], [0.5,0.8] ],
46
+ 'K' => [ [125,190], [50,75], [13,19], [4.0,5.9], [1.0,1.5], [0.5,0.6], [0.2,0.3] ],
47
+ 'M' => [ [100,150], [50,76], [16,24], [5.0,7.5], [0,0], [0.1,0.2], [0.1,0.1] ],
48
+ 'D' => [ [0.03, 0.03] ],
49
+ }
50
+ SPECTRAL = {
51
+ 'O' => [9],
52
+ 'B' => [0,2,5,8],
53
+ 'A' => [0,2,5],
54
+ 'F' => [0,2,5],
55
+ 'G' => [0,2,5,8],
56
+ 'K' => [0,2,5],
57
+ 'M' => [0,2,4,6]
58
+ }
59
+ MASS = {
60
+ 'O' => [70, 60, 0, 0, 50, 0 ],
61
+ 'B' => [50, 40, 35, 30, 20, 10],
62
+ 'A' => [30, 16, 10, 6, 4, 3],
63
+ 'F' => [15, 13, 8, 2.5, 2.2, 1.9],
64
+ 'G' => [12, 10, 6, 2.7, 1.8, 1.1, 0.8],
65
+ 'K' => [15, 12, 6, 3, 2.3, 0.9, 0.5],
66
+ 'M' => [20, 16, 8, 4, 0.3, 0.2],
67
+ 'D' => [0.8,0.8,0.8,0.8,0.8,0.8,]
68
+ }
69
+ COMPANION_SEPARATION = [[0.05]*2, [0.5]*3, [2.0]*2, [10.0]*3, [50.0] * 10].flatten
70
+ BODE_RATIO = [[0.3] * 4, [0.35] * 3, [0.4] * 4].flatten
71
+ def initialize(volume, primary=nil,ternary=0)
72
+ @volume = volume
73
+ @primary = primary
74
+ @orbits = []
75
+ @companions = []
76
+ @world = nil
77
+
78
+ @type_dm = 0
79
+ @size_dm = 0
80
+ @has_gg = false
81
+
82
+ if primary.nil?
83
+ @orbit = 0
84
+ @type_dm = (toss(2,0) + @volume.star_dm ).max(12)
85
+ @size_dm = (toss(2,0) + 0 ).max(12)
86
+ @star_type = %w{B B A M M M M M K G F F F}[@type_dm]
87
+ @star_size = %w{0 1 2 3 4 5 5 5 5 5 5 6 500}[@size_dm].to_i
88
+ else
89
+ separation = (toss(2,0) * COMPANION_SEPARATION[toss(3) + (4 * ternary) - 2]).round(2) # Gurps Space 4e p.105
90
+
91
+ @orbit = au_to_orbit(separation) - 1
92
+ @star_type = %w{X B A F F G G K K M M M M}[(toss(2,0) + primary.type_dm).max(12)]
93
+ @star_size = %w{0 1 2 3 4 500 500 5 5 6 500 500 500 500}[(toss(2,0) + primary.size_dm).max(12)].to_i
94
+ end
95
+ @spectral = @star_type + SPECTRAL[@star_type].sample.to_s
96
+ @star_size ||= 500
97
+
98
+ @bode_constant = (@star_type=='M' and @star_size==5) ? 0.2 : BODE_RATIO[toss]
99
+
100
+ if @star_size == 500
101
+ @star_subtype = (true) ? 'B' : @star_type
102
+ @star_type = 'D'
103
+ end
104
+
105
+ dm = 0
106
+ dm += 4 if @star_size == 3
107
+ dm += 8 if @star_size < 3
108
+ dm -= 4 if @star_type == 'M'
109
+ dm -= 2 if @star_type == 'K'
110
+
111
+ # Populate Orbits
112
+ (toss(2,0) + dm).whole.times do |i|
113
+ @orbits << Orbit.new(self,i).populate unless orbit_to_au(i) > outer_limit
114
+ @world = @orbits.last if @orbits.last.is_a?(World)
115
+ end
116
+ @world.gas_giant = (@orbits.map{|o| o.kid}.include?('G')) ? 'G' : '.' unless @world.nil?
117
+ prune!
118
+ end
119
+ def prune! # Ensure last orbits are not empty.
120
+ @orbits.each_index { |x| @orbits[x] = Orbit.new(self,x) if @orbits[x].nil?}
121
+ c = @orbits
122
+ # exit
123
+ tk = false
124
+ @orbits = @orbits.sort{|b,a| a.orbit_number <=> b.orbit_number}.map {|o| tk = true unless (o.kid == '.' or tk); o if tk }.reverse.compact
125
+ # @orbits.each_index { |x| @orbits[x] = Orbit.new(self,x) if @orbits[x].nil?}
126
+
127
+ return if @orbits.size < 2
128
+ @orbits.length.times do |i|
129
+ @orbits[i].orbit_number = i
130
+ @orbits[i].au = self.orbit_to_au(i)
131
+ end
132
+
133
+ end
134
+ def orbit_to_au(o)
135
+ inner_limit + (self.bode_constant * (2 ** o)).round(1)
136
+ end
137
+ def au_to_orbit(au)
138
+ constant = (@primary.nil?) ? @bode_constant : @primary.bode_constant
139
+ (Math.log(au / constant) / Math.log(2) ).round(2).abs - inner_limit
140
+ end
141
+ def companions=(star)
142
+ orbit = star.orbit.abs
143
+ companion = Companion.new(self, orbit, star)
144
+
145
+ # Gurps Space 4e p.107 - Clear Forbidden orbits
146
+ inner = au_to_orbit(companion.au * 0.67).floor
147
+ outer = au_to_orbit(companion.au * 3).ceil
148
+ @forbidden = (inner .. outer)
149
+ @forbidden.each { |x| @orbits[x] = nil }
150
+ @orbits[orbit - 1] = companion
151
+ @companions << star
152
+ prune!
153
+ end
154
+ def to_s; kid; end
155
+ def kid; 'C'; end
156
+ def radius; (155000 * Math.sqrt(luminosity)) ** 2; end # Gurps Space 4e p. 104
157
+ def snow_line; 4.85 * Math.sqrt(luminosity); end # Gurps Space 4e p. 106
158
+ def outer_limit; 40 * mass; end # Gurps Space 4e p. 107
159
+ def orbits_to_ascii
160
+ return '' if @orbits.empty?
161
+ "\n" + @orbits.map{|o| o.to_ascii}.join("\n") + "\n"
162
+ end
163
+ def crib
164
+ stars = [classification]
165
+ @companions.each { |s| stars << s.classification }
166
+ "%-17s %-16s" % [stars.join('/'), @orbits.map{|o| o.kid}.join('')]
167
+ end
168
+ def to_ascii
169
+ classification
170
+ end
171
+ def classification
172
+ return @star_type + @star_subtype if (@star_type == 'D')
173
+ "#{@spectral}#{@star_size.roman}"
174
+ end
175
+ def world?
176
+ return @orbits.join('').include?('W')
177
+ return false
178
+ end
179
+ def column; @volume.column; end
180
+ def row; @volume.row; end
181
+ def sector; @volume.sector; end
182
+ def location; @volume.location; end
183
+ def type; @star_type; end
184
+ def type=(s); @star_type = s; end
185
+ def size; @star_size; end
186
+ def size=(s); @star_size = s; end
187
+ def inner_limit; limit; end
188
+ def limit
189
+ return 0 if @star_size.nil?
190
+ INNER_LIMIT[@star_type][@star_size % 10]
191
+ end
192
+ def biozone; BIOZONE[@star_type][@star_size % 10] or []; end
193
+ def luminosity; STAR_CHART[@spectral][2]; end
194
+ def temperature; @temperature = STAR_CHART[@spectral][1].around(20) if @temperature.nil?; end
195
+ def mass; MASS[@star_type][@star_size] || 0.3; end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,38 @@
1
+ module Astromapper
2
+ module Builder
3
+ class Volume < Astromapper::Builder::Base
4
+
5
+ attr_accessor :gas_giant, :name
6
+
7
+ def initialize(c,r)
8
+ @name = (config['named']) ? Astromapper.names.sample : "%02d%02d" % [c,r]
9
+ @column = c
10
+ @row = r
11
+ @star = Star.new(self)
12
+ [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2][toss(2,0)].times do |i|
13
+ @star.companions = Star.new(self, @star,i)
14
+ end
15
+ end
16
+
17
+ def star_dm
18
+ return 0 if @atmo.nil? or @popx.nil?
19
+ ((4..9).include?(@atmo) or @popx > 7) ? 4 : 0
20
+ end
21
+
22
+ def to_ascii
23
+ w = @star.world
24
+ sumy = "%s %s %s %s %s\t%-15s\t%-8s\t%s\t%s" % [location, w.uwp, w.temp, w.bases, w.travel_code, w.trade_codes.join(','), w.factions.join(','), @star.crib, @name]
25
+ sumy += @star.orbits_to_ascii
26
+ return sumy
27
+ end
28
+
29
+ def empty?
30
+ return true if @star.world.nil? or @star.world.empty? or !@star.world?
31
+ end
32
+
33
+ def location
34
+ "%02d%02d" % [@column,@row]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'thor'
3
+ require 'Astromapper/version'
4
+ module Astromapper
5
+ class Cli < Thor
6
+ FORMATS = %w[pdf draft proof html epub mobi txt]
7
+ check_unknown_options!
8
+
9
+ def self.exit_on_failure?
10
+ true
11
+ end
12
+ def initialize(args = [], options = {}, config = {})
13
+ # if (config[:current_task] || config[:current_command]).name == "new" && args.empty?
14
+ # raise Error, "The e-Book path is required. For details run: Astromapper help new"
15
+ # end
16
+ super
17
+ end
18
+
19
+ desc "new", "Create Astromapper Directory"
20
+ map %w(-n new -c) => :create
21
+ def create(path)
22
+ say "Voices of billions cry out in terror at the creation of '#{path}'"
23
+ generator = Generator.new
24
+ generator.destination_root = path.squish.gsub(' ','-')
25
+ generator.invoke_all
26
+ end
27
+
28
+ desc "build", "Generate a map of {sector / domain}"
29
+ map %w{-b --build generate} => :build
30
+ def build(type='sector')
31
+ say "Building #{type}: #{config['name'].inspect}"
32
+ Astromapper::Exporter.run(root_dir, options)
33
+ end
34
+
35
+ desc "svg", "Convert ASCII output to SVG"
36
+ map %w{-s --svg} => :svg
37
+ def svg
38
+ source = Astromapper.output_file('sector')
39
+ say "Converting #{source} to SVG"
40
+ s = Svg.new(source)
41
+ s.convert
42
+ say "SVG available at #{Astromapper.output_file('svg')}"
43
+ end
44
+
45
+ desc "version", "Prints the Astromapper's version information"
46
+ map %w(-v --version) => :version
47
+ def version
48
+ say "Astromapper version #{Astromapper::VERSION}"
49
+ end
50
+
51
+ private
52
+ def config
53
+ # YAML.load_file(config_path).with_indifferent_access
54
+ Astromapper.config
55
+ end
56
+ def root_dir
57
+ @root ||= Pathname.new(Dir.pwd)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,64 @@
1
+ module Astromapper
2
+ class Exporter
3
+ def self.run(root_dir, options)
4
+ exporter = new(root_dir, options)
5
+ exporter.export!
6
+ end
7
+
8
+ attr_accessor :root_dir
9
+ attr_accessor :options
10
+
11
+ def initialize(root_dir, options)
12
+ @root_dir = root_dir
13
+ @options = options
14
+ end
15
+
16
+ def ui
17
+ @ui ||= Thor::Base.shell.new
18
+ end
19
+
20
+ def export!
21
+ helper = root_dir.join("config/helper.rb")
22
+ load(helper) if helper.exist?
23
+ exported = []
24
+
25
+ sector = Builder::Sector.constitute(root_dir)
26
+
27
+ sector.to_file
28
+
29
+ # export_pdf = [nil, "pdf"].include?(options[:only])
30
+ # export_html = [nil, "html", "mobi", "epub"].include?(options[:only])
31
+ # export_epub = [nil, "mobi", "epub"].include?(options[:only])
32
+ # export_mobi = [nil, "mobi"].include?(options[:only])
33
+ # export_txt = [nil, "txt"].include?(options[:only])
34
+
35
+ # exported = []
36
+ # exported << Parser::PDF.parse(root_dir) if export_pdf && Dependency.xelatex?# && Dependency.prince?
37
+ # exported << Parser::HTML.parse(root_dir) if export_html
38
+ # epub_done = Parser::Epub.parse(root_dir) if export_epub
39
+ # exported << epub_done
40
+ # exported << Parser::Mobi.parse(root_dir) if export_mobi && epub_done && Dependency.kindlegen?
41
+ # exported << Parser::Txt.parse(root_dir) if export_txt && Dependency.html2text?
42
+
43
+ if exported.all?
44
+ color = :green
45
+ message = options[:auto] ? "exported!" : "** Map has been exported"
46
+
47
+ # Notifier.notify(
48
+ # # :image => Astromapper::ROOT.join("templates/ebook.png"),
49
+ # :title => "Astromapper",
50
+ # :message => "Your \"#{config[:title]}\" map has been exported!"
51
+ # )
52
+ else
53
+ color = :red
54
+ message = options[:auto] ? "could not be exported!" : "** e-book couldn't be exported"
55
+ end
56
+
57
+ ui.say message, color
58
+ end
59
+
60
+ def config
61
+ Astromapper.config(root_dir)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ class Array
2
+ def roll(n=1)
3
+ n.times.map{ self.rotate!; self.first }.inject{|s,x| s + x}
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Float
2
+ def tweak
3
+ self.round(2)
4
+ end
5
+ end
@@ -0,0 +1,44 @@
1
+ class Integer
2
+ def dn(n)
3
+ (1..self).inject(0) { |a, e| a + rand(n) + 1 }
4
+ end
5
+ def d3
6
+ dn(3)
7
+ end
8
+ def d6
9
+ dn(6)
10
+ end
11
+ def d100
12
+ dn(100)
13
+ end
14
+ def hexd
15
+ return 'F' if self > 15
16
+ self.whole.to_s(16).upcase
17
+ end
18
+ def whole
19
+ return 0 if self < 0
20
+ return self
21
+ end
22
+ def natural
23
+ return 1 if self < 1
24
+ return self
25
+ end
26
+ def roman
27
+ return 'D' if self ==500
28
+ return %w{Ia Ib II III IV V VI VII VIII IX X}[self]
29
+ end
30
+ def max(n)
31
+ return n if self > n
32
+ return self
33
+ end
34
+ def min(n)
35
+ return n if self < n
36
+ return self
37
+ end
38
+ def tweak
39
+ return self
40
+ end
41
+ def to_string
42
+ return self.tweak
43
+ end
44
+ end