Thursday, March 28, 2013

Empty Progress

So, I got a working prototype of my solution. It uses a mix of Roodylib's grammar routine helper stuff and object classes.

First, let's look at our new grammar definition:
verb "empty", "unload"
    *                                                       DoVague
#ifset NEW_EMPTY
    * (CheckEmpty) "on"/"onto" "ground"/"floor"             DoEmptyGround
#else
    * object "on"/"onto" "ground"/"floor"                   DoEmptyGround
#endif
    * multi "from"/"off"/"on"/"in" parent                    DoGet
    * multi "offof"/"outof" parent                         DoGet
    * multi "from" "offof"/"outof"/"on"/"in" parent         DoGet
! Send >UNLOAD OBJECT to DoEmptyoOrGet, which dispatches to DoEmpty or DoGet
!    * object                                                DoEmpty
#ifset NEW_EMPTY
    * (CheckEmpty)                        DoEmpty ! DoEmptyOrGet
#else
    * object                DoEmpty
#endif

In no cases does it run DoEmptyOrGet anymore as I think it's so general that it just leads to trouble. Next, let's take a look at our object classes:
#ifset NEW_EMPTY
property empty_type

class unheld_to_player
{
    empty_type NOTHELD_T
    before
    {
        object DoEmpty
        {
            local a, b, obj, xobj
            local thisobj, nextobj

            CalculateHolding(object)

            if object is container, openable, not open
            {
                VMessage(&DoEmpty, 1)           ! "It's closed."
                return true
            }

            if object is not container, platform
            {
                ParseError(12, object)
                return false
            }

            if not children(object)
            {
                VMessage(&DoEmpty, 2)           ! "It's already empty."
                return true
            }

            thisobj = child(object)
            while thisobj
            {
                nextobj = sibling(thisobj)

                print thisobj.name; ":  ";

                if thisobj is static
                    VMessage(&DoEmpty, 3)    ! "You can't move that."
                else
                {
                    a = player.holding
                    b = thisobj
                    obj = object
                    xobj = xobject

                    if Perform(&DoGet, b)
                        player.holding = a + b.size
                    else
                        player.holding = a
                    object = obj
                    xobject = xobj

                    if b not in object
                        object.holding = object.holding - b.size
                }

                thisobj = nextobj
            }

            run object.after
            return true
        }
    }
}

class held_to_player
{
    empty_type HELD_T
    inherits unheld_to_player
}

class held_to_ground
{
    empty_type HELD_T
}

constant NO_EMPTY_T 16

class no_empty
{
    empty_type NO_EMPTY_T
}
If it's not self-explanatory, that consists of a class that represents objects that must be held and empty out to player (like unloading bullets from a gun), objects that must be not held and empty out to player (like unloading a laundry machine), objects that must be held and empty out to ground (like a bottle of liquid), and objects that can't be emptied (for containers and platforms that deserve a "You can't empty that." message).

Here is the grammar helper routine:
routine CheckEmpty(obj)
{
    if obj.empty_type
    {
        TOKEN = obj.empty_type
        if not CheckObject(obj)
        {
            return false
        }
        elseif obj.empty_type = NO_EMPTY_T
        {
            ParseError(12, obj)
            return false
        }
        return true
    }
    elseif not CheckObject(obj)
        return false
    return true
}
#endif NEW_EMPTY

Lastly, whether or not players use this new system, I think Roodylib will replace DoEmpty to switch around the platform/container check before the children check:
 replace DoEmpty
{
    local a, b, obj, xobj
    local thisobj, nextobj

    CalculateHolding(object)

    if object is container, openable, not open
    {
        VMessage(&DoEmpty, 1)           ! "It's closed."
        return true
    }
    if object is not container, platform
    {
        ParseError(12, object)
        return false
    }
    if not children(object)
    {
        VMessage(&DoEmpty, 2)           ! "It's already empty."
        return true
    }

    thisobj = child(object)
    while thisobj
    {
        nextobj = sibling(thisobj)

        print thisobj.name; ":  ";

        if thisobj is static
            VMessage(&DoEmpty, 3)    ! "You can't move that."
        else
        {
            a = player.holding
            b = thisobj
            obj = object
            xobj = xobject

            if player not in location and
                (parent(player) is platform or
                    parent(player) is container) and
                not xobject:

                Perform(&DoPutIn, b, parent(player))
            else
                Perform(&DoDrop, b)

            object = obj
            xobject = xobj
            player.holding = a
            if b not in object
                object.holding = object.holding - b.size
        }

        thisobj = nextobj
    }

    run object.after
    return true
}
 EDIT: Just throwing in that, yeah, I know my code does nothing about the "multi from/outof/etc xobject" grammar that points to DoGet, but I think that would go to DoGet in most cases anyway and I'm comfortable with people having to write their own before routines to catch the rest.

No comments:

Post a Comment