Heartbeat script question
TheTinman
Member Posts: 75
How taxing would this script be on an area?
// Tinmans Heartbeat area respawner test script
// Created 12\8\2023
void main()
{
// Get the object type of the object that runs the script
int nObjectType = GetObjectType(OBJECT_SELF);
// Check if the object is a placeable
if (nObjectType == OBJECT_TYPE_PLACEABLE)
{
// Use the Tag of a Standard Creature
// Use the resref of a Custom Creature
string sTag = GetTag(OBJECT_SELF);
// Check if the object has a local variable named “DO_ONCE”
if (GetLocalInt(OBJECT_SELF, "DO_ONCE") == 0)
{
// Set the variable to 1, so the script will not fire again
SetLocalInt(OBJECT_SELF, "DO_ONCE", 1);
// We run this section only once
CreateObject (OBJECT_TYPE_CREATURE, sTag, GetLocation (OBJECT_SELF), FALSE);
}
// Check if the object is an area
if (nObjectType == OBJECT_TYPE_PLACEABLE)
{
nObjectType = GetObjectType(OBJECT_SELF);
// Get the area object
object oArea = GetArea(OBJECT_SELF);
// Get the first creature in the area
object oCreature = GetFirstObjectInArea(oArea);
// The delay time for the spawner script
float fDelay = 20.0;
// Loop through all creatures in the area
while (GetIsObjectValid(oCreature))
{
// Check if the creature is dead
if (GetIsDead(oCreature))
{
// Increment the delay time by 7 seconds
//fDelay += 7.0;//Not sure i will use this option
// Get the tag of the creature
string sTag = GetTag(oCreature);
// Find the closest placeable with the same tag as the creature
object oClosestPlaceable = GetNearestObjectByTag(sTag, oCreature);
// Check if the placeable is valid
if (GetIsObjectValid(oClosestPlaceable))
{
// Reset the variable of the closest placeable to 0
DelayCommand(fDelay, SetLocalInt(oClosestPlaceable, "DO_ONCE", 0));
}
}
// Get the next creature in the area
oCreature = GetNextObjectInArea(oArea);
}
}
}
}
0
Comments
void main() { int nObjectType = GetObjectType(OBJECT_SELF); if (nObjectType == OBJECT_TYPE_PLACEABLE) { string sTag = GetTag(OBJECT_SELF); if (GetLocalInt(OBJECT_SELF, "DO_ONCE") == 0) { SetLocalInt(OBJECT_SELF, "DO_ONCE", 1); CreateObject (OBJECT_TYPE_CREATURE, sTag, GetLocation (OBJECT_SELF), FALSE); } // Check if the object is an area // I don't think this should be used on an area. And that's another OBJECT_TYPE_PLACEABLE check. // This should be in the first if statement or a check for a different type. (or !=) if (nObjectType == OBJECT_TYPE_PLACEABLE) { // GetObjectType(OBJECT_SELF) will return the same thing it already is. nObjectType = GetObjectType(OBJECT_SELF); object oArea = GetArea(OBJECT_SELF); // Get the first creature in the area // This can return placeables. Probably need to check if it's a creature. object oCreature = GetFirstObjectInArea(oArea); float fDelay = 20.0; while (GetIsObjectValid(oCreature)) { if (GetIsDead(oCreature)) { string sTag = GetTag(oCreature); object oClosestPlaceable = GetNearestObjectByTag(sTag, oCreature); if (GetIsObjectValid(oClosestPlaceable)) { DelayCommand(fDelay, SetLocalInt(oClosestPlaceable, "DO_ONCE", 0)); } } oCreature = GetNextObjectInArea(oArea); } } }To me it looks like you will need one placeable for every one creature you want to respawn.
Would it be easier to make a waypoint with a tag and a variable and the do_once variable?
On heartbeat go through all the waypoints with that tag. If not do_once, spawn the creature stored in the variable. I suppose you would need to modify the onDeath script of the creature to reset the do_once variable of the correct waypoint. I've done a very similar thing but with placeables. They don't move, so I can with confidence call GetNearestObjectByTag when the placeable gets destroyed.
You might consider storing the spawning placeable object on the spawned creature. You'd know exactly which placeable the creature needs to reset. Then you could clear the do_once thing in the on death handler of the creature and not have to loop through everything (actually... assign the delay command to the placeable since the creature will likely be gone and so the delayed command will go away).
If you want to do it in the placeable HB, have the placeable store the creature object so it can easily check its creature (since you seem to have this 1:1).
That way, you minimise how many items the script has to deal with and therefore how long it takes to run.
// Tinmans Heartbeat area respawner test script // Created 12\8\2023 // This script runs on the areas heartbeat void main() { // Get the area object that is running this script object oArea = OBJECT_SELF; // Get the first object in the area object oObject = GetFirstObjectInArea(oArea); // Loop through all the objects in the area while (GetIsObjectValid(oObject)) { // Check if the object is a placeable object if (GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE) { // Get the tag of the placeable object string sTag = GetTag(oObject); // Check if the placeable object has not spawned a creature yet if (GetLocalInt(oObject, "DO_ONCE") == 0) { // Set a local variable on the placeable object to prevent multiple spawns SetLocalInt(oObject, "DO_ONCE", 1); // Create a creature object with the same tag as the placeable object at its location object oCreature = CreateObject (OBJECT_TYPE_CREATURE, sTag, GetLocation (oObject), FALSE); // Set a local variable on the creature object to store a reference to the placeable object SetLocalObject(oCreature, "SPAWNER", oObject); } } // Check if the object is a creature object and if it is dead if (GetObjectType(oObject) == OBJECT_TYPE_CREATURE && GetIsDead(oObject)) { // Set the current hit points of the creature object to 1 to prevent it from disappearing // Used to offset the creature decay time and the area heartbeat SetCurrentHitPoints(oObject, 1); // Get the reference to the placeable object that spawned the creature object object oSpawner = GetLocalObject(oObject, "SPAWNER"); // Check if the reference is valid if (GetIsObjectValid(oSpawner)) { // Set a delay of 20 seconds float fDelay = 20.0; // Add 7 seconds to the delay // fDelay += 7.0; // Not sure I will use this feature // After the delay, reset the local variable on the placeable object to allow another spawn DelayCommand(fDelay, SetLocalInt(oSpawner, "DO_ONCE", 0)); } } // Get the next object in the area oObject = GetNextObjectInArea(oArea); } }object GetObjectByTag(string, int);
Finds objects based on the object's tag.
You'd be better off if you gave all of the spawn objects the same tag, searched only for the objects with that tag, then used a string variable on the spawn object as the ResRef of the creature to spawn. The script would have a lot less work to do, that way, taking up a lot less time to run due to not having to run as many instructions.
The following is just to illustrate what I was thinking of. It doesn't do the delay you wanted (except that it would delay until the body of the creature vanishes, so you could "fudge it" by making the body decay time be the time you wanted until respawn). This is a module heartbeat script.
void main() { string sFind="creaturespawner";// The tag of all of the creature spawn placeables object oThing=GetObjectByTag(sFind,0);// Find the first one string sMakeIt=GetLocalString(oThing,"SPAWN");// Get the tag of what to spawn object oWhat=GetLocalObject(oThing,"MADE");// check for an object ID in case it's already spawned int iIndex=1;// Point to the next creature spawn placeable while(GetIsObjectValid(oThing))// Loop until no more creature spawn placeables { if(!GetIsObjectValid(oWhat))// Only do the next two instructions if the creature does not exist { oWhat=CreateObject(OBJECT_TYPE_CREATURE,sMakeIt,GetLocation(oThing));// Create the creature where the placeable is SetLocalObject(oThing,"MADE",oWhat);// Set the object pointer to the created creature so we can try to find it later } oThing=GetObjectByTag(sFind,iIndex++);// Find the next creature spawn placeable, if any sMakeIt=GetLocalString(oThing,"SPAWN");// Find out what to spawn there oWhat=GetLocalObject(oThing,"MADE");// Find the creature of the last creature spawned here, if any was. }// Loop until there are no more spawn placeables left to look through }I expect you would be able to modify this code to match exactly what you want it to do.In any game of respectable length, you'll quickly run into the dreaded "Too Many Instructions" error. If you override that with the system setting, every heartbeat will cause your game to pause which will make it unplayable. It will only work if your game is just a few areas with hardly any placeable objects.
Once the variable is not reset on the placeable will it take some of the load off of this script?
My second guess would be that the body has despawned sometimes by the time your script gets around to that creature. That's why I use the object pointer instead of the actual creature in order to detect whether or not it's dead.
I'll see if I can come up with something which will do everything you want, although I'm a little puzzled about why you aren't just using an encounter, since you can spawn a single creature reliably that way, and set it to infinite respawn, and set the respawn delay?