Author Topic: Which function is faster?  (Read 571 times)

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Which function is faster?
« on: July 28, 2011, 10:14:54 pm »


               I'm in the process of try to streamline some scripts, and I'm looking for the quickest way to determine if an area is in use. Currently I place a variable on the area once a PC or DM enters it, which gets removed on a timer-delayed function in the area's OnExit event which checks to make sure no PCs are still in it after someone leaves. 

So if I need something's heartbeat script in the area to determine if there are actually real-live PCs in that area, is it quicker to use the GetLocalInt(oArea, "AreaInUse") function to retrieve the variable set on the area? Or is the GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC) faster?

My gut reaction is GetNearestCreature is more intensive and slower, but I'd just like confirmation if anyone knows for sure.

Thanks!
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Which function is faster?
« Reply #1 on: July 28, 2011, 11:12:06 pm »


               Forget about "whats faster" and rather think about "whats more realiable"

And since its possible that PC wont fire then OnExit event of area, then only looping all players either via

GetFirst/NextPC and checking their location or using GetNearestCreature but there is a new issue with this function since patch 1.69 and thats the fact that if you dont enter second condition for CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC then it counts like IS_ALIVE?, YES so you must use it twice and with IS_ALIVE, NO to be sure. Thats why I prefer GetFirst/NextPC way.
               
               

               


                     Modifié par ShaDoOoW, 28 juillet 2011 - 10:12 .
                     
                  


            

Legacy_Axe_Murderer

  • Full Member
  • ***
  • Posts: 199
  • Karma: +0/-0
Which function is faster?
« Reply #2 on: July 29, 2011, 12:46:36 am »


               Totally agree with ShaDoOoW about the reliability of OnExit and a local int, but I'd say two calls to GetNearest with iNth set to 1 is better than a loop through every player if you expect more than just a couple of players online on average.

Although there are some performance differences, I doubt you would notice anything no matter which of the methods you choose...unless you are doing it quite often. I'd question whether a heartbeat is the right place for such a check, but then I don't know the application you need it for so...
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Which function is faster?
« Reply #3 on: July 29, 2011, 12:57:04 am »


               Thanks guys, but why is the OnExit unreliable? Like if a PC logs out it doesn't fire or something?

And what do you mean by the IS_ALIVE flag must be set? Is it that calls need to look like the following to make sure there is a nearby PC?
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsObjectValid(oPC)) oPC = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, FALSE);
               
               

               


                     Modifié par Thayan, 28 juillet 2011 - 11:57 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Which function is faster?
« Reply #4 on: July 29, 2011, 01:13:06 am »


               Have to disagree, Axe. Looping players is very fast - looping getnearest isn't SLOW, but it's almost definitely slower than looping a pre-established list, since it involves measuring distances. I have not, however, run a speed comparison, and I doubt the difference is all that large either way, regardless of the number of pcs logged in.

Here's the area exit we use, ending with the check to tell if an area is empty - ShaDoOow is quite right that your first concern should be reliability. Anything below this in the code would not execute if there were still pcs in the area.


void main () {
    object oPC = GetExitingObject();
    object oObject, oArea = OBJECT_SELF;

    /* deplot everything leaving an area, to prevent invulnerability exploits -
     * exceptions for BBoD, DMs, and intentionally invulnerable summons */
    if (GetResRef(oPC) != "x2_s_bblade" && !GetLocalInt(oPC, "FKY_CHAT_INVULN") && !GetLocalInt(oPC, "PlotSummons"))
        SetPlotFlag(oPC, FALSE);

    /* destroy all dominated creatures unless specifically allowed to transition */
    if (!GetIsPC(oPC)                                  &&
        GetHasEffectOfType(EFFECT_TYPE_DOMINATED, oPC) &&
        !GetLocalInt(oPC, "DomTransition")) {

        DestroyObject(oPC);
        return;
    }

    /* only players and DMs are tagged with ID */
    if (GetLocalString(oPC, "ID") == "" || GetIsDM(oPC))
        return;

    /* fire off custom script for area exit if specified */
    string sExecuteExit = GetLocalString(oArea, "Area_OnExit");
    if (sExecuteExit != "")
        ExecuteScript(sExecuteExit, oArea);

    /* de-AFK players on any transition */
    DeleteLocalInt(oPC, "FKY_CHAT_AFK");
    DeleteLocalObject(oPC, "FKY_CHAT_BULK_TARGET");

    if (GetHasSpellEffect(HGEFFECT_AREA_PENALTIES, oPC)) {
        RemoveEffectsFromSpell(HGEFFECT_AREA_PENALTIES, oPC);
        CheckLegendaryBABEffect(oPC);
    }

    /* remove supernatural darkness from area */
    RemoveEffectsOfType(EFFECT_TYPE_DARKNESS, oPC, oArea);

    /* removes effects of underwater bubbles if any */
    if (GetHasSpellEffect(HGEFFECT_UNDERWATER_BUBBLES, oPC))
        RemoveEffectsFromSpell(HGEFFECT_UNDERWATER_BUBBLES, oPC);


    /* scan to see if there are any PCs left in the area */
    oPC = GetFirstPC();
    while (GetIsObjectValid(oPC)) {
        if (GetArea(oPC) == oArea && oPC != oArea && !GetIsDM(oPC))
            return;

        oPC = GetNextPC();
    }

Funky
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Which function is faster?
« Reply #5 on: July 29, 2011, 03:39:57 am »


               Thanks for the code snippets Funky - always appreciated! '<img'>

OK, so on my area OnExit, I use a DelayCommand to call the following function (which looks similiar to yours Funky) several minutes after a PC leaves the area. I delay the call to this because I don't want areas immeidately cleaned to avoid PCs farming an area by leaving and then immediately returning. If this function returns FALSE when it gets called several minutes after a PC leaves the area, it then removes the "InUse" variable set on the area and then my main area cleaning function gets called. Is this a 'reliable' way to handle removing that variable?

int GetIsAreaOccupied(object oArea)
{
  if (GetIsObjectValid(oArea)) {
      object oPlayer = GetFirstPC();
      while (GetArea(oPlayer) != oArea && oPlayer != OBJECT_INVALID) oPlayer = GetNextPC();
      if (oPlayer != OBJECT_INVALID) return TRUE;
      else return FALSE;
  }
  return FALSE;
}

if (!GetIsAreaOccupied(OBJECT_SELF)) {
  //Set the area InUse variable to FALSE and run through the rest of the area cleaning script
}

If so, then back to what I am originally trying to accomplish is to have things that run heartbeat scripts in that area (like the few static NPCs we have placed, or the ambient anvils or bookshelves we have placed) to check for either the "InUse" variable on the area and immediately end (return) if it is not there. My original question then - is it faster to have those heartbeat scripts use GetLocalInt to retrieve the "InUse" variable on the area, or should I have the GetNearestPC function check if there is an actual valid PC in the area on each heartbeat?

Or are these heartbeats all a huge waste of resources anyway and I should I reqrite those scripts and call them as psuedoheartbeats OnAreaEnter?
               
               

               
            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
Which function is faster?
« Reply #6 on: July 29, 2011, 07:16:54 am »


               why don't you timestamp it when the player leave. An in my opinion this feature isn't critical so any missed onexit isn't that much of a deal. aslong as you have selfrepairing system. ie it verify the number of player once in a while so the "missed" players will not keep the system glitchy. what is the worst that can happen the last player leaves and the area remain "active" that would only prevent thing from reseting, not a major deal. Most of the time it will work. and if that happens, a new or the old player will repair it an perhaps never notice that something went wrong.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Which function is faster?
« Reply #7 on: July 29, 2011, 08:10:23 am »


               A simple delaycommand is all you need, if you adopt your approach. If, after your delay, the area is clear, you despawn. If not, there's another pc in there, and another onexit will be fired, triggering another check. No pseudo or timestamp needed.

Frankly, though, if you're trying to prevent farming, our system works quite well. We despawn, and mark the area with the time of despawn. Despawners are marked with the number despawned, and if it raises above a handful (missed creature allowance) loot containers may respawn, but our universal loot script checks for the despawn timestamp and, unless it's been long enough, they spawn junk loot, rather than the stuff players want to farm. If it HAS been long enough, the despawn stamp is deleted. This requires code both onexit and onenter. Here's the full onexit.


#include "hg_inc"

#include "afx_sfunc"
#include "ac_qstatus_inc"
#include "legendarybab_inc"
#include "gen_interact_inc"

void TrashObject (object oObject) {
    if (GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE) {
        /* search and destroy contents of placeables */

        object oItem = GetFirstItemInInventory(oObject);

        while (GetIsObjectValid(oItem)) {
            SetPlotFlag(oItem, FALSE);
            DestroyObject(oItem);

            oItem = GetNextItemInInventory(oObject);
        }
    }

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


/* -------------------- remove this section once the new loot system is in place -------------------- */
void RespawnObject(string sTag, int iType, location lLoc, int nLoot = 0) {
    object oPlace = CreateObject(iType, sTag, lLoc);

    if (nLoot != 0)
        SetLocalInt(oPlace, "RLoot", nLoot);
}

void DespawnRespawn(object oObject, float fDelay) {
    SetPlotFlag(oObject, FALSE);
    TrashObject(oObject);
    string sTag = GetResRef(oObject);
    int iType = GetObjectType(oObject);
    location lLoc = GetLocation(oObject);

    /* if this is set to 1, object spawns random loot, tag should be preserved */
    int nLoot = GetLocalInt(oObject, "RLoot");

    /* added nLoot paramenter to Respawn function to pass locals to respawned
     * version (avoids having to set them in the object palettes) */
    if (fDelay < 8000.0)
        AssignCommand(GetArea(oObject), DelayCommand(fDelay, RespawnObject(sTag, iType, lLoc, nLoot)));
}
/* -------------------- end section to be removed -------------------- */


void main () {
    object oPC = GetExitingObject();
    object oObject, oArea = OBJECT_SELF;

    /* deplot everything leaving an area, to prevent invulnerability exploits -
     * exceptions for BBoD, DMs, and intentionally invulnerable summons */
    if (GetResRef(oPC) != "x2_s_bblade" && !GetLocalInt(oPC, "FKY_CHAT_INVULN") && !GetLocalInt(oPC, "PlotSummons"))
        SetPlotFlag(oPC, FALSE);

    /* destroy all dominated creatures unless specifically allowed to transition */
    if (!GetIsPC(oPC)                                  &&
        GetHasEffectOfType(EFFECT_TYPE_DOMINATED, oPC) &&
        !GetLocalInt(oPC, "DomTransition")) {

        DestroyObject(oPC);
        return;
    }

    /* only players and DMs are tagged with ID */
    if (GetLocalString(oPC, "ID") == "" || GetIsDM(oPC))
        return;

    /* fire off custom script for area exit if specified */
    string sExecuteExit = GetLocalString(oArea, "Area_OnExit");
    if (sExecuteExit != "")
        ExecuteScript(sExecuteExit, oArea);

    /* de-AFK players on any transition */
    DeleteLocalInt(oPC, "FKY_CHAT_AFK");
    DeleteLocalObject(oPC, "FKY_CHAT_BULK_TARGET");

    if (GetHasSpellEffect(HGEFFECT_AREA_PENALTIES, oPC)) {
        RemoveEffectsFromSpell(HGEFFECT_AREA_PENALTIES, oPC);
        CheckLegendaryBABEffect(oPC);
    }

    /* remove supernatural darkness from area */
    RemoveEffectsOfType(EFFECT_TYPE_DARKNESS, oPC, oArea);

    /* removes effects of underwater bubbles if any */
    if (GetHasSpellEffect(HGEFFECT_UNDERWATER_BUBBLES, oPC))
        RemoveEffectsFromSpell(HGEFFECT_UNDERWATER_BUBBLES, oPC);


    /* scan to see if there are any PCs left in the area */
    oPC = GetFirstPC();
    while (GetIsObjectValid(oPC)) {
        if (GetArea(oPC) == oArea && oPC != oArea && !GetIsDM(oPC))
            return;

        oPC = GetNextPC();
    }

    SetLocalInt(oArea, "Area_Clear", 1);

    /* fire off custom script for pc-free area if specififed */
    string sExecuteClear = GetLocalString(oArea, "Area_OnClear");
    if (sExecuteClear != "")
        ExecuteScript(sExecuteClear, oArea);

    /* reset any interaction triggers in need of it, and shut off any interactions
       marked for area-exit shutoff */
    int nTriggerResetCount = GetLocalInt(oArea, "Interact_Triggers_To_Reset");
    if (nTriggerResetCount) {

        int nX, nY, nZ, nInteractions, nObjMask;
        object oTriggerToReset, oLoop;
        string sObjTag;
        for (nX = 1; nX <= nTriggerResetCount; nX++) {

            oTriggerToReset = GetLocalObject(oArea, "Interact_Trigger_Reset_" + IntToString(nX));
            nInteractions = GetLocalInt(oTriggerToReset, "Interact_Count");
            for (nY = 1; nY <= nInteractions; nY++) {

                if (GetLocalInt(oTriggerToReset, "Interact_Trigger_Shutoff_" + IntToString(nY)) == 2)
                    DeleteLocalInt(oTriggerToReset, "Interact_Off_" + IntToString(nY));
                if (GetLocalInt(oTriggerToReset, "Interact_Interaction_Shutoff_" + IntToString(nY)) == 2) {
                    sObjTag = GetLocalString(OBJECT_SELF, "Interact_Object_Tag_" + IntToString(nY));
                    if (sObjTag == "")
                        sObjTag = "gen_interact_obj";
                    nObjMask = GetLocalInt(OBJECT_SELF, "Interact_Object_Mask_" + IntToString(nY));
                    nZ = 1;
                    oLoop = GetNearestObjectByTag(sObjTag, oTriggerToReset, 1);
                    while (GetIsObjectValid(oLoop)) {

                        if ((GetLocalInt(oLoop, "Interact_Object_Mask") & nObjMask) &&
                            (GetLocalInt(OBJECT_SELF, "Interact_Interaction_Shutoff_"
                                + IntToString(nY)) == 1))
                            ShutOffInteraction(oLoop, nY);

                        nZ++;
                        oLoop = GetNearestObjectByTag(sObjTag, oTriggerToReset, nZ);
                    }
                }
            }
        }
    }


    /* despawn the entire area */
    int bArena = GetLocalInt(oArea, "Arena");
    int nUptime = GetLocalInt(GetModule(), "uptime");
    int nDespawn, bDespawnTracking = GetLocalInt(oArea, "DespawnTrack");
    int bNoDespawnCreatures = GetLocalInt(oArea, "NoDespawnCreatures");
    string sBoss;

    for (oObject = GetFirstObjectInArea(oArea);
         GetIsObjectValid(oObject);
         oObject = GetNextObjectInArea(oArea)) {

        switch (GetObjectType(oObject)) {
            case OBJECT_TYPE_PLACEABLE:
                /*
                if (GetTag(oObject) == "BodyBag" || GetLocalInt(oObject, "Despawn"))
                    TrashObject(oObject);
                 */

                /* ---- remove this section once the new loot system is in place ---- */
                nDespawn = GetLocalInt(oObject, "fkydespawn");

                if (GetTag(oObject) == "BodyBag" || nDespawn < 0)
                    TrashObject(oObject);
                else if (nDespawn)
                    DespawnRespawn(oObject, IntToFloat(nDespawn));

                /* ---- end section to be removed ----------------------------------- */
                break;

            case OBJECT_TYPE_ITEM:
                if (!bArena)
                    TrashObject(oObject);
                break;

            case OBJECT_TYPE_CREATURE:
                if (GetIsPC(oObject) || GetIsPC(GetMaster(oObject)) || bNoDespawnCreatures)
                    break;

                if ((sBoss = GetLocalString(oObject, "TrapArea_Waypoint")) != "") {
                    location lSelf = GetLocation(oObject);
                    object oTrapped, oTrapArea = GetArea(GetWaypointByTag(sBoss));
                    string sMessage = GetLocalString(oObject, "TrapArea_Escape");

                    if (GetIsObjectValid(oTrapArea)) {
                        for (oTrapped = GetFirstPC(); GetIsObjectValid(oTrapped); oTrapped = GetNextPC()) {
                            if (GetArea(oTrapped) == oTrapArea) {
                                SendMessageToPC(oTrapped, sMessage);
                                ForceJump(oTrapped, lSelf);
                            }
                        }
                    }
                }

                if ((sBoss = GetLocalString(oObject, "QSDeathTag")) != "") {
                    struct SubString ss = GetFirstSubString(sBoss, "~");

                    if (ss.first != "")
                        QSSetQuestStatus(ss.first, StringToInt(ss.rest) * -1);

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

                /* delete NPCs, encounter creatures, and spawned in
                 * creatures (with Despawn set). Don't delete creatures that
                 * have a PC as a master, as summons and dominates could be destroyed
                 * before they can zone out with their master. */
                if ((nDespawn = GetLocalInt(oObject, "Despawn")) ||
                    (GetIsEncounterCreature(oObject) && !GetIsPC(GetMaster(oObject)))) {

                    if (nDespawn >= 0 && bDespawnTracking) {
                        AddLocalInt(oArea, "DespawnCount", 1);
                        SetLocalInt(oArea, "DespawnTime", nUptime);
                    }

                    TrashObject(oObject);
                }
                break;

            case OBJECT_TYPE_TRIGGER:
                if (GetLocalInt(oObject, "Despawn"))
                    TrashObject(oObject);
                break;

        }
    }
}

               
               

               


                     Modifié par FunkySwerve, 29 juillet 2011 - 07:11 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Which function is faster?
« Reply #8 on: July 29, 2011, 08:12:25 am »


               Here's the onenter:


#include "hg_inc"
#include "hg_area_inc"
#include "hg_antiex_inc"
#include "fky_environ_inc"
#include "ac_qstatus_inc"

#include "tsk_inc"

void DoAreaEffects (object oArea, object oPC, int nDamAmount, int nDamType, int nDamVis, string sMessage) {
    if (GetArea(oPC) != oArea)
        return;

    if (!GetIsDead(oPC) && !GetPlotFlag(oPC)) {
        if (nDamType < 0) {
            if (nDamType == -1) {
                int nBreath = GetCanBreatheWater(oPC, TRUE);

                if (nBreath == 2)
                    return;

                if (!nBreath) {
                    if (GetLocalInt(oPC, "Area_WaterBreath_Warning") < 3) {
                        FloatingTextStringOnCreature("You cannot hold your breath much longer!", oPC, FALSE);
                        AddLocalInt(oPC, "Area_WaterBreath_Warning", 1);
                    } else {
                        FloatingTextStringOnCreature("You can no longer hold your breath!", oPC, FALSE);
                        DeleteLocalInt(oPC, "Area_WaterBreath_Warning");

                        ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath()), oPC);
                    }
                } else
                    DeleteLocalInt(oPC, "Area_WaterBreath_Warning");
            } else if (nDamType == -2) {
                int nLev = GetCanLevitate(oPC);

                if (nLev == 2)
                    return;

                if (!nLev) {
                    if (!GetIsResting(oPC))
                        FloatingTextStringOnCreature("You are unable to control your motion in the air!", oPC, FALSE);

                    RemoveEffectsOfType(EFFECT_TYPE_CUTSCENEIMMOBILIZE, oPC, oArea);

                    effect eEff = SupernaturalEffect(EffectCutsceneImmobilize());
                    DelayCommand(0.01, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEff, oPC, 9.0));
                }
            } else if (nDamType == -3) {
                /* passwall; do nothing */
                return;
            } else if (nDamType == -4) {
                int nFirewalk = GetCanFirewalk(oPC);

                if (nFirewalk == 2)
                    return;

                if (!nFirewalk) {
                    FloatingTextStringOnCreature("You are unable to breathe elemental fire!", oPC, FALSE);

                    ApplyDirectDamage(oPC, (GetMaxHitPoints(oPC) * 2) / 5, DAMAGE_TYPE_INTERNAL,
                                      DAMAGE_POWER_ENERGY, "Elemental Fire", "You burn to a crisp!");
                    ApplyVisualToObject(VFX_IMP_FLAME_M, oPC);
                }
            }
        } else {
            effect eDam = EffectDamage(d10(nDamAmount), nDamType);
            effect eVis = EffectVisualEffect(nDamVis);

            ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oPC);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);

            if (sMessage != "")
                FloatingTextStringOnCreature(sMessage, oPC, FALSE);
        }
    }
    DelayCommand(6.0, DoAreaEffects(oArea, oPC, nDamAmount, nDamType, nDamVis, sMessage));
}

void DoDust (object oPC, object oItem) {
    SetPlotFlag(oItem, FALSE);
    DestroyObject(oItem);
    CreateItemOnObject("drowdust", oPC);
}

object GetVFXLoopTarget (object oSource, string sTarget) {
    int nCount = 1;
    struct SubString ss = GetFirstSubString(sTarget, "#");

    if (ss.rest != "") {
    }

    return GetNearestObjectByTag(ss.first, oSource, nCount);
}

float GetVFXLoopVaryingFloat (float fRand) {
    int nVary = FloatToInt(fRand * 100.0);
    nVary = Random((nVary * 2) + 1) - nVary;

    return (nVary * 0.01);
}

void VoidBroadcastProjectileToObject (object oSource, object oTarget, int nSpellId, int nDelay) {
    BroadcastProjectileToObject(oSource, oTarget, nSpellId, nDelay);
}

void DoVFXLoop (object oVFX, int nVis, float fCyc, float fDur, string sTarget, int bBeam,
                float fCycRand, float fDurRand, int nMulti, float fMultiInt, float fMultiRand) {
    if (GetLocalInt(OBJECT_SELF, "Area_Clear")) {
        AddLocalInt(OBJECT_SELF, "Area_VFX_Active", -1);
        return;
    }

    if (nMulti > 1) {
        /* ugly to have a second copy, but removes unnecessary delaycommands */
        int i;
        float fDelay = 0.0;

        for (i = 0; i < nMulti; i++) {
            float fDurVary = GetVFXLoopVaryingFloat(fDurRand);

            if (sTarget != "") {
                object oTarget = GetVFXLoopTarget(oVFX, sTarget);

                if (bBeam) {
                    effect eBeam = EffectBeam(nVis, oVFX, BODY_NODE_CHEST, (bBeam == 2));
                    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam, oTarget, fDur + fDurVary));
                } else if (nVis < 0) {
                    DelayCommand(fDelay, VoidBroadcastProjectileToObject(oVFX, oTarget, -nVis, FloatToInt((fDur + fDurVary) * 1000.0)));
                } else if (fDur > 0.0) {
                    effect eVis = EffectVisualEffect(nVis);
                    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget, fDur + fDurVary));
                } else {
                    DelayCommand(fDelay, ApplyVisualToObject(nVis, oTarget));
                }
            } else {
                if (fDur > 0.0) {
                    effect eVis = EffectVisualEffect(nVis);
                    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oVFX, fDur + fDurVary));
                } else {
                    DelayCommand(fDelay, ApplyVisualToObject(nVis, oVFX));
                }
            }

            fDelay += fMultiInt + GetVFXLoopVaryingFloat(fMultiRand);
        }
    } else {
        float fDurVary = GetVFXLoopVaryingFloat(fDurRand);

        if (sTarget != "") {
            object oTarget = GetVFXLoopTarget(oVFX, sTarget);

            if (bBeam) {
                effect eBeam = EffectBeam(nVis, oVFX, BODY_NODE_CHEST, (bBeam == 2));
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam, oTarget, fDur + fDurVary);
            } else if (nVis < 0) {
                BroadcastProjectileToObject(oVFX, oTarget, -nVis, FloatToInt((fDur + fDurVary) * 1000.0));
            } else if (fDur > 0.0) {
                effect eVis = EffectVisualEffect(nVis);
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oTarget, fDur + fDurVary);
            } else {
                ApplyVisualToObject(nVis, oTarget);
            }
        } else {
            if (fDur > 0.0) {
                effect eVis = EffectVisualEffect(nVis);
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, oVFX, fDur + fDurVary);
            } else {
                ApplyVisualToObject(nVis, oVFX);
            }
        }
    }

    float fCycVary = GetVFXLoopVaryingFloat(fCycRand);
    DelayCommand(fCyc + fCycVary, DoVFXLoop(oVFX, nVis, fCyc, fDur, sTarget, bBeam, fCycRand, fDurRand, nMulti, fMultiInt, fMultiRand));
}


void main () {
    object oPC = GetEnteringObject();
    object oArea = GetArea(oPC);

    if (GetIsPC(oPC)) {
        DeleteLocalInt(oArea, "Area_Clear");

        int bReveal = GetLocalInt(oArea, "Area_Reveal");
        if (bReveal > 0)
            ExploreAreaForPlayer(oArea, oPC, TRUE);
    }

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

    /* execute specific onenter script if specified */
    string sScript = GetLocalString(oArea, "Area_OnEnter");
    if (sScript != "")
        ExecuteScript(sScript, oArea);

    /* PC-only stuff below here */
    if (!GetIsPC(oPC))
        return;

    if (GetLocalInt(oArea, "Area_VFX_Objects") > 0 &&
        GetLocalInt(oArea, "Area_VFX_Active") == 0) {

        int i, nObjects = GetLocalInt(oArea, "Area_VFX_Objects");
        object oVFX;

        for (i = 0; i < nObjects; i++) {
            oVFX = GetLocalObject(oArea, "Area_VFX_Object_" + IntToString(i));
            if (GetIsObjectValid(oVFX)) {
                int    nVis       = GetLocalInt(oVFX,    "VFX_Loop");
                int    nMulti     = GetLocalInt(oVFX,    "VFX_Loop_Multi");
                int    bBeam      = GetLocalInt(oVFX,    "VFX_Loop_Beam");
                float  fCyc       = GetLocalFloat(oVFX,  "VFX_Loop_Cycle");
                float  fCycRand   = GetLocalFloat(oVFX,  "VFX_Loop_Cycle_Vary");
                float  fDur       = GetLocalFloat(oVFX,  "VFX_Loop_Dur");
                float  fDurRand   = GetLocalFloat(oVFX,  "VFX_Loop_Dur_Vary");
                float  fMultiInt  = GetLocalFloat(oVFX,  "VFX_Loop_Multi_Int");
                float  fMultiRand = GetLocalFloat(oVFX,  "VFX_Loop_Multi_Int_Vary");
                string sTarget    = GetLocalString(oVFX, "VFX_Loop_Target");

                AddLocalInt(oArea, "Area_VFX_Active", 1);
                AssignCommand(oArea, DelayCommand(fCyc, DoVFXLoop(oVFX, nVis, fCyc, fDur, sTarget, bBeam, fCycRand, fDurRand, nMulti, fMultiInt, fMultiRand)));
            }
        }
    }

    /* if the PC is not allowed in the area, boot them and return */
    if (!CheckAreaTagRequirement(oArea, oPC))
        return;

    string sQuest = GetLocalString(oArea, "Area_Quest");
    if (sQuest != "")
        QSAddQuestStatus(sQuest, 1);

    /* for Hell and Limbo areas, set the Succor_ local */
    if (GetLocalInt(oArea, "notele") > 0)
        SetLocalInt(oPC, "Succor_" + GetResRef(oArea), 1);


    /* area damage/underwater areas */
    /* TODO: enhance this to be more generic, e.g. Hells penalties */
    if (!GetIsDM(oPC)) {
        int nDamType = GetLocalInt(oArea, "Area_Damage_Type");
        if (GetLocalInt(oArea, "Area_Underwater"))
            nDamType = -1;
        else if (GetLocalInt(oArea, "Area_Aerial"))
            nDamType = -2;
        else if (GetLocalInt(oArea, "Area_Passwall"))
            nDamType = -3;
        else if (GetLocalInt(oArea, "Area_Firewalk"))
            nDamType = -4;

        if (nDamType) {
            int nDamAmount  = GetLocalInt(oArea, "Area_Damage_Amount");
            int nDamVis     = GetLocalInt(oArea, "Area_Damage_VFX");
            string sMessage = GetLocalString(oArea, "Area_Damage_Message");

            AssignCommand(oArea, DoAreaEffects(oArea, oPC, nDamAmount, nDamType, nDamVis, sMessage));
        }


        /* destroy items that cannot survive in daylight */
        if (GetIsDay()                &&
            !GetIsAreaInterior(oArea) &&
            GetIsAreaAboveGround(oArea)) {

            int i;
            object oItem;

            for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
                oItem = GetItemInSlot(i, oPC);

                if (GetStringLeft(GetTag(oItem), 4) == "asdf")
                    DoDust(oPC, oItem);
            }

            if (GetIsObjectValid(oItem = GetItemPossessedBy(oPC, "sealofshadows")))
                DestroyObject(oItem);
        }
    }


    /* spawn anything specified in area locals */
    int nSpawns = GetLocalInt(oArea, "Area_Spawns");
    string sTask;
    struct IntList li;

    if (nSpawns > 0) {
        int i, nType;
        string sKey, sTag, sRes, sLoc, sLocType;
        object oSpawn;
        location lSpawn;

        for (i = 1; i <= nSpawns; i++) {
            sKey = "Area_Spawn_" + IntToString(i);
            sTag = GetLocalString(oArea, sKey + "_Tag");


            /* if the object has already been spawned, skip it */
            if (sTag != "") {
                if (GetIsObjectValid(GetNearestObjectByTag(sTag, oPC)))
                    continue;
            } else {
                if (GetIsObjectValid(GetLocalObject(oArea, sKey + "_Obj")))
                    continue;
            }


            sRes  = GetLocalString(oArea, sKey + "_Res");
            sLoc  = GetLocalString(oArea, sKey + "_Loc");
            nType = GetLocalInt(oArea, sKey + "_Type");

            if (nType == 0)
                nType = OBJECT_TYPE_CREATURE;

            sLocType = GetStringLeft(sLoc, 1);


            if (sLocType == "!")
                lSpawn = GetLocation(GetNearestObjectByTag(GetSubString(sLoc, 1, 64), oPC));
            else if (sLocType == "@")
                lSpawn = GetLocation(GetWaypointByTag(GetSubString(sLoc, 1, 64)));
            else if (sLocType == "&") {//designates task creature, only spawn if pc requires (uses waypoint)  ex: tsk_cr_1_2
                sTask = GetStringRight(sRes, (GetStringLength(sRes) - 7));
                li = GetIntList(sTask, "_");
                if (!GetPCHasTaskActive(oPC, li.i0) || (GetTaskCompleted(oPC, li.i0) != (li.i1 - 1)))//if they don't have the task active, don't spawn
                    continue;
                else
                    lSpawn = GetLocation(GetWaypointByTag(GetSubString(sLoc, 1, 64)));
            } else
                continue;


            if (GetAreaFromLocation(lSpawn) == oArea) {
                oSpawn = CreateObject(nType, sRes, lSpawn, FALSE, sTag);
                SetLocalObject(oArea, sKey + "_Obj", oSpawn);
            }
        }
    }


    /* respawn loot or other other respawnables */
    nSpawns = GetLocalInt(oArea, "Area_Respawns");

    if (nSpawns > 0) {
        int i, nType, nRespawnTime, nUptime = GetLocalInt(GetModule(), "uptime");
        string sKey, sVar;
        object oSpawn;

        for (i = 1; i <= nSpawns; i++) {
            sKey = IntToString(i);

            nRespawnTime = GetLocalInt(oArea, "Area_Respawn_" + sKey);
            if (nRespawnTime <= 0 ||
                nRespawnTime > nUptime ||
                GetIsObjectValid(GetLocalObject(oArea, "Area_Respawn_Obj_" + sKey)))
                continue;

            oSpawn = CreateObject(GetLocalInt(oArea, "Area_Respawn_Type_" + sKey),
                GetLocalString(oArea, "Area_Respawn_Res_" + sKey),
                GetLocalLocation(oArea, "Area_Respawn_Loc_" + sKey));

            SetLocalObject(oArea, "Area_Respawn_Obj_" + sKey, oSpawn);

            if ((sVar = GetLocalString(oArea, "Area_Respawn_Var_" + sKey)) != "")
                AssignCommand(oArea, DelayCommand(0.0, RestoreLocals(oSpawn, sVar)));
        }
    }

    /* clear despawn setting on area */
    if (GetLocalInt(oArea, "DespawnTrack")) {
        int nDespawnTime = GetLocalInt(oArea, "DespawnTime");
        if (nDespawnTime) {
            int nUptime = GetLocalInt(GetModule(), "uptime");
            if ((nUptime - 3600) > nDespawnTime) {
                DeleteLocalInt(oArea, "DespawnTime");
                DeleteLocalInt(oArea, "DespawnCount");
            }
        }
    }
}


LMK if you have any questions. "uptime" is incremented in the mod heartbeat.

Funky
               
               

               
            

Legacy_Thayan

  • Sr. Member
  • ****
  • Posts: 435
  • Karma: +0/-0
Which function is faster?
« Reply #9 on: July 29, 2011, 09:41:43 pm »


               Wow - thanks for the examples Funky. It's always nice seeing what the big boys use. It definitely helps as a benchmark to what I'm doing, if nothing else.

I will likely be changing the area OnExit to clean the areas immediately if no PCs are in it. There's probably more sense to do that than having an area running at full capacity for the several minutes delay when no PCs are in it anyway. Then I'll just tie into my hearbeat scripts and set them to return right away if the area use variable is not set.

My head has been spinning the last several weeks as Thay's player numbers have grown and continue to average decent numbers (for us). While this is a great, it has also led to an increase in lag and the headaches that go with trying to eliminate some of it. So I'm glad to hear new perspectives in looking at making things more efficient.
               
               

               


                     Modifié par Thayan, 29 juillet 2011 - 08:53 .