From: Jean-Marc Giffin Date: Mon Jun 05 2006 - 13:16:06 CDT Hey All, I found something about editing the Front-End that programmers may be very interested in. Last week, Kevin generously took the time to warn me about the difficulties of messing with the encore frontend, and everything he mentions is right. The biggest problems that Kevin correctly points out are mentioned in the following list: 1) Object Descriptions - As you have already found out, trying to hunt down where the various WEB display elements come from has been quite a challenge. A simple example is how the WEB side of the Xpress interface displays these objects. In short it doesn't! They appear in the WEB display as room objects. If the user clicks on them, which with a normal non-room object shows the user the objects description, they are summarily moved INTO the object!.. They DO NOT USE THE OBJECT'S VERBS for their input. So instead of calling the objects version of the "look" and "look_self" verbs to get the description it tries to read the Objects description property! Consequently the description property is never really correct. EnCore does not follow the rules and tries to bypass the MOO object hierarchy to make it's display thus making such "on the fly" changes almost impossible to achieve. 2) enCore verbs are a) WIZ owned, b) not really aware of the user in MOO space, c) stuck trying to both generate an interactive display AND generate a wEB display where no user is really present at all (browsing from the WEB), d) scattered across several objects and utilities such that trying to customize them has potentially bad effects on the system as a whole. This presented a challenge, and I wanted to see if I could edit this front-end so that the WEB display was affected. What I tried doing was making it so that your description was dynamically edited, based on which items you were carrying. So for example, if I am wizard and my description is: A wonderful wizard that you must obey, or else... But I were also carrying around the objects "Mangy Cat" and "Pet Rock", then my description would read: A wonderful wizard that you must obey, or else... He carefully carries around a precious pet rock. A mangy cat attaches itself to his back. Of course, if the wizard drops the mangy cat and the pet rock, then his description would return to normal. So how was I going to do this? First I needed to know: a) Where is a player's description located? b) Where is a player's inventory located? c) How can I make this work for ALL players, respective to the items they have? After spending some time looking around, I found my answers: a) The player's description is (simply enough) player.description b) The player's inventory is stored in player.contents (this caused a lot of trouble for a while, because I got this and player.owned_objects mixed up!) c) In order to make the proper changes, I had to edit the "Generic Player", which was object #6 for me. First, the "things" that described the player must have a property that tells what the alteration to the character will be. So I added a property to "$thing" called "describe_player_msg". The reason for "_msg" is that it can be accessed from @messages. For an individual item's "describe_player_msg", I set "Pet Rock"'s using pronoun substitutions. What this does is make it so that if a female has the pet rock, it will say: "She carefully carries around a precious pet rock" But if the player is male, it will say: "He carefully carries around a precious pet rock" So I set Pet Rock's to be: "%S carefully carries around a precious pet rock." Then, to actually get this property, we'll create a verb in $thing called "describe_player_msg()". It only has the code: return this.describe_player_msg; --- Next, I went into #6 (generic player) and added a "describe()" verb. It is always a good idea to make new verbs as much as you can instead of editing existing ones, if it will do the job. I also made a verb "getDescription()". The reason I made two is this: A) describe() actually "tell()"s the player what the description is. B) getDescription() RETURNS the description. The difference is important. So the code for describe() was this: player:tell(getDescription()); and the code for getDescription was this: return this.description; Easy enough! Tested it out, and now when you type something like "describe me", it will say: A wonderful wizard that you must obey, or else... But what we REALLY want is for it to say (assuming that he is carrying the Pet Rock): A wonderful wizard that you must obey, or else... He carefully carries around a precious pet rock So what do we do? We have to modify getDescription() so that it adds on the extra part. First we come up with an algorithm: 1. Get the current description 2. Go through the player's contents (inventory) 3. If the current object has the property "describe_player_msg", and it is not blank, add the object's "describe_player_msg" to the player's description, making sure to format the pronoun substitutions. 4. Return the description. The code I came up with is as follows: 1: description = this.description; 2: for item in (this.contents) 3: if ($object_utils:has_property(item, "describe_player_msg")) 4: if (toobj(item).describe_player_msg) 5: item_desc =$string_utils:pronoun_sub(toobj(item):describe_player_msg()); 6: description = tostr(description, "
", item_desc); 7: endif 8: endif 9: endfor 10: return description; Now when you type in "describe me" in encore, it will append the "describe_player_msg" to the player's description. But this doesn't change the WEB interface. Here's how I did that: Look in the verb "_html" of "Generic Player". It's return value is "out". Looking backwards, we see that "out" is an append of "out, extra", and is originally gotten from "pass(user)". This means that the parent's "_html" out value will pass through this verb. Working backwards, we now have to go to Generic Player's parent, which is "encore web object". Load it's "_html" verb. The "description" part of it is loaded way at the bottom with the lines: 36: description = $encore_web_utils:detect_urls(user, this.description); 37: description = $encore_web_utils:insert_line_breaks(description); 38: description = $encore_web_utils:align($encore_web_utils:p(description), this.text_alignment); Most of the work is done on line 36 there, since the others are just web formatting. So instead, we do this: 33: if ($object_utils:has_verb(this, "getDescription")) 34: description = this:getDescription(); 35: else 36: description = $encore_web_utils:detect_urls(user, this.description); 37: endif So now, if the object DOES have a getDescription(), it will load that up instead, else it will get the regular description. Now, if you observe a player in the WEB interface, it should give you a description that includes the object's added stuff... BUT WAIT! The pronouns are wrong. Instead of "he" or "she", we get "it". I tried a number of ways to change this, and the best way I have found is this: Change the getDescription() verb of player, so that the line: 5: item_desc = $string_utils:pronoun_sub(toobj(item):describe_player_msg()); To this: 5: item_desc = $string_utils:pronoun_sub(toobj(item):describe_player_msg(), this); Notice the extra parameter "this". This is an optional parameter of the "pronoun_sub()" verb which explicitedly say "who" the pronoun should be relative to. There are probably some gaps in my explanation, but I have to get back to work! I just wanted to share this, because doing all this took a few hours to narrow down the best methods, what to change, where to change it, etc. So if anyone is editing the web interface of encore, this should save you hours or work. Jean-Marc Giffin