Costume Closet
Tutorial by Chris Hunt – nospam@cwhunt.com
in collaboration with Ron Broglio – ron.broglio@lcc.gatech.edu
1. Purpose
This patch gives players the ability play with his identity by wearing ‘costumes’—new user icons, names, descriptions, etc. defined by the costume maker.
For example, a player can become Frankenstein’s monster for a few minutes, interact with other players, then ‘drop’ his costume and reacquire his original identity. It installs two new generic objects, Costume Closet and Costume. Additional Costume Closets can be created by using the first one as a parent.
2. Background
This upgrade is a bit more demanding than the other ones we have presented. It requires two new object classes, each with their own methods and properties. As such, we will drop the line-by-line tutorial in favor of a more wholesale guide to implementation. This guide has a slightly quicker pace than our other documentation.
We used the @dump command to export these objects to a text format that enCore can understand. First we will create our empty objects, tailor our text to these objects, and then we will install the object methods and properties.
This specific implementation assumes wizard privileges. Any programmer may implement a costume closet, but a few changes need to be made. We will flag these after installation.
3. Implementation
Open the object editor. Press ‘Create New Object’ and create a generic thing. Call it ‘Costume’. Repeat the same process to create a second generic thing called ‘Costume Closet’.
Close the object editor and open the program editor. Find your two new objects and select your Costume; check ‘Read’ and ‘Fertile’, then press ‘Save Object’. Repeat the same process for the Costume Closet. (Skipping this step will prevent the creation of other closets.)

Figure 3.1
Note the object number in the title bar (the number after Costume, followed by the pound sign, ‘#’). Write down the object numbers of your Costume and your Costume Closet; make sure you label them carefully. Now we will configure our install text to fit your new objects.
Open Notepad, Word, or some other application that can search/replace text. Paste the following code into a new window.
@prop #COSTUME."home_closet" #-1 rc
;;#COSTUME.("icon") = "thing.gif"
;;#COSTUME.("banner") = ""
;;#COSTUME.("footer") = ""
;;#COSTUME.("external_stylesheet") = "encore_web_object.css"
;;#COSTUME.("hits") = 3
;;#COSTUME.("aliases") = {"Costume"}
;;#COSTUME.("description") = "a costume"
;;#COSTUME.("object_size") = {2049, 1130805543}
@verb #COSTUME:"d*rop th*row" this none none rxd
@program #COSTUME:drop
this.home_closet:return_costume(this.home_closet);
"Don't allow the parent class to be recycled";
if (this != #COSTUME)
recycle(this);
endif
"Code and tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME:"initialize" none none none rxd
@program #COSTUME:initialize
"Code and tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
Run a search for ‘#COSTUME’, and replace it with the object number for your Costume. For instance, if my new Costume object had number #20221, I would search for ‘#COSTUME’ and replace it with ‘#20221’ (without the quotes, of course).
Take this updated text and paste it into the MOO command box.

Figure 3.2
If you created the object properly (and used the right number) you should see something like the following:

Figure 3.3
Now we will repeat the same process for the Costume Closet. This is a more complex object. Replace #COSTUME_CLOSET with the object number of your Costume Closet in the following code and then paste the updated text into the MOO to register the verbs and properties.
@prop #COSTUME_CLOSET."costumes" {} rc
@prop #COSTUME_CLOSET."backup" {} rc
@prop #COSTUME_CLOSET."costume_desc_header" "<br><br><table><tr><td><font size=+3>?</font></td><td valign=\"top\"><i>Panicking over your lost identity? Just type \"drop costume\" to return to your normal state!</i></td></tr></table>" rc
@prop #COSTUME_CLOSET."costume_class" #-1 rc
;;#COSTUME_CLOSET.("icon") = "thing.gif"
;;#COSTUME_CLOSET.("banner") = ""
;;#COSTUME_CLOSET.("footer") = ""
;;#COSTUME_CLOSET.("external_stylesheet") = "encore_web_object.css"
;;#COSTUME_CLOSET.("aliases") = {"closet"}
;;#COSTUME_CLOSET.("description") = "You can become any character by borrowing a costume. <br><br>Type 'borrow costume-name from closet' and it will change<br>you to the given costume name. So, for example, you can<br>type <i>'borrow Monster from closet'</i> and you will become a Monster.<br>Type <i>'return_costume to closet'</i> to return to your old self.<br>Type <i>'add_costume to closet'</i> to add new costumes<br><br>Costumes avaliable:<br>"
;;#COSTUME_CLOSET.("object_size") = {9750, 1130807808}
@verb #COSTUME_CLOSET:"borrow" any from this rxd
@program #COSTUME_CLOSET:borrow
if (this.costumes == {})
player:tell("There are no costumes for you to borrow.");
player:tell(("You need to run \"add_costume to " + self.name) + "\".");
endif
ok = 0;
for costume in (this.costumes)
if (costume[1] == args[1])
user_already_has_costume = 0;
for item in (player.contents)
if (parent(item) == this.costume_class)
user_already_has_costume = 1;
endif
endfor
if (user_already_has_costume == 0)
player_costume = create(this.costume_class, #-1);
player_costume.name = "Costume";
player_costume.home_closet = this;
player_costume:moveto(player);
endif
this:savePlayer();
playerName = player.name;
player.name = costume[1];
player.description = costume[2] + this.costume_desc_header;
player.url_address = costume[3];
if ($string_utils:is_numeric(costume[4]))
player.web_width = tonum(costume[4]);
endif
if ($string_utils:is_numeric(costume[5]))
player.web_height = tonum(costume[5]);
endif
player.audio_url = costume[6];
if (length(costume[7]) > 0)
player.icon = costume[7];
endif
if (length(costume[8]) > 0)
player.gender = costume[8];
endif
player.location:look_self();
player.location:announce((playerName + " becomes ") + costume[1]);
player:tell("You become " + costume[1]);
ok = 1;
break;
endif
endfor
if (ok == 0)
player:tell("No such costume.");
player:tell(("You need to run \"add_costume to " + this.name) + "\" to add that costume.");
endif
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"savePlayer" none none this rxd
@program #COSTUME_CLOSET:savePlayer
for backupPerson in (this.backup)
if (backupPerson[1] == player)
return;
endif
endfor
this.backup = listappend(this.backup, {player, player.name, player.description, player.url_address, player.web_width, player.web_height, player.audio_url, player.icon, player.gender});
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"return_costume" none to this rxd
@program #COSTUME_CLOSET:return_costume
this:update_desc();
i = 0;
for personBackup in (this.backup)
i = i + 1;
if (personBackup[1] == player)
playerName = player.name;
player.name = personBackup[2];
player.description = personBackup[3];
player.url_address = personBackup[4];
player.web_width = personBackup[5];
player.web_height = personBackup[6];
player.audio_url = personBackup[7];
player.icon = personBackup[8];
player.gender = personBackup[9];
this.backup = listdelete(this.backup, i);
player.location:look_self();
player:tell("You morph back to " + player.name);
player.location:announce((playerName + " morphes back to ") + player.name);
return;
endif
endfor
player:tell("You haven't borrowed any costumes to restore.");
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"update_desc" none none this rxd
@program #COSTUME_CLOSET:update_desc
this.description = "You can become any character by borrowing a costume. <br><br>";
this.description = this.description + "Type 'borrow costume-name from closet' and it will change<br>";
this.description = this.description + "you to the given costume name. So, for example, you can<br>";
this.description = this.description + "type <i>'borrow Monster from closet'</i> and you will become a Monster.<br>";
this.description = this.description + "Type <i>'return_costume to closet'</i> to return to your old self.<br>";
this.description = this.description + "Type <i>'add_costume to closet'</i> to add new costumes<br><br>";
if (length(this.costumes) > 0)
this.description = this.description + "Costumes avaliable:";
for costume in (this.costumes)
this.description = this.description + "<br><b><i>";
this.description = this.description + costume[1];
this.description = this.description + "</i></b>";
endfor
else
this.description = this.description + "Currently no costumes available.";
endif
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"list_costumes" none in this rxd
@program #COSTUME_CLOSET:list_costumes
this:update_desc();
if (length(this.costumes) == 0)
player:tell("No costumes avaliable. Add new constumes");
else
player:tell("Costumes avaliable:");
for costume in (this.costumes)
player:tell(costume[1]);
endfor
endif
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"add_costume" none to this rxd
@program #COSTUME_CLOSET:add_costume
player:tell("Give the name of the new costume:");
new_name = read();
player:tell("Give the description of the new costume:");
new_description = read();
player:tell("Give the visual-url of the new costume:");
new_url = read();
player:tell("Give the visual-width of the new costume:");
new_width = read();
player:tell("Give the visual-height of the new costume:");
new_height = read();
player:tell("Give the audio-url of the new costume:");
new_audio = read();
player:tell("Give the icon of the new costume:");
new_icon = read();
player:tell("Give the gender of the new costume:");
new_gender = read();
newCostume = {new_name, new_description, new_url, new_width, new_height, new_audio, new_icon, new_gender};
answer = "yes";
i = 0;
for costume in (this.costumes)
i = i + 1;
if (costume[1] == new_name)
player:tell("This costume already exists, overwrite [yes/no]?");
answer = read();
if (answer == "yes")
this.costumes = listdelete(this.costumes, i);
this.costumes = listinsert(this.costumes, newCostume, i);
this:update_desc();
player:tell(new_name + " updated.");
else
player:tell(new_name + " not added.");
endif
return;
endif
endfor
this.costumes = listappend(this.costumes, newCostume);
this:update_desc();
player:tell(new_name + " added to costumes.");
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
@verb #COSTUME_CLOSET:"remove_costume" any from this rxd
@program #COSTUME_CLOSET:remove_costume
i = 0;
for costume in (this.costumes)
i = i + 1;
if (costume[1] == args[1])
this.costumes = listdelete(this.costumes, i);
player:tell((args[1] + " removed from the ") + this.name);
this:update_desc();
return;
endif
endfor
player:tell((args[1] + " not found in the ") + this.name);
"Tutorial by Chris Hunt -- nospam@cwhunt.com";
"Maintained and published by Dr. Ron Broglio, Georgia Tech";
" ron.broglio@lcc.gatech.edu";
.
Your screen should look something like this:

Figure 3.4
Now we need to tell your Costume Closet where to find the costume objects it gives out.
Open the program editor. Press ‘My Objects’ and choose your Costume Closet. Scroll to the bottom of the properties list and select ‘costume_class’. You should see ‘#-1’ in the text box. Replace it with the object number of your Costume. Press ‘Save Property’ and make sure that the Data Type remains ‘Object’. If it changes to ‘List’ or ‘String’ delete the number and try again; make sure you do not insert a line-break in the text box. Now your screen should look like this (with your object number instead, of course):

Figure 3.5
We mentioned earlier that this implementation requires wizard privileges. These privileges are only need to create the first closet; afterwards, other programmers can create new closets using the wizard-installed one as a parent.
You should now have a working Costume Closet! We recommend using the Closet you just created only as a parent object--any costumes you put in this Closet will be in any other Closets that you make.
Replace ‘#MY_CLOSET’ with your object’s number and create your first child closet by typing:
@create #MY_CLOSET named “My Costume Closet”
I recommend hiding your parent Closet so that no one can move it or add any costumes to the root. You can do this by replacing ‘#MY_CLOSET’ again and typing:
@move #MY_CLOSET to #-1
Naturally, we recommend you lock whatever Closets you create to their rooms. See the Closet’s description for information on creating costumes and configuring your Closet.
Note:
We strongly recommend that wizards install the base copy of the closet. However, base implementation is possible as a programmer. See our tutorials on creating clones. In this version of the closet, the wizard-only method is used to create clones of the Costume class. Modify the code contained in the borrow_costume verb in the Costume Closet to fit one of the other methods—pay particular attention to line 15.