28 Sep, 2008, gorex wrote in the 1st comment:
Votes: 0
Anyone seen Ghost code lingering around anywhere?
28 Sep, 2008, Kline wrote in the 2nd comment:
Votes: 0
I've got some I could dig out of my old AckMUD for you. Diku based; should transport with minimal difficulty. We went as far as to change speech and make ghosts invis to players unless they manifest themselves, and some other fun tricks, too.
28 Sep, 2008, gorex wrote in the 3rd comment:
Votes: 0
Sounds great! I'm really just looking for a base to get started. Thanks!
28 Sep, 2008, Kline wrote in the 4th comment:
Votes: 0
Ok I think I found most parts of it. Probably not the most elegant (or correct ;) solutions in some places, but it's old code and hopefully gives you a good starting point to work from.

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;

};
28 Sep, 2008, Conner wrote in the 5th comment:
Votes: 0
That looks pretty cool, Kline, any restrictions on it's use?
28 Sep, 2008, Kline wrote in the 6th comment:
Votes: 0
Nah, take it and run with it :) I've been meaning to redo and add something similar to AckFUSS and somebody asking for it was a good catalyst for me to go dig it up!
28 Sep, 2008, Conner wrote in the 7th comment:
Votes: 0
Cool, I do believe I'll do just that then. :smile:

I showed this to Dragona and we both love the idea in general, though I'm thinking I want to make it that you resurrected when you get your corpse rather than after a few minutes, like so many MMOs seem to do. Alternatively (considering death traps & folks who run out of time for corpse retrieval, etc) you could be resurrected by a healer (like you've got up there already) if you want to just start over without gear. :ghostface:

I might even try to get you a copy of what I end up with in case you want to officially release it since it's starting out as a snippet from you, but it'll have smaug color codes by then. :wink: Or at least, if I (re?)released it, I'd be sure to credit you as the original author.:cool: (Honestly, that'd be entirely up to you but either way I'd prolly want to share what we end up with with you since it was your code to begin with)

On a related note, that reminds me that I need to shoot an email to Exodus as we've made some "further refinements" to his buidty code recently over at my mud that I believe he'll like…
28 Sep, 2008, Hades_Kane wrote in the 8th comment:
Votes: 0
With our ghost code (which I think is a completely different system than this) we recently underwent some changes.

Before, you died, your corpse fell to the ground with all of your stuff, then you were a ghost. Someone could use a spell or appropriate potion or you could go to the healer to come back to life. Once alive, you go back to your corpse (or if it has decayed, the room with all of your belongings on the ground) and you get your stuff back.

That was really the only penalty to death.

Well, we've amped up death penalties (you lose exp every death, but subsequent deaths within an hour of the first carries with it a chance of additional penalties such as more exp loss, a stat loss, a piece of eq loss) but to counter this, we've changed the way death/corpses work a bit.

I was always bothered with the idea that you could be "alive" but somehow retrieving your corpse. So what we did is there are two revival options, both result in never having a "corpse" while you are alive.

1) Typical Resurrection: This is done as the freebie 'heal ghost' at a healer, or if you are brought back to life after your corpse has decayed or if you are in another room than your corpse. Your corpse dissipates from the room it was in, basically being returned to you and your form solidifies.

2) Better Resurrection: This is a costly 'heal revive' at a healer, or if you are brought back to life within the same room as your corpse. This way, you basically "wake up" in your corpse with all of your stuff in your inventory. This is clearly the superior revival method and it negates corpse/eq retrieval, but it is pretty costly.

These changes were made for both logical concerns and to add another money sink into the game.

Just thought I would throw out some alternate ideas that others might be able to get some use out of.
28 Sep, 2008, David Haley wrote in the 9th comment:
Votes: 0
I'd be curious to hear how your ghost changes work out, HK.
29 Sep, 2008, Kline wrote in the 10th comment:
Votes: 0
Yeah, there were some further parts of this but I think I just forgot to include them. Running back to your body wasn't an option we wanted to do. When you die, you sit there. This way if you're deep in a hard dungeon with a party of friends and happen to have a healer, they can rez you on the spot. Otherwise your options include running to a nearby healer mob (maybe the dungeon had one in it someplace) or if you're really just utterly lost and stuck, to wait for the auto-rez to not frustrate people. There are lots of possibilities with a system like this :)

Let me know if you make something larger and cooler out of it Conner, maybe it'd save me re-writing it myself when I get off my butt and put it in AckFUSS :P
30 Sep, 2008, Guest wrote in the 11th comment:
Votes: 0
I had some grand plans for stuff like this that never got much beyond the initial "hey, this would be cool" stage.

* Corpse rots to skeleton on death.
- Deity favor to resurrect, cleric spell, pay a priest, special items.
- Can't touch, pick up stuff
- Immune to hunger, thirst, sleep, etc.
- Immune to all forms of magic, bad or good, except resurrection.
- Cannot engage in combat.
- Ability to possess lesser mobs.
- Stage of corpse decay determines percentage of HP on resurrect.

Corpses that become skeletons were as far as I got, aside from adding the actual PLR_GHOST flag and making all the imm commands and very basic movement etc ghost-useable. The reason I had plans to turn corpses into skeletons was so that once the flesh rotted away you wouldn't just lose everything to falling on the ground so soon. The skeletons last a considerably longer period of time, on Alsherok measuring realtime hours, before they too decay into dust leaving their contents behind. The idea being that as a ghost you'd be able to wander about freely but be unable to interact with anything except some noted exceptions I hadn't even made cheesy notes out of yet.
30 Sep, 2008, quixadhal wrote in the 12th comment:
Votes: 0
WileyMUD had corpse rot. We also implemented food rot, and the same mechanic works, you just change the outcome. For food, it decays every N ticks, prints a warning message "A hunk of meat looks a little brown.", a few more ticks later it becomes poisonous (just like a potion), and then a few ticks later still it decays to dust.

For corpses, you don't need the message or poison (although a roomwide message about flies swarming would be fine), but when decay hits 0, we make a choice. If the creature wasn't in the newbie zones, and a dice roll hits, the corpse is raised as a random undead creature who then equips all the things that were in its inventory. If the dice roll misses, it dissolves and all the stuff ends up on the ground where other mobs/players can wander by and loot it.

Dying in town was hazardus, since we had corpse eating dogs roaming the streets. If a dog ate your corpse (and your stuff), you could kill the dog to get it back… assuming you could find the right dog… and there wasn't a guard nearby when you found him. :)

Actually, I always wanted to implement some of the restrictions you've listed for immortals. I don't think an immortal has any business interacting with the world beyond doing reimbursements (good luck with that!), or building. If they want to fight, or mess with players, they should create/possess an avatar and thus be mortal. Back when we had a player population, I thought it would be amusing to allow players to worship the immortals, and make their avatar's level based on their followers.
05 Oct, 2008, gorex wrote in the 13th comment:
Votes: 0
Ok, so this is the function I've created to bring the ghost back to life. I'm having some difficulty getting it to allow three types to use: Immortals, healers, and clerics. It currently works for Immortals and Healers, but I can't seem to get it to work for clerics. Guidance and suggestions would be greatly appreciated!

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;
}
05 Oct, 2008, Kline wrote in the 14th comment:
Votes: 0
So this might be a silly question, but you've verified that if ch->class == 3 (or whatever) that your class_table[3].name IS actually cleric, right? With no color codes or special crap in the way?
05 Oct, 2008, gorex wrote in the 15th comment:
Votes: 0
yes, "cleric"
05 Oct, 2008, David Haley wrote in the 16th comment:
Votes: 0
That's not the best way of checking the class. Surely there is a constant or something that you can use? You already have the identifier ch->class, why not use that instead?
05 Oct, 2008, gorex wrote in the 17th comment:
Votes: 0
explain?
05 Oct, 2008, Hades_Kane wrote in the 18th comment:
Votes: 0
What I would suggest is adding in a macro in your merc.h file, something like:

#define IS_CLERIC(ch)	(  ch->class == 3 )


Then maybe repeat for every other class… this way you don't have to remember what number each class is defined as, and in a check like that you can simply do an if check for IS_CLERIC. Overall, it should be less code as well.

The reason I have stuff like that defined in our's is because we have a "class promotion" system where a Thief can promote to Assassin or Pirate, and those "promotions" can further promote later on, so its handy to be able to define "Thief" as the base class Thief and any further classes, such as:

#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 )


But anyway, I hope this helps!
05 Oct, 2008, gorex wrote in the 19th comment:
Votes: 0
helps…I get through loop now…but I still get hung up on

(!IS_IMMORTAL(ch) || !IS_CLERIC(ch))
05 Oct, 2008, Kline wrote in the 20th comment:
Votes: 0
You want if( !IS_IMMORTAL(ch) && !IS_CLERIC(ch) )

If MORTAL AND NOT a Cleric. Otherwise you're checking if MORTAL OR NOT a Cleric. So they would have to be an Imm AND a Cleric, to pass.
0.0/21