diff --git a/evennia/contrib/events/commands.py b/evennia/contrib/events/commands.py index b0fbb4d6be..7583f657a1 100644 --- a/evennia/contrib/events/commands.py +++ b/evennia/contrib/events/commands.py @@ -287,7 +287,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS): definition = types.get(event_name, (None, "Chain event")) description = definition[1] - self.msg(description) + self.msg(raw(description)) # Open the editor event = self.handler.add_event(obj, event_name, "", @@ -356,7 +356,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS): # Check the definition of the event definition = types.get(event_name, (None, "Chained event")) description = definition[1] - self.msg(description) + self.msg(raw(description)) # Open the editor event = dict(event) diff --git a/evennia/contrib/events/handler.py b/evennia/contrib/events/handler.py index 8d7f06e33d..5a85623afb 100644 --- a/evennia/contrib/events/handler.py +++ b/evennia/contrib/events/handler.py @@ -60,6 +60,23 @@ class EventsHandler(object): """ return self.all().get(event_name, []) + def get_variable(self, variable_name): + """ + Return the variable value or None. + + Args: + variable_name (str): the name of the variable. + + Returns: + Either the variable's value or None. + + """ + handler = type(self).script + if handler: + return handler.get_variable(variable_name) + + return None + def add(self, event_name, code, author=None, valid=False, parameters=""): """ Add a new event for this object. diff --git a/evennia/contrib/events/scripts.py b/evennia/contrib/events/scripts.py index c3f34e4627..2709fb6c66 100644 --- a/evennia/contrib/events/scripts.py +++ b/evennia/contrib/events/scripts.py @@ -132,6 +132,31 @@ class EventHandler(DefaultScript): return types + def get_variable(self, variable_name): + """ + Return the variable defined in the locals. + + This can be very useful to check the value of a variable that can be modified in an event, and whose value will be used in code. This system allows additional customization. + + Args: + variable_name (str): the name of the variable to return. + + Returns: + The variable if found in the locals. + None if not found in the locals. + + Note: + This will return the variable from the current locals. + Keep in mind that locals are shared between events. As + every event is called one by one, this doesn't pose + additional problems if you get the variable right after + an event has been executed. If, however, you differ, + there's no guarantee the variable will be here or will + mean the same thing. + + """ + return self.ndb.current_locals.get(variable_name) + def add_event(self, obj, event_name, code, author=None, valid=False, parameters=""): """ diff --git a/evennia/contrib/events/typeclasses.py b/evennia/contrib/events/typeclasses.py index 016c879927..f7ab05d8cc 100644 --- a/evennia/contrib/events/typeclasses.py +++ b/evennia/contrib/events/typeclasses.py @@ -9,6 +9,105 @@ from evennia.contrib.events.custom import ( create_event_type, patch_hook, create_time_event) from evennia.contrib.events.handler import EventsHandler +class PatchedCharacter: + + """Patched typeclass for DefaultCharcter.""" + + @staticmethod + @patch_hook(DefaultCharacter, "announce_move_from") + def announce_move_from(character, destination, msg=None, hook=None): + """ + Called if the move is to be announced. This is + called while we are still standing in the old + location. Customizing the message through events is possible. + + Args: + destination (Object): The place we are going to. + msg (optional): a custom message to replace the default one. + + """ + if not character.location: + return + + if msg: + string = msg + else: + string = "{character} is leaving {origin}, heading for {destination}." + + # Get the exit from location to destination + location = character.location + exits = [o for o in location.contents if o.location is location and o.destination is destination] + if exits: + exits[0].events.call("msg_leave", character, exits[0], + location, destination, string) + string = exits[0].events.get_variable("message") + + mapping = { + "character": character, + "exit": exits[0] if exits else "somewhere", + "origin": location or "nowhere", + "destination": destination or "nowhere", + } + + # If there's no string, don't display anything + # It can happen if the "message" variable in events is set to None + if not string: + return + + location.msg_contents(string, exclude=(character, ), mapping=mapping) + + @staticmethod + @patch_hook(DefaultCharacter, "announce_move_to") + def announce_move_to(character, source_location, msg=None, hook=None): + """ + Called after the move if the move was not quiet. At this point + we are standing in the new location. + + Args: + source_location (Object): The place we came from + msg (str, optional): the default message to be displayed. + + """ + + if not source_location and character.location.has_player: + # This was created from nowhere and added to a player's + # inventory; it's probably the result of a create command. + string = "You now have %s in your possession." % self.get_display_name(self.location) + character.location.msg(string) + return + + if source_location: + if msg: + string = msg + else: + string = "{character} arrives to {destination} from {origin}." + else: + string = "{character} arrives to {destination}." + + origin = source_location + destination = character.location + if origin: + exits = [o for o in destination.contents if o.location is destination and o.destination is origin] + if exits: + exits[0].events.call("msg_arrive", character, exits[0], + origin, destination, string) + string = exits[0].events.get_variable("message") + + mapping = { + "character": character, + "exit": exits[0] if exits else "somewhere", + "origin": origin or "nowhere", + "destination": destination or "nowhere", + } + + # If there's no string, don't display anything + # It can happen if the "message" variable in events is set to None + if not string: + return + + destination.msg_contents(string, exclude=(character, ), mapping=mapping) + + class PatchedObject(object): @lazy_property def events(self): @@ -37,9 +136,8 @@ class PatchedExit(object): """ is_character = inherits_from(traversing_object, DefaultCharacter) - script = ScriptDB.objects.get(db_key="event_handler") if is_character: - allow = script.call_event(exit, "can_traverse", traversing_object, + allow = exit.events.call("can_traverse", traversing_object, exit, exit.location) if not allow: return @@ -48,7 +146,7 @@ class PatchedExit(object): # After traversing if is_character: - script.call_event(exit, "traverse", traversing_object, + exit.events.call("traverse", traversing_object, exit, exit.location, exit.destination) @@ -66,6 +164,51 @@ create_event_type(DefaultExit, "can_traverse", ["character", "exit", "room"], exit: the exit to be traversed. room: the room in which stands the character before moving. """) +create_event_type(DefaultExit, "msg_arrive", ["character", "exit", + "origin", "destination", "message"], """ + Customize the message when a character arrives through this exit. + This event is called when a character arrives through this exit. + To customize the message that will be sent to the room where the + character arrives, change the value of the variable "message" + to give it your custom message. The character itself will not be + notified. You can use mapping between braces, like this: + message = "{character} climbs out of a hole." + In your mapping, you can use {character} (the character who has + arrived), {exit} (the exit), {origin} (the room in which + the character was), and {destination} (the room in which the character + now is). If you need to customize the message with other information, + you can also set "message" to None and send something else instead. + + Variables you can use in this event: + character: the character who is arriving through this exit. + exit: the exit having been traversed. + origin: the past location of the character. + destination: the current location of the character. + message: the message to be displayed in the destination. +""") +create_event_type(DefaultExit, "msg_leave", ["character", "exit", + "origin", "destination", "message"], """ + Customize the message when a character leaves through this exit. + This event is called when a character leaves through this exit. + To customize the message that will be sent to the room where the + character came from, change the value of the variable "message" + to give it your custom message. The character itself will not be + notified. You can use mapping between braces, like this: + message = "{character} falls into a hole!" + In your mapping, you can use {character} (the character who is + about to leave), {exit} (the exit), {origin} (the room in which + the character is), and {destination} (the room in which the character + is heading for). If you need to customize the message with other + information, you can also set "message" to None and send something + else instead. + + Variables you can use in this event: + character: the character who is leaving through this exit. + exit: the exit being traversed. + origin: the location of the character. + destination: the destination of the character. + message: the message to be displayed in the location. +""") create_event_type(DefaultExit, "traverse", ["character", "exit", "origin", "destination"], """ After the characer has traversed through this exit. @@ -98,4 +241,4 @@ create_event_type(DefaultRoom, "time", ["room"], """ Variables you can use in this event: room: the room connected to this event. -""", create_time_event) + """, create_time_event)