Citizens of the Imperium

Citizens of the Imperium (
-   Classic Traveller (
-   -   Web-based Automatic Sector Data / Map pdf Generator (

Mickazoid April 27th, 2006 02:49 PM

Hi folks.

I know these things get whipped up all the time, but I got on a roll after re-reading some of my old LBB's last year, so I wrote a sector data/map generator that accepts sector files or randomly generates a sector, and then outputs text files containing all the relevant data and pdf's with formatting and design very similar to that of the original LBB's.

I used some choice old Unix-based Traveller software (James Perkins' SW4) and created a web-based random sector generator script that accepts a URL and returns a high-res pdf file. The quality and speed exceeded what I initially thought possible, so I thought I'd pass along the info and see if others can benefit.

Yes, I do hope to be hosting this on my public web server soon, with a bunch of improvements to come as I'm inspired. If you'd like to see a live demo (in other words, to see it running on my personal machine), please feel free to contact me via email.

After you install the required components (see script), merely pass the sectorname and the desired % of systems via a URL: http://[servername]/SectorMaker.cgi?Sector-TL4826+41

And presto, in around 30 - 45 seconds, you've got a choice, printable pdf of a Classic Traveller sector. It contains system names, UPP listings and a hexmap for each subsector - a brand new sector, chock full of gaming possibilities!

Update: now with color option:

In addition, each generated doc can optionally contain a 'descriptions' section, that breaks the UPP down into easy-to-read text using the 'full-upp' program.

Once my upload has been approved in the admin queue, you can see a sample of the untouched output (scroll through the pages!) here: (1mb) (28k) (268k)

The text of the SectorMaker.cgi is located here:

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">#!/bin/sh

# SectorMaker.cgi
# by Micki Kaufman
# I was looking at my LBB collection, and got an idea, so voila!
# Presenting the Traveller Sector Guidebook .cgi script. Creates and returns
# a high-resolution (vector-art) pdf containing the sector data and hexmaps,
# listed subsector by subsector.
# Requires:
# - James M. Perkins' Traveller software programs
# - Paul J. Netherwood's Traveller program 'full-upp'
# - Christopher Pound's language confluxer
# - pstopdf
# (built in on Mac OSX)
# - enscript
# (built in on Mac OSX)
# - joinPDF
# - pdftk
# Using sector tools, the sector data and individual subsector data is
# created, and the PostScript hexmap is generated. Using pstopdf, the PostScript
# hexmap is converted to a pdf. Using enscript, the text sector data is
# converted to a PostScript file. Still working on page size. using joinPDF, the
# pdf's are concatenated together. And then we serve it up!
# Still to come: data fields (containing name, date, etc.), Univers (yet monospaced)
formatted list.
# Far Future Enterprises Fair Use Notice:
# The Traveller game in all forms is owned by Far Future Enterprises. Copyright
# 1977 - 1998 Far Future Enterprises. Traveller is a registered trademark of Far
# Future Enterprises. Far Future permits web sites and fanzines for this game,
# provided it contains this notice, that Far Future is notified, and subject to
# a withdrawal of permission on 90 days notice. The contents of this site are
# for personal, non-commercial use only. Any use of Far Future Enterprises’s
# copyrighted material or trademarks anywhere on this web site and its files
# should not be viewed as a challenge to those copyrights or trademarks. In
# addition, any program/articles/file on this site cannot be republished or
# distributed without the consent of the author who contributed it.

#### First, here are the get_UPP and parse_SectorDescription functions.

### get_UPP (requires 'full-upp', installed in bin folder.

function get_UPP()
full-upp $2 &gt; /tmp/$1uppo.txt
cat /tmp/$1uppo.txt /Library/WebServer/CGI-Executables/trav/ret.txt &gt; /tmp/$1upp.txt
chmod ugo+w /tmp/$1upp.txt /tmp/$1uppo.txt
#echo &quot;Content-Type: application/text&quot;
#echo &quot; Filename: &quot;$1upp.txt
echo &quot;&quot;
echo &quot;&quot;
echo $1
echo &quot;Name: &quot;$3
echo &quot;UPP: &quot;$2
echo &quot;&quot;
cat &lt; /tmp/$1upp.txt
rm -rf /tmp/*upp.txt
rm -rf /tmp/*uppo.txt

### get_SectorDescriptions grabs each of the planet's descriptions (using the get_UPP
function on each) and then serves the whole thing up as a text file and pdf.

function get_SectorDescriptions()
while read LINE
get_UPP $LINE &gt; /tmp/$1det$LINE.txt
done &lt; /tmp/$1

cat /Library/WebServer/CGI-Executables/trav/pageblanker.txt /tmp/$2title.txt
/Library/WebServer/CGI-Executables/trav/ret.txt /tmp/$1det*.txt &gt; /tmp/$1finaldet.txt


# Create .ps files from each datafile
enscript --word-wrap --margins=40:-50:0:40
--fancy-header='travellerpagenums' --header='|- $% -|'
--header-font=Univers9 /tmp/$1finaldet.txt -f Univers-Light8.25
--media=Traveller -q -p /tmp/$

# Create .pdf files from each datafile .ps
pstopdf /tmp/$ -o /tmp/$1piecetemp.pdf

# Grab the pages, starting #36 (the prior 35 are blank to set up the numbering,
# since the pdftk program can't start the numbering at 36.
pdftk /tmp/$1piecetemp.pdf cat 36-end output /tmp/$1piecetempText.pdf

# Grab the first page of the descriptions
pdftk /tmp/$1piecetempText.pdf cat 1-1 output /tmp/$1piecetempIntro.pdf

# Place the 'World Descriptions' header on the first page, in keeping with the
# document's section headings.
pdftk /tmp/$1piecetempIntro.pdf background
/Library/WebServer/CGI-Executables/trav/Desc_Background.pdf output /tmp/$1pieceDescIntroWithBack.pdf

# Grab the rest of the descriptions
pdftk /tmp/$1piecetempText.pdf cat 2-end output /tmp/$1pieceEnd.pdf

# Join the first page of descriptions (now with header) and the rest of the descriptions
pdftk /tmp/$1pieceDescIntroWithBack.pdf /tmp/$1pieceEnd.pdf cat output /tmp/$1piece.pdf


#### Now the main body of the script.


## Generate the custom cover

# Generate the text of the sector name
echo $1&quot; Sector&quot; &gt; /tmp/$1seccover.txt

# Add a line to the sectorname for processing
cat /Library/WebServer/CGI-Executables/trav/covercat.txt /tmp/$1seccover.txt &gt; /tmp/$1seccover2.txt

# Turn it PostScript
enscript --word-wrap /tmp/$1seccover2.txt --margins=12:-100:264:40 -B -f
Optima-Italic32 --media=Traveller -q -p /tmp/$

# Turn the generated text white for the cover
sed 's/5 273 M/5 273 M 1 setgray/g' /tmp/$ &gt; /tmp/$

# Make the generated text of the cover a pdf
pstopdf /tmp/$ -o /tmp/$1seccover1.pdf

# Combine the generated name and the background front cover pdf into the new sector front cover.
pdftk /tmp/$1seccover1.pdf background /Library/WebServer/CGI-Executables/trav/SectorData_Cover.pdf
output /tmp/$1Cover.pdf

## Generate the back page

# For now, grab Jim Lovell's quote. Will accept a text field or a 'fortune' as well.
enscript /Library/WebServer/CGI-Executables/trav/LovellQuote.txt --word-wrap
--margins=25:-90:100:160:40 -B -f Optima-Italic23 --media=Traveller -q -p /tmp/$

# Make the generated text of the back cover a pdf
sed 's/5 302 M/5 302 M 1 setgray/g' /tmp/$ &gt; /tmp/$

# Make the generated text of the back cover a pdf
pstopdf /tmp/$ -o /tmp/$1Backtemp.pdf

# Combine the generated text and the background back cover pdf into the new sector back cover.
pdftk /tmp/$1Backtemp.pdf background /Library/WebServer/CGI-Executables/trav/SectorData_Back.pdf
output /tmp/$1Back.pdf


## Generate the raw subsector data or import it

if [ $5 &gt; 0 ]; then
cp /Library/WebServer/CGI-Executables/$5 /tmp/$1secdata
sed q /tmp/$1secdata &gt; /tmp/$1secdataorighead

gensec3 $2 $3 &gt; /tmp/$1secdataorig2

# Save the first line of the sector file ('Version' tag)
sed q /tmp/$1secdataorig2 &gt; /tmp/$1secdataorighead

# Remove the first line for the text processing
sed '1d' /tmp/$1secdataorig2 &gt; /tmp/$1secdataorig

## Generate the sector's system names

# Count the number of worlds generated
NUM_WORLDS=`wc -l /tmp/$1secdataorig | awk '{ print $1 }'`

# Grab the generated datafile's contents preceding and following the name
cut -b20-80 /tmp/$1secdataorig &gt; /tmp/$1secdataorigBack

# Run the random word generator
perl /Library/WebServer/CGI-Executables/trav/lc -$NUM_WORLDS
/Library/WebServer/CGI-Executables/trav/namesmaster.txt &gt; /tmp/$1namegrab1

# Grab the names from the file
sed -e :a -e 's/^.\{1,18\}$/&amp; /;ta' /tmp/$1namegrab1 &gt; /tmp/$1namegrab2

# Combine the three files into a new secdata file with the names inside
paste -d '\0' /tmp/$1namegrab2 /tmp/$1secdataorigBack &gt; /tmp/$1secdatainterim

# paste the header back onto the sector data
cat /tmp/$1secdataorighead /tmp/$1secdatainterim &gt; /tmp/$1secdata



#Create Title Text for Listings and Descriptions
echo &quot;&quot;$1&quot;&quot;&quot; Sector&quot; &gt; /tmp/$1title.txt

## Big Per-Subsector Loop Starts

for x in A B C D E F G H I J K L M N O P; do

# Generate this subsector's data file
subsec2 S=$x &lt; /tmp/$1secdata &gt; /tmp/$1subsec$x

# Create a duplicate
sed '' /tmp/$1subsec$x &gt; /tmp/$1subsecdata$x

# Reorder the ID on the datafile for output only
cut -b20-24 /tmp/$1subsecdata$x &gt; /tmp/$1secdatareorderID
cut -b1-19 /tmp/$1subsecdata$x &gt; /tmp/$1secdatareorderName
cut -b25-81 /tmp/$1subsecdata$x &gt; /tmp/$subsecend$x
paste -d '\0' /tmp/$1secdatareorderID /tmp/$1secdatareorderName /tmp/$subsecend$x
&gt; /tmp/$1subsecReorder$x

# Put the heading on top of this subsector's data file (for printing)
cat -u /Library/WebServer/CGI-Executables/trav/introspace.txt /tmp/$1title.txt
/Library/WebServer/CGI-Executables/trav/beginfile.txt /tmp/$1subsecReorder$x &gt; /tmp/$1subsecOut$x

# Create .ps file from this subsector map, using PostScript format (for luscious printability!)

# Change the version number to trip the logic of the mapper
sed 's/3/2/g' /tmp/$1secdataorighead &gt; /tmp/$1secdataorighead2

# Put the header on each subsector file
cat /tmp/$1secdataorighead2 /tmp/$1subsec$x &gt; /tmp/$1subsecCalc$x

# Map each subsector's data
mapsub3 -p &lt; /tmp/$1subsecCalc$x &gt; /tmp/$1subsec$

# Create .pdf file from this subsectors map's .ps file
/usr/bin/pstopdf /tmp/$1subsec$ -o /tmp/$1subsecinter$x.pdf

# Create .ps file from this subsectors data's file
enscript /tmp/$1subsecOut$x --margins=40:20:40:40 -B -f Courier8 --media=Traveller
-q -p /tmp/$1subsecdata$

# Create .pdf file from this subsector data's .ps file
/usr/bin/pstopdf /tmp/$1subsecdata$ -o /tmp/$1subsecdatainter$x.pdf

# Place the generated data on a background with header and page number
pdftk /tmp/$1subsecdatainter$x.pdf background
output /tmp/$1subsecdata$x.pdf

# Place the generated map on a background with header and page number
pdftk /tmp/$1subsecinter$x.pdf background
output /tmp/$1subsec$x.pdf

#Each subsector's loop ends here

### Assemble final .pdf containing cover and each subsector's map and data

#Evaluate whether the fourth argument is higher than 1 (to bypass descriptions)


let &quot;desc = desc + 1&quot;

if [ &quot;$needfordesc&quot; -lt &quot;$desc&quot; ]; then # -n tests to see if the argument is non empty


# Bring it together with the right TOC (no 'world descriptions' line)
pdftk /tmp/$1Cover.pdf /Library/WebServer/CGI-Executables/trav/SectorData_IntNoDesc.pdf
/tmp/$1subsecdataA.pdf /tmp/$1subsecA.pdf /tmp/$1subsecdataB.pdf /tmp/$1subsecB.pdf
/tmp/$1subsecdataC.pdf /tmp/$1subsecC.pdf /tmp/$1subsecdataD.pdf /tmp/$1subsecD.pdf
/tmp/$1subsecdataE.pdf /tmp/$1subsecE.pdf /tmp/$1subsecdataF.pdf /tmp/$1subsecF.pdf
/tmp/$1subsecdataG.pdf /tmp/$1subsecG.pdf /tmp/$1subsecdataH.pdf /tmp/$1subsecH.pdf
/tmp/$1subsecdataI.pdf /tmp/$1subsecI.pdf /tmp/$1subsecdataJ.pdf /tmp/$1subsecJ.pdf
/tmp/$1subsecdataK.pdf /tmp/$1subsecK.pdf /tmp/$1subsecdataL.pdf /tmp/$1subsecL.pdf
/tmp/$1subsecdataM.pdf /tmp/$1subsecM.pdf /tmp/$1subsecdataN.pdf /tmp/$1subsecN.pdf
/tmp/$1subsecdataO.pdf /tmp/$1subsecO.pdf /tmp/$1subsecdataP.pdf /tmp/$1subsecP.pdf
cat output /tmp/$1pre.pdf

# Combine the subsector pages into the final pdf and compress
pdftk /tmp/$1pre.pdf /tmp/$1Back.pdf cat output /tmp/$1.pdf compress

# Back up the relevant files in the survey archives
cp /tmp/$1.pdf /sectors/autogen/$1.pdf
cp /tmp/$1secdata /sectors/autogen/$1_secdata


# Cut and recombine the ID, UPP and NAME fields into a new list
cut -b20-24 /tmp/$1secdata &gt; /tmp/$1secdatadescreformID
cut -b25-34 /tmp/$1secdata &gt; /tmp/$1secdatadescreformSpaceUPP
cut -b1-18 /tmp/$1secdata &gt; /tmp/$1secdatadescreformName
paste -d '\0' /tmp/$1secdatadescreformID /tmp/$1secdatadescreformSpaceUPP
/tmp/$1secdatadescreformName &gt; /tmp/$1secdatareform
#sed -e 's/ /\+/' /tmp/$1secdatareform &gt; /tmp/$1secdatareform2
#sed -e 's/-//' /tmp/$1secdatareform2 &gt; /tmp/$1secdatareform3
sed -e 's/-//' /tmp/$1secdatareform &gt; /tmp/$1secdatareform4
#sed -e 's/ /\+/' /tmp/$1secdatareform3 &gt; /tmp/$1secdataform4
#sed '1d' /tmp/$1secdataform4 &gt; /tmp/$1secdatadesc
sed '1d' /tmp/$1secdatareform4 &gt; /tmp/$1secdatadesc

# Run the parser
get_SectorDescriptions $1secdatadesc $1


# Bring it together with the right TOC (w/ 'world descriptions' line)
pdftk /tmp/$1Cover.pdf /Library/WebServer/CGI-Executables/trav/SectorData_IntDesc.pdf
/tmp/$1subsecdataA.pdf /tmp/$1subsecA.pdf /tmp/$1subsecdataB.pdf /tmp/$1subsecB.pdf
/tmp/$1subsecdataC.pdf /tmp/$1subsecC.pdf /tmp/$1subsecdataD.pdf /tmp/$1subsecD.pdf
/tmp/$1subsecdataE.pdf /tmp/$1subsecE.pdf /tmp/$1subsecdataF.pdf /tmp/$1subsecF.pdf
/tmp/$1subsecdataG.pdf /tmp/$1subsecG.pdf /tmp/$1subsecdataH.pdf /tmp/$1subsecH.pdf
/tmp/$1subsecdataI.pdf /tmp/$1subsecI.pdf /tmp/$1subsecdataJ.pdf /tmp/$1subsecJ.pdf
/tmp/$1subsecdataK.pdf /tmp/$1subsecK.pdf /tmp/$1subsecdataL.pdf /tmp/$1subsecL.pdf
/tmp/$1subsecdataM.pdf /tmp/$1subsecM.pdf /tmp/$1subsecdataN.pdf /tmp/$1subsecN.pdf
/tmp/$1subsecdataO.pdf /tmp/$1subsecO.pdf /tmp/$1subsecdataP.pdf /tmp/$1subsecP.pdf
cat output /tmp/$1pre.pdf

# Combine the subsector pages and descriptions pages, plus covers into the final pdf and compress
pdftk /tmp/$1pre.pdf /tmp/$1secdatadescpiece.pdf /tmp/$1Back.pdf cat output /tmp/$1.pdf compress

#back up the relevant files in the survey archives
cp /tmp/$1.pdf /sectors/autogen/$1.pdf
cp /tmp/$1secdata /sectors/autogen/$1_secdata
sed '1,1998d' /tmp/$1secdatadescfinaldet.txt &gt; /tmp/$1secdatadescfinaldet1.txt
cp /tmp/$1secdatadescfinaldet1.txt /sectors/autogen/$1_desc.txt

### And Serve (temporarily disabled till I fix the web server perms)

# CGI for presenting a pdf
#echo &quot;Content-Type: application/pdf&quot;
#echo &quot; Filename: &quot;$1.pdf
#echo &quot;&quot;
#cat &lt; /tmp/$1.pdf

# And For the cgi's debug, verbose option
#echo &quot; o . . . . . . . . . . . . . . . . . . . . . . . . .&quot;
#echo &quot; .&quot;

#Shell script
echo &quot; . $1 Sector containing&quot; $NUM_WORLDS&quot; worlds (&quot;$2&quot;%) took&quot; $SECONDS &quot;seconds to generate. &quot;
#echo &quot; .&quot;

#Clean up
rm -rf /tmp/$1*</pre>[/QUOTE]In any case, you can download all the text files you'll need right here.

Still to come - trying to get the subsector data pages' font to the correct Univers (while maintaining the monospacing), background art and headers, consistent page numbers, and maybe trade routes (although I liked creating those in the course of past campaigns).

If anyone would like help using it, please let me know!

Thanks, Micki

FlightCommanderSolitude April 27th, 2006 03:19 PM

That's fantastic! Quick question: why is the output file so huge?

Mickazoid April 27th, 2006 03:23 PM

I think it's 2.2 mb because it's got a buncha fonts and images in it, and it's not compressed. I'll see about compressing it, etc. to reduce the size to the max (or rather, the min) [img]smile.gif[/img]

robject April 27th, 2006 04:13 PM

Totally beautiful. I am in awe.

far-trader April 27th, 2006 04:20 PM

Sweeeeeeeet! Must remember to grab this later.

A most appreciative welcome aboard Micki :D

Mickazoid April 27th, 2006 05:08 PM

Thanks guys! I started playing Traveller in the late 70's, when I was around 10 years old (my cousin is a game writer) and I've had my LBB's and the new Collector's Reprints in a place of honor ever since!

Soon this will be hosted on a persistent server, so you can generate a pdf on demand when you need one [img]smile.gif[/img]


Sorel April 27th, 2006 05:14 PM

I must admit, I've been looking for something like this.

I can hardly wait for the posted version and the sample to get 'cleared'.

Mickazoid April 27th, 2006 05:34 PM

Oh, all right! [img]smile.gif[/img] [img]smile.gif[/img]

Here's a direct link to my website, where I've posted it (along with the sector data and description files:

And a special bonus: here's a URL to a pdf that I generated from the existing Spinward Marches datafile, on my own web site:

And the Foreven sector, just for BeRKA [img]smile.gif[/img]

I can generate maps of any sector with data in standard format ). So - if you've got a data file and you'd like a Survey Guidebook generated, let me know.

The Oz April 27th, 2006 06:07 PM

Very cool.

The Hinterworlds Rambler April 27th, 2006 08:24 PM

Astounding, Actually! Who are you, sir? You live in NYC? This is really Outstanding!

All times are GMT -4. The time now is 02:16 PM.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
Copyright (c) 2010-2013, Far Future Enterprises. All Rights Reserved.