From: ferric@white116.uwyo.edu

-------------------------------------------------------------------------
Ok, this code is for a morph skill I added to my mud; it basically lets a
player mimic an object of their level or lower, anywhere in the game
world.  It has the following restrictions:

-You cannot save, cast, or fight while morphed.
-You are still a player, so can't use object commands on a morphed player.
-At auto-save you are forced to reform (to avoid odd pfile names).
-When morphed, you are not parsed in as a true object is.  This is because
 I didn't want morph to stand up under careful inspection. 

Now, this code is easily configurable for however you want it to work on
your mud.  If you find bugs, or need help with this code, contact
Ferric@uwyo.edu.  I realize this code could have been simplified, or made
more elaborate; feel free to make alterations as you see fit.  I treat it
as a command for thieves/mages on my mud.  Perhaps a spell would have made
more sense, but I like this.

Enjoy; feel free to drop me a line at ferric@uwyo.edu if you use this
code.
----------------------------------------------------------------------------


-----------
First:
-----------
At the top of: act_comm.c,
	       fight.c,
               magic.c,
               save.c, add:

void do_reform       args( (CHAR_DATA *ch) );


----------
Next: Merc.h
----------
In merc.h find #define COMM_AFK.  Under it add:

#define COMM_MORPH              (bb)

/*I used Comm because it was open, and you can use any open flags instead
  of bb.*/

---------
then: merc.h
---------

find: extern  sh_int  gsn_enhance;

and under it add:

extern  sh_int  gsn_morph;


---------
then: merc.h
---------

/*This is ugly code, and could be done nicer. But, it works! :) -Ferric*/

Find: 
char *              name; /*in struct char_data*/
and
char *              description;/*same place*/


and add below each (respectively):

char *              backup_name;
char * 		    backup_desc;

--------
then: merc.h
--------

In struct pc_data find:

char *              title;

add below it:

char *              backup_title;


--------
Next: act_info.c
--------

Add the following bits of code.  I used act_info.c for no real reason, 
but you may as well add it there.


void do_reform(CHAR_DATA *ch)
{
/*This code is used to retake your shape. -Ferric*.
  if(IS_NPC(ch))
  return;

  if(!IS_SET(ch->comm,COMM_MORPH))
  {
        send_to_char("You are in your origional shape.\n\r",ch);
        return;
  }

  REMOVE_BIT(ch->comm,COMM_MORPH);
  ch->name = ch->backup_name;
  ch->pcdata->title = ch->pcdata->backup_title;
  ch->description = ch->backup_desc;
  act("$n regains $s real shape.\n\r",ch,NULL,NULL,TO_ROOM);
  send_to_char("You retake your familiar shape.\n\r",ch);
}


void do_polymorph(CHAR_DATA *ch, char *argument )
{

    OBJ_DATA *obj;
    int number = 0, max_found;
    int skill;
    number = 0;
    max_found = 200;

    if(IS_NPC(ch))
        return; 

    if ((skill = get_skill(ch,gsn_morph)) < 1)
    {
        send_to_char("You are unable to morph!\n\r",ch);
        return;
    }
   
    smash_tilde(argument);
    if (argument[0] == '\0')
    {
        send_to_char("Polymorph into what?\n\r",ch);
        return;
    }

    if(IS_SET(ch->comm,COMM_MORPH))
    {
        send_to_char("You must wait until you regain your shape.\n\r",ch);
        return;
    }
	/*Don't ask me why I duplicated this code.
	  But since it's already here, I'll leave it.
	  Shouldn't be a prob if you cut the next 3 lines.
	  -Ferric
	*/	  

        ch->backup_name = ch->name;
        ch->pcdata->backup_title= ch->pcdata->title;
        ch->backup_desc = ch->description;

    for ( obj = object_list; obj != NULL; obj = obj->next )
    {
        if ( !can_see_obj( ch, obj ) || !is_name( argument, obj->name )
        ||   ch->level < obj->level)
             continue;

        act("$n morphs into $p",ch,obj,NULL,TO_ROOM);
        ch->backup_name = ch->name;
        ch->pcdata->backup_title= ch->pcdata->title;
        ch->backup_desc = ch->description;

        SET_BIT(ch->comm,COMM_MORPH);
        ch->pcdata->title = ("");
        ch->name = obj->description;
        ch->description = obj->description;
        send_to_char("You have changed!\n\r",ch);
        return;

    }
/*Failure. -Ferric*/
send_to_char("Try as you might, you cannot.\n\r",ch);
     
}


--------
Next: act_info.c
--------

/* Ok:  We don't want odd who's and whois's. So: I added this check. */

In do_whois, find the line: 

IS_SET(wch->act,PLR_THIEF) ? "(THIEF) " : "",

Under it add:

IS_SET(wch->comm,COMM_MORPH) ? wch->backup_name:wch->name,
IS_NPC(wch) ? "" :
IS_SET(wch->comm,COMM_MORPH) ? wch->pcdata->backup_title:
wch->pcdata->title);

/*The NPC check probably doesn't matter, but doesn't hurt anything.*/

---------
then: act_info.c
---------

In do_who, find the line: 

IS_SET(wch->act,PLR_THIEF) ? "(THIEF) " : "",

Under it add:

IS_SET(wch->comm,COMM_MORPH) ? wch->backup_name:wch->name,
IS_NPC(wch) ? "" :
IS_SET(wch->comm,COMM_MORPH) ? wch->pcdata->backup_title:
wch->pcdata->title);

/*The NPC check probably doesn't matter, but doesn't hurt anything.*/



-----------
then: act_info.c
-----------

In show_char_to_char find:

char buf[MAX_STRING_LENGTH],message[MAX_STRING_LENGTH],

under it add:

buf2[MAX_STRING_LENGTH];

then find (still in show_char_to_char)

strcat( buf, PERS( victim, ch ) );
if ( !IS_NPC(victim) && !IS_SET(ch->comm, COMM_BRIEF)
&&   victim->position == POS_STANDING && ch->on == NULL )
     strcat( buf, victim->pcdata->title );

Directly under it add:

/* This allows immortals to see the real identity of morphed chars who are
   in the same room. */
if(IS_SET(victim->comm,COMM_MORPH) && IS_IMMORTAL(ch))
{
sprintf(buf2, " [%s] ",victim->backup_name);
strcat( buf,buf2);
}

----------
then: act_info.c
----------

find:
    switch ( victim->position )
    {
    case POS_DEAD:     strcat( buf, " is DEAD!!" );              break;
    case POS_MORTAL:   strcat( buf, " is mortally wounded." );   break;
    case POS_INCAP:    strcat( buf, " is incapacitated." );      break;
    case POS_STUNNED:  strcat( buf, " is lying here stunned." ); break;
    case POS_SLEEPING:

change to:

    /* This prevents wounded morphed chars from giving it away.*/
    if(!IS_SET(victim->comm,COMM_MORPH))
    switch ( victim->position )
    {
    case POS_DEAD:     strcat( buf, " is DEAD!!" );              break;
    case POS_MORTAL:   strcat( buf, " is mortally wounded." );   break;
    case POS_INCAP:    strcat( buf, " is incapacitated." );      break;
    case POS_STUNNED:  strcat( buf, " is lying here stunned." ); break;
    case POS_SLEEPING:

----------
Next: const.c
----------
Add this in the skill table in const.c

/*Change this to suit your mud. -Ferric*/
/*Be sure to add it to any defaults you want, as well.*/

    {
        "morph",                { 28, 63, 15, 63}, { 5, 0, 7, 0},  
        spell_null,             TAR_CHAR_SELF,          POS_RESTING,
        &gsn_morph,             SLOT(0),        0,      12,
        "morph",                "!Morph!",              ""
    },



/*
Now we get to add all the nifty checks for things that don't allow 
players to do while morphed.  Feel free to change any, but take my advice
and don't allow players to save while morphed unless you add a function to
have it save to their origional name.  -Ferric
*/

---------
Next: act_comm.c
---------

in do_delete, under the:

if (IS_NPC(ch))
   return;

add:

if(IS_SET(ch->comm,COMM_MORPH))
   do_reform(ch);


---------
then: act_comm.c
---------

in do_quit find:

if ( IS_NPC(ch) )
   return;

and under it add:

if(IS_SET(ch->comm,COMM_MORPH))
   do_reform(ch);
/*probably not necissary with the check in do_save, but doesn't hurt.*.


-----------
then: act_comm.c
-----------

find: do_save

under it add:

if(IS_SET(ch->comm,COMM_MORPH))
  do_reform(ch);


--------
Next: fight.c
--------

in function one_hit find:

if ( victim->position == POS_DEAD || ch->in_room != victim->in_room )
return;

under it add:

if(IS_SET(ch->comm,COMM_MORPH))
  do_reform(ch);

----------
Next: magic.c
----------


in do_cast, find

if ( IS_NPC(ch) && ch->desc == NULL)
    return;   

under it add:

if(IS_SET(ch->comm,COMM_MORPH))
  do_reform(ch);



----------
Next: save.c
----------

/*I know this isn't needed, per se, but I'm using it as a 'safety latch',
should anybody get past the previous ones.  I can't stress enough how
importanat it is to prevent the saving of morphed chars.*/

find save_char_obj;

in it find:     

if ( IS_NPC(ch) )   
   return;

under it add:

if(IS_SET(ch->comm,COMM_MORPH))
  do_reform(ch);


-------
Lastly: interp.c and interp.h
-------

In interp.c add:

{ "reform",         do_reform,      POS_RESTING,     0,  LOG_NORMAL, 1},
{ "morph",          do_polymorph,   POS_RESTING,     0,  LOG_ALWAYS, 1},
/*Still deciding if it can be abused.*/

in interp.h add:

DECLARE_DO_FUN( do_polymorph    );
DECLARE_DO_FUN( do_reform       );


------------
Done!
------------
Ok, as I've said, this code could certainly used a clean-up.  Basically I
wrote it, and when it worked, I never looked back.  And if you should find
any bugs in this, *please* email me with them so that I can fix them up
and re-release this code.  Last thing; you needn't credit me in any way
you don't want to, although an email to ferric@uwyo.edu letting me know
you are using it will certainly be appreciated, and might even encourage
me to release some more of my more interesting code.

-----------
Note
-----------

If you are using mahntor.are, obj #1336 (a golden altar) has no
description; so, any player morphing into it is effectivly super-invis.
A couple of fixes: either add a description, or up the level high enough
that it's impossible for anybody to morph into it.

------------
To-do list
------------

-change 'where' to be more accurate with this.
-allow a more efficient way for imms to see morphed chars.
-clean the code up a great deal.
-parse the name in so that it matches up w/ other objects.
-allow for (glowing) (humming) flags on chars morphed to appropriate
 objects.
-fix tell so that you can tell to morphed players w/out knowing their 
 current shape.

So, thanks for your time/attention, and happy mudding/Admining.

-Ferric
ferric@uwyo.edu
white116.uwyo.edu 9000