Author Topic: Script for spawning/despawning NPCs on client enter/exit of map  (Read 319 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0


               Wondering if anyone has a script that can spawn NPCs in an area if they aren't spawned already when a player enters the area, and despawns them when the player leaves the area if there are no other PCs in that area?
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Script for spawning/despawning NPCs on client enter/exit of map
« Reply #1 on: June 28, 2011, 12:10:07 am »


               This is what most people use. NESS:

nwvault.ign.com/View.php

And someone reuploaded it with a demo mod here:

nwvault.ign.com/View.php
               
               

               


                     Modifié par GhostOfGod, 27 juin 2011 - 11:14 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Script for spawning/despawning NPCs on client enter/exit of map
« Reply #2 on: June 28, 2011, 01:18:54 am »


               Thank you ghost. I found an updated version here:
http://www.lrjonline.net/swg/ness.html
but sadly the link to the tutorial is broken.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Script for spawning/despawning NPCs on client enter/exit of map
« Reply #3 on: June 28, 2011, 01:45:42 am »


               Here's a chunk from our generic onenter, which goes on every area in the module:



    /* 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);
            }
        }
    }

Code is acaos', and very elegant. You can basically spawn what you want where you want. For example, here are the variables that spawn in two creatures in the area in question:

Area_Spawns int 2        /* indicates two NPC spawnins in this area */
Area_Spawn_1_Loc string @ele_water_m2s      /* indicates location of the first spawn, a waypoint named  ele_water_m2s */
Area_Spawn_1_Res string ele_portalwater /*indicates resref of the first spawn */
Area_Spawn_1_Tag string ele_water_s2m /* indicates what the tag of the first spawn should be set to - this allows you to spawn in multiple creatures of the same resref at different points without the script mixing them up */
Area_Spawn_2_Loc string @ele_water_m2d  /* waypoint location of second spawn */
Area_Spawn_2_Res string ele_portalwater /*resref of second spawn, same as first */
Area_Spawn_2_Tag string ele_water_d2m /* tag to set on second spawn */
This example shows how you can ensure only one of each NPC spawns in, even when using the same resref more than once.

Here's the entire onexit. You won't be able to use it, as there are missing includes, but you can see what gets despawned and what doesn't. The NPCs from the onenter script Have a Despawn int 1 set on them - you could set up a much simpler loop just to eliminate anything with that int set on it, if you liked.


#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;

        }
    }
}

Hope that helps. Let me know if you have questions.

Funky
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Script for spawning/despawning NPCs on client enter/exit of map
« Reply #4 on: June 28, 2011, 02:45:39 am »


               Thank you FunkySwerve.