Author Topic: Help understanding a script.  (Read 1672 times)

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #45 on: November 23, 2011, 09:01:02 am »


               Was there a question in there?

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #46 on: November 23, 2011, 09:28:33 am »


               Yes. Where am I wrong there (i guess my assumption that si.sp is caster level is wrong)? How does it work then and how does it solves my issue?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #47 on: November 23, 2011, 06:38:35 pm »


               Si.sp casterlevel is correct, because it is passed in the struct from when the spell is initially cast. Take a look at the AOE script again. Casterlevel is never rechecked after the initial cast; rather it is passed via struct - you could just as easily pass it via variable, but we use that struct for all our spells, to make edits to the spell system at larger simpler.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #48 on: November 23, 2011, 07:56:09 pm »


               I see, your AOEs passing a bSROnly = 2 thus you are checking only spell resistance and spell immunity. I havent though of that as I wanted the spell mantle functionality as well, BUT if I think about it, fact that spell mantle doesnt work for AOE might be better balanced then default behavior. Even if not its a small price for fixing the ResistSpell 3xpl0it. So, thanks, I will think about this approach though it means I will have to print fake feedback (which might be issue when client has different language installed than server)
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #49 on: November 23, 2011, 10:35:38 pm »


               Here's our Get and Send messages to get you started. I imagine you'll be able to find some tlk values for them that fit. The PC Filter option you can ignore - we use it, combined with NWNX, to allow players to only see some messages in combat, instead of the superscroll of normal combat.


struct SubString GetSpellResistanceMessage (object oCaster, object oTarget, int nRoll, int nSP, int nSR) {
    struct SubString ss;
    int bCasterBrief = GetPCFilter(oCaster, PCFILTER_BRIEF);
    int bTargetBrief = GetPCFilter(oTarget, PCFILTER_BRIEF);

    string sCaster = (bCasterBrief ? "SP" : "Spell Penetration");
    string sTarget = (bTargetBrief ? "SR" : "Spell Resistance");


    if (nSR == -2) {
        ss.first = C_TEAL + GetName(oTarget) + " : " + sCaster + " : *immune*" + C_END;
        ss.rest  = C_TEAL + GetName(oCaster) + " : " + sTarget + " : *immune*" + C_END;
    } else if (nSR == -3) {
        ss.first = C_TEAL + GetName(oTarget) + " : " + sCaster + ": *absorbed*" + C_END;
        ss.rest  = C_TEAL + GetName(oCaster) + " : " + sTarget + ": *absorbed*" + C_END;
    } else {
        string sCasterRoll = "(" + IntToString(nRoll) + " + " + IntToString(nSP) +
            " = " + IntToString(nRoll + nSP) + (bCasterBrief ? " / " : " vs. SR: " ) +
            IntToString(nSR) + ")";
        string sTargetRoll = "(" + IntToString(nRoll) + " + " + IntToString(nSP) +
            " = " + IntToString(nRoll + nSP) + (bTargetBrief ? " / " : " vs. SR: " ) +
            IntToString(nSR) + ")";

        if (nSP + nRoll >= nSR) {
            ss.first = C_TEAL + GetName(oTarget) + " : " + sCaster + " : *success* : "  + sCasterRoll + C_END;
            ss.rest  = C_TEAL + GetName(oCaster) + " : " + sTarget + " : *defeated* : " + sTargetRoll + C_END;
        } else {
            ss.first = C_TEAL + GetName(oTarget) + " : " + sCaster + " : *failure* : "  + sCasterRoll + C_END;
            ss.rest  = C_TEAL + GetName(oCaster) + " : " + sTarget + " : *resisted* : " + sTargetRoll + C_END;
        }
    }

    return ss;
}

void SendSpellResistanceMessage (object oCaster, object oTarget, int nRoll, int nSP, int nSR, float fDelay=0.0) {
    struct SubString ss = GetSpellResistanceMessage(oCaster, oTarget, nRoll, nSP, nSR);

    switch (GetPCFilter(oCaster, PCFILTER_SPELLPEN)) {
        case 0: DelayCommand(fDelay, SendMessageToPC(oCaster, ss.first));                     break;
        case 1: DelayCommand(fDelay, SendSystemMessage(oCaster, ss.first));                   break;
        case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(ss.first, oCaster, FALSE)); break;
    }

    switch (GetPCFilter(oTarget, PCFILTER_SPELLPEN)) {
        case 0: DelayCommand(fDelay, SendMessageToPC(oTarget, ss.rest));                      break;
        case 1: DelayCommand(fDelay, SendSystemMessage(oTarget, ss.rest));                    break;
        case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(ss.rest, oTarget, FALSE));  break;
    }
}

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #50 on: November 28, 2011, 11:31:58 am »


               So I choosed your solution and implemented it in my Patch project. However my function to check whether is Target immune to the spell is quite heavy already and I do not check all items, only skin. Which is something I would like to improve, but Im not sure whether is good idea to loop all items and all their itemproperties each time an AOE spell triggers heartbeat.

Atm this solution is used only inside AOEs or when target has spell mantle effect.

Any idea to make it efficient? Or shouldnt I worry about this?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #51 on: November 28, 2011, 08:25:32 pm »


               Can you post your function please? We use the nwnx_defenses function:

int GetHasSpellImmunity (int nSpellId, object oCreature=OBJECT_SELF, int nSpellSchool=-1, int nSpellLevel=-1, int nDurType=-1) {
    return NWNXDefensesFour(oCreature, "NWNX!DEFENSES!GETHASSPELLIMMUNITY", nSpellId, nSpellSchool, nSpellLevel, nDurType);
}
which is extraordinarily fast in the engine - so much so that acaos has used spell immunity effects as proxies for 'true' (stacking wihtout regard for the 20 cap) ab boosters in our custom hacks (and you KNOW how much those get called upon in combat). I don't know exactly what you're doing engine-wise in your patch, so I don't know if something like that is an option.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #52 on: November 28, 2011, 08:40:13 pm »


               pastebin
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #53 on: November 28, 2011, 09:22:06 pm »


               I'm not crazy about doing 2da reads in spells, but since you're only hitting 2 2das, you should be fine with the new default caching - it might even be faster than the method we currently use to get some of that stuff, which predates the new 2da handling. We're using a modified spell_func include, orginally by Old Man Whilster, which caches spell info like school (among many other things there are no Gets for in vanilla NWN) on variables, which are loaded onto the module when it loads.

I guess my first recommendation would be to haxxor GetHasSpellImmunity into your patch, using the linux nwnx_defenses function as a basis. I don't have the skill to do that, however, and I have no idea if you do, or if its even an option.

Failing that, I say leave it as is. The overhead is probably not terrible. I dislike your itemproperty loop, since it's both potentially heavy and incomplete, but I can see why you don't want to loop them all. That means it won't properly handle pc spell immunity from item properties, though, unless I overlooked something.

One possibility would be to handle it onequip, instead. If an item is equipped with a spell immunity, set a var on the creature, and remove it when it's unequipped. You could store them in a pseudo list, with vars setting like:

SpellImmunity_<spell id>  int 1

That would cover both creatures and pcs, and would be far faster than that loop, but I don't know if your patch includes modifications to module events. It's also somewhat hacktastic, I suppose. Just some food for thought.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #54 on: November 28, 2011, 09:34:06 pm »


               nwnx is not an option for this project

onequip variable also as I'm trying to do it as less event-extensive as possible, having user to put some code in his OnEquip is not good for me
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #55 on: December 01, 2011, 11:06:56 pm »


               pastebin - attempt to improve performancy, because  especially stacked AOEs could do some lags I suppose (and they do in fact in 1.69 due to the several issues in OnSpellCastAt default event) - if anyone see a way to improve it further or if I missed something let me know

I thought about two scenarios:

1) druid PC gets flanked by many monsters and then casts several instances of grease, entangle, vine mine, spike growth, stonehold, storm of vengeance and then casts ice storm into this

2) PC is subject to several web spells from many spiders around

I presume always at least ten monsters and PC himself.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #56 on: December 02, 2011, 01:11:30 am »


               My suspicion is that any lag you're going to get in that scenario is going to be vfx lag from the aoes, especially grease, rather than cpu. I like that you expanded the loop to check all equipped slots, since my inclination is to nail down a fully working function where possible and then tweak for performance. It seems to me the variable approach you use still leaves you stuck with an onunequip event, however - without it, the pc  could still show as immune when he isn't, unless you're deleting the variable somewhere I'm not seeing. Pretty minor detail, but there you have it...I guess it depends on the compromise you pick between accuracy and performance.

Funky
               
               

               


                     Modifié par FunkySwerve, 02 décembre 2011 - 01:11 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #57 on: December 02, 2011, 02:38:01 am »


               the local variable is used only for non-pcs, player character will be checked for all items each time unless the function returns TRUE before that

its true that even monster could possibly unequip weapon or rather lose it, if that was a weapon that gives the immunity it would not worked correctly anymore however I would call this scenario to be a bad design. Monsters should have defensive abilities on skin.
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Help understanding a script.
« Reply #58 on: December 03, 2011, 02:03:56 am »


               ShaDoOow,

I disagree about monsters always having all of their powers on their skin.
Let's say there's a boss monster who uses an enchanted weapon that grants it an immunity. The players must defeat him to loot the weapon off of his corpse as a plot reward. Mid fight, a player manages to disarm him to get rid of his immunity. It might not work.

Second example:
My systems are designed to create very accurate NPC's. Nothing is ever kludged. If an NPC is supposed to have a crown that gives them huge defensive bonuses, then we will make that crown and put it on his head so that PC's can loot it, which I consider fair.
My Treasure system randomly generates NPC treasure in their inventory OnSpawn. So, they'll randomly get different weapons. If they get a better weapon than what they are already holding, they'll switch and use the better weapon. That weapon may grant an immunity. The NPC may also switch weapons in combat to use ranged melee weapons, or other tactical reasons. Or, they can be disarmed.

I think it's important to make sure that your patches are complete fixes. In this case, it would introduce a new bug that people with custom systems would need to worry about.
Remember that the official patches updated the default event scripts often. It's not necessarily a bad thing to use them.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #59 on: December 03, 2011, 11:22:23 am »


               OK I see, however Im not sure what to do now - the performancy is really problem, the default scripts causes huge cross-server lags in the situation #1, my scripts made it a little better but still not perfect. While the issue is in different place any additional code has relevance in such situations. You can try lure like 30monsters into stacked AOEs -> 3x grease 3x entangle 5x stonehold 7x vengeance and you will see. I know that issue is elsewhere but in this situation any additional piece of code matters I think.

Someone could also argument that a npc can unequip even a helmet, but is it really worth to make it compatible with such case?

In your case, it really leaves an exploit, but negative for players because even if the weapon granted immunity (and they cannot know that) after disarming the immunity will still be counted like the weapon was still equipped. At least provided that an AOE spell like web affected the monster before he got disarmed. But still, its much lesser issue than what you can do in 1.69. I can't see how players could abuse this one.

So I guess I could store item in left/right hand slot and check if they matches current items. If not repeat itemproperties check, what do you think? Still it won't handle unequipping helmet/destroying armor but you can really add immunities from helmet/armor to skin because every creature has a one and the armor/helmet is only for appearance.