Author Topic: Undead player questions and scripting know how!  (Read 634 times)

Legacy_Fester Pot

  • Hero Member
  • *****
  • Posts: 1698
  • Karma: +0/-0
Undead player questions and scripting know how!
« on: December 19, 2012, 08:27:23 pm »


               Hey, hey!

Got a sticky situation and need guidance toward adding this feature to Fate of the Auren - I've put it off too long - and with testing, I need to balance what one finds with this script added in.

So ... what's the best option in having the player cast Negative Energy spells on themselves to heal, while healing spells would harm?

nw_i0_spells - modify and check for Undead under the void spellsCure function?

OR ...

Modify all the cure spells individual to HARM rather than HEAL?
nw_s0_curminw
nw_s0_curlgtw
nw_s0_curmodw
nw_s0_curserw
nw_s0_curcrwn
nw_s0_heal
nw_s0_healcirc

That's the first question. I do like making a modification to one script, rather than multiple ones, so maybe I'm answering my own question, but would like some thoughts on doing so.

Second question!

How can I make the system think a player character - Human, Dwarf, Gnome, Elf, Half-Elf, Halfling - is Undead for said spells to do what I'd like?

The nw_i0_spells already does have a check set up for this (as do the spells it seems) -

if (GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD)
    {
        //Figure out the amount of damage to heal
        nHeal = nDamage;
        //Set the heal effect
        eHeal = EffectHeal(nHeal);
        //Apply heal effect and VFX impact
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);
        //Fire cast spell at event for the specified target
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID, FALSE));


    }
    //Check that the target is undead
    else
    {
        int nTouch = TouchAttackMelee(oTarget);
        if (nTouch > 0)
        {
            if(!GetIsReactionTypeFriendly(oTarget))
            {
                //Fire cast spell at event for the specified target
                SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID));
                if (!MyPRCResistSpell(OBJECT_SELF, oTarget))
                {
                    eDam = EffectDamage(nDamage,DAMAGE_TYPE_NEGATIVE);
                    //Apply the VFX impact and effects
                    DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
                    ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
                }
            }
        }
    }


Problem is that there is no SetRacialType, and being a single player game, players from Almraiven are either Human, Dwarf, Gnome, Half-Elf, Halfling or Elf.

FP!
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #1 on: December 19, 2012, 08:38:08 pm »


               Best way to do this is probably via core function hooking. Either way you have to recompile all scripts using GetRacialType(oTarget) == UNDEAD and either rewrite it to the MyGetRacialType(oTarget) == UNDEAD or with use of the core hooking spell can stay untouched (with the new functioon GetRacialType added into nw_i0_spells)

Depends probably on how much global this should be, whether you want to alter only these spells or you plan to add functionality of all undead-treated spells like control undead, undeath do dead etc.


Detailed info: Simple change in the spellsCure function inside nw_i0_spells will do nothing. To make it work you have to open all spells that uses this function and recompile them.,

EDIT: so it would looked like this

int MyGetRacialType(object oTarget)
{
if(GetLevelByclass(class_type_monk,oTarget) > 19 return RACIAL_TYPE_OUTSIDER;
if(GetLevelByclass(class_type_palemaster,oTarget)>9 return RACIAL_TYPE_UNDEAD;
if(GetItemPossessedBy("undead_token",oTarget) != OBJECT_INVALID) return RACIAL_TYPE_UNDEAD;
return GetRacialType(oTarget);
}
               
               

               


                     Modifié par ShaDoOoW, 19 décembre 2012 - 08:40 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #2 on: December 19, 2012, 08:46:46 pm »


               For determining whether the PC is undead:

Create a function that checks whether a creature is undead

int GetIsUndead(object oCreature)
{
    if(    GetSubRace(oCreature")=="undead"       ||  GetRacialType(oCreature)==RACIAL_TYPE_UNDEAD
      )
        return TRUE;
   else          return FALSE;
}

alternatively instead of checking for the undead subrace you could create a local int "UNDEAD" You will need to set one or the other on the PC depending on which method you prefer. 

In the Cure/Harm spell you will want to substitute that function in place of the GetRacialType function in the if statement

With regards to healing versus harming:
I think you need to change each of those spells unless you want to write one spell and then add that spell script to each of the spells in spells.2da.  That script will need to check which spell indeax was used to determine potency.
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #3 on: December 19, 2012, 09:11:54 pm »


               An easy way to address this is to use NWNX and a plugin like nwnx_funcs to set the PC's racial type to undead. This can be done with nwnx_funcs using the NWNXFuncs_SetRace(oPC, RACIAL_TYPE_UNDEAD) function. It's pretty simple to do and saves a boatload of work with modifying all the spells. We have just used that for some events we have running and so far it works really slick - Turn Undead working vs. PCs, Negative Energy healing, Curing spells harming, etc is all taken care of without any script modifications.

Just thought I'd throw out that option for you.
               
               

               


                     Modifié par Thayan, 19 décembre 2012 - 09:20 .
                     
                  


            

Legacy_HipMaestro

  • Hero Member
  • *****
  • Posts: 2849
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #4 on: December 20, 2012, 12:53:59 am »


               The heal skill will heal undead but I think the script is hard-coded. You guys would know better than I.
               
               

               
            

Legacy_Fester Pot

  • Hero Member
  • *****
  • Posts: 1698
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #5 on: December 24, 2012, 04:27:28 am »


               Thanks everyone!

I've made the changes required, but in testing, I've come across a snag.

In allowing the player to cast Negative Energy Ray upon themselves. Currently, you can't, but if it's to be used as a healing spell, where do I go about making the required modification so you can target yourself?

For reference, I've gone the route Henesua suggested, which is the easiest for me to understand and work with.

FP!
               
               

               
            

Legacy_MagicalMaster

  • Hero Member
  • *****
  • Posts: 2712
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #6 on: December 24, 2012, 04:38:49 am »


               Spells.2da

Not sure if there's a way to do it that doesn't require a hak file change.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #7 on: December 24, 2012, 03:19:05 pm »


               Changes to spell targeting require a hak file change, if you care about the mouse cursor and where/on what you can click to cast it. Worse, it has to be a clientside hak edit, not just a serverside one - otherwise complications arise, the details of which I've forgotten (though I recall a definite reason - it's why our ball lightning's targeting is different from our firebrand's).

If, however, you don't care about the cursor, you can alter spell behavior simply through scripting, given a few limitations. That is, you can make any given spell create a sphere on damage centered on the target or target's location, effecting only hostiles, or you can make it have no effect other than to heal the caster, given the conditions you have in mind. That is, even on a spell that can only target hostiles, you can still have it heal the caster instead, though they WILL need a hostile to target. With most damage spells, though, you can target the ground, (and with some, the caster) so that shouldn't be a major issue, if you pick another spell - a ray spell is not great in this regard. Maybe NEB instead?

Funky
               
               

               
            

Legacy_DM_Vecna

  • Hero Member
  • *****
  • Posts: 501
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #8 on: August 05, 2013, 07:22:41 pm »


               I am very interested in getting Thayan's suggestion here working with NWNX_funcs but I am finding conflicting reports as to the possibility of success. Does anyone know if Thayan is still active or have contact information?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #9 on: August 06, 2013, 04:42:17 pm »


               I don't know for certain if Thayan's suggestion is possible - I seem to recall issues with setting racial type with nwnx, but that may have been limited to leto - I just don't remember. I do know, however, that acaos, the guy who pioneered most of the nwnx_funcs functions, found it much simpler to route all the pos/neg spells to a single script with a serverside 2da edit, and handle it in nwscript.  He edited the following 2da lines, excluding our custom spells:


*snip*
Sigh at bioboards. Paring down to get a clean post that'll fit.

Funky
               
               

               


                     Modifié par FunkySwerve, 06 août 2013 - 03:50 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #10 on: August 06, 2013, 04:49:54 pm »


               31
 Cure_Critical_Wounds


 32
 Cure_Light_Wounds


 33
 Cure_Minor_Wounds


 34
 Cure_Moderate_Wounds


 35
 Cure_Serious_Wounds


 77
 Harm


 79
 Heal


 114
 Mass_Heal


 431
 Inflict_Minor_Wounds


 432
 Inflict_Light_Wounds


 433
 Inflict_Moderate_Wounds


 434
 Inflict_Serious_Wounds


 435
 Inflict_Critical_Wounds


 567
 Cure_Critical_Wounds_Others


 611
 BGInflictSerious


 612
 BGInflictCritical


 759
 UndeadSelfHarm


 2137
 HGSPELL_MASS_CURE_CRITICAL_WOUNDS


 2138
 HGSPELL_MASS_CURE_LIGHT_WOUNDS


 2139
 HGSPELL_MASS_CURE_MODERATE_WOUNDS


 2140
 HGSPELL_MASS_CURE_SERIOUS_WOUNDS


 2149
 HGSPELL_MASS_HARM


 2150
 HGSPELL_MASS_INFLICT_CRITICAL_WOUNDS


 2151
 HGSPELL_MASS_INFLICT_LIGHT_WOUNDS


 2152
 HGSPELL_MASS_INFLICT_MODERATE_WOUNDS


 2153
 HGSPELL_MASS_INFLICT_SERIOUS_WOUNDS
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #11 on: August 06, 2013, 05:07:24 pm »


               hgs_gen_posneg is the name of the script that fires for all those spells. Here's a sample line, in case you haven't done much 2da editing:

31    Cure_Critical_Wounds    781    is_curcrwnds    C    T    vs    0x3F    0x2B    hgs_gen_posneg    4    4    5    ****    ****    ****    5    1500    head    vco_mehanheal03    ****    ****    sco_mehanheal03    vs_chant_conj_hm    vs_chant_conj_hf    touch    1000    ****    ****    ****    ****    0    ****    ****    ****    ****    ****    ****    1    ****    ****    ****    ****    ****    5    ****    1    16883343    1    1    ****    0    ****    ****    ****    0   

All you have to do is sub out the bioware script in those lines with the name of the spell script you use in its place. Acaos did a lot of _gen_ (general) spells - 37 in total - when he worked on our spell scripts, as they make mass edits far easier, and save mod resources to boot. Here is a list of the names, in case you're curious - the hgs is short for higher ground spell, and is the prefix we use on our all custom spellscripts.




 hgs_gen_abilbuff.nss


 hgs_gen_beam.nss


 hgs_gen_bolt.nss


 hgs_gen_broken.nss


 hgs_gen_buff.nss


 hgs_gen_cone.nss


 hgs_gen_damred.nss


 hgs_gen_damshld.nss


 hgs_gen_dispel.nss


 hgs_gen_dot.nss


 hgs_gen_dragbrth.nss


 hgs_gen_elemres.nss


 hgs_gen_font.nss


 hgs_gen_monabil.nss


 hgs_gen_monaura.nss


 hgs_gen_monbolt.nss


 hgs_gen_monbuff.nss


 hgs_gen_moncone.nss


 hgs_gen_mondrag.nss


 hgs_gen_mongaze.nss


 hgs_gen_monhowl.nss


 hgs_gen_monpulse.nss


 hgs_gen_monsumm.nss


 hgs_gen_orb.nss


 hgs_gen_poly.nss


 hgs_gen_posneg.nss


 hgs_gen_ray.nss


 hgs_gen_restore.nss


 hgs_gen_shifter.nss


 hgs_gen_skilbuff.nss


 hgs_gen_sphere.nss


 hgs_gen_spmantle.nss


 hgs_gen_summon.nss


 hgs_gen_trap.nss


 hgs_gen_tr_enter.nss


 hgs_gen_wpndbuff.nss


 hgs_gen_wpnebuff.nss
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #12 on: August 06, 2013, 05:09:19 pm »


               And last, hgs_gen_posneg itself - sorry for all the split posts.


#include "hg_inc"
#include "ac_spell_inc"

const int ENERGY_RANK_HARM       = -6;
const int ENERGY_RANK_INF_CRIT   = -5;
const int ENERGY_RANK_INF_SER    = -4;
const int ENERGY_RANK_INF_MOD    = -3;
const int ENERGY_RANK_INF_LIGHT  = -2;
const int ENERGY_RANK_INF_MINOR  = -1;
const int ENERGY_RANK_INVALID    =  0;
const int ENERGY_RANK_CURE_MINOR =  1;
const int ENERGY_RANK_CURE_LIGHT =  2;
const int ENERGY_RANK_CURE_MOD   =  3;
const int ENERGY_RANK_CURE_SER   =  4;
const int ENERGY_RANK_CURE_CRIT  =  5;
const int ENERGY_RANK_HEAL       =  6;

void ApplyEnergyVisual (object oTarget, int nRank, int nClass, float fDelay) {
    int nVis = -1, nSnd = -1;

    if (GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = CEPVFX_IMP_HARM_YELLOW;                      nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_CRIT:   nVis = VFX_IMP_SUNSTRIKE;                           nSnd = -1;                   break;
            case ENERGY_RANK_INF_SER:    nVis = VFX_IMP_SUNSTRIKE;                           nSnd = -1;                   break;
            case ENERGY_RANK_INF_MOD:    nVis = VFX_IMP_SUNSTRIKE;                           nSnd = -1;                   break;
            case ENERGY_RANK_INF_LIGHT:  nVis = VFX_IMP_SUNSTRIKE;                           nSnd = -1;                   break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_SUNSTRIKE;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = CEPVFX_IMP_HEALING_S_ORANGE;                 nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_LIGHT: nVis = CEPVFX_IMP_HEALING_S_ORANGE;                 nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_MOD:   nVis = CEPVFX_IMP_HEALING_M_ORANGE;                 nSnd = CEPSFX_IMP_HEALING_M; break;
            case ENERGY_RANK_CURE_SER:   nVis = CEPVFX_IMP_HEALING_L_ORANGE;                 nSnd = CEPSFX_IMP_HEALING_L; break;
            case ENERGY_RANK_CURE_CRIT:  nVis = CEPVFX_IMP_HEALING_G_ORANGE;                 nSnd = CEPSFX_IMP_HEALING_G; break;
            case ENERGY_RANK_HEAL:       nVis = PRCVFX_IMP_HEALING_X_UNDEAD; nSnd = -1;                   break;
            default:                     return;
        }
    } else if (GetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT) {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = VFX_IMP_HARM;                                nSnd = -1;                   break;
            case ENERGY_RANK_INF_CRIT:   nVis = PRCVFX_IMP_INFLICT_G;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_SER:    nVis = PRCVFX_IMP_INFLICT_L;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MOD:    nVis = PRCVFX_IMP_INFLICT_M;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_LIGHT:  nVis = PRCVFX_IMP_INFLICT_S;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_HEAD_EVIL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = CEPVFX_IMP_HEALING_S_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_LIGHT: nVis = CEPVFX_IMP_HEALING_S_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_MOD:   nVis = CEPVFX_IMP_HEALING_M_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_M; break;
            case ENERGY_RANK_CURE_SER:   nVis = CEPVFX_IMP_HEALING_L_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_L; break;
            case ENERGY_RANK_CURE_CRIT:  nVis = CEPVFX_IMP_HEALING_G_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_G; break;
            case ENERGY_RANK_HEAL:       nVis = CEPVFX_IMP_HEALING_X_PURPLE;                 nSnd = CEPSFX_IMP_HEALING_X; break;
            default:                     return;
        }
    } else if (GetRacialType(oTarget) == RACIAL_TYPE_PLANT || nClass == CLASS_TYPE_DRUID) {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = CEPVFX_IMP_HARM_ORANGE;                      nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_CRIT:   nVis = PRCVFX_IMP_INFLICT_G;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_SER:    nVis = PRCVFX_IMP_INFLICT_L;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MOD:    nVis = PRCVFX_IMP_INFLICT_M;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_LIGHT:  nVis = PRCVFX_IMP_INFLICT_S;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_HEAD_EVIL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = VFX_IMP_HEAD_HEAL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_LIGHT: nVis = CEPVFX_IMP_HEALING_S_GREEN;                  nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_MOD:   nVis = CEPVFX_IMP_HEALING_M_GREEN;                  nSnd = CEPSFX_IMP_HEALING_M; break;
            case ENERGY_RANK_CURE_SER:   nVis = CEPVFX_IMP_HEALING_L_GREEN;                  nSnd = CEPSFX_IMP_HEALING_L; break;
            case ENERGY_RANK_CURE_CRIT:  nVis = CEPVFX_IMP_HEALING_G_GREEN;                  nSnd = CEPSFX_IMP_HEALING_G; break;
            case ENERGY_RANK_HEAL:       nVis = CEPVFX_IMP_HEALING_X_GREEN;                  nSnd = CEPSFX_IMP_HEALING_X; break;
            default:                     return;
        }
    } else if (nClass == CLASS_TYPE_CLERIC) {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = VFX_IMP_HARM;                                nSnd = -1;                   break;
            case ENERGY_RANK_INF_CRIT:   nVis = PRCVFX_IMP_INFLICT_G;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_SER:    nVis = PRCVFX_IMP_INFLICT_L;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MOD:    nVis = PRCVFX_IMP_INFLICT_M;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_LIGHT:  nVis = PRCVFX_IMP_INFLICT_S;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_HEAD_EVIL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = VFX_IMP_HEAD_HEAL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_LIGHT: nVis = CEPVFX_IMP_HEALING_S_BLUE;                   nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_MOD:   nVis = CEPVFX_IMP_HEALING_M_BLUE;                   nSnd = CEPSFX_IMP_HEALING_M; break;
            case ENERGY_RANK_CURE_SER:   nVis = CEPVFX_IMP_HEALING_L_BLUE;                   nSnd = CEPSFX_IMP_HEALING_L; break;
            case ENERGY_RANK_CURE_CRIT:  nVis = CEPVFX_IMP_HEALING_G_BLUE;                   nSnd = CEPSFX_IMP_HEALING_G; break;
            case ENERGY_RANK_HEAL:       nVis = CEPVFX_IMP_HEALING_X_BLUE;                   nSnd = CEPSFX_IMP_HEALING_X; break;
            default:                     return;
        }
    } else if (nClass == CLASS_TYPE_BARD) {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = VFX_IMP_HARM;                                nSnd = -1;                   break;
            case ENERGY_RANK_INF_CRIT:   nVis = PRCVFX_IMP_INFLICT_G;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_SER:    nVis = PRCVFX_IMP_INFLICT_L;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MOD:    nVis = PRCVFX_IMP_INFLICT_M;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_LIGHT:  nVis = PRCVFX_IMP_INFLICT_S;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_HEAD_EVIL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = VFX_IMP_HEAD_HEAL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_LIGHT: nVis = CEPVFX_IMP_HEALING_S_CYAN;                   nSnd = CEPSFX_IMP_HEALING_S; break;
            case ENERGY_RANK_CURE_MOD:   nVis = CEPVFX_IMP_HEALING_M_CYAN;                   nSnd = CEPSFX_IMP_HEALING_M; break;
            case ENERGY_RANK_CURE_SER:   nVis = CEPVFX_IMP_HEALING_L_CYAN;                   nSnd = CEPSFX_IMP_HEALING_L; break;
            case ENERGY_RANK_CURE_CRIT:  nVis = CEPVFX_IMP_HEALING_G_CYAN;                   nSnd = CEPSFX_IMP_HEALING_G; break;
            case ENERGY_RANK_HEAL:       nVis = CEPVFX_IMP_HEALING_X_CYAN;                   nSnd = CEPSFX_IMP_HEALING_X; break;
            default:                     return;
        }
    } else {
        switch (nRank) {
            case ENERGY_RANK_HARM:       nVis = VFX_IMP_HARM;                                nSnd = -1;                   break;
            case ENERGY_RANK_INF_CRIT:   nVis = PRCVFX_IMP_INFLICT_G;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_SER:    nVis = PRCVFX_IMP_INFLICT_L;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MOD:    nVis = PRCVFX_IMP_INFLICT_M;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_LIGHT:  nVis = PRCVFX_IMP_INFLICT_S;                        nSnd = CEPSFX_IMP_HARM;      break;
            case ENERGY_RANK_INF_MINOR:  nVis = VFX_IMP_HEAD_EVIL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MINOR: nVis = VFX_IMP_HEAD_HEAL;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_LIGHT: nVis = VFX_IMP_HEALING_S;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_MOD:   nVis = VFX_IMP_HEALING_M;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_SER:   nVis = VFX_IMP_HEALING_L;                           nSnd = -1;                   break;
            case ENERGY_RANK_CURE_CRIT:  nVis = VFX_IMP_HEALING_G;                           nSnd = -1;                   break;
            case ENERGY_RANK_HEAL:       nVis = VFX_IMP_HEALING_X;                           nSnd = -1;                   break;
            default:                     return;
        }
    }

    if (nSnd >= 0)
        DelayCommand(fDelay, ApplyVisualToObject(nSnd, oTarget));
    DelayCommand(fDelay, ApplyVisualToObject(nVis, oTarget));
}


void main() {
    struct SpellInfo si = GetSpellInfo();
    if (si.id < 0)
        return;

    if (GetLocalInt(si.item, "Unlimited") > 0 &&
        GetLocalInt(si.item, "Unlimited") == GetBaseItemType(si.item)) {

        string sSourceTag = GetLocalString(si.item, "UnlimitedSourceTag");
        if (sSourceTag != "" && !GetIsObjectValid(GetItemPossessedBy(si.caster, sSourceTag))) {
            SetPlotFlag(si.item, FALSE);
            DestroyObject(si.item);
        } else
            SetItemStackSize(si.item, 99);

        if (GetLocalInt(si.item, "UnlimitedSelfOnly") && si.target != si.caster) {
            FloatingTextStringOnCreature("You can only use this item on yourself!", si.caster, FALSE);
            return;
        }

        SetItemCursedFlag(si.item, TRUE);
    }

    int nHeal = GetSkillRank(SKILL_HEAL, OBJECT_SELF);
    if (nHeal < 4)
        nHeal = 4;
    else if (GetIsObjectValid(si.item) && nHeal > 20 && (nHeal > si.clevel * 2))
        nHeal = si.clevel * 2;

    int nDice = 0, nBonus = 0, nSides = 8, nRank = 0, nFocus = GetCasterSpellFocus(si.school);
    int nAmount, nRace, nHealRace = -1, nHarmRace = -1, nSaveType = -1, nDamType = DAMAGE_TYPE_POSITIVE;
    float fDelay, fRadius = 0.0;

    switch (si.id) {
        case SPELLABILITY_BG_INFLICT_SERIOUS_WOUNDS:
            FloatingTextStringOnCreature("Please use the Flame Weapon spell from your Blackguard spellbook.", si.caster, FALSE);
            return;

        case SPELLABILITY_BG_INFLICT_CRITICAL_WOUNDS:
            FloatingTextStringOnCreature("Please use the Bestow Curse spell from your Blackguard spellbook.", si.caster, FALSE);
            return;

        case SPELL_CURE_MINOR_WOUNDS:
            nRank   = ENERGY_RANK_CURE_MINOR;
            nDice   = 1;
            nSides  = 1;
            nBonus  = nHeal - 1;
            si.id   = SPELL_CURE_MINOR_WOUNDS;
            break;

        case HGSPELL_MASS_CURE_LIGHT_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_CURE_LIGHT_WOUNDS:
            nRank   = ENERGY_RANK_CURE_LIGHT;
            nDice   = nHeal / 4;
            nBonus  = (si.clevel > 5 ? 5 : si.clevel);
            si.id   = SPELL_CURE_LIGHT_WOUNDS;
            break;

        case SPELL_HEALING_CIRCLE:
        case HGSPELL_MASS_CURE_MODERATE_WOUNDS:
            fRadius = (si.id == SPELL_HEALING_CIRCLE ? RADIUS_SIZE_LARGE : RADIUS_SIZE_MEDIUM);
        case SPELL_CURE_MODERATE_WOUNDS:
            nRank   = ENERGY_RANK_CURE_MOD;
            nDice   = nHeal / 2;
            nBonus  = (si.clevel > 10 ? 10 : si.clevel);
            si.id   = SPELL_CURE_MODERATE_WOUNDS;
            break;

        case HGSPELL_MASS_CURE_SERIOUS_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_CURE_SERIOUS_WOUNDS:
            nRank   = ENERGY_RANK_CURE_SER;
            nDice   = (nHeal * 3) / 4;
            nBonus  = (si.clevel > 15 ? 15 : si.clevel);
            si.id   = SPELL_CURE_SERIOUS_WOUNDS;
            if (GetLocalInt(si.caster, "HER_PICKUP")) {
                if (!GetIsDead(si.target)) {
                    effect eEff;
                    int nRemoved = 0;
                    for (eEff = GetFirstEffect(si.target); GetIsEffectValid(eEff); eEff = GetNextEffect(si.target)) {
                        if (GetEffectTrueType(eEff) == EFFECT_TRUETYPE_KNOCKDOWN) {
                            nRemoved++;
                            RemoveEffect(si.target, eEff);
                        }
                    }
                    if (nRemoved > 0) {
                        effect eImmob = ExtraordinaryEffect(EffectCutsceneImmobilize());
                        eImmob = EffectLinkEffects(eImmob, EffectVisualEffect(PRCVFX_DUR_AIR1));
                        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmob, si.target, 2.0);
                    }
                }
                DeleteLocalInt(si.caster, "HER_PICKUP");
                return;
            }
            break;

        case HGSPELL_MASS_CURE_CRITICAL_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_CURE_CRITICAL_WOUNDS:
            nRank   = ENERGY_RANK_CURE_CRIT;
            nDice   = nHeal;
            nBonus  = (si.clevel > 20 ? 20 : si.clevel);
            si.id   = SPELL_CURE_CRITICAL_WOUNDS;
            break;

        case SPELL_MASS_HEAL:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_HEAL:
            nRank   = ENERGY_RANK_HEAL;
            si.id   = SPELL_HEAL;

            if (GetLocalInt(GetArea(si.caster), "SkillBasedHeal")) {
                nDice  = nHeal * 2;
                nBonus = 200;
            } else
                nDice = -1;
            break;


        case SPELL_INFLICT_MINOR_WOUNDS:
            nRank     = ENERGY_RANK_CURE_MINOR;
            nDice     = 1;
            nSides    = 1;
            nBonus    = nHeal - 1;
            nDamType  = DAMAGE_TYPE_NEGATIVE;
            si.id     = SPELL_INFLICT_MINOR_WOUNDS;
            break;

        case HGSPELL_MASS_INFLICT_LIGHT_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_INFLICT_LIGHT_WOUNDS:
            nRank    = ENERGY_RANK_CURE_LIGHT;
            nDice    = nHeal / 4;
            nBonus   = (si.clevel > 5 ? 5 : si.clevel);
            nDamType = DAMAGE_TYPE_NEGATIVE;
            si.id    = SPELL_INFLICT_LIGHT_WOUNDS;
            break;

        case HGSPELL_MASS_INFLICT_MODERATE_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_INFLICT_MODERATE_WOUNDS:
            nRank    = ENERGY_RANK_CURE_MOD;
            nDice    = nHeal / 2;
            nBonus   = (si.clevel > 10 ? 10 : si.clevel);
            nDamType = DAMAGE_TYPE_NEGATIVE;
            si.id    = SPELL_INFLICT_MODERATE_WOUNDS;
            break;

        case HGSPELL_MASS_INFLICT_SERIOUS_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_INFLICT_SERIOUS_WOUNDS:
            nRank    = ENERGY_RANK_CURE_SER;
            nDice    = (nHeal * 3) / 4;
            nBonus   = (si.clevel > 15 ? 15 : si.clevel);
            nDamType = DAMAGE_TYPE_NEGATIVE;
            si.id    = SPELL_INFLICT_SERIOUS_WOUNDS;
            break;

        case HGSPELL_MASS_INFLICT_CRITICAL_WOUNDS:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_INFLICT_CRITICAL_WOUNDS:
            nRank    = ENERGY_RANK_CURE_CRIT;
            nDice    = nHeal;
            nBonus   = (si.clevel > 20 ? 20 : si.clevel);
            nDamType = DAMAGE_TYPE_NEGATIVE;
            si.id    = SPELL_INFLICT_CRITICAL_WOUNDS;
            break;

        case HGSPELL_MASS_HARM:
            fRadius = RADIUS_SIZE_MEDIUM;
        case SPELL_HARM:
        case 759:               /* Undead Self Harm */
            nRank    = ENERGY_RANK_HEAL;
            nDamType = DAMAGE_TYPE_NEGATIVE;
            si.id    = SPELL_HARM;

            if (GetLocalInt(GetArea(si.caster), "SkillBasedHeal")) {
                nDice  = nHeal * 2;
                nBonus = 200;
            } else
                nDice = -1;
            break;

        default:
            FloatingTextStringOnCreature("An invalid pos/neg spell #" + IntToString(si.id) + " was cast. Please inform a DM.", si.caster);
            return;
    }


    if (nHealRace < 0 && nHarmRace < 0 && nSaveType < 0) {
        if (nDamType == DAMAGE_TYPE_POSITIVE) {
            nHealRace = RACIAL_TYPE_ALL;
            nHarmRace = RACIAL_TYPE_UNDEAD;
            nSaveType = SAVING_THROW_TYPE_POSITIVE;
        } else {
            nHealRace = RACIAL_TYPE_UNDEAD;
            nHarmRace = RACIAL_TYPE_ALL;
            nSaveType = SAVING_THROW_TYPE_NEGATIVE;
        }
    }


    if (si.class == CLASS_TYPE_CLERIC && nHealRace == RACIAL_TYPE_ALL && GetHasFeat(FEAT_HEALING_DOMAIN_POWER, si.caster))
        nDice = (nDice * 3) / 2;

    if (!GetIsObjectValid(si.item) && si.class == CLASS_TYPE_CLERIC && nFocus > 1)
        nFocus = (nFocus - 1) * 2;
    else
        nFocus = 0;

    if (fRadius > 0.0) {
        if (si.id == SPELL_HEALING_CIRCLE)
            ApplyVisualAtLocation(VFX_FNF_LOS_HOLY_20, si.loc);
        else if (nDamType == DAMAGE_TYPE_NEGATIVE)
            ApplyVisualAtLocation(VFX_FNF_LOS_EVIL_10, si.loc);
        else if (si.class == CLASS_TYPE_DRUID)
            ApplyVisualAtLocation(HGVFX_FNF_LOS_GREEN_10, si.loc);
        else
            ApplyVisualAtLocation(VFX_FNF_LOS_HOLY_10, si.loc);

        si.target = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, si.loc, TRUE);
    }

    while (GetIsObjectValid(si.target)) {
        nRace  = GetRacialType(si.target);
        fDelay = GetSpellEffectDelay(si.loc, si.target);

        if (nRace == RACIAL_TYPE_UNDEAD && GetLocalInt(si.target, "HealType") == DAMAGE_TYPE_POSITIVE)
            nRace = RACIAL_TYPE_HUMAN;

        if (GetIsSpellTarget(si, si.target, TARGET_TYPE_ALLY) || nRace == nHealRace || GetLocalInt(si.target, "AllowHeal")) {
            if (GetSpellBuffLevel(si, si.target) > 0) {
                if (nRace != nHarmRace                                   &&
                    (nHealRace == RACIAL_TYPE_ALL || nRace == nHealRace) &&
                    !GetIsQuasiclass(QUASICLASS_ACCURSED_PARIAH, si.target)) {

                    SignalEvent(si.target, EventSpellCastAt(si.caster, si.id, FALSE));

                    if (nDice < 0) {
                        if (GetLocalInt(si.target, "SkillBasedHeal"))
                            nAmount = MetaPower(si, GetSkillRank(SKILL_HEAL, si.caster) * 2, 8, 200);
                        else
                            nAmount = GetMaxHitPoints(si.target);
                    } else if (nSides > 1) {
                        if (si.clevel > 40)
                            nAmount = MetaPower(si, nDice, nSides + 4, nBonus);
                        else if (si.clevel > 20)
                            nAmount = MetaPower(si, nDice, nSides + 2, nBonus);
                        else
                            nAmount = MetaPower(si, nDice, nSides, nBonus);
                    } else
                        nAmount = MetaPower(si, nDice, nSides, nBonus);

                    effect eHeal = EffectHeal(nAmount);

                    ApplyEnergyVisual(si.target, nRank, si.class, fDelay);
                    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, si.target));
                }

                /* Heal can heal persistent wounds at CL41+ */
                if (si.id == SPELL_HEAL) {
                    if (GetLocalInt(si.target, "PersistentWound")) {
                        if (si.clevel > 40) {
                            DeleteLocalInt(si.target, "PersistentWound");
                            RemoveEffectsFromSpell(HGEFFECT_PERSISTENT_WOUND, si.target);

                            FloatingTextStringOnCreature("Your wound closes!", si.target, FALSE);
                        } else
                            FloatingTextStringOnCreature("The Heal spell was too weak to close the wound!", si.target, FALSE);
                    }
                }
            }
        } else if (nRace == nHarmRace || nHarmRace == RACIAL_TYPE_ALL) {
            int bTouch;

            if (fRadius > 0.0) {
                si.dc += nFocus;
                bTouch = !GetSpellSaved(si, SAVING_THROW_REFLEX, si.target, nSaveType, fDelay);
                si.dc -= nFocus;
            } else
                bTouch = TouchAttackMelee(si.target);

            SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));

            if (bTouch > 0 && !GetSpellResisted(si, si.target, fDelay)) {
                if (nDice >= 0) {
                    nAmount = MetaPower(si, nDice, nSides, nBonus);

                    if (bTouch == 2)
                        nAmount *= 2;
                    if (GetSpellSaved(si, SAVING_THROW_WILL, si.target, nSaveType, fDelay))
                        nAmount /= 2;
                } else if (GetObjectType(si.target) == OBJECT_TYPE_CREATURE) {
                    if (GetLocalInt(si.target, "SkillBasedHarm"))
                        nAmount = MetaPower(si, GetSkillRank(SKILL_HEAL, si.caster) * 2, 8, 200);
                    else
                        nAmount = GetCurrentHitPoints(si.target) - d4();
                } else
                    nAmount = 0;

                if (nAmount > 0) {
                    effect eDam = EffectDamage(nAmount, nDamType);

                    if (GetIsPC(si.caster))
                        MinLocalInt(si.target, "AttackerLevel", GetHitDiceIncludingLLs(si.caster));

                    ApplyEnergyVisual(si.target, -nRank, si.class, fDelay);
                    DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, si.target));
                }
            }
        }

        if (fRadius > 0.0)
            si.target = GetNextObjectInShape(SHAPE_SPHERE, fRadius, si.loc, TRUE);
        else
            si.target = OBJECT_INVALID;
    }
}

LMK if you have questions.

Funky
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #13 on: August 06, 2013, 05:09:19 pm »


               Not dead yet. '<img'>

Right now we are using NWNX to set race for our PC subraces and undead (vampires) and it seems to be working fine, albeit we haven't had a large sampling of undead PCs who had their race change since our end-of-world events in January. Earlier this year we ended up making a hak for Thay, and in that the necessary changes to the spells.2da allow the negative energy spells to be cast on one's self, so as far as spells that should affect undead, I have made no changes since that takes care of them. Another benefit of using NWNX to change race is that some of the hardcoded stuff like item AC or AB bonuses vs. race do end up affecting these PCs as well.

However, a drawback is that this does affect other systems which 'assume' all PCs are of one of the 6 standarad races. For example, off the top of my head I do know I had to modify the Bioware horse scripts to avoid appearance changes when logging in. But other than that I guess I'm not sure why there are reports it doesn't work. However if someone has specifics I'd be more than happy to test them with our systems to try either verifying or disproving.
               
               

               
            

Legacy_DM_Vecna

  • Hero Member
  • *****
  • Posts: 501
  • Karma: +0/-0
Undead player questions and scripting know how!
« Reply #14 on: August 07, 2013, 11:45:27 pm »


               Thayan, are you running Linux or windows nwnx_funncs?