Run Migrate. Implemented a full separation between Player and Character - Players (OOC entities) can now also hold cmdsets and execute commands. This means that "disconnecting" from a Character becomes possible, putting the Player in an "OOC" state outside the game. This overall makes the game much more stable since there used to be issues if the character was destroyed. Having an OOC set also avoids the previous problem of @puppeting into an object that didn't have any cmdset of its own - you couldn't get back out! A new default OOC-Cmdset handles commands available to a player while OOC. Commands in this set are applied with a low priority, allowing "IC" mode to give precedence if desired.

This change meant several changes to the lock and permission functionality, since it becomes important if permissions are assigned on the Player or on their Character (lock functions pperm() and pid() etc check on Player rather than Character). This has the boon of allowing Admins to switch and play/test the game as a "Low access" character as they like.

Plenty of bug fixes and adjustments. Migrations should make sure to move over all data properly.
This commit is contained in:
Griatch 2011-04-23 11:54:08 +00:00
parent ce2a8e9ffe
commit 28fe2ad3f4
37 changed files with 1622 additions and 555 deletions

View file

@ -58,7 +58,7 @@ class CmdBoot(MuxCommand):
break
else:
# Boot by player object
pobj = caller.search("*%s" % args, global_search=True)
pobj = caller.search("*%s" % args, global_search=True, player=True)
if not pobj:
return
if pobj.character.has_player:
@ -118,6 +118,9 @@ class CmdDelPlayer(MuxCommand):
caller = self.caller
args = self.args
if hasattr(caller, 'player'):
caller = caller.player
if not args:
caller.msg("Usage: @delplayer[/delobj] <player/user name or #id> [: reason]")
return
@ -128,7 +131,7 @@ class CmdDelPlayer(MuxCommand):
# We use player_search since we want to be sure to find also players
# that lack characters.
players = caller.search("*%s" % args)
players = caller.search("*%s" % args, player=True)
if not players:
try:
players = PlayerDB.objects.filter(id=args)
@ -304,7 +307,7 @@ class CmdNewPassword(MuxCommand):
return
# the player search also matches 'me' etc.
player = caller.search("*%s" % self.lhs, global_search=True)
player = caller.search("*%s" % self.lhs, global_search=True, player=True)
if not player:
return
player.user.set_password(self.rhs)
@ -320,12 +323,14 @@ class CmdPerm(MuxCommand):
Usage:
@perm[/switch] <object> [= <permission>[,<permission>,...]]
@perm[/switch] *<player> [= <permission>[,<permission>,...]]
Switches:
del : delete the given permission from <object>.
This command sets/clears individual permission strings on an object.
If no permission is given, list all permissions on <object>
del : delete the given permission from <object> or <player>.
player : set permission on a player (same as adding * to name)
This command sets/clears individual permission strings on an object
or player. If no permission is given, list all permissions on <object>.
"""
key = "@perm"
aliases = "@setperm"
@ -340,17 +345,18 @@ class CmdPerm(MuxCommand):
lhs, rhs = self.lhs, self.rhs
if not self.args:
string = "Usage: @perm[/switch] object [ = permission, permission, ...]\n"
string = "Usage: @perm[/switch] object [ = permission, permission, ...]"
caller.msg(string)
return
# locate the object
obj = caller.search(lhs, global_search=True)
playermode = 'player' in self.switches or lhs.startswith('*')
# locate the object
obj = caller.search(lhs, global_search=True, player=playermode)
if not obj:
return
if not rhs:
if not obj.access(caller, 'examine'):
caller.msg("You are not allowed to examine this object.")
return
@ -396,12 +402,10 @@ class CmdPerm(MuxCommand):
for perm in self.rhslist:
perm = perm.lower()
# don't allow to set a permission higher in the hierarchy than the one the
# caller has (to prevent self-escalation)
if perm in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm):
if perm.lower() in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm):
caller.msg("You cannot assign a permission higher than the one you have yourself.")
return
@ -416,45 +420,6 @@ class CmdPerm(MuxCommand):
if tstring:
obj.msg(tstring.strip())
class CmdPuppet(MuxCommand):
"""
Switch control to an object
Usage:
@puppet <character object>
This will attempt to "become" a different character. Note that this command does not check so that
the target object has the appropriate cmdset. You cannot puppet a character that is already "taken".
"""
key = "@puppet"
locks = "cmd:perm(puppet) or perm(Builders)"
help_category = "Admin"
def func(self):
"""
Simple puppet method (does not check permissions)
"""
caller = self.caller
if not self.args:
caller.msg("Usage: @puppet <character>")
return
player = caller.player
new_character = caller.search(self.args)
if not new_character:
return
if not utils.inherits_from(new_character, settings.BASE_CHARACTER_TYPECLASS):
caller.msg("%s is not a Character." % self.args)
return
if new_character.player:
caller.msg("This character is already under the control of a player.")
if player.swap_character(new_character):
new_character.msg("You now control %s." % new_character.name)
else:
caller.msg("You cannot control %s." % new_character.name)
class CmdWall(MuxCommand):
"""
@wall

View file

@ -6,6 +6,7 @@ Building and world design commands
from django.conf import settings
from src.objects.models import ObjectDB, ObjAttribute
from src.players.models import PlayerAttribute
from src.utils import create, utils, debug
from src.commands.default.muxcommand import MuxCommand
@ -122,7 +123,7 @@ class CmdSetObjAlias(MuxCommand):
old_aliases = obj.aliases
if old_aliases:
caller.msg("Cleared aliases from %s: %s" % (obj.key, ", ".join(old_aliases)))
del obj.dbobj.aliases # TODO: del does not understand indirect typeclass reference!
del obj.dbobj.aliases
else:
caller.msg("No aliases to clear.")
return
@ -1389,16 +1390,25 @@ class CmdExamine(ObjManipCommand):
Usage:
examine [<object>[/attrname]]
examine [*<player>[/attrname]]
Switch:
player - examine a Player (same as adding *)
The examine command shows detailed game info about an
object and optionally a specific attribute on it.
If object is not specified, the current location is examined.
Append a * before the search string to examine a player.
"""
key = "@examine"
aliases = ["@ex","ex", "exam", "examine"]
locks = "cmd:perm(examine) or perm(Builders)"
help_category = "Building"
player_mode = False
def format_attributes(self, obj, attrname=None, crop=True):
"""
Helper function that returns info about attributes and/or
@ -1411,7 +1421,10 @@ class CmdExamine(ObjManipCommand):
except Exception:
ndb_attr = None
else:
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
if player_mode:
db_attr = [(attr.key, attr.value) for attr in PlayerAttribute.objects.filter(db_obj=obj)]
else:
db_attr = [(attr.key, attr.value) for attr in ObjAttribute.objects.filter(db_obj=obj)]
try:
ndb_attr = [(aname, avalue) for aname, avalue in obj.ndb.__dict__.items()]
except Exception:
@ -1439,24 +1452,25 @@ class CmdExamine(ObjManipCommand):
returns a string.
"""
if obj.has_player:
if hasattr(obj, "has_player") and obj.has_player:
string = "\n{wName/key{n: {c%s{n (%s)" % (obj.name, obj.dbref)
else:
string = "\n{wName/key{n: {C%s{n (%s)" % (obj.name, obj.dbref)
if obj.aliases:
if hasattr(obj, "aliases") and obj.aliases:
string += "\n{wAliases{n: %s" % (", ".join(obj.aliases))
if obj.has_player:
if hasattr(obj, "has_player") and obj.has_player:
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
perms = obj.player.permissions
if obj.player.is_superuser:
perms = ["<Superuser>"]
elif not perms:
perms = ["<None>"]
string += "\n{wPlayer Perms{n: %s" % (", ".join(perms))
string += "\n{wPlayer Perms{n: %s" % (", ".join(perms))
string += "\n{wTypeclass{n: %s (%s)" % (obj.typeclass, obj.typeclass_path)
string += "\n{wLocation{n: %s" % obj.location
if obj.destination:
if hasattr(obj, "location"):
string += "\n{wLocation{n: %s" % obj.location
if hasattr(obj, "destination") and obj.destination:
string += "\n{wDestination{n: %s" % obj.destination
perms = obj.permissions
if perms:
@ -1467,8 +1481,8 @@ class CmdExamine(ObjManipCommand):
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
string += "\n{wCurrent Cmdset (before permission checks){n:\n %s" % cmdsetstr
if obj.scripts.all():
string += "\n{wCurrent Cmdset (including permission checks){n:\n %s" % cmdsetstr
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
string += "\n{wScripts{n:\n %s" % obj.scripts
# add the attributes
string += self.format_attributes(obj)
@ -1476,21 +1490,21 @@ class CmdExamine(ObjManipCommand):
exits = []
pobjs = []
things = []
for content in obj.contents:
if content.destination:
# an exit
exits.append(content)
elif content.player:
pobjs.append(content)
else:
things.append(content)
if exits:
string += "\n{wExits{n: " + ", ".join([exit.name for exit in exits])
if pobjs:
string += "\n{wCharacters{n: " + ", ".join(["{c%s{n" % pobj.name for pobj in pobjs])
if things:
string += "\n{wContents{n: " + ", ".join([cont.name for cont in obj.contents
if cont not in exits and cont not in pobjs])
if hasattr(obj, "contents"):
for content in obj.contents:
if content.destination:
exits.append(content)
elif content.player:
pobjs.append(content)
else:
things.append(content)
if exits:
string += "\n{wExits{n: " + ", ".join([exit.name for exit in exits])
if pobjs:
string += "\n{wCharacters{n: " + ", ".join(["{c%s{n" % pobj.name for pobj in pobjs])
if things:
string += "\n{wContents{n: " + ", ".join([cont.name for cont in obj.contents
if cont not in exits and cont not in pobjs])
#output info
return "-"*78 + '\n' + string.strip() + "\n" + '-'*78
@ -1506,36 +1520,35 @@ class CmdExamine(ObjManipCommand):
caller.execute_cmd('look %s' % obj.name)
return
string = self.format_output(obj)
else:
# we have given a specific target object
string = ""
for objdef in self.lhs_objattr:
obj_name = objdef['name']
obj_attrs = objdef['attrs']
obj = caller.search(obj_name)
if not obj:
continue
if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead.
caller.execute_cmd('look %s' % obj_name)
continue
if obj_attrs:
for attrname in obj_attrs:
# we are only interested in specific attributes
string += self.format_attributes(obj, attrname, crop=False)
else:
string += self.format_output(obj)
string = string.strip()
# Send it all
if string:
caller.msg(string.strip())
return
# we have given a specific target object
string = ""
for objdef in self.lhs_objattr:
obj_name = objdef['name']
obj_attrs = objdef['attrs']
global player_mode
player_mode = "player" in self.switches or obj_name.startswith('*')
obj = caller.search(obj_name, player=player_mode)
if not obj:
continue
if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead.
caller.execute_cmd('look %s' % obj_name)
continue
if obj_attrs:
for attrname in obj_attrs:
# we are only interested in specific attributes
string += self.format_attributes(obj, attrname, crop=False)
else:
string += self.format_output(obj)
caller.msg(string.strip())
class CmdFind(MuxCommand):

View file

@ -18,17 +18,14 @@ class DefaultCmdSet(CmdSet):
# The general commands
self.add(general.CmdLook())
self.add(general.CmdHome())
self.add(general.CmdPassword())
self.add(general.CmdWho())
self.add(general.CmdInventory())
self.add(general.CmdQuit())
self.add(general.CmdPose())
self.add(general.CmdNick())
self.add(general.CmdGet())
self.add(general.CmdDrop())
self.add(general.CmdWho())
self.add(general.CmdSay())
self.add(general.CmdAccess())
self.add(general.CmdEncoding())
# The help system
self.add(help.CmdHelp())
@ -52,7 +49,6 @@ class DefaultCmdSet(CmdSet):
self.add(admin.CmdEmit())
self.add(admin.CmdNewPassword())
self.add(admin.CmdPerm())
self.add(admin.CmdPuppet())
self.add(admin.CmdWall())
# Building and world manipulation
@ -79,24 +75,6 @@ class DefaultCmdSet(CmdSet):
self.add(building.CmdLock())
self.add(building.CmdScript())
self.add(building.CmdHome())
# Comm commands
self.add(comms.CmdAddCom())
self.add(comms.CmdDelCom())
self.add(comms.CmdAllCom())
self.add(comms.CmdChannels())
self.add(comms.CmdCdestroy())
self.add(comms.CmdChannelCreate())
self.add(comms.CmdCset())
self.add(comms.CmdCBoot())
self.add(comms.CmdCemit())
self.add(comms.CmdCWho())
self.add(comms.CmdCdesc())
self.add(comms.CmdPage())
self.add(comms.CmdIRC2Chan())
self.add(comms.CmdIMC2Chan())
self.add(comms.CmdIMCInfo())
self.add(comms.CmdIMCTell())
# Batchprocessor commands
self.add(batchprocess.CmdBatchCommands())

View file

@ -0,0 +1,55 @@
"""
This is the cmdset for OutOfCharacter (OOC) commands.
These are stored on the Player object and should
thus be able to handle getting a Player object
as caller rather than a Character.
"""
from src.commands.cmdset import CmdSet
from src.commands.default import help, comms, general, admin
class OOCCmdSet(CmdSet):
"""
Implements the player command set.
"""
key = "DefaultOOC"
priority = -5
def at_cmdset_creation(self):
"Populates the cmdset"
# general commands
self.add(general.CmdOOCLook())
self.add(general.CmdIC())
self.add(general.CmdOOC())
self.add(general.CmdEncoding())
self.add(general.CmdQuit())
self.add(general.CmdPassword())
# help command
self.add(help.CmdHelp())
# admin commands
self.add(admin.CmdBoot())
self.add(admin.CmdDelPlayer())
self.add(admin.CmdNewPassword())
# Comm commands
self.add(comms.CmdAddCom())
self.add(comms.CmdDelCom())
self.add(comms.CmdAllCom())
self.add(comms.CmdChannels())
self.add(comms.CmdCdestroy())
self.add(comms.CmdChannelCreate())
self.add(comms.CmdCset())
self.add(comms.CmdCBoot())
self.add(comms.CmdCemit())
self.add(comms.CmdCWho())
self.add(comms.CmdCdesc())
self.add(comms.CmdPage())
self.add(comms.CmdIRC2Chan())
self.add(comms.CmdIMC2Chan())
self.add(comms.CmdIMCInfo())
self.add(comms.CmdIMCTell())

View file

@ -1,5 +1,11 @@
"""
Comsys command module.
Comsystem command module.
Comm commands are OOC commands and intended to be made available to
the Player at all times (they go into the PlayerCmdSet). So we
make sure to homogenize self.caller to always be the player object
for easy handling.
"""
from django.conf import settings
from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
@ -29,6 +35,25 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
caller.msg("Multiple channels match (be more specific): \n%s" % matches)
return None
return channels[0]
class CommCommand(MuxCommand):
"""
This is a parent for comm-commands. Since
These commands are to be available to the
Player, we make sure to homogenize the caller
here, so it's always seen as a player to the
command body.
"""
def parse(self):
"overload parts of parse"
# run parent
super(CommCommand, self).parse()
# fix obj->player
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
# an object. Convert it to its player.
self.caller = self.caller.player
class CmdAddCom(MuxCommand):
"""
@ -46,14 +71,14 @@ class CmdAddCom(MuxCommand):
key = "addcom"
aliases = ["aliaschan","chanalias"]
help_category = "Comms"
locks = "cmd:not perm(channel_banned)"
locks = "cmd:not pperm(channel_banned)"
def func(self):
"Implement the command"
caller = self.caller
args = self.args
player = caller.player
player = caller
if not args:
caller.msg("Usage: addcom [alias =] channelname.")
@ -120,7 +145,7 @@ class CmdDelCom(MuxCommand):
"Implementing the command. "
caller = self.caller
player = caller.player
player = caller
if not self.args:
caller.msg("Usage: delcom <alias or channel>")
@ -169,7 +194,7 @@ class CmdAllCom(MuxCommand):
"""
key = "allcom"
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -189,7 +214,7 @@ class CmdAllCom(MuxCommand):
caller.execute_cmd("addcom %s" % channel.key)
elif args == "off":
#get names all subscribed channels and disconnect from them all
channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)]
channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)]
for channel in channels:
caller.execute_cmd("delcom %s" % channel.key)
elif args == "destroy":
@ -230,7 +255,7 @@ class CmdChannels(MuxCommand):
key = "@channels"
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
help_category = "Comms"
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
def func(self):
"Implement function"
@ -243,7 +268,7 @@ class CmdChannels(MuxCommand):
caller.msg("No channels available.")
return
# all channel we are already subscribed to
subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)]
subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)]
if self.cmdstring != "comlist":
@ -298,7 +323,7 @@ class CmdCdestroy(MuxCommand):
key = "@cdestroy"
help_category = "Comms"
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
def func(self):
"Destroy objects cleanly."
@ -337,7 +362,7 @@ class CmdCBoot(MuxCommand):
"""
key = "@cboot"
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -352,12 +377,12 @@ class CmdCBoot(MuxCommand):
if not channel:
return
reason = ""
player = None
if ":" in self.rhs:
playername, reason = self.rhs.rsplit(":", 1)
player = self.caller.search("*%s" % playername.lstrip('*'))
if not player:
player = self.caller.search("*%s" % self.rhs.lstrip('*'))
searchstring = playername.lstrip('*')
else:
searchstring = self.rhs.lstrip('*')
player = self.caller.search(searchstring, player=True)
if not player:
return
if reason:
@ -400,7 +425,7 @@ class CmdCemit(MuxCommand):
key = "@cemit"
aliases = ["@cmsg"]
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -437,7 +462,7 @@ class CmdCWho(MuxCommand):
List who is connected to a given channel you have access to.
"""
key = "@cwho"
locks = "cmd: not perm(channel_banned)"
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -475,7 +500,7 @@ class CmdChannelCreate(MuxCommand):
key = "@ccreate"
aliases = "channelcreate"
locks = "cmd:not perm(channel_banned)"
locks = "cmd:not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -522,7 +547,7 @@ class CmdCset(MuxCommand):
"""
key = "@cset"
locks = "cmd:not perm(channel_banned)"
locks = "cmd:not pperm(channel_banned)"
aliases = ["@cclock"]
help_category = "Comms"
@ -568,7 +593,7 @@ class CmdCdesc(MuxCommand):
"""
key = "@cdesc"
locks = "cmd:not perm(channel_banned)"
locks = "cmd:not pperm(channel_banned)"
help_category = "Comms"
def func(self):
@ -611,7 +636,7 @@ class CmdPage(MuxCommand):
key = "page"
aliases = ['tell']
locks = "cmd:not perm(page_banned)"
locks = "cmd:not pperm(page_banned)"
help_category = "Comms"
def func(self):
@ -619,7 +644,7 @@ class CmdPage(MuxCommand):
"Implement function using the Msg methods"
caller = self.caller
player = caller.player
player = caller
# get the messages we've sent
messages_we_sent = list(Msg.objects.get_messages_by_sender(player))
@ -751,7 +776,7 @@ class CmdIRC2Chan(MuxCommand):
"""
key = "@irc2chan"
locks = "cmd:serversetting(IRC_ENABLED) and perm(Immortals)"
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Immortals)"
help_category = "Comms"
def func(self):
@ -840,7 +865,7 @@ class CmdIMC2Chan(MuxCommand):
"""
key = "@imc2chan"
locks = "cmd:serversetting(IMC2_ENABLED) and perm(Immortals)"
locks = "cmd:serversetting(IMC2_ENABLED) and pperm(Immortals)"
help_category = "Comms"
def func(self):
@ -923,7 +948,7 @@ class CmdIMCInfo(MuxCommand):
key = "@imcinfo"
aliases = ["@imcchanlist", "@imclist", "@imcwhois"]
locks = "cmd: serversetting(IMC2_ENABLED) and perm(Wizards)"
locks = "cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)"
help_category = "Comms"
def func(self):
@ -982,7 +1007,7 @@ class CmdIMCInfo(MuxCommand):
return
from src.comms.imc2 import IMC2_CLIENT
self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.")
IMC2_CLIENT.msg_imc2(None, from_obj=self.caller.player, packet_type="imcwhois", data={"target":self.args})
IMC2_CLIENT.msg_imc2(None, from_obj=self.caller, packet_type="imcwhois", data={"target":self.args})
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
# show channels
@ -1051,6 +1076,6 @@ class CmdIMCTell(MuxCommand):
data = {"target":target, "destination":destination}
# send to imc2
IMC2_CLIENT.msg_imc2(message, from_obj=self.caller.player, packet_type="imctell", data=data)
IMC2_CLIENT.msg_imc2(message, from_obj=self.caller, packet_type="imctell", data=data)
self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))

View file

@ -5,11 +5,13 @@ now.
import time
from django.conf import settings
from src.server.sessionhandler import SESSIONS
from src.objects.models import HANDLE_SEARCH_ERRORS
from src.utils import utils
from src.objects.models import Nick
from src.objects.models import ObjectNick as Nick
from src.commands.default.muxcommand import MuxCommand
AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
class CmdHome(MuxCommand):
"""
home
@ -45,7 +47,7 @@ class CmdLook(MuxCommand):
Observes your location or objects in your vicinity.
"""
key = "look"
aliases = ["l"]
aliases = ["l", "ls"]
locks = "cmd:all()"
def func(self):
@ -53,18 +55,19 @@ class CmdLook(MuxCommand):
Handle the looking.
"""
caller = self.caller
args = self.args # caller.msg(inp)
args = self.args
if args:
# Use search to handle duplicate/nonexistant results.
looking_at_obj = caller.search(args, use_nicks=True)
if not looking_at_obj:
return
return
else:
looking_at_obj = caller.location
if not looking_at_obj:
caller.msg("Location: None")
caller.msg("You have no location to look at!")
return
if not hasattr(looking_at_obj, 'return_appearance'):
# this is likely due to us having a player instead
looking_at_obj = looking_at_obj.character
@ -89,6 +92,8 @@ class CmdPassword(MuxCommand):
"hook function."
caller = self.caller
if hasattr(caller, "player"):
caller = caller.player
if not self.rhs:
caller.msg("Usage: @password <oldpass> = <newpass>")
@ -96,7 +101,7 @@ class CmdPassword(MuxCommand):
oldpass = self.lhslist[0] # this is already stripped by parse()
newpass = self.rhslist[0] # ''
try:
uaccount = caller.player.user
uaccount = caller.user
except AttributeError:
caller.msg("This is only applicable for players.")
return
@ -309,7 +314,7 @@ class CmdDrop(MuxCommand):
# those in our inventory.
results = [obj for obj in results if obj in caller.contents]
# now we send it into the handler.
obj = HANDLE_SEARCH_ERRORS(caller, self.args, results, False)
obj = AT_SEARCH_RESULT(caller, self.args, results, False)
if not obj:
return
@ -348,13 +353,13 @@ class CmdWho(MuxCommand):
who
doing
Shows who is currently online. Doing is an
alias that limits info also for those with
all permissions.
Shows who is currently online. Doing is an alias that limits info
also for those with all permissions.
"""
key = "who"
aliases = "doing"
locks = "cmd:all()"
def func(self):
"""
@ -518,17 +523,20 @@ class CmdEncoding(MuxCommand):
Sets the encoding.
"""
caller = self.caller
if hasattr(caller, 'player'):
caller = caller.player
if 'clear' in self.switches:
# remove customization
old_encoding = caller.player.db.encoding
old_encoding = caller.db.encoding
if old_encoding:
string = "Your custom text encoding ('%s') was cleared." % old_encoding
else:
string = "No custom encoding was set."
del caller.player.db.encoding
del caller.db.encoding
elif not self.args:
# just list the encodings supported
pencoding = caller.player.db.encoding
pencoding = caller.db.encoding
string = ""
if pencoding:
string += "Default encoding: {g%s{n (change with {w@encoding <encoding>{n)" % pencoding
@ -539,9 +547,9 @@ class CmdEncoding(MuxCommand):
string = "No encodings found."
else:
# change encoding
old_encoding = caller.player.db.encoding
old_encoding = caller.db.encoding
encoding = self.args
caller.player.db.encoding = encoding
caller.db.encoding = encoding
string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding)
caller.msg(string.strip())
@ -579,3 +587,141 @@ class CmdAccess(MuxCommand):
if hasattr(caller, 'player'):
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
caller.msg(string)
# OOC commands
class CmdOOCLook(CmdLook):
"""
ooc look
Usage:
look
This is an OOC version of the look command. Since a
Player doesn't have an in-game existence, there is no
concept of location or "self". If we are controlling
a character, pass control over to normal look.
"""
key = "look"
aliases = ["l", "ls"]
locks = "cmd:all()"
help_cateogory = "General"
def func(self):
"implement the command"
self.character = None
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
# An object of some type is calling. Convert to player.
self.character = self.caller
self.caller = self.caller.player
if not self.character:
string = "You are out-of-character (OOC). "
string += "Use {w@ic{n to get back to the game, {whelp{n for more info."
self.caller.msg(string)
else:
self.caller = self.character # we have to put this back for normal look to work.
super(CmdLook, self).func()
class CmdIC(MuxCommand):
"""
Switch control to an object
Usage:
@ic <character>
Go in-character (IC) as a given Character.
This will attempt to "become" a different object assuming you have
the right to do so. You cannot become an object that is already
controlled by another player. In principle <character> can be
any in-game object as long as you have access right to puppet it.
"""
key = "@ic"
locks = "cmd:all()" # must be all() or different puppeted objects won't be able to access it.
aliases = "@puppet"
help_category = "General"
def func(self):
"""
Simple puppet method
"""
caller = self.caller
if utils.inherits_from(caller, "src.objects.objects.Object"):
caller = caller.player
new_character = None
if not self.args:
new_character = caller.db.last_puppet
if not new_character:
caller.msg("Usage: @ic <character>")
return
if not new_character:
# search for a matching character
new_character = caller.search(self.args)
if not new_character:
# the search method handles error messages etc.
return
if new_character.player:
if new_character.player == caller:
caller.msg("{RYou already are {c%s{n." % new_character.name)
else:
caller.msg("{c%s{r is already acted by another player.{n" % new_character.name)
return
if not new_character.access(caller, "puppet"):
caller.msg("{rYou may not become %s.{n" % new_character.name)
return
old_char = None
if caller.character:
# save the old character. We only assign this to last_puppet if swap is successful.
old_char = caller.character
if caller.swap_character(new_character):
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
caller.db.last_puppet = old_char
new_character.execute_cmd("look")
else:
caller.msg("{rYou cannot become {C%s{n." % new_character.name)
class CmdOOC(MuxCommand):
"""
@ooc - go ooc
Usage:
@ooc
Go out-of-character (OOC).
This will leave your current character and put you in a incorporeal OOC state.
"""
key = "@ooc"
locks = "cmd:all()" # this must be all(), or different puppeted objects won't be able to access it.
aliases = "@unpuppet"
help_category = "General"
def func(self):
"Implement function"
caller = self.caller
if utils.inherits_from(caller, "src.objects.objects.Object"):
caller = self.caller.player
if not caller.character:
string = "You are already OOC."
caller.msg(string)
return
caller.db.last_puppet = caller.character
# disconnect
caller.character.player = None
caller.character = None
caller.msg("\n{GYou go OOC.{n\n")
caller.execute_cmd("look")

View file

@ -441,5 +441,12 @@ class TestCwho(CommandTest):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("@cwho testchan1b", "Channel subscriptions")
# OOC commands
#class TestOOC_and_IC(CommandTest): # can't be tested it seems, causes errors in other commands (?)
# def test_call(self):
# self.execute_cmd("@ooc", "\nYou go OOC.")
# self.execute_cmd("@ic", "\nYou become TestChar")
# Unloggedin commands
# these cannot be tested from here.

View file

@ -62,49 +62,81 @@ class CmdConnect(MuxCommand):
# We are logging in, get/setup the player object controlled by player
character = player.character
if not character:
# Create a new character object to tie the player to. This should
# usually not be needed unless the old character object was manually
# deleted.
default_home_id = ServerConfig.objects.conf("default_home")
default_home = ObjectDB.objects.get_id(default_home_id)
typeclass = settings.BASE_CHARACTER_TYPECLASS
character = create.create_object(typeclass=typeclass,
key=player.name,
location=default_home,
home=default_home,
player=player)
character.db.FIRST_LOGIN = "True"
# Getting ready to log the player in.
# Check if this is the first time the
# *player* connects
if player.db.FIRST_LOGIN:
player.at_first_login()
del player.db.FIRST_LOGIN
# check if this is the first time the *character*
# character (needs not be the first time the player
# does so, e.g. if the player has several characters)
if character.db.FIRST_LOGIN:
character.at_first_login()
del character.db.FIRST_LOGIN
# actually do the login, calling
# customization hooks before and after.
player.at_pre_login()
character.at_pre_login()
character = player.character
if character:
# this player has a character. Check if it's the
# first time *this character* logs in
if character.db.FIRST_LOGIN:
character.at_first_login()
del character.db.FIRST_LOGIN
# run character login hook
character.at_pre_login()
# actually do the login
session.session_login(player)
# post-login hooks
player.at_post_login()
if character:
character.at_post_login()
character.execute_cmd('look')
else:
player.execute_cmd('look')
player.at_post_login()
character.at_post_login()
# run look
#print "character:", character, character.scripts.all(), character.cmdset.current
character.execute_cmd('look')
#
# character = player.character
# if not character:
# # Create a new character object to tie the player to. This should
# # usually not be needed unless the old character object was manually
# # deleted.
# default_home_id = ServerConfig.objects.conf("default_home")
# default_home = ObjectDB.objects.get_id(default_home_id)
# typeclass = settings.BASE_CHARACTER_TYPECLASS
# character = create.create_object(typeclass=typeclass,
# key=player.name,
# location=default_home,
# home=default_home,
# player=player)
# character.db.FIRST_LOGIN = "True"
# # Getting ready to log the player in.
# # Check if this is the first time the
# # *player* connects
# if player.db.FIRST_LOGIN:
# player.at_first_login()
# del player.db.FIRST_LOGIN
# # check if this is the first time the *character*
# # character (needs not be the first time the player
# # does so, e.g. if the player has several characters)
# if character.db.FIRST_LOGIN:
# character.at_first_login()
# del character.db.FIRST_LOGIN
# # actually do the login, calling
# # customization hooks before and after.
# player.at_pre_login()
# character.at_pre_login()
# session.session_login(player)
# player.at_post_login()
# character.at_post_login()
# # run look
# #print "character:", character, character.scripts.all(), character.cmdset.current
# character.execute_cmd('look')
class CmdCreate(MuxCommand):
"""
@ -169,61 +201,69 @@ class CmdCreate(MuxCommand):
return
# Run sanity and security checks
if PlayerDB.objects.get_player_from_name(playername) or User.objects.filter(username=playername):
# player already exists
session.msg("Sorry, there is already a player with the name '%s'." % playername)
elif PlayerDB.objects.get_player_from_email(email):
return
if PlayerDB.objects.get_player_from_email(email):
# email already set on a player
session.msg("Sorry, there is already a player with that email address.")
elif len(password) < 3:
return
if len(password) < 3:
# too short password
string = "Your password must be at least 3 characters or longer."
string += "\n\rFor best security, make it at least 8 characters long, "
string += "avoid making it a real word and mix numbers into it."
session.msg(string)
else:
# everything's ok. Create the new player account
try:
default_home_id = ServerConfig.objects.conf("default_home")
default_home = ObjectDB.objects.get_id(default_home_id)
typeclass = settings.BASE_CHARACTER_TYPECLASS
permissions = settings.PERMISSION_PLAYER_DEFAULT
return
new_character = create.create_player(playername, email, password,
permissions=permissions,
location=default_home,
typeclass=typeclass,
home=default_home)
# character safety features
new_character.locks.delete("get")
new_character.locks.add("get:perm(Wizards)")
# everything's ok. Create the new player account.
try:
default_home_id = ServerConfig.objects.conf("default_home")
default_home = ObjectDB.objects.get_id(default_home_id)
# set a default description
new_character.db.desc = "This is a Player."
typeclass = settings.BASE_CHARACTER_TYPECLASS
permissions = settings.PERMISSION_PLAYER_DEFAULT
new_character.db.FIRST_LOGIN = True
new_player = new_character.player
new_player.db.FIRST_LOGIN = True
# join the new player to the public channel
pchanneldef = settings.CHANNEL_PUBLIC
if pchanneldef:
pchannel = Channel.objects.get_channel(pchanneldef[0])
if not pchannel.connect_to(new_player):
string = "New player '%s' could not connect to public channel!" % new_player.key
logger.log_errmsg(string)
new_character = create.create_player(playername, email, password,
permissions=permissions,
location=default_home,
typeclass=typeclass,
home=default_home)
new_player = new_character.player
# character safety features
new_character.locks.delete("get")
new_character.locks.add("get:perm(Wizards)")
# allow the character itself and the player to puppet this character.
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
(new_character.id, new_player.id))
string = "A new account '%s' was created with the email address %s. Welcome!"
string += "\n\nYou can now log with the command 'connect %s <your password>'."
session.msg(string % (playername, email, email))
except Exception:
# we have to handle traceback ourselves at this point, if
# we don't, errors will give no feedback.
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
session.msg(string % (traceback.format_exc()))
logger.log_errmsg(traceback.format_exc())
# set a default description
new_character.db.desc = "This is a Player."
new_character.db.FIRST_LOGIN = True
new_player = new_character.player
new_player.db.FIRST_LOGIN = True
# join the new player to the public channel
pchanneldef = settings.CHANNEL_PUBLIC
if pchanneldef:
pchannel = Channel.objects.get_channel(pchanneldef[0])
if not pchannel.connect_to(new_player):
string = "New player '%s' could not connect to public channel!" % new_player.key
logger.log_errmsg(string)
string = "A new account '%s' was created with the email address %s. Welcome!"
string += "\n\nYou can now log with the command 'connect %s <your password>'."
session.msg(string % (playername, email, email))
except Exception:
# We are in the middle between logged in and -not, so we have to handle tracebacks
# ourselves at this point. If we don't, we won't see any errors at all.
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
session.msg(string % (traceback.format_exc()))
logger.log_errmsg(traceback.format_exc())
class CmdQuit(MuxCommand):
"""