Persistent World Area of Effect Spells
#1
Posté 13 décembre 2010 - 07:05
On my persistent world, area of effect spells (such as Grease, Cloud of Bewilderment, etc.) simply only to fire off the first time a PC enters into the area of effect. Subsequent rounds of remaining in the cloud do not seem to work consistently.
Is this a common issue on other worlds, and/or is anyone aware of a good fix?
Thanks,
#2
Posté 13 décembre 2010 - 07:58
also it means there is something pretty wrong on your module, so the best would be to find the real cause and not workarounds for spells. I do not however can tell you cause without knowing anything of your server and module.
EDIT: more technically, the aoes have lowest priority as far as memory use, so if the module dont have any of it, they will does what you described
Modifié par ShaDoOoW, 13 décembre 2010 - 08:02 .
#3
Posté 13 décembre 2010 - 08:27
Howlando_EFU wrote...
Is this a common issue on other worlds, and/or is anyone aware of a good fix?
This is actually a common thing on several pw worlds. There are numerous fixes on the vault but it has been so long I am unsure of which one we used. I will try and see which one we used but if I remember correctly it was not hard to fix once we read how....
I think the guys name was Don Wolf or something similiar though.
#4
Posté 13 décembre 2010 - 11:34
Here's a sample I posted a few years back at someone's request:
Click Me
We've evolved the process somewhat since then on HG. All aoes now run through a central include. Here's the scripts for that acid fog spell now (code is mostly acaos'):
First, the spell itself:
#include "ac_aoeper_inc"
struct SpellInfo GetPersistentAoESpellInfo () { return GetSpellInfo(); }
int GetPersistentAoELimit (struct SpellInfo si) {
if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
return -2;
return -1;
}
int GetPersistentAoEEffect (struct SpellInfo si) { return AOE_PER_FOGACID; }
string GetPersistentAoETag (struct SpellInfo si) { return "VFX_PER_FOGACID"; }
string GetPersistentAoEName (struct SpellInfo si) { return "Acid Fog"; }
int GetPersistentAoETargetMask (struct SpellInfo si) { return OBJECT_TYPE_CREATURE; }
int GetPersistentAoETargetType (struct SpellInfo si) { return TARGET_TYPE_DEFAULT; }
float GetPersistentAoEDuration (struct SpellInfo si) {
return MetaDuration(si, si.clevel / 2, DURATION_IN_ROUNDS);
}
effect GetPersistentAoEImpactEffect (struct SpellInfo si) {
effect eEff;
return eEff;
}
effect GetPersistentAoEDurationEffect (struct SpellInfo si) {
effect eDur;
if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
eDur = EffectDamageIncrease(1);
return eDur;
}
effect GetPersistentAoEVisualEffect (struct SpellInfo si) {
ApplyVisualAtLocation(VFX_FNF_GAS_EXPLOSION_ACID, si.loc);
return EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID);
}
void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis) {
if (!GetSpellResisted(si, oTarget, 0.0, 2)) {
int nDamage, nDice = si.clevel, nEffType = GetEffectType(eDur);
int nDamType = DAMAGE_TYPE_ACID, nSaveType = SAVING_THROW_TYPE_ACID;
if (nDice < 1)
nDice = 1;
nDamage = MetaPower(si, nDice, 6);
nDamage = GetReflexAdjustedDamage(nDamage, oTarget, si.dc, nSaveType, si.caster);
if (nDamage > 0) {
if (nEffType == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE) {
if (!GetHasSpecificEffect(eDur, oTarget))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDur, oTarget);
eEff = EffectDamage(nDamage / 2, nDamType);
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));
eEff = EffectDamage(nDamage / 2, DAMAGE_TYPE_MAGICAL);
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));
} else if (nEffType == EFFECT_TYPE_DAMAGE_INCREASE) {
if (GetTrueDamageImmunity(oTarget, nDamType) < 100) {
int nDecrease = 25 - GetTotalDamageImmunityDecrease(oTarget, nDamType);
if (nDecrease > 5)
nDecrease = 5;
if (nDecrease > 0) {
eEff = EffectDamageImmunityDecrease(nDamType, nDecrease);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oTarget);
}
}
eEff = EffectDamage(nDamage, nDamType);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
} else {
eEff = EffectDamage(nDamage, nDamType);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
}
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
}
}
}
Then, the include
ac_aoeper_inc (which, unlike most includes, actually has the void main in it - don't let that throw you):
#include "hg_inc"
#include "ac_spell_inc"
int GetIsHeraldAoE(object oAoE) {
string sTag = GetTag(oAoE);
if (sTag == "VFX_PER_FOGFREEZE" ||
sTag == "VFX_AOE_CONSECRATE_20" ||
sTag == "VFX_PER_FOGACID" ||
sTag == "VFX_PER_FOGKILL" ||
sTag == "VFX_PER_FOGMIND" ||
sTag == "VFX_PER_FOGSTINK")
return TRUE;
return FALSE;
}
struct SpellInfo GetPersistentAoESpellInfo ();
int GetPersistentAoELimit (struct SpellInfo si);
int GetPersistentAoEEffect (struct SpellInfo si);
string GetPersistentAoETag (struct SpellInfo si);
string GetPersistentAoEName (struct SpellInfo si);
int GetPersistentAoETargetMask (struct SpellInfo si);
int GetPersistentAoETargetType (struct SpellInfo si);
float GetPersistentAoEDuration (struct SpellInfo si);
effect GetPersistentAoEImpactEffect (struct SpellInfo si);
effect GetPersistentAoEDurationEffect (struct SpellInfo si);
effect GetPersistentAoEVisualEffect (struct SpellInfo si);
void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis);
float GetPersistentAoERemaining (object oAoE) {
int nRemaining = GetLocalInt(oAoE, "AoEExpires") - GetLocalInt(GetModule(), "uptime");
return IntToFloat(nRemaining < 1 ? 1 : nRemaining);
}
void DoAoEHeartbeat (struct SpellInfo si, object oAoE, effect eEff, effect eDur, effect eVis) {
int bDestroy = FALSE, bAllPCs = FALSE;
if (!GetIsObjectValid(oAoE))
return;
/* Storm of Vengeance doesn't destroy properly sometimes */
if (GetPersistentAoEEffect(si) == AOE_PER_STORM) {
if (si.id == SPELL_STORM_OF_VENGEANCE && GetLocalInt(GetArea(oAoE), "Area_Underwater"))
bAllPCs = TRUE;
if (GetLocalInt(GetModule(), "uptime") > GetLocalInt(oAoE, "AoEExpires"))
bDestroy = TRUE;
}
if (bDestroy ||
!GetIsObjectValid(si.caster) ||
GetIsDead(si.caster) ||
GetArea(si.caster) != si.area) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
return;
}
DelayCommand(6.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
AddLocalInt(oAoE, "AoERounds", 1);
si.target = oAoE;
int nMask = GetPersistentAoETargetMask(si);
int nType = GetPersistentAoETargetType(si);
for (si.target = GetFirstInPersistentObject(oAoE, nMask);
GetIsObjectValid(si.target);
si.target = GetNextInPersistentObject(oAoE, nMask)) {
if (GetIsSpellTarget(si, si.target, nType) || (bAllPCs && GetIsPC(si.target))) {
SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));
AssignCommand(si.caster, DelayCommand(GetRandomDelay(0.5, 4.5), ApplyAoEEffect(si, oAoE, si.target, eEff, eDur, eVis)));
}
}
}
void StartAoEHeartbeat (struct SpellInfo si, string sTag, effect eEff, effect eDur, effect eVis, int nUntil) {
int nCount = 1;
object oLoc, oAoE;
do {
oLoc = GetNearestObjectToLocation(OBJECT_TYPE_ALL, si.loc, nCount++);
} while (GetTag(oLoc) == sTag);
nCount = 1;
oAoE = GetNearestObjectByTag(sTag, oLoc);
while (GetIsObjectValid(oAoE)) {
if (GetAreaOfEffectCreator(oAoE) == si.caster && !GetLocalInt(oAoE, "AoEHeartbeat")) {
SetLocalInt(oAoE, "AoEHeartbeat", 1);
SetLocalInt(oAoE, "AoEExpires", nUntil);
SetLocalInt(oAoE, "AoESP", si.sp);
DelayCommand(0.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
return;
}
oAoE = GetNearestObjectByTag(sTag, oLoc, ++nCount);
}
}
void main () {
struct SpellInfo si = GetPersistentAoESpellInfo();
if (si.id < 0)
return;
float fDur = GetPersistentAoEDuration(si);
string sTag = GetPersistentAoETag(si);
effect eAoE = EffectAreaOfEffect(GetPersistentAoEEffect(si),
(si.id == SPELL_GREASE ? "nw_s0_greasea" : "****"), "****", "****");
int nLimit = GetPersistentAoELimit(si);
if (nLimit > 0) {
int nFound = 0, nCount = 1;
object oOther, oCreator, oArea = GetArea(si.caster);
while (GetIsObjectValid(oOther = GetNearestObjectByTag(sTag, si.caster, nCount++))) {
oCreator = GetAreaOfEffectCreator(oOther);
if (oCreator == oArea ||
GetLocalInt(oOther, "NoAoEDispel"))
continue;
if (GetIsPC(si.caster) && GetIsPC(oCreator)) {
if (GetIsHeraldAoE(oOther)) {
if (!GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCreator))
nFound++;
} else
nFound++;
} else if (GetFactionEqual(si.caster, oCreator)) {
nFound++;
}
if (nFound >= nLimit) {
SetPlotFlag(oOther, FALSE);
DestroyObject(oOther);
if (nFound == nLimit)
FloatingTextStringOnCreature("To prevent lag, only " +
IntToString(nLimit) + " " + GetPersistentAoEName(si) +
" spell" + (nLimit == 1 ? "" : "s") + " may exist in an area at the same time.", si.caster);
}
}
} else if (nLimit == -1) {
object oAoE, oArea = GetArea(si.caster);
for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {
if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
GetAreaOfEffectCreator(oAoE) != si.caster)
continue;
if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGFIRE VFX_PER_FOGFREEZE VFX_PER_STORM VFX_PER_RAINFIRE VFX_PER_RAINFREEZE VFX_AOE_CONSECRATE_20 ",
" " + GetTag(oAoE) + " ") >= 0) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
FloatingTextStringOnCreature("Only one area of effect damage field may exist per caster in an area at the same time.", si.caster);
}
}
} else if (nLimit == -2) {
object oAoE, oArea = GetArea(si.caster);
int nFound;
for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {
if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
!GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, GetAreaOfEffectCreator(oAoE)))
continue;
if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGSTINK VFX_PER_FOGKILL VFX_AOE_CONSECRATE_20 VFX_PER_FOGFREEZE VFX_PER_FOGMIND ",
" " + GetTag(oAoE) + " ") >= 0) {
nFound++;
if (nFound >= 2) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
if (nFound == 2)
FloatingTextStringOnCreature("Only two herald of storms clouds may exist in an area at the same time.", si.caster);
}
}
}
}
effect eEff = GetPersistentAoEImpactEffect(si);
effect eDur = GetPersistentAoEDurationEffect(si);
effect eVis = GetPersistentAoEVisualEffect(si);
AssignCommand(si.area, DelayCommand(2.0, StartAoEHeartbeat(si, sTag, eEff, eDur, eVis,
GetLocalInt(GetModule(), "uptime") + FloatToInt(fDur))));
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAoE, si.loc, fDur);
}
The main reason for the change in systems was to easily create more without a lot of duplicative code.
Funky
Modifié par FunkySwerve, 13 décembre 2010 - 11:37 .
#5
Posté 14 décembre 2010 - 04:09
Thanks Funky for sharing that.
#6
Posté 14 décembre 2010 - 07:33
Weeel, maybe. I haven't seen this issue on many servers and many of them was even poorly scripted, whats the difference?FunkySwerve wrote...
This does NOT necessarily mean that there's anything wrong with your module, however, as TSM notes - we have it on HG despite the best streamlining, even with only a couple players on.
For what I know. On the server this issue is, its from the start even after restart, so it does not appear as "heavy load" problem. And are mostly linux hosted. Anyone have this issue on windows? NWNX or not?
From what I know about the servers where I seen this, I never found anything what could cause it.
But maybe we can find it out. I post there few servers specs one have this issue second one does not.
with this issue
Arkhalia, PW Action server
linux hosting (debian)
CEP1 and 2GB of custom haks
NWNX odbc using MySQL probably
restart twice per week
like 100 spawned NPCs when load whose do not despawn and wander in towns
0-5 players average
monsters and loot have despawn 5 minutes (this is done with delay command running on every monster)
muling allowed, players have PC storages, they very often relogs
no persistent chests
overloaded stores after some time
around 500 locations
without
Demona, Light RP server
windows hosting
1GB custom haks (was done pre-CEP)
no NWNX, uses bio DB with custom scripted workaround to improve efficiency (which does HUGE lag at module load btw)
restart every 3-5 hours, often crashes LOL
like 50 npcs wandering in towns
5-15 players average
monsters never despawn
transfer items between characters disallowed
persistent chest using conversation, able to store like 50 items, using resref only
merchants do not buy much but there is player store which heavy rely on DB
around 300 locations
Lands of Larinia, Action quest based server
windows hosting
no haks
NWNX with all recent plugins
restart once per 5 hours
like 300 wandering NPCS in towns
0-5 players average
monsters despawn (delay command on all of them)
mullling allowed so far, but noone does this
no persistent chest yet
merchants buy everything but its restarted every 5 hours, merchants are never overloaded
around 500 locations
So far I see no other difference than hosting...
BTW do not bring the server on list if you do not know certainly, like I know that Bastions of War do not have this problem, but they might use pseudo heartbeats workaround.
Modifié par ShaDoOoW, 14 décembre 2010 - 07:35 .
#7
Posté 14 décembre 2010 - 07:37
Funky
#8
Posté 14 décembre 2010 - 08:17
#9
Posté 14 décembre 2010 - 01:33
City of Arabel had this for a bit as well...maybe it is somewhat linked to players though as the servers I have seen it on most are servers with a healthy player pop.
#10
Posté 14 décembre 2010 - 02:47
#11
Posté 15 décembre 2010 - 08:58
Players cause load. Load causes this. Even a single player creates load in all sorts of ways - remember that the server is streaming everything to him, from sending placeable info for every one he perceives, to the more commonly considered script load. Put another way, you don't need players to see this problem, just too much load - and even a little is too much.ShaDoOoW wrote...
Players shouldn't be the cause, because even right after server restart on the first server when I log in as first player the issue is there. Freshly restarted with NWNX, explain this. And there arent so many players on HG as well because they are scattered between multiple servers.
Funky
#12
Posté 15 décembre 2010 - 12:01
This doesnt seem to match the server I described, really.FunkySwerve wrote...
Players cause load. Load causes this. Even a single player creates load in all sorts of ways - remember that the server is streaming everything to him, from sending placeable info for every one he perceives, to the more commonly considered script load. Put another way, you don't need players to see this problem, just too much load - and even a little is too much.
Funky
#13
Posté 15 décembre 2010 - 05:30
Frankly, the server that doesn't really fit with what I've observed of this issue is the 5-15 player server (with regular crashes and no NPC despawn). Could they be running a psuedo fix without you knowing it?
Funky
Modifié par FunkySwerve, 15 décembre 2010 - 05:32 .
#14
Posté 15 décembre 2010 - 11:37
No they can't. I know this server very well, its very old it was created before expansions and even CEP. Thats why they dont have it until now yet. After years it became changed by various new wbs but their scripting skills was often not great, but anyway I played there and that issue was never there. But problem with crashes they become to have recently, I believe its the toll for heavy using of bioware db. Also they in past (yet 2 years back) have 50+ players and it was verry laggy, but aoes worked great all the time. I still checking their forum even though I dont playe there anymore because the last few WB groups totally screwed it out.FunkySwerve wrote...
Frankly, the server that doesn't really fit with what I've observed of this issue is the 5-15 player server (with regular crashes and no NPC despawn). Could they be running a psuedo fix without you knowing it?
Funky
Oh and btw max level is 30 because they never finished new areas since expansions came out.
Modifié par ShaDoOoW, 15 décembre 2010 - 11:40 .
#15
Posté 16 décembre 2010 - 03:18
Those crashes sound like the result of exploded bioware databases. See here for the extent of my knowledge on that:
Click Here
Funky
Modifié par FunkySwerve, 16 décembre 2010 - 03:19 .
#16
Posté 16 décembre 2010 - 08:19
Its czech only specific server which is passworded on gamespy because they are running on game portal which uses special program to join the game where players can chat. All conversations are in my language so I don't think it would be even playable for you, might be quite tricky to get the password since its changed every restart.FunkySwerve wrote...
What server is this? I'd like to take a look. From what you describe, I just can't believe they're working (as opposed to simply getting tripped onenter, which always works).
Those crashes sound like the result of exploded bioware databases. See here for the extent of my knowledge on that:
Click Here
Funky
For the bioware database, they have special treatment, they described it on this picture and thats the best script they are most proud of.
#17
Posté 17 décembre 2010 - 03:48
When I hosted Worlds of Rhun, a 100mb + module, the issue exists with the Native Peristent AOE spells.
Web, Grease, Storm of Vengeance.
In order to fix it, I needed to copy the hb scripts, into functions, that then called themselves, and have themselves, the hb, initiated on the SpellCast script, opposed to the default method, of letting the persistent object handling the heartbeat.
The issue is not necessarily related to player load either.
It can be related to objects, npcs, and anything else that uses the native scripting heartbeat.
Eg - Shayan's subrace engine 3.0 REFUSES to work in Rhun Modules, if you try to use the Subrace Clock placeable. However, if you attach the Subrace Clock's HB Script to the players 'default' script (which is the player heartbeat), it will work, because this script has a much higher priority.
On the grand scheme of things, Persisent AOE Objects have a priority of about -4 compared to everything else.
If your server is going to decide on using resources to run this pretty low priority AOE script, or to Run all the NPC HB, object HB scripts..... its going to choose the npc' and Objects.
Note - As much as we might like to think that nwserver.exe can do dozens of things at once, in reality... it cant. Hense why it needs to prioritize.
#18
Posté 17 décembre 2010 - 05:05
TSM Dude mentioned FRC. They share a similar fate. As soon as they get somewhere between 16-20 players online, AoEs begin to falter and their HBs simply fail above 30 or so (and 30+ is their norm most times of the day). FRC has been doing alot of optimizing and house cleaning of late and lag is getting better, IE lessening. Heartbeats had been a plague on FRC. They just recently killed the CEP "torch" scripts that were causing about 1900+ firings constantly. Even though these scripts simply fired and returned as no variables had been set on the placeables to make use of them properly, that was still a ton of fire/abort every heartbeats happening. You couldn't even actually count them in the completed module. The full module only showed about 20 percent of that total firing. Upon dissecting the module into several small chunks though, those HBs that never fired now fired more often and a better count was gained.
Anyhow, my main point is, any module that has to reset often has some sort of issue they are addressing. So while AoEs might work there, would they if they didn't reset 3-5 times a day?
#19
Posté 17 décembre 2010 - 10:32
Ha! I am quite sure the Arhalia server (low players and has this issue) have many placeables running this. Will suggest them how to get rid of it, and we will see.kalbaern wrote...
CEP "torch"
#20
Posté 18 décembre 2010 - 06:28
As for the rest, by way of comparison, we run a lot of delaycommands, which eats into our load budget, and run a mod heartbeat that is not-quite-but-nearly as hefty as I'm comfortable making it (but adds very slick functionality to the mod). We don't see much lag unless parties mass whole areas (generating about 100 hostile critters at one go). But, we just moved to better hosting (formerly on Amazon EC2), so will have to re-benchmark, since even that no longer generates noticeable server lag. Anyway, on the old servers, despite the lack of noticeable lag, we hit this issue with somewhere between 3-5 players on. I should note that we cap our instance servers at 16 to avoid getting ugly lag - the spawn size we feature wasn't allowing more, though on the new server 100+ spawns in the same area as a party of 10 isn't making lag.
kalbaern wrote...
I spawn/despawn all placeables that use a heartbeat to keep their impacts low).
This doesn't work, if you're suffering load. As I note above, the priority for spawned in placeable hearbeats is, like that for PAoEs, incredibly low. I know because we tried the same thing. Instead, you need to fire up psuedos on the places when players enter the area, and terminate when they're no longer in the area.
Funky
Modifié par FunkySwerve, 18 décembre 2010 - 06:31 .





Retour en haut







