mirror of
https://github.com/evennia/evennia.git
synced 2026-03-23 00:06:30 +01:00
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,207 +1,312 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
|
||||
Evennia World Builder
|
||||
|
||||
Contribution - Cloud_Keeper 2016
|
||||
|
||||
This is a command capable of taking a reference to a basic 2D ASCII
|
||||
map stored in the Evennia directory and generating the rooms and exits
|
||||
necessary to populate that world. The characters of the map are iterated
|
||||
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:
|
||||
Build a map from a 2D ASCII map.
|
||||
|
||||
This is a command which takes two inputs:
|
||||
|
||||
≈≈≈≈≈
|
||||
≈♣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
|
||||
|
||||
|
||||
from evennia.contrib import mapbuilder
|
||||
|
||||
|
||||
...
|
||||
|
||||
|
||||
self.add(mapbuilder.CmdMapBuilder())
|
||||
|
||||
You then call the command in-game using the path to the module and the
|
||||
name of the variable holding the map string. The path you provide is
|
||||
relative to the evennia or your mygame folder.
|
||||
You then call the command in-game using the path to the MAP and MAP_LEGEND vars
|
||||
The path you provide is relative to the evennia or 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
|
||||
that your map be stored in a separate stand alone module in the
|
||||
mygame/world folder accessed with @mapbuilder world.gamemap.MAP
|
||||
|
||||
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.
|
||||
Below are two examples showcasing the use of automatic exit generation and
|
||||
custom exit generation. Whilst located, and can be used, from this module for
|
||||
convenience The below example code should be in mymap.py in mygame/world.
|
||||
|
||||
"""
|
||||
# ---------- #
|
||||
|
||||
# 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 -*-
|
||||
|
||||
EXAMPLE_MAP = """\
|
||||
≈≈≈≈≈≈≈≈≈
|
||||
≈≈≈≈≈≈≈≈≈
|
||||
≈≈♣♠♣♠♣≈≈
|
||||
≈≈♠n∩n♠≈≈
|
||||
≈≈♣∩▲∩♣≈≈
|
||||
≈≈♠n≈n♠≈≈
|
||||
≈≈♣♠≈♠♣≈≈
|
||||
≈≈≈≈≈≈≈≈≈
|
||||
≈≈≈≈≈≈≈≈≈
|
||||
"""
|
||||
|
||||
# ---------- #
|
||||
|
||||
#Add the necessary imports for your instructions here.
|
||||
# Add the necessary imports for your instructions here.
|
||||
from evennia import create_object
|
||||
from typeclasses import rooms, exits
|
||||
from evennia.utils import utils
|
||||
from random import randint
|
||||
import random
|
||||
|
||||
def build_map(caller, raw_map):
|
||||
"""
|
||||
This is the part of the code designed to be changed and expanded. It
|
||||
contains the instructions that are called when a match is made between
|
||||
the characters in your map and the characters that trigger the building
|
||||
instructions.
|
||||
# A map with a temple (▲) amongst mountains (n,∩) in a forest (♣,♠) on an
|
||||
# island surrounded by water (≈). By giving no instructions for the water
|
||||
# characters we effectively skip it and create no rooms for those squares.
|
||||
EXAMPLE1_MAP = """\
|
||||
≈≈≈≈≈
|
||||
≈♣n♣≈
|
||||
≈∩▲∩≈
|
||||
≈♠n♠≈
|
||||
≈≈≈≈≈
|
||||
"""
|
||||
|
||||
|
||||
def build_forest(x, y, **kwargs):
|
||||
"""A basic example of build instructions. Make sure to include **kwargs
|
||||
in the arguments and return an instance of the room for exit generation."""
|
||||
|
||||
# Create a room and provide a basic description.
|
||||
room = create_object(rooms.Room, key="forest" + str(x) + str(y))
|
||||
room.db.desc = "Basic forest room."
|
||||
|
||||
# Send a message to the player
|
||||
kwargs["caller"].msg("Forest Room Created.")
|
||||
|
||||
# This is generally mandatory.
|
||||
return room
|
||||
|
||||
|
||||
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 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 create_mountains(x, y):
|
||||
#We'll do something fancier in this one.
|
||||
room = create_object(rooms.Room, key="mountains" + str(x) + str(y))
|
||||
|
||||
#We'll select a description at random 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)
|
||||
|
||||
#Let's populate the room with a random amount of rocks.
|
||||
for i in xrange(randint(0,3)):
|
||||
rock = create_object(key = "Rock", location = room)
|
||||
rock.db.desc = "An ordinary rock."
|
||||
|
||||
#Mandatory.
|
||||
caller.msg(room.key + " " + room.dbref)
|
||||
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))
|
||||
# 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."
|
||||
|
||||
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])
|
||||
# Send a message to the player
|
||||
kwargs["caller"].msg("Mountain Room Created.")
|
||||
|
||||
#Include your keys and instructions in the master dictionary.
|
||||
master_dict = {
|
||||
forest:create_forest,
|
||||
mountains:create_mountains,
|
||||
temple:create_temple
|
||||
}
|
||||
# This is generally mandatory.
|
||||
return room
|
||||
|
||||
# --- ADVANCED USERS ONLY. Altering things below may break it. ---
|
||||
|
||||
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
|
||||
|
||||
#Create reference list and split map string to list of rows.
|
||||
room_list = []
|
||||
map = prepare_map(raw_map)
|
||||
# Include your trigger characters and build functions in a legend dict.
|
||||
EXAMPLE1_LEGEND = {("♣", "♠"): build_forest,
|
||||
("∩", "n"): build_mountains,
|
||||
("▲"): build_temple}
|
||||
|
||||
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])
|
||||
# ---------- EXAMPLE 2 ---------- #
|
||||
# @mapbuilder evennia.contrib.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.conf import settings
|
||||
# Add the necessary imports for your instructions here.
|
||||
from evennia import create_object
|
||||
from typeclasses import rooms, exits
|
||||
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)
|
||||
|
||||
|
||||
|
||||
# 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):
|
||||
"""
|
||||
Build a map from a 2D ASCII map.
|
||||
|
||||
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:
|
||||
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE_MAP
|
||||
@mapbuilder world.gamemap.MAP
|
||||
@mapbuilder evennia.contrib.mapbuilder.EXAMPLE_MAP MAP_LEGEND
|
||||
@mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND
|
||||
|
||||
This is a simple way of building a map of placeholder or otherwise
|
||||
bare rooms from a 2D ASCII map. The command merely imports the map
|
||||
and runs the build_map function in evennia.contrib.mapbuilder.
|
||||
This function should be altered with keys and instructions that
|
||||
suit your individual needs.
|
||||
This is a command which takes two inputs:
|
||||
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. 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"
|
||||
aliases = ["@buildmap"]
|
||||
|
|
@ -209,48 +314,145 @@ class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
|
|||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
"Starts the processor."
|
||||
|
||||
"""Starts the processor."""
|
||||
|
||||
caller = self.caller
|
||||
args = self.args
|
||||
map = None
|
||||
|
||||
#Check if arguments passed.
|
||||
if not args:
|
||||
caller.msg("Usage: @mapbuilder <path.to.module.VARNAME>")
|
||||
args = self.args.split()
|
||||
|
||||
# Check if arguments passed.
|
||||
if not self.args or (len(args) != 2):
|
||||
caller.msg("Usage: @mapbuilder <path.to.module.VARNAME> "
|
||||
"<path.to.module.MAP_LEGEND>")
|
||||
return
|
||||
|
||||
# Set up base variables.
|
||||
game_map = None
|
||||
legend = None
|
||||
|
||||
# OBTAIN MAP FROM MODULE
|
||||
|
||||
#Breaks down path into PATH, VARIABLE
|
||||
args = args.rsplit('.', 1)
|
||||
# Breaks down path_to_map into [PATH, VARIABLE]
|
||||
path_to_map = args[0]
|
||||
path_to_map = path_to_map.rsplit('.', 1)
|
||||
|
||||
try:
|
||||
#Retrieves map variable from module.
|
||||
map = utils.variable_from_module(args[0],args[1])
|
||||
# Retrieves map variable from module or raises error.
|
||||
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:
|
||||
#Or relays error message if fails.
|
||||
# Or relays error message if fails.
|
||||
caller.msg(exc)
|
||||
|
||||
#Display map retrieved.
|
||||
caller.msg("Creating Map...")
|
||||
caller.msg(map)
|
||||
# OBTAIN MAP_LEGEND FROM MODULE
|
||||
|
||||
#Pass map to the bulid function.
|
||||
build_map(caller, map)
|
||||
caller.msg("Map Created.")
|
||||
# Breaks down path_to_legend into [PATH, VARIABLE]
|
||||
path_to_legend = args[1]
|
||||
path_to_legend = path_to_legend.rsplit('.', 1)
|
||||
|
||||
# If no path given default to path_to_map's path
|
||||
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)
|
||||
|
||||
#Helper function for readability.
|
||||
def prepare_map(map):
|
||||
# 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.
|
||||
|
||||
Args:
|
||||
map (str): An ASCII map
|
||||
|
||||
Returns:
|
||||
list (list): The map split into rows
|
||||
Receives the fetched map and legend vars provided by the player. The map
|
||||
is iterated over character by character, comparing it to the trigger
|
||||
characters in the legend var and executing the build instructions on
|
||||
finding a match. The map is iterated over according to the `iterations`
|
||||
value and exits are optionally generated between adjacent rooms according
|
||||
to the `build_exits` value.
|
||||
|
||||
"""
|
||||
list_map = map.split('\n')
|
||||
return [character.decode('UTF-8') if isinstance(character, basestring)
|
||||
else character for character in list_map]
|
||||
|
||||
# Split map string to list of rows and create reference list.
|
||||
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