Page 1 of 1

Customized Necromancy Spells

Posted: Wed Nov 23, 2022 7:36 pm
by Azzerhoden
This script was developed using dragon_slayers necro build out for guidance and inspiration. The spells contained here in are:
# . . Spell Name . . . . . . . . . . Mana . . SKill . . . .Descptions
1 . . Call the Dead . . . . . . . . . . 7 . . . . 0 . . . . Summons Skeleton, Zombie, Wraith
2 . . Repair Minion . . . . . . . . . .10 . . . .20 . . . .Use casters health and mana to heal pet or target character.
3 . . Cure Poison . . . . . . . . . . . 12 . . . .25 . . . .Cure the target of poison
4 . . Curse Weapon . . . . . . . . . 15 . . . . 30 . . . .Curse your weapon so that targets it hits become cursed
5 . . Hex Target . . . . . . . . . . . 18 . . . . 35 . . . .Curse your target with a stronger curse
6 . . Bone Armor . . . . . . . . . . .20 . . . . 40 . . . .Increases physical damage resistance at expense of elemental damage (like Reactive Armor)
7 . . Summon Spirit . . . . . . . . .21 . . . . 45 . . . .Summon a players ghost to their corpse - the ghost of the corpse is given the option to refuse
8 . . Summon Familiar . . . . . . .23 . . . . 50 . . . .Summons a random pet (small snake, large snake, spider, vampire bat, dire wolf)
9 . . Spend Life . . . . . . . . . . . 25 . . . . 55 . . . .Transfers casters Health to Mana
10 . . Siphon Minion . . . . . . . . 31 . . . . 60 . . . .Drains mana, life and stamina from minions, gives to caster, but summoned have a chance to break free
11 . . Death Aura . . . . . . . . . . 35 . . . . 65 . . . .Life drain around necromancer, but does not effect undead
12 . . Poison Strike . . . . . . . . .38 . . . . .70 . . . .Cast poison on target and immediate area. Effected have a chance to partially resist
13 . . Call Greater Minion . . . . 40 . . . . .75 . . . .Summon Lich, Mummy, Gazar, Bone Knight, Bone Mage. The longer controlled, the greater chance for them to break free
14 . . Lich Form . . . . . . . . . . .45 . . . . 80 . . . .Changes your form to that of a Lich, with a boost to Magery, Meditation, and Magic Resist
15 . . Ghost Summoning . . . . . 50 . . . . .85 . . . .Summon a murderous ghost - it will not attempt to break free.
16 . . Deaths Dominion . . . . . . 55 . . . . 90 . . . .Resurrect a target player

Summoning forth any undead will flag you as a criminal for the duration of the summoned creatures normal life (as in, if it dies or you send it back, you will still be marked as a criminal). The more powerful summoned will retain their special abilities, such as a ghouls paralyzation attack, or a wraith's life drain. Like mages, a necromancer cannot have a weapon equipped to cast a spell, and failure will use reagents.

On my server I have added Necromancer vendors who sell most of the reagents used for these spells. Others have to drop. I also hijacked 'Wrym's heart' to use as ghost essence, which can be used to summon a ghost. I've added a variable to the script for you to disable that if you choose. This script also makes use of the necrosummoned.dfn file for the list of creatures that a Necro can summon, and those creatures in turn use some of the special abilities I have added in other threads in this section. Specifically, life_drain.js, ghoul_touch.js, and fear_aura.js

Re: Customized Necromancy Spells

Posted: Wed Nov 23, 2022 7:37 pm
by Azzerhoden
Here is the necromancer_spells.js code. NOTE: For a player to transform back to their normal form after becoming a Lich, you must update the race.dfn file and set PLAYERRACE=1 for humans, elfs, and player gargoyles. Otherwise the switch back will fail.
//  PNecromancer Spells Enablement
//  By Azzerhoden Razeri - assist by Dragon Slayer
//  Nov, 2022 - version .5
//  This script adds 16 spells for Necromancers, using the standard plus two additional reagents.  

var summonTheDeadOnly = true;   // Should a Necromancer be able to call back a living player to their corpse?
var lichFormBuffAmount = 300;   // How much should we buff the magery, resist, and meditation skills when in Lich form?
var useGhostEssence = true;     // Should we test for an item called GhostEssence?  Must add it to reagents.dfn if true

function getNecroDuration(pUser)
{
    return (parseInt((pUser.skills.necromancy)/30*10000)); // The default length of time a spell will last.  At skill of 60 this is 200 seconds)
}

function getNecroEffect(pUser)
{
    return (parseInt((pUser.skills.necromancy)/100)* 2); // Default effect of a spell that is cast (Repair Minion).  At 60 this is 12.
}

function onUseChecked( pUser, iUsed )
{
    var socket = pUser.socket;
    socket.tempObj = iUsed;
    if( iUsed.container != null )
    {
        var necroGump = new Gump;
        necroGump.AddPage(0);
        necroGump.AddGump( 30, 30, 2200 );
        necroGump.AddText( 70, 40, 31, "Lesser Rituals" );
        necroGump.AddText( 230, 40, 31, "Greater Rituals" );
        necroGump.AddButton( 60, 70, 0x837, 1, 0, 1 ); 
        necroGump.AddText( 80, 65, 0, "Summon the Dead" );          //  Summons Skeleton, Zombie, Wraith
        necroGump.AddButton( 60, 90, 0x837, 1, 0, 2 );
        necroGump.AddText( 80, 85, 0, "Repair Minon" );             //  (Transfer caster health to heal minion)
        necroGump.AddButton( 60, 110, 0x837, 1, 0, 3 );
        necroGump.AddText( 80, 105, 0, "Cure Poison" );             //  As Mage Spell
        necroGump.AddButton( 60, 130, 0x837, 1, 0, 4 );
        necroGump.AddText( 80, 125, 0, "Curse Weapon" );            //  Curse Weapon - As weapon effect
        necroGump.AddButton( 60, 150, 0x837, 1, 0, 5 );
        necroGump.AddText( 80, 145, 0, "Hex Target" );              //  Hex Target - Apply strong curse
        necroGump.AddButton( 60, 170, 0x837, 1, 0, 6 );
        necroGump.AddText( 80, 165, 0, "Bone Armor" );              //  As Mage Spell Reactive Armor
        necroGump.AddButton( 60, 190, 0x837, 1, 0, 7 );
        necroGump.AddText( 80, 185, 0, "Summon Spirit" );           //  Summon player ghost to corpse
        necroGump.AddButton( 60, 210, 0x837, 1, 0, 8 );
        necroGump.AddText( 80, 205, 0, "Summon Familiar" );         //  Summons (Dire Wolf, Snake, other similar types)
        necroGump.AddButton( 220, 70, 0x837, 1, 0, 9 );
        necroGump.AddText( 240, 65, 0, "Spend Life" );              //  Transfer Casters Health to Mana - gets skill + rnd
        necroGump.AddButton( 220, 90, 0x837, 1, 0, 10 );
        necroGump.AddText( 240, 85, 0, "Siphon Minion" );           //  Drains mana, life and stamina from minions, gives to caster, breaks hold on higher beings (20, 20, 20)
        necroGump.AddButton( 220, 110, 0x837, 1, 0, 11 );
        necroGump.AddText( 240, 105, 0, "Death Aura" );             //  Cast poison on target and immediate area
        necroGump.AddButton( 220, 130, 0x837, 1, 0, 12 );
        necroGump.AddText( 240, 125, 0, "Poison Strike" );          //  Cast poison on target and immediate area
        necroGump.AddButton( 220, 150, 0x837, 1, 0, 13 );
        necroGump.AddText( 240, 145, 0, "Call Greater Minion" );    //  Summon Lich, Mummy, Elder Gazar
        necroGump.AddButton( 220, 170, 0x837, 1, 0, 14 );
        necroGump.AddText( 240, 165, 0, "Lich Form" );              //  As exists
        necroGump.AddButton( 220, 190, 0x837, 1, 0, 15 );
        necroGump.AddText( 240, 185, 0, "Ghost Summoning" );        //  Summon a powerful ghost who will not rebel
        necroGump.AddButton( 220, 210, 0x837, 1, 0, 16);
        necroGump.AddText( 240, 205, 0, "Deaths Dominion" );        //  Resurrect Player
        necroGump.Send( pUser ); // send this gump to client now
        necroGump.Free(); // clear this gump from uox-memory
        return false;
    }
    else
        pUser.SysMessage( "That must be in your pack for you to use it." );
    return false;
}

function onGumpPress( pSock, pButton, gumpData )
{
    var iUsed = pSock.tempObj;
    var pUser = pSock.currentChar;
   
    // Are we recovering from another spell that was just cast
    if( pUser.GetTimer( Timer.SPELLRECOVERYTIME ) != 0 )
    {
        if( pUser.GetTimer( Timer.SPELLRECOVERYTIME ) > GetCurrentClock() )
        {
            if( pSock )
                pSock.SysMessage( GetDictionaryEntry( 1638, mSock.language ) ); // You must wait a little while before casting
            return true;
        }
    }

    // Are we already casting?
    if( !spellTimerCheck( pUser, pSock ) )
        return true;

    if( !jailTimerCheck( pUser, pSock ) )
        return true;

    // The following loop checks to see if any item is currently equipped (if not a GM)
    if( pUser.commandlevel < 2 )
    {
        var itemRHand = pUser.FindItemLayer( 0x01 );
        var itemLHand = pUser.FindItemLayer( 0x02 );
        if( itemLHand || ( itemRHand && itemRHand.type != 9 ) ) // Spellbook
        {
            pUser.SysMessage( GetDictionaryEntry( 708, pUser.language ) ); // You cannot cast with a weapon equipped.
            pUser.SetTimer( Timer.SPELLTIME, 0 );
            pUser.isCasting = false;
            pUser.spellCast = -1;
            return true;
        }
    }


    // Region checks
    var ourRegion = pUser.region;
    if( pButton == 12 && !ourRegion.canRecall )
    {
        if( pSock )
            pSock.SysMessage( GetDictionaryEntry( 705, pSock.language ) );
        pUser.SetTimer( Timer.SPELLTIME, 0 );
        pUser.isCasting = false;
        pUser.spellCast = -1;
        return true;
    }

    if( pUser.visible == 1 || pUser.visible == 2 )
        pUser.visible = 0;

    if( pSock )
        pUser.BreakConcentration( pSock );

    // batwing 0x0f78
    // blackmoore 0x0f79
    // pigiron 0x0f8a
    // nox 0x0f8e
    // deamonblood 0x0f7d
    // gravedust 0x0f8f
    // bone 0x0f7e
    switch(pButton)
    {
        case 0:// abort and do nothing
            pUser.SysMessage("You cancelled the action");
            break;
        case 1:     // Summon the Dead - first warn caster that this is a criminal action
            if ( !pUser.criminal)
                displayCriminalWarningGump(pSock, 20);
            else
                callLesserMinion(pUser);
            break;
        case 2:
            if (checkMana(pUser, 10) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "gravedust", 1))  
            {
                pUser.mana = (pUser.mana - 10);        
                pUser.TextMessage("Tralativa Anima");
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f8f);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 200, 451 ) )  // check if Repair Minion cast succeeds
                    pUser.StartTimer( 750, 2, true );
                else
                    spellFailed(pUser, "give some of yourself");
            }
            break;
        case 3:
            if (checkMana(pUser, 12) && checkReagents(pUser, "deamonblood", 1))  
            {
                pUser.mana = (pUser.mana - 12);
                pUser.TextMessage("Purgo Nox");
                pUser.UseResource(1, 0x0f7d);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 250, 501 ) )  // check if cure poison succeeds
                    pUser.StartTimer( 1500, 3, true );
                else
                    spellFailed(pUser, "cleanse your target");
            }
            break;
        case 4:
            if (checkMana(pUser, 15) && checkReagents(pUser, "batwing", 1))  
            {
                pUser.mana = (pUser.mana - 15);
                pUser.TextMessage("Purgo Nox");
                pUser.UseResource(1, 0x0f78);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 300, 551 ) )  // check if cure poison succeeds
                    pUser.StartTimer( 1500, 4, true );
                else
                    spellFailed(pUser, "cleanse your target");
            }
            break;
        case 5:
            if (checkMana(pUser, 18) && checkReagents(pUser, "batwing", 1) && checkReagents(pUser, "nox", 1))  
            {
                pUser.mana = (pUser.mana - 18);
                pUser.UseResource(1, 0x0f78);
                pUser.UseResource(1, 0x0f8e);
                pUser.TextMessage("Oro Vomica");
                if(!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 350, 601 ) )  // check if Hex Traget succeeds
                    pUser.StartTimer( 1500, 5, true );
                else
                    spellFailed(pUser, "curse your target");
            }
            break;
        case 6:
            if (checkMana(pUser, 20) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "gravedust", 1))  
            {
                pUser.mana = (pUser.mana - 20);
                pUser.UseResource(1, 0x0f8f);
                pUser.TextMessage("Voco Spiritus");
                if(!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 400, 651 ) )  // check if Bone Armor succeeds
                    pUser.StartTimer( 2500, 6, true );
                else
                    spellFailed(pUser, "increase your defences");
            }
            break;
        case 7:     // Summon Spirit
            if (checkMana(pUser, 21) && checkReagents(pUser, "gravedust", 1))  
            {
                pUser.mana = (pUser.mana - 21);        
                pUser.TextMessage("Uus Xen");
                pUser.UseResource(1, 0x0f7d);
                pUser.UseResource(1, 0x0f8f);
                if(!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 500, 751 ) )  // check if Summon Familiar succeeds
                    pUser.StartTimer( 2000, 7, true );
                else
                    spellFailed(pUser, "summon the spirit");
            }
            break;
        case 8:     //  Summon Familiar
            if (checkMana(pUser, 23) && checkReagents(pUser, "deamonblood", 1) && checkReagents(pUser, "batwing", 1))  
            {
                pUser.mana = (pUser.mana - 23);        
                pUser.TextMessage("Uus Xen");
                pUser.UseResource(1, 0x0f7d);
                pUser.UseResource(1, 0x0f78);
                if(!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 500, 751 ) )  // check if Summon Familiar succeeds
                    pUser.StartTimer( 2000, 8, true );
                else
                    spellFailed(pUser, "summon a familiar");
            }
            break;
        case 9:     // Spend Life
            if (checkMana(pUser, 25) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "nox", 1))  
            {
                pUser.mana = (pUser.mana - 25);        
                pUser.TextMessage("Vita Muto Medeis");
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f8e);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 550, 801 ) )  // check if Spend Life
                    pUser.StartTimer( 1500, 9, true );
                else
                    spellFailed(pUser, "give life for mana");
            }
            break;
        case 10:    //  Siphon Monion
            if (checkMana(pUser, 31) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "nox", 1) && checkReagents(pUser, "deamonblood", 1))  
            {
                pUser.mana = (pUser.mana - 31);        
                pUser.TextMessage("Adficio Famulus");
                pUser.UseResource(1, 0x0f7d);
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f8e);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 600, 851 ) )  // check if Siphon Minion cast succeeds
                    pUser.StartTimer( 2500, 10, true );
                else
                    spellFailed(pUser, "siphon from other(s)");
            }
            break;
        case 11:        // Death Aura
            if (checkMana(pUser, 35) && checkReagents(pUser, "blackmoore", 1) && checkReagents(pUser, "nox", 1) && checkReagents(pUser, "batwing", 1))  
            {
                pUser.mana = (pUser.mana - 35);        
                pUser.TextMessage("Castus Mors");
                pUser.UseResource(1, 0x0f79);
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f78);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 650, 901 ) )  // check if Siphon Minion cast succeeds
                {      
                    if ( pUser.GetTempTag("DeathAuraActive") == "" )        // Only 1 active at a time
                    {
                        pUser.SetTempTag("DeathAuraActive", "true");
                        pUser.SetTempTag("DeathAuraCount", 0);
                        pUser.StartTimer( 2500, 11, true );
                    }
                    else
                        pUser.SysMessage("Death Aura already in effect");
                    break;             
                }
                else
                    spellFailed(pUser, "generate death's aura");
            }
            break;
        case 12:        // Poison Strike
            if (checkMana(pUser, 38) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "nox", 1) && checkReagents(pUser, "batwing", 1))  
            {
                pUser.mana = (pUser.mana - 38);        
                pUser.TextMessage("Displodo Toxicum");
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f78);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 700, 951 ) )  // check if Poison Strike succeeds
                    pUser.StartTimer( 2500, 12, true );
                else
                    spellFailed(pUser, "generate death's aura");
            }
            break;
        case 13:        // Call Greater Minion
            if ( !pUser.criminal)
                displayCriminalWarningGump(pSock, 22);
            else
                callGreaterMinion(pUser);
            break;
        case 14:        // Lich Form
            if (pUser.isonhorse)
            {
                pUser.SysMessage("You must dismount first");
                break;
            }
            if (checkMana(pUser, 45) && checkReagents(pUser, "bone", 1) && checkReagents(pUser, "blackmoore", 1))  
            {
                pUser.mana = (pUser.mana - 45);        
                pUser.TextMessage("Fio Inmortui Veneficus");
                pUser.UseResource(1, 0x0f7e);
                pUser.UseResource(1, 0x0f79);
                if( pUser.CheckSkill( 49, 800, 1001 ) )  // check if Deaths Dominion cast succeeds
                    pUser.StartTimer( 4000, 14, true );
                else
                    spellFailed(pUser, "transform");
            }
            break;
        case 15:        // Summon Ghost
            if ( !pUser.criminal)
                displayCriminalWarningGump(pSock, 23);
            else
                callGhost(pUser);
            break;
        case 16:        // Deaths Dominion
            if (checkMana(pUser, 55) && checkReagents(pUser, "pigiron", 1) && checkReagents(pUser, "nox", 1) &&
                    checkReagents(pUser, "deamonblood", 1) && checkReagents(pUser, "gravedust", 1))  
            {
                pUser.mana = (pUser.mana - 55);        
                pUser.TextMessage("Mors Verto Vita");
                pUser.UseResource(1, 0x0f7d);
                pUser.UseResource(1, 0x0f8a);
                pUser.UseResource(1, 0x0f8e);  
                pUser.UseResource(1, 0x0f8f);
                if (!pUser.isonhorse)
                    pUser.DoAction( 17 );
                if( pUser.CheckSkill( 49, 900, 1001 ) )  // check if Deaths Dominion cast succeeds
                    pUser.StartTimer( 2500, 16, true );
                else
                    spellFailed(pUser, "bring the dead to life");
            }
            break;
        case 20:    // Summon Undead pet after player confirms action
                callLesserMinion(pUser);
            break;
        case 21:
                pUser.Teleport(pUser.GetTempTag("loc.x"), pUser.GetTempTag("loc.y"), pUser.GetTempTag("loc.z"), pUser.GetTempTag("loc.w"));
                pUser.SetTempTag("loc.x", "");
                pUser.SetTempTag("loc.y", "");
                pUser.SetTempTag("loc.z", "");
                pUser.SetTempTag("loc.x", "");
            break;
        case 22:    // Summon Greater Undead pet after player confirms action
            callGreaterMinion(pUser);
            break;
        case 23:        // players can summon with ghost essence or mundane reagents
            callGhost(pUser);
            break;
    }
}

function onTimer( pUser, timerID )
{
    var socket = pUser.socket;
    switch(timerID)
    {
        case 1: // Call the dead
            pUser.StaticEffect( 0x373A, 0, 15 );
            pUser.SoundEffect( 0x1FB, true );
            summoned = "";
            rndCreature = RandomNumber(0,100);
            {
                if ( rndCreature < 41 )
                    summoned = "skeleton-summon";
                else if ( rndCreature < 71 )
                    summoned = "zombie-summon";
                else if ( rndCreature < 91 )
                    summoned = "skeletalaxeman-summon";
                else if ( rndCreature < 96 )
                    summoned = "ghoul-summon";
                else
                    summoned = "wraith-summon";
            }
            var nSpawned = SpawnNPC( summoned, pUser.x, pUser.y, pUser.z, pUser.worldnumber );
            if( nSpawned )
                setSummoningInfo(pUser, nSpawned, true);
            break;
        case 2: // Repair Minion
            if( socket )
                socket.CustomTarget( 1, "Select the target minion", 2 ); // Friendly cursor type
            break;         
        case 3: // Cure Poison
            if( socket )
                socket.CustomTarget( 3, "Select the target", 2 ); // Friendly cursor type
            break;         
        case 4:     // Cursed Weapon
            if( socket )
                socket.CustomTarget( 4, "Select the weapon to curse", 2 ); // Friendly cursor type
            break;         
        case 5: //  Hex Target
            if( socket )
                socket.CustomTarget( 5, "Select the target", 2 ); // Friendly cursor type
            break;         
        case 6: // Bone Armor
            if( socket )
            {
                if ( parseInt(pUser.GetTempTag("boneArmor")) == 1)
                {
                    pUser.SysMessage("Bone Armor spell already active");
                    break;
                }
                pUser.SoundEffect( 0x01E7, true );
                pUser.StaticEffect( 0x373A, 0, 15 );
                DoTempEffect(0, pUser, pUser, 15, getNecroEffect(pUser), getNecroDuration(pUser), 0);
            }
            break;
        case 7:     // Summon Spirit
            if( socket )
                socket.CustomTarget( 7, "Select the target minion", 2 ); // Friendly cursor type
            break;
        case 8:     // Summon Familiar
            pUser.StaticEffect( 0x373A, 0, 15 );
            pUser.SoundEffect( 0x1FB, true );
            summoned = "";
            rndCreature = RandomNumber(0,100);
            {
                if ( rndCreature < 41 )
                    summoned = "snake-summon";
                else if ( rndCreature < 71 )  
                    summoned = "direwolf-summon";
                else if ( rndCreature < 91 )
                    summoned = "giantspider-summon";
                else if ( rndCreature < 96 )
                    summoned = "giantserpent-summon";
                else
                    summoned = "vampirebat-summon";
            }
            var nSpawned = SpawnNPC( summoned, pUser.x, pUser.y, pUser.z, pUser.worldnumber );
            if( nSpawned )
                setSummoningInfo(pUser, nSpawned, false);
            break;
        case 9:     // Spend Life
            pUser.health = parseInt(pUser.health) - getNecroEffect(pUser);
            pUser.StaticEffect(0x374a, 0, 15);
            pUser.SoundEffect( 0x56D, true );
            pUser.mana = parseInt(pUser.mana) + getNecroEffect(pUser) + RandomNumber(15,25);   // if successfull get all + bonus in mana
            break;
        case 10:    // Siphon Minion
            var petList = pUser.GetPetList();
            for( var i = 0; i < petList.length; i++ )
            {
                if( ValidateObject( petList[i] ))
                {
                    // Make sure we only take up to what the pet has
                    var deltaHealth = parseInt(getNecroEffect(pUser) > petList[i].health ? petList[i].health : getNecroEffect(pUser));
                    var deltaStamina = parseInt(getNecroEffect(pUser) > petList[i].stamina ? petList[i].stamina : getNecroEffect(pUser));
                    var deltaMana = parseInt(getNecroEffect(pUser) > petList[i].mana ? petList[i].mana : getNecroEffect(pUser));

                    // Show effects
                    petList[i].StaticEffect(0x374a, 0, 15 );
                    petList[i].SoundEffect(0x5cf, true);
                   
                    // Now apply the effecets
                    pUser.health += (deltaHealth);
                    petList[i].health -= (deltaHealth);
                    pUser.stamina += (deltaStamina);
                    petList[i].stamina -= (deltaStamina);
                    pUser.mana += (deltaMana);
                    petList[i].mana -= (deltaMana);
                   
                    // Test whether pet breaks free
                    if ( HasBrokenFree(pUser, petList[i]))
                    {
                        pUser.SysMessage( petList[i].name + " has broken free and attacks you!" );
                        petList[i].tamed = false;
                        petList[i].attacker = pUser;
                        pUser.attacker = petList[i];
                        pUser.controlSlotsUsed = parseInt(pUser.controlSlotsUsed) - parseInt(petList[i].controlSlots);
                        petList[i].owner = null;
                        petList[i].npcai = 2;
                        petList[i].aitype = 2;
                    }
                    else
                    {
                        pUser.SysMessage( petList[i].name + " could not break free." );
                        petList[i].baseskills.magicresistance += 100;
                    }
                }
            }
            break;
        case 11:        // Deaths Aura
            if ( pUser.GetTempTag("DeathAuraActive") != "" )
            {
                pUser.SetTempTag("DeathAuraCount", parseInt(pUser.GetTempTag("DeathAuraCount") + 1));
                AreaCharacterFunction("DoDeathAura", pUser, 3);
                pUser.StartTimer( 5000, 11, true );
            }
            break;
        case 12:
            if( socket )
                socket.CustomTarget( 12, "Select the principal target", 2 ); // Friendly cursor type
            break;
        case 13:
            pUser.StaticEffect( 0x373A, 0, 15 );
            pUser.SoundEffect( 0x1FB, true );
            summoned = "";
            rndCreature = RandomNumber(0,100);
            {
                if ( rndCreature < 41 )
                    summoned = "gazer-summon";
                else if ( rndCreature < 71 )
                    summoned = "boneknight-summon";
                else if ( rndCreature < 91 )
                    summoned = "bonemage-summon";
                else if ( rndCreature < 96 )
                    summoned = "mummy-summon";
                else
                    summoned = "lich-summon";
            }
            var nSpawned = SpawnNPC( summoned, pUser.x, pUser.y, pUser.z, pUser.worldnumber );
            if( nSpawned )
            {
                setSummoningInfo(pUser, nSpawned, true);
                // Check for summoned breaking free
                var timerTest = parseInt(getNecroDuration(pUser)/5);
                nSpawned.StartTimer(timerTest,20,true);
            }
            break;
        case 14:
            var LichForm = pUser.GetTempTag("LichForm");
            if(LichForm != "True" || pUser.id != 0x0018)
            {
                pUser.SetTempTag("LichForm", "True");
                pUser.SetTempTag("OriginalID", pUser.id);
                pUser.SetTempTag("LichBuffAmount", (lichFormBuffAmount));
                pUser.id = 0x0018;
                pUser.skills.magery = (pUser.skills.magery) + (lichFormBuffAmount);
                pUser.skills.meditation = (pUser.skills.meditation) + (lichFormBuffAmount);
                pUser.skills.magicresistance = (pUser.skills.magicresistance) + (lichFormBuffAmount);
            }
            else
            {
                pUser.SetTempTag("LichForm", "");
                pUser.id = (pUser.GetTempTag("OriginalID"));
                pUser.SetTempTag("OriginalID", "");
                pUser.skills.magery = (pUser.skills.magery) - (lichFormBuffAmount);
                pUser.skills.meditation = (pUser.skills.meditation) - (lichFormBuffAmount);
                pUser.skills.magicresistance = (pUser.skills.magicresistance) - (lichFormBuffAmount);
                pUser.SetTempTag("LichBuffAmount", 0);             
            }
            break;
        case 15:        // Ghost Summoning
            pUser.StaticEffect( 0x373A, 0, 15 );
            pUser.SoundEffect( 0x1FB, true );
            summoned = "ghost-summon";
            var nSpawned = SpawnNPC( summoned, pUser.x, pUser.y, pUser.z, pUser.worldnumber );
            if( nSpawned )
                setSummoningInfo(pUser, nSpawned, true);
            break;
        case 16:        // Death's Dominion
            if( socket )
            {
                socket.CustomTarget( 16, "Select the target", 2 ); // Friendly cursor type
            }
            break;         
        case 20:
            // Test for greater minion to break free, then have pet attack caster if true.  pUser is the pet in this test
            if (! pUser)
                break;
            var pOwner = pUser.owner;
            if (HasBrokenFree(pOwner, pUser))
            {
                pOwner.SysMessage( pUser.name + " has broken free and attacks you!" );
                pUser.tamed = false;
                pUser.attacker = pOwner;
                pOwner.attacker = pUser;
                pOwner.controlSlotsUsed = parseInt(pOwner.controlSlotsUsed) - parseInt(pUser.controlSlots);
                pUser.owner = null;
                pUser.npcai = 88;
                pUser.aitype = 88;
            }
            else
            {
                pOwner.SysMessage( pUser.name + " could not break free." );
                var effectTimer = parseInt(getNecroDuration(pOwner)/5);
                pUser.baseskills.magicresistance += 100;
                pUser.StartTimer(effectTimer,20,true);
            }
            break;
        case 21:
            // pUser in this situation is the weapon that was cursed.
            pUser.morex = 0;
            pUser.morey = 0;
            pUser.morez = 0;
            pUser.RemoveScriptTrigger(3304);
            break; 
        case 22:
            // We removed the curse from the weapon, now remove from the wielder
            pUser.RemoveScriptTrigger(3305);
            pUser.SysMessage("Your cursed weapon has lost its effect");
            break;
    }
}


function callLesserMinion(pUser)
{
    if (checkMana(pUser, 7) && checkReagents(pUser, "deamonblood", 1) && checkReagents(pUser, "gravedust", 1))  
    {
        pUser.mana = (pUser.mana - 7);         
        pUser.TextMessage("Uus Corp");
        pUser.UseResource(1, 0x0f7d);
        pUser.UseResource(1, 0x0f8f);
        if(!pUser.isonhorse)
            pUser.DoAction( 17 );
        if( pUser.CheckSkill( 49, 0, 251 ) )  // check if Summon the Dead succeeds
            pUser.StartTimer( 750, 1, true );
        else
            spellFailed(pUser, "summon a minion");
    }
    return true;
}

function callGreaterMinion(pUser)
{
    if (checkMana(pUser, 40) && checkReagents(pUser, "bone", 1) && checkReagents(pUser, "gravedust", 1) && checkReagents(pUser, "deamonblood", 1))  
    {
        pUser.mana = (pUser.mana - 40);        
        pUser.TextMessage("Adficio Vas Famulus");
        pUser.UseResource(1, 0x0f7d);
        pUser.UseResource(1, 0x0f7e);
        pUser.UseResource(1, 0x0f8f);
        if (!pUser.isonhorse)
            pUser.DoAction( 17 );
        if( pUser.CheckSkill( 49, 750, 1001 ) )  // check if Summon Greater Minion is successful
            pUser.StartTimer( 3500, 13, true );
        else
            spellFailed(pUser, "summon a greater minion");
    }
    return true;
}

function callGhost(pUser)
{
    var hasGhostReagents = false;
    var hasOtherReagents = false;
    if (checkMana(pUser, 50))
    {
        if (checkReagents(pUser, "ghostessence", 1))
            hasGhostReagents = true;
        else if (checkReagents(pUser, "batwing", 1) && checkReagents(pUser, "gravedust", 1) && checkReagents(pUser, "deamonblood", 1))
            hasOtherReagents = true;
        if ( hasGhostReagents || hasOtherReagents )
        {
            pUser.mana = (pUser.mana - 50);        
            if ( useGhostEssence && hasGhostReagents)  // if we should test for GhostEssence, and players have ghost essence, it might not get used
            {
                rndReagentTest = RandomNumber(1, 100);
                if (rndReagentTest < 25)
                {
                    pUser.UseResource(1, 0x0F91);
                    pUser.SysMessage("Your summoning consumes your ghostly essence.");
                }
                else
                    pUser.SysMessage("Your ghostly essence is intact!");
            }
            else
            {
                pUser.UseResource(1, 0x0f7d);
                pUser.UseResource(1, 0x0f78);
                pUser.UseResource(1, 0x0f8f);
            }
            pUser.TextMessage("Spiritus Concalo");
            if (!pUser.isonhorse)
                pUser.DoAction( 17 );
            if( pUser.CheckSkill( 49, 850, 1001 ) )  // check if Ghost Summoning is successful
                pUser.StartTimer( 5000, 15, true );
            else
                spellFailed(pUser, "summon a greater minion");
        }
    }
    return true;
}

function onCallback1( socket, myTarget)     //  Repair Minion
{
    var pUser = socket.currentChar;
    var healAmt = getNecroEffect(pUser);
    var isMyPet = false;
//  pUser.SysMessage("Is Char: " + myTarget.isChar + " - Is NPC: " + myTarget.npc + " - Owner is: " + myTarget.owner.name);
    if( !socket.GetWord( 1 ) && (myTarget.isChar || (myTarget.npc && myTarget.tamed)))
    {
        var petList = pUser.GetPetList();
        for( var i = 0; i < petList.length; i++ )
        {
            if( myTarget == petList[i] )
                isMyPet = true;
        }
        if( pUser.InRange( myTarget, 12 ) && isMyPet)
        {
            pUser.StaticEffect(0x374a, 0, 15);
            pUser.SoundEffect( 0x56D, true );
            pUser.health = parseInt(pUser.health) - 10;
            myTarget.StaticEffect( 0x373A, 0, 15 );
            myTarget.SoundEffect(0x01E0, true );
            myTarget.health = getNecroEffect(pUser) + healAmt;
        }
        else
            pUser.SysMessage( "Your target is out of range." );    
    }
    else
        pUser.SysMessage("Invalid target");
    return true;
}

function onCallback3( socket, myTarget)     //  Cure Poison
{
    var pUser = socket.currentChar;
    if( !socket.GetWord( 1 ) && (myTarget.isChar || (myTarget.npc && myTarget.owner == pUser)))
    {
        if( pUser.InRange( myTarget, 12 ))
        {
            myTarget.poison = 0;
            myTarget.StaticEffect( 0x373A, 0, 15 );
            myTarget.SoundEffect(0x01E0, true );
        }
        else
            pUser.SysMessage( "Your target is out of range." );
    }
    else
        pUser.SysMessage( "You cannot target that." );
}

function onCallback4( socket, myTarget)     //  Curse Weapon
{
    var pUser = socket.currentChar;
    if (!socket.GetWord(1) && ((myTarget.layer == 1 || myTarget.layer == 2) && myTarget.type != 9))
    {
        if( pUser.InRange( myTarget, 12 ))
        {
            var timerDuration = getNecroDuration(pUser);
            myTarget.morex = 4;
            myTarget.morey = 27;
            myTarget.morez = 25;
            myTarget.AddScriptTrigger(3304);
            myTarget.owner = pUser;
            pUser.StaticEffect( 0x373A, 0, 15 );
            pUser.SoundEffect(0x01E0, true );
            // Set the timer for the player, then for the object
            pUser.StartTimer((timerDuration), 22, true);
            myTarget.StartTimer((timerDuration),21,true);
        }
        else
            pUser.SysMessage( "Your target is out of range." );    
    }
    else
        pUser.SysMessage("You must cast this on a weapon");
}

function onCallback5( socket, myTarget)     //  Hex Target
{
    var pUser = socket.currentChar;
    if( !socket.GetWord( 1 ) && (myTarget.isChar || myTarget.npc ))
    {
        if( pUser.InRange( myTarget, 12 ))
        {
            DoTempEffect(0, null, myTarget, 12, getNecroEffect(pUser), getNecroDuration(pUser), 0);
            myTarget.StaticEffect( 0x373A, 0, 15 );
            myTarget.SoundEffect(0x01E0, true );
        }
        else
            pUser.SysMessage( "Your target is out of range." );
    }
    else
        pUser.SysMessage( "You cannot target that." );
}

function onCallback7( socket, myTarget)     //  Summon Spirit
{
    var pUser = socket.currentChar;
    if( !socket.GetWord( 1 ) && (myTarget.amount == 400 || myTarget.amount == 401)) // Only works on a players corpse
    {
        var deadPlayer = myTarget.owner;
        if( pUser.InRange( myTarget, 12 ))
        {
            if ( deadPlayer.dead || !summonTheDeadOnly)
            {
                displaySummonsGump(deadPlayer.socket, pUser.name);  // Give the player a choice on being recalled
                deadPlayer.SetTempTag("loc.x", myTarget.x);
                deadPlayer.SetTempTag("loc.y", myTarget.y);
                deadPlayer.SetTempTag("loc.z", myTarget.z);
                deadPlayer.SetTempTag("loc.w", myTarget.worldnumber );
            }
            else
                pUser.SysMessage( "The owner is back among the living." );
        }
        else
            pUser.SysMessage( "Your target is out of range." );
    }
    else
        pUser.SysMessage( "You cannot target that." );
}

function onCallback12(socket, myTarget)
{
    var pUser = socket.currentChar;
    if( !socket.GetWord( 1 ) && (myTarget.isChar || myTarget.npc ) && myTarget.commandlevel < 1)
    {
        if( pUser.InRange( myTarget, 12 ))
        {
            var baseChance = ((500 - (pUser.skills.necromancy - myTarget.baseskills.magicresistance))+ 100);
            if (baseChance > 950)
                baseChance = 950;
            else if (baseChance < 50)
                baseChance = 50;
            var rndNumber = RandomNumber(0, 1000);
            if (rndNumber > baseChance)
                myTarget.SetPoisoned(3, 30000);
            else
            {
                trgChar.SetPoisoned(1, 30000);
                trgChar.EmoteMessage("*partially resists*");
            }
            AreaCharacterFunction("ApplyPoisonStrike", myTarget, 5, socket);
        }
        else
            pUser.SysMessage( "Your target is out of range." );
    }
    else
        pUser.SysMessage("Invalid target");
}

function onCallback16( socket, myTarget)    // Death's Dominion
{
    var pUser = socket.currentChar;
    if( !socket.GetWord( 1 ) && myTarget.isChar )
    {
        if( pUser.InRange( myTarget, 12 ) && myTarget.dead)
        {
            myTarget.Resurrect();
            return true;
        }
        else
            pUser.SysMessage( "Your target is out of range." );
    }      
}

function setSummoningInfo(pUser, nCreature, crime)
{
    nCreature.owner = pUser;
    nCreature.aitype = 0;
    nCreature.Follow( pUser );
    nCreature.wandertype = 1;
    nCreature.isDispellable = true;
    pUser.controlSlotsUsed = (pUser.controlSlotsUsed) += nCreature.controlSlots;
    if (crime)
    {
        pUser.criminal = true;
        pUser.SetTimer( Timer.CRIMFLAG, getNecroDuration(pUser) );
        nCreature.criminal = true; 
        nCreature.SetTimer( Timer.CRIMFLAG, getNecroDuration(pUser) );
    }
    nCreature.SetTimer(Timer.SUMMONTIME, getNecroDuration(pUser));
}

function HasBrokenFree(pUser, pPet) // Determine if pet breaks free, always a small chance of success/failure
{
    var baseChance = ((500 - (pUser.skills.necromancy - pPet.baseskills.magicresistance))+ 100);
    if (baseChance > 950)
        baseChance = 950;
    else if (baseChance < 50)
        baseChance = 50;
    var rndNumber = RandomNumber(0, 1000);
    if (rndNumber > baseChance)
        return false;
    return true;
}

function ApplyPoisonStrike(pUser, trgChar, socket)
{
    if (trgChar.poison == 0 && trgChar.online && trgChar.commandlevel < 1)
    {
        var baseChance = ((500 - (pUser.skills.necromancy - trgChar.baseskills.magicresistance))+ 100);
        if (baseChance > 950)
            baseChance = 950;
        else if (baseChance < 50)
            baseChance = 50;
        var rndNumber = RandomNumber(0, 1000);
        if (rndNumber > baseChance)
            trgChar.SetPoisoned(2, 30000);
        else
        {
            trgChar.SetPoisoned(1, 30000);
            trgChar.EmoteMessage("*partially resists*");
        }
    }
}

function DoDeathAura(pUser, trgChar, socket)        // Death Aura only effects the living who are online
{                                      
    pUser.SysMessage("Count is: " + pUser.GetTempTag("DeathAuraCount") + " - Total Cycles: " + (getNecroEffect(pUser) / 4));
    if ( parseInt(pUser.GetTempTag("DeathAuraCount")) <= (getNecroEffect(pUser) / 4))
    {
        if( ValidateObject( trgChar ) && trgChar != pUser && trgChar.vulnerable && trgChar.race.id != 11 &&
                ( trgChar.npc || trgChar.online ))
        {  
            trgChar.health = parseInt(trgChar.health - (getNecroEffect(pUser) / 2));
            trgChar.StaticEffect(0x374a, 0, 15 );
            trgChar.SoundEffect(0x5cf, true);
            pUser.health = parseInt(pUser.health + (getNecroEffect(pUser) / 4));
            pUser.StaticEffect( 0x373A, 0, 15 );
        }
    }
    else
    {
        pUser.SetTempTag("DeathAuraActive", "");
        pUser.SetTempTag("DeathAuraCount", 0);
    }
}

function checkMana(pUser, min)
{
    if ( pUser.mana < min)
    {
        pUser.SysMessage("Your mana is to low.");
        return false;
    }
    return true;
}

function checkReagents(pUser, reagent, min)
{
    var name = reagent;
    var inventory = 0;
    switch(reagent)
    {
        case "batwing":
            inventory = (pUser.ResourceCount( 0x0f78 ));
            name = "bat wing";
            break;
        case "pigiron":
            inventory = (pUser.ResourceCount( 0x0f8a ));
            name = "pig iron";
            break;
        case "nox":
            inventory = (pUser.ResourceCount( 0x0f8e ));
            name = "nox crystal";
            break;
        case "deamonblood":
            inventory = (pUser.ResourceCount( 0x0f7d ));
            name = "daemon blood";
            break;
        case "gravedust":
            inventory = (pUser.ResourceCount( 0x0f8f ));
            name = "grave dust";
            break;
        case "bone":
            inventory = (pUser.ResourceCount( 0x0f7e ));
            break;
        case "blackmoore":
            inventory = (pUser.ResourceCount( 0x0f79 ));
            break;
        case "ghostessence":
            inventory = (pUser.ResourceCount( 0x0F91 ));
            name = "ghostly essence";
            break;
        //  var bloodspawn = pUser.ResourceCount( 0x0f7c );
        //  var brimstone = pUser.ResourceCount( 0x0f7f );
    }
    if ((inventory) < (min))
    {
        pUser.SysMessage("You lack any " + name + ".");
        return false;
    }
    return true;
}


function spellFailed(pUser, name)
{
    pUser.SysMessage( "You failed to " + name + "." );
    pUser.StaticEffect( 0x3735, 0, 15 );
    pUser.SoundEffect( 0x56D, true );
    return true;    
}

function spellTimerCheck( mChar, mSock )
{
    if( mChar.GetTimer( Timer.SPELLTIME ) != 0 )
    {
        if( mChar.isCasting )
        {
            if( mSock )
                mSock.SysMessage( GetDictionaryEntry( 762, mSock.language ) );
            return false;
        }
        else if( mChar.GetTimer( Timer.SPELLTIME ) > GetCurrentClock() )
        {
            if( mSock )
                mSock.SysMessage( GetDictionaryEntry( 1638, mSock.language ) );
            return false;
        }
    }
    return true;
}


function jailTimerCheck( mChar, mSock )
{
    if( mChar.isJailed && mChar.commandlevel < 2 )
    {
        mSock.SysMessage( GetDictionaryEntry( 704, mSock.language ) );
        mChar.SetTimer( Timer.SPELLTIME, 0 );
        mChar.isCasting = false;
        mChar.spellCast = -1;
        return false;
    }
    return true;
}

function spellEnableCheck( mChar, mSock, mSpell )
{
    if( !mSpell.enabled )
    {
        if( mSock )
            mSock.SysMessage( GetDictionaryEntry( 707, mSock.language ) );
        mChar.SetTimer( Timer.SPELLTIME, 0 );
        mChar.isCasting = false;
        mChar.spellCast = -1;
        return false;
    }
    return true;
}

function displayCriminalWarningGump(srcSock, but2Press)
{
    var myGump = new Gump;

    myGump.AddPage(0);
    myGump.AddBackground( 200, 100, 225, 150, 2500 );
    myGump.AddText( 250, 145, 0, "This will flag you");
    myGump.AddText( 250, 165, 0, "as a criminal!" );
    myGump.AddButton( 250, 210, 0x817, 0x818, 1, 0, 0 );
    myGump.AddButton( 325, 210, 0x81A, 0x81B, 1, 1, but2Press );
    myGump.Send( srcSock );
    myGump.Free();
}

function displaySummonsGump(srcSock, necroName)
{
    var myGump = new Gump;

    myGump.AddPage(0);
    myGump.AddBackground( 200, 100, 225, 150, 2500 );
    myGump.AddText( 238, 130, 0, necroName + " wants to summon");
    myGump.AddText( 238, 150, 0, "you back to your " );
    myGump.AddText( 238, 170, 0, "corpse. Do you consent?" );
    myGump.AddButton( 250, 210, 0x817, 0x818, 1, 0, 0 );
    myGump.AddButton( 325, 210, 0x81A, 0x81B, 1, 1, 21 );
    myGump.Send( srcSock );
    myGump.Free();
}