da da da.
This commit is contained in:
parent
043cdfc230
commit
db12c674ef
15 changed files with 734 additions and 212 deletions
|
@ -1,6 +1,7 @@
|
|||
from evennia import default_cmds, create_object, search_tag
|
||||
from evennia.utils import inherits_from
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
from evennia.prototypes import spawner
|
||||
|
||||
from commands.command import Command
|
||||
from typeclasses.exits import BaseDoor
|
||||
|
@ -24,6 +25,7 @@ def _descdoor_quit(caller):
|
|||
caller.attributes.remove("evmenu_target")
|
||||
caller.msg("Exited editor.")
|
||||
|
||||
|
||||
class CmdDescDoor(Command):
|
||||
"""
|
||||
describe a BaseDoor in the current room.
|
||||
|
@ -129,6 +131,7 @@ class CmdOpen(default_cmds.CmdOpen):
|
|||
back_exit.db.return_exit = new_exit
|
||||
return new_exit
|
||||
|
||||
|
||||
class CmdUpdateLightState(Command):
|
||||
"""
|
||||
update room light state.
|
||||
|
@ -160,14 +163,15 @@ class CmdUpdateLightState(Command):
|
|||
target.check_light_state()
|
||||
caller.msg("Performed update on {}!".format(target.key))
|
||||
|
||||
|
||||
class CmdZone(Command):
|
||||
"""
|
||||
creates, deletes or lists zones
|
||||
|
||||
Usage:
|
||||
zone[/list||/del||/addroom] [zonename] [= room]
|
||||
zone[/add||/del||/map] [zonename] [= room|size]
|
||||
|
||||
Creates a new zone.
|
||||
Manages zones.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -182,73 +186,70 @@ class CmdZone(Command):
|
|||
|
||||
caller = self.caller
|
||||
|
||||
if "list" in self.switches:
|
||||
string = "";
|
||||
zones = search_tag(key="zone", category="general")
|
||||
for zone in zones:
|
||||
string += "|c{}|n ({})\n".format(zone.name, zone.dbref)
|
||||
rooms = search_tag(key=zone.name, category="zoneId")
|
||||
for room in rooms:
|
||||
string += "- {} ({})\n".format(room.name, room.dbref)
|
||||
|
||||
caller.msg("Zones found: \n" + string)
|
||||
return
|
||||
|
||||
if not self.args:
|
||||
string = "Usage: zone[/list||/del||/addroom] [zonename] [= room]"
|
||||
caller.msg(string)
|
||||
if [ele for ele in ["del", "add", "map"] if(ele in self.switches)] and not self.args:
|
||||
caller.msg(self.get_help(caller, self.cmdset))
|
||||
return
|
||||
|
||||
if "del" in self.switches:
|
||||
self.delete_zone(self.args)
|
||||
elif "addroom" in self.switches:
|
||||
self.add_room_to_zone(self.lhs, self.rhs)
|
||||
self.delete_zone()
|
||||
elif "map" in self.switches:
|
||||
self.print_map()
|
||||
elif "add" in self.switches:
|
||||
zone, errors = Zone.create(key=self.lhs, size=self.rhs)
|
||||
if not errors:
|
||||
caller.msg("Created zone |w{}|n.".format(zone.name))
|
||||
else:
|
||||
caller.msg("Errors creating zone:|n{}|n.".format(errors))
|
||||
else:
|
||||
zone = create_object(Zone, key=self.args)
|
||||
caller.msg("Created zone |w{}|n.".format(zone.name))
|
||||
string = ""
|
||||
zones = search_tag(key="zone", category="general")
|
||||
for zone in zones:
|
||||
string += "|c{}|n ({})\n".format(zone.name, zone.dbref)
|
||||
rooms = search_tag(key=zone.name, category="zoneId")
|
||||
for room in rooms:
|
||||
string += "- {} ({}) ({},{})\n".format(room.name, room.dbref, room.db.x, room.db.y)
|
||||
|
||||
def delete_zone(self, zone_string):
|
||||
caller.msg("Zones found: \n" + string)
|
||||
|
||||
def print_map(self):
|
||||
caller = self.caller
|
||||
zone = caller.search(zone_string, global_search=True, exact=True)
|
||||
zone = caller.search(self.args, global_search=True, exact=True)
|
||||
if not zone:
|
||||
return
|
||||
|
||||
map_str = ""
|
||||
for y in range(zone.db.size):
|
||||
for x in range(zone.db.size):
|
||||
map_str += zone.ndb.map[x][y]['room_map_icon']
|
||||
|
||||
map_str += '|/'
|
||||
|
||||
caller.msg(map_str)
|
||||
|
||||
def delete_zone(self):
|
||||
caller = self.caller
|
||||
zone = caller.search(self.args, global_search=True, exact=True)
|
||||
if not zone:
|
||||
return
|
||||
if not inherits_from(zone, Zone):
|
||||
caller.msg("{} is not a valid zone.",format(zone.name))
|
||||
caller.msg("{} is not a valid zone.".format(zone.name))
|
||||
return
|
||||
|
||||
key = zone.name
|
||||
zone.delete()
|
||||
caller.msg("Zone {} deleted.".format(key))
|
||||
|
||||
def add_room_to_zone(self, zone_string, room_string):
|
||||
caller = self.caller
|
||||
zone = caller.search(zone_string, global_search=True, exact=True)
|
||||
if not zone:
|
||||
return
|
||||
if not inherits_from(zone, Zone):
|
||||
caller.msg("{} is not a valid zone.",format(zone.name))
|
||||
return
|
||||
|
||||
room = caller.search(room_string, global_search=True)
|
||||
if not room:
|
||||
return
|
||||
if not inherits_from(room, Room):
|
||||
caller.msg("{} is not a valid room.",format(room.name))
|
||||
return
|
||||
|
||||
zone.add_room(room)
|
||||
caller.msg("{} added to zone {}.".format(room.name, zone.name))
|
||||
|
||||
class CmdAddToZone(Command):
|
||||
"""
|
||||
add a room to a zone
|
||||
|
||||
Usage:
|
||||
@addtozone obj = zone
|
||||
addtozone obj = zone,x,y
|
||||
|
||||
Adds a room to an existing zone.
|
||||
"""
|
||||
key = "@addtozone"
|
||||
key = "addtozone"
|
||||
locks = "cmd:perm(zone) or perm(Builders)"
|
||||
help_category = "Building"
|
||||
|
||||
|
@ -258,28 +259,124 @@ class CmdAddToZone(Command):
|
|||
"""
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if self.rhs:
|
||||
# We have an =
|
||||
zone = caller.search(self.rhs, global_search=True, exact=True)
|
||||
if not zone:
|
||||
self.msg("Zone %s doesn't exist." % self.rhs)
|
||||
return
|
||||
if not utils.inherits_from(zone, Zone):
|
||||
self.msg("{r%s is not a valid zone.{n" % zone.name)
|
||||
return
|
||||
|
||||
room = caller.search(self.lhs)
|
||||
if not room:
|
||||
self.msg("{rRoom %s doesn't exist.{n" % self.lhs)
|
||||
return
|
||||
if not utils.inherits_from(room, BaseRoom):
|
||||
self.msg("{r%s is not a valid room.{n" % room.name)
|
||||
return
|
||||
|
||||
room.add_to_zone(zone.name)
|
||||
self.msg("Room %s (%s) added to zone %s (%s)." % (room.name, room.dbref, zone.name, zone.dbref))
|
||||
|
||||
else:
|
||||
self.msg("{rUsage: @addtozone obj = zone{n")
|
||||
if len(self.rhslist) < 3:
|
||||
caller.msg(self.get_help(caller, self.cmdset))
|
||||
return
|
||||
|
||||
zone_key, x, y = self.rhslist
|
||||
|
||||
if zone_key and x and y:
|
||||
zone = caller.search(zone_key, global_search=True, exact=True)
|
||||
if not zone:
|
||||
caller.msg("Zone {} doesn't exist.".format(zone_key))
|
||||
return
|
||||
if not inherits_from(zone, Zone):
|
||||
caller.msg("|r{} is not a valid zone.|n".format(zone.name))
|
||||
return
|
||||
|
||||
room = caller.search(self.lhs, global_search=True, nofound_string="|rRoom {} doesn't exist.|n".format(self.lhs))
|
||||
if not room:
|
||||
return
|
||||
if not inherits_from(room, Room):
|
||||
caller.msg("|r{} is not a valid room.|n".format(room.name))
|
||||
return
|
||||
try:
|
||||
if room.db.zone:
|
||||
caller.msg("|r{} is already assigned to zone {}.|n".format(room.name, zone.name))
|
||||
return
|
||||
zone.add_room(room, x, y)
|
||||
except ValueError as ve:
|
||||
caller.msg(ve.args[0])
|
||||
return
|
||||
|
||||
caller.msg("Room {} ({}) added to zone {} ({}).".format(room.name, room.dbref, zone.name, zone.dbref))
|
||||
else:
|
||||
caller.msg(self.get_help(caller, self.cmdset))
|
||||
return
|
||||
|
||||
|
||||
class CmdPopen(Command):
|
||||
"""
|
||||
open a new exit from prototype linking two rooms
|
||||
|
||||
Usage:
|
||||
popen <prototype>[;alias;alias..] [,<return exit>[;alias;..]]] = <origin>,<destination>
|
||||
|
||||
Handles the creation of exits. If a destination is given, the exit
|
||||
will point there. The <return exit> argument sets up an exit at the
|
||||
destination leading back to the current room. Destination name
|
||||
can be given both as a #dbref and a name, if that name is globally
|
||||
unique.
|
||||
|
||||
"""
|
||||
key = "popen"
|
||||
locks = "cmd:perm(open) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
This is where the processing starts.
|
||||
Uses the ObjManipCommand.parser() for pre-processing
|
||||
as well as the self.create_exit() method.
|
||||
"""
|
||||
caller = self.caller
|
||||
|
||||
if not self.args or not self.rhs or len(self.rhslist) != 2:
|
||||
caller.msg(self.get_help(caller, self.cmdset))
|
||||
return
|
||||
|
||||
exit_prototype = self.lhs_objs[0]["name"]
|
||||
exit_aliases = self.lhs_objs[0]["aliases"]
|
||||
|
||||
location_name, destination_name = self.rhslist
|
||||
|
||||
# first, check if the destination and origin exist.
|
||||
destination = caller.search(destination_name, global_search=True)
|
||||
if not destination:
|
||||
return
|
||||
|
||||
location = caller.search(location_name, global_search=True)
|
||||
if not location:
|
||||
return
|
||||
|
||||
try:
|
||||
exit_obj, *rest = spawner.spawn(exit_prototype)
|
||||
except KeyError:
|
||||
caller.msg("Prototype {} not found".format(exit_prototype))
|
||||
return
|
||||
|
||||
exit_obj.location = location
|
||||
exit_obj.destination = destination
|
||||
exit_obj.aliases.add(exit_aliases)
|
||||
|
||||
return_exit_object = None
|
||||
|
||||
if len(self.lhs_objs) == 2:
|
||||
return_exit_prototype = self.lhs_objs[1]["name"]
|
||||
return_exit_aliases = self.lhs_objs[1]["aliases"]
|
||||
|
||||
try:
|
||||
return_exit_object, *rest = spawner.spawn(return_exit_prototype)
|
||||
except KeyError:
|
||||
caller.msg("Return prototype {} not found, rolling back...".format(return_exit_prototype))
|
||||
exit_obj.delete()
|
||||
return
|
||||
|
||||
return_exit_object.location = destination
|
||||
return_exit_object.destination = location
|
||||
|
||||
# BaseDoor requires a return exit
|
||||
if inherits_from(exit_obj, "typeclasses.exits.BaseDoor"):
|
||||
if not return_exit_object:
|
||||
return_exit_object, *rest = spawner.spawn(exit_prototype)
|
||||
return_exit_object.location = destination
|
||||
return_exit_object.destination = location
|
||||
|
||||
exit_obj.db.return_exit = return_exit_object
|
||||
return_exit_object.db.return_exit = exit_obj
|
||||
|
||||
caller.msg("Created exit {} from {} to {}.".format(exit_obj.name, location.name, destination.name))
|
||||
if return_exit_object:
|
||||
caller.msg("Created exit {} from {} to {}.".format(return_exit_object.name, destination.name, location.name))
|
||||
|
|
|
@ -14,7 +14,7 @@ from evennia.utils import inherits_from
|
|||
from evennia.utils.utils import list_to_string
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
|
||||
from utils.building import create_room, create_exit
|
||||
from utils.building import create_exit
|
||||
from utils.utils import has_tag, fmt_light, fmt_dark, toggle_effect, has_effect, indefinite_article
|
||||
from typeclasses.exits import BaseDoor
|
||||
from typeclasses.rooms import IndoorRoom
|
||||
|
@ -47,6 +47,39 @@ class Command(default_cmds.MuxCommand):
|
|||
|
||||
"""
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
We need to expand the default parsing to get all
|
||||
the cases, see the module doc.
|
||||
"""
|
||||
# get all the normal parsing done (switches etc)
|
||||
super().parse()
|
||||
|
||||
obj_defs = ([], []) # stores left- and right-hand side of '='
|
||||
obj_attrs = ([], []) # "
|
||||
|
||||
for iside, arglist in enumerate((self.lhslist, self.rhslist)):
|
||||
# lhslist/rhslist is already split by ',' at this point
|
||||
for objdef in arglist:
|
||||
aliases, option, attrs = [], None, []
|
||||
if ":" in objdef:
|
||||
objdef, option = [part.strip() for part in objdef.rsplit(":", 1)]
|
||||
if ";" in objdef:
|
||||
objdef, aliases = [part.strip() for part in objdef.split(";", 1)]
|
||||
aliases = [alias.strip() for alias in aliases.split(";") if alias.strip()]
|
||||
if "/" in objdef:
|
||||
objdef, attrs = [part.strip() for part in objdef.split("/", 1)]
|
||||
attrs = [part.strip().lower() for part in attrs.split("/") if part.strip()]
|
||||
# store data
|
||||
obj_defs[iside].append({"name": objdef, "option": option, "aliases": aliases})
|
||||
obj_attrs[iside].append({"name": objdef, "attrs": attrs})
|
||||
|
||||
# store for future access
|
||||
self.lhs_objs = obj_defs[0]
|
||||
self.rhs_objs = obj_defs[1]
|
||||
self.lhs_objattr = obj_attrs[0]
|
||||
self.rhs_objattr = obj_attrs[1]
|
||||
|
||||
def at_post_cmd(self):
|
||||
caller = self.caller
|
||||
prompt = "|_|/°|w%s|n°: " % (caller.location)
|
||||
|
@ -103,7 +136,7 @@ class CmdGet(Command):
|
|||
caller.msg("Get what?")
|
||||
return
|
||||
|
||||
if inherits_from(caller.location, IndoorRoom) and not caller.location.db.is_lit:
|
||||
if inherits_from(caller.location, IndoorRoom) and not caller.location.db.is_lit and not caller.is_superuser:
|
||||
caller.msg("Its too dark to get anything.")
|
||||
return
|
||||
|
||||
|
@ -543,7 +576,12 @@ class CmdInventory(Command):
|
|||
|
||||
class CmdCast(Command):
|
||||
"""
|
||||
cast a spell.
|
||||
|
||||
Usage:
|
||||
cast <spell> [at <target>]
|
||||
|
||||
Casts a spell.
|
||||
"""
|
||||
key = "cast"
|
||||
aliases = ["cs"]
|
||||
|
@ -555,16 +593,18 @@ class CmdCast(Command):
|
|||
"""
|
||||
Handle parsing of:
|
||||
::
|
||||
<spell> [at <target>]
|
||||
<spell> [at|on <target>]
|
||||
"""
|
||||
self.args = args = self.args.strip().lower()
|
||||
spell_name, target_name = "", ""
|
||||
|
||||
if " at " in args:
|
||||
spell_name, *rest = args.split(" at ", 1)
|
||||
target_name = rest[0] if rest else ""
|
||||
elif " on " in args:
|
||||
spell_name, *rest = args.split(" on ", 1)
|
||||
else:
|
||||
spell_name = args
|
||||
spell_name, rest = args, []
|
||||
|
||||
target_name = rest[0] if rest else ""
|
||||
|
||||
self.spell_name = spell_name.strip()
|
||||
self.target_name = target_name.strip()
|
||||
|
@ -573,7 +613,7 @@ class CmdCast(Command):
|
|||
caller = self.caller
|
||||
|
||||
if not self.args or not self.spell_name:
|
||||
caller.msg("Usage: cast <spell> [at <target>]")
|
||||
caller.msg(self.get_help(caller, self.cmdset))
|
||||
return
|
||||
|
||||
spell_id = self.spell_name.replace(' ', '_')
|
||||
|
@ -600,14 +640,16 @@ class CmdTestPy(Command):
|
|||
def func(self):
|
||||
caller = self.caller
|
||||
|
||||
caller.msg(self.lhs_objs)
|
||||
|
||||
pattern = re.compile(r'''((?:[^ "']|"[^"]*"|'[^']*')+)''')
|
||||
self.args = pattern.split(self.lhs)[1::2]
|
||||
|
||||
# room = create_room(self.args[0].strip(" \"'"), int(self.args[1].strip(" \"'")), int(self.args[2].strip(" \"'")), self.args[3].strip(" \"'"))
|
||||
# caller.msg(room)
|
||||
|
||||
exit = create_exit("exit_empty", caller.location, "north")
|
||||
caller.msg(exit)
|
||||
# exit = create_exit("exit_empty", caller.location, "north")
|
||||
# caller.msg(exit)
|
||||
|
||||
# caller.msg(dkmud_oob=({"testarg": "valuetestarg"}))
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ from commands.builder import CmdUpdateLightState
|
|||
from commands.builder import CmdOpen
|
||||
from commands.builder import CmdDescDoor
|
||||
from commands.builder import CmdZone
|
||||
from commands.builder import CmdAddToZone
|
||||
from commands.builder import CmdPopen
|
||||
|
||||
from utils.crafting import CmdCraft
|
||||
|
||||
|
@ -70,9 +72,12 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
|||
self.add(CmdOpen())
|
||||
self.add(CmdDescDoor())
|
||||
self.add(CmdZone())
|
||||
self.add(CmdAddToZone())
|
||||
self.add(CmdPopen())
|
||||
|
||||
self.add(CmdCraft())
|
||||
|
||||
|
||||
class AccountCmdSet(default_cmds.AccountCmdSet):
|
||||
"""
|
||||
This is the cmdset available to the Account at all times. It is
|
||||
|
|
|
@ -39,6 +39,7 @@ GLOBAL_SCRIPTS = {
|
|||
'repeats': 0, 'interval': 1}
|
||||
}
|
||||
|
||||
PROTOTYPE_MODULES += ["world.tutorial_prototypes"]
|
||||
CRAFT_RECIPE_MODULES = ['world.recipes_base']
|
||||
|
||||
######################################################################
|
||||
|
|
|
@ -36,8 +36,6 @@ class Mob(Object):
|
|||
pass
|
||||
|
||||
def think(self):
|
||||
|
||||
|
||||
if not self.db.action:
|
||||
self.db.action = create_object(ActionIdle, key="action_idle")
|
||||
self.db.action.prepare(self)
|
||||
|
|
|
@ -36,6 +36,8 @@ class Room(DefaultRoom):
|
|||
self.db.x = 0
|
||||
self.db.y = 0
|
||||
|
||||
self.db.map_icon = '|w⊡|n'
|
||||
|
||||
self.db.zone = None
|
||||
|
||||
|
||||
|
@ -54,6 +56,8 @@ class IndoorRoom(Room):
|
|||
"You can't see anything, but the air is damp. It feels like you are far underground.",
|
||||
)
|
||||
|
||||
map_icon = '|w□|n'
|
||||
|
||||
def at_object_creation(self):
|
||||
super().at_object_creation()
|
||||
self.locks.add("search:all()")
|
||||
|
@ -228,9 +232,28 @@ class Zone(DefaultRoom):
|
|||
provide path-finding capabilities to mob.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def create(cls, key, account=None, **kwargs):
|
||||
description = kwargs.pop("description", "This is a zone.")
|
||||
|
||||
size = kwargs.pop("size")
|
||||
size = MAP_SIZE if not size else size
|
||||
|
||||
zone, errors = super(Zone, cls).create(key, account=account, description=description, **kwargs)
|
||||
|
||||
if not errors:
|
||||
try:
|
||||
zone.db.size = int(size)
|
||||
except ValueError:
|
||||
errors.append("Size must be an integer.")
|
||||
|
||||
return zone, errors
|
||||
|
||||
def at_object_creation(self):
|
||||
super().at_object_creation()
|
||||
|
||||
self.db.size = MAP_SIZE
|
||||
|
||||
self.tags.add("zone", category="general")
|
||||
self.locks.add(";".join(["get:false()", "puppet:false()", "view:perm(zone) or perm(Builder)"]))
|
||||
|
||||
|
@ -239,41 +262,27 @@ class Zone(DefaultRoom):
|
|||
def at_init(self):
|
||||
super().at_init()
|
||||
# when reloaded recalculate path-finding data
|
||||
self.create_paths()
|
||||
self._create_paths()
|
||||
|
||||
def create_paths(self):
|
||||
self.ndb.sp_graph = spath.Graph()
|
||||
self.ndb.map = [[{"room_id": -1} for i in range(MAP_SIZE)] for j in range(MAP_SIZE)]
|
||||
def add_room(self, room, x, y):
|
||||
xi = int(x)
|
||||
yi = int(y)
|
||||
|
||||
rooms = search_tag(key=self.name, category="zoneId")
|
||||
if xi < 0 or xi >= self.db.size or yi < 0 or yi >= self.db.size:
|
||||
raise ValueError("Coordinates must be between 0 and {}.".format(self.db.size - 1))
|
||||
|
||||
for room in rooms:
|
||||
self.add_room(room)
|
||||
if self.ndb.map[xi][yi]['room_id'] != -1:
|
||||
raise ValueError("Coordinates ({},{}) are not empty.".format(x, y))
|
||||
|
||||
def add_room(self, room):
|
||||
# add to map
|
||||
if 0 <= room.db.x < MAP_SIZE and 0 <= room.db.y < MAP_SIZE and self.ndb.map[room.db.x][room.db.y]["room_id"] == -1:
|
||||
self.ndb.map[room.db.x][room.db.y]["room_id"] = room.dbref
|
||||
else:
|
||||
logger.log_err("Cannot add room {} to {} at position {}:{}.".format(room.dbref, self.dbref, room.db.x, room.db.y))
|
||||
raise Exception("Cannot add room {} to {} at position {}:{}.".format(room.dbref, self.dbref, room.db.x, room.db.y))
|
||||
room.db.x = xi
|
||||
room.db.y = yi
|
||||
|
||||
# avoid inserting room into graph if is already inserted
|
||||
if not self.ndb.sp_graph.is_vertex(room):
|
||||
self.ndb.sp_graph.add_vertex(room)
|
||||
room.tags.add(self.name, category="zoneId")
|
||||
room.db.zone = self
|
||||
|
||||
self.update_room_exits(room)
|
||||
|
||||
def update_room_exits(self, room):
|
||||
if self.ndb.sp_graph.is_vertex(room):
|
||||
for ex in room.exits: # iterate exits in the room
|
||||
if not self.ndb.sp_graph.is_edge(room, ex.destination):
|
||||
self.ndb.sp_graph.add_edge(room, ex.destination, 1, ex.name)
|
||||
room.db.zone = self.dbref
|
||||
self._add_room_to_graph(room)
|
||||
|
||||
def remove_room_exit(self, exit_obj):
|
||||
if self.ndb.sp_graph.is_vertex(exit_obj.location) and self.ndb.sp_graph.is_edge(exit_obj.location, exit_obj.destination):
|
||||
if self.ndb.sp_graph.is_vertex(exit_obj.location) and self.ndb.sp_graph.is_edge(exit_obj.location,
|
||||
exit_obj.destination):
|
||||
self.ndb.sp_graph.del_edge(exit_obj.location, exit_obj.destination)
|
||||
|
||||
def delete(self):
|
||||
|
@ -285,3 +294,35 @@ class Zone(DefaultRoom):
|
|||
|
||||
def shortest_path(self, start, end):
|
||||
return spath.shortestPath(self.ndb.sp_graph, start, end)
|
||||
|
||||
def _create_paths(self):
|
||||
self.ndb.sp_graph = spath.Graph()
|
||||
self.ndb.map = [[{'room_id': -1, 'room_map_icon': "|=g∙|n"} for i in range(self.db.size)] for j in range(self.db.size)]
|
||||
|
||||
rooms = search_tag(key=self.name, category="zoneId")
|
||||
|
||||
for room in rooms:
|
||||
self._add_room_to_graph(room)
|
||||
|
||||
def _add_room_to_graph(self, room):
|
||||
# add to map
|
||||
if 0 <= room.db.x < self.db.size and 0 <= room.db.y < self.db.size and self.ndb.map[room.db.x][room.db.y]["room_id"] == -1:
|
||||
self.ndb.map[room.db.x][room.db.y]['room_id'] = room.dbref
|
||||
self.ndb.map[room.db.x][room.db.y]['room_map_icon'] = room.db.map_icon
|
||||
else:
|
||||
logger.log_err("Cannot add room {} to {} at position {}:{}.".format(room.dbref, self.dbref, room.db.x, room.db.y))
|
||||
raise Exception("Cannot add room {} to {} at position {}:{}.".format(room.dbref, self.dbref, room.db.x, room.db.y))
|
||||
|
||||
# avoid inserting room into graph if is already inserted
|
||||
if not self.ndb.sp_graph.is_vertex(room):
|
||||
self.ndb.sp_graph.add_vertex(room)
|
||||
room.tags.add(self.name, category="zoneId")
|
||||
room.db.zone = self
|
||||
|
||||
self._update_room_exits(room)
|
||||
|
||||
def _update_room_exits(self, room):
|
||||
if self.ndb.sp_graph.is_vertex(room):
|
||||
for ex in room.exits: # iterate exits in the room
|
||||
if not self.ndb.sp_graph.is_edge(room, ex.destination):
|
||||
self.ndb.sp_graph.add_edge(room, ex.destination, 1, ex.name)
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
from evennia.contrib.ingame_python import typeclasses
|
||||
from evennia.prototypes import spawner
|
||||
from evennia.utils import inherits_from
|
||||
from evennia.utils.search import search_object
|
||||
|
||||
def create_room(room_prototype, x, y, zone_id):
|
||||
zones = search_object(zone_id, typeclass="typeclasses.rooms.Zone", exact=True)
|
||||
if not zones:
|
||||
raise Exception("create_room: cannot find zone {}".format(zone_id))
|
||||
|
||||
zone = zones[0]
|
||||
room, *rest = spawner.spawn(room_prototype)
|
||||
room.db.x = x
|
||||
room.db.y = y
|
||||
|
||||
zone.add_room(room)
|
||||
|
||||
return room
|
||||
|
||||
|
||||
def create_exit(exit_prototype, location, direction):
|
||||
x = location.db.x
|
||||
|
|
|
@ -120,6 +120,7 @@ a full example of the components for creating a sword from base components.
|
|||
"""
|
||||
|
||||
from copy import copy
|
||||
from evennia import logger
|
||||
from evennia.utils.utils import callables_from_module, inherits_from, make_iter, iter_to_string
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.command import Command
|
||||
|
@ -232,7 +233,7 @@ class CraftingRecipeBase:
|
|||
**kwargs: Any optional properties relevant to this send.
|
||||
|
||||
"""
|
||||
self.crafter.msg(message, {"type": "crafting"})
|
||||
self.crafter.msg(message, oob=({"type": "crafting"}))
|
||||
|
||||
def pre_craft(self, **kwargs):
|
||||
"""
|
||||
|
@ -382,6 +383,7 @@ class CraftingRecipe(CraftingRecipeBase):
|
|||
## Properties on the class level:
|
||||
|
||||
- `name` (str): The name of this recipe. This should be globally unique.
|
||||
- 'crafting_time' (int): The time needed for crafting.
|
||||
|
||||
### tools
|
||||
|
||||
|
@ -540,7 +542,9 @@ class CraftingRecipe(CraftingRecipeBase):
|
|||
# general craft-failure msg to show after other error-messages.
|
||||
failure_message = ""
|
||||
# show after a successful craft
|
||||
success_message = "You successfully craft {outputs}!"
|
||||
success_message = "You craft {outputs}."
|
||||
# recipe crafting time
|
||||
crafting_time = 1
|
||||
|
||||
def __init__(self, crafter, *inputs, **kwargs):
|
||||
"""
|
||||
|
@ -921,6 +925,62 @@ def craft(crafter, recipe_name, *inputs, raise_exception=False, **kwargs):
|
|||
return recipe.craft(raise_exception=raise_exception)
|
||||
|
||||
|
||||
def can_craft(crafter, recipe_name, *inputs, **kwargs):
|
||||
"""
|
||||
Access function.Check if crafter can craft a given recipe from a source recipe module.
|
||||
|
||||
Args:
|
||||
crafter (Object): The one doing the crafting.
|
||||
recipe_name (str): The `CraftRecipe.name` to use. This uses fuzzy-matching
|
||||
if the result is unique.
|
||||
*inputs: Suitable ingredients and/or tools (Objects) to use in the crafting.
|
||||
raise_exception (bool, optional): If crafting failed for whatever
|
||||
reason, raise `CraftingError`. The user will still be informed by the
|
||||
recipe.
|
||||
**kwargs: Optional kwargs to pass into the recipe (will passed into
|
||||
recipe.craft).
|
||||
|
||||
Returns:
|
||||
list: Error messages, if any.
|
||||
|
||||
Raises:
|
||||
CraftingError: If `raise_exception` is True and crafting failed to
|
||||
produce an output. KeyError: If `recipe_name` failed to find a
|
||||
matching recipe class (or the hit was not precise enough.)
|
||||
|
||||
Notes:
|
||||
If no recipe_module is given, will look for a list `settings.CRAFT_RECIPE_MODULES` and
|
||||
lastly fall back to the example module `"evennia.contrib."`
|
||||
|
||||
"""
|
||||
# delayed loading/caching of recipes
|
||||
_load_recipes()
|
||||
|
||||
RecipeClass = search_recipe(crafter, recipe_name)
|
||||
|
||||
if not RecipeClass:
|
||||
raise KeyError(
|
||||
f"No recipe in settings.CRAFT_RECIPE_MODULES has a name matching {recipe_name}"
|
||||
)
|
||||
recipe = RecipeClass(crafter, *inputs, **kwargs)
|
||||
|
||||
if recipe.allow_craft:
|
||||
|
||||
# override/extend craft_kwargs from initialization.
|
||||
craft_kwargs = copy(recipe.craft_kwargs)
|
||||
craft_kwargs.update(kwargs)
|
||||
|
||||
try:
|
||||
recipe.pre_craft(**craft_kwargs)
|
||||
except (CraftingError, CraftingValidationError):
|
||||
logger.log_err(CraftingValidationError.args)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def search_recipe(crafter, recipe_name):
|
||||
# delayed loading/caching of recipes
|
||||
_load_recipes()
|
||||
|
@ -933,7 +993,7 @@ def search_recipe(crafter, recipe_name):
|
|||
# try in-match
|
||||
matches = [key for key in _RECIPE_CLASSES if recipe_name in key]
|
||||
if len(matches) == 1:
|
||||
recipe_class = matches[0]
|
||||
recipe_class = _RECIPE_CLASSES.get(matches[0], None)
|
||||
|
||||
return recipe_class
|
||||
|
||||
|
@ -1068,13 +1128,18 @@ class CmdCraft(Command):
|
|||
return
|
||||
tools.append(obj)
|
||||
|
||||
if not search_recipe(caller, self.recipe):
|
||||
recipe_cls = search_recipe(caller, self.recipe)
|
||||
if not recipe_cls:
|
||||
caller.msg("You don't know how to craft {} {}.".format(indefinite_article(self.recipe), self.recipe))
|
||||
return
|
||||
|
||||
tools_and_ingredients = tools + ingredients
|
||||
if not can_craft(caller, recipe_cls.name, *tools_and_ingredients):
|
||||
return
|
||||
|
||||
toggle_effect(caller, "is_busy")
|
||||
caller.msg("You start crafting {} {}.".format(indefinite_article(self.recipe), self.recipe))
|
||||
action_script = create_script("utils.crafting.CmdCraftComplete", obj=caller, interval=15, attributes=[("recipe", self.recipe), ("tools_and_ingredients", tools + ingredients)])
|
||||
caller.msg("You start crafting {} {}.".format(indefinite_article(recipe_cls.name), recipe_cls.name))
|
||||
action_script = create_script("utils.crafting.CmdCraftComplete", obj=caller, interval=recipe_cls.crafting_time, attributes=[("recipe", recipe_cls.name), ("tools_and_ingredients", tools_and_ingredients)])
|
||||
caller.db.current_action = action_script
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from evennia.prototypes import spawner
|
||||
|
||||
|
||||
def has_tag(obj, key, category):
|
||||
return obj.tags.get(key=key, category=category) != None;
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
# -must- be separated by at least one comment-line.
|
||||
@tel #2
|
||||
#
|
||||
zone/add tutorial_zone = 32
|
||||
#
|
||||
|
||||
@dig/tel ruined room;start_00:typeclasses.rooms.IndoorRoom
|
||||
#
|
||||
@desc here =
|
||||
|
@ -23,6 +26,7 @@ clutched to the handle of a broken spear.
|
|||
#
|
||||
@lock skeleton = search:all()
|
||||
#
|
||||
|
||||
@dig/tel long hall;hall;start_01:typeclasses.rooms.IndoorRoom
|
||||
#
|
||||
@desc start_01 =
|
||||
|
@ -59,6 +63,7 @@ filling the floor with debris.
|
|||
#delle assi portanti. Una parte delle pietre di copertura sono rovinate al suolo,
|
||||
#riempiendo il pavimento di detriti.
|
||||
#
|
||||
|
||||
@dig/tel old guardhouse;guardhouse;start_02:typeclasses.rooms.IndoorRoom
|
||||
#
|
||||
@desc start_02 =
|
||||
|
@ -99,17 +104,15 @@ A big oak door, reinforced with iron bars across its frame.
|
|||
It bears marks and burns all over its surface but hasn't been breached during the
|
||||
siege.
|
||||
#
|
||||
zone tutorial_zone
|
||||
addtozone start_00 = tutorial_zone, 16, 30
|
||||
#
|
||||
zone/addroom tutorial_zone = start_door_00
|
||||
addtozone start_01 = tutorial_zone, 16, 29
|
||||
#
|
||||
zone/addroom tutorial_zone = start_door_01
|
||||
addtozone start_02 = tutorial_zone, 15, 29
|
||||
#
|
||||
zone/addroom tutorial_zone = start_door_02
|
||||
addtozone start_03 = tutorial_zone, 17, 29
|
||||
#
|
||||
zone/addroom tutorial_zone = start_door_03
|
||||
#
|
||||
zone/addroom tutorial_zone = start_door_04
|
||||
addtozone start_04 = tutorial_zone, 18, 29
|
||||
#
|
||||
@tel start_00
|
||||
#
|
||||
|
|
45
world/batches/tutorial.ev
Normal file
45
world/batches/tutorial.ev
Normal file
|
@ -0,0 +1,45 @@
|
|||
# We start from limbo. Remember that every command in the batchfile
|
||||
# -must- be separated by at least one comment-line.
|
||||
@tel #2
|
||||
#
|
||||
zone/add tutorial_zone = 32
|
||||
#
|
||||
# rooms
|
||||
spawn/noloc start_00
|
||||
#
|
||||
spawn/noloc start_01
|
||||
#
|
||||
spawn/noloc start_02
|
||||
#
|
||||
spawn/noloc start_03
|
||||
#
|
||||
spawn/noloc start_04
|
||||
#
|
||||
# exits
|
||||
popen start_door_00 = start_00,start_01
|
||||
#
|
||||
popen start_door_01 = start_01,start_02
|
||||
#
|
||||
popen start_door_02 = start_01,start_03
|
||||
#
|
||||
popen start_door_03 = start_03,start_04
|
||||
#
|
||||
#add rooms to starting zone
|
||||
addtozone start_00 = tutorial_zone, 16, 30
|
||||
#
|
||||
addtozone start_01 = tutorial_zone, 16, 29
|
||||
#
|
||||
addtozone start_02 = tutorial_zone, 15, 29
|
||||
#
|
||||
addtozone start_03 = tutorial_zone, 17, 29
|
||||
#
|
||||
addtozone start_04 = tutorial_zone, 18, 29
|
||||
#
|
||||
tel start_00
|
||||
#
|
||||
spawn f_armored_skeleton
|
||||
#
|
||||
tel start_01
|
||||
#
|
||||
spawn f_rubble_01
|
||||
#
|
|
@ -48,133 +48,210 @@ See the `spawn` command and `evennia.prototypes.spawner.spawn` for more info.
|
|||
|
||||
"""
|
||||
|
||||
ROOM_EMPTY = {
|
||||
"prototype_key": "room_empty",
|
||||
# TEMPLATES
|
||||
|
||||
ROOM = {
|
||||
"prototype_key": "room",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "empty room",
|
||||
"desc": "An empty room.",
|
||||
"map_icon": "|w□|n",
|
||||
"typeclass": "typeclasses.rooms.IndoorRoom"
|
||||
}
|
||||
|
||||
EXIT_EMPTY = {
|
||||
"prototype_key": "exit_empty",
|
||||
EXIT = {
|
||||
"prototype_key": "exit",
|
||||
"prototype_tags": ["room", "exit"],
|
||||
"key": "corridor",
|
||||
"desc": "An empty corridor.",
|
||||
"typeclass": "typeclasses.exits.BaseDoor"
|
||||
}
|
||||
|
||||
BROKEN_CROWN = {
|
||||
"prototype_key": "broken_crown",
|
||||
"key": "broken crown",
|
||||
"desc": "An old iron crown, dented and covered in rust.",
|
||||
ITEM = {
|
||||
"prototype_key": "item",
|
||||
"prototype_tags": ["item"],
|
||||
"key": "item",
|
||||
"desc": "An unremarkable item made of dreams.",
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
}
|
||||
|
||||
ITEM_EQUIPPABLE = {
|
||||
"prototype_key": "item_equippable",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"key": "equippable item",
|
||||
"desc": "An unremarkable equippable item made of dreams.",
|
||||
"typeclass": "typeclasses.objects.EquippableItem",
|
||||
"slot": 'head'
|
||||
}
|
||||
|
||||
|
||||
MULTICOLORED_ROBE = {
|
||||
"prototype_key": "multicolored robe",
|
||||
"key": "multicolored robe",
|
||||
"desc": "A long robe, made of many different colored cloth patches.",
|
||||
"typeclass": "typeclasses.objects.EquippableItem",
|
||||
"slot": 'torso'
|
||||
}
|
||||
|
||||
PLAIN_TROUSERS = {
|
||||
"prototype_key": "plain trousers",
|
||||
"key": "plain trousers",
|
||||
"desc": "Simple but robust cloth trousers.",
|
||||
"typeclass": "typeclasses.objects.EquippableItem",
|
||||
"slot": 'legs'
|
||||
}
|
||||
|
||||
LEATHER_BOOTS = {
|
||||
"prototype_key": "leather boots",
|
||||
"key": "leather boots",
|
||||
"desc": "A worn pair of leather boots.",
|
||||
"typeclass": "typeclasses.objects.EquippableItem",
|
||||
"slot": 'foot'
|
||||
FEATURE = {
|
||||
"prototype_key": "feature",
|
||||
"prototype_tags": ["feature"],
|
||||
"key": "feature",
|
||||
"desc": "Something slightly remarkable.",
|
||||
"feature_desc": "A slightly remarkable |wfeature|n.",
|
||||
"typeclass": "typeclasses.objects.Feature"
|
||||
}
|
||||
|
||||
FEATURE_CONTAINER = {
|
||||
"prototype_key": "feature_container",
|
||||
"key": "chest",
|
||||
"desc": "A chest.",
|
||||
"feature_desc": "A |wchest|n lies on the floor.",
|
||||
"prototype_tags": ["feature", "container"],
|
||||
"key": "generic container",
|
||||
"desc": "A generic container.",
|
||||
"feature_desc": "A dreadful |wgeneric container|n lies on the floor.",
|
||||
"typeclass": "typeclasses.objects.ContainerFeature"
|
||||
}
|
||||
|
||||
FEATURE_SKELETON = {
|
||||
"prototype_key": "feature_skeleton",
|
||||
"key": "rugged skeleton",
|
||||
"desc": "An old humanoid skeleton, eroded by the passage of time.",
|
||||
"feature_desc": "A rugged humanoid |wskeleton|n lies on the floor, theirs bony hand still clutching a broken spear. What remains of theirs armor and clothings is too battered to let you recognize their origins.",
|
||||
"typeclass": "typeclasses.objects.Feature"
|
||||
# FEATURES
|
||||
|
||||
F_ARMORED_SKELETON = {
|
||||
"prototype_parent": "FEATURE",
|
||||
"prototype_tags": ["feature"],
|
||||
"prototype_key": "f_armored_skeleton",
|
||||
"key": "skeleton of a soldier in armor",
|
||||
"aliases": ["skeleton"],
|
||||
"desc": "The skeleton of a soldier, still locked in their armor now "
|
||||
"rusty. They lie leaning against the barricade where he died, their bony hand "
|
||||
"clutched to the handle of a broken spear.",
|
||||
"feature_desc": "A |wskeleton|n in a broken armor is collapsed on the floor behind the table.",
|
||||
"locks": "search:all()"
|
||||
}
|
||||
|
||||
F_RUBBLE_01 = {
|
||||
"prototype_parent": "FEATURE",
|
||||
"prototype_tags": ["feature"],
|
||||
"prototype_key": "f_rubble_01",
|
||||
"key": "pile of stones",
|
||||
"aliases": ["pile"],
|
||||
"desc": "A large root system pierced the ceiling of this room, shattering one"
|
||||
" of the load-bearing boards. Some of the covering stones now lie damaged on the ground,"
|
||||
"filling the floor with debris.",
|
||||
"feature_desc": "A |wpile of stones|n and a collapsed beam from the ceiling make it difficult to cross this area.",
|
||||
"locks": "search:all()"
|
||||
}
|
||||
|
||||
FEATURE_SKELETON = {
|
||||
"prototype_parent": "FEATURE",
|
||||
"prototype_tags": ["feature"],
|
||||
"prototype_key": "feature_skeleton",
|
||||
"key": "rugged skeleton",
|
||||
"aliases": ["skeleton"],
|
||||
"desc": "An old humanoid skeleton, eroded by the passage of time.",
|
||||
"feature_desc": "A rugged humanoid |wskeleton|n lies on the floor, theirs bony hand still clutching a broken "
|
||||
"spear. What remains of theirs armor and clothing is too battered to let you recognize their "
|
||||
"origins.",
|
||||
"locks": "search:all()"
|
||||
}
|
||||
|
||||
SUMMONING_CIRCLE = {
|
||||
"prototype_parent": "feature",
|
||||
"prototype_tags": ["feature"],
|
||||
"prototype_key": "summoning_circle",
|
||||
"key": "circle of summoning",
|
||||
"aliases": ["circle", "summoning circle"],
|
||||
"desc": "A circular pattern of mystical runes drawn with blood.",
|
||||
"feature_desc": "An arcane |wcircle of summoning|n is draw with blood on the floor.",
|
||||
}
|
||||
|
||||
# ITEMS
|
||||
|
||||
STONE = {
|
||||
"prototype_parent": "ITEM",
|
||||
"prototype_tags": ["item"],
|
||||
"prototype_key": "stone",
|
||||
"key": "stone",
|
||||
"desc": "An unremarkable stone made of granite.",
|
||||
"aliases": ["granite stone"],
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
"desc": "An unremarkable stone made of granite."
|
||||
}
|
||||
|
||||
BIG_STONE = {
|
||||
"prototype_parent": "ITEM",
|
||||
"prototype_tags": ["item"],
|
||||
"prototype_key": "big stone",
|
||||
"key": "big stone",
|
||||
"desc": "An unremarkable stone made of granite. It seems very heavy.",
|
||||
"aliases": ["big granite stone"],
|
||||
"desc": "An unremarkable stone made of granite. It seems very heavy.",
|
||||
"get_err_msg": "You are not strong enough to lift this stone.",
|
||||
"locks": "get:attr_gt(strength, 50)",
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
}
|
||||
|
||||
BROKEN_CROWN = {
|
||||
"prototype_parent": "ITEM_EQUIPPABLE",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"prototype_key": "broken_crown",
|
||||
"key": "broken crown",
|
||||
"desc": "An old iron crown, dented and covered in rust.",
|
||||
"slot": 'head'
|
||||
}
|
||||
|
||||
MULTICOLORED_ROBE = {
|
||||
"prototype_parent": "ITEM_EQUIPPABLE",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"prototype_key": "multicolored robe",
|
||||
"key": "multicolored robe",
|
||||
"desc": "A long robe, made of many different colored cloth patches.",
|
||||
"slot": 'torso'
|
||||
}
|
||||
|
||||
PLAIN_TROUSERS = {
|
||||
"prototype_parent": "ITEM_EQUIPPABLE",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"prototype_key": "plain trousers",
|
||||
"key": "plain trousers",
|
||||
"desc": "Simple but robust cloth trousers.",
|
||||
"slot": 'legs'
|
||||
}
|
||||
|
||||
LEATHER_BOOTS = {
|
||||
"prototype_parent": "ITEM_EQUIPPABLE",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"prototype_key": "leather boots",
|
||||
"key": "leather boots",
|
||||
"desc": "A worn pair of leather boots.",
|
||||
"slot": 'foot'
|
||||
}
|
||||
|
||||
LANTERN = {
|
||||
"prototype_parent": "ITEM",
|
||||
"prototype_tags": ["item"],
|
||||
"prototype_key": "lantern",
|
||||
"key": "old lantern",
|
||||
"desc": "An old lantern, still filled with oil.",
|
||||
"aliases": ["lantern"],
|
||||
"desc": "An old lantern, still filled with oil.",
|
||||
"attrs": [("is_lit", True, None, None)],
|
||||
"tags": [("emit_light", "effect", None)],
|
||||
"locks": "light:all()",
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
}
|
||||
|
||||
BLADE_TOOL = {
|
||||
"prototype_parent": "ITEM_EQUIPPABLE",
|
||||
"prototype_tags": ["item", "equippable"],
|
||||
"prototype_key": "blade tool",
|
||||
"key": "steel blade",
|
||||
"desc": "A steel blade, with an oak handle wrapped in cloth.",
|
||||
"aliases": ["blade"],
|
||||
"desc": "A steel blade, with an oak handle wrapped in cloth.",
|
||||
"tags": [("blade", "crafting_tool", None)],
|
||||
"typeclass": "typeclasses.objects.EquippableItem",
|
||||
"slot": 'foot'
|
||||
}
|
||||
|
||||
WOOD_MATERIAL = {
|
||||
"prototype_parent": "ITEM",
|
||||
"prototype_tags": ["item"],
|
||||
"prototype_key": "wood_material",
|
||||
"key": "piece of wood",
|
||||
"desc": "An unremarkable piece of wood.",
|
||||
"aliases": ["wood"],
|
||||
"desc": "An unremarkable piece of wood.",
|
||||
"tags": [("wood", "crafting_material", None)],
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
}
|
||||
|
||||
BLOOD_MATERIAL = {
|
||||
"prototype_parent": "ITEM",
|
||||
"prototype_tags": ["item"],
|
||||
"prototype_key": "blood_material",
|
||||
"key": "vial of blood",
|
||||
"desc": "A vial of blood. Fresh.",
|
||||
"aliases": ["blood, vial"],
|
||||
"desc": "A vial of blood. Fresh.",
|
||||
"tags": [("blood", "crafting_material", None)],
|
||||
"typeclass": "typeclasses.objects.Item"
|
||||
}
|
||||
|
||||
SUMMONING_CIRCLE = {
|
||||
"prototype_key": "summoning_circle",
|
||||
"key": "summoning circle",
|
||||
"aliases": ["circle"],
|
||||
"desc": "A circular pattern of mystical runes drawn with blood.",
|
||||
"feature_desc": "An arcane |wcircle of summoning|n is draw with blood on the floor.",
|
||||
"typeclass": "typeclasses.objects.Feature"
|
||||
}
|
||||
|
||||
## example of module-based prototypes using
|
||||
|
|
|
@ -1,9 +1,42 @@
|
|||
from utils.crafting import CraftingRecipe
|
||||
|
||||
|
||||
class BloodRecipe(CraftingRecipe):
|
||||
"""Some blood"""
|
||||
name = "vial of blood" # name to refer to this recipe as
|
||||
crafting_time = 5
|
||||
tool_tags = ["blade"]
|
||||
consumable_tags = []
|
||||
output_prototypes = [
|
||||
"blood_material"
|
||||
]
|
||||
output_names = ["a vial of blood"]
|
||||
success_message = "You collect your blood in a vial."
|
||||
|
||||
def post_craft(self, craft_result, **kwargs):
|
||||
result_obj = super().post_craft(craft_result, **kwargs)
|
||||
if result_obj and self.crafter.attributes.has('health'):
|
||||
self.crafter.db.health -= 1
|
||||
|
||||
return result_obj
|
||||
|
||||
|
||||
class SummoningCircleRecipe(CraftingRecipe):
|
||||
"""A summoning circle"""
|
||||
name = "summoning circle" # name to refer to this recipe as
|
||||
crafting_time = 20
|
||||
tool_tags = []
|
||||
consumable_tags = ["blood"]
|
||||
output_prototypes = [
|
||||
"summoning_circle"
|
||||
]
|
||||
success_message = "You draw an arcane circle on the ground."
|
||||
|
||||
|
||||
class WoodenPuppetRecipe(CraftingRecipe):
|
||||
"""A puppet"""
|
||||
name = "wooden puppet" # name to refer to this recipe as
|
||||
crafting_time = 15
|
||||
tool_tags = ["blade"]
|
||||
consumable_tags = ["wood"]
|
||||
output_prototypes = [
|
||||
|
@ -11,13 +44,3 @@ class WoodenPuppetRecipe(CraftingRecipe):
|
|||
"typeclass": "typeclasses.objects.Item",
|
||||
"desc": "A small carved doll"}
|
||||
]
|
||||
|
||||
|
||||
class SummoningCircleRecipe(CraftingRecipe):
|
||||
"""A summoning circle"""
|
||||
name = "summoning circle" # name to refer to this recipe as
|
||||
tool_tags = []
|
||||
consumable_tags = ["blood"]
|
||||
output_prototypes = [
|
||||
"summoning_circle"
|
||||
]
|
||||
|
|
|
@ -8,10 +8,9 @@ from utils.utils import has_effect
|
|||
|
||||
def spell_light(caller, target, **kwargs):
|
||||
if not target:
|
||||
caller.msg("You need something to place your light on.")
|
||||
return
|
||||
|
||||
target_obj = caller.search(target, location=[caller, caller.location])
|
||||
target_obj = caller
|
||||
else:
|
||||
target_obj = caller.search(target, location=[caller, caller.location])
|
||||
|
||||
if not target_obj:
|
||||
return
|
||||
|
|
142
world/tutorial_prototypes.py
Normal file
142
world/tutorial_prototypes.py
Normal file
|
@ -0,0 +1,142 @@
|
|||
"""
|
||||
Prototypes
|
||||
|
||||
A prototype is a simple way to create individualized instances of a
|
||||
given typeclass. It is dictionary with specific key names.
|
||||
|
||||
For example, you might have a Sword typeclass that implements everything a
|
||||
Sword would need to do. The only difference between different individual Swords
|
||||
would be their key, description and some Attributes. The Prototype system
|
||||
allows to create a range of such Swords with only minor variations. Prototypes
|
||||
can also inherit and combine together to form entire hierarchies (such as
|
||||
giving all Sabres and all Broadswords some common properties). Note that bigger
|
||||
variations, such as custom commands or functionality belong in a hierarchy of
|
||||
typeclasses instead.
|
||||
|
||||
A prototype can either be a dictionary placed into a global variable in a
|
||||
python module (a 'module-prototype') or stored in the database as a dict on a
|
||||
special Script (a db-prototype). The former can be created just by adding dicts
|
||||
to modules Evennia looks at for prototypes, the latter is easiest created
|
||||
in-game via the `olc` command/menu.
|
||||
|
||||
Prototypes are read and used to create new objects with the `spawn` command
|
||||
or directly via `evennia.spawn` or the full path `evennia.prototypes.spawner.spawn`.
|
||||
|
||||
A prototype dictionary have the following keywords:
|
||||
|
||||
Possible keywords are:
|
||||
- `prototype_key` - the name of the prototype. This is required for db-prototypes,
|
||||
for module-prototypes, the global variable name of the dict is used instead
|
||||
- `prototype_parent` - string pointing to parent prototype if any. Prototype inherits
|
||||
in a similar way as classes, with children overriding values in their partents.
|
||||
- `key` - string, the main object identifier.
|
||||
- `typeclass` - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`.
|
||||
- `location` - this should be a valid object or #dbref.
|
||||
- `home` - valid object or #dbref.
|
||||
- `destination` - only valid for exits (object or #dbref).
|
||||
- `permissions` - string or list of permission strings.
|
||||
- `locks` - a lock-string to use for the spawned object.
|
||||
- `aliases` - string or list of strings.
|
||||
- `attrs` - Attributes, expressed as a list of tuples on the form `(attrname, value)`,
|
||||
`(attrname, value, category)`, or `(attrname, value, category, locks)`. If using one
|
||||
of the shorter forms, defaults are used for the rest.
|
||||
- `tags` - Tags, as a list of tuples `(tag,)`, `(tag, category)` or `(tag, category, data)`.
|
||||
- Any other keywords are interpreted as Attributes with no category or lock.
|
||||
These will internally be added to `attrs` (eqivalent to `(attrname, value)`.
|
||||
|
||||
See the `spawn` command and `evennia.prototypes.spawner.spawn` for more info.
|
||||
|
||||
"""
|
||||
|
||||
# ROOMS
|
||||
|
||||
START_00 = {
|
||||
"prototype_parent": "ROOM",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "ruined room",
|
||||
"aliases": "start_00",
|
||||
"desc": "This room, once royally adorned, now lies in ruins. |/"
|
||||
"A violent battle must have been fought in this place,"
|
||||
"mixed with the broken wood of the furniture stand out broken weapons"
|
||||
"and bodies devoured by the passage of time. "
|
||||
"The long oak table that once occupied the center of the room"
|
||||
" it's now overturned against the wall to create a makeshift barricade."
|
||||
}
|
||||
|
||||
START_01 = {
|
||||
"prototype_parent": "ROOM",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "long hall",
|
||||
"aliases": ["hall", "start_01"],
|
||||
"desc": "A long hall paved with large hewn stones, thick oak beams"
|
||||
"still hold up the ceiling frescoed with gilded symbols. Dust corpuscles swirl"
|
||||
"in the light, disturbed by your passage."
|
||||
}
|
||||
|
||||
START_02 = {
|
||||
"prototype_parent": "ROOM",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "old guardhouse",
|
||||
"aliases": ["guardhouse", "start_02"],
|
||||
"desc": "An old guardhouse devastated by the fighting that took place in these halls."
|
||||
"The only part that has been spared is the ceiling, completely covered with"
|
||||
"peeling frescoes depicting scenes of martial life."
|
||||
}
|
||||
|
||||
START_03 = {
|
||||
"prototype_parent": "ROOM",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "empty corridor",
|
||||
"aliases": ["corridor", "start_03"],
|
||||
"desc": "The sides of the corridor are lined with stone archways, each adorned by a"
|
||||
"stone statue. All the statues have been broken behind recognition."
|
||||
}
|
||||
|
||||
START_04 = {
|
||||
"prototype_parent": "ROOM",
|
||||
"prototype_tags": ["room"],
|
||||
"key": "empty corridor",
|
||||
"aliases": ["corridor", "start_04"],
|
||||
"desc": "This building seems to have survived the ravages of time better than"
|
||||
"most of the others. Its arched roof and wide spaces suggests that"
|
||||
"this is a temple or church of some kind."
|
||||
}
|
||||
|
||||
# EXITS
|
||||
|
||||
START_DOOR_00 = {
|
||||
"prototype_parent": "EXIT",
|
||||
"prototype_tags": ["exit"],
|
||||
"key": "sculpted archway",
|
||||
"aliases": ["archway", "start_door_00"],
|
||||
"desc": "A beautifully sculpted arched entrance. Two figures are carved into the"
|
||||
"stone on either side of the door, on the right Its, the muse of Deception, on"
|
||||
"right Izzac, the muse of Authority."
|
||||
}
|
||||
|
||||
START_DOOR_01 = {
|
||||
"prototype_parent": "EXIT",
|
||||
"prototype_tags": ["exit"],
|
||||
"key": "open doorway",
|
||||
"aliases": ["doorway", "start_door_01"],
|
||||
"desc": "A large doorway, with no door. The rune '|y◧|n' is engraved on the granite jamb."
|
||||
}
|
||||
|
||||
START_DOOR_02 = {
|
||||
"prototype_parent": "EXIT",
|
||||
"prototype_tags": ["exit"],
|
||||
"key": "small doorway",
|
||||
"aliases": ["doorway", "start_door_02"],
|
||||
"desc": "A small doorway, with no door. The rune '|y◓|n' is engraved on the granite jamb."
|
||||
}
|
||||
|
||||
START_DOOR_03 = {
|
||||
"prototype_parent": "EXIT",
|
||||
"prototype_tags": ["exit"],
|
||||
"key": "reinforced door",
|
||||
"aliases": ["door", "start_door_03"],
|
||||
"desc": "A big oak door, reinforced with iron bars across its frame."
|
||||
"It bears marks and burns all over its surface but hasn't been breached during the"
|
||||
"siege."
|
||||
}
|
||||
|
Loading…
Reference in a new issue