Author Topic: Are there any simple tutorials for how to modify spells, feats, and abilities for a PW?  (Read 567 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               I play on a PW that already has a number of these customizations with out requiring players to use a HAK. Unfortunately our current dev is working crazy hours, so has not had time to comtinue this work from numerous previous generations of Devs. I am considering picking up the torch, and am wondering what is involved in doing this, how easy is it to do for a novice, and if there are any simple tutorials and tools for how to do this?
               
               

               


                     Modifié par Lazarus Magni, 28 mars 2011 - 11:08 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0


               Well first there are three ways how to modify spells:

1) find the spell script (see NWN wiki) and modify the spell behavior in it thats usefull for specific changes like that spell is not capped at lvl 20

2) spellhook, this will allow you to disable casting of the spell in certain area or lets say stacking AOEs or change the actual cast spell (wild magic etc.)

3) global changes in spells
this is the best way to make changes, but also most harder.
There is several ways how to make certain changes, you can modify some spells functions in include files like MySavingThrow or spellsIsTarget, but that won't allow you much. The way to do almost anything global is called "core function hook" see HERE.

And also Community Patch 1.70 allows to do this and more easily via changing the 70_inc_spells library. Because there is whole new spell engine in community patch and all spells are rewritten onto it, its possible to modify some basic spell informations like: caster level, DC or metamagic there.

Still both solutions needs to recompile all spell scripts after you make a change in any include file. To do this you need THIS. The Community Patch 1.70 has its own version in zip archive for builders.


I can show you examples with the community patch spell engine if you would consider this route (there are also spellscripts fixes in it). If you want to try the core function hook (which is needed if you would want to change other global things like: area of effect distance, spell damage  type, etc.) tell me if you wouldn't understand it from my explanation in that document.
               
               

               


                     Modifié par ShaDoOoW, 28 mars 2011 - 11:40 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               Thanks for the response Shadow. I see that I can modify certain parameters for spells by either editing the 2da, or modifying the script in the toolset, so I think that may cover anything I might attempt with spells.

As to feats and abilities though, can any one provide me some information on this? Like say if I wanted to give the AA death arrow 3 uses per day instead of one, or alter the DD defensive stance to do something more usefull for a medium/high item magic world, like say perhaps have it double the DD DR, or give regen and SR or something (just random ideas, I would have to put more thought into it), does anyone know how to do that with out requiring a HAK? I see in the 2da I can modify certain things like requirements, but nothing along those lines. I know it can be done too, as we already have a number of these types of server side customizations.
               
               

               


                     Modifié par Lazarus Magni, 29 mars 2011 - 06:56 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0


               

Lazarus Magni wrote...

Thanks for the response Shadow. I see that I can modify certain parameters for spells by either editing the 2da, or modifying the script in the toolset, so I think that may cover anything I might attempt with spells.

Yea I forgot about fact that you can change some spell related informations in 2da like which class can cast it on what level.

Though you already figured it, there is a good explanations of the fields in spells.2da - http://nwn.wikia.com/wiki/Spells.2da

But not all collumns are server-side, for example if you change targettype players wont be able to cast the spell at all.

As to feats and abilities though, can any one provide me some
information on this? Like say if I wanted to give the AA death arrow 3
uses per day instead of one


that could be done either via feat.2da and USESPERDAY collumn - see more here http://nwn.wikia.com/wiki/Feat.2da

or via feat script, you know feats that are not automatic actually triggers special non-player-castable spell which got script again, you can find the spellscript reference on wiki again. For Arrow of Death it is
X1_S2_DeathArrow.nss. So you could add there a code that increment feat use to 1 again unless it have been increased 3 times this rest already. etc.

or alter the DD defensive stance to do
something more usefull for a medium/high item magic world, like say
perhaps have it double the DD DR, or give regen and SR or something
(just random ideas, I would have to put more thought into it), does
anyone know how to do that with out requiring a HAK? I see in the 2da I
can modify certain things like requirements, but nothing along those
lines. I know it can be done too, as we already have a number of these
types of server side customizations.

bugged DD stance is special case, its hardcoded and there are only two ways how to alter is, one is using hak and creating a replacement for it and second is NWNX and some linux plugin.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               Is there a list somewhere as to which columns in the 2dAs are server side?

Also is NWNX and the linux plugin the same thing needed to alter dev crit to say an increased multiplier? If so then I believe the servers to have that, since we already have that in place.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0


               

Lazarus Magni wrote...

Is there a list somewhere as to which columns in the 2dAs are server side?

Not really I tried to point out my knowledge here: http://social.biowar...-4407114-1.html


Also is NWNX and the linux plugin the same thing needed to alter dev crit to say an increased multiplier? If so then I believe the servers to have that, since we already have that in place.

That means you got nwnx_funcs, you need nwnx_events and UseFeat event. Since you got the NWNX installed it won't be problem to add this plugin, but even with that Im not totally sure this can "catch" the defensive stance being activated, cos im windows user.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               Hmm.. I will have to look into it. Thank you Shadow for the info, I appreciate it.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               I am still interested in modifying a few feats like defensive stance, and ki critical (amoungst others)... has anyone made any progress on editing these type of feats like the nwnx_functions modification of dev crit? (speaking of which can anyone point me to a readme on how this works, it looks like it is installed on my module, however the original dev crit is still functioning....) Any input would very much be appreciated.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0


               Defensive Stance: x2_s2_defstance
Ki Crit has to be done in the engine, I THINK - can't check easily atm.
Most feats, spells, items, etc, can be hooked with nwnx_events. Here's our events script by way of comparison. We use it for all sorts of things - binding SIMTools commands to voicechats, instant-use items, fast actions/spells, and custom feats and skills:

//::////////////////////////////////////////////////////////////////////////:://
//:: SIMTools V3.0 Speech Integration & Management Tools Version 3.0        :://
//:: Created By: FunkySwerve                                                :://
//:: Created On: April 4 2006                                               :://
//:: Last Updated: March 27 2007                                            :://
//:: With Thanks To:                                                        :://
//:: Dumbo - for his amazing plugin                                         :://
//:: Virusman - for Linux versions, and for the reset plugin, and for       :://
//::    his excellent events plugin, without which this update would not    :://
//::    be possible                                                         :://
//:: Dazzle - for his script samples                                        :://
//:: Butch - for the emote wand scripts                                     :://
//:: The DMFI project - for the languages conversions and many of the emotes:://
//:: Lanessar and the players of the Myth Drannor PW - for the new languages:://
//:: The players and DMs of Higher Ground for their input and playtesting   :://
//::////////////////////////////////////////////////////////////////////////:://
//This script is only used by Linux users, to tell what conversation node was selected in the popup menus.
//The other events shown will work with the Linux version but are commented out

//#include "aps_include"
//#include "nwnx_events"

#include "hg_inc"

#include "fky_chat_instant"


void main() {
    int nEventType = GetEventType();
    int nSubType;
    string sCommand;
    location lTarget;
    object oTarget, oItem;

    switch (nEventType) {
        case EVENT_TYPE_CAST_SPELL:
            SetActionMode(OBJECT_SELF, ACTION_MODE_COUNTERSPELL, FALSE);

            nSubType = GetEventSubType();

            // 0x08000000 = already an instant spell; 0x03000000 = last legit class slot
            if (GetIsPC(OBJECT_SELF) && !(nSubType & 0x08000000) && (nSubType & 0x07000000) < 0x03000000) {
                switch (nSubType & 0xFFFF) {
                    case SPELL_TRUE_STRIKE:     /* don't let Nightblades cast True Strike swiftly when they go in */

                    case SPELL_LESSER_RESTORATION:
                    case SPELL_RESTORATION:
                    case HGSPELL_CRITICAL_STRIKE:
                    case HGSPELL_DOLOROUS_BLOW:
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                    case SPELL_HOLD_PERSON:
                        if (GetclassByPosition(((nSubType >> 24) & 0x7) + 1, OBJECT_SELF) != class_TYPE_CLERIC)
                            break;
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                    case HGSPELL_VOCALIZE:
                        if (1 || GetclassByPosition(((nSubType >> 24) & 0x7) + 1, OBJECT_SELF) != class_TYPE_WIZARD)
                            break;
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                }
            }
            break;

        case EVENT_TYPE_USE_ITEM:
            oItem = GetEventItem();

            if (GetLocalInt(oItem, "FKY_CHAT_INSTANT")) {
                oTarget = GetEventTarget();
                if (GetObjectType(oTarget) == OBJECT_TYPE_TRIGGER)
                    lTarget = GetLocation(OBJECT_SELF);
                else
                    lTarget = Location(GetArea(OBJECT_SELF), GetEventPosition(), GetFacing(OBJECT_SELF));

                if (DoInstantUse(OBJECT_SELF, oItem, oTarget, lTarget))
                    BypassEvent();
            }
            break;

        case EVENT_TYPE_USE_FEAT:
            nSubType = GetEventSubType();

            if (nSubType == FEAT_STUNNING_FIST && GetLLControlclass(OBJECT_SELF) == class_TYPE_MONK) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_stunningfist", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_QUIVERING_PALM) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_quiveringpalm", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_CALLED_SHOT                   &&
                GetLevelByclass(class_TYPE_RANGER, OBJECT_SELF) >= 35 &&
                GetHasFeat(FEAT_EPIC_BANE_OF_ENEMIES, OBJECT_SELF)) {

                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_calledshot", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_DISARM || nSubType == FEAT_IMPROVED_DISARM) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_disarm", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_KNOCKDOWN || nSubType == FEAT_IMPROVED_KNOCKDOWN) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_knockdown", OBJECT_SELF));
                BypassEvent();
            } else if (FindSubString(" 304 305 335 336 337 338 339 340 341 342 872 873 898 900 901 902 903 1060 1061 ", " " + IntToString(nSubType) + " ") >= 0) {
                if (GetHasEffectOfType(EFFECT_TYPE_POLYMORPH, OBJECT_SELF)) {
                    FloatingTextStringOnCreature("You cannot change shape while already polymorphed!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
            }

            break;

        case EVENT_TYPE_USE_SKILL:
            nSubType = GetEventSubType();

            if (nSubType == SKILL_TAUNT) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_taunt", OBJECT_SELF));
                BypassEvent();
            }
            break;

        case EVENT_TYPE_TOGGLE_MODE:
            nSubType = GetEventSubType();

            if (nSubType == ACTION_MODE_COUNTERSPELL) {
                if (GetIsObjectValid(GetAttackTarget(OBJECT_SELF)))
                    ClearAllActions(TRUE);
                RemoveEffectsOfType(EFFECT_TYPE_ETHEREAL, OBJECT_SELF);
            }

            break;

        case EVENT_TYPE_PICKPOCKET:
            oTarget = GetEventTarget();

            if (GetIsPC(OBJECT_SELF) && GetIsPC(oTarget)) {
                if (GetLocalInt(GetArea(OBJECT_SELF), "nopp")) {
                    FloatingTextStringOnCreature("You cannot pickpocket other players!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
                if (abs(GetHitDice(oTarget) - GetHitDice(OBJECT_SELF)) > 6) {
                    FloatingTextStringOnCreature("You cannot pickpocket players more than 6 levels above or below you!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
                if (GetIsHardcore(OBJECT_SELF) || GetIsHardcore(oTarget)) {
                    FloatingTextStringOnCreature("Hardcore players cannot pickpocket or be pickpocketed by other players!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
            }
            RemoveEffectsOfType(EFFECT_TYPE_ETHEREAL, OBJECT_SELF);
            break;

        case EVENT_TYPE_QUICKCHAT:
            nSubType = GetEventSubType();
            sCommand = GetLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));

            if (GetLocalString(OBJECT_SELF, "VoiceBind_Save") != "") {
                sCommand = GetLocalString(OBJECT_SELF, "VoiceBind_Save");
                DeleteLocalString(OBJECT_SELF, "VoiceBind_Save");

                if (nSubType >= 100                                                          ||
                    (nSubType >= VOICE_CHAT_ENEMIES  && nSubType <= VOICE_CHAT_FLEE)         ||
                    (nSubType >= VOICE_CHAT_LOOKHERE && nSubType <= VOICE_CHAT_TASKCOMPLETE) ||
                    (nSubType >= VOICE_CHAT_TALKTOME && nSubType <= VOICE_CHAT_BADIDEA)) {
                    if (GetStringLowerCase(sCommand) == "clear") {
                        DeleteLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));
                        DeletePersistentVariable(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));

                        FloatingTextStringOnCreature(COLOR_GREEN + "Voice chat cleared!", OBJECT_SELF, FALSE);
                    } else {
                        SetLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType), sCommand);
                        SetPersistentString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType), sCommand);

                        FloatingTextStringOnCreature(COLOR_GREEN + "Voice chat bound!", OBJECT_SELF, FALSE);
                    }
                } else
                    FloatingTextStringOnCreature(COLOR_RED + "You cannot bind that voice chat!", OBJECT_SELF, FALSE);

                BypassEvent();
            } else if (sCommand != "" || (nSubType >= 100 && nSubType <= 110)) {
                if (sCommand == "") {
                    switch (nSubType) {
                        case 100: sCommand = "!autocast";                    break;
                        case 101: sCommand = "!list imm";                    break;
                        case 102: sCommand = "!effects";                     break;
                        case 103: sCommand = "!who inparty class";           break;
                        case 104: sCommand = "!effects eq";                  break;
                        case 105: sCommand = "!list servers";                break;
                        case 107: sCommand = "!who player class group=area"; break;
                        case 108: sCommand = "!list voicebinds";             break;
                        case 109: sCommand = "!render";                      break;
                        case 110: sCommand = "!stuck";                       break;
                        default:  sCommand = "!time";                        break;
                    }
                }

                if (GetStringLeft(sCommand, 8) == "!target ") {
                    sCommand = GetSubString(sCommand, 8, 255);
                    DeleteLocalObject(OBJECT_SELF, "FKY_CHAT_TARGET");
                } else {
                    SetLocalObject(OBJECT_SELF, "FKY_CHAT_TARGET", OBJECT_SELF);
                    SetLocalInt(OBJECT_SELF, "FKY_CHAT_TARGET_CLEANUP", 1);
                }

                AssignCommand(OBJECT_SELF, SpeakString(sCommand, TALKVOLUME_WHISPER));
                BypassEvent();
            }
            break;
    }
}

Funky
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               For some reason when I had the nwnx_events plugin installed it seemed to be crashing the server (or the mod) every time a player encountered a spawn... Is there something with a misconfiguration of this that could have caused this. Also could this be the reason why dev crit is now back to it's out of the box version?