Author Topic: A couple PW script related questions  (Read 658 times)

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
A couple PW script related questions
« on: April 18, 2013, 03:52:30 am »


               I've been a big advocate of tag-based scripting since it was implemented. However I've been doing some re-scripting in a test PW just trying to condense stuff. I decided to make 1 script for all placeable useable objects that just checks the tag and does that one part of the script for that object. That started me thinking about the old way of activating items by just sticking all the if (sTag == "blah blah") checks in one big OnActivate script. I'd like to get the opinion of people with PWs on whether the old or new "tag-based" method is less "computer resource" intesive etc. I'm thinking now just having less scripts would be the prefered method? I don't know. What do you guys prefer and why?

My second question has to do with the NESS spawn system. So for those who are using it or who have used it in the past, is it better to go with the area HB method or the OnEnter psuedo HB method?

Thanks in advance for any advice.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
A couple PW script related questions
« Reply #1 on: April 18, 2013, 06:51:06 am »


               

GhostOfGod wrote...

I've been a big advocate of tag-based scripting since it was implemented. However I've been doing some re-scripting in a test PW just trying to condense stuff. I decided to make 1 script for all placeable useable objects that just checks the tag and does that one part of the script for that object. That started me thinking about the old way of activating items by just sticking all the if (sTag == "blah blah") checks in one big OnActivate script. I'd like to get the opinion of people with PWs on whether the old or new "tag-based" method is less "computer resource" intesive etc. I'm thinking now just having less scripts would be the prefered method? I don't know. What do you guys prefer and why?

mostly I implement everything in the one script, but I do have ExecuteScript(GetTag()) enabled as well for special cases where the item has special handling for more than one event. If it is in one event only I dont bother with tag based scripting. After a while it becomes a bit harder to orientate in such script but thats a minor inconvinience.
               
               

               
            

Legacy_acomputerdood

  • Sr. Member
  • ****
  • Posts: 378
  • Karma: +0/-0
A couple PW script related questions
« Reply #2 on: April 18, 2013, 02:02:16 pm »


               

GhostOfGod wrote...

just sticking all the if (sTag == "blah blah") checks in one big OnActivate script



this is what i do.  i think it's easier to manage.  and it reduces the number of "resources" your module uses to stay under the whatever number that's the hard limit.

my OnActivate is 1800+ lines with about 20 other #includes.  it is semi-sorted based on what items i think are used most often and does returns after it executes the particular item's function.

that last part makes me feel a little better, but i can't imagine for a game as old as nwn that computational resources are even remotely a factor anymore.
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
A couple PW script related questions
« Reply #3 on: April 18, 2013, 03:30:21 pm »


               Ditto to this. For us the OnUsed and OnActivate events are all in one big script using either the sTag == "whatever" method or ExecuteScript calls.

We do also use NESS as well and do the OnEnter pseudo heartbeat. I have no Area heartbeat scripts at all based on feedback seen on the NWN scripting forums that basically boils down to 'don't use any heartbeat event unless there is any other way to do it'. Plus it seems to make more sense to me to only run the area (pseudo)heartbeat when a PC is actually in the area and it is needed.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
A couple PW script related questions
« Reply #4 on: April 18, 2013, 09:02:16 pm »


               Thanks for the feedback guys.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
A couple PW script related questions
« Reply #5 on: April 19, 2013, 05:01:33 am »


               

GhostOfGod wrote...

I've been a big advocate of tag-based scripting since it was implemented. However I've been doing some re-scripting in a test PW just trying to condense stuff. I decided to make 1 script for all placeable useable objects that just checks the tag and does that one part of the script for that object. That started me thinking about the old way of activating items by just sticking all the if (sTag == "blah blah") checks in one big OnActivate script. I'd like to get the opinion of people with PWs on whether the old or new "tag-based" method is less "computer resource" intesive etc. I'm thinking now just having less scripts would be the prefered method? I don't know. What do you guys prefer and why?

Some general remarks, first, which I will later contradict (food for thought, in other words):

Using tags is somewhat primitive - it only happened to begin with because you couldn't set locals in the toolset, at first. Use local variables, and save tags for GetByTag functions and other things of that nature - times when you need to indicate an instance varies in some way from its palette. I'm assuming locals are much faster than the string compares for tags, but that's not really the basis of my answer. The locals are designed to do precisely what you're using the tags for. You can change or add to them later without making a mess of things. Consider, for example, the first set of underwater areas I added to my mod, which required waterbreathing, had custom spellhooks, etc. I originally did a tag check, checking for a prefix. Of course, if I want another mod-wide subsystem like that, I can't use a prefix anymore, if I want to be able to have overlap. That's one reason we switched to an Area_Underwater variable - another being simple human readability.

All that being said, though, we use a combination tag-based system, only firing it for some events (most of our stuff is modwide). The one event we do use it for is onactivate. We break down activation scripts by area grouping (one for aboleths items, one for locathah, another for Mount Uroboros, etc). And yes, we use tag-based code for that. I would not attempt to consolidate ALL onactivates into one, as that kills most of the modularity that tag-based was intended to allow. A lot of it boils down into what makes your mod organized in a way you can understand it best.

We use prefixing of tags and resrefs to link them to an area, allowing us to find a given thing with relative speed, instead of paging through tens of thousands of lines of code in huge, unitary, and slower-to-run master scripts. If a script or palette item is prefixed aby_, I know it's related to our Abyss areas, while abo_ is aboleths, and so on. We also have a randuse script for our multi-area random loot with useable properties - again, it just depends on what makes sense to you.

Here's a sample script written this way - as you can see, it still has a lot of added functions and includes - another reason to go modular (avoiding cross-inclusion, even though Skywing's can handle circular includes, they're still a bit distasteful). Skip to the bottom to read the main() function first - the rest is irrelevant, other than to make the point about problems with unitary scripts:


#include "hg_inc"

#include "x2_inc_switches"

#include "ac_spell_inc"
#include "ac_dispel_inc"
#include "ac_itemreq_inc"

#include "inc_draw"

#include "fky_chat_inc"
#include "ac_cooldown_inc"

void ApplyTreeHealing (object oPC, object oTree, int nRounds) {
    if (nRounds < 1              ||
        !GetIsObjectValid(oPC)   ||
        !GetIsObjectValid(oTree) ||
        GetArea(oPC) != GetArea(oTree)) {

        SetPlotFlag(oTree, FALSE);
        DestroyObject(oTree);
        return;
    }

    DelayCommand(6.0, ApplyTreeHealing(oPC, oTree, nRounds - 1));

    location lTarget = GetLocation(oTree);
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget);

    effect eHeal = EffectLinkEffects(EffectVisualEffect(VFX_IMP_HEALING_S), EffectHeal(60));

    while (GetIsObjectValid(oTarget)) {
        if (GetFactionEqual(oTarget, oPC) || GetLocalInt(oTarget, "AllowHeal"))
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);

        oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lTarget);
    }
}

void ApplyDeath (object oTarget) {
    if (GetIsDead(oTarget)) {
        ApplyVisualAtLocation(VFX_IMP_DEATH_L, GetLocation(oTarget));
        return;
    }

    SetPlotFlag(oTarget, FALSE);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath()), oTarget);

    DelayCommand(0.1, ApplyDeath(oTarget));
}

void ApplyResurrection (object oTarget, object oPC) {
    if (!GetIsObjectValid(oTarget) || !GetIsDead(oTarget))
        return;

    effect eRez = EffectResurrection();
    effect eHeal = EffectHeal(GetMaxHitPoints(oTarget) + 10);

    SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_RESURRECTION, FALSE));

    ApplyEffectToObject(DURATION_TYPE_INSTANT, eRez, oTarget);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);
    ApplyVisualAtLocation(VFX_IMP_RAISE_DEAD, GetLocation(oTarget));
    SendMessageToParty(oTarget, C_MED_GREY + GetName(oPC) + " resurrects " + GetName(oTarget) + " : Potion of Life Unbound : *success*" + C_END);
    AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
}


void UseAccusingStatue (object oPC, object oItem) {
    location lTarget = GetLocation(oPC);

    DelayCommand(0.0, DrawSpring(DURATION_TYPE_INSTANT, VFX_IMP_HEAD_EVIL, lTarget,
        -3.0, 3.0, 0.0, 0.0, 0.0, 30, 0.0, 1.5,   0.0));
    DelayCommand(1.0, DrawSpring(DURATION_TYPE_INSTANT, VFX_IMP_HEAD_EVIL, lTarget,
        -3.0, 3.0, 0.0, 0.0, 0.0, 30, 0.0, 1.5, 180.0));

    ApplyVisualToObject(GAOVFX_IMP_REDUCE_ABILITY_SCORE_YELLOW, oPC);

    effect eLink = EffectImmunity(IMMUNITY_TYPE_CRITICAL_HIT);
    eLink = EffectLinkEffects(eLink, EffectDamageImmunityDecrease(DAMAGE_TYPE_BLUDGEONING, 30));
    eLink = EffectLinkEffects(eLink, EffectDamageImmunityDecrease(DAMAGE_TYPE_PIERCING, 30));
    eLink = EffectLinkEffects(eLink, EffectDamageImmunityDecrease(DAMAGE_TYPE_SLASHING, 30));
    eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_IOUNSTONE_YELLOW));
    eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE));
    eLink = ExtraordinaryEffect(eLink);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, TurnsToSeconds(2));
}

void UseBiorevivifier (object oPC, object oItem) {
    int nTimer = GetCooldownTimer(oPC, "BIO");
    if (nTimer > 0) {
        FloatingTextStringOnCreature("You cannot use a biorejuvenator again for another " +
        IntToString(nTimer) + " second" + (nTimer == 1 ? "" : "s") + "!", oPC, FALSE);
        return;
    }
    DoRest(oPC, TRUE);
    DestroyObject(oItem);
}

void UseCasterLevelBoost (object oPC, object oItem) {
    int nUptime = GetLocalInt(GetModule(), "uptime");
    int nIndex = 1;
    int nUntil = GetLocalInt(oPC, "TempCasterLevel_1");
    int nCheck = GetLocalInt(oPC, "TempCasterLevel_2");

    if (nCheck < nUntil) {
        nIndex = 2;
        nUntil = nCheck;
    }

    nCheck = GetLocalInt(oPC, "TempCasterLevel_3");

    if (nCheck < nUntil)
        nIndex = 3;

    ApplyVisualToObject(GAOVFX_IMP_IMPROVE_ABILITY_SCORE_PURPLE, oPC);
    SetLocalInt(oPC, "TempCasterLevel_" + IntToString(nIndex), nUptime + 60);
}

void UseForcecage (object oPC, object oItem) {
    if (GetItemCharges(oItem) < 1)
        DestroyObject(oItem);

    object oTarget = GetItemActivatedTarget();

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE &&
        GetIsTarget(oTarget, TARGET_TYPE_ENEMY, oPC)   &&
        GetChallengeRating(oTarget) <= 200.0           &&
        !GetLocalInt(oTarget, "PCDeathAcc")) {

        effect eLink = EffectVisualEffect(VFX_DUR_GLYPH_OF_WARDING);
        eLink = EffectLinkEffects(eLink, EffectCutsceneImmobilize());
        eLink = ExtraordinaryEffect(eLink);

        SignalEvent(oTarget, EventSpellCastAt(oPC, SPELL_HOLD_MONSTER));
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(1));
    } else
        FloatingTextStringOnCreature("You cannot use the Moderately Escapable Forcecage on " + GetName(oTarget) + "!", oPC, FALSE);
}

void UseMalleksLecture (object oPC, object oItem) {
    /* temporary immunity to mords/breach, but no spellcasting capabilities;
     * can only be used on self or pets */
}

void UsePixieBomb (object oPC, object oItem) {
    /* summon several pixies for a short time */
}

void UsePotionOfTheThirdEye (object oPC, object oItem) {
    object oArea = GetArea(oPC);

    if (GetTag(oArea) != "limbohell") {
        FloatingTextStringOnCreature("You can only use the Potion of the Third Eye in Limbo!", oPC, FALSE);
        return;
    }

    int nCount = 1;
    effect eVis = EffectVisualEffect(VFX_DUR_GHOSTLY_PULSE_QUICK);
    object oWall = GetNearestObjectByTag("invisiblebarrier", oPC, nCount++);

    while (GetIsObjectValid(oWall)) {
        RemoveEffectsOfType(EFFECT_TYPE_VISUALEFFECT, oWall);
        DelayCommand(nCount * 0.01, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, oWall));

        oWall = GetNearestObjectByTag("invisiblebarrier", oPC, nCount++);
    }

    AssignCommand(oArea, DelayCommand(300.0, DeleteLocalInt(oArea, "VisualsApplied")));
}

void UseResurrectionPotion (object oPC, object oItem) {
    float fRadius = RADIUS_SIZE_MEDIUM;

    if (GetRacialType(oPC) == RACIAL_TYPE_DRAGON) {
        fRadius = RADIUS_SIZE_HUGE;
        ApplyVisualToObject(VFX_FNF_LOS_HOLY_20, oPC);
    } else
        ApplyVisualToObject(VFX_FNF_LOS_HOLY_10, oPC);

    location lTarget = GetLocation(oPC);
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget);

    while (GetIsObjectValid(oTarget)) {
        if (GetIsPC(oTarget) && GetIsDead(oTarget) && GetFactionEqual(oTarget, oPC))
            DelayCommand(GetDistanceBetween(oTarget, oPC) / 20, ApplyResurrection(oTarget, oPC));

        oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lTarget);
    }
}

void UseScrollOfTheMiser (object oPC, object oItem) {
    object oTarget = GetItemActivatedTarget();

    if (GetLocalString(oTarget, "ServerDestroyed") == "RESPAWN") {
        FloatingTextStringOnCreature("You cannot restore items lost to death with the Scroll of the Miser!", oPC, FALSE);
        return;
    }

    if (GetTag(oTarget) != "pileofrust" || GetItemPossessor(oTarget) != oPC) {
        FloatingTextStringOnCreature("You can only restore your own slagged items with the Scroll of the Miser!", oPC, FALSE);
        return;
    }

    if (GetGold(oPC) < 50000000) {
        FloatingTextStringOnCreature("You must have 50 million gold to restore an item with Scroll of the Miser!", oPC, FALSE);
        return;
    }

    ApplyVisualToObject(VFX_IMP_KNOCK, oPC);
    TakeGoldFromCreature(50000000, oPC, TRUE);

    ExecuteScript("repair_item", oTarget);

    DestroyObject(oItem);
}

void UseSeedsOfLife (object oPC, object oItem) {
    location lTarget = GetItemActivatedTargetLocation();

    object oTree = CreateObject(OBJECT_TYPE_PLACEABLE, "randuse_lifetree", lTarget);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, ExtraordinaryEffect(EffectCutsceneGhost()), oTree);

    AssignCommand(GetArea(oPC), ApplyTreeHealing(oPC, oTree, 30));
    DestroyObject(oItem);
}

void UseSpellFocusBoost (object oPC, object oItem, int nSchool) {
    if (GetItemCharges(oItem) < 1)
        DestroyObject(oItem);

    int nVis;

    switch (nSchool) {
        case SPELL_SCHOOL_ABJURATION:    nVis = VFX_IMP_HEAD_SONIC;  break;
        case SPELL_SCHOOL_CONJURATION:   nVis = VFX_IMP_HEAD_ACID;   break;
        case SPELL_SCHOOL_DIVINATION:    nVis = VFX_IMP_HEAD_NATURE; break;
        case SPELL_SCHOOL_ENCHANTMENT:   nVis = VFX_IMP_HEAD_COLD;   break;
        case SPELL_SCHOOL_EVOCATION:     nVis = VFX_IMP_HEAD_FIRE;   break;
        case SPELL_SCHOOL_ILLUSION:      nVis = VFX_IMP_HEAD_MIND;   break;
        case SPELL_SCHOOL_NECROMANCY:    nVis = VFX_IMP_HEAD_EVIL;   break;
        case SPELL_SCHOOL_TRANSMUTATION: nVis = VFX_IMP_HEAD_ODD;    break;
    }

    ApplyVisualToObject(nVis, oPC);

    SetLocalInt(oPC, "TempSpellFocus_School", nSchool);
    SetLocalInt(oPC, "TempSpellFocus_Until", GetLocalInt(GetModule(), "uptime") + 60);

    effect eVis = ExtraordinaryEffect(EffectVisualEffect(VFX_DUR_IOUNSTONE_YELLOW));
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oPC, 60.0);
}

void UseTulipofTenacity (object oPC, object oItem) {
    int nXP = 210000 - GetXP(oPC);

    if (nXP < 100000)
        nXP = 100000;

    GiveXPToCreature(oPC, nXP);

    SetPlotFlag(oItem, FALSE);
    DestroyObject(oItem);
}

void UseJewelOfMask (object oPC, object oItem) {
    object oTarget = GetItemActivatedTarget();

    if (GetTag(oTarget) != "hgt_maker") {
        FloatingTextStringOnCreature("You can only upgrade Trap Makers with the Jewel of Mask!", oPC, FALSE);
        return;
    }

    int nLimit = GetLocalInt(oTarget, "TrapMaker_Limit");
    if (nLimit < 6) {
        FloatingTextStringOnCreature("That trap maker is too weak to be upgraded with the Jewel of Mask!", oPC, FALSE);
        return;
    } else if (nLimit >= 8) {
        FloatingTextStringOnCreature("That trap maker is too powerful to be upgraded with the Jewel of Mask!", oPC, FALSE);
        return;
    }

    SetPlotFlag(oItem, FALSE);
    DestroyObject(oItem);

    SetItemCursedFlag(oTarget, TRUE);
    SetLocalInt(oTarget, "TrapMaker_Limit", nLimit + 1);

    ApplyVisualToObject(VFX_IMP_HEAD_EVIL, oPC);
    FloatingTextStringOnCreature("Your " + GetName(oTarget) + " has been upgraded to produce " +
        (nLimit == 7 ? "Godlike" : "Legendary") + " traps!", oPC, FALSE);
}

void DoRandomWeapon (object oPC, object oItem) {
    if (GetLocalInt(oItem, "Modified")) {
        FloatingTextStringOnCreature("This weapon has already been randomized!", oPC, FALSE);
        return;
    }

    int i, nEle = 5, nExo = 4;
    string sEle = "6 7 9 10 13 ", sExo = "5 8 11 12 ", sType;

    SetLocalInt(oItem, "Modified", 1);

    sType = GetStringSubString(sEle, Random(5));

    itemproperty ip = ItemPropertyDamageBonus(StringToInt(sType), IP_CONST_DAMAGEBONUS_5d12);
    AddItemProperty(DURATION_TYPE_PERMANENT, ip, oItem);

    sType = GetStringSubString(sExo, Random(4));

    itemproperty ipb = ItemPropertyDamageBonus(StringToInt(sType), IP_CONST_DAMAGEBONUS_5d12);
    AddItemProperty(DURATION_TYPE_PERMANENT, ipb, oItem);

    DrawSpring(DURATION_TYPE_INSTANT, VFX_IMP_CHARM, GetLocation(oPC), 2.5, 2.5, 2.0, 2.0, 0.0, 30, 1.0, 0.0);
}

void UseJumpItem(object oPC, object oItem) {
    object oWay = GetWaypointByTag(GetLocalString(oItem, "JumpTo"));
    location lJump = GetLocation(oWay);
    object oArea = GetAreaFromLocation(lJump);
    if (GetIsObjectValid(oArea)) {
        AssignCommand(oArea, ForceJump(oPC, lJump));
    } else
        FloatingTextStringOnCreature("Invalid destination! Please alert a DM!", oPC, FALSE);
}

void ApplyImmunity (object oTarget, int nRounds) {
    effect eLink = EffectImmunity(IMMUNITY_TYPE_CRITICAL_HIT);
    eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_IOUNSTONE_YELLOW));
    eLink = ExtraordinaryEffect(eLink);
    SetEffectSpellId(eLink, HGEFFECT_TEMP_CRITICAL_IMMUNITY);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}

void ApplyDispelImmunity (object oTarget, int nRounds) {
    effect eLink = EffectSpellImmunity(SPELL_LESSER_DISPEL);
    eLink = EffectLinkEffects(eLink, EffectSpellImmunity(SPELL_DISPEL_MAGIC));
    eLink = EffectLinkEffects(eLink, EffectSpellImmunity(SPELL_GREATER_DISPELLING));
    eLink = EffectLinkEffects(eLink, EffectVisualEffect(HGVFX_DUR_IOUNSTONE_VIBRANT_PURPLE));
    eLink = ExtraordinaryEffect(eLink);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}

void DoMassDomination(object oPC) {
    object oParty, oTarget;
    int nCount, nCheck, i;
    for (oParty = GetFirstFactionMember(oPC); GetIsObjectValid(oParty); oParty = GetNextFactionMember(oPC)) {
        if (GetIsPC(oPC))
            nCount++;
    }

    effect eDom     = EffectLinkEffects(EffectDominated(), EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED));
    for (oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC, i++, CREATURE_TYPE_IS_ALIVE, TRUE);
                   GetIsObjectValid(oTarget);
                   oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC, i++, CREATURE_TYPE_IS_ALIVE, TRUE)) {
        if (GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS) || GetIsImmune(oTarget, IMMUNITY_TYPE_DOMINATE))
            continue;
        if (GetHasEffectOfType(EFFECT_TYPE_DOMINATED, oTarget))
            continue;
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDom, oTarget, RoundsToSeconds(20));
        nCheck++;
        if (nCheck >= nCount)
            break;
    }
}

void main () {
    if (GetUserDefinedItemEventNumber() != X2_ITEM_EVENT_ACTIVATE)
        return;
    SetExecutedScriptReturnValue(X2_EXECUTE_SCRIPT_END);

    object oPC = GetItemActivator();
    object oItem = GetItemActivated();
    string sRes = GetResRef(oItem);

    if (!GetItemIsUsable(oItem, oPC))
        return;

    int nId = StringToInt(GetStringRight(GetResRef(oItem), 3));

    if (GetStringLeft(sRes, 6) == "randwp") {
        if ((nId > 499) && (nId < 550))
            DoRandomWeapon(oPC, oItem);
        else
            FloatingTextStringOnCreature("This weapon is bugged! Please report this error to a DM.", oPC, FALSE);

        return;
    }

    /* Add 1000 to id if non-useable; for random loot with coded special powers */
    if (GetStringLeft(sRes, 7) != "randuse")
        nId += 1000;

    /* XXX: convert Scroll of Intervention to Remove Paralysis (remove HGEFFECT_PHYSICAL_DOMINATION) */

    switch (nId) {

        case 1:     AssignCommand(oPC, UseCasterLevelBoost(oPC,         oItem));                               break;
        case 2:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_ABJURATION));    break;
        case 3:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_CONJURATION));   break;
        case 4:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_DIVINATION));    break;
        case 5:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_ENCHANTMENT));   break;
        case 6:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_EVOCATION));     break;
        case 7:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_ILLUSION));      break;
        case 8:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_NECROMANCY));    break;
        case 9:     AssignCommand(oPC, UseSpellFocusBoost(oPC,          oItem,   SPELL_SCHOOL_TRANSMUTATION)); break;
        case 10:    AssignCommand(oPC, UseBiorevivifier(oPC,            oItem));                               break;
        case 26:    AssignCommand(oPC, UseResurrectionPotion(oPC,       oItem));                               break;
        case 28:    AssignCommand(oPC, UseMalleksLecture(oPC,           oItem));                               break;
        case 29:    AssignCommand(oPC, UseForcecage(oPC,                oItem));                               break;
        case 34:    AssignCommand(oPC, UsePotionOfTheThirdEye(oPC,      oItem));                               break;
        case 35:    AssignCommand(oPC, UseScrollOfTheMiser(oPC,         oItem));                               break;
        case 37:    AssignCommand(oPC, UseSeedsOfLife(oPC,              oItem));                               break;
        case 39:    AssignCommand(oPC, UsePixieBomb(oPC,                oItem));                               break;
        case 41:    AssignCommand(oPC, UseAccusingStatue(oPC,           oItem));                               break;
        case 42:    AssignCommand(oPC, UseTulipofTenacity(oPC,          oItem));                               break;
        case 45:    AssignCommand(oPC, UseJewelOfMask(oPC,              oItem));                               break;
        case 47:    AssignCommand(oPC, UseJumpItem(oPC,                 oItem));                               break;
        case 1119:  AssignCommand(oPC,                   DoMassDomination(oPC));                               break;   /* randam119 */
        case 1132:  AssignCommand(oItem,                ApplyImmunity(oPC, 50));                               break;   /* randbl132 */
        case 1146:  AssignCommand(oItem,                ApplyImmunity(oPC, 15));                               break;   /* randbl146 */
    }
}

That said, we also have nwnx_events-based code, which allows for 'fast-use' items, spells, etc - code which cancels the event and executes in its place. For that, we use variables, though some of them point right back to the item's tag with a 'use tag' variable. For some idea what that looks like:

        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;
[/quote]

And DoInstantUse (taken from the linux version of SIMTools):
[code]
int DoInstantUse(object oIUPC, object oIUItem, object oIUTarget, location lIUTarget)
{
    string sTag = GetTag(oIUItem);
    string sScript = GetLocalString(oIUItem, "FKY_CHAT_INSTANT_SCRIPT");

    if (sTag == "fky_chat_ventril")
        return DoVentril(oIUPC, oIUItem, oIUTarget, lIUTarget);
    else if (sTag == "fky_chat_target")
        return DoTarget(oIUPC, oIUItem, oIUTarget, lIUTarget);
    else if (sScript != "") {
        if (sScript == "TAG")
            sScript = sTag;

        SetLocalObject(oIUPC, "FKY_CHAT_INSTANT_ITEM", oIUItem);
        SetLocalObject(oIUPC, "FKY_CHAT_INSTANT_TARGET", oIUTarget);
        SetLocalLocation(oIUPC, "FKY_CHAT_INSTANT_LOCATION", lIUTarget);

        ExecuteScript(sScript, oIUPC);

        DeleteLocalObject(oIUPC, "FKY_CHAT_INSTANT_ITEM");
        DeleteLocalObject(oIUPC, "FKY_CHAT_INSTANT_TARGET");
        DeleteLocalLocation(oIUPC, "FKY_CHAT_INSTANT_LOCATION");

        return TRUE;
    }

    /* BEGIN HG SPECIFIC */
    else if (GetStringLowerCase(sTag) == "pclist")
        return DoPCList(oIUPC, oIUItem, oIUTarget, lIUTarget);
    else if (GetLocalInt(oIUItem, "PseudoSpell") && GetLocalInt(oIUItem, "Singleton"))
        return DoPseudoSpell(oIUPC, oIUItem, oIUTarget, lIUTarget);
    /* END HG SPECIFIC */

    return FALSE;
}


My second question has to do with the NESS spawn system. So for those who are using it or who have used it in the past, is it better to go with the area HB method or the OnEnter psuedo HB method?


I don't use NESS. My general rule probably applies, though, setting other considerations like bugginess aside. We use pseudos whenever they'll be running a 5th of mod uptime or less, since they are roughly 5 times as cpu-intensive as an equivalent heartbeat. Of course, there may be idiosyncratic reasons to use pseudos with NSS that I'm unaware of (or not to).

Funky
               
               

               


                     Modifié par FunkySwerve, 19 avril 2013 - 04:02 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
A couple PW script related questions
« Reply #6 on: April 21, 2013, 08:53:44 am »


               Definitely some food for thought. Thanks Funky.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
A couple PW script related questions
« Reply #7 on: April 21, 2013, 04:32:07 pm »


               Since locals have been brought up, be aware that standard scripts can delete the locals from dying and crafting (options commonly available to a PC).  Fortunately, there are only four scripts that need to be altered to prevent losing variables, no includes need to be changed.  The scripts are

x2_im_start_a
x2_im_start_w
x2_im_start_ar
x2_s2_dyearmor

For each of these scripts find the line that has CopyItem() and insert TRUE as the third parameter.

An alternative to locals is storing information in the unidentified description (for identified items only).  This process is more cumbersome, but keeps things intact from module changes.
               
               

               
            

Legacy__Guile

  • Hero Member
  • *****
  • Posts: 1308
  • Karma: +0/-0
A couple PW script related questions
« Reply #8 on: April 29, 2013, 11:54:22 pm »


               I love the science Funky put into his item scripts... Awesome...

I'd just like to add that, many of the scripts which end up taking up resources, more often than not, are usually conversations in most module, therefore I've done away with multiple scripts for multiple conversations by placing all conversation scripts into a multiple script routine, reducing 2000++ scripts to a mere 300!  (Yes it was a huge amount of work believe me)

Something to consider...  ':wizard:'
               
               

               


                     Modifié par _Guile, 25 mai 2013 - 03:28 .