dkmud/commands/builder.py
Francesco Cappelli db12c674ef da da da.
2022-01-25 22:23:39 +01:00

382 lines
12 KiB
Python

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
from typeclasses.rooms import Room, Zone
def _descdoor_load(caller):
return caller.db.evmenu_target.db.desc or ""
def _descdoor_save(caller, buf):
"""
Save line buffer to the desc prop. This should
return True if successful and also report its status to the user.
"""
caller.db.evmenu_target.setdesc(buf)
caller.msg("Saved.")
return True
def _descdoor_quit(caller):
caller.attributes.remove("evmenu_target")
caller.msg("Exited editor.")
class CmdDescDoor(Command):
"""
describe a BaseDoor in the current room.
Usage:
descdoor <obj> = <description>
Switches:
edit - Open up a line editor for more advanced editing.
Sets the "desc" attribute on an object. If an object is not given,
describe the current room.
"""
key = "descdoor"
aliases = ["descd"]
switch_options = ("edit",)
locks = "cmd:perm(descdoor) or perm(Builder)"
help_category = "Building"
def edit_handler(self):
if self.rhs:
self.msg("|rYou may specify a value, or use the edit switch, " "but not both.|n")
return
if self.args:
obj = self.caller.search(self.args)
else:
obj = self.caller.location or self.msg("|rYou can't describe oblivion.|n")
if not obj:
return
if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")):
self.caller.msg("You don't have permission to edit the description of %s." % obj.key)
self.caller.db.evmenu_target = obj
# launch the editor
EvEditor(
self.caller,
loadfunc=_descdoor_load,
savefunc=_descdoor_save,
quitfunc=_descdoor_quit,
key="desc",
persistent=True,
)
return
def func(self):
"""Define command"""
caller = self.caller
if not self.args or ("=" in self.args and "edit" in self.switches):
caller.msg("Usage: descdoor <obj> = <description>")
return
if "edit" in self.switches:
self.edit_handler()
return
# We have an =
obj = caller.search(self.lhs)
if not obj:
return
desc = self.rhs or ""
if inherits_from(obj, BaseDoor):
if obj.access(self.caller, "control") or obj.access(self.caller, "edit"):
obj.setdesc(desc)
caller.msg("The description was set on %s." % obj.get_display_name(caller))
else:
caller.msg("You don't have permission to edit the description of %s." % obj.key)
else:
self.msg("|rYou can't describe oblivion.|n")
class CmdOpen(default_cmds.CmdOpen):
__doc__ = default_cmds.CmdOpen.__doc__
# overloading parts of the default CmdOpen command to support doors.
def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None):
"""
Simple wrapper for the default CmdOpen.create_exit
"""
# create a new exit as normal
new_exit = super().create_exit(
exit_name, location, destination, exit_aliases=exit_aliases, typeclass=typeclass
)
if hasattr(self, "return_exit_already_created"):
# we don't create a return exit if it was already created (because
# we created a door)
del self.return_exit_already_created
return new_exit
if inherits_from(new_exit, BaseDoor):
# a door - create its counterpart and make sure to turn off the default
# return-exit creation of CmdOpen
self.caller.msg(
"Note: A door-type exit was created - ignored eventual custom return-exit type."
)
self.return_exit_already_created = True
back_exit = self.create_exit(
exit_name, destination, location, exit_aliases=exit_aliases, typeclass=typeclass
)
new_exit.db.return_exit = back_exit
back_exit.db.return_exit = new_exit
return new_exit
class CmdUpdateLightState(Command):
"""
update room light state.
Usage:
update_light [targetroom]
"""
key = "update_light"
aliases = ["up_l"]
locks = "cmd:perm(update_light) or perm(Builder)"
help_category = "Building"
arg_regex = r"(?:^(?:\s+|\/).*$)|^$"
def func(self):
caller = self.caller
if not self.args:
target = caller.location
if not target:
caller.msg("You have no location to update!")
return
else:
target = caller.search(self.args)
if not (target.attributes.has("is_lit") and hasattr(target, "check_light_state")):
caller.msg(
"You cannot update lights on {}!".format(target.key))
return
target.check_light_state()
caller.msg("Performed update on {}!".format(target.key))
class CmdZone(Command):
"""
creates, deletes or lists zones
Usage:
zone[/add||/del||/map] [zonename] [= room|size]
Manages zones.
"""
key = "zone"
locks = "cmd:perm(zone) or perm(Builders)"
help_category = "Building"
def func(self):
"""
Creates the zone.
"""
caller = self.caller
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()
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:
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)
caller.msg("Zones found: \n" + string)
def print_map(self):
caller = self.caller
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))
return
key = zone.name
zone.delete()
caller.msg("Zone {} deleted.".format(key))
class CmdAddToZone(Command):
"""
add a room to a zone
Usage:
addtozone obj = zone,x,y
Adds a room to an existing zone.
"""
key = "addtozone"
locks = "cmd:perm(zone) or perm(Builders)"
help_category = "Building"
def func(self):
"""
Adds a room to an existing zone.
"""
caller = self.caller
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))