# *********
# *WARNING* Spoilers contained in this file!
# *********
# This program colorizes doomrl maps for the doomrl wiki.
# Program written by tehtmi
# Contact: tehtmi gmail
# @ .com
# You can also contact my on the DoomRL forums/wiki.
# I am tehtmi on both.
# Feel free to use/edit this script however you want for
# the purposes of contributing to the doomrl wiki.
# Please do not sell this program.
# This script is not intended to cause damage to your
# computer in any way, but understand that it is provided
# with no warranty or guarantee of safety.
# Usage Notes:
# Running this program requires your computer to have an
# implementation of python installed. You can download
# python for free at:
# http://www.python.org/
# I believe this program should run on python 2.6 and 3.0.
# The program is designed to be run from the command line.
# In windows:
# 1) Install python (if necessary)
# 2) Put this script in a textfile with the .py extension.
# 2.5) It helps to put the script in the same directory as
# the map you want to colorize
# 3) Open a command prompt (Start->Run...->"cmd")
# 4) Navigate to the location of the script ("cd")
# 5) Type "[filename].py map.txt colormap.txt"
# Where [filename] is the name you gave to this
# script, map.txt is the name of the map file
# you want to colorize, and colormap.txt is the
# name of file you want to output to.
# In *nix:
# 1-2.5) as above
# 3) Open a terminal (if necessary)
# 4) Navigate to the location of the script
# 5) Type "python [filename].py map.txt colormap.txt
# WARNING: the contents of the output file might be
# overwritten if a file with that name already
# exists!
# Map file format:
# Maps are plain text files
# Empty lines are ignored, as are lines that begin with //
# Use lines beginning with // to comment your map if desired.
# The file should contain a map grid enclosed between a line
# that contains only the word "map" and another line that
# contains only the words "end map".
# Each character in the map grid represents one DoomRL tile.
# By default, certain characters refer to certain tiles. There
# is a list of default associations in the file below.
# Outside of the "map"/"end map" block, the map file can create
# and reassign associations between characters in the map grid
# and DoomRL tiles. To do this, write a line of the form:
# [map grid character] : [DoomRL tile name]
# A list of recognized DoomRL tiles is found below.
# The program knows how to colorize and draw these tiles
# based on their names.
# NOTE: A map grid character DOES NOT have to be the same
# character used by DoomRL to draw the map-tile it represents.
# E.G. "P" could represent a pain elemental even though pain
# elementals look like "O" in the game.
import sys
import re
inputFileName = sys.argv[1]
outputFileName = sys.argv[2]
inputFile = open(inputFileName, 'r')
tileMapFlag = False
# Non ascii characters: generated using html escapes
middleDot = '·' #Used for floor
brokenBar = '¦' #Used for ammo
bullet = '•' #Used for pool of blood
openBracket = '[' #Fixes wiki issue with [[ for two adjacent armors
# These are all the types of tile that are recognized by the program
# TODO: add different types of corpses
# TODO: do some enemies have green blood?
terms = {'stone wall' :('#', 'silver'),
'blooded wall' :('#', 'maroon'),
'bloodstone' :('#', 'maroon'),
'blooded wall (bloodstone)' :('#', 'red'),
'locked door' :('+', 'olive'),
'closed door' :('+', 'olive'),
'open door' :('/', 'olive'),
'phobos rock' :('.', 'maroon'),
'floor' :(middleDot, 'silver'),
'blood' :(middleDot, 'maroon'),
'pool of blood' :(bullet, 'maroon'),
'corpse' :('%', 'maroon'),
'stairs' :('>', 'silver'),
'down stairs' :('>', 'silver'),
'special stairs' :('>', 'red'),
'water' :('=', 'navy'),
'acid' :('=', 'green'),
'lava' :('=', 'PLAID:yellow:maroon'),
'lever' :('&', 'white'),
'special lever' :('&', 'fuchsia'),
'teleporter' :('*', 'aqua'),
'hellgate' :('0', 'fuchsia'),
'barrel of fuel' :('0', 'olive'),
'barrel of acid' :('0', 'green'),
'barrel of napalm' :('0', 'red'),
'pistol' :('}', 'silver'),
'shotgun' :('}', 'gray'),
'combat shotgun' :('}', 'blue'),
'double shotgun' :('}', 'white'),
'chaingun' :('}', 'maroon'),
'rocket launcher' :('}', 'olive'),
'plasma rifle' :('}', 'teal'),
'bfg 9000' :('}', 'fuchsia'),
'exotic weapon' :('}', 'fuchsia'),
'unique weapon' :('}', 'lime'),
'combat knife' :('\\', 'white'),
'chainsaw' :('\\', 'fuchsia'),
'exotic melee weapon' :('\\', 'fuchsia'),
'unique melee weapon' :('\\', 'lime'),
'artifact melee weapon' :('\\', 'yellow'),
'10mm ammo' :(brokenBar, 'silver'),
'shotgun shell' :(brokenBar, 'gray'),
'rocket' :(brokenBar, 'olive'),
'power cell' :(brokenBar, 'teal'),
'green armor' :(openBracket, 'green'),
'blue armor' :(openBracket, 'navy'),
'red armor' :(openBracket, 'maroon'),
'exotic armor' :(openBracket, 'fuchsia'),
'unique armor' :(openBracket, 'lime'),
'artifact armor' :(openBracket, 'yellow'),
'steel boots' :(';', 'white'),
'protective boots' :(';', 'green'),
'plasteel boots' :(';', 'navy'),
'exotic boots' :(';', 'fuchsia'),
'unique boots' :(';', 'lime'),
'agility mod pack' :('"', 'aqua'),
'bulk mod pack' :('"', 'blue'),
'power mod pack' :('"', 'fuchsia'),
'technical mod pack' :('"', 'yellow'),
'exotic mod pack' :('"', 'fuchsia'),
'unique mod pack' :('"', 'lime'),
'small med-pack' :('+', 'red'),
'large med-pack' :('+', 'maroon'),
'phase device' :('+', 'navy'),
'homing phase device' :('+', 'blue'),
'envirosuit pack' :('+', 'green'),
'exotic pack' :('+', 'fuchsia'),
'unique pack' :('+', 'lime'),
'thermonuclear bomb' :('%', 'blue'),
'thermonuclear bomb (active)':('0', 'maroon'),
'unique staff' :('?', 'lime'),
'artifact staff' :('?', 'yellow'),
'small health globe' :('^', 'red'),
'large health globe' :('^', 'maroon'),
'berserk pack' :('^', 'maroon'),
'supercharge globe' :('^', 'blue'),
'invulnerabilty globe' :('^', 'white'),
'armour shard' :('^', 'yellow'),
'megasphere' :('^', 'fuchsia'),
'computer map' :('^', 'green'),
'backpack' :('^', 'olive'),
'player start' :('@', 'silver'),
'former human' :('h', 'silver'),
'former sergeant' :('h', 'gray'),
'former captain' :('h', 'maroon'),
'former commando' :('h', 'blue'),
'imp' :('i', 'olive'),
'demon' :('c', 'red'),
'lost soul' :('s', 'yellow'),
'cacodemon' :('O', 'maroon'),
'hell knight' :('B', 'olive'),
'pain elemental' :('O', 'olive'),
'mancubus' :('M', 'olive'),
'arachnotron' :('A', 'yellow'),
'revenant' :('R', 'white'),
'baron of hell' :('B', 'maroon'),
'arch-vile' :('V', 'yellow'),
'nightmare imp' :('i', 'blue'),
'nightmare demon' :('c', 'blue'),
'nightmare cacodemon' :('O', 'blue'),
'arena master' :('V', 'lime'),
'shambler' :('B', 'white'),
'bruiser' :('B', 'red'),
'angel of death' :('A', 'maroon'),
'lava elemental' :('E', 'yellow'),
'cyberdemon' :('C', 'olive'),
'john carmack' :('@', 'blue'),
'random armor or boots' :('?', 'navy'),
'random weapon' :('?', 'olive'),
'[space]' :(' ', None),
'[newline]' :('\n', None),
'[empty]' :('', None)}
# These are default associations between map characters and actual tiles
# Associations can be added or modified by the input file
assoc = {'@':'player start',
'^':'supercharge globe',
'#':'stone wall',
'+':'closed door',
'.':'floor',
'=':'lava',
'&':'lever',
'*':'teleporter',
'0':'barrel',
'>':'down stairs',
'h':'former human',
'i':'imp',
's':'lost soul',
'c':'demon',
'B':'baron of hell',
'O':'cacodemon',
'R':'revenant',
'A':'arachnotron',
'M':'mancubus',
'C':'cyberdemon',
'V':'arch-vile',
'E':'lava elemental'}
# Regular expressions used to parse the input file
mapProg = re.compile(r'[\s]*map[\s]*$')
endMapProg = re.compile(r'[\s]*end map[\s]*$')
prog = re.compile(r'[\s]*([\S])[\s]*:[\s]*(.*?)[\s]*$')
mapLines = []
autobindingPrefix = '_'
autobindingNumber = 0
# Read the input file.
for line in inputFile:
if line == '\n':
continue
if len(line) >= 2 and line[0] == line[1] == '/':
# comment
continue
elif not tileMapFlag:
if mapProg.match(line) is not None:
tileMapFlag = True
else:
result = prog.match(line)
# print result.group(1), result.group(2)
name = result.group(1)
binding = result.group(2)
if len(binding) >= 3 and binding[0] == '.':
autobinding = autobindingPrefix + str(autobindingNumber)
autobindingNumber += 1
assoc[name] = autobinding
terms[autobinding] = (binding[1], binding[3:])
else:
if not terms.has_key(binding):
print "Invalid tile name '" + binding + "'."
print "Check spelling and consult the list in the file."
sys.exit(1)
assoc[name] = binding
else:
if endMapProg.match(line) is not None:
tileMapFlag = False
else:
mapLines.append(line)
inputFile.close()
def handle(tiles, colorStack):
if(len(tiles) == 0):
return
fColors = set([])
bColors = set([])
x = 0
while fColors.isdisjoint(bColors):
if x == len(tiles):
# all colors are None
for tile in tiles:
outputFile.write(tile[0])
return
color1 = tiles[x][1]
color2 = tiles[-(x + 1)][1]
if color1 is not None:
fColors.add(color1)
if color2 is not None:
bColors.add(color2)
x += 1
color = (fColors & bColors).pop()
x = 0
while not tiles[x][1] == color:
x += 1
y = len(tiles) - 1
while not tiles[y][1] == color:
y -= 1
handle(tiles[0:x], colorStack)
if len(colorStack) >= 2 and colorStack[1] == color:
inStack = colorStack[1:]
outputFile.write('</span>')
popMode = True
else:
inStack = [color] + colorStack
outputFile.write('<span style="color:' + color + '">')
popMode = False
x1 = x
while tiles[x1][1] in [color, None] and x1 < y:
outputFile.write(tiles[x1][0])
x1 += 1
y1 = y
while tiles[y1][1] in [color, None] and y1 >= x1:
y1 -= 1
y1 += 1
handle(tiles[x1:y1], inStack)
for y0 in range(y1, y + 1):
outputFile.write(tiles[y0][0])
if popMode:
outputFile.write('<span style="color:' + colorStack[0] + '">')
else:
outputFile.write('</span>')
handle(tiles[(y + 1):], colorStack)
outputFile = open(outputFileName, 'w')
tiles = []
for y in range(0, len(mapLines)):
line = mapLines[y]
for x in range(0, len(line) - 1): # -1 ignores ending '\n'
c = line[x]
tileChar, tileColor = terms[assoc[c].lower()]
if tileColor.startswith('PLAID'):
plaidColors = tileColor[6:].split(':')
tileColor = plaidColors[(x + y) % len(plaidColors)]
tiles.append((tileChar, tileColor))
if y <= len(mapLines) - 2:
tiles.append(terms['[newline]'])
tiles.append(terms['[space]'])
outputFile.write(' <span style="font-size:larger;background-color:black">')
handle(tiles,[])
outputFile.write('</span>\n')
outputFile.close()