Showing posts with label clothing. Show all posts
Showing posts with label clothing. Show all posts

Monday, July 14, 2014

Clothing Update Part II

So, all of this work with clothing made me go, huh, wonder if my old "AIF" code still works. That's the flag that allows you to take off all of your clothes easily.  I mean, I have no intention of writing any clothes-heavy (or clothes-light har har) games anytime soon, AIF or not, but the world model fetishist in me likes to know these things work.  Anyhow, I found that, no, my old code did not work (I don't think it ever worked perfectly; I just hadn't completely tested it correctly).

See, the big problem is that >REMOVE ALL should default to held items, but you can't give it a multiheld token because you still want REMOVE to work with things like platforms or containers, and if you give it just the multi token, it ignores held items completely (only working for held items when they are used specifically).

Initially, the only way I could get it to work was to use the USE_CHECKHELD flag.  The checkheld system moves everything the player is holding to a hidden container in the room, so everything is considered not held (but it marks them with the checkheld workflag so the library knows it WAS held), allowing all verbs to work as you'd like.

Still, I put in all of this work so that in the instances where REMOVE failed, I made WEAR and TAKE OFF also fail in the same way just so there'd be consistency. I also made some instances of DoGet get directed to DoTakeOff.  Anyhow, I'm sort of embarrassed by how much work went into it, but if you want to check it out for yourself, check out the routines ExcludeFromAll, ParseError (cases 3 and 9), and VerbHeldMode in the next official release of Roodylib (version 3.9).  It is really ugly code; I should probably clean it up, but I just don't want to even look at it for a while.

As it often goes, I figured out a nice, non-checkheld-system workaround the next day. It occurred to me that the following PreParse code would do the trick:


        if word[1] = "remove" and word[2] = "~all"
        {
            word[1] = "take"
            InsertWord(2,1)
            word[2] = "off"
            return true
        }
        return false

So, basically, >REMOVE ALL gets turned into >TAKE OFF ALL (since >TAKE OFF doesn't have the same grammar issues).  Of course, ParseError messages will say TAKE OFF instead of REMOVE, but I don't think most players would even notice it isn't intentional.

Right now, if the AIF flag is not set, all variations of TAKE OFF, REMOVE, or WEAR ALL get a "Please specify which item to <blank>."-type message.  If it's set, those commands work, although they work in slightly different ways, depending on whether USE_CHECKHELD is set.

(Of course, I jokingly call it the "AIF" flag, but an author could easily want such a flag in a roleplaying-flavored game where the PC changes his or her armor a lot.)

Clothing Update Part I

So, it feels like I've been working on Roodylib a lot over the last few weeks.  It'll be interesting when I put up the next official release and go over all of the updates one last time for the changelog.

Robb Sherwin has been looking to get his game Cryptozookeeper sold online at places such as Steam and Desura, so I've been looking over the code to suggest tweaks to make this or that more user-friendly to those not familiar with IF.  Anyhow, looking at some of the things that game does made me go, "oh yeah, that probably should be an option in Roodylib!" on several occasions.

One thing CZK does is list worn clothing items before listing the rest of the inventory.  I actually wrote that code in the first place, but I didn't like how it replaced SpecialDesc in such an awkward way.  I felt, this time around that, hey, Roodylib can do it better!

So, first off, Roodylib has a new LIST_CLOTHES_FIRST flag that you should set if you want to run the new code. Then, for any character you want clothing to be automatically listed for, you add this:


    list_contents
        return ListClothesFirst(self)

Interestingly, ListClothesFirst only returns true if the character is wearing all of their belongings (this keeps an extra space from being printed after the worn-clothing list).  If you have an NPC where you only want clothing and held items to be listed when you examined them (and not in room descriptions), you could do this:


    list_contents
    {
        if verbroutine = &DoLookAround
            return true
        else
            return ListClothesFirst(self)
    }


Here is a screenshots of this system in action:




So, let's take a look at how this works. First off, of course, there's that ListClothesFirst routine:


routine ListClothesFirst(char)
{
    local x,w,c, list_save, v
    v = verbroutine
    verbroutine = &ListClothesFirst
    list_save = list_count
    list_count = 0
    for x in char
    {
        if x is worn and x is clothing
        {
            w++
            list_count++
        }
        elseif x is not hidden
        {
            x is already_listed
            c++
        }
    }
    if w and c
        list_nest = 1
    if list_count
    {
        if v ~= &DoInventory
            Indent
        if v = &DoLook
            FORMAT = FORMAT | USECHARNAMES_F
        RLibMessage(&ListClothesFirst,1,char) ! "You are wearing"
        ListObjects(char)
        if FORMAT & USECHARNAMES_F
            FORMAT = FORMAT & ~USECHARNAMES_F
        else
            FORMAT = FORMAT & ~USECHARNAMES_F
        list_nest = 0
    }
    for x in char
    {
        if x is not worn or (x is not clothing and x is worn)
            x is not already_listed
        else
        {
            AddSpecialDesc(x) ! tags worn items as already_listed
        }
    }
    verbroutine = v
    list_count = list_save - w
    return (not c and w)
}

It checks to see if any objects are worn, lists them, and marks them as already_listed.  I also needed to add this bit to ListObjects:


The ClothingCheck routine makes sure that children of worn clothing items aren't listed a second time (as they were listed by the ListClothesFirst routine).  There's also some code to make sure character names are used when it might be confusing.

Anyhow, here is the ClothingCheck routine:


routine ClothingCheck(a)
{
#ifset LIST_CLOTHES_FIRST
    if (a is worn and a is clothing and verbroutine ~= &ListClothesFirst) or
        (a is not worn and verbroutine = &ListClothesFirst)
        return true
    else
#endif
        return false
}


As you see, it has to check the verbroutine (which ListClothesFirst temporarily sets).

Anyhow, part of the reason I break this all down is because it's very possible you'll want to split up your player's or characters' inventories in other ways, and hopefully this is enough of a blueprint to get you on your way.

(All of this will be in the next official Roodylib release... coming soon!)