Help understanding a script.
#51
Posté 28 novembre 2011 - 11:31
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?
#52
Posté 28 novembre 2011 - 08:25
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
#54
Posté 28 novembre 2011 - 09:22
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
#55
Posté 28 novembre 2011 - 09:34
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
#56
Posté 01 décembre 2011 - 11:06
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.
#57
Posté 02 décembre 2011 - 01:11
Funky
Modifié par FunkySwerve, 02 décembre 2011 - 01:11 .
#58
Posté 02 décembre 2011 - 02:38
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.
#59
Posté 03 décembre 2011 - 02:03
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.
#60
Posté 03 décembre 2011 - 11:22
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.
#61
Posté 03 décembre 2011 - 03:00
update for the weapon switching issue//private function
//1.70 by Shadooow: Is my target immune to last spell cast?
int MyResistSpell_GetIsSpellImmune(object oTarget, int bAOE)
{
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oTarget);
object oLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oTarget);
int bNoChange = GetLocalObject(oTarget,"ITEM_IN_RIGHT") == oRight && GetLocalObject(oTarget,"ITEM_IN_LEFT") == oLeft;
int nSpellId = GetEffectSpellId(EffectDazed());//AOE spells workaround
if(bAOE && bNoChange && !GetIsPC(oTarget) && GetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId)) == 1)
{
return TRUE;//immunity to AOE is granted via itemproperty, no reason to repeat whole process again
}
else if((nSpellId == SPELL_MAGIC_MISSILE || nSpellId == SPELL_SHADOW_CONJURATION_MAGIC_MISSILE) && GetHasSpellEffect(SPELL_SHIELD,oTarget))
{
return TRUE;//magic missile on target with Shield spell effect
}
else if((nSpellId == SPELL_DROWN || nSpellId == SPELLABILITY_PULSE_DROWN || nSpellId == SPELL_FLESH_TO_STONE) && GetHasSpellEffect(nSpellId,oTarget))
{
return TRUE;//drown and flesh to stone immunity workaround
}
int nSpellLevel = 99;
int nclass = GetLastSpellCastclass();
if(bAOE)
{
nSpellLevel = GetLocalInt(OBJECT_SELF,"AOE_INNATE")-1;
if(nSpellLevel < 0)
{
nSpellLevel = 99;
if(GetLocalInt(OBJECT_SELF,"AOE_class") > 0)
{
nclass = GetLocalInt(OBJECT_SELF,"AOE_class")-1;
}
}
}
if(nSpellLevel == 99)
{
string sCollumn = "Innate";
switch(nclass)
{
case class_TYPE_WIZARD:
case class_TYPE_SORCERER: sCollumn = "Wiz_Sorc"; break;
case class_TYPE_CLERIC: sCollumn = "Cleric"; break;
case class_TYPE_DRUID: sCollumn = "Druid"; break;
case class_TYPE_BARD: sCollumn = "Bard"; break;
case class_TYPE_RANGER: sCollumn = "Ranger"; break;
case class_TYPE_PALADIN: sCollumn = "Paladin"; break;
}
sCollumn = Get2DAString("spells",sCollumn,nSpellId);
if(sCollumn != "****" && sCollumn != "")
{
nSpellLevel = StringToInt(sCollumn);
if(bAOE) SetLocalInt(OBJECT_SELF,"AOE_INNATE",nSpellLevel+1);
}
}
int nMaxLevel;
if(GetHasSpellEffect(734,oTarget))
nMaxLevel = 8;
else if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY,oTarget))
nMaxLevel = 4;
else if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY,oTarget) || GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE,oTarget))
nMaxLevel = 3;
else if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE,oTarget))
nMaxLevel = 2; //shadow ghostly visage
else if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE,oTarget) || GetHasSpellEffect(SPELLABILITY_AS_GHOSTLY_VISAGE,oTarget) || GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE,oTarget))
nMaxLevel = 1;
if(nSpellLevel <= nMaxLevel)
{
return TRUE;//immunity via spell immunity effect like globe of invulnerability
}
string sSchool = Get2DAString("spells","School",nSpellId);
if(GetHasSpellEffect(SPELL_SHADOW_SHIELD,oTarget) && sSchool == "N")
{
return TRUE;//Necromantic spell cast at target with Shadow Shield
}
else if(GetHasSpellEffect(390,oTarget) && sSchool == "E")
{
return TRUE;//Enchantment spell cast at target polymorphed into pixie
}
int nSchool = -1;
if (sSchool == "A") nSchool = 0;
else if(sSchool == "C") nSchool = 1;
else if(sSchool == "D") nSchool = 2;
else if(sSchool == "E") nSchool = 3;
else if(sSchool == "V") nSchool = 4;
else if(sSchool == "I") nSchool = 5;
else if(sSchool == "N") nSchool = 6;
else if(sSchool == "T") nSchool = 7;
if(bAOE && !GetIsPC(oTarget))
{
if(bNoChange && GetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId)) == -1)
{
return FALSE;//immunity to AOE is not granted via itemproperty, no reason to repeat whole process again
}
else
{
SetLocalObject(oTarget,"ITEM_IN_RIGHT",oRight);
SetLocalObject(oTarget,"ITEM_IN_LEFT",oLeft);
}
}
//still nothing, lets check target skin as well to handle creatures like demiliches
int nSlot;
object oItem;
itemproperty ip;
for(;nSlot < NUM_INVENTORY_SLOTS;nSlot++)
{
oItem = GetItemInSlot(nSlot,oTarget);
if(GetIsObjectValid(oItem))
{
itemproperty ip = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ip))
{
switch(GetItemPropertyType(ip))
{
case ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL:
if(StringToInt(Get2DAString("iprp_spellcost","SpellIndex",GetItemPropertyCostTableValue(ip))) == nSpellId)
{
if(bAOE) SetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId),1);
return TRUE;//immunity specifically on our spell from itemproperty
}
break;
case ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL:
if(nSpellLevel <= GetItemPropertyCostTableValue(ip))
{
if(bAOE) SetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId),1);
return TRUE;//immunity to spell by level from itemproperty
}
break;
case ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL:
if(GetItemPropertySubType(ip) == nSchool)
{
if(bAOE) SetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId),1);
return TRUE;//immunity to spell school from itemproperty
}
break;
}
ip = GetNextItemProperty(oItem);
}
}
}
if(bAOE) SetLocalInt(oTarget,"IMMUNE_TO_"+IntToString(nSpellId),-1);
return FALSE;
}
#62
Posté 03 décembre 2011 - 03:57
ShaDoOoW wrote...
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. ...
Sorry I have not been following this thread that much. Mainly because I have not had the time to test and fulsh out my Idea. If you have the time however you may want to test it out.
The Original Idea that I did not fully explaine with Fester pots original script is still valid. That was to use the ResistSell function. Where It would have worked with his script. It will take even more testion with your AoE's to make sure every thing is flushed out right.
I know you are now going to say that ResistSpell(),GetSpellId(), GetSpellSaveDC(), GetCasterLevel(), and so on; do not work outside of the SpellCastEvent. So to me the solution is to just place the script back inside of the Spell.
In Festers case he was trying to cast a fake spell that the player had to have, then reducing the spell usages, and then doing the calculations outside of the spell event. For him it would have been better to cast Real spell and create a spell hook that would re-run the script he was running inside the spellevent. Of cource the spell hook would also stop the SpellScript from running. Yes, you will also need to place a filter in the script/function to make sure that the script only tries to cast the splee to place it back into the Spellevent one time.
Festers script would have nt been to hard to get to work that way. After all we had full contorl of the action que for the in his script.
I do not currently have enought time to test out the Idea with the AOE's It should work there are just more thing to take into concideration. Like who is going to cast the spell to place it back into the spell event. If the PC who cast the spell to bengin with is no longer even log in, he sure can not do it. even if he was does the bInstant switch in actionCastSpell bypass the action que. would be nice if it did, Yea I really don have the time to flush it out right now.
Hopefully that give you enough information if you wanted to try and work out the kinks.
Modifié par Lightfoot8, 03 décembre 2011 - 03:57 .
#63
Posté 03 décembre 2011 - 05:54
ShaDoOoW wrote...
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.
If performance is an issue, and the alternative bugs to serious of an issue to allow compromise, I think you're stuck with the onun/equip variable solution. I understand you want to avoid mod events, and why, but I think that's the only alternative.
Funky
#64
Posté 03 décembre 2011 - 06:45
The issue that does these lags is "cross-shouts". If there is a spell with larger are of effect which hits in one cast multiple enemies, then every enemy hit triggers OnSpellCastAt event which triggers two times OnConversation event which causes every creature nerby shouter to attack caster. Even single spell like fireball can cause lag for whole minute if the spell hits 100 enemies. And this is even worse with AOE spells.
I found no other solution than disable the silent shouts in SpellCast event which unfortunately results into non-reaction in situation where caster cast a spellll and hit only single enemy. Other will then not respond to the spell being cast, only to the vision.
#65
Posté 03 décembre 2011 - 11:42
ShaDoOoW wrote...
But the latest script should be reliable in 99% cases.
The issue that does these lags is "cross-shouts". If there is a spell with larger are of effect which hits in one cast multiple enemies, then every enemy hit triggers OnSpellCastAt event which triggers two times OnConversation event which causes every creature nerby shouter to attack caster. Even single spell like fireball can cause lag for whole minute if the spell hits 100 enemies. And this is even worse with AOE spells.
I found no other solution than disable the silent shouts in SpellCast event which unfortunately results into non-reaction in situation where caster cast a spellll and hit only single enemy. Other will then not respond to the spell being cast, only to the vision.
As an aside, acaos cut most (like 90%) of our silent shouts out, as they are mostly useless overhead. That's something else you could look at for your patch.
Funky





Retour en haut







