Author Topic: modifying describe.c  (Read 2240 times)

Offline irmo

  • Acquaintance
  • *
  • Posts: 36
    • View Profile
modifying describe.c
« on: August 10, 2008, 11:44:41 am »
Hi!

I've been wanting to change the way /verbs/players/describe works, played around with it, but didn't manage to get it to work the way I would like. I personally feel that using a name, or similar personal information, inside a standard description, is somewhat inappropriate, simply because standard observation is not supposed to reveal such details.

So, I'm hoping someone is able to help/guide me into getting the describe verb to work without the use of the $N token.

Here's the code. The verb itself /verbs/players/describe.c:
Code: [Select]
#include <lib.h>
#include "include/describe.h"

inherit LIB_VERB;

static void create() {
    verb::create();
    SetVerb("describe");
    SetRules("LIV","STR");
    SetErrorMessage("Describe syntax: describe <message>");
    SetHelp("Syntax: describe MESSAGE\n"
      "\n"
      "Provides a player with a description. You must include "
      "an instance of $N at least once in your description to "
      "denote your name. Example: If I typed 'describe $N is "
      "nondescript.', my description would be 'Rush is "
      "nondescript.'\n");
}

mixed can_describe_str(string str) {
    if(strsrch(str, "$N") == -1)
        return("Your description must include a minimum of one '$N' "
          + "to specify your name.");
    return 1;
}

mixed do_describe_str(string str) {
    this_player()->SetLong(str);
    write("Ok.");
    return 1;
}

Also, /verbs/players/include/describe.h:
Code: [Select]
#ifndef l_describe_h
#define l_describe_h

static void create();
mixed can_describe_str(string str);
mixed do_describe_str(string str);

#endif /* l_describe_h */


I'm probably not the first, or the only one feeling that player descriptions should be made without the use of $N. So the outcome of this topic will hopefully help others, as well as me.

-I.

I'm not as think as you drunk I am.

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: modifying describe.c
« Reply #1 on: August 10, 2008, 01:31:42 pm »
I took this opportunity to document how to
search for related functions and events in
the lib. Hopefully this is helpful to folks
beyond just getting rid of the $N name token.

The first thing I did was look in the verb
code for what seems like it actually sets
the description:

Code: [Select]
this_player()->SetLong(str);
Fair enough, let's see what happens when we try
to just call that function:

Quote
call me->SetLong("foo")
OBJ(cratylus /secure/save/creators/c/cratylus) -> SetLong( "foo" ) = "$N looks a bit rumpled and tired."

Ok...not that it will work, but let's try with
an eval:

Quote
eval return this_player()->SetLong("bar")
Result = "$N looks a bit rumpled and tired."

Right...it was pretty sure not to work, but
it's worth trying a thing a few different ways
sometimes. Unexpected results are a gift from
the fates.

Let's see what happens if we do it with an $N.

Quote
eval return this_player()->SetLong("foo $N bar")
Result = "foo $N bar"

Dead Souls Zayin /domains/campus/obj >
exa me
Optimus Cratylus Maximus
foo Cratylus bar
The male human is in top condition.
Cratylus is carrying:
Wire-rimmed glasses (worn)
A small black box
A robe (worn)
A .357 magnum revolver

Sure enough. Looks like SetLong wants a $N.
Let's find where this SetLong is defined for
me and why it's being finicky.

Quote
findfun SetLong
/lib/events/look
/lib/interactive
/lib/door
/lib/std/room
/lib/die

Ok, it looks like there are several files that define
SetLong. We're looking for a file that is inherited by
me...since the describe verb calls

Code: [Select]
    this_player()->SetLong(str);
It's not terribly likely that I inherit door, room,
or die code (that's die as in dice you roll), so the
most likely candidates for inspection are /lib/events/look
and /lib/interactive.

To see if I inherit those, I can use the showtree command.
Since I am a creator, my top lib file is LIB_CREATOR,
aka /lib/creator.c

Quote
showtree /lib/creator.c
/lib/creator
    /lib/player
        /lib/interactive
            /lib/events/describe
            /lib/comp/container
                /lib/events/look_in
                /lib/props/addstuff
            /lib/comp/object
                /lib/shadow_hook
                /lib/props/clean
                /lib/props/description
                    /lib/events/search
                    /lib/events/disarm
                /lib/props/id
                /lib/events/listen
                /lib/events/look
                /lib/props/properties
                /lib/props/radiance
                /lib/events/smell
                /lib/events/touch
                /lib/events/shoot
            /lib/user/autosave
            /lib/files
            /lib/props/move
            /lib/pager
            /lib/messages
            /lib/interface
                /lib/chat
(1-28 44%) pr
ess enter:


                /lib/command
                /lib/editor
                /lib/nmsh
                    /lib/history
        /lib/living
            /lib/props/carry
            /lib/combat
                /lib/race
                    /lib/body
                        /lib/lvs/position
                            /lib/events/fall
                            /lib/events/sink
                        /lib/undead
                        /lib/events/crawl
                        /lib/events/fly
                        /lib/events/swim
                        /lib/mount
                        /lib/props/body_mass
                        /lib/persist
                    /lib/genetics
                    /lib/language
                    /lib/talk
                /lib/classes
                    /lib/lvs/abilities
                        /lib/lvs/level
                /lib/combatmsg
   
         /lib/currency
            /lib/follow
(29-56 90%) press enter:


            /lib/magic
            /lib/lead
            /lib/teach
            /lib/learn
            /lib/quest
            /lib/events/stop
Dead Souls Zayin /domains/campus/obj >

Ug, what a lot of inherits. Rather than wade
through all that, how about using the
inherits command:


Quote
help inherits
Syntax: inherits THING -f FILE

Tries to match FILE with the list of inherited files for THING.

See also: showtree, findobj

 
Dead Souls Zayin /domains/campus/obj >
inherits me -f /lib/interactive
Checking OBJ(cratylus /secure/save/creators/c/cratylus) for inheritance of
/lib/interactive , just a moment...
Optimus Cratylus Maximus inherits /lib/interactive.
Dead Souls Zayin /domains/campus/obj >
inherits me -f /lib/events/look
Checking OBJ(cratylus /secure/save/creators/c/cratylus) for inheritance of
/lib/events/look , just a moment...
Optimus Cratylus Maximus inherits /lib/events/look.

Sho nuff. Let's start with SetLong() in /lib/events/look.c

Code: [Select]
string SetLong(string str){
    return SetExternalDesc(str);
}

Hrm. Nothing about $N's there. But it seems to call
SetExternalDesc(), so let's investigate that function:

Code: [Select]
string SetExternalDesc(string desc){
    return (ExternalDesc = desc);
}

No dice. SetLong() in /lib/events/look.c only calls
a local function and doesn't seem interested in
string tokens. Let's leave this file alone for now
and investigate the other likely candidate, /lib/interactive.c

Code: [Select]
string SetLong(string str){
    if(strsrch(str, "$N") == -1) return object::GetLong();
    else return object::SetLong(str);
}

AHA! A check for $N. It looks like if "$N" does not
exist in the passed variable 'str', SetLong() in LIB_INTERACTIVE
is supposed to just return your current GetLong()...which
is consistent with the results from our eval and call tests.

Well, let's change it by commenting out the $N check,
and just return the inherited SetLong():

Code: [Select]
string SetLong(string str){
    //if(strsrch(str, "$N") == -1) return object::GetLong();
    //else return object::SetLong(str);
    return object::SetLong(str);
}

You might be wondering what those :'s are. '::' is the
"scope resolution operator", it means "don't call this
function in this current inheritable, call it in the
file in inherit called 'object'."
Since SetLong() is defined in the current inheritable,
LIB_INTERACTIVE, then just having that line read

Code: [Select]
return SetLong(str);
Would cause a recursing call to itself that
would eventually fail and not do anything at all.
Instead, with the scope resolution operator, we
call SetLong() where it is defined in an object
we inherit, in this case, LIB_OBJECT.

Confused? Don't worry, it's not super important to
grok that for our task. And that's kind of a nice
thing about lib stuff. You don't have to fully
understand every last thing...just keep tinkering
and eventually things will make more sense as you
play with them.

Anyway, so now we removed the check, let's make sure
LIB_INTERACTIVE still works:

Quote
update /lib/interactive
/lib/interactive: Ok

Good. Now remember, this is a file we inherit...so
my player object still has the old code. I have to
somehow update my own player object in order to
take advantage of the new LIB_INTERACTIVE code:

Quote
userload me
Done.
Done.
/domains/default/room/arena
The Arena
You are in a large room with blank cement walls. This room was built so
Creators may test their armor, weapons and NPC's in combat. A large steel door
is here, which can be used to prevent wimpy creatures from escaping.
Obvious exit: south
A weapons rack, a recycling bin, an ammo box, and a tall metal locker are here.
A fighter is standing here.
A training dummy is standing here.


Done.
You wear a robe.
You wear wire-rimmed glasses.

Whee! Looks like it works ok.
Protip: I'm showing off here. Normally you should avoid
userloading yourself. Test on a test creator first.

Now, let's see about changing my description without the
name token:

Quote
describe Code! Until your fingers break!
Your description must include a minimum of one '$N' to specify your name.

What?? Oh right. We changed the SetLong(), but we
never changed the verb, which *also* checks. Let's try
a direct call before we monkey with the verb:

Quote
call me->SetLong("Code! Until your eyes bleed!")
OBJ(cratylus /secure/save/creators/c/cratylus) -> SetLong( "Code! Until your
eyes bleed!" ) = "Code! Until your eyes bleed!"
Dead Souls Zayin /domains/campus/obj >
exa me
Optimus Cratylus Maximus
Cratylus is nondescript.
The male human is in top condition.
Cratylus is carrying:
Wire-rimmed glasses (worn)
A small black box
A robe (worn)
A .357 magnum revolver

Uh...Hrm. So apparently we succeeded in changing the
description but now my long is "nondescript"? Let's
check to see what my actual Long is:

Quote
call me->GetLong()
OBJ(cratylus /secure/save/creators/c/cratylus) -> GetLong() = "Optimus Cratylus
Maximus\nCratylus is nondescript.\nThe male human is in top
condition.\nCratylus is carrying:\nWire-rimmed glasses (worn)\nA small black
box\nA robe (worn)\nA .357 magnum revolver\n\n"

I'm suspicious, though. Take another look at what the return
was from my call:

Quote
"Code! Until your eyes bleed!"

Why would my call return that, but now GetLong() doesn't show it?
After all, the return is supposed to be what the
ExternalDesc is set to in LIB_LOOK (remember we examined
that file first?). Something tells me that the ExternalDesc
is indeed correctly set, but GetLong() *also* wants a $N. Let's
see if that's correct.

Quote
findfun GetLong
/lib/lamp
/lib/events/look
/lib/cigar
/lib/player
/lib/pipe
/lib/bot
/lib/fuel
/lib/interactive
/lib/door
/lib/torch
/lib/std/room
/lib/creator
/lib/npc
/lib/body
/lib/donate

Ok, let's look at GetLong() in LIB_INTERACTIVE:

Code: [Select]
varargs string GetLong(){
    string str;
    str = object::GetLong(str);
    if(!str || strsrch(str, "$N") == -1) str = "$N is nondescript.";
    str = replace_string(str, "$N", GetName());
    return str;
}

Bingo! Ok, Let's fiddle with that check too...

Code: [Select]
varargs string GetLong(){
    string str;
    str = object::GetLong(str);
    //if(!str || strsrch(str, "$N") == -1) str = "$N is nondescript.";
    str = replace_string(str, "$N", GetName());
    return str;
}

I commented out the check, but left the line that replaces
$N with a name. After all, maybe there is some usefulness
to replacing a token with a name.

Allrighty, let's test...

Quote
update /lib/interactive
/lib/interactive: Ok
Dead Souls Zayin /domains/campus/obj >
userload me
Done.
Done.
/domains/default/room/arena
The Arena
You are in a large room with blank cement walls. This room was built so
Creators may test their armor, weapons and NPC's in combat. A large steel door
is here, which can be used to prevent wimpy creatures from escaping.
Obvious exit: south
A weapons rack, a recycling bin, an ammo box, and a tall metal locker are here.
A fighter is standing here.
A training dummy is standing here.


Done.
You wear wire-rimmed glasses.
You wear a robe.
call me->SetLong("Code! Though the heavens fall!")
OBJ(cratylus /secure/save/creators/c/cratylus) -> SetLong( "Code! Though the
heavens fall!" ) = "Code! Though the heavens fall!"
Dead Souls Zayin /domains/campus/obj >
exa me
Optimus Cratylus Maximus
Code! Though the heavens fall!
The male human is in top condition.
Cratylus is carrying:
Wire-rimmed glasses (worn)
A .357 magnum revolver
A robe (worn)
A small black box

Tadaaa!

With this example I've demonstrated both how to
do what you want, but also the steps you'll want
to take when faced with another such challenge.

Good luck, and happy coding.

-Crat

Offline irmo

  • Acquaintance
  • *
  • Posts: 36
    • View Profile
Re: modifying describe.c
« Reply #2 on: August 10, 2008, 03:56:11 pm »
Thanks for taking the time to write this, it was very usefull.

Not only did this help me get the command to work the way I wanted, learning howto approach similar situations was fun and very informative. It helped me better understand a some things I couldn't grasp before. It's was a valuable lesson for me, hopefully more people will benefit from it.

Thank you,

-I.
I'm not as think as you drunk I am.

Offline Atomic

  • BFF
  • ***
  • Posts: 115
  • To infinity and beyond!
    • View Profile
Re: modifying describe.c
« Reply #3 on: August 11, 2008, 09:59:46 am »
Sure thing! Two thumbs up for the lesson Miyagi.  :)
Always remember that the early bird gets the worm first, but the fi...*SNAP*...second mouse gets the cheese.