Page 1 of 1

Wandering Healer

Posted: Sun Dec 11, 2005 7:47 pm
by Xuri
// Wandering Healer
// v1.00
// by Xuri (xuri@sensewave.com)

// The Wandering Healer-script will let any character it's attached to, heal and resurrect wounded/dead players, as
// well as heal him/her-self in the process, if wounded. (Also a chance to heal him/her-self if in combat)
// By default it's setup to function as a wandering healer-script, but customization is easy.
// Will not heal/res criminals or murderers

// DON'T CHANGE THIS VALUE:
var i = 0;

// searchAmount = Number of times healer will look around for chars to heal/resurrect before stopping
// searchInterval = The interval at wihch the healer looks around for chars to heal/resurrect after having started searching
// searchRange = The radius in which the healer searches for wounded people
// searchTimer = Amount of time between each time the healer initiates his searches
// resTimer = Minimum time that must pass before healer will resurrect same char again (1000 = 1 second)
// healTimer = Minimum time that must pass before healer will heal same char again (1000 = 1 second)
// manaCostHeal = the amount of mana the NPC uses for healing
// manaCostRes = the amount of mana the NPC uses for resurrecting
var searchAmount = 3;
var searchInterval = 5000;
var searchRange = 4;
var searchTimer = 15000;
var resTimer = 30000;
var healTimer = 30000;
var manaCostHeal = 11;
var manaCostRes = 50;

// These variables can be customized or commented out if you don't want to use them
var healSoundFX = 0x01f2;
var healGFXEffect = 0x376A;
var resSoundFX = 0x376A;
var resGFXEffect = 0x376A;

// These messages can be customized. If you don't want to use them at all, comment them out
var healMsgPositive = "Thou hast been healed. Mayest thou stay healthy.";
var healMsgNegative = "Thou hast been healed too recently. Try again later.";
var resMsgPositive = "Thou hast been resurrected. Now STAY alive!";
var resMsgNegative = "Thou hast been resurrected too recently. Try again later.";
var criminalReply = "Thou art a criminal and I will not assist thee!";
var outOfManaMsg = "I have no mana left! Try again later...";
var startSearchEmote = "*looks around for someone to heal*";
var endSearchEmote = "*shrugs and goes back to wandering*";
var healSelfEmote = "*heals self*";

function inRange( pCharacter, objInRange )
{
    if( objInRange.isChar )
    {
        // Get the current server clock, and if it exists, the time for when the last search was started
        // Compare the two, and the script will see if enough time has passed to initiate a new search
        // This also ensures that the script stays working even if the server saves in the middle of a
        // search, but crashes before the next save.
        var iTime = GetCurrentClock();
        var initSearchTime = pCharacter.GetTag( "initSearchTime" );
        //If search has already been initiated, don't start a new search, unless an abnormal amount of time has passed
        if(( initSearchTime != null && initSearchTime != 0 ) && ((( iTime - initSearchTime ) < searchTimer ) && !( initSearchTime > iTime )))
            return;
        else if((( iTime - initSearchTime ) > searchTimer ) || initSearchTime > iTime )
        {
            pCharacter.SetTag( "initSearchTime", iTime );
            if( startSearchEmote )
                pCharacter.EmoteMessage( startSearchEmote );
            pCharacter.StartTimer( searchInterval, 1, true );
        }
    }
}

// This triggers the keyword-based healing/resurrection
function onSpeech( strSaid, pTalking, npcHealer )
{
    if( strSaid == "heal" )
    {
        if( pTalking.dead )
            doRes( pTalking, npcHealer );
        else if( pTalking.health < pTalking.maxhp )
            doHeal( pTalking, npcHealer );
    }
    return false;
}

// This is the general function for healing characters
function doHeal( woundedChar, npcHealer )
{
    if( !woundedChar.criminal && !woundedChar.murderer )
    {
        if( npcHealer.mana > manaCostHeal )
        {
            var iTime = GetCurrentClock();
            var lastHealTime = woundedChar.GetTag( "lastHealTime" );
            if(( lastHealTime == null || lastHealTime == 0 ) || ((( iTime - lastHealTime ) > healTimer ) || ( lastHealTime > iTime )))
            {
                woundedChar.health = woundedChar.maxhp;
                woundedChar.StaticEffect( healGFXEffect, 0, 15 );
                woundedChar.SoundEffect( healSoundFX, true );
                woundedChar.SetTag( "lastHealTime", iTime );
                npcHealer.mana-= manaCostHeal;
                if( healMsgPositive )
                    npcHealer.TextMessage( healMsgPositive );
                return;
            }
            else
            {
                if( healMsgNegative )
                    npcHealer.TextMessage( healMsgNegative );
                return;
            }
        }
        else
        {
            if( outOfManaMsg )
                npcHealer.TextMessage( outOfManaMsg );
            return;
        }
    }
    else
    {
        if( criminalReply )
            npcHealer.TextMessage( criminalReply );
        return;
    }
}

// This is the general function for resurrecting characters
function doRes( deadChar, npcHealer )
{
    if( !deadChar.criminal && !deadChar.murderer )
    {
        if( npcHealer.mana > manaCostRes )
        {
            var iTime = GetCurrentClock();
            var lastResTime = deadChar.GetTag( "lastResTime" );
            if(( lastResTime == null || lastResTime == 0 ) || ((( iTime - lastResTime ) > resTimer ) || ( lastResTime > iTime )))
            {
                deadChar.Resurrect();
                deadChar.SetTag( "lastResTime", iTime );
                npcHealer.mana-= manaCostRes;
                if( resMsgPositive )
                    npcHealer.TextMessage( resMsgPositive );
                return;
            }
            else
            {
                if( resMsgNegative )
                    npcHealer.TextMessage( resMsgNegative );
                return;
            }
        }
        else
        {
            if( outOfManaMsg )
                npcHealer.TextMessage( outOfManaMsg );
            return;
        }
    }
    else
    {
        if( criminalReply )
            npcHealer.TextMessage( criminalReply );
        return;
    }  
}

// Gives the healer a chance to heal himself any time damage is done towards him
function onDefense( pAttacker, pDefender )
{
    var iNum = RandomNumber( 0, 1000 );
    if( iNum > 700 )
    {
        if( pDefender.health < pDefender.maxhp )
        {
            if( pDefender.mana > manaCostHeal )
            {
                pDefender.health = pDefender.maxhp;
                pDefender.mana-= manaCostHeal;
                pDefender.StaticEffect( 0x376A, 0, 15 );
                pDefender.SoundEffect( 0x01f2, true );
                if( healSelfEmote )
                    pDefender.EmoteMessage( healSelfEmote );
            }
        }
    }
}

function onTimer( srcChar, timerID )
{
    if( timerID == 1 )
    { //Search for nearby wounded characters the specified amount of times
        if( i < searchAmount )
        {
            AreaCharacterFunction( "searchForWounded", srcChar, searchRange );
            srcChar.StartTimer( searchInterval, 1, true );
            i++;
        }
        else
        {
            i = 0;
            if( endSearchEmote )
                srcChar.EmoteMessage( endSearchEmote );
        }
    }
}

//This function iterates through all characters within the specified radius in AreaCharacterFunction
//It then checks to make sure they are valid for receiving healing or resurrection.
function searchForWounded( srcChar, trgChar, pSock )
{
    if( trgChar.serial != srcChar.serial )
    {
        if( trgChar.dead )
            doRes( trgChar, srcChar );
        else if( trgChar.health < trgChar.maxhp )
            doHeal( trgChar, srcChar );
    }
    else
    {
        if( srcChar.health < srcChar.maxhp )
        {
            if( srcChar.mana > manaCostHeal )
            {
                srcChar.health = srcChar.maxhp;
                srcChar.mana-= manaCostHeal;
                srcChar.StaticEffect( 0x376A, 0, 15 );
                srcChar.SoundEffect( 0x01f2, true );
                if( healSelfEmote )
                    srcChar.EmoteMessage( healSelfEmote );
            }
        }
    }
}

Posted: Wed Jan 11, 2006 3:45 pm
by stranf
Used it, works great.

However, I'm not sure where in the file, but when the healer is searching he likes to call out:

"2102 202102 102102" (or some similar number)
and then

"*mutters and goes back to wandering*"

I just figure my wandering healers get bored and like to count all the trees they pass by.

Posted: Wed Jan 11, 2006 7:07 pm
by Xuri
Oops! I seem to have left a debugging message in there :)

Remove the following line, and you'll stop seeing the numbers:
pCharacter.TextMessage( initSearchTime + " " + iTime + " " + searchTimer );

Posted: Tue Jan 17, 2006 5:25 pm
by stranf
fixed and done.

Great work!

I actually added a Lord British NPC using the GM skin and your healer template (it was the quickest way to get Lord B to heal you a la Ultima IV)

It's kind of cool really, you walk in the throne room and the great king looks on his throne and *searches for someone to heal*. what a noble lord!

It's kind of funny scince the title remains: The Glorious Lord British, the wandering healer