Add a player flag to toggle ghost. We used ch->pcdata->pflags, but pick whatever suits your game.
fight.c:
Find the raw_kill() function. AFTER the extract_char(victim,FALSE) set the ghost bit on the player.
Find the damage() function. Under if( victim != ch ) add checks to prevent fighting a ghost (victim) or ghost (ch).
Find the one_hit() function. Add a check to return if victim is a ghost.
magic.c
Near the top of your cast function add a check to prevent ghosts from using magic.
comm.c
Find the write_to_buffer() function. At some point it should translate your color codes; the below converted all
colors to grey/white in my MUD, update them to what you use. This will make a greyscale world for ghosts.
ch= d->original != NULL ? d->original : d->character;
if (ch != NULL && !IS_SET(ch->config, CONFIG_COLOR))
continue;
/* set to default highlight or dim set by player */
lookup = c;
if ( ch != NULL && !IS_NPC( ch ) ) /* shouldn't happen, but…*/
{
if ( lookup == '!' )
lookup = ch->pcdata->hicol;
else
if ( lookup == '.' )
lookup = ch->pcdata->dimcol;
}
/*************** PERTINENT CODE BELOW THIS **************/
if ( ch != NULL && !IS_NPC( ch ) )
if ( IS_SET( ch->pcdata->pflags, PFLAG_GHOST ) )
{
if ( ( cnt = number_range( 1, 2 ) ) == 1 )
lookup = 'W';
else
lookup = 'd';
}
/*************** PERTINENT CODE ABOVE THIS **************/
for ( cnt = 0; cnt < MAX_ANSI; cnt ++ )
if ( ansi_table[cnt].letter == lookup )
break;
act_move.c
Find the move_char() function. Consider adding separate messages for "You can't go that way." if the player is a
ghost. My MUD had a room "cage" spell, too, and we let ghosts pass through this while it blocked live players. Same
for doors.
act_info.c
At the bottom of show_char_to_char_0 you can add the following to make ghosts appear differently from other players.
if ( IS_GHOST( victim ) )
{
buf[0] = '\0';
sprintf( buf, "@@N@@d(@@gGhost@@d) @@g%s floats here morbidly.@@N\n\r", victim->name );
}
act_comm.c
Find the talk_channel() function. The below will make ghosts speak 'OooOOOO' ish so people can't understand them.
You might also want to add checks to each of your channel commands to stop ghost use, except say. That's how we left
it. Ghosts could say but no other chans.
switch ( channel )
{
default:
/*************** PERTINENT talk_channel() CODE BELOW THIS **************/
if ( IS_GHOST(ch) )
{
buf2[0] = '\0';
for ( cnt = 0; cnt < strlen(argument); cnt++ )
{
if ( ( random = number_range( 1, 2 ) ) == 1 )
sprintf( buf, "o" );
else
sprintf( buf, "O" );
sprintf( buf2+strlen(buf2), buf );
}
sprintf( buf, "@@gYou oOoOo '@@d%s@@g'.%s\n\r", argument, color_string( ch, "normal" ) );
send_to_char( buf, ch );
sprintf( buf, "$n %ss '$t'.", verb );
break;
}
/*************** PERTINENT talk_channel() CODE ABOVE THIS **************/
sprintf( buf, "You %s '%s'.\n\r", verb, argument );
send_to_char( buf, ch );
sprintf( buf, "$n %ss '$t'.", verb );
break;
/*************** PERTINENT do_say() CODE BELOW THIS **************/
if ( IS_GHOST(ch) )
{
buf2[0] = '\0';
for ( cnt = 0; cnt < strlen(argument); cnt++ )
{
if ( ( random = number_range( 1, 2 ) ) == 1 )
sprintf( buf, "o" );
else
sprintf( buf, "O" );
sprintf( buf2+strlen(buf2), buf );
}
sprintf( buf, "$n oOoOo's '@@g$t@@N'." );
}
for ( ppl = ch->in_room->first_person; ppl != NULL; ppl = ppl->next_in_room )
{
if ( !IS_GHOST(ch) || IS_GHOST(ppl) )
{
sprintf( buf, "$n says '%s$t%s'.",
color_string( ppl, "say" ), color_string( ppl, "normal" ) );
act( buf, ch, argument, ppl, TO_VICT );
}
else
act( buf, ch, buf2, ppl, TO_VICT );
}
/*************** PERTINENT do_say() CODE ABOVE THIS **************/
interp.c
Find the interpret() function. Below the checks for proper char position, add the following. Limits the commands a
ghost can use.
if ( IS_GHOST( ch ) )
{
if ( ( str_prefix( command, "say" ) )
&& ( str_prefix( command, "who" ) )
&& ( str_prefix( command, "inv" ) )
&& ( str_prefix( command, "eq" ) )
&& ( str_prefix( command, "score" ) )
&& ( str_prefix( command, "pray" ) )
&& ( str_prefix( command, "zzz" ) )
&& ( str_prefix( command, "n" ) )
&& ( str_prefix( command, "north" ) )
&& ( str_prefix( command, "s" ) )
&& ( str_prefix( command, "south" ) )
&& ( str_prefix( command, "w" ) )
&& ( str_prefix( command, "west" ) )
&& ( str_prefix( command, "e" ) )
&& ( str_prefix( command, "east" ) )
&& ( str_prefix( command, "u" ) )
&& ( str_prefix( command, "up" ) )
&& ( str_prefix( command, "d" ) )
&& ( str_prefix( command, "down" ) )
&& ( str_prefix( command, "look" ) )
&& ( str_prefix( command, "config" ) )
&& ( str_prefix( command, "alias" ) )
&& ( str_prefix( command, "sleep" ) )
&& ( str_prefix( command, "stand" ) )
&& ( str_prefix( command, "wake" ) )
&& ( str_prefix( command, "rest" ) )
&& ( str_prefix( command, "save" ) )
&& ( str_prefix( command, "mset" ) )
&& ( str_prefix( command, "immtalk" ) )
&& ( str_prefix( command, "quit" ) )
&& ( str_prefix( command, "'" ) ) )
{
send_to_char( "@@NGhosts cannot do that.\n\r", ch );
return;
}
}
special.c
Find the spec_cast_adept() function. You can add the following to it below the if( victim == NULL ) check to auto-rez
ghosts at any mob with this spec set.
for ( ppl = victim->in_room->first_person; ppl != NULL; ppl = ppl->next_in_room )
if ( IS_GHOST(ppl) )
{
resurrect(ppl);
act( "$n @@Nraises his hands as @@llightning@@N strikes in the background.", ch, NULL, NULL, TO_ROOM );
send_to_char( "@@gBe wary traveller, as many dangers lie in wait.\n\r", ppl );
send_to_char( "\n\r@@g – @@WYou have been granted @@ylife @@g–@@N\n\r\n\r\n\r", ppl );
}
update.c
We added a death_update() to auto-rez people after 3 to 4 minutes. You can add this into update_handler() however
frequent you like. Also below is the auto-rez func resurrect called by the above code and the death_update().
void death_update()
{
CHAR_DATA *ch;
CHAR_DATA *ch_next;
CREF( ch_next, CHAR_NEXT );
for ( ch = first_char; ch != NULL; ch = ch_next )
{
ch_next = ch->next;
if ( ch->is_free != FALSE )
continue;
if ( ch->death_cnt > -1 )
ch->death_cnt -= 1;
if ( ch->death_cnt == 0 && IS_GHOST(ch) )
{
resurrect( ch );
char_from_room( ch );
char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );
do_mpcr( ch, ch->name );
do_look( ch, "auto" );
send_to_char( "@@gYou have been granted @@ylife@@g!@@N\n\r", ch );
save_char_obj( ch );
}
}
CUREF( ch_next );
}
void resurrect( CHAR_DATA *ch )
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
if ( IS_NPC( ch ) )
return;
REMOVE_BIT( ch->pcdata->pflags , PFLAG_GHOST );
ch->hit = 1;
ch->move = 1;
ch->mana = 1;
for ( paf = ch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if ( paf->type == skill_lookup( "Enraged" ) )
continue;
affect_remove( ch, paf );
}
save_char_obj( ch );
return;
};
void do_reanimate ( CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
CHAR_DATA *victim;
CHAR_DATA *mob;
char const *class = class_table[ch->class].name;
argument = one_argument ( argument, arg);
/* No arguments, Find healer for ghost, syntax for Immortal and cleric */
if ( arg[0] == '\0')
{
if IS_SET(ch->act, PLR_GHOST)
{
for (mob = ch->in_room->people; mob; mob = mob->next_in_room)
{
if (IS_NPC (mob) && (IS_SET(mob->act, ACT_IS_HEALER)))
{
if (ch->position != POS_STANDING)
{
send_to_char ("You must be standing.\n\r", ch);
return;
}
else
REMOVE_BIT( ch->act, PLR_GHOST);
send_to_char( "The healer has brought you back to life!\n\r", ch);
return;
}
}
send_to_char ("Find a healer or Cleric!\n\r", ch);
return;
}
/* Not sure why but ! is doing the opposite, allowing the cleric to reach this point */
else if (IS_IMMORTAL(ch) || !str_cmp(class, "cleric"))
{
send_to_char( "You'd like to bring who back to life?\n\rSyntax: reanimate <$
return;
}
}
/* Make sure non one can reanimate other than clerics and Immortals, Clerics get caught here for some reason */
if (!str_cmp(class, "cleric") || !IS_IMMORTAL(ch))
{
send_to_char ("Huh?\n\r", ch);
return;
}
/* are they in the room */
if (( victim = get_char_room(ch, arg)) == NULL)
{
send_to_char("They aren't here.\n\r", ch);
return;
}
if (IS_NPC(victim))
{
send_to_char( "You cannot reanimate a NPC, nice try though!\n\r", ch);
return;
}
if ((victim == ch) && (!IS_SET(ch->act, PLR_GHOST)))
{
send_to_char("You're not a GHOST!\n\r", ch);
return;
}
if (!IS_SET(victim->act, PLR_GHOST))
{
send_to_char("They're not a GHOST!\n\r", ch);
return;
}
if ( victim == ch)
{
send_to_char( "You cannot reanimate yourself!\n\r", ch);
return;
}
if (victim->position != POS_STANDING)
{
send_to_char("They must be standing.\n\r", ch);
return;
}
/* Remove the GHOST */
REMOVE_BIT( victim->act, PLR_GHOST);
sprintf( buf, "%s has been brought back to life!\n\r", victim->name);
send_to_char(buf, ch);
sprintf( buf, "%s has brought you back to life!\n\r", ch->name);
send_to_char(buf, victim);
return;
}
#define IS_CLERIC(ch) ( ch->class == 3 )
#define IS_THIEF(ch) ( ch->class == 1 \
|| ch->class == 8 \
|| ch->class == 9 \
|| ch->class == 10 \
|| ch->class == 22 \
|| ch->class == 23 \
|| ch->class == 24 \
|| ch->class == 25 \
|| ch->class == 26 )