I worked on something that may interest people here ...

Moderator: Event DM

Post Reply
User avatar
Korrigan
Prince of Bloated Discourse
Posts: 280
Joined: Sat Apr 12, 2003 4:21 pm
Location: Jester of the Fey Vivian, Lady of the Lake ...

I worked on something that may interest people here ...

Post by Korrigan » Fri Jun 06, 2003 1:42 pm

... so here it is :

Code: Select all

/*
    Custom object effects for NWN - Version 0.1 beta

    Made By KORRIGAN

    The script uses the tag of items with unique powers as a command line.
    SEE EXAMPLE BELOW FOR MORE HELP

    the tag format is following :

    FX_<type>_...parameters...

    - type : Actually, the type of effect can only be "DR", which applies a damage reduction effect on the PC.

    Then, the parameters are following :
    FX_DR_<dmg_type>_<amount>_<limit>_<duration>_<forbidden class 1>_<forbidden class 2>_ ...
    - dmg_type can be :
        Fi(FIRE),Co(COLD),Ac(ACID),El(ELECTRICAL),So(SONIC),Sl(SLASHING),Pi(PIERCING),Bl(BLUGEONING)
    - amount is the quantity of damage that will be negated.
    - limit is the quantity of damage that can be absobed before the protection fades. 0=infinite.
    - duration is the max duration in seconds the protection will last.
    - forbidden classes are the PC classes that CANNOT use the item.
      Even multiclassed PCs will no longer be able to take 1 level of a class just to use some items.
      Forbidden classes can be :
        Ba (Barbarian)
        Bd (Bard)
        Cl (Cleric)
        Dr (Druid)
        Fi (Fighter)
        Mo (Monk)
        Pa (Paladin)
        Ra (Ranger)
        Ro (Rogue)
        So (Sorcerer)
        Wi (Wizard)

    WHY THE HELL ARE YOU DOING THAT ???

    Permanent damage reduction items are totally overpowered in NWN.
    But if you remove them all, it makes spellcasters godlike compared to pure non spellcasters.
    I also wanted to introduce a system that allowed to avoid people taking 1 level of a class simply for the sake of using certain items.

    EXAMPLE :

    You want to make a damage reduction amulet that :
    - Is usable 3 times a day.
    - Negates 10 points of SLASHING damage.
    - Effect lasts 1 minute (real time).
    - No limitation to the damage absorbed.
    - Is usable only by classes that don't have Wizard, Cleric, Druid or Sorcerer levels.
    - Is usable only on self.

    1) Simply put this script in the onactivate script of your module.
    2) Create an amulet using the item wizard. Make it's only feature "Unique power self only 3 uses/day".
    3) Edit the tag of the amulet and make it :

    FX_DR_Sl_10_0_60_Wi_Cl_Dr_So

    FX = this is a custom effect
    DR = Damage Reduction
    Sl = Slashing
    10 = 10 damage is negated
    0  = unlimited damage is absorbed
    60 = lasts 60 seconds real time
    Wi = not usable by Wizards.
    Cl = not usable by Clerics.
    Dr = not usable by Druids.
    So = not usable by Sorcerers.

    You're done =)

    PS : Of course, you can set the usual usage restrictions using the regular way through the toolset.

*/

string ParseTag(string tag,int entry)
{
    string  result="";
    string  temp="";
    int     start=0;
    int     end=0;

    while (entry>0)
    {
        temp=GetSubString(tag,start,1);
        if (temp=="")
            return ""; // too far in the line, dumbass =P
        if (temp=="_")
        {
            entry--;
        }
        start++;
        if (entry==0)
            break;
    }

    end=start;
    do
    {
        end++;
        temp=GetSubString(tag,end,1);
    } while ((temp!="_") && (temp!=""));

    if (end>start+1)
    {
        result=GetSubString(tag,start,end-start);
    }

    return result;
}

int ParseTagInt(string tag,int entry)
{
    int     result=0;
    string  arg;

    arg=ParseTag(tag,entry);
    if (arg!="")
        result=StringToInt(arg);

    return result;
}

float ParseTagFloat(string tag,int entry)
{
    float   result=0.0;
    string  arg;

    arg=ParseTag(tag,entry);
    if (arg!="")
        result=StringToFloat(arg);

    return result;
}

// number is the first argument of the command starting the forbidden classes list

int IsClassForbidden(object activator, string tag, int number)
{
    string  arg;

    arg=ParseTag(tag,number);
    while (arg!="")
    {
        if (arg=="Ba")
        {
            if (GetLevelByClass(CLASS_TYPE_BARBARIAN,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Bd")
        {
            if (GetLevelByClass(CLASS_TYPE_BARD,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Cl")
        {
            if (GetLevelByClass(CLASS_TYPE_CLERIC,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Dr")
        {
            if (GetLevelByClass(CLASS_TYPE_DRUID,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Fi")
        {
            if (GetLevelByClass(CLASS_TYPE_FIGHTER,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Mo")
        {
            if (GetLevelByClass(CLASS_TYPE_MONK,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Pa")
        {
            if (GetLevelByClass(CLASS_TYPE_PALADIN,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Ra")
        {
            if (GetLevelByClass(CLASS_TYPE_RANGER,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Ro")
        {
            if (GetLevelByClass(CLASS_TYPE_ROGUE,activator)>0)
                return TRUE;
        }
        else
        if (arg=="So")
        {
            if (GetLevelByClass(CLASS_TYPE_SORCERER,activator)>0)
                return TRUE;
        }
        else
        if (arg=="Wi")
        {
            if (GetLevelByClass(CLASS_TYPE_WIZARD,activator)>0)
                return TRUE;
        }
        number++;
        arg=ParseTag(tag,number);
    }
    return FALSE;
}

void ApplyDamageReduction(object activator,string tag)
{

    if (IsClassForbidden(activator,tag,6))
    {
        SendMessageToPC(activator,"This effect cannot be used on this class");
    }
    else
    {
        int     type;
        string  arg;
        effect  effex;
        int     vfx1;
        int     vfx2;
        int     amount;
        int     limit;
        float   duration;
        arg=ParseTag(tag,2);
        if (arg=="Fi")
        {
            type=DAMAGE_TYPE_FIRE;
            vfx1=VFX_IMP_HEAD_FIRE;
            vfx2=VFX_DUR_PROTECTION_ELEMENTS;
        }
        if (arg=="Co")
        {
            type=DAMAGE_TYPE_COLD;
            vfx1=VFX_IMP_HEAD_COLD;
            vfx2=VFX_DUR_PROTECTION_ELEMENTS;
        }
        if (arg=="Ac")
        {
            type=DAMAGE_TYPE_ACID;
            vfx1=VFX_IMP_HEAD_ACID;
            vfx2=VFX_DUR_PROTECTION_ELEMENTS;
        }
        if (arg=="El")
        {
            type=DAMAGE_TYPE_ELECTRICAL;
            vfx1=VFX_IMP_HEAD_ELECTRICITY;
            vfx2=VFX_DUR_PROTECTION_ELEMENTS;
        }
        if (arg=="So")
        {
            type=DAMAGE_TYPE_SONIC;
            vfx1=VFX_IMP_HEAD_SONIC;
            vfx2=VFX_DUR_PROTECTION_ELEMENTS;
        }
        if (arg=="Pi")
        {
            type=DAMAGE_TYPE_PIERCING;
            vfx1=VFX_IMP_HEAD_ODD;
            vfx2=VFX_DUR_PROT_STONESKIN;
        }
        if (arg=="Sl")
        {
            type=DAMAGE_TYPE_SLASHING;
            vfx1=VFX_IMP_HEAD_ODD;
            vfx2=VFX_DUR_PROT_STONESKIN;
        }
        if (arg=="Bl")
        {
            type=DAMAGE_TYPE_BLUDGEONING;
            vfx1=VFX_IMP_HEAD_ODD;
            vfx2=VFX_DUR_PROT_STONESKIN;
        }
        amount=ParseTagInt(tag,3);
        limit=ParseTagInt(tag,4);
        duration=ParseTagFloat(tag,5);

        effex=EffectLinkEffects(
                EffectVisualEffect(vfx1,FALSE),
                EffectDamageResistance(type,amount,limit));
        effex=EffectLinkEffects(
                EffectVisualEffect(vfx2,FALSE),
                effex);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY,effex,activator,duration);
    }
}

void ApplyCustomEffect(object activator,string tag)
{
    if (ParseTag(tag,1)=="DR")
        ApplyDamageReduction(activator,tag);
}

void main()
{
    object item;
    object activator;
    string tag;
    item=GetItemActivated();
    activator=GetItemActivatedTarget();
    tag=GetTag(item);
    if (ParseTag(tag,0)=="FX")
    {
        ApplyCustomEffect(activator,tag);
        return;
    }
// ... do your usual itemactivation stuff here
}
User avatar
Korrigan
Prince of Bloated Discourse
Posts: 280
Joined: Sat Apr 12, 2003 4:21 pm
Location: Jester of the Fey Vivian, Lady of the Lake ...

Post by Korrigan » Fri Jun 06, 2003 2:21 pm

Made a demo module so you can better understand what it does exactly, and how it does it :

http://perso.wanadoo.fr/wildcopper/nwn/FXTest.zip

Better enter the module with a fresh level 1 char.
The module will automatically give you the xp for being level 2, as the test Rod of Slashing protection is level 2+.
The rod is also forbidden of use for wizards, sorcerers, clerics and druids, even multiclassed, so you can make some tests also.

This version was made in less than an hour, and there's much more to do.
- Allow several effects at once.
- Other FX, like spell resistance, ac increase, etc ...

Also important, the effects are NOT limited to fixed values like the NWN spells. You can make items that give any amount of any effect available in the game.

---

UPDATE changes I'm already working on :
- Add a "minimum level in a class" req. This will serve the same purpose as forbidden classes but will be more adaptable. E.g. Rod of Slashing Protection usable only by chars who have 10+ fighter levels. Should be something like "FiL10" for Fighter but only level 10+.
- Only allow one of the items to be used. Will forbid people to collect dozens of Rods of Slashing protections to have a full time effect. If one item was used but you own several if the same kind, only the already 'worn' object will be usable until it's uses per day are all burned. E.g. if you have two Rods, but you already have used one, only the already "started" rod will be usable unless you rest again.
User avatar
Korrigan
Prince of Bloated Discourse
Posts: 280
Joined: Sat Apr 12, 2003 4:21 pm
Location: Jester of the Fey Vivian, Lady of the Lake ...

Post by Korrigan » Sat Jun 07, 2003 9:35 am

UPDATE downloadable :
http://perso.wanadoo.fr/wildcopper/nwn/FXTest.zip

NEW :
- You can now define limitations on minimum and maximum levels in a given class. Read the comment at the start of the script in the example module for more info.

The example rod can only be used by chars with at least 2 fighter levels and no cleric levels. A new char will automatically be made level 3.
I added a few ennemies to help you test the effect too ...
User avatar
Korrigan
Prince of Bloated Discourse
Posts: 280
Joined: Sat Apr 12, 2003 4:21 pm
Location: Jester of the Fey Vivian, Lady of the Lake ...

Post by Korrigan » Sat Jun 07, 2003 10:00 am

New version uploaded at same location...
http://perso.wanadoo.fr/wildcopper/nwn/FXTest.zip

Corrected the problem that you could only have one good class.

Example : Now, PaM10_FiM08 will work for both level 10+ paladins and level 8+ fighters ...
User avatar
maxinion
Team Member; Retired with Honors
Posts: 2778
Joined: Mon Mar 17, 2003 7:44 pm
DM Avatar: Andrinor
Location: Bay Area, CA
Contact:

Post by maxinion » Sat Jun 07, 2003 3:27 pm

Nice work Korrigan. The String part was helpful to me... I had been trying to figure out how to parse strings. Good work!
Post Reply