Update to code as per suggestions on PR and IRC.
The code has been changed following peer review. *Both the map and build instructions have been abstracted out of the module. *Functionality has been expanded to include multiple passes allowing custom exit creation. *Documentation expanded and a further example provided.
This commit is contained in:
parent
d80eb80f1d
commit
a544e37ca9
1 changed files with 388 additions and 186 deletions
|
|
@ -1,17 +1,58 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Evennia World Builder
|
Evennia World Builder
|
||||||
|
|
||||||
Contribution - Cloud_Keeper 2016
|
Contribution - Cloud_Keeper 2016
|
||||||
|
|
||||||
This is a command capable of taking a reference to a basic 2D ASCII
|
Build a map from a 2D ASCII map.
|
||||||
map stored in the Evennia directory and generating the rooms and exits
|
|
||||||
necessary to populate that world. The characters of the map are iterated
|
This is a command which takes two inputs:
|
||||||
over and compared to a list of trigger characters. When a match is found
|
|
||||||
it triggers the corresponding instructions. Use by importing and including
|
≈≈≈≈≈
|
||||||
the command in your default_cmdsets module. For example:
|
≈♣n♣≈ MAP_LEGEND = {("♣", "♠"): build_forest,
|
||||||
|
≈∩▲∩≈ ("∩", "n"): build_mountains,
|
||||||
|
≈♠n♠≈ ("▲"): build_temple}
|
||||||
|
≈≈≈≈≈
|
||||||
|
|
||||||
|
A string of ASCII characters representing a map and a dictionary of functions
|
||||||
|
containing build instructions. The characters of the map are iterated over and
|
||||||
|
compared to a list of trigger characters. When a match is found the
|
||||||
|
corresponding function is executed generating the rooms, exits and objects as
|
||||||
|
defined by the users build instructions. If a character is not a match to
|
||||||
|
a provided trigger character (including spaces) it is simply skipped and the
|
||||||
|
process continues.
|
||||||
|
|
||||||
|
For instance, the above map represents a temple (▲) amongst mountains (n,∩)
|
||||||
|
in a forest (♣,♠) on an island surrounded by water (≈). Each character on the
|
||||||
|
first line is iterated over but as there is no match with our MAP_LEGEND it
|
||||||
|
is skipped. On the second line it finds "♣" which is a match and so the
|
||||||
|
`build_forest` function is called. Next the `build_mountains` function is
|
||||||
|
called and so on until the map is completed. Building instructions are passed
|
||||||
|
the following arguments:
|
||||||
|
x - The rooms position on the maps x axis
|
||||||
|
y - The rooms position on the maps y axis
|
||||||
|
caller - The player calling the command
|
||||||
|
iteration - The current iterations number (0, 1 or 2)
|
||||||
|
room_dict - A dictionary containing room references returned by build
|
||||||
|
functions where tuple coordinates are the keys (x, y).
|
||||||
|
ie room_dict[(2, 2)] will return the temple room above.
|
||||||
|
|
||||||
|
Building functions should return the room they create. By default these rooms
|
||||||
|
are used to create exits between valid adjacent rooms to the north, south,
|
||||||
|
east and west directions. This behaviour can turned off with the use of switch
|
||||||
|
arguments. In addition to turning off automatic exit generation the switches
|
||||||
|
allow the map to be iterated over a number of times. This is important for
|
||||||
|
something like custom exit building. Exits require a reference to both the
|
||||||
|
exits location and the exits destination. During the first iteration it is
|
||||||
|
possible that an exit is created pointing towards a destination that
|
||||||
|
has not yet been created resulting in error. By iterating over the map twice
|
||||||
|
the rooms can be created on the first iteration and room reliant code can be
|
||||||
|
be used on the second iteration. The iteration number and a dictionary of
|
||||||
|
references to rooms previously created is passed to the build commands.
|
||||||
|
|
||||||
|
Use by importing and including the command in your default_cmdsets module.
|
||||||
|
For example:
|
||||||
|
|
||||||
# mygame/commands/default_cmdsets.py
|
# mygame/commands/default_cmdsets.py
|
||||||
|
|
||||||
|
|
@ -21,187 +62,251 @@ the command in your default_cmdsets module. For example:
|
||||||
|
|
||||||
self.add(mapbuilder.CmdMapBuilder())
|
self.add(mapbuilder.CmdMapBuilder())
|
||||||
|
|
||||||
You then call the command in-game using the path to the module and the
|
You then call the command in-game using the path to the MAP and MAP_LEGEND vars
|
||||||
name of the variable holding the map string. The path you provide is
|
The path you provide is relative to the evennia or mygame folder.
|
||||||
relative to the evennia or your mygame folder.
|
|
||||||
|
|
||||||
@mapbuilder <path.to.module.VARNAME>
|
Usage:
|
||||||
|
@mapbuilder[/switch] <path.to.file.MAPNAME> <path.to.file.MAP_LEGEND>
|
||||||
|
|
||||||
For example to generate from the sample map in this module:
|
Switches:
|
||||||
|
one - execute build instructions once without automatic exit creation.
|
||||||
|
two - execute build instructions twice without automatic exit creation.
|
||||||
|
|
||||||
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE_MAP
|
Example:
|
||||||
|
@mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND
|
||||||
|
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND
|
||||||
|
(Legend path defaults to map path)
|
||||||
|
|
||||||
Whilst this map is contained here for convenience, it is suggested
|
Below are two examples showcasing the use of automatic exit generation and
|
||||||
that your map be stored in a separate stand alone module in the
|
custom exit generation. Whilst located, and can be used, from this module for
|
||||||
mygame/world folder accessed with @mapbuilder world.gamemap.MAP
|
convenience The below example code should be in mymap.py in mygame/world.
|
||||||
|
|
||||||
The rooms generated for each square of the map are generated using
|
|
||||||
instructions for each room type. These instructions are intended
|
|
||||||
to be changed and adapted for your purposes. In writing these
|
|
||||||
instructions you have access to the full API just like Batchcode.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# ---------- #
|
|
||||||
|
|
||||||
# This code should be in mymap.py in mygame/world.
|
from django.conf import settings
|
||||||
|
from evennia.utils import utils
|
||||||
|
|
||||||
|
# ---------- EXAMPLE 1 ---------- #
|
||||||
|
# @mapbuilder evennia.contrib.mapbuilder.EXAMPLE1_MAP EXAMPLE1_LEGEND
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
EXAMPLE_MAP = """\
|
# Add the necessary imports for your instructions here.
|
||||||
≈≈≈≈≈≈≈≈≈
|
|
||||||
≈≈≈≈≈≈≈≈≈
|
|
||||||
≈≈♣♠♣♠♣≈≈
|
|
||||||
≈≈♠n∩n♠≈≈
|
|
||||||
≈≈♣∩▲∩♣≈≈
|
|
||||||
≈≈♠n≈n♠≈≈
|
|
||||||
≈≈♣♠≈♠♣≈≈
|
|
||||||
≈≈≈≈≈≈≈≈≈
|
|
||||||
≈≈≈≈≈≈≈≈≈
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ---------- #
|
|
||||||
|
|
||||||
#Add the necessary imports for your instructions here.
|
|
||||||
from evennia import create_object
|
from evennia import create_object
|
||||||
from typeclasses import rooms, exits
|
from typeclasses import rooms, exits
|
||||||
from evennia.utils import utils
|
from evennia.utils import utils
|
||||||
from random import randint
|
from random import randint
|
||||||
import random
|
import random
|
||||||
|
|
||||||
def build_map(caller, raw_map):
|
# A map with a temple (▲) amongst mountains (n,∩) in a forest (♣,♠) on an
|
||||||
"""
|
# island surrounded by water (≈). By giving no instructions for the water
|
||||||
This is the part of the code designed to be changed and expanded. It
|
# characters we effectively skip it and create no rooms for those squares.
|
||||||
contains the instructions that are called when a match is made between
|
EXAMPLE1_MAP = """\
|
||||||
the characters in your map and the characters that trigger the building
|
≈≈≈≈≈
|
||||||
instructions.
|
≈♣n♣≈
|
||||||
|
≈∩▲∩≈
|
||||||
"""
|
≈♠n♠≈
|
||||||
|
≈≈≈≈≈
|
||||||
#Create a tuple containing the trigger characters
|
"""
|
||||||
forest = ("♣", "♠")
|
|
||||||
#Create a function that contains the instructions.
|
|
||||||
def create_forest(x, y):
|
|
||||||
#This has just basic instructions, building and naming the room.
|
|
||||||
room = create_object(rooms.Room, key="forest" + str(x) + str(y))
|
|
||||||
room.db.desc = "Basic forest room."
|
|
||||||
|
|
||||||
#Always include this at the end. Sets up for advanced functions.
|
|
||||||
caller.msg(room.key + " " + room.dbref)
|
|
||||||
room_list.append([room, x, y])
|
|
||||||
|
|
||||||
|
|
||||||
mountains = ("∩", "n")
|
def build_forest(x, y, **kwargs):
|
||||||
def create_mountains(x, y):
|
"""A basic example of build instructions. Make sure to include **kwargs
|
||||||
#We'll do something fancier in this one.
|
in the arguments and return an instance of the room for exit generation."""
|
||||||
room = create_object(rooms.Room, key="mountains" + str(x) + str(y))
|
|
||||||
|
|
||||||
#We'll select a description at random from a list.
|
# Create a room and provide a basic description.
|
||||||
room_desc = [
|
room = create_object(rooms.Room, key="forest" + str(x) + str(y))
|
||||||
"Mountains as far as the eye can see",
|
room.db.desc = "Basic forest room."
|
||||||
"Your path is surrounded by sheer cliffs",
|
|
||||||
"Haven't you seen that rock before?"]
|
|
||||||
room.db.desc = random.choice(room_desc)
|
|
||||||
|
|
||||||
#Let's populate the room with a random amount of rocks.
|
# Send a message to the player
|
||||||
for i in xrange(randint(0,3)):
|
kwargs["caller"].msg("Forest Room Created.")
|
||||||
rock = create_object(key = "Rock", location = room)
|
|
||||||
rock.db.desc = "An ordinary rock."
|
|
||||||
|
|
||||||
#Mandatory.
|
# This is generally mandatory.
|
||||||
caller.msg(room.key + " " + room.dbref)
|
return room
|
||||||
room_list.append([room, x, y])
|
|
||||||
|
|
||||||
temple = ("▲")
|
|
||||||
def create_temple(x, y):
|
|
||||||
#This room is only used once so we can be less general.
|
|
||||||
room = create_object(rooms.Room, key="temple" + str(x) + str(y))
|
|
||||||
|
|
||||||
room.db.desc = "In what, from the outside, appeared to be a grand " \
|
|
||||||
"and ancient temple you've somehow found yourself in the the " \
|
|
||||||
"Evennia Inn! It consists of one large room filled with tables. " \
|
|
||||||
"The bardisk extends along the east wall, where multiple barrels " \
|
|
||||||
" and bottles line the shelves. The barkeep seems busy handing " \
|
|
||||||
"out ale and chatting with the patrons, which are a rowdy and " \
|
|
||||||
"cheerful lot, keeping the sound level only just below thunderous" \
|
|
||||||
". This is a rare spot of warmth and mirth on this dread moor."
|
|
||||||
|
|
||||||
#Mandatory.
|
|
||||||
caller.msg(room.key + " " + room.dbref)
|
|
||||||
room_list.append([room, x, y])
|
|
||||||
|
|
||||||
#Include your keys and instructions in the master dictionary.
|
|
||||||
master_dict = {
|
|
||||||
forest:create_forest,
|
|
||||||
mountains:create_mountains,
|
|
||||||
temple:create_temple
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- ADVANCED USERS ONLY. Altering things below may break it. ---
|
|
||||||
|
|
||||||
#Create reference list and split map string to list of rows.
|
|
||||||
room_list = []
|
|
||||||
map = prepare_map(raw_map)
|
|
||||||
|
|
||||||
caller.msg("Creating Landmass...")
|
|
||||||
for y in xrange(len(map)):
|
|
||||||
for x in xrange(len(map[y])):
|
|
||||||
for key in master_dict:
|
|
||||||
if map[y][x] in key:
|
|
||||||
master_dict[key](x,y)
|
|
||||||
|
|
||||||
#Creating exits
|
|
||||||
caller.msg("Connecting Areas...")
|
|
||||||
for location in room_list:
|
|
||||||
x = location[1]
|
|
||||||
y = location[2]
|
|
||||||
|
|
||||||
for destination in room_list:
|
|
||||||
#north
|
|
||||||
if destination[1] == x and destination[2] == y-1:
|
|
||||||
exit = create_object(exits.Exit, key="north",
|
|
||||||
aliases=["n"], location=location[0],
|
|
||||||
destination=destination[0])
|
|
||||||
|
|
||||||
#east
|
|
||||||
if destination[1] == x+1 and destination[2] == y:
|
|
||||||
exit = create_object(exits.Exit, key="east",
|
|
||||||
aliases=["e"], location=location[0],
|
|
||||||
destination=destination[0])
|
|
||||||
#south
|
|
||||||
if destination[1] == x and destination[2] == y+1:
|
|
||||||
exit = create_object(exits.Exit, key="south",
|
|
||||||
aliases=["s"], location=location[0],
|
|
||||||
destination=destination[0])
|
|
||||||
|
|
||||||
#west
|
|
||||||
if destination[1] == x-1 and destination[2] == y:
|
|
||||||
exit = create_object(exits.Exit, key="west",
|
|
||||||
aliases=["w"], location=location[0],
|
|
||||||
destination=destination[0])
|
|
||||||
|
|
||||||
|
|
||||||
from django.conf import settings
|
def build_mountains(x, y, **kwargs):
|
||||||
|
"""A room that is a little more advanced"""
|
||||||
|
|
||||||
|
# Create the room.
|
||||||
|
room = create_object(rooms.Room, key="mountains" + str(x) + str(y))
|
||||||
|
|
||||||
|
# Generate a description by randomly selecting an entry from a list.
|
||||||
|
room_desc = ["Mountains as far as the eye can see",
|
||||||
|
"Your path is surrounded by sheer cliffs",
|
||||||
|
"Haven't you seen that rock before?"]
|
||||||
|
room.db.desc = random.choice(room_desc)
|
||||||
|
|
||||||
|
# Create a random number of objects to populate the room.
|
||||||
|
for i in xrange(randint(0, 3)):
|
||||||
|
rock = create_object(key="Rock", location=room)
|
||||||
|
rock.db.desc = "An ordinary rock."
|
||||||
|
|
||||||
|
# Send a message to the player
|
||||||
|
kwargs["caller"].msg("Mountain Room Created.")
|
||||||
|
|
||||||
|
# This is generally mandatory.
|
||||||
|
return room
|
||||||
|
|
||||||
|
|
||||||
|
def build_temple(x, y, **kwargs):
|
||||||
|
"""A unique room that does not need to be as general"""
|
||||||
|
|
||||||
|
# Create the room.
|
||||||
|
room = create_object(rooms.Room, key="temple" + str(x) + str(y))
|
||||||
|
|
||||||
|
# Set the description.
|
||||||
|
room.db.desc = ("In what, from the outside, appeared to be a grand and "
|
||||||
|
"ancient temple you've somehow found yourself in the the "
|
||||||
|
"Evennia Inn! It consists of one large room filled with "
|
||||||
|
"tables. The bardisk extends along the east wall, where "
|
||||||
|
"multiple barrels and bottles line the shelves. The "
|
||||||
|
"barkeep seems busy handing out ale and chatting with "
|
||||||
|
"the patrons, which are a rowdy and cheerful lot, "
|
||||||
|
"keeping the sound level only just below thunderous. "
|
||||||
|
"This is a rare spot of mirth on this dread moor.")
|
||||||
|
|
||||||
|
# Send a message to the player
|
||||||
|
kwargs["caller"].msg("Temple Room Created.")
|
||||||
|
|
||||||
|
# This is generally mandatory.
|
||||||
|
return room
|
||||||
|
|
||||||
|
# Include your trigger characters and build functions in a legend dict.
|
||||||
|
EXAMPLE1_LEGEND = {("♣", "♠"): build_forest,
|
||||||
|
("∩", "n"): build_mountains,
|
||||||
|
("▲"): build_temple}
|
||||||
|
|
||||||
|
# ---------- EXAMPLE 2 ---------- #
|
||||||
|
# @mapbuilder evennia.contrib.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Add the necessary imports for your instructions here.
|
||||||
|
from evennia import create_object
|
||||||
|
from typeclasses import rooms, exits
|
||||||
from evennia.utils import utils
|
from evennia.utils import utils
|
||||||
import imp
|
from random import randint
|
||||||
|
import random
|
||||||
|
|
||||||
|
# This is the same layout as Example 1 but included are characters for exits.
|
||||||
|
# We can use these characters to determine which rooms should be connected.
|
||||||
|
EXAMPLE2_MAP = """\
|
||||||
|
≈ ≈ ≈ ≈ ≈
|
||||||
|
|
||||||
|
≈ ♣-♣-♣ ≈
|
||||||
|
| |
|
||||||
|
≈ ♣ ♣ ♣ ≈
|
||||||
|
| | |
|
||||||
|
≈ ♣-♣-♣ ≈
|
||||||
|
|
||||||
|
≈ ≈ ≈ ≈ ≈
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def build_forest(x, y, **kwargs):
|
||||||
|
"""A basic room"""
|
||||||
|
# If on anything other than the first iteration - Do nothing.
|
||||||
|
if kwargs["iteration"] > 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
room = create_object(rooms.Room, key="forest" + str(x) + str(y))
|
||||||
|
room.db.desc = "Basic forest room."
|
||||||
|
|
||||||
|
return room
|
||||||
|
|
||||||
|
|
||||||
|
def build_verticle_exit(x, y, **kwargs):
|
||||||
|
"""Creates two exits to and from the two rooms north and south."""
|
||||||
|
# If on the first iteration - Do nothing.
|
||||||
|
if kwargs["iteration"] == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
for key, value in kwargs["room_dict"].iteritems():
|
||||||
|
kwargs["caller"].msg(str(key))
|
||||||
|
kwargs["caller"].msg(str(value))
|
||||||
|
|
||||||
|
north_room = kwargs["room_dict"][(x, y-1)]
|
||||||
|
south_room = kwargs["room_dict"][(x, y+1)]
|
||||||
|
|
||||||
|
north = create_object(exits.Exit, key="south",
|
||||||
|
aliases=["s"], location=north_room,
|
||||||
|
destination=south_room)
|
||||||
|
|
||||||
|
south = create_object(exits.Exit, key="north",
|
||||||
|
aliases=["n"], location=south_room,
|
||||||
|
destination=north_room)
|
||||||
|
|
||||||
|
|
||||||
|
def build_horizontal_exit(x, y, **kwargs):
|
||||||
|
"""Creates two exits to and from the two rooms east and west."""
|
||||||
|
# If on the first iteration - Do nothing.
|
||||||
|
if kwargs["iteration"] == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
west_room = kwargs["room_dict"][(x-1, y)]
|
||||||
|
east_room = kwargs["room_dict"][(x+1, y)]
|
||||||
|
|
||||||
|
west = create_object(exits.Exit, key="east",
|
||||||
|
aliases=["e"], location=west_room,
|
||||||
|
destination=east_room)
|
||||||
|
|
||||||
|
east = create_object(exits.Exit, key="west",
|
||||||
|
aliases=["w"], location=east_room,
|
||||||
|
destination=west_room)
|
||||||
|
|
||||||
|
# Include your trigger characters and build functions in a legend dict.
|
||||||
|
EXAMPLE2_LEGEND = {("♣", "♠"): build_forest,
|
||||||
|
("|"): build_verticle_exit,
|
||||||
|
("-"): build_horizontal_exit}
|
||||||
|
|
||||||
|
# ---------- END OF EXAMPLES ---------- #
|
||||||
|
|
||||||
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||||
|
|
||||||
|
|
||||||
|
# Helper function for readability.
|
||||||
|
def _map_to_list(game_map):
|
||||||
|
"""
|
||||||
|
Splits multi line map string into list of rows, treats for UTF-8 encoding.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
game_map (str): An ASCII map
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list (list): The map split into rows
|
||||||
|
|
||||||
|
"""
|
||||||
|
list_map = game_map.split('\n')
|
||||||
|
return [character.decode('UTF-8') if isinstance(character, basestring)
|
||||||
|
else character for character in list_map]
|
||||||
|
|
||||||
|
|
||||||
class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
|
class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
|
||||||
"""
|
"""
|
||||||
Build a map from a 2D ASCII map.
|
Build a map from a 2D ASCII map.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@mapbuilder <path.to.module.MAPNAME>
|
@mapbuilder[/switch] <path.to.file.MAPNAME> <path.to.file.MAP_LEGEND>
|
||||||
|
|
||||||
|
Switches:
|
||||||
|
one - execute build instructions once without automatic exit creation
|
||||||
|
two - execute build instructions twice without automatic exit creation
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE_MAP
|
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE_MAP MAP_LEGEND
|
||||||
@mapbuilder world.gamemap.MAP
|
@mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND
|
||||||
|
|
||||||
This is a simple way of building a map of placeholder or otherwise
|
This is a command which takes two inputs:
|
||||||
bare rooms from a 2D ASCII map. The command merely imports the map
|
A string of ASCII characters representing a map and a dictionary of
|
||||||
and runs the build_map function in evennia.contrib.mapbuilder.
|
functions containing build instructions. The characters of the map are
|
||||||
This function should be altered with keys and instructions that
|
iterated over and compared to a list of trigger characters. When a match
|
||||||
suit your individual needs.
|
is found the corresponding function is executed generating the rooms,
|
||||||
|
exits and objects as defined by the users build instructions. If a
|
||||||
|
character is not a match to a provided trigger character (including spaces)
|
||||||
|
it is simply skipped and the process continues. By default exits are
|
||||||
|
automatically generated but is turned off by switches which also determines
|
||||||
|
how many times the map is iterated over.
|
||||||
"""
|
"""
|
||||||
key = "@mapbuilder"
|
key = "@mapbuilder"
|
||||||
aliases = ["@buildmap"]
|
aliases = ["@buildmap"]
|
||||||
|
|
@ -209,48 +314,145 @@ class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
|
||||||
help_category = "Building"
|
help_category = "Building"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"Starts the processor."
|
"""Starts the processor."""
|
||||||
|
|
||||||
caller = self.caller
|
caller = self.caller
|
||||||
args = self.args
|
args = self.args.split()
|
||||||
map = None
|
|
||||||
|
|
||||||
#Check if arguments passed.
|
# Check if arguments passed.
|
||||||
if not args:
|
if not self.args or (len(args) != 2):
|
||||||
caller.msg("Usage: @mapbuilder <path.to.module.VARNAME>")
|
caller.msg("Usage: @mapbuilder <path.to.module.VARNAME> "
|
||||||
|
"<path.to.module.MAP_LEGEND>")
|
||||||
return
|
return
|
||||||
|
|
||||||
#Breaks down path into PATH, VARIABLE
|
# Set up base variables.
|
||||||
args = args.rsplit('.', 1)
|
game_map = None
|
||||||
|
legend = None
|
||||||
|
|
||||||
|
# OBTAIN MAP FROM MODULE
|
||||||
|
|
||||||
|
# Breaks down path_to_map into [PATH, VARIABLE]
|
||||||
|
path_to_map = args[0]
|
||||||
|
path_to_map = path_to_map.rsplit('.', 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#Retrieves map variable from module.
|
# Retrieves map variable from module or raises error.
|
||||||
map = utils.variable_from_module(args[0],args[1])
|
game_map = utils.variable_from_module(path_to_map[0],
|
||||||
|
path_to_map[1])
|
||||||
|
if not game_map:
|
||||||
|
raise ValueError("Command Aborted!\n"
|
||||||
|
"Path to map variable failed.\n"
|
||||||
|
"Usage: @mapbuilder <path.to.module."
|
||||||
|
"VARNAME> <path.to.module.MAP_LEGEND>")
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
#Or relays error message if fails.
|
# Or relays error message if fails.
|
||||||
caller.msg(exc)
|
caller.msg(exc)
|
||||||
|
|
||||||
#Display map retrieved.
|
# OBTAIN MAP_LEGEND FROM MODULE
|
||||||
caller.msg("Creating Map...")
|
|
||||||
caller.msg(map)
|
|
||||||
|
|
||||||
#Pass map to the bulid function.
|
# Breaks down path_to_legend into [PATH, VARIABLE]
|
||||||
build_map(caller, map)
|
path_to_legend = args[1]
|
||||||
caller.msg("Map Created.")
|
path_to_legend = path_to_legend.rsplit('.', 1)
|
||||||
|
|
||||||
#Helper function for readability.
|
# If no path given default to path_to_map's path
|
||||||
def prepare_map(map):
|
if len(path_to_legend) == 1:
|
||||||
|
path_to_legend.insert(0, path_to_map[0])
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Retrieves legend variable from module or raises error if fails.
|
||||||
|
legend = utils.variable_from_module(path_to_legend[0],
|
||||||
|
path_to_legend[1])
|
||||||
|
if not legend:
|
||||||
|
raise ValueError("Command Aborted!\n"
|
||||||
|
"Path to legend variable failed.\n"
|
||||||
|
"Usage: @mapbuilder <path.to.module."
|
||||||
|
"VARNAME> <path.to.module.MAP_LEGEND>")
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
# Or relays error message if fails.
|
||||||
|
caller.msg(exc)
|
||||||
|
|
||||||
|
# Set up build_map arguments from switches
|
||||||
|
iterations = 1
|
||||||
|
build_exits = True
|
||||||
|
|
||||||
|
if "one" in self.switches:
|
||||||
|
build_exits = False
|
||||||
|
|
||||||
|
if "two" in self.switches:
|
||||||
|
iterations = 2
|
||||||
|
build_exits = False
|
||||||
|
|
||||||
|
# Pass map and legend to the build function.
|
||||||
|
build_map(caller, game_map, legend, iterations, build_exits)
|
||||||
|
|
||||||
|
|
||||||
|
def build_map(caller, game_map, legend, iterations=1, build_exits=True):
|
||||||
"""
|
"""
|
||||||
Splits multi line map string into list of rows, treats for UTF-8 encoding.
|
Receives the fetched map and legend vars provided by the player. The map
|
||||||
|
is iterated over character by character, comparing it to the trigger
|
||||||
Args:
|
characters in the legend var and executing the build instructions on
|
||||||
map (str): An ASCII map
|
finding a match. The map is iterated over according to the `iterations`
|
||||||
|
value and exits are optionally generated between adjacent rooms according
|
||||||
Returns:
|
to the `build_exits` value.
|
||||||
list (list): The map split into rows
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
list_map = map.split('\n')
|
|
||||||
return [character.decode('UTF-8') if isinstance(character, basestring)
|
# Split map string to list of rows and create reference list.
|
||||||
else character for character in list_map]
|
caller.msg("Creating Map...")
|
||||||
|
caller.msg(game_map)
|
||||||
|
game_map = _map_to_list(game_map)
|
||||||
|
|
||||||
|
# Create a reference dictionary which be passed to build functions and
|
||||||
|
# will store obj returned by build functions so objs can be referenced.
|
||||||
|
room_dict = {}
|
||||||
|
|
||||||
|
caller.msg("Creating Landmass...")
|
||||||
|
for iteration in xrange(iterations):
|
||||||
|
for y in xrange(len(game_map)):
|
||||||
|
for x in xrange(len(game_map[y])):
|
||||||
|
for key in legend:
|
||||||
|
if game_map[y][x] in key:
|
||||||
|
room = legend[key](x, y, iteration=iteration,
|
||||||
|
room_dict=room_dict,
|
||||||
|
caller=caller)
|
||||||
|
if iteration == 0:
|
||||||
|
room_dict[(x, y)] = room
|
||||||
|
|
||||||
|
if build_exits:
|
||||||
|
# Creating exits. Assumes single room object in dict entry
|
||||||
|
caller.msg("Connecting Areas...")
|
||||||
|
for loc_key, location in room_dict.iteritems():
|
||||||
|
x = loc_key[0]
|
||||||
|
y = loc_key[1]
|
||||||
|
|
||||||
|
# north
|
||||||
|
if (x, y-1) in room_dict:
|
||||||
|
if room_dict[(x, y-1)]:
|
||||||
|
exit = create_object(exits.Exit, key="north",
|
||||||
|
aliases=["n"], location=location,
|
||||||
|
destination=room_dict[(x, y-1)])
|
||||||
|
|
||||||
|
# east
|
||||||
|
if (x+1, y) in room_dict:
|
||||||
|
if room_dict[(x+1, y)]:
|
||||||
|
exit = create_object(exits.Exit, key="east",
|
||||||
|
aliases=["e"], location=location,
|
||||||
|
destination=room_dict[(x+1, y)])
|
||||||
|
|
||||||
|
# south
|
||||||
|
if (x, y+1) in room_dict:
|
||||||
|
if room_dict[(x, y+1)]:
|
||||||
|
exit = create_object(exits.Exit, key="south",
|
||||||
|
aliases=["s"], location=location,
|
||||||
|
destination=room_dict[(x, y+1)])
|
||||||
|
|
||||||
|
# west
|
||||||
|
if (x-1, y) in room_dict:
|
||||||
|
if room_dict[(x-1, y)]:
|
||||||
|
exit = create_object(exits.Exit, key="west",
|
||||||
|
aliases=["w"], location=location,
|
||||||
|
destination=room_dict[(x-1, y)])
|
||||||
|
|
||||||
|
caller.msg("Map Created.")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue