Author Topic: Custom feats and skill bonuses  (Read 336 times)

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Custom feats and skill bonuses
« on: August 08, 2011, 05:03:22 pm »


               How do you create a custom feat which gives a racial bonus to a skill? Is this possible? (I can think of a way of scripting an instant effect that benefits a skill but am hoping there is another way)

Next is it also possible to create such a feat which only benefits the player against certain opponents? For example, a bonus to spot that only works against reptilians.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Custom feats and skill bonuses
« Reply #1 on: August 08, 2011, 05:21:52 pm »


               Depends on what you mean by possible, and how picky you are about implementation. You can do this in vanilla NWN by simply adding a feat to the feats 2da, and then putting code ingame that checks for the feat and applies a bonus if it's found. You'll have to reapply bonuses like that every time a player is raised/rezzed, though, so you'll need an 'on resurrection' script that you fire any time a player is raised, a sort of pseudoevent - I'll post our subraces include and 'death process' script for you.

If, however, you want a bonus that stacks outside of the 50 skills cap, you would need engine hacks.

As for making skills only count against reptilians, you would need either script edits or some fairly extraordinary engine hacks to pull it off. If checked in a scriptable event, it's fairly easy - you would just NOT apply the feat to the character's base skill, and add it in where appropriate. With spot, though, there is no player perception event, so you would need hacks.

Here's some excerpts from our subrace include, to show you how some effects are applied on entry/death. You'll see that we use it for class bonuses as well, not just subraces, when appropriate.





int GetSubraceSR (object oPC=OBJECT_SELF) {
    int nSR = GetLocalInt(oPC, "SubraceSR");

    if (!nSR) {
        struct SubraceInfo sub = GetSubraceInfo(oPC);

        nSR = sub.sr;
        SetLocalInt(oPC, "SubraceSR", (nSR == 0 ? -1 : nSR));
    }

    if (nSR < -1)
        nSR = GetHitDiceIncludingLLs(oPC) - ((nSR + 2) * 5);
    if (nSR < 0)
        nSR = 0;

    int nLevel = GetLevelIncludingLLs(class_TYPE_DRAGONDISCIPLE, oPC);
    if (nLevel > 19 && GetLocalInt(oPC, "RDDLevel") >= 20) {
        nLevel = 20 + nLevel;

        if (nLevel > nSR)
            nSR = nLevel;
    }

    if (GetLLControlclass(oPC) == class_TYPE_MONK) {
        int nLevel = 10 + ((GetLevelIncludingLLs(class_TYPE_MONK, oPC) * 7) / 6);

        if (nLevel > nSR)
            nSR = nLevel;
    }

    nSR += GetKnowsFeatChain(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_1, oPC) * 2;

    return nSR;
}


/* Apply vulnerabilities which can be reduced by dragon's blood */
void ApplySubraceDamageVulnerabilities (object oPC, int nSubID) {
    int bBlood = GetLocalInt(oPC, "DragonBlood");
    int nDamType, nDamVuln = 0;

    switch (nSubID) {
        case SUBRACE_DRIDER:
            nDamType = DAMAGE_TYPE_FIRE;
            nDamVuln = (bBlood ? 10 : 50);
            break;

        case SUBRACE_DWARF_AZER:
            nDamType = DAMAGE_TYPE_COLD;
            nDamVuln = (bBlood ? 10 : 50);
            break;

        case SUBRACE_HALF_DRAGON_RED:
            nDamType = DAMAGE_TYPE_COLD;
            nDamVuln = (bBlood ? 25 : 150);
            break;

        case SUBRACE_HALF_DRAGON_BLUE:
            nDamType = DAMAGE_TYPE_ACID;
            nDamVuln = (bBlood ? 25 : 150);
            break;

        case SUBRACE_HALF_DRAGON_GREEN:
            nDamType = DAMAGE_TYPE_ELECTRICAL;
            nDamVuln = (bBlood ? 25 : 150);
            break;

        case SUBRACE_HALF_DRAGON_BLACK:
            nDamType = DAMAGE_TYPE_COLD;
            nDamVuln = (bBlood ? 25 : 150);
            break;

        case SUBRACE_HALF_DRAGON_WHITE:
            nDamType = DAMAGE_TYPE_FIRE;
            nDamVuln = (bBlood ? 25 : 150);
            break;

        case SUBRACE_TROLL:
            nDamType = DAMAGE_TYPE_ACID | DAMAGE_TYPE_FIRE;
            nDamVuln = (bBlood ? 20 : 75);
            break;
    }

    if (nDamVuln < 1)
        return;

    int i;
    effect eVuln;

    for (i = 0; i < 12; i++) {
        if (nDamType & (1 << i)) {
            eVuln = EffectDamageImmunityDecrease(1 << i, nDamVuln);
            eVuln = SupernaturalEffect(eVuln);

            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVuln, oPC);
        }
    }
}

void ApplySubraceSize (object oPC) {
    int nRDDType, nCurrentWings;
    int nSub = GetLocalInt(oPC, "SubraceID");
    if (GetLocalInt(oPC, "RDDLevel") >= 30  ||
        nSub == SUBRACE_TREANT              ||
        nSub == SUBRACE_HALF_CYCLOPS        ||
        nSub == SUBRACE_HALF_GIANT_CLOUD) {

        SetCreatureSize(oPC, CREATURE_SIZE_LARGE);
    }

    if ((nRDDType = GetLocalInt(oPC, "RDDType")) > 0 &&
        (nCurrentWings = GetCreatureWingType(oPC)) != 0) {
        int nWings = -1;

        switch (nRDDType) {
            case SUBRACE_HALF_DRAGON_BLACK: nWings = WING_MODEL_DRAGON_BLACK; break;
            case SUBRACE_HALF_DRAGON_BLUE:  nWings = WING_MODEL_DRAGON_BLUE;  break;
            case SUBRACE_HALF_DRAGON_GREEN: nWings = WING_MODEL_DRAGON_GREEN; break;
            case SUBRACE_HALF_DRAGON_RED:   nWings = WING_MODEL_DRAGON_RED;   break;
            case SUBRACE_HALF_DRAGON_WHITE: nWings = WING_MODEL_DRAGON_WHITE; break;
        }

        if (nCurrentWings != nWings &&
            (nCurrentWings == WING_MODEL_DRAGON_BLACK ||
             nCurrentWings == WING_MODEL_DRAGON_BLUE  ||
             nCurrentWings == WING_MODEL_DRAGON_GREEN ||
             nCurrentWings == WING_MODEL_DRAGON_RED   ||
             nCurrentWings == WING_MODEL_DRAGON_WHITE))
            DelayCommand(18.0, SetCreatureWingType(nWings, oPC));
    }
}

void ApplySubraceEffects (object oPC) {
    string sEffects = GetLocalString(oPC, "SubraceEffects");

    SetLocalInt(oPC, "sne_applied", 1);


    if (sEffects == "") {
        struct SubraceInfo sub = GetSubraceInfo(oPC, 2);

        if ((sub.id == SUBRACE_HALF_DRAGON_WHITE && GetQuasiclass(oPC) == QUASIclass_BLOODFIRE_MAGE) ||
            (sub.id == SUBRACE_HALF_DRAGON_GREEN && GetQuasiclass(oPC) == QUASIclass_DRAGONSTORM_MAGE))
            sEffects = "";
        else
            sEffects = sub.effects;

        SetLocalInt(oPC, "SubraceSR", (sub.sr == 0 ? -1 : sub.sr));
        SetLocalString(oPC, "SubraceEffects", (sEffects == "" ? "NONE" : sEffects));

        if (sub.moverate > 0)
            SetLocalInt(oPC, "SubraceMovementRate", sub.moverate);
        else
            SetLocalInt(oPC, "SubraceMovementRate", MOVEMENT_RATE_NORMAL);
    }


    int nRate = GetBaseMovementRate(oPC);

    if (nRate == MOVEMENT_RATE_NORMAL)
        SetMovementRate(oPC, MOVEMENT_RATE_PC);
    else
        SetMovementRate(oPC, nRate);


    if (sEffects == "NONE")
        sEffects = "";


    /* 21 Fighter needs at least 1% concealment to trigger their innate Parry conceal */
    if (GetLevelByclass(class_TYPE_FIGHTER, oPC) >= 21)
        sEffects += " 72,1";

    /* 15 Shadowdancer grants Imm: Blindness */
    if (GetLevelByclass(class_TYPE_SHADOWDANCER, oPC) >= 15)
        sEffects += " 15,7";

    /* 20 RDD and ET5 grant TS and Imm: Sneak Attack */
    if (GetLevelIncludingLLs(class_TYPE_DRAGONDISCIPLE, oPC) >= 20 &&
        GetLocalInt(oPC, "RDDLevel") >= 20)
        sEffects += " 64 15,30";

    /* 25 CoT grants True Seeing */
    int nLevel = GetLevelIncludingLLs(class_TYPE_DIVINECHAMPION, oPC);
    if (nLevel >= 25)
        sEffects += " 64";

    /* 45 CoT grants Imm: Stun/Daze/Charm/Confuse */
    if (nLevel >= 45)
        sEffects += " 15,12 15,14 15,16 15,18";


    /* Dwarven Defender grants (StrMod) natural AC in LLs, with RDD AC
     *   subtracted (minimum cap of +16)
     */
    int nControl = GetLLControlclass(oPC);
    int i, nPhysImm = 0;

    if (nControl == class_TYPE_DWARVENDEFENDER) {
        int nAC = GetAbilityModifier(ABILITY_STRENGTH, oPC);

        int nMax = 20 - (GetLevelByclass(class_TYPE_DRAGONDISCIPLE, oPC) / 3);
        if (nMax < 16)
            nMax = 16;

        sEffects += " 46," + IntToString(nAC > nMax ? nMax : nAC) + ",1";

    } else if (nControl == class_TYPE_MONK) {
        nPhysImm += (GetAbilityModifier(ABILITY_STRENGTH, oPC)/2);
    }

    /* Legendary Battle Hardening */
    for (i = 2514; i > 2510; i--) {
        if (GetHasFeat(i, oPC)) {
            nPhysImm += ((i-2510) * 5);
            break;
        }
    }

    if (nPhysImm > 0) {
        string sPhysImm = IntToString(nPhysImm);

        sEffects += " 44,1," + sPhysImm + " 44,2," + sPhysImm + " 44,4," + sPhysImm;
    }


    /* Legendary Skill Focus grants +20 to the selected skill */
    for (i = 0; i < 27; i++) {
        if (GetHasFeat(GetSkillLegendaryFocusFeat(i), oPC))
            sEffects += " 54," + IntToString(i) + ",20";
    }


    /* Legendary Battle Awareness grants Imm: Sneak Attack */
    if (GetHasFeat(HGFEAT_LEG_BATTLE_AWARENESS, oPC))
        sEffects += " 15,30";


    int nSR = GetSubraceSR(oPC);
    if (nSR > 0)
        sEffects += " 52," + IntToString(nSR);


    int nArtificial = GetLocalInt(oPC, "ArtificialLevel");
    if (nArtificial > 0) {
        int nACPenalty = 1 + ((GetLootable(oPC) - nArtificial) / 3);

        sEffects += " 47," + IntToString(nACPenalty) + ",0";
    }

    if (GetHasFeat(HGFEAT_PAR_INHERENT_BREATHING, oPC))
        sEffects += " 73," + IntToString(HGEFFECT_SURVIVAL_BREATHE_WATER) + " 73,437 44,32,20";//drown imm, cold 20%

    if (GetHasFeat(HGFEAT_PAR_INHERENT_LEVITATION, oPC))
        sEffects += " 73," + IntToString(HGEFFECT_SURVIVAL_LEVITATION) + " 44,128,20";

    if (GetHasFeat(HGFEAT_PAR_INHERENT_PASSWALL, oPC))
        sEffects += " 73," + IntToString(HGEFFECT_SURVIVAL_PASSWALL) + " 44,16,20";

    if (GetHasFeat(HGFEAT_PAR_INHERENT_FIREWALK, oPC))
        sEffects += " 73," + IntToString(HGEFFECT_SURVIVAL_FIREWALK) + " 44,256,20";

    /* chop off a leading space if there is one */
    if (GetStringLeft(sEffects, 1) == " ")
        sEffects = GetStringRight(sEffects, GetStringLength(sEffects) - 1);

    ApplyDynamicEffects(sEffects, oPC, -2, -1.0, SUBTYPE_SUPERNATURAL);
    ApplySubraceDamageVulnerabilities(oPC, GetLocalInt(oPC, "SubraceID"));

    /* Paragon Skills */
    string sSkills = GetLocalString(oPC, "ParagonSkills");//format "0_21 7_6 8_33"
    string sEffects2;
    if (sSkills != "") {
        struct SubString ss;
        ss.rest = sSkills;
        int nSkill, nScore, nPos;
        while (ss.rest != "") {
            ss = GetFirstSubString(ss.rest);
            nPos = FindSubString(ss.first, "_");
            nScore = StringToInt(GetStringRight(ss.first, GetStringLength(ss.first) - (nPos + 1)));
            nSkill = StringToInt(GetStringLeft(ss.first, nPos));
            sEffects2 += " 54," + IntToString(nSkill) + "," + IntToString(nScore);
        }
    }

    if (GetStringLeft(sEffects2, 1) == " ")
        sEffects2 = GetStringRight(sEffects2, GetStringLength(sEffects2) - 1);
    ApplyDynamicEffects(sEffects2, oPC, HGEFFECT_PARAGON_SKILL_BONUS, -1.0, SUBTYPE_SUPERNATURAL);


    /* Accursed Pariahs receive 5% regeneration 2x/round */
    if (GetIsQuasiclass(QUASIclass_ACCURSED_PARIAH, oPC))
        ApplyEffectToObject(DURATION_TYPE_PERMANENT,
            SupernaturalEffect(EffectRegenerate(GetMaxHitPoints(oPC) / 20, 3.0)), oPC);


    int nArtifact = GetLocalInt(oPC, "StatArtifactUsed");
    if (nArtifact)
        ApplyArtifactEffects(nArtifact, oPC);


    if (ApplyAccomplishmentBonuses(oPC) == HGSPELL_IMMUNITY_DAMAGE_BONUS_PRELL) {
        int nAdj = GetXPAdjustment(oPC, TRUE);

        if (nAdj != 0)
            SetLocalInt(oPC, "XPAdjustment", nAdj);
        else
            DeleteLocalInt(oPC, "XPAdjustment");
    }

    effect eSurv;
    int nMonkSurvival = GetLocalInt(oPC, "MonkSurvival");
    if (nMonkSurvival) {
        int nMS, nSurvImm;
        for (nMS = 1; nMS < 16; nMS *= 2) {
            if (nMS & nMonkSurvival) {
                nSurvImm = GetMonkSurvivalImmunity(nMS);
                if (!GetHasSpellImmunity(nSurvImm, oPC)) {
                    eSurv = SupernaturalEffect(EffectSpellImmunity(nSurvImm));
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSurv, oPC);
                }
            }
        }
    }
}

void CheckSubraceEffects (object oPC) {
    if (GetLocalInt(oPC, "sne_applied") > 0)
        return;

    object oCreator = GetLocalObject(GetModule(), "subcreator");
    AssignCommand(oCreator, ApplySubraceEffects(oPC));
}


void OnSubraceEnter (object oPC) {
    string sPath = GetLocalString(oPC, "BicFilePath");

    if (sPath == "") {
        sPath = GetBicFilePath(oPC);

        if (sPath != "") {
            SetLocalString(oPC, "BicFilePath", sPath);

            if (!GetCommandable(oPC))
                SetCommandable(TRUE, oPC);
        } else {
            ExportSingleCharacter(oPC);
            FloatingTextStringOnCreature("File System Error! Attempting to fix, please wait. " +
                "If you get this message more than 3 times in a row, please contact a DM.",
                oPC, FALSE);

            if (GetCommandable(oPC))
                SetCommandable(FALSE, oPC);
            DelayCommand(5.0f,
                FloatingTextStringOnCreature("Accents or other unusual symbols in character names " +
                    "prevent the server from locating your character for subrace and other edits.",
                    oPC, FALSE));

            /* if the bic hasn't updated yet, try again at an extended delay */
            DelayCommand(10.0f, OnSubraceEnter(oPC));
            return;
        }
    }

    DoHardCoreChange(oPC, sPath);
    ApplySubraceEdits(oPC);

    if (!GetLocalInt(oPC, "SubraceID"))
        GetSubraceInfo(oPC);

    ApplySubraceSize(oPC);
    CheckSubraceEffects(oPC);

    SetLocalInt(oPC, "XPAdjustment", GetXPAdjustment(oPC));
}

void OnSubraceLeave (object oPC) {
    string sScript = "";

    if (GetLootable(oPC) <= 1 && GetLocalInt(oPC, "SubraceID") < -1)
        sScript += "/Subrace = q!INVALID - TAG NEEDED!; ";

    if (sScript != "") {
        string sBic = GetLocalString(oPC, "BicFilePath");

        if (sBic != "") {
            WriteTimestampedLogEntry("LETO : " + sBic + " : " + sScript);
            LetoScript("%char= q!" + sBic + "!; " + sScript + "%char = '>'; close %char; ");
        }
    }
}

void OnSubraceLevelUp (object oPC) {
    int nAdj = GetXPAdjustment(oPC, TRUE);

    if (nAdj != 0)
        SetLocalInt(oPC, "XPAdjustment", nAdj);
    else
        DeleteLocalInt(oPC, "XPAdjustment");
}


int GetBaseRaceFavoredclass (object oPC=OBJECT_SELF) {
    switch (GetRacialType(oPC)) {
        case RACIAL_TYPE_DWARF:         return class_TYPE_FIGHTER;
        case RACIAL_TYPE_ELF:           return class_TYPE_WIZARD;
        case RACIAL_TYPE_GNOME:         return (GetLevelByclass(class_TYPE_BARD, oPC) > 0 ? class_TYPE_BARD : class_TYPE_WIZARD);
        case RACIAL_TYPE_HALFLING:      return class_TYPE_ROGUE;
        case RACIAL_TYPE_HALFORC:       return class_TYPE_BARBARIAN;
        case RACIAL_TYPE_HALFELF:
        case RACIAL_TYPE_HUMAN:         return class_TYPE_INVALID;

        case RACIAL_TYPE_ABERRATION:    return class_TYPE_ABERRATION;
        case RACIAL_TYPE_ANIMAL:        return class_TYPE_ANIMAL;
        case RACIAL_TYPE_BEAST:         return class_TYPE_BEAST;
        case RACIAL_TYPE_CONSTRUCT:     return class_TYPE_CONSTRUCT;
        case RACIAL_TYPE_DRAGON:        return class_TYPE_DRAGON;
        case RACIAL_TYPE_ELEMENTAL:     return class_TYPE_ELEMENTAL;
        case RACIAL_TYPE_FEY:           return class_TYPE_FEY;
        case RACIAL_TYPE_GIANT:         return class_TYPE_GIANT;
        case RACIAL_TYPE_MAGICAL_BEAST: return class_TYPE_MAGICAL_BEAST;
        case RACIAL_TYPE_OOZE:          return class_TYPE_OOZE;
        case RACIAL_TYPE_OUTSIDER:      return class_TYPE_OUTSIDER;
        case RACIAL_TYPE_SHAPECHANGER:  return class_TYPE_SHAPECHANGER;
        case RACIAL_TYPE_UNDEAD:        return class_TYPE_UNDEAD;
        case RACIAL_TYPE_VERMIN:        return class_TYPE_VERMIN;
    }

    return class_TYPE_COMMONER;
}

int GetIsBonusclass (int nclass, object oPC=OBJECT_SELF) {
    int nBonus = 0, nFavored = GetLocalInt(oPC, "SubraceFavored");

    if (nFavored & SUBRACE_FAVORED_BONUS) {
        if ((nFavored & SUBRACE_FAVORED_BONUS_1) && nclass == (nFavored & 0xFF) - 1)
            nBonus++;
        if ((nFavored & SUBRACE_FAVORED_BONUS_2) && nclass == ((nFavored >> 8) & 0xFF) - 1)
            nBonus++;
        if ((nFavored & SUBRACE_FAVORED_BONUS_3) && nclass == ((nFavored >> 16) & 0xFF) - 1)
            nBonus++;
    }

    return nBonus;
}

int GetIsFavoredclass (int nclass, object oPC=OBJECT_SELF, int bHighest=FALSE) {
    int nFavored = GetLocalInt(oPC, "SubraceFavored");

    if (nFavored == 0) {
        struct SubraceInfo sub = GetSubraceInfo(oPC);

        if ((nFavored = sub.favored) == 0)
            nFavored = -1;

        SetLocalInt(oPC, "SubraceFavored", nFavored);
    }

    /* if no favored class is set or if -1 was specified, use the base race's */
    if (nFavored < 0 || (nFavored & SUBRACE_FAVORED_BASE)) {
        int nBaseFavored = GetBaseRaceFavoredclass(oPC);

        /* if class_TYPE_INVALID was specified, any class can be favored */
        if (nBaseFavored == class_TYPE_INVALID && bHighest)
            return TRUE;

        if (nFavored < 0 || nclass == nBaseFavored)
            return (nclass == nBaseFavored);
    }


    /* 0xFFFFFF means all classes are always favored classes */
    if (nFavored == 0xFFFFFF)
        return TRUE;

    /* if SUBRACE_FAVORED_HIGHEST is set, the highest-level class is always favored */
    if (bHighest && (nFavored & SUBRACE_FAVORED_HIGHEST))
        return TRUE;


    /* The value of the subrace data is (bytewise) FABC, where F is the flags
     * byte, and A B and C are favored classes (in the form class constant + 1).
     *
     * If SUBRACE_FAVORED_GENDER is set, C applies to both genders, A applies to
     * female characters only, and B applies to male characters only.
     *
     * Otherwise, A B and C apply to all characters.
     */
    if (nFavored & SUBRACE_FAVORED_GENDER) {
        if (nclass == (nFavored & 0xFF) - 1)
            return TRUE;

        if (GetGender(oPC) == GENDER_FEMALE)
            return (nclass == ((nFavored >> 16) & 0xFF) - 1);
        else
            return (nclass == ((nFavored >> 8) & 0xFF) - 1);
    }

    return (nclass == (nFavored & 0xFF) - 1        ||
            nclass == ((nFavored >> 8) & 0xFF) - 1 ||
            nclass == ((nFavored >> 16) & 0xFF) - 1);
}


int GetXPAdjustment (object oPC, int bTemporary=FALSE) {
    int i, nclass, nLevel, nFav, nHighestclass, nHighestLevel = 0, nclasses = 0, nAdj = 0;

    /* first find their highest-level class */
    for (i = 1; i <= 3; i++) {
        nclass = GetclassByPosition(i, oPC);
        if (nclass < 0 || nclass > class_TYPE_WIZARD)
            continue;

        if ((nLevel = GetLevelByPosition(i, oPC)) > nHighestLevel) {
            nHighestclass = nclass;
            nHighestLevel = nLevel;
        }
    }

    nHighestLevel = 0;

    for (i = 1; i <= 3; i++) {
        if ((nclass = GetclassByPosition(i, oPC)) < 0 || nclass == class_TYPE_INVALID)
            continue;

        if ((nFav = GetIsFavoredclass(nclass, oPC, (nclass == nHighestclass)))) {
            if ((nFav = GetIsBonusclass(nclass, oPC)) > 0)
                nAdj += nFav * 10;
        } else if (nclass <= class_TYPE_WIZARD) {
            nclasses |= (1 << i);

            if ((nLevel = GetLevelByPosition(i, oPC)) > nHighestLevel)
                nHighestLevel = nLevel;
        }
    }

    for (i = 1; i <= 3; i++) {
        if (!(nclasses & (1 << i)))
            continue;

        if (GetLevelByPosition(i, oPC) < nHighestLevel - 1)
            nAdj -= 20;
    }

    if (bTemporary && GetHasSpellImmunity(HGSPELL_IMMUNITY_DAMAGE_BONUS_PRELL, oPC))
        nAdj += 5;

    if (nAdj < 0 && GetLocalInt(oPC, "NoXPPenalty"))
        return 0;

    return (nAdj > 30 ? 30 : (nAdj < -40 ? -40 : nAdj));
}

Funky
               
               

               


                     Modifié par FunkySwerve, 08 août 2011 - 04:25 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Custom feats and skill bonuses
« Reply #2 on: August 08, 2011, 05:31:37 pm »


               Here's the 'fky_deathprocess' script, called after every rez/raise event:


#include "hg_inc"

#include "subrace_inc"
#include "fky_chat_inc"

#include "ac_effect_inc"
#include "ac_itemprop_inc"
#include "ac_itemenh_inc"
#include "ac_cooldown_inc"

#include "hg_antiex_inc"
#include "hg_eqeffect_inc"
#include "hg_specabil_inc"

#include "legendarybab_inc"

#include "immoglow_inc"


void RestoreEffects (object oPC) {
    if (!GetIsObjectValid(oPC))
        return;

    if (!GetIsObjectValid(GetArea(oPC)) || GetPlotFlag(oPC)) {
        DelayCommand(1.0, RestoreEffects(oPC));
        return;
    }

    CheckSubraceEffects(oPC);
    CheckEquipmentEffectsAndProperties(oPC);
    CheckLegendaryBABEffect(oPC);
    CheckSpecialAbilities(oPC);

    ForceEffectRecalculation(oPC);
}


void main () {
    object oPC = OBJECT_SELF;
    object oItemToTake = GetItemPossessedBy(oPC, "death");


    AssignCommand(GenCreator(), UpdateImmortalGlow(oPC));

    if (GetLocalString(oPC, "FKY_CHAT_PASSWORD_IP") == "CHECK")
        AssignCommand(GenCreator(), ApplyPasswordHold(oPC));

    if (GetPCOption(oPC, PCOPTION_SHIFTERFIX) || GetLocalInt(oPC, "ShifterFix")) {
        /* cures the shifter bug */
        DeleteLocalInt(oPC, "ShifterFix");
        ApplyPolymorphEffect(DURATION_TYPE_TEMPORARY, EffectPolymorph(POLYMORPH_TYPE_NULL_HUMAN), oPC, 0.1);
    }


    /* recalculate movement rate */
    RecalculateMovementRate(oPC);

    /* clean up Sigil of Mystra effects tail */
    if (GetCreatureTailType(oPC) == TAIL_MODEL_VFX_RAYS_DESTRUCTION)
        SetCreatureTailType(TAIL_MODEL_VFX_TRACE_2_ODD, oPC);
    if (GetCreatureWingType(oPC) == 218)
        SetCreatureWingType(0, oPC);

    /* clean up Lifethreading effects tail/wings */
    if (GetCreatureTailType(oPC) == TAIL_MODEL_VFX_DEATH_SHIELD)
        SetCreatureTailType(0, oPC);
    if (GetCreatureWingType(oPC) == 215)
        SetCreatureWingType(0, oPC);
    DeleteLocalInt(oPC, "Lifethreading");


    RestoreEffects(oPC);
    RestartCooldownTimers(oPC, TRUE);

    /* turn off autorez prevention and direct damage death notice */
    DeleteLocalInt(oPC, "NoAutorez");
    DeleteLocalInt(oPC, "DirectDamageDeath");
    DeleteLocalInt(oPC, "Rez_Require_Level");

    /* turn off spontaneous metamagic and delete temporary caster levels */
    DeleteLocalInt(oPC, "MetaChannel");
    DeleteLocalInt(oPC, "TempCasterLevel_1");
    DeleteLocalInt(oPC, "TempCasterLevel_2");
    DeleteLocalInt(oPC, "TempCasterLevel_3");
    DeleteLocalInt(oPC, "TempSpellFocus_School");


    /* reactivate passwall/item-binding if necessary */
    int i;
    object oItem;
    for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
        oItem = GetItemInSlot(i, oPC);

        if (!GetIsObjectValid(oItem))
            continue;

        if (GetLocalInt(oItem, "Passwall")) {
            if (!GetHasEffectByCreator(oItem, oPC, HGEFFECT_SURVIVAL_PASSWALL)) {
                effect eEff = EffectSpellImmunity(HGEFFECT_SURVIVAL_PASSWALL);
                eEff = SupernaturalEffect(eEff);

                SetEffectSpellId(eEff, HGEFFECT_SURVIVAL_PASSWALL);
                SetEffectCreator(eEff, oItem);

                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oPC);
            }
        }

        if (GetLocalInt(oItem, "RestCharge") == -101) {
            int nSpellId = HGEFFECT_EQUIPMENT_BASE + i;

            if (!GetHasSpellEffect(nSpellId, oPC)) {
                effect eEff = SupernaturalEffect(EffectSpellImmunity(HGSPELL_UNUSED));
                SetEffectSpellId(eEff, nSpellId);
                SetEffectCreator(eEff, oItem);

                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oPC);
            }
        }
    }


    DestroyObject(oItemToTake);
}

Funky
               
               

               
            

Legacy_Alex Warren

  • Sr. Member
  • ****
  • Posts: 326
  • Karma: +0/-0
Custom feats and skill bonuses
« Reply #3 on: August 08, 2011, 06:18:20 pm »


               

henesua wrote...
Next is it also possible to create such a feat which only benefits the player against certain opponents? For example, a bonus to spot that only works against reptilians.


There is an engine function - VersusRacialTypeEffect() it should do what you want (It works in our Hide Form Animal Spell - the spell makes character invisible but only to animals)
               
               

               
            

Legacy_ShadowM

  • Hero Member
  • *****
  • Posts: 1373
  • Karma: +0/-0
Custom feats and skill bonuses
« Reply #4 on: August 08, 2011, 10:13:49 pm »


               You make the feat, then check for it on enter and then put it as an item property on the skin. You let them know this bonus is not exclude from the cap of 50. That how I would do it in basic nwn. But if you using nwnx_funcs you could mod the skill. Now against specific would depend on the skill and each of the ones above are a possibility.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Custom feats and skill bonuses
« Reply #5 on: August 09, 2011, 01:01:24 am »


               Thanks Funky et al. It seems clear that if I want special case bonuses to skills I need to catch those cases individually. I think i'll just skip the special case feat unless I want to apply these to the social skills and just handle them myself in each conversation. Its much easier to create a generic skill bonus, and refresh it when you need to.

I'm beginning to see why there is one big PRC project, and not a lot of independents just trying out custom classes and races on their own. You need to create a custom framework for these sorts of things which is a much bigger project than just editing some 2das, custom tlks, and writing a few feat/spell scripts.