From 47356ca6329c0b4c48cc10b5d56b2bcb663c97d6 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 18 Feb 2013 20:08:05 +0100 Subject: [PATCH 1/8] Fixed a lingering error from turning off "quick assignment" that caused issues in TutorialWorld. --- contrib/tutorial_world/objects.py | 4 ++-- src/objects/models.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/tutorial_world/objects.py b/contrib/tutorial_world/objects.py index 0a184bf94d..08a9f1ab3e 100644 --- a/contrib/tutorial_world/objects.py +++ b/contrib/tutorial_world/objects.py @@ -773,8 +773,8 @@ class Weapon(TutorialObject): super(Weapon, self).at_object_creation() self.db.hit = 0.4 # hit chance self.db.parry = 0.8 # parry chance - self.damage = 8.0 - self.magic = False + self.db.damage = 8.0 + self.db.magic = False self.cmdset.add_default(CmdSetWeapon, permanent=True) def reset(self): diff --git a/src/objects/models.py b/src/objects/models.py index 21bcdda2d0..63f70a2e21 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -35,7 +35,7 @@ from django.utils.translation import ugettext as _ #__all__ = ("ObjAttribute", "Alias", "ObjectNick", "ObjectDB") - +_ScriptDB = None _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1)) _GA = object.__getattribute__ @@ -900,6 +900,10 @@ class ObjectDB(TypedObject): objects to their respective home locations, as well as clean up all exits to/from the object. """ + global _ScriptDB + if not _ScriptDB: + from src.scripts.models import ScriptDB as _ScriptDB + if _GA(self, "delete_iter") > 0: # make sure to only call delete once on this object # (avoid recursive loops) @@ -924,8 +928,10 @@ class ObjectDB(TypedObject): _SA(_GA(self, "player"), "character", None) _SA(self, "player", None) - for script in _GA(self, "scripts").all(): + for script in _ScriptDB.objects.get_all_scripts_on_obj(self): script.stop() + #for script in _GA(self, "scripts").all(): + # script.stop() # if self.player: # self.player.user.is_active = False From 0121f36ac0c41467ab7dcc77dc6eb5c85db0e75b Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 19 Feb 2013 23:30:33 +0100 Subject: [PATCH 2/8] Added cmd.funcpart as a way of adding multiple-part commands, each with a possibility to yield with a deferred. This allows for flexible implementation of delayed commands and other asynchronous goodies. --- src/commands/cmdhandler.py | 9 +++++++-- src/utils/utils.py | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index f182f5e5ad..c9dd47aeab 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -43,7 +43,7 @@ from src.comms.channelhandler import CHANNELHANDLER from src.utils import logger, utils from src.commands.cmdset import CmdSet from src.commands.cmdparser import at_multimatch_cmd -from src.utils.utils import string_suggestions +from src.utils.utils import string_suggestions, make_iter from django.utils.translation import ugettext as _ @@ -254,7 +254,7 @@ def cmdhandler(caller, raw_string, testing=False): cmd.raw_string = unformatted_raw_string if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'): - # cmd.obj are automatically made available. + # cmd.obj is automatically made available. # we make sure to validate its scripts. yield cmd.obj.scripts.validate() @@ -270,6 +270,11 @@ def cmdhandler(caller, raw_string, testing=False): # (return value is normally None) ret = yield cmd.func() + if hasattr(cmd, "funcparts"): + # yield on command parts (for multi-part delayed commands) + for funcpart in make_iter(cmd.funcparts): + yield funcpart() + # post-command hook yield cmd.at_post_cmd() diff --git a/src/utils/utils.py b/src/utils/utils.py index 0093e819e5..efbcb58e62 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -496,7 +496,7 @@ def uses_database(name="sqlite3"): engine = settings.DATABASE_ENGINE return engine == "django.db.backends.%s" % name -def delay(to_return, delay=2, callback=None): +def delay(delay=2, retval=None, callback=None): """ Delay the return of a value. Inputs: @@ -508,7 +508,7 @@ def delay(to_return, delay=2, callback=None): """ d = defer.Deferred() callb = callback or d.callback - reactor.callLater(delay, callb, to_return) + reactor.callLater(delay, callb, retval) return d _FROM_MODEL_MAP = None From 65e370f93b715a314a96e349f5088ce6ac08a107 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 20 Feb 2013 00:17:50 +0100 Subject: [PATCH 3/8] Added an abort condition to the cmd's funcparts chain. --- src/commands/cmdhandler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index c9dd47aeab..4af60fe2db 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -273,7 +273,9 @@ def cmdhandler(caller, raw_string, testing=False): if hasattr(cmd, "funcparts"): # yield on command parts (for multi-part delayed commands) for funcpart in make_iter(cmd.funcparts): - yield funcpart() + err = yield funcpart() + # returning anything but a deferred/None will kill the chain + if err: break # post-command hook yield cmd.at_post_cmd() From 743edd88ffb4f7fe72d71969ce6d5a2b0fad21b1 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 20 Feb 2013 00:27:44 +0100 Subject: [PATCH 4/8] Renamed cmd.funcparts to cmd.func_parts for naming consistency with other command optionals. --- src/commands/cmdhandler.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index 4af60fe2db..82bf011372 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -270,10 +270,10 @@ def cmdhandler(caller, raw_string, testing=False): # (return value is normally None) ret = yield cmd.func() - if hasattr(cmd, "funcparts"): + if hasattr(cmd, "func_parts"): # yield on command parts (for multi-part delayed commands) - for funcpart in make_iter(cmd.funcparts): - err = yield funcpart() + for func_part in make_iter(cmd.func_parts): + err = yield func_part() # returning anything but a deferred/None will kill the chain if err: break From 7607edca5b1c93916c6472ea68856580309603fc Mon Sep 17 00:00:00 2001 From: Bobby Bailey Date: Sat, 2 Mar 2013 22:01:44 -0500 Subject: [PATCH 5/8] Update @about to reflect current license. --- src/commands/default/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/default/system.py b/src/commands/default/system.py index 5ddba48cb5..5ef0975275 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -526,7 +526,7 @@ class CmdAbout(MuxCommand): {cEvennia{n %s{n MUD/MUX/MU* development system - {wLicence{n Artistic Licence/GPL + {wLicence{n BSD 3-Clause Licence {wWeb{n http://www.evennia.com {wIrc{n #evennia on FreeNode {wForum{n http://www.evennia.com/discussions From f0fa6b5aeef5c9a931d0c7d67ffa946b25bccf75 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 8 Mar 2013 21:42:51 +0100 Subject: [PATCH 6/8] Fixed a bug in IMC2 implementation. Made sure the Tutorial world Ghost keeps moving after winning a battle. --- contrib/tutorial_world/mob.py | 4 ++++ src/comms/imc2.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/tutorial_world/mob.py b/contrib/tutorial_world/mob.py index f210e15bcf..87f6611b0c 100644 --- a/contrib/tutorial_world/mob.py +++ b/contrib/tutorial_world/mob.py @@ -241,6 +241,10 @@ class Enemy(Mob): elif not ostring: ostring = "%s falls to the ground!" % target.key self.location.msg_contents(ostring, exclude=[target]) + # Pursue any stragglers after the battle + self.battle_mode = False + self.roam_mode = False + self.pursue_mode = True else: # no players found, this could mean they have fled. Switch to pursue mode. self.battle_mode = False diff --git a/src/comms/imc2.py b/src/comms/imc2.py index 1f04c0502e..07cfac24d1 100644 --- a/src/comms/imc2.py +++ b/src/comms/imc2.py @@ -434,7 +434,7 @@ def create_connection(channel, imc2_channel): # how the evennia channel will be able to contact this protocol in reverse send_code = "from src.comms.imc2 import IMC2_CLIENT\n" send_code += "data={'channel':from_channel}\n" - send_code += "IMC2_CLIENT.msg_imc2(message, from_obj=from_obj, data=data)\n" + send_code += "IMC2_CLIENT.msg_imc2(message, senders=[self])\n" conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, db_external_config=config) conn.save() From d4b0afca838092f74bf69ae75b14e51ef1664b0c Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 8 Mar 2013 21:46:05 +0100 Subject: [PATCH 7/8] Updated taling_npc contrib to new standard import locations, thanks to patch by Metathink. Resolves issue 354. --- contrib/talking_npc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/contrib/talking_npc.py b/contrib/talking_npc.py index 0128d0b722..61025407f5 100644 --- a/contrib/talking_npc.py +++ b/contrib/talking_npc.py @@ -23,17 +23,15 @@ mob implementation. """ +from ev import Object, CmdSet, default_cmds from contrib import menusystem -from game.gamesrc.objects.baseobjects import Object -from game.gamesrc.commands.basecmdset import CmdSet -from game.gamesrc.commands.basecommand import MuxCommand # # The talk command # -class CmdTalk(MuxCommand): +class CmdTalk(default_cmds.MuxCommand): """ talks to an npc From 0f2762d5f234603648a4e1f6f00fdb6a3d505613 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 8 Mar 2013 23:09:21 +0100 Subject: [PATCH 8/8] Added functionality to @services command. Allowed @reload to also accept a reason argument. --- src/commands/default/system.py | 47 ++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/commands/default/system.py b/src/commands/default/system.py index 5ef0975275..3abd163d84 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -35,7 +35,7 @@ class CmdReload(MuxCommand): Reload the system Usage: - @reload + @reload [reason] This restarts the server. The Portal is not affected. Non-persistent scripts will survive a @reload (use @@ -49,7 +49,10 @@ class CmdReload(MuxCommand): """ Reload the system. """ - SESSIONS.announce_all(" Server restarting ...") + reason = "" + if self.args: + reason = "(Reason: %s) " % self.args.rstrip(".") + SESSIONS.announce_all(" Server restarting %s..." % reason) SESSIONS.server.shutdown(mode='reload') class CmdReset(MuxCommand): @@ -94,7 +97,8 @@ class CmdShutdown(MuxCommand): def func(self): "Define function" try: - session = self.caller.sessions[0] + # Only allow shutdown if caller has session + self.caller.sessions[0] except Exception: return self.caller.msg('Shutting down server ...') @@ -417,12 +421,14 @@ class CmdService(MuxCommand): Switches: list - shows all available services (default) - start - activates a service - stop - stops a service + start - activates or reactivate a service + stop - stops/inactivate a service (can often be restarted) + delete - tries to permanently remove a service Service management system. Allows for the listing, starting, and stopping of services. If no switches - are given, services will be listed. + are given, services will be listed. Note that to operate on the + service you have to supply the full (green or red) name as given in the list. """ key = "@service" @@ -436,8 +442,8 @@ class CmdService(MuxCommand): caller = self.caller switches = self.switches - if switches and switches[0] not in ["list", "start", "stop"]: - caller.msg("Usage: @service/ [service]") + if switches and switches[0] not in ("list", "start", "stop", "delete"): + caller.msg("Usage: @service/ [servicename]") return # get all services @@ -450,7 +456,7 @@ class CmdService(MuxCommand): # Just display the list of installed services and their # status, then exit. string = "-" * 78 - string += "\n{wServices{n (use @services/start|stop):" + string += "\n{wServices{n (use @services/start|stop|delete):" for service in service_collection.services: if service.running: @@ -469,26 +475,35 @@ class CmdService(MuxCommand): service = service_collection.getServiceNamed(self.args) except Exception: string = 'Invalid service name. This command is case-sensitive. ' - string += 'See @service/list for valid services.' + string += 'See @service/list for valid service name (enter the full name exactly).' caller.msg(string) return - if switches[0] == "stop": - # Stopping a service gracefully closes it and disconnects + if switches[0] in ("stop", "delete"): + # Stopping/killing a service gracefully closes it and disconnects # any connections (if applicable). + delmode = switches[0] == "delete" if not service.running: caller.msg('That service is not currently running.') return if service.name[:7] == 'Evennia': - string = "You seem to be shutting down a core Evennia* service. Note that" - string += "Stopping some TCP port services will *not* disconnect users *already*" + if delmode: + caller.msg("You cannot remove a core Evennia service (named 'Evennia***').") + return + string = "You seem to be shutting down a core Evennia service (named 'Evennia***'). Note that" + string += "stopping some TCP port services will *not* disconnect users *already*" string += "connected on those ports, but *may* instead cause spurious errors for them. To " string += "safely and permanently remove ports, change settings file and restart the server." caller.msg(string) - service.stopService() - caller.msg("Stopping service '%s'." % self.args) + if delmode: + service.stopService() + service_collection.removeService(service) + caller.msg("Stopped and removed service '%s'." % self.args) + else: + service.stopService() + caller.msg("Stopped service '%s'." % self.args) return if switches[0] == "start":