astromapper 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +124 -0
- data/Rakefile +1 -0
- data/astromapper.gemspec +29 -0
- data/bin/astromapper +5 -0
- data/lib/astromapper.rb +54 -0
- data/lib/astromapper/builder.rb +43 -0
- data/lib/astromapper/builder/orbit.rb +370 -0
- data/lib/astromapper/builder/sector.rb +33 -0
- data/lib/astromapper/builder/star.rb +198 -0
- data/lib/astromapper/builder/volume.rb +38 -0
- data/lib/astromapper/cli.rb +60 -0
- data/lib/astromapper/exporter.rb +64 -0
- data/lib/astromapper/extensions/array.rb +5 -0
- data/lib/astromapper/extensions/float.rb +5 -0
- data/lib/astromapper/extensions/integer.rb +44 -0
- data/lib/astromapper/extensions/string.rb +11 -0
- data/lib/astromapper/generator.rb +31 -0
- data/lib/astromapper/svg.rb +303 -0
- data/lib/astromapper/version.rb +3 -0
- data/templates/config.erb +79 -0
- data/templates/names.yml +2050 -0
- metadata +183 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Merovex
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
Traveller Astromapper
|
2
|
+
==========================
|
3
|
+
|
4
|
+
The **Traveller Astromapper** creates random Traveller star maps intended for YOTS.
|
5
|
+
|
6
|
+
The maps are generated using an inspired amalgam of [Mongoose](http://www.mongoosepublishing.com/rpgs/traveller/core-rulebooks-accessories.html) and [Classic Traveller](http://www.farfuture.net/) rules, with some [Gurps Space](http://www.sjgames.com/gurps/books/space/) 4e and 3e.
|
7
|
+
|
8
|
+
Mongoose rules are used when generating the World characteristics. Classic Traveller is used when fleshing out star system details such as stars, non-world orbits, presence of companion stars. Gurps is used to flesh out star characteristics and the impact of a companion star on the primary's orbits.
|
9
|
+
|
10
|
+
* Sector: 40x32 hex grid
|
11
|
+
* Tract: 8x10 hex grid (Traveller Subsector)
|
12
|
+
* Volume: 1-hex
|
13
|
+
* World: primary inhabited planet.
|
14
|
+
* Orbit: A slot around primary star, may include companion stars, planets, belts or nothing.
|
15
|
+
|
16
|
+
Installation
|
17
|
+
============
|
18
|
+
|
19
|
+
This software relies upon Ruby 1.9.2+.
|
20
|
+
|
21
|
+
To convert from SVG to JPG, PNG, GIF you will need to install Imagemagick with -rsvg flag (later feature).
|
22
|
+
|
23
|
+
How to Use Traveller Astromapper
|
24
|
+
======================
|
25
|
+
|
26
|
+
To create a new Traveller Astromapper project, execute the following on the command line:
|
27
|
+
|
28
|
+
```
|
29
|
+
astromapper new yots_sector
|
30
|
+
```
|
31
|
+
|
32
|
+
The command creates the following directory structure:
|
33
|
+
|
34
|
+
```
|
35
|
+
yots_sector
|
36
|
+
├── _astromapper.yml
|
37
|
+
├── output
|
38
|
+
└── templates
|
39
|
+
└── names.yml
|
40
|
+
```
|
41
|
+
|
42
|
+
ASCII Output
|
43
|
+
------------
|
44
|
+
|
45
|
+
The block below shows Traveller Astromapper's ASCII output. The top row is the key system aspects: Volume ID, World UWP, Temperature, Presence of Bases & Gas Giants, Trade Codes, Stars, Primary Star's Orbits, Name. The rows that follow elaborate the primary star's orbits. Rows with two dashes are the Primary's orbits, orbit type, UWP, and orbit distance (usable for travel and year length). Other rows with the '/' are that orbit's satellites. When the UWP is dots, that orbit is empty.
|
46
|
+
|
47
|
+
```
|
48
|
+
1201 E949556-5 T ..G.. .. Lt,NI F0IV/DB R..WGG..S Secundus
|
49
|
+
-- 1. R // X600000-0 // 0.4 au
|
50
|
+
/ 7 rad. X420000
|
51
|
+
/ 9 rad. X620000
|
52
|
+
-- 2. . // .......-. // 0.7 au
|
53
|
+
-- 3. . // .......-. // 1.4 au
|
54
|
+
-- 4. * W // E949556-5 // 2.8 au
|
55
|
+
-- 5. G // Large GG // 5.6 au
|
56
|
+
-- 6. G // Large GG // 11.2 au
|
57
|
+
/ 1 rad. XR00000
|
58
|
+
/ 6 rad. X402000
|
59
|
+
/ 7 rad. X405000
|
60
|
+
/ 9 rad. X100000
|
61
|
+
/ 10 rad. X302000
|
62
|
+
-- 7. . // .......-. // 22.4 au
|
63
|
+
-- 8. . // .......-. // 44.8 au
|
64
|
+
-- 9. - S // DB // 89.6 au
|
65
|
+
```
|
66
|
+
|
67
|
+
To generate a (mostly) random Traveller sector in the ASCII format, execute the following on the command line:
|
68
|
+
|
69
|
+
```
|
70
|
+
astromapper generate
|
71
|
+
```
|
72
|
+
|
73
|
+
SVG Output
|
74
|
+
----------
|
75
|
+
|
76
|
+
Traveller Astromapper converts the ASCII output as described above to create an SVG file describing the key aspects of a volume. This includes the Star type, Starport, Name and the presence of bases (Navy, Scout, etc.) and Gas Giants.
|
77
|
+
|
78
|
+
To convert that ASCII into an SVG image, execut the following:
|
79
|
+
|
80
|
+
```
|
81
|
+
astrographer svg
|
82
|
+
```
|
83
|
+
|
84
|
+
Copyright
|
85
|
+
=========
|
86
|
+
|
87
|
+
Copyright 2012--13, Benjamin C. Wilson. All Rights Reserved.
|
88
|
+
|
89
|
+
You may not use this work for commercial purposes. You may not alter, transform or build upon this work. Any of the above conditions can be waived if you get permission from the copyright holder. Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license. For any reuse or distribution, you must make clear to others the license terms of this work. In no way are any of the following rights affected by the license:
|
90
|
+
|
91
|
+
* Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
|
92
|
+
* The author's moral rights;
|
93
|
+
* Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
|
94
|
+
|
95
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
96
|
+
|
97
|
+
Product names, logos, brands, and other trademarks featured or referred to in software are the property of their respective trademark holders. Usage of those marks does not convey sponsorship or endorsement of this generator.
|
98
|
+
|
99
|
+
Credits
|
100
|
+
=======
|
101
|
+
|
102
|
+
SVG Output uses some algorithms from [phreeow.net Perl mapping software](http://www.phreeow.net/wiki/tiki-index.php?page=Subsector+mapping+and+generating+software) with drawing hexes in the Classic Traveller way.
|
103
|
+
|
104
|
+
Known bugs
|
105
|
+
===========
|
106
|
+
* If the dice pool is too small, the generated output will repeat.
|
107
|
+
|
108
|
+
Troubleshooting
|
109
|
+
===============
|
110
|
+
|
111
|
+
Changelog
|
112
|
+
=========
|
113
|
+
|
114
|
+
Version 0.1 (1 March 2012)
|
115
|
+
--------------------------
|
116
|
+
* Initially written
|
117
|
+
* Generate Sector Map
|
118
|
+
* Convert to SVG
|
119
|
+
|
120
|
+
Version 1.0 (7 April 2013)
|
121
|
+
--------------------------
|
122
|
+
* Re-implemented as Ruby Gem
|
123
|
+
|
124
|
+
* A News sections might also be include to lists project updates for users.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/astromapper.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'astromapper/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "astromapper"
|
9
|
+
s.version = Astromapper::VERSION
|
10
|
+
s.authors = ["Merovex"]
|
11
|
+
s.email = ["dausha@gmail.com"]
|
12
|
+
s.description = %q{Astromapper generates Traveller RPG Star Charts (from Sector to Domain).}
|
13
|
+
s.summary = %q{Generating Traveller RPG Star Charts for YOTS}
|
14
|
+
s.homepage = ""
|
15
|
+
s.license = "MIT"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "rspec", "~> 2.6"
|
25
|
+
s.add_development_dependency "cucumber"
|
26
|
+
s.add_development_dependency "aruba"
|
27
|
+
s.add_dependency "activesupport"
|
28
|
+
s.add_dependency "thor"
|
29
|
+
end
|
data/bin/astromapper
ADDED
data/lib/astromapper.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
# require "awesome_print"
|
3
|
+
require "active_support/all"
|
4
|
+
# require "notifier"
|
5
|
+
require "pathname"
|
6
|
+
require "thor"
|
7
|
+
require "thor/group"
|
8
|
+
require "yaml"
|
9
|
+
|
10
|
+
module Astromapper
|
11
|
+
require 'astromapper/extensions/float'
|
12
|
+
require 'astromapper/extensions/integer'
|
13
|
+
require 'astromapper/extensions/string'
|
14
|
+
|
15
|
+
autoload :Builder, "astromapper/builder"
|
16
|
+
autoload :Cli, "astromapper/cli"
|
17
|
+
# autoload :Dependency, "astromapper/dependency"
|
18
|
+
autoload :Exporter, "astromapper/exporter"
|
19
|
+
autoload :Generator, "astromapper/generator"
|
20
|
+
# autoload :Stats, "astromapper/stats"
|
21
|
+
# autoload :Stream, "astromapper/stream"
|
22
|
+
# autoload :TOC, "astromapper/toc"
|
23
|
+
autoload :Svg, "astromapper/svg"
|
24
|
+
autoload :Version, "astromapper/version"
|
25
|
+
|
26
|
+
Encoding.default_internal = "utf-8"
|
27
|
+
Encoding.default_external = "utf-8"
|
28
|
+
def self.config(root_dir = nil)
|
29
|
+
root_dir ||= Pathname.new(Dir.pwd)
|
30
|
+
path = root_dir.join("_astromapper.yml")
|
31
|
+
|
32
|
+
raise "Invalid Bookmaker directory; couldn't found #{path} file." unless File.file?(path)
|
33
|
+
content = File.read(path)
|
34
|
+
erb = ERB.new(content).result
|
35
|
+
|
36
|
+
YAML.load(erb)#.with_indifferent_access
|
37
|
+
end
|
38
|
+
def self.output_file(ext="txt")
|
39
|
+
"output/#{config['name'].to_permalink}.#{ext}"
|
40
|
+
end
|
41
|
+
def self.names(root_dir = nil)
|
42
|
+
root_dir ||= Pathname.new(Dir.pwd)
|
43
|
+
path = root_dir.join("templates/names.yml")
|
44
|
+
|
45
|
+
raise "Invalid Bookmaker directory; couldn't found #{path} file." unless File.file?(path)
|
46
|
+
content = File.read(path)
|
47
|
+
erb = ERB.new(content).result
|
48
|
+
|
49
|
+
@names = YAML.load(erb)#.with_indifferent_access
|
50
|
+
end
|
51
|
+
def self.logger
|
52
|
+
@logger ||= Logger.new(File.open("/tmp/astromapper.log", "a"))
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Astromapper
|
4
|
+
module Builder
|
5
|
+
autoload :Orbit, "astromapper/builder/orbit"
|
6
|
+
autoload :Sector, "astromapper/builder/sector"
|
7
|
+
autoload :Star, "astromapper/builder/star"
|
8
|
+
autoload :Volume, "astromapper/builder/volume"
|
9
|
+
|
10
|
+
class Base
|
11
|
+
attr_accessor :root_dir
|
12
|
+
|
13
|
+
def self.constitute(root_dir)
|
14
|
+
new(root_dir).constitute
|
15
|
+
end
|
16
|
+
def initialize(root_dir)
|
17
|
+
@root_dir = Pathname.new(root_dir)
|
18
|
+
end
|
19
|
+
|
20
|
+
def config
|
21
|
+
Astromapper.config(root_dir)
|
22
|
+
end
|
23
|
+
def toss(a=2,b=2)
|
24
|
+
(a.d6 - b).whole
|
25
|
+
# (@@dice.roll(a) - b).whole
|
26
|
+
end
|
27
|
+
def names
|
28
|
+
Astromapper.names
|
29
|
+
end
|
30
|
+
|
31
|
+
def spawn_command(cmd)
|
32
|
+
begin
|
33
|
+
stdout_and_stderr, status = Open3.capture2e(*cmd)
|
34
|
+
rescue Errno::ENOENT => e
|
35
|
+
puts e.message
|
36
|
+
else
|
37
|
+
puts stdout_and_stderr unless status.success?
|
38
|
+
status.success?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,370 @@
|
|
1
|
+
module Astromapper
|
2
|
+
module Builder
|
3
|
+
|
4
|
+
# Class Orbit
|
5
|
+
class Orbit < Astromapper::Builder::Base
|
6
|
+
attr_accessor :id, :kid, :au, :port, :orbit_number, :xsize
|
7
|
+
def initialize(star,orbit_number,companion=nil)
|
8
|
+
@orbit_number = orbit_number.round
|
9
|
+
@au = star.orbit_to_au(orbit_number)
|
10
|
+
@kid = '.'
|
11
|
+
@star = star
|
12
|
+
@atmo = 0
|
13
|
+
@moons = 0
|
14
|
+
@h20 = 0
|
15
|
+
@popx = 0
|
16
|
+
@tek = 0
|
17
|
+
@port = 'X'
|
18
|
+
@govm = 0
|
19
|
+
@law = 0
|
20
|
+
@xsize = '.'
|
21
|
+
begin
|
22
|
+
@zone = case
|
23
|
+
when @au < @star.biozone[0] then -1 # Inside
|
24
|
+
when @au > @star.biozone[1] then 1 # Outside
|
25
|
+
else 0
|
26
|
+
end
|
27
|
+
@distant = (@au > @star.biozone[1] * 10)
|
28
|
+
rescue
|
29
|
+
# There is no biozone, so all is "inside"
|
30
|
+
@zone = -1
|
31
|
+
@distant = 1000
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def uwp
|
35
|
+
'.......-.' # "%s%s%s%s%s%s%s-%s" % [port, @size.hexd, @atmo.hexd, @h20.hexd, @popx.hexd, @govm.hexd, @law.hexd, @tek.hexd]
|
36
|
+
end
|
37
|
+
def port
|
38
|
+
@port || 'X'
|
39
|
+
end
|
40
|
+
def populate
|
41
|
+
case
|
42
|
+
when @au > @star.outer_limit then return self
|
43
|
+
when limit? then return self
|
44
|
+
when inner? then populate_inner
|
45
|
+
when outer? then populate_outer
|
46
|
+
else populate_biozone
|
47
|
+
end
|
48
|
+
end
|
49
|
+
def populate_biozone
|
50
|
+
return World.new(@star, @orbit_number)
|
51
|
+
roll = toss(2,0)
|
52
|
+
return (roll < 12) ? World.new(@star, @orbit_number) : GasGiant.new(@star, @orbit_number)
|
53
|
+
end
|
54
|
+
def populate_inner
|
55
|
+
roll = toss(2,0)
|
56
|
+
return case
|
57
|
+
when roll < 5 then self
|
58
|
+
when (5..6) === roll then Hostile.new(@star, @orbit_number)
|
59
|
+
when (7..9) === roll then Rockball.new(@star, @orbit_number)
|
60
|
+
when (10..11) === roll then Belt.new(@star, @orbit_number)
|
61
|
+
else GasGiant.new(@star, @orbit_number)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
def populate_outer
|
65
|
+
roll = toss(1,0)
|
66
|
+
roll += 1 if distant?
|
67
|
+
return case
|
68
|
+
when roll == 1 then Rockball.new(@star, @orbit_number)
|
69
|
+
when roll == 2 then Belt.new(@star, @orbit_number)
|
70
|
+
when roll == 3 then self
|
71
|
+
when (4..7) === roll then GasGiant.new(@star, @orbit_number)
|
72
|
+
else Rockball.new(@star, @orbit_number)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def to_s
|
76
|
+
@kid
|
77
|
+
end
|
78
|
+
def to_ascii
|
79
|
+
bio = (@zone == 0 ) ? '*' : ' '
|
80
|
+
bio = '-' if @au > @star.outer_limit
|
81
|
+
output = " -- %2s. %s %s // %s // %4.1f au" % [@orbit_number + 1, bio, @kid, self.uwp, @au]
|
82
|
+
@moons.each {|m| output += m.to_ascii} unless @moons.nil? or @moons == 0
|
83
|
+
output
|
84
|
+
|
85
|
+
end
|
86
|
+
def period; (@au * 365.25).round(2); end
|
87
|
+
def km; return (150000000 * @au).to_i; end
|
88
|
+
def radii; (@au * 200).to_i; end
|
89
|
+
def limit?; return @au < @star.limit ; end
|
90
|
+
def inner?; return @zone < 0; end
|
91
|
+
def outer?; return @zone > 0; end
|
92
|
+
def biozone?; return @zone == 0; end
|
93
|
+
def distant?; @distant; end
|
94
|
+
end # End Orbit
|
95
|
+
|
96
|
+
class Companion<Orbit
|
97
|
+
def initialize(star,orbit_number,companion)
|
98
|
+
@star = star
|
99
|
+
@comp = companion
|
100
|
+
super
|
101
|
+
@kid = 'S'
|
102
|
+
end
|
103
|
+
def uwp
|
104
|
+
"%-9s" % [@comp.classification]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
class Belt<Orbit
|
108
|
+
def initialize(star,orbit_number)
|
109
|
+
super
|
110
|
+
@kid = 'B'
|
111
|
+
end
|
112
|
+
def uwp
|
113
|
+
'XR00000-0'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
class Planet<Orbit
|
119
|
+
def initialize(star,orbit_number)
|
120
|
+
super
|
121
|
+
@moons = make_moons(toss(1,3))
|
122
|
+
@size = toss if @size.nil? or @size == 0
|
123
|
+
end
|
124
|
+
def make_moons(c)
|
125
|
+
moons = {}
|
126
|
+
c.times { |i|
|
127
|
+
m = Moon.new(self,i)
|
128
|
+
moons["#{m.orbit}"] = m
|
129
|
+
}
|
130
|
+
moons.values.sort{ |a,b| a.orbit <=> b.orbit } unless @moons.size < 2
|
131
|
+
end
|
132
|
+
def uwp
|
133
|
+
"%s%s%s%s%s%s%s-%s" % [port, @size.hexd, @atmo.hexd, @h20.hexd, @popx.hexd, @govm.hexd, @law.hexd, @tek.hexd]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Rockball<Planet
|
138
|
+
def initialize(star,orbit_number)
|
139
|
+
super
|
140
|
+
@kid = 'R'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Hostile<Planet
|
145
|
+
def initialize(star,orbit_number)
|
146
|
+
super
|
147
|
+
@atmo = [10,11,12,13,14].sample
|
148
|
+
@hydro = toss(2,4)
|
149
|
+
@kid = 'H'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class GasGiant<Planet
|
154
|
+
def initialize(star,orbit_number)
|
155
|
+
super
|
156
|
+
@xsize = (toss(1,0) < 4) ? 'L' : 'S'
|
157
|
+
moons = toss(2,0)
|
158
|
+
moons = (moons - 4).whole if @xsize == 'S'
|
159
|
+
@moons = make_moons(moons)
|
160
|
+
@kid = 'G'
|
161
|
+
end
|
162
|
+
def uwp
|
163
|
+
(@xsize == 'S') ? 'Small GG ' : 'Large GG '
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Terrestrial<Planet
|
168
|
+
def initialize(star,orbit_number)
|
169
|
+
super
|
170
|
+
@kid = 'R'
|
171
|
+
|
172
|
+
# Size, Climate & Biosphere. MgT 170--71.
|
173
|
+
@size = toss(2,1)
|
174
|
+
@atmo = toss()
|
175
|
+
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
|
176
|
+
temp_dice = toss(2,0) + [0, 0,-2,-2,-1,-1, 0, 0, 1, 1, 2, 6, 6, 2,-1, 2][@atmo]
|
177
|
+
|
178
|
+
@temp = %w{F F F C C T T T T T H H R R R R R }[temp_dice]
|
179
|
+
|
180
|
+
# Hydrographics. MgT p. 172
|
181
|
+
@h20 = case
|
182
|
+
when (@size < 2 or !biozone?) then 0
|
183
|
+
when ([0,1,10,11,12].include?(@atmo)) then (toss(2,11) + @size).max(10)
|
184
|
+
else @h20 = (toss(2,7) + @size).max(10)
|
185
|
+
end
|
186
|
+
@h20 -= 2 if @temp == 'H'
|
187
|
+
@h20 -= 6 if @temp == 'R'
|
188
|
+
@h20 = @h20.whole
|
189
|
+
|
190
|
+
# Adjust Atmosphere and Hydrographics when not Normal. MgT p. 180.
|
191
|
+
if (%{opera firm}.include?(config['genre'].downcase))
|
192
|
+
@atmo = case
|
193
|
+
when (@size < 3 or (@size < 4 and @atmo < 3)) then 0
|
194
|
+
when ([3,4].include?(@size) and (3..5).include?(@atmo)) then 1
|
195
|
+
when ([3,4].include?(@size) and @atmo > 5) then 10
|
196
|
+
else @atmo
|
197
|
+
end
|
198
|
+
@h20 -= 6 if (((3..4).include?(@size) and @atmo == 'A' ) or @atmo < 2)
|
199
|
+
@h20 -= 4 if ([2,3,11,12].include?(@atmo))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end # End Terrestrial
|
203
|
+
|
204
|
+
#===============
|
205
|
+
# Big Dea
|
206
|
+
#
|
207
|
+
#
|
208
|
+
#
|
209
|
+
#
|
210
|
+
#
|
211
|
+
#
|
212
|
+
#
|
213
|
+
#
|
214
|
+
|
215
|
+
class World<Terrestrial
|
216
|
+
attr_accessor :factions, :temp, :gas_giant
|
217
|
+
def initialize(star,orbit_number)
|
218
|
+
super
|
219
|
+
|
220
|
+
@port_roll = toss(2,0)
|
221
|
+
|
222
|
+
@kid = 'W'
|
223
|
+
@popx = toss()
|
224
|
+
if ('firm' == config['genre'].downcase)
|
225
|
+
@popx -= 1 if (@size < 3 or @size > 9)
|
226
|
+
@popx += [-1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1][@atmo]
|
227
|
+
@port_roll = (@port_roll - 7 + @popx.whole).whole
|
228
|
+
end
|
229
|
+
@popx = @popx.whole
|
230
|
+
|
231
|
+
# Government & Law. MgT p. 173
|
232
|
+
@govm = (toss(2,7) + @popx).whole
|
233
|
+
@law = (toss(2,7) + @govm).whole
|
234
|
+
|
235
|
+
# Identify Factions. MgT p. 173
|
236
|
+
fax_r = 1.d3.max(3)
|
237
|
+
fax_r += 1 if [0,7].include?(@law)
|
238
|
+
fax_r -= 1 if @law > 9
|
239
|
+
rolls = [toss(2,0),toss(2,0),toss(2,0),toss(2,0),toss(2,0)]
|
240
|
+
@factions = (@popx == 0) ? [] : fax_r.times.map { |r| %w{O O O O F F M M N N S S P}[rolls.shift] }
|
241
|
+
|
242
|
+
# Set Technology die modifier based on World attributes. MgT p. 170
|
243
|
+
tek_dm = { 'A' => 6, 'B' => 4, 'C' => 2, 'D' => 0, 'E' => 0, 'X' => -4}[port]
|
244
|
+
tek_dm += [2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0][@size]
|
245
|
+
tek_dm += [1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1][@atmo]
|
246
|
+
tek_dm += [1,0,0,0,0,0,0,0,0,1,2][@h20]
|
247
|
+
tek_dm += [0,1,1,1,1,1,0,0,0,1,2,3,4][@popx]
|
248
|
+
tek_dm += [1,0,0,0,0,1,0,2,0,0,0,0,0,-2,-2,0][@govm]
|
249
|
+
tek_limit = environmental_tek_limits[@atmo]
|
250
|
+
@tek = (toss(1,0) + tek_dm).min( tek_limit ) # MgT p. 179 Environmental Limits
|
251
|
+
|
252
|
+
# For those who want to limit technology
|
253
|
+
@tek = @tek.max(config['tech_cap']) unless config['tech_cap'].nil?
|
254
|
+
@tek = @tek.min(tek_limit)
|
255
|
+
@tek = @tek.min(@popx)
|
256
|
+
@law = @govm = @tek = 0 if @popx == 0
|
257
|
+
|
258
|
+
# Fix temperature (Me)
|
259
|
+
@temp = 'F' if (trade_codes.include?('IC') or trade_codes.include?('Va'))
|
260
|
+
@temp = 'T' if ((trade_codes.include?('Ag') or trade_codes.include?('Ga') or trade_codes.include?('Ri') or trade_codes.include?('Wa')) and @temp != 'T')
|
261
|
+
|
262
|
+
base = {
|
263
|
+
"Navy" => { 'A' => 8, 'B' => 8, 'C' => 20, 'D' => 20, 'E' => 20, 'X' => 20 }[port],
|
264
|
+
"Scout" => { 'A' => 10, 'B' => 8, 'C' => 8, 'D' => 7, 'E' => 20, 'X' => 20 }[port],
|
265
|
+
"Consolate" => { 'A' => 6, 'B' => 8, 'C' => 10, 'D' => 20, 'E' => 20, 'X' => 20 }[port],
|
266
|
+
"Pirate" => { 'A' => 20, 'B' => 12, 'C' => 10, 'D' => 12, 'E' => 20, 'X' => 20 }[port]
|
267
|
+
}
|
268
|
+
|
269
|
+
@base = {}
|
270
|
+
base.keys.each {|key| @base[key] = (2.d6 > base[key] - 1) ? key[0] : '.'}
|
271
|
+
end
|
272
|
+
def travel_code
|
273
|
+
@code = (@atmo > 9 or [0,7,10].include?(@govm) or [0,9,10,11,12,13].include?(@law)) ? 'AZ' : '..'
|
274
|
+
end
|
275
|
+
def gravity
|
276
|
+
@gravity = [0,0.05,0.15,0.25,0.35,0.45,0.7,0.9,1.0,1.25,1.4][@size] if @gravity.nil?
|
277
|
+
@gravity
|
278
|
+
end
|
279
|
+
def bases
|
280
|
+
return [@base['Navy'],@base['Scout'],@gas_giant,@base['Consolate'],@base['Pirate']].join('')
|
281
|
+
end
|
282
|
+
def port
|
283
|
+
%w{X X X E E D D C C B B A A A A A A A A A}[@port_roll.whole]
|
284
|
+
end
|
285
|
+
def environmental_tek_limits
|
286
|
+
[8,8,5,5,3,0,0,3,0,8,9,10,5,8]
|
287
|
+
end
|
288
|
+
def empty?
|
289
|
+
(uwp.include?('X000000'))
|
290
|
+
end
|
291
|
+
def trade_codes
|
292
|
+
code = []
|
293
|
+
code << 'Ag' if ((4..9) === @atmo and (4..8) === @h20 and (5..7) === @popx)
|
294
|
+
code << 'As' if (@size == 0 and @atmo == 0 and @h20 ==0)
|
295
|
+
code << 'Ba' if (@popx == 0 and @govm == 0 and @law == 0)
|
296
|
+
code << 'De' if (@atmo > 1 and @h20 == 0)
|
297
|
+
code << 'Fl' if (@atmo > 9 and @h20 > 0)
|
298
|
+
code << 'Ga' if (@size > 4 and (4..9) === @atmo and (4..8) === @hydro)
|
299
|
+
code << 'Hi' if (@popx > 8)
|
300
|
+
code << 'Ht' if (@tek > 12)
|
301
|
+
code << 'IC' if (@atmo < 2 and @h20 > 0)
|
302
|
+
code << 'In' if ([0,1,2,4,7,9].include?(@atmo) and @popx > 8)
|
303
|
+
code << 'Lo' if ((1..3) === @popx)
|
304
|
+
code << 'Lt' if (@tek < 6)
|
305
|
+
code << 'Na' if ((0..3) === @atmo and (0..3) === @h20 and @popx > 5)
|
306
|
+
code << 'NI' if ((4..6) === @popx)
|
307
|
+
code << 'Po' if ((2..5) === @atmo and (0..3) === @h20)
|
308
|
+
code << 'Ri' if ([6,8].include?(@atmo) and (6..8) === @popx)
|
309
|
+
code << 'Va' if (@atmo == 0)
|
310
|
+
code << 'Wa' if (@hydro == 10)
|
311
|
+
code
|
312
|
+
end
|
313
|
+
end # End World (Mainworld)
|
314
|
+
|
315
|
+
class Moon < Astromapper::Builder::Base
|
316
|
+
attr_accessor :orbit, :size, :h20
|
317
|
+
@@orbits = { 'C' => (1..14).to_a, 'R' => [1,1,1,2,2,3] }
|
318
|
+
@@orbits['F'] = @@orbits['C'].map{|c| c * 5}
|
319
|
+
@@orbits['E'] = @@orbits['C'].map{|c| c * 25}
|
320
|
+
|
321
|
+
def initialize(planet,i=0)
|
322
|
+
@planet = planet
|
323
|
+
@popx = 0
|
324
|
+
@law = 0
|
325
|
+
@tek = 0
|
326
|
+
@govm = 0
|
327
|
+
@size = case
|
328
|
+
when @planet.xsize = 'L' then toss(2,4)
|
329
|
+
when @planet.xsize = 'S' then toss(2,6)
|
330
|
+
else @planet.size - toss(1,0)
|
331
|
+
end
|
332
|
+
orbit = toss(2,i)
|
333
|
+
@orbit = (case
|
334
|
+
when (@size < 1) then @@orbits['R'][toss(1,1)]
|
335
|
+
when (orbit == 12 and @planet.xsize == 'L') then @@orbits['E'][toss(2,0)]
|
336
|
+
when (orbit < 8) then @@orbits['C'][toss(2,0)]
|
337
|
+
when (orbit > 7) then @@orbits['C'][toss(2,0)]
|
338
|
+
else 0
|
339
|
+
end).whole
|
340
|
+
@h20 = (case
|
341
|
+
when (@planet.inner?) then 0
|
342
|
+
when (@size == 0) then 0
|
343
|
+
when (@planet.outer?) then toss(2,4)
|
344
|
+
when (@planet.biozone?) then toss(2,7)
|
345
|
+
else 0
|
346
|
+
end).whole
|
347
|
+
@atmo = toss(2,7) + @size
|
348
|
+
@atmo = (case
|
349
|
+
when (@size == 0) then 0
|
350
|
+
when (@planet.inner?) then @atmo - 4
|
351
|
+
when (@planet.outer?) then @atmo - 4
|
352
|
+
else 0
|
353
|
+
end).whole
|
354
|
+
end
|
355
|
+
def to_ascii
|
356
|
+
"\n%28s/ %3d rad. %s" % ['', @orbit, uwp]
|
357
|
+
end
|
358
|
+
def uwp
|
359
|
+
size = case
|
360
|
+
when @size < 0 then 'S'
|
361
|
+
when @size == 0 then 'R'
|
362
|
+
else @size.hexd
|
363
|
+
end
|
364
|
+
# size = (@size == 0) ? 'R' : @size.hexd
|
365
|
+
"%s%s%s%s%s%s%s" % ['X', size,@atmo.hexd,@h20.hexd,@popx.hexd,@govm.hexd,@law.hexd]
|
366
|
+
end
|
367
|
+
end # End Moon
|
368
|
+
|
369
|
+
end # End Builder
|
370
|
+
end # End Astromapper
|