Aller au contenu

Photo

Spell disruption by level - possible?


  • Veuillez vous connecter pour répondre
19 réponses à ce sujet

#1
Happycrow

Happycrow
  • Members
  • 612 messages
Hey folks...

I'm slowly preparing to create my first module, and one of the things I need to do is to set areas where divine casters can't reach their deities and are thus able to cast only first and second level spells.  (bear with on why this might have fun value, the adventure idea is unusual).

Are there functions which can set it so that either all divine casters can only do lvl2 and below, or that would be deity-selective in such areas?  I can follow a script (usually, slowly and painstakingly), but am not a good coder myself.

#2
kevL

kevL
  • Members
  • 4 061 messages
yes, am sure this is possible through spellhooking

It's not hard as far as scripting goes but def. painstaking

#3
Happycrow

Happycrow
  • Members
  • 612 messages
Spellhooking? As in, by spell?

OW. It'd be easier to go back and make custom classes instead... thanks, kevL.

#4
Dann-J

Dann-J
  • Members
  • 3 161 messages
You could quickly reduce party members' wisdom scores to 12 when they enter the area, and prevent them from being able to rest while there. A temporary effect that reduces WIS for only a second would probably not even be noticed by the player. However their level 3 and above memorised spells would be kaput. Arcane spell casters wouldn't be affected by a hit to their wisdom scores.

They'd still be able to cast divine spells from scrolls or wands though.

I had quells in Shaar Moan that blocked all divine spells if you got too close to them, but that was via a simple 100% spell failure effect.

Modifié par DannJ, 04 décembre 2013 - 10:42 .


#5
Happycrow

Happycrow
  • Members
  • 612 messages
I remember those quells. :)

I'll take a look at how to do the on-enter scripting, then.

#6
kevL

kevL
  • Members
  • 4 061 messages
I just want to put this out here for anyone considering the basic procedure:

void main()
{
    if (GetLastSpellCastClass() == CLASS_TYPE_CLERIC
        && GetSpellLevel(GetSpellId()) > 2)
    {
        SetLocalInt(OBJECT_SELF, "X2_L_BLOCK_LAST_SPELL", TRUE);
    }
}


the devil is ofc in the details

#7
Dann-J

Dann-J
  • Members
  • 3 161 messages
Spell-hooking would be the elegant way to do it - but it requires learning all about spell-hooking first. Which is well worth it, by the way, since it opens up a whole slew of new modding possibilities. It might not be something you'd want to tackle if you aren't a confident scripter to begin with though.

Reducing WIS to12 for a second in an OnClientEnter script would be the quick-and-dirty method - easier to script, but less elegant in its execution.

#8
kevL

kevL
  • Members
  • 4 061 messages
yeh, but i'd get p.o'd having to redo my spells, right?

:\\


i'm thinking the SpellFailure is the method to go...

edit, it seems they all have their problems:

- spellhooking gets complicated
- wis reduction meta-screws the player
- spellfailure doesn't distinguish level of spell on its own..

Modifié par kevL, 05 décembre 2013 - 04:58 .


#9
Surango

Surango
  • Members
  • 307 messages
Nevermind me. Tried to make it more complicated than it needed to be.

Modifié par Surango, 05 décembre 2013 - 02:30 .


#10
Dann-J

Dann-J
  • Members
  • 3 161 messages

kevL wrote...

yeh, but i'd get p.o'd having to redo my spells, right?


Spell-hooking doesn't require any modifications to existing spell scripts. It's a separate script that runs before any spell that can stop the spell script from firing.  Usually that allows you to run a different script to replace it, but it could also be used to simply stop the spell without a replacement.

The downside to spell-hooking is that the player still goes through the casting animation and plays the FXs, and for spells with projectile animations you still get the travelling and impact effects as well. You just don't get the end result (spellus interuptus). That's because the spell script (and therefore the spell-hooking script) doesn't fire until the spell hits it's target. All the other animations and FX before that point are handled by spells.2da, rather than the spell script itself.

I've used spell-hooking to simulate a wild magic area. I wasn't happy with spell failure via spell-hooking because all the FX kept playing, so I decided to apply 25% spell failure to players in the area. That way one out of every four spells failed completely without any animations or effects, with the remaining 3/4 being split between normal casting, casting with a backlash, and spell warping.

#11
Tchos

Tchos
  • Members
  • 5 054 messages

DannJ wrote...
The downside to spell-hooking is that the player still goes through the casting animation and plays the FXs, and for spells with projectile animations you still get the travelling and impact effects as well. You just don't get the end result (spellus interuptus). That's because the spell script (and therefore the spell-hooking script) doesn't fire until the spell hits its target.

That's the worst part, and the biggest stumbling block for me to use spell hooking.  Is there no better method that can stop everything before it begins?

#12
kevL

kevL
  • Members
  • 4 061 messages
was saying that, as a *player* by reducing Wis to 12, I'd have to redo my spellbook (if i had spells above level 2 or whatever).


here's what i came up with, btw:


// 'spellhook_test'


// Returns TRUE if the spell cast is a divine spell
int GetIsDivineSpell(int iSpellID);


void main()
{
    SendMessageToPC(
            GetFirstPC(FALSE),
            "run ( spellhook_test ) " + GetName(OBJECT_SELF));

    // quick out, allow item usage.
    if (GetIsObjectValid(GetSpellCastItem())) return;


    string sDeity = GetDeity(OBJECT_SELF);
    SendMessageToPC(
            GetFirstPC(FALSE),
            ". deity = " + sDeity);

    // quick out, for Deity's favor.
    if (sDeity == "ILikeTurtles"
            || sDeity == "DoTheTimeWarp"
            || sDeity == "FunkyChickenChipoteSauce") return;


    int iClass = GetLastSpellCastClass();
    int bDivineCaster =
              (iClass == CLASS_TYPE_CLERIC
            || iClass == CLASS_TYPE_PALADIN
            || iClass == CLASS_TYPE_DRUID
            || iClass == CLASS_TYPE_RANGER);
    // quick out, not a Divine caster.
//    if (!bDivineCaster) return;
        // that needs to be joined with !bDivineSpell below;
        // polymorphed characters cast as their 1st class-slot type,
        // which might not be a divine caster class.

    int iSpellID = GetSpellId();
    int bDivineSpell = GetIsDivineSpell(iSpellID);

    // early out, not a Divine caster or spell.
    if (!bDivineCaster && !bDivineSpell) return;
        // note that it's possible for a polomorphed character
        // whose 1st class-slot isn't Divine_caster type,
        // when casting a Domain spell that's not a Divine spell,
        // to get away with it.

    // okay, finally, let's do this:
    int iSpellLevel = GetSpellLevel(iSpellID);
    int iSpellLevelCap = 2;

    if (iSpellLevel > iSpellLevelCap)
    {
        SetLocalInt(OBJECT_SELF, "X2_L_BLOCK_LAST_SPELL", TRUE);
    }
}



// based on: The Amethyst Dragon
// - http://social.bioware.com/forum/1/topic/192/index/17004145#17004208
//
// Returns TRUE if the spell cast is a divine spell
// iSpellID = line number of the spell in spells.2da, use GetSpellId()
// Note, this does not return whether a spell is exclusively divine;
// some spells are both Arcane and Divine. This does not distinguish:
int GetIsDivineSpell(int iSpellID)
{
    string sClass;
    int i;

    for (i = 0; i < 4; i++)
    {
        if (i == 0)
        {
            // 0th level divine spells:
            if (iSpellID == SPELL_CURE_MINOR_WOUNDS
                    || iSpellID == SPELL_INFLICT_MINOR_WOUNDS
                    || iSpellID == SPELL_LIGHT
                    || iSpellID == SPELL_RESISTANCE
                    || iSpellID == SPELL_VIRTUE)
            {
                return TRUE;
            }

            sClass = "Cleric";
        }
        else if (i == 1)
        {
            // 0th level divine spells:
            if (iSpellID == SPELL_CURE_MINOR_WOUNDS
                    || iSpellID == SPELL_LIGHT
                    || iSpellID == SPELL_RESISTANCE
                    || iSpellID == SPELL_VIRTUE
                    || iSpellID == SPELL_FLARE)
            {
                return TRUE;
            }

            sClass = "Druid";
        }
        else if (i == 2) sClass = "Paladin";
        else if (i == 3) sClass = "Ranger";

        string sLevel = Get2DAString("spells", sClass, iSpellID);
        int iLevel = StringToInt(sLevel);
        if (iLevel)
        {
            return TRUE;
        }
    }

    return FALSE;
}


yes, the initial animations play from Spells.2da but i notice that a final sound is omitted, and ofc the "spell applied" icon doesn't appear over the recipient's head. It seems appropriate in this case because the OP isn't talking about absolute spell failure ( no Weave at all active in the area ), it seems to me

#13
Happycrow

Happycrow
  • Members
  • 612 messages
Yeah, not looking to hurt arcane casters so much, but to make divine spellcasting iffy, problematic, and in very certain cases, overwhelmingly special.

I don't actually understand that script or where to put it, but I'll print the puppy out and start parsing it this weekend until I get what's going on. Thanks!

#14
kevL

kevL
  • Members
  • 4 061 messages
/at yer leisure


Nwn wiki Spellhook <- browse

here's the essentials

- in the module Properties, set a string variable "X2_S_UD_SPELLSCRIPT" with the name of your spellhook script.
- on each **area** properties, set an int variable "X2_L_WILD_MAGIC" to 1, if you want the hook to affect more than just the main PC.


note: on that webpage, to stop a spell from casting, it says to call
SetModuleOverrideSpellScriptFinished();
- it is exactly the same as this (above):
SetLocalInt(OBJECT_SELF, "X2_L_BLOCK_LAST_SPELL", TRUE);

( hope i got that right )

Modifié par kevL, 06 décembre 2013 - 04:31 .


#15
Morbane

Morbane
  • Members
  • 1 883 messages

kevL wrote...

yeh, but i'd get p.o'd having to redo my spells, right?


pre-owned metapreppa rod anyone?

going cheap

just add spell book memory

if it doesnt already exist

;)

Modifié par Morbane, 06 décembre 2013 - 03:20 .


#16
kevL

kevL
  • Members
  • 4 061 messages

Morbane wrote...

if it doesnt already exist

;)

nop. no spellbook mem

#17
Dann-J

Dann-J
  • Members
  • 3 161 messages
I've got a script function that takes a snapshot of spells available so it can restore them later. I designed it for sorcerors and bards, since the overland map in my current module automatically equips a 'riding cloak' if you've got one, which potentially displaces a nymph cloak (which can repeatedly depricate sorceror/bard spells).

It restores all spells via the rest function, then depricates some of them until their number of castings matches the stored snapshot. The downside is that they get fully healed as well. Although if you've just put your divine casters through hell, that's the least you can do to make it up to them.

#18
Happycrow

Happycrow
  • Members
  • 612 messages
lol.

Yeah, if I can get this off the ground (it's probably over-ambitious for a first module and then some), Everybody gets to go through hell.

Haven't really been able to crack the script above yet, we were caught in the big ice storm in TX and only got electricity/heat back yesterday. IF I'm reading that right at a cursory glance and spell use can be left untouched in a given area by deity that would be point-perfect (allowing for "holy places" where they're WAY stronger), but I'm a bit behind the conversation here and THEN some atm.

#19
kevL

kevL
  • Members
  • 4 061 messages

Happycrow wrote...

if ... spell use can be left untouched in a given area by deity

interesting.

just put a string_var on the area's properties, "DEITY" with the string_value of the favored deity. (don't forget you'll probly also want the "X2_L_WILD_MAGIC" int_var TRUE here also, so more than only the PC is affected by the hook) Then, instead of these lines


string sDeity = GetDeity(OBJECT_SELF);
// quick out, for Deity's favor.
if (sDeity == "ILikeTurtles"
|| sDeity == "DoTheTimeWarp"
|| sDeity == "FunkyChickenChipoteSauce") return;


have these:

string sDeity = GetDeity(OBJECT_SELF);
string sDeity_area = GetLocalString(GetArea(OBJECT_SELF), "DEITY");
if (sDeity == sDeity_area) return;


note i removed the smidge of debug code, which you can leave in until things are working well enough.

#20
Happycrow

Happycrow
  • Members
  • 612 messages
NEAT.
Thanks, if I can pull this off it should be pretty darned cool.