Virtual Land Creation

The virtual land creation tool generates a random set of rooms based on a template xml file and an image. It reads each pixel and uses the xml template to generate a room based on the pixel color. It can pull from multiple room descriptions to make your area more unique by haveing a set of room descriptions.

This is a python script that uses PIL to read the image.

Setup

License

This code is public domain, do what you like with it.

Example Data:

Source image
Sample XML

<xml>
    <colors>
        <color rgb="0,0,0" type="pointofinterest" />
        <color rgb="1,50,100" type="water" />
        <color rgb="60,100,30" type="grass" />
        <color rgb="150,130,90" type="dirt" />
        <color rgb="255,255,255" type="bridge" />
        <color rgb="250,250,250" type="bridge2" />
        <color rgb="100,80,50" type="road" />
    </colors>    
    <pointofinterest>
        <roomdetails>
            <room>
                <short>Some Magical Happy Place</short>
                <daylong>A fun place with a crack in the ground.</daylong>
                <nightlong>A fun place with a crack in the ground.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_CUSTOM</terraintype>
                <medium>MEDIUM_LAND</medium>
                <viewitems>({"crack","ground", "earth", "baked earth"}) : "The crack in the ground is about a foot long and is quite dark. There is a strange hot breeze coming from the crack. Perhaps you could search around in it to find out more.",
                </viewitems>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>
#include <damage_types.h>
#include ROOMS_H

inherit LIB_ROOM;

int searched;

static void heart_beat(){
	searched = 0;
}

string SearchCrack(){
    string result;
	string item;
    int losthand = 0;
    if(!searched){
        if(!random(100)){
            result="Poking your hand into the crack you reach in and "+
                "discover a kevlar helmet.";
            say(this_player()->GetName()+" searches near the crack "+
                    "and seems to have found something of value.");
            if(!new("/domains/savsoul/armor/helmet2")->eventMove(this_player()))
                new("/domains/savsoul/armor/helmet2")->eventMove(environment(this_object()));
            searched=1;
            return result; 
        } else if (!random(2)){
            say(this_player()->GetName()+" searches the crack "+
                    "and seems to have found something.");
			switch(random(1)) {
				case 1:
				result="You stick your hand into the crack in the ground and discover a %^CYAN%^black wool cap%^RESET%^.";
				item = "/domains/savsoul/armor/wool_cap";
				break;
				default:
				result="As you stick your hand into the crack you feel an intense rush of %^RED%^flames%^RESET%^.";
                losthand = 1;
			}
            if (losthand == 1) {
                this_player()->eventReceiveDamage(environment(this_object()),(HEAT), 100, 0, "right hand");
            } else {
                if(!new(item)->eventMove(this_player()))
                    new(item)->eventMove(environment(this_object()));
            }
            searched=1;
            return result; 
		}
    }

	if (searched) {
	    result="You feel a bit tired, perhaps you can search again later";		
	} else {
    	result="You search the crack in the ground but find nothing.";
	}
    say(this_player()->GetName()+" searches the crack in the ground and finds nothing.");
    searched=1;
    return result; 
}

void create() {
    room::create();
    
    ]]></header>
        <footer><![CDATA[

    SetSearch( "crack", (:SearchCrack:) );

}
        
void init(){
    ::init();
	set_heart_beat(30);    
}        
        ]]></footer>
    </pointofinterest>
    <road>
        <landmarkdescriptions>
            <description>
                <distance>2</distance>
                <description>A distant road can be seen to the $DIR.</description>
            </description>
            <description>
                <distance>1</distance>
                <description>There is a road that can be seen to the $DIR.</description>
            </description>                
        </landmarkdescriptions>
        <roomdetails>
            <room>
                <short>Road</short>
                <daylong>A road 1.</daylong>
                <nightlong>A road 1 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
            <room>
                <short>Road</short>
                <daylong>A road 2.</daylong>
                <nightlong>A road 2 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
            <room>
                <short>Road</short>
                <daylong>A road 3.</daylong>
                <nightlong>A road 3 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();

    ]]></header>
        <footer><![CDATA[

}
        
void init(){
    ::init();
}        
        ]]></footer>
    </road>    
    <bridge>
        <landmarkdescriptions>
            <description>
                <distance>2</distance>
                <description>A bridge can be seen to the $DIR.</description>
            </description>
            <description>
                <distance>1</distance>
                <description>A wooden bridge can be seen to the $DIR.</description>
            </description>                
        </landmarkdescriptions>    
        <roomdetails>
            <room>
                <short>Wooden Bridge</short>
                <daylong>A wooden bridge 1.</daylong>
                <nightlong>A wooden bridge 1 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                    <exit direction="down">"down" :"/domains/somedomain/room/start",</exit>
                </exits>
            </room>
            <room>
                <short>Wooden Bridge</short>
                <daylong>A wooden bridge 2.</daylong>
                <nightlong>A wooden bridge 2 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                    <exit direction="down">"down" :"/domains/somedomain/room/start",</exit>
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();

    ]]></header>
        <footer><![CDATA[

}
        
void init(){
    ::init();
}        
        ]]></footer>
    </bridge>
    <bridge2>
        <landmarkdescriptions>
            <description>
                <distance>5</distance>
                <description>Far off in the distance a bridge can be seen to the $DIR.</description>
            </description>
            <description>
                <distance>2</distance>
                <description>A bridge can be seen to the $DIR.</description>
            </description>
            <description>
                <distance>1</distance>
                <description>A bridge can be seen to the $DIR.</description>
            </description>                
        </landmarkdescriptions>    
        <roomdetails>
            <room>
                <short>Bridge</short>
                <daylong>A bridge 1.</daylong>
                <nightlong>A bridge 1 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                    <exit direction="down">"down" :"/domains/somedomain/room/start",</exit>
                </exits>
            </room>
            <room>
                <short>Bridge</short>
                <daylong>A bridge 2.</daylong>
                <nightlong>A bridge 2 at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_ROAD</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                    <exit direction="down">"down" :"/domains/somedomain/room/start",</exit>
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();

    ]]></header>
        <footer><![CDATA[

}
        
void init(){
    ::init();
}        
        ]]></footer>
    </bridge2>
    <water>
        <landmarkdescriptions>
            <description>
                <distance>2</distance>
                <description>A distant river can be seen to the $DIR.</description>
            </description>
            <description>
                <distance>1</distance>
                <description>A slow moving river can be seen to the $DIR.</description>
            </description>                
        </landmarkdescriptions>     
        <roomdetails>
            <room>
                <short>Daylay River</short>
                <daylong>Some Water.</daylong>
                <nightlong>Some Water at night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_SURFACE</terraintype>
                <medium>MEDIUM_WATER</medium>
                <viewitems>
                    <item>({"water","bubbles"}) : "The water has some bubbles!",</item>
                </viewitems>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                    <exit direction="down">"down" :"/domains/somedomain/room/start",</exit>
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();

    ]]></header>
        <footer><![CDATA[

}

int CanReceive(object ob) {
    if(living(ob) && !interactive(ob)){
        message("info","NPC's not allowed, sorry.", ob);
        return 0;
    }
    return room::CanReceive(ob);
}

void init(){
    ::init();
}        
        ]]></footer>
    </water>
    <dirt>
        <roomdetails>
            <room>
                <short>Open Field</short>
                <daylong>Dirt desc 1.</daylong>
                <nightlong>Dirt desc 1 night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_SAND</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
            <room>
                <short>Open Field</short>
                <daylong>Dirt desc 2.</daylong>
                <nightlong>Dirt desc 2 night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_SAND</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();

    ]]></header>
        <footer><![CDATA[

}
        
void init(){
    ::init();
}        
        ]]></footer>
    </dirt>
    <grass>
        <roomdetails>
            <room>
                <short>Grass</short>
                <daylong>grass description 1.</daylong>
                <nightlong>grass description 1 night.</nightlong>
                <ambientlight>0</ambientlight>
                <nightlight>10</nightlight>
                <daylight>20</daylight>
                <terraintype>T_OUTDOORS</terraintype>
                <medium>MEDIUM_LAND</medium>
                <inventoryitems>
                    <invitem chance="100">"/domains/somedomain/npc/monster":({150, 1}),</invitem>
                </inventoryitems>
                <exits> <!-- Any explicit exits that are not the default. -->
                </exits>
            </room>
        </roomdetails>
        <header><![CDATA[
#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>
#include <damage_types.h>
#include ROOMS_H

inherit LIB_ROOM;


void create() {
    room::create();
    
    ]]></header>
        <footer><![CDATA[

}
        
void init(){
    ::init();
}       
        ]]></footer>
    </grass>
</xml>

Source (Still a WIP):
try:
    from PIL import Image
except ImportError:
    print('PIL module is not installed. Please visit: ' +
        'http://www.pythonware.com/products/pil/\n\n')
    print('If you are on Ubuntu you may want to look at this guide: ' +
        'http://obroll.com/install-python-pil-python-image-library-on-ubuntu-11-10-oneiric/')
import random
import argparse
import os
import sys
import re
from amara import bindery
from math import degrees, atan2, sqrt
import shutil

def getdirection(dirx, diry, playerx, playery):
    angle = degrees(atan2(diry - playery, dirx - playerx))
    bearing = (angle + 360) % 360
    #print "%d, %d, %d, %d, %d, %d" % (dirx, diry, playerx, playery, angle, bearing)
    if (bearing >= 0 and bearing <= 20) or (bearing > 340):
        return "west"   
    if bearing > 30 and bearing <= 60:
        return "northwest" 
    if bearing > 60 and bearing <= 120:
        return "north"     
    if bearing > 120 and bearing <= 160:
        return "northeast"   
    if bearing > 160 and bearing <= 200:
        return "east"     
    if bearing > 200 and bearing <= 240:
        return "southeast" 
    if bearing > 240 and bearing <= 300:
        return "south"      
    if bearing > 300 and bearing <= 340:
        return "southwest"  
    return "distance"

def GetNearbyLandmarks(xmldata, roomtype, x, y, pixels, colors):
    #roomtype = None
    foundlandmarks = {}
    cpixel = None
    for xexp in range(x-5, x+5):
        for yexp in range(y-5, y+5):
            if xexp == x and yexp == y:
                #skip the zone were in.
                continue
            try:
                cpixel = pixels[xexp, yexp]
            except:
                #skip bad areas.
                continue
            for colortup in colors:
                if int(colortup[0]) == cpixel[0] and int(colortup[1]) == cpixel[1] and int(colortup[2]) == cpixel[2]:
                    newroomtype = colortup[3]
            if roomtype == newroomtype:
                # same as the current room, skip.
                continue
            if xmldata[newroomtype] == None:
                continue
            try:
                if xmldata[newroomtype].landmarkdescriptions == None:
    	            continue
    	    except AttributeError:
    	        continue
            distance = sqrt( (xexp - x)**2 + (yexp - y)**2 )
            direction = getdirection( x, y, xexp, yexp)
            for landmark in xmldata[newroomtype].landmarkdescriptions.description:
                if distance <= int(str(landmark.distance)):
                    try:
                        if foundlandmarks[newroomtype]["distance"] < int(str(landmark.distance)):
                            continue
                    except KeyError:
                        pass
                    foundlandmarks[newroomtype] = {"distance":int(str(landmark.distance)), 
                        "description":str(landmark.description).replace("$DIR", direction)}
    return foundlandmarks

def buildRoom(xmldata, roomtype, width, height, x, y, domainname, virtualname, imgxpos, imgypos, pixels, colors):
    
    outputroom = str(xmldata[roomtype].header)
    randroom = random.randint(0, len(xmldata[roomtype].roomdetails.room)-1)
    outputroom += '\n    SetAmbientLight(' + str(xmldata[roomtype].roomdetails.room[randroom].ambientlight) + ');\n';
    outputroom += '    SetDayLight(' + str(xmldata[roomtype].roomdetails.room[randroom].daylight) + ');\n';
    outputroom += '    SetNightLight(' + str(xmldata[roomtype].roomdetails.room[randroom].nightlight) + ');\n';
    outputroom += '    SetTerrainType(' + str(xmldata[roomtype].roomdetails.room[randroom].terraintype) + ');\n';
    outputroom += '    SetMedium(' + str(xmldata[roomtype].roomdetails.room[randroom].medium) + ');\n';
    outputroom += '    SetShort("' + str(xmldata[roomtype].roomdetails.room[randroom].short) + '");\n';
    
    foundlandmarks = GetNearbyLandmarks(xmldata, roomtype, imgxpos, imgypos, pixels, colors);
    daylong = str(xmldata[roomtype].roomdetails.room[randroom].daylong) + " "
    for landmark in foundlandmarks.values():
        daylong += str(landmark["description"]) + " "
    outputroom += '    SetDayLong("' + daylong + '");\n';
    
    # Don't display the landmarks at night.
    outputroom += '    SetNightLong("' + str(xmldata[roomtype].roomdetails.room[randroom].nightlong) + '");\n';
    
    if xmldata[roomtype].roomdetails.room[randroom].viewitems != None:
        outputroom += '    SetItems( ([\n' + str(xmldata[roomtype].roomdetails.room[randroom].viewitems) + '\n';
        outputroom += ']));'

    if xmldata[roomtype].roomdetails.room[randroom].inventoryitems.invitem != None:
        outputroom += '    SetInventory( ([\n'
        for item in xmldata[roomtype].roomdetails.room[randroom].inventoryitems.invitem:
            if item["chance"] == None:
                continue
            rand = random.randint(1, 100)
            if rand <= int(str(item["chance"])):
                outputroom += str(item) + '\n';
            outputroom += '\n'
        outputroom += ']));'

    outputroom += '\n    SetExits(([\n'
    exits = {}
    if imgxpos-1 >= 0:
        exits["west"] = ('"west" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x-1) + "," + str(y) + '",\n')
    if imgxpos+2 <= width -2:
        if (x == 50) and (y == -99):
            print imgxpos+2
            print width-2
        exits["east"] = ('"east" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x+1) + "," + str(y) + '",\n')
    if imgypos-1 >= 0:
        exits["north"] = ('"north" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x) + "," + str(y+1) + '",\n')
    if imgypos+1 <= height-1:
        exits["south"] = ('"south" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x) + "," + str(y-1) + '",\n')
    if imgxpos-1 >= 0 and imgypos-1 >= 0:
        exits["northwest"] = ('"northwest" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x-1) + "," + str(y+1) + '",\n')
    if imgxpos+2 <= width-2 and imgypos-2 >= 0:
        exits["northeast"] = ('"northeast" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x+1) + "," + str(y+1) + '",\n')
    if imgxpos-1 >= 0 and imgypos+1 <= height-1:
        exits["southwest"] = ('"southwest" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x-1) + "," + str(y-1) + '",\n')
    if imgxpos+2 <= width-2 and imgypos+1 <= height-1:
        exits["southeast"] = ('"southeast" : "/domains/' + domainname + '/virtual/' + 
            virtualname + '/' + str(x+1) + "," + str(y-1) + '",\n')
    
    if xmldata[roomtype].roomdetails.room[randroom].exits.exit != None:
        for exit in xmldata[roomtype].roomdetails.room[randroom].exits:
            if exit['removedir'] == 'true':
                try:
                    del exits[exit['direction']]
                except KeyError:
                    continue
            else:
                exits[exit['direction']] = exit
    
    for exit in exits.values():
        if exit != None:
            outputroom += str(exit)
        
    outputroom += '\n]));\n\n'
    
    outputroom += str(xmldata[roomtype].footer)
    return outputroom

def processImage(args, xmldata, colors):
	i = Image.open(args.image)
	
	pixels = i.load() 
	width, height = i.size
	startxpos = 2
	startypos = 0
	#directions 1 = southeast 2 = southwest 3 = northeast 4 = northwest
	direction = 1
	cnt = 0
	somestr = ""
	prevpercent = 0
	for x in range(width):
		currpercent = int((float(x) / float(width)) * 100)
		if currpercent > prevpercent:
			sys.stdout.write("\rPercent Complete: " + str(currpercent))
			sys.stdout.flush()
			prevpercent = currpercent
		for y in range(height):
			mudx = x
			mudy = y
			cnt+=1
			cpixel = pixels[x, y]
			cfile = None
			if direction == 1:
				mudx = startxpos + x
				mudy = startypos - y
			if args.outdir.endswith("/"):
				filename = args.outdir + str(mudx) + "," + str(mudy) + ".c"
			else:
				filename = args.outdir + "/" + str(mudx) + "," + str(mudy) + ".c"
	
			
	
			#print filename
			roomtype = None

			for colortup in colors:
				if int(colortup[0]) == cpixel[0] and int(colortup[1]) == cpixel[1] and int(colortup[2]) == cpixel[2]:
					roomtype = colortup[3]
			if roomtype == None:
				print("Missing Room Definition for Pixel Color: " + str(cpixel[0]) + ", " + 
					str(cpixel[1]) + ", " + str(cpixel[2]) + " at position: " + str(x) + ", " + str(y))
				quit()
			#print roomtype
			if xmldata[roomtype] == None:
				#ignore any colors that do not have room definitions. This will let the generic virtual area be used instead.
				continue
			cfile = open(filename, 'w')            
			cfile.write(buildRoom(xmldata, roomtype, width, height, mudx, mudy, 
				args.domainname, args.virtualname, x, y, pixels, colors))
	sys.stdout.write("\rRoom Generation Complete!\n\n")

def GetArgs():
	parser = argparse.ArgumentParser(description='Converts an image by pixel into ' +
		'individual rooms for virtual creation.')
	parser.add_argument('--image', '-i', dest='image', required=True,
		help='The image can be of any type supported by PIL. Jpeg, PNG, GIF, etc...')
	parser.add_argument('--domain', '-d', dest='domainname', required=True,
		help='The name of the domain where this will be created. This is used for building the exit path')
	parser.add_argument('--virtual', '-v', dest='virtualname', required=True,
		help='The name of the virtual area where this will be created. This is used for building the exit path')
	parser.add_argument('--outputdir', '-o', dest='outdir', default='roomfiles',
		help='The directory where the X,X.c files will be written. By default this is "roomfiles"')
	parser.add_argument('--template', '-t', dest='template', required=True,
		help='The source template that will be used to generate the rooms.')
	parser.add_argument('--replace', '-r', dest='replace', type=bool, default=False,
		help='If the output directory / files already exist they will be replaced ' +
			'when this is set to true. By default this is false.')
	
	return parser.parse_args()

def parseXml(template):
	xmldata = None
	try:
		xmldata = bindery.parse(open(template))
		print("Room Types Parsed:\n")
	
		for room in xmldata.xml.colors.color:
			print("    " + room['type'])
		print('\n')
		sys.stdout.flush()
		return xmldata.xml
		
	except Exception as error:
		print('Template Error: ')
		print(error)
		print('Could not parse the template file. Please see sample xml file ' +
			'for details.')
		quit()

def createFolder(outdir, replace):
	if not os.path.exists(outdir): 
		os.makedirs(outdir)
	else:
		if replace == True:
			shutil.rmtree(outdir)
			os.makedirs(outdir)
		else:
			print('The output folder already exists. You can remove it yourself ' +
				'or pass --replace True as an argument.')
			quit()


def main():
	args = GetArgs()	
	print("Parsing XML template...\n")
	xmldata = parseXml(args.template)
	colors = []
	# only perform this split once so it can avoid calling split.
	for color in xmldata.colors.color:
		colortup = color['rgb'].split(',')
		colortup.append(color['type'])
		colors.append(colortup)
	createFolder(args.outdir, args.replace)
	processImage(args, xmldata, colors)
	
if __name__ == "__main__":
    main()
    
Sample output:

#include <lib.h>
#include <daemons.h>
#include <medium.h>
#include <terrain_types.h>

inherit LIB_ROOM;

static void create() {
    room::create();
    SetAmbientLight(0);
    SetDayLight(20);
    SetNightLight(10);
    SetTerrainType(T_OUTDOORS);
    SetMedium(MEDIUM_LAND);
    SetShort("its room 1 grass");
    SetDayLong("It's Daytime in room 1 type grass");
    SetNightLong("It's Nighttime in room 1 grass");

    SetExits(([
"northeast" : "/domains/savsoul/virtual/ROWasteland/11,-13",
"north" : "/domains/savsoul/virtual/ROWasteland/10,-15",
"west" : "/domains/savsoul/virtual/ROWasteland/9,-14",
"southeast" : "/domains/savsoul/virtual/ROWasteland/11,-15",
"east" : "/domains/savsoul/virtual/ROWasteland/11,-14",
"southwest" : "/domains/savsoul/virtual/ROWasteland/9,-15",

]));

}
        
void init(){
    ::init();
}

Sample Output