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 = 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 = ") 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 [;alias;alias..] [,[;alias;..]]] = , Handles the creation of exits. If a destination is given, the exit will point there. The 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))