nakedmud-mod/
nakedmud-mod/html/tutorials/
nakedmud-mod/html/tutorials/building_extras/
nakedmud-mod/html/tutorials/c/
nakedmud-mod/html/tutorials/reference/
nakedmud-mod/html/tutorials/scripting/
nakedmud-mod/html/tutorials/scripting_extras/
nakedmud-mod/lib/
nakedmud-mod/lib/help/A/
nakedmud-mod/lib/help/B/
nakedmud-mod/lib/help/C/
nakedmud-mod/lib/help/D/
nakedmud-mod/lib/help/G/
nakedmud-mod/lib/help/H/
nakedmud-mod/lib/help/J/
nakedmud-mod/lib/help/L/
nakedmud-mod/lib/help/M/
nakedmud-mod/lib/help/O/
nakedmud-mod/lib/help/P/
nakedmud-mod/lib/help/R/
nakedmud-mod/lib/help/S/
nakedmud-mod/lib/help/W/
nakedmud-mod/lib/logs/
nakedmud-mod/lib/misc/
nakedmud-mod/lib/players/
nakedmud-mod/lib/pymodules/polc/
nakedmud-mod/lib/txt/
nakedmud-mod/lib/world/
nakedmud-mod/lib/world/zones/examples/
nakedmud-mod/lib/world/zones/examples/mproto/
nakedmud-mod/lib/world/zones/examples/oproto/
nakedmud-mod/lib/world/zones/examples/reset/
nakedmud-mod/lib/world/zones/examples/rproto/
nakedmud-mod/lib/world/zones/examples/trigger/
nakedmud-mod/lib/world/zones/limbo/
nakedmud-mod/lib/world/zones/limbo/room/
nakedmud-mod/lib/world/zones/limbo/rproto/
nakedmud-mod/src/alias/
nakedmud-mod/src/dyn_vars/
nakedmud-mod/src/editor/
nakedmud-mod/src/example_module/
nakedmud-mod/src/help2/
nakedmud-mod/src/set_val/
nakedmud-mod/src/socials/
nakedmud-mod/src/time/
'''
cmd_manip.py

a set of commands that NakedMud(tm) comes with that allows characters to
manipulate various things. These commands are mostly directed towards
manipulating objects (e.g. get, put, drop, etc...) but can also affect other
things like exits (e.g. open, close)
'''
import mudsys, mud, inform, utils, movement, hooks
import obj as mudobj



def do_give(ch, recv, obj):
    '''does the handling of the give command'''
    mud.message(ch, recv, obj, None, True, "to_room",
                "$n gives $o to $N.")
    mud.message(ch, recv, obj, None, True, "to_vict",
                "$n gives $o to you.")
    mud.message(ch, recv, obj, None, True, "to_char",
                "You give $o to $N.")
    obj.carrier = recv

    # run our give hook
    hooks.run("give", hooks.build_info("ch ch obj", (ch, recv, obj)))

def cmd_give(ch, cmd, arg):
    '''Usage: give <object> [to] <person>

       Attempts to transfer an object from your inventory to the specified
       person. You can give multiple objects at a time by using the all.
       prefix. For example:

       > give all.cookie george

       Would give all of the cookies in your inventory to George. If you only
       want to give him the raisin cookie, which also happens to be the third
       cookie in your inventory, you can use a numeric prefix instead of
       the all prefix. For example:

       > give 3.cookie george'''
    try:
        to_give, multi, recv = mud.parse_args(ch, True, cmd, arg,
                                              "[the] obj.inv.multiple " +
                                              "[to] ch.room.noself")
    except: return

    if multi == False:
        do_give(ch, recv, to_give)
    else:
        for obj in to_give:
            do_give(ch, recv, obj)

def do_get(ch, obj, cont):
    '''transfers an item from the ground to the character'''
    if utils.is_keyword(obj.bits, "notake"):
        ch.send("You cannot take " + ch.see_as(obj) + ".")
    elif cont != None:
        obj.carrier = ch
        mud.message(ch, None, obj, cont, True, "to_char", "You get $o from $O.")
        mud.message(ch, None, obj, cont, True, "to_room", "$n gets $o from $O.")
    else:
        obj.carrier = ch
        mud.message(ch, None, obj, None, True, "to_char", "You get $o.")
        mud.message(ch, None, obj, None, True, "to_room", "$n gets $o.")

        # run get hooks
        hooks.run("get", hooks.build_info("ch obj", (ch, obj)))

def try_get_from(ch, cont, arg):
    '''tries to get one item from inside another'''
    if not cont.istype("container"):
        mud.message(ch, None, cont, None, True, "to_char",
                    "$o is not a container.")
    elif cont.container_is_closed:
        mud.message(ch, None, cont, None, True, "to_char", "$o is closed.")
    else:
        # find our count and name
        num, name = utils.get_count(arg)

        # multi or single?
        if num == "all":
            list = utils.find_all_objs(ch, cont.objs, name)
            for obj in list:
                do_get(ch, obj, cont)
        else:
            # obj = find_obj(ch, cont.objs, num, name)
            obj = mudobj.find_obj(arg, cont, ch)
            if obj != None:
                do_get(ch, obj, cont)
            else:
                mud.message(ch, None, cont, None, True, "to_char",
                            "You could not find what you were looking for in $o.")

def cmd_get(ch, cmd, arg):
    '''Usage: get [the] <item> [[from] <other item>]

       Attempts to move an object from the room to your inventory. If an
       addition argument is supplied, the command assumes it is a container and
       instead tries to move an object from the container to your inventory.'''
    try:
        arg,cont = mud.parse_args(ch, True, cmd, arg,
                                  "[the] word(object) | [from] obj.room.inv.eq")
    except: return
    
    # are we doing get, or get-from?
    if cont != None:
        try_get_from(ch, cont, arg)
    else:
        # try to find the object in the room
        try:
            found,multi= mud.parse_args(ch, True, cmd, arg, "obj.room.multiple")
        except: return

        # pick up all the items we want
        if multi == False:
            do_get(ch, found, None)
        else:
            for obj in found:
                do_get(ch, obj, None)

def do_drop(ch, obj):
    '''handles object dropping'''
    obj.room = ch.room

    mud.message(ch, None, obj, None, True, "to_char", "You drop $o.")
    mud.message(ch, None, obj, None, True, "to_room", "$n drops $o.")

    # run our drop hook
    hooks.run("drop", hooks.build_info("ch obj", (ch, obj)))

def cmd_drop(ch, cmd, arg):
    '''Usage: drop <item>

       Attempts to move an object from your inventory to the ground.'''
    try:
        found,multi=mud.parse_args(ch, True, cmd, arg, "[the] obj.inv.multiple")
    except: return

    # are we dropping a list of things, or just one?
    if multi == False:
        do_drop(ch, found)
    else:
        for obj in found:
            do_drop(ch, obj)

def do_remove(ch, obj):
    '''handles equipment removing'''
    # try to put it to our inventory
    obj.carrier = ch

    # make sure it succeeded
    if obj.carrier != ch:
        ch.send("You were unable to remove " + ch.see_as(obj) + ".")
    else:
        mud.message(ch, None, obj, None, True, "to_char", "You remove $o.")
        mud.message(ch, None, obj, None, True, "to_room", "$n removes $o.")

        # run our hooks
        hooks.run("remove", hooks.build_info("ch obj", (ch, obj)))

def cmd_remove(ch, cmd, arg):
    '''Usage: remove <item | all>

       Attempts to remove an item you have equipped. If you would like to
       remove everything you are wearing, you may instead specify \'all\'
       instead of a specific item. If you would like to remove all of a certain
       type of object (for instance, rings) you can use an all. prefix. For
       example:

       > remove all.ring

       This command will remove everything you are wearing with the \'ring\'
       keyword. If you would instead like to remove, say, the second thing you
       are wearing with the \'ring\' keyword, you can supply a numeric prefix.
       For example:

       > remove 2.ring'''
    try:
        found,multi= mud.parse_args(ch, True, cmd, arg, "[the] obj.eq.multiple")
    except: return

    # are we removing one thing, or multiple things?
    if multi == False:
        do_remove(ch, found)
    else:
        for obj in found:
            do_remove(ch, obj)

def do_wear(ch, obj, where):
    '''handles object wearing'''
    if not obj.istype("worn"):
        ch.send("But " + ch.see_as(obj) + " is not equippable.")
        
    elif ch.equip(obj, where):
        mud.message(ch, None, obj, None, True, "to_char", "You wear $o.")
        mud.message(ch, None, obj, None, True, "to_room", "$n wears $o.")

        # run our wear hook
        hooks.run("wear", hooks.build_info("ch obj", (ch, obj)))

def cmd_wear(ch, cmd, arg):
    '''Usage: wear <item> [where]

       Attempts to equip an item from your inventory. If you would like to
       equip it to a non-default location, you can supply where on your body
       you would like to wear it. For example, if you would like to equip a
       torch, but in your offhand instead of your mainhand:

       > wear torch offhand

       If an item covers multiple locations on your body, you can specify where
       all you would like to equip the item as a comma-separated list:

       > wear gloves left hand, right hand'''
    try:
        found, multi, where = mud.parse_args(ch, True, cmd, arg,
                                             "[the] obj.inv.multiple | [on] string(bodyparts)")
    except: return

    # Are the things we're looking for not body positions? Try to catch this!
    # it will happen when someone enters multiple arguments for the name without
    # supplying ' and ' around it. The mud will misinterpret it as an item
    if not multi and where != None and not "," in where:
        # reparse what we want!
        if not where in ch.bodyparts:
            where = None
            try:
                found, = mud.parse_args(ch,True,cmd,"'"+arg+"'","[the] obj.inv")
            except: return

    # are we wearing one thing, or multiple things?
    if multi == False:
        do_wear(ch, found, where)
    else:
        for obj in found:
            do_wear(ch, obj, where)

def do_put(ch, obj, cont):
    '''handles the putting of objects'''
    if obj == cont:
        ch.send("You cannot put " + ch.see_as(obj) + " into itself.")
    # make sure we have enough room 
    elif obj.weight > cont.container_capacity - cont.weight + cont.weight_raw:
        ch.send("There is not enough room in " + ch.see_as(cont) +
                " for " + ch.see_as(obj) + ".")
    # do the move
    else:
        obj.container = cont
        mud.message(ch, None, obj, cont, True, "to_char", "You put $o in $O.")
        mud.message(ch, None, obj, cont, True, "to_room", "$n puts $o in $O.")

def cmd_put(ch, cmd, arg):
    '''Usage: put [the] <item> [in the] <container>

       Attempts to move an object from your inventory into a specified
       container. The container must be in the room, in your inventory, or
       worn.'''
    try:
        found, multi, cont = mud.parse_args(ch, True, cmd, arg,
                                            "[the] obj.inv.multiple " +
                                            "[in] [the] obj.room.inv")
    except: return

    # make sure we have a container
    if not cont.istype("container"):
        ch.send(ch.see_as(cont) + " is not a container.")
    elif cont.container_is_closed:
        ch.send(ch.see_as(cont) + " is currently closed.")
    # do we have one or multiple items?
    elif multi == False:
        do_put(ch, found, cont)
    else:
        for obj in found:
            do_put(ch, obj, cont)

def try_manip_other_exit(room, ex, closed, locked):
    '''used by open, close, lock, and unlock. When an exit is manipulated on one
       side, it is the case that we'll want to do an identical manipulation on
       the other side. That's what we do here. Note: Can only do close OR lock
       with one call to this function. Cannot handle both at the same time!'''
    opp_dir = None
    if ex.dest == None:
        return

    # see if we can figure out the opposite direction
    if ex.opposite != '':
        opp_dir = ex.opposite
    else:
        # figure out the direction of the exit, and its opposite
        dirnum = movement.dir_index(room.exdir(ex))
        if dirnum != -1:
            opp_dir = movement.dir_name[movement.dir_opp[dirnum]]

    # do we have an opposite direction to manipulate?
    if opp_dir == None:
        return

    # do we have an opposite exit to manipulate?
    opp_ex = ex.dest.exit(opp_dir)
    if opp_ex != None:
        # figure out our name
        name = "an exit"
        if opp_ex.name != '':
            name = opp_ex.name

        # try to manipulate the exit
        if closed and not opp_ex.is_closed:
            opp_ex.close()
            ex.dest.send(name + " closes from the other side.")
        elif locked and opp_ex.is_closed and not opp_ex.is_locked:
            opp_ex.lock()
            ex.dest.send(name + " locks from the other side.")
        elif not closed and opp_ex.is_closed and not opp_ex.is_locked:
            opp_ex.open()
            ex.dest.send(name + " opens from the other side.")
        elif not locked and opp_ex.is_locked:
            opp_ex.unlock()
            ex.dest.send(name + " unlocks from the other side.")
        else:
            return
        # hooks.run("room_change", hooks.build_info("rm", (opp_ex.room, )))

def cmd_lock(ch, cmd, arg):
    '''Usage: lock <direction | door | container>

       Attempts to lock a specified door, direction, or container.'''
    try:
        found, type = mud.parse_args(ch, True, cmd, arg,
                                     "[the] {obj.room.inv.eq exit }")
    except: return

    # what did we find?
    if type == "exit":
        ex = found
        name = ex.name
        if ex.name == "":
            name = "the exit"
        
        if not ex.is_closed:
            ch.send(name + " must be closed first.")
        elif ex.is_locked:
            ch.send(name + " is already locked.")
        elif ex.key == '':
            ch.send("You cannot figure out how " + name +" would be locked.")
        elif not has_proto(ch, ex.key):
            ch.send("You cannot seem to find the key.")
        else:
            mud.message(ch, None, None, None, True, "to_char",
                        "You lock " + name + ".")
            mud.message(ch, None, None, None, True, "to_room",
                        "$n locks " + name + ".")
            ex.lock()
            # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
            try_manip_other_exit(ch.room, ex, ex.is_closed, True)

    # type must be object
    else:
        obj = found
        if not obj.istype("container"):
            ch.send(ch.see_as(obj) + " is not a container.")
        elif not obj.container_is_closed:
            ch.send(ch.see_as(obj) + " is not closed.")
        elif obj.container_is_locked:
            ch.send(ch.see_as(obj) + " is already locked.")
        elif obj.container_key == '':
            ch.send("You cannot figure out how to lock " + ch.see_as(obj))
        elif not has_proto(ch, obj.container_key):
            ch.send("You cannot seem to find the key.")
        else:
            mud.message(ch, None, obj, None, True, "to_char", "You lock $o.")
            mud.message(ch, None, obj, None, True, "to_room", "$n locks $o.")
            obj.container_is_locked = True

def cmd_unlock(ch, cmd, arg):
    '''Usage: unlock <door | direction | container>

       Attempts to unlock the specified door, direction, or container.'''
    try:
        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
    except: return

    # what did we find?
    if type == "exit":
        ex = found
        name = ex.name
        if ex.name == "":
            name = "the exit"
        
        if not ex.is_closed:
            ch.send(name + " is already open.")
        elif not ex.is_locked:
            ch.send(name + " is already unlocked.")
        elif ex.key == '':
            ch.send("You cannot figure out how " + name +
                    " would be unlocked.")
        elif not has_proto(ch, ex.key):
            ch.send("You cannot seem to find the key.")
        else:
            mud.message(ch, None, None, None, True, "to_char",
                        "You unlock " + name + ".")
            mud.message(ch, None, None, None, True, "to_room",
                        "$n unlocks " + name + ".")
            ex.unlock()
            # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
            try_manip_other_exit(ch.room, ex, ex.is_closed, False)

    # must be an object
    else:
        obj = found
        if not obj.istype("container"):
            ch.send(ch.see_as(obj) + " is not a container.")
        elif not obj.container_is_closed:
            ch.send(ch.see_as(obj) + " is already open.")
        elif not obj.container_is_locked:
            ch.send(ch.see_as(obj) + " is already unlocked.")
        elif obj.container_key == '':
            ch.send("You cannot figure out how to unlock "+ ch.see_as(obj))
        elif not has_proto(ch, obj.container_key):
            ch.send("You cannot seem to find the key.")
        else:
            mud.message(ch, None, obj, None, True, "to_char", "You unlock $o.")
            mud.message(ch, None, obj, None, True, "to_room", "$n unlocks $o.")
            obj.container_is_locked = False

def cmd_open(ch, cmd, arg):
    '''Usage: open [the] <direction | door | container>

       Attempts to open the speficied door, direction, or container.'''
    try:
        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
    except: return

    # is it an exit?
    if type == "exit":
        ex = found
        name = ex.name
        if name == "":
            name = "the exit"
        
        if not ex.is_closed:
            ch.send(name + " is already open.")
        elif ex.is_locked:
            ch.send(name + " must be unlocked first.")
        elif not ex.is_closable:
            ch.send(name + " cannot be opened.")
        else:
            mud.message(ch, None, None, None, True, "to_char",
                        "You open " + name + ".")
            mud.message(ch, None, None, None, True, "to_room",
                        "$n opens " + name + ".")
            ex.open()
            # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
            try_manip_other_exit(ch.room, ex, False, ex.is_locked)
            hooks.run("open_door", hooks.build_info("ch ex", (ch, ex)))

    # must be an object
    else:
        obj = found
        if not obj.istype("container"):
            ch.send(ch.see_as(obj) + " is not a container.")
        elif not obj.container_is_closed:
            ch.send(ch.see_as(obj) + " is already open.")
        elif obj.container_is_locked:
            ch.send(ch.see_as(obj) + " must be unlocked first.")
        elif not obj.container_is_closable:
            ch.send(ch.see_as(obj) + " cannot be opened.")
        else:
            mud.message(ch, None, obj, None, True, "to_char", "You open $o.")
            mud.message(ch, None, obj, None, True, "to_room", "$n opens $o.")
            obj.container_is_closed = False
            hooks.run("open_obj", hooks.build_info("ch obj", (ch, obj)))

def cmd_close(ch, cmd, arg):
    '''Usage: close <direction | door | container>

       Attempts to close the specified door, direction, or container.'''
    try:
        found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
    except: return

    # is it an exit?
    if type == "exit":
        ex = found
        name = ex.name
        if name == "":
            name = "the exit"

        if ex.is_closed:
            ch.send(name + " is already closed.")
        elif ex.is_locked:
            ch.send(name + " must be unlocked first.")
        elif not ex.is_closable:
            ch.send(name + " cannot be closed.")
        else:
            mud.message(ch, None, None, None, True, "to_char",
                        "You close " + name + ".")
            mud.message(ch, None, None, None, True, "to_room",
                        "$n closes " + name + ".")
            ex.close()
            # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
            try_manip_other_exit(ch.room, ex, True, ex.is_locked) 
            hooks.run("open_door", hooks.build_info("ch ex", (ch, ex)))

    # must be an object
    else:
        obj = found
        if not obj.istype("container"):
            ch.send(ch.see_as(obj) + " is not a container.")
        elif obj.container_is_closed:
            ch.send(ch.see_as(obj) + " is already closed.")
        elif not obj.container_is_closable:
            ch.send(ch.see_as(obj) + " cannot be closed.")
        else:
            mud.message(ch, None, obj, None, True, "to_char", "You close $o.")
            mud.message(ch, None, obj, None, True, "to_room", "$n closes $o.")
            obj.container_is_closed = True
            hooks.run("close_obj", hooks.build_info("ch obj", (ch, obj)))



################################################################################
# load all of our commands
################################################################################
mudsys.add_cmd("give",   None, cmd_give,   "player", True)
mudsys.add_cmd("get",    None, cmd_get,    "player", True)
mudsys.add_cmd("drop",   None, cmd_drop,   "player", True)
mudsys.add_cmd("remove", None, cmd_remove, "player", True)
mudsys.add_cmd("wear",   None, cmd_wear,   "player", True)
mudsys.add_cmd("put",    None, cmd_put,    "player", True)
mudsys.add_cmd("open",   None, cmd_open,   "player", True)
mudsys.add_cmd("close",  None, cmd_close,  "player", True)
mudsys.add_cmd("lock",   None, cmd_lock,   "player", True)
mudsys.add_cmd("unlock", None, cmd_unlock, "player", True)

def chk_can_manip(ch, cmd):
    if not ch.pos in ["sitting", "standing", "flying"]:
        ch.send("You cannot do that while " + ch.pos + ".")
        return False

for cmd in ["give", "get", "drop", "remove", "wear", "put", "open", "close",
            "lock", "unlock"]:
    mudsys.add_cmd_check(cmd, chk_can_manip)