Author Topic: Making Onheartbeat happen in only one area  (Read 391 times)

Legacy_Fallyn Rayne

  • Newbie
  • *
  • Posts: 34
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« on: December 11, 2011, 02:36:23 pm »


               Hi Everyone,

I have an underwater area where the goal is to make the pc lose 2 hp per round while underwater.
I set the following script on the area's onheartbeat.

void main()
{

object oPC = GetEnteringObject();

effect eEffect;
eEffect = EffectDamage(2, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_NORMAL);

ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC);

}


The problem is that it happens in any area that I'm in now. I thought that it was only supposed to happen in the one area since I set it on that area's onheartbeat. Is there something else I need to do to make this happen only in the area I assign it to? Thanks!
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #1 on: December 11, 2011, 03:32:26 pm »


                 I would likely go with a pseudo HB triggered off the areas OnEnter, rather than a HB script.  I just did these up quickly, but they should do what you want when used placed into the area's on enter.  Both need to be put into the script, the DrownHB function above the main, since I didn't bother with a prototype for it.


// Pseudo HB for area drown effect.
void DrownHB (object oArea = OBJECT_SELF)
{
 effect eEffect = EffectDamage(2, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_NORMAL);
 int nActive = FALSE;
 int nRace;
 object oPC = GetFirstPC();
 while (GetIsObjectValid (oPC))
    {
     if (GetArea (oPC) == oArea)
        {
         nActive = TRUE;
         nRace   = GetRacialType (oPC);
         // Racial check, so clever PCs that can shift to a form that doesn't breathe
         // are immune to the "drowning" damage.
         // comment out if you don't want to use it.
         if (nRace != RACIAL_TYPE_CONSTRUCT && nRace != RACIAL_TYPE_UNDEAD)
            {
             ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC);
            }
        }
     oPC = GetNextPC();
    }
 // If a PC is in the area, repeat the pseudo HB again in 6 seconds.
 // Else, end it, and remove the variable to get it ready for the next entering PC.
 if (nActive)
    {
     DelayCommand (6.0, DrownHB() );
    }
 else
    {
     DeleteLocalInt (OBJECT_SELF, "ACTIVE");
    }
}
void main()
{
 object oPC = GetEnteringObject();
 if (GetIsPC (oPC) && !GetLocalInt (OBJECT_SELF, "ACTIVE"))
    {
     SetLocalInt (OBJECT_SELF, "ACTIVE", TRUE);
     DrownHB ();
    }
}
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #2 on: December 11, 2011, 08:34:00 pm »


                The reason it's doing it in all areas is because you changed the script and saved it.If you open your other areas, you'll see that they call the same script.I think most people do something like Failed Bard did.
However, here are a couple of other choices:
1: Open the area properties and add a variable to the area. Type INT. Name "Underwater". Set it to 1.Use this code:
void main()
{
   object oPC = GetEnteringObject(); 
    if (GetLocalInt(OBJECT_SELF, "Underwater"))
   {     
         effect eEffect;      eEffect = EffectDamage(2, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_NORMAL);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC); 
   }
}
This will only run the code block on the area with the underwater variable.

The other way would be to open your script and hit the "Save As" button instead of save. Choose a new name such as "are_hb_unwtr". Use that script on your underwater areas hb.
Delete that block of code from your other script since your other areas use it.

If you're already doing that and it's still running in all areas, there is an odd problem somewhere.

EDIT: 
It looks like Failed Bards code also needs to use one of my sugestions along with it. Otherwise it'll always run. 
GetArea(OBJECT_SELF) will always be the same as GetArea(oPC) in any areas hb. You need to make sure that you only run it in underwater areas by using either a variable or a unique script. That way, the pseudo hb will end when they go to a new area.
Also, in this block of code from Failed Bard:

 // If a PC is in the area, repeat the pseudo HB again in 6 seconds.
 // Else, end it, and remove the variable to get it ready for the next entering PC.
    if (nActive)
   {
       DelayCommand (6.0, DrownHB() );
   }

We need to make sure that it passes the same area back in to the function call. Otherwise, it'll grab the current area that the PC is in and it may never stop unless it tries to check while the PC is loading a new area.

 // If a PC is in the area, repeat the pseudo HB again in 6 seconds.
 // Else, end it, and remove the variable to get it ready for the next entering PC.
    if (nActive)
    {
       // Passing in the same area
       DelayCommand (6.0, DrownHB(oArea) );
    }
               
               

               


                     Modifié par wyldhunt1, 11 décembre 2011 - 08:59 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #3 on: December 11, 2011, 10:17:19 pm »


               The only thing I see wrong with Faild Bards code at quick glance is that it will only work for a single player game.  

In wyldhunt1's post I see several misconceptions about how the nwnengine works. Let me break that post down to explaine.

Quote
wyldhunt1 wrote...

 The reason it's doing it in all areas is because you changed the script and saved it.If you open your other areas, you'll see that they call the same script...

I dout that this is the case.   Area HB scripts fire every round reguardless of there being a PC in the area or not. If the OP had there script in every areas HB they would have been taking 2 points of damage per area in the module per round.

Quote
I think most people do something like Failed Bard did.
However, here are a couple of other choices:
1: Open the area properties and add a variable to the area. Type INT. Name "Underwater". Set it to 1.Use this code:
void main()
{
   object oPC = GetEnteringObject(); 
    if (GetLocalInt(OBJECT_SELF, "Underwater"))
   {     
         effect eEffect;      eEffect = EffectDamage(2, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_NORMAL);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC); 
   }
}
This will only run the code block on the area with the underwater variable.

First GetEnteringObject is not a valid accessor for a HB script.   It does have a chance of getting the last PC that entered the area.  but even then it would only be the last PC that entered.  Most of the time this script would just be firing with an invalid PC, It would be a wast of CPU time.


Quote
The other way would be to open your script and hit the "Save As" button instead of save. Choose a new name such as "are_hb_unwtr". Use that script on your underwater areas hb.
Delete that block of code from your other script since your other areas use it.

If you're already doing that and it's still running in all areas, there is an odd problem somewhere.

Like said above, there is no reason to ever have the same HB script running in several areas. HB scripts run every round reguardless of there being a PC in the area (or even the module for that matter)  or not.   The only object  HB script in the game that can be turned on and off are the HB scripts  attached to encounters.   encounters that are active fire there HB scripts, encounters that are inactive do not.

EDIT: 
It looks like Failed Bards code also needs to use one of my sugestions along with it. Otherwise it'll always run. 
GetArea(OBJECT_SELF) will always be the same as GetArea(oPC) in any areas hb. You need to make sure that you only run it in underwater areas by using either a variable or a unique script. That way, the pseudo hb will end when they go to a new area.[/quote]
To me it looked like FB's script was checking the area against the area the PC is currently in.  The HB is running on the area (OBJECT_SELF)  and checking to see if the PC left the area (GetArea(oPC))  I do not see the problem.     

Quote
Also, in this block of code from Failed Bard:

 // If a PC is in the area, repeat the pseudo HB again in 6 seconds.
 // Else, end it, and remove the variable to get it ready for the next entering PC.
    if (nActive)
   {
       DelayCommand (6.0, DrownHB() );
   }

We need to make sure that it passes the same area back in to the function call. Otherwise, it'll grab the current area that the PC is in and it may never stop unless it tries to check while the PC is loading a new area.

 // If a PC is in the area, repeat the pseudo HB again in 6 seconds.
 // Else, end it, and remove the variable to get it ready for the next entering PC.
    if (nActive)
    {
       // Passing in the same area
       DelayCommand (6.0, DrownHB(oArea) );
    }

FB's code was fine No reason to pass the area since the psedo HB he was using was running on the Area not the PC.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #4 on: December 11, 2011, 10:47:20 pm »


               

Fallyn Rayne wrote...

Hi Everyone,

I have an underwater area where the goal is to make the pc lose 2 hp per round while underwater.
I set the following script on the area's onheartbeat.

void main()
{

object oPC = GetEnteringObject();

effect eEffect;
eEffect = EffectDamage(2, DAMAGE_TYPE_NEGATIVE, DAMAGE_POWER_NORMAL);

ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC);

}


The problem is that it happens in any area that I'm in now. I thought that it was only supposed to happen in the one area since I set it on that area's onheartbeat. Is there something else I need to do to make this happen only in the area I assign it to? Thanks!


The problem you are running into is the HB script runs reguardless PC's being in the area or not.   I think (Do not see the need to double check it)  location the GetEnteringObject(); function checks is in the data structure of the module object.   Meaning in multiplayer your script could even change the one PC who it is applying damage to. The PC taking the damage be the one who last triggered any of the onEnter events.  

FB's code above looks like it will work,  However it will only work for a single player module.  The question is,  Is this for a single player module or for a multi player module?

There are many way to do it.   The Area's HB script is not the way to go though.  If you did want to use a single HB script to handle it, the Module's HB would be better for the sole reason that you only want one of them firing and it is just easier to track down and find there.   In that case you just loop through all the PC's in the module and check to see if they are in an under water area or not. 

wyldhunt1 suggestions above where good, It just looked like he misunderstood that HB scripts fire all the time.    What you basicly need is a way to tell what area's are underwater and wich one are not.   The int set on the area is as good of a method as any.    

I myself would do it one of two ways.  Either create a module HB script that regestered the PC's in underwater areas with it let it handle the damage and removing them from its list when they left the water.  Or the Pseudo Hb applyed to the PC OnArea Enter.    The OnAreaEnter would need to check if the PC already had the pseudo HB running on it or not,  else you could end up with the PC taking double damage.   The Pseudo would only need to check if the PC was still in an underwater area, if he is apply the damage and recall its self, if not remove the varaiable the OnEnter set on the PC so to stop the pseudo from getting applied twice and exit.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #5 on: December 11, 2011, 11:05:58 pm »


               

Lightfoot8 wrote...
HB scripts run every round reguardless of there being a PC in the area (or even the module for that matter)  or not.   The only object  HB script in the game that can be turned on and off are the HB scripts  attached to encounters.   encounters that are active fire there HB scripts, encounters that are inactive do not.


Objects in an area do not fire heart beat scripts when there is no PC in the area.  Outside of that, heartbeats for areas and module should be universal.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #6 on: December 11, 2011, 11:10:45 pm »


               

WhiZard wrote...

Lightfoot8 wrote...
HB scripts run every round reguardless of there being a PC in the area (or even the module for that matter)  or not.   The only object  HB script in the game that can be turned on and off are the HB scripts  attached to encounters.   encounters that are active fire there HB scripts, encounters that are inactive do not.


Objects in an area do not fire heart beat scripts when there is no PC in the area.  Outside of that, heartbeats for areas and module should be universal.


You are wrong,  Placeables do fire the HB scripts,  Even if there is no PC.   Now they my be getting cut out if there are to many scripts firring in the module,  But that is due to low priority.
               
               

               


                     Modifié par Lightfoot8, 11 décembre 2011 - 11:11 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #7 on: December 11, 2011, 11:14:31 pm »


               

Lightfoot8 wrote...

WhiZard wrote...

Lightfoot8 wrote...
HB scripts run every round reguardless of there being a PC in the area (or even the module for that matter)  or not.   The only object  HB script in the game that can be turned on and off are the HB scripts  attached to encounters.   encounters that are active fire there HB scripts, encounters that are inactive do not.


Objects in an area do not fire heart beat scripts when there is no PC in the area.  Outside of that, heartbeats for areas and module should be universal.


You are wrong,  Placeables do fire the HB scripts,  Even if there is no PC.   Now they my be getting cut out if there are to many scripts firring in the module,  But that is due to low priority.


Nope tested this with the placeable created with deck of hazards (for the plague effect).  The magical plague damage only takes place if there is a PC in the area.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #8 on: December 11, 2011, 11:26:36 pm »


               lol. Ok I made a new module, created only two areas. Placed one placeable in each area, with a HB script on it to reports its name + HB to the log file. here is my log out put with no PC in the server.


[Sun Dec 11 18:21:27] Loading Module: HB test
[Sun Dec 11 18:21:33] Plac 1 HB
[Sun Dec 11 18:21:33] Plac 2 HB
[Sun Dec 11 18:21:39] Plac 2 HB
[Sun Dec 11 18:21:39] Plac 1 HB
[Sun Dec 11 18:21:45] Plac 2 HB
[Sun Dec 11 18:21:45] Plac 1 HB
[Sun Dec 11 18:21:51] Plac 2 HB
[Sun Dec 11 18:21:51] Plac 1 HB
[Sun Dec 11 18:21:57] Plac 2 HB
[Sun Dec 11 18:21:57] Plac 1 HB
[Sun Dec 11 18:22:03] Plac 1 HB
[Sun Dec 11 18:22:03] Plac 2 HB
[Sun Dec 11 18:22:09] Plac 2 HB
[Sun Dec 11 18:22:09] Plac 1 HB
[Sun Dec 11 18:22:15] Plac 1 HB
[Sun Dec 11 18:22:15] Plac 2 HB
[Sun Dec 11 18:22:21] Plac 1 HB
[Sun Dec 11 18:22:21] Plac 2 HB


EDIT; Question is there a filter on the decks placable to filter the damage if no PC is in the area?
               
               

               


                     Modifié par Lightfoot8, 11 décembre 2011 - 11:31 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #9 on: December 11, 2011, 11:36:45 pm »


               

Lightfoot8 wrote...

lol. Ok I made a new module, created only two areas. Placed one placeable in each area, with a HB script on it to reports its name + HB to the log file. here is my log out put with no PC in the server.


[Sun Dec 11 18:21:27] Loading Module: HB test
[Sun Dec 11 18:21:33] Plac 1 HB
[Sun Dec 11 18:21:33] Plac 2 HB
[Sun Dec 11 18:21:39] Plac 2 HB
[Sun Dec 11 18:21:39] Plac 1 HB
[Sun Dec 11 18:21:45] Plac 2 HB
[Sun Dec 11 18:21:45] Plac 1 HB
[Sun Dec 11 18:21:51] Plac 2 HB
[Sun Dec 11 18:21:51] Plac 1 HB
[Sun Dec 11 18:21:57] Plac 2 HB
[Sun Dec 11 18:21:57] Plac 1 HB
[Sun Dec 11 18:22:03] Plac 1 HB
[Sun Dec 11 18:22:03] Plac 2 HB
[Sun Dec 11 18:22:09] Plac 2 HB
[Sun Dec 11 18:22:09] Plac 1 HB
[Sun Dec 11 18:22:15] Plac 1 HB
[Sun Dec 11 18:22:15] Plac 2 HB
[Sun Dec 11 18:22:21] Plac 1 HB
[Sun Dec 11 18:22:21] Plac 2 HB


EDIT; Question is there a filter on the decks placable to filter the damage if no PC is in the area?


No filter on the plague heartbeat.  But I finally did get it to work. (Should have waited the full 15 rounds),  but yes it works as does the hatchling placeable and the premonition placeable all created by the deck of hazards.  I guess I need to speak to The Krit about his wikia posting, which describes OnHeartBeat event to only work on objects in the area if there is a PC also.

EDIT: Oops looks like this was done by Enigmatic not The Krit, all the way back in 2005.
               
               

               


                     Modifié par WhiZard, 11 décembre 2011 - 11:43 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #10 on: December 12, 2011, 12:57:51 am »


               I noticed a queer incident happening when I was in a different area than a creature, and I was wondering if you could shed light on it.

I set up an area with a trigger and a monster both sending a message by HB script.  In that area the creature and trigger sent the message every six seconds.

When in a different area the trigger sent its message once every six seconds, while the creature sent its message once every 8-9 seconds.

Is there a separate frequency being used whether or not a PC is in the same area?
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #11 on: December 12, 2011, 01:26:57 am »


               Now that gets into an area I have not fully explored yet.    It really comes down to the priority of the events.   Here is my basic understanding, with my very limited knowlage on the subject.

Every Object has a priority factor.  

when scripts are ran they are ran by object.  

when a round starts all the scripts/Events on the hightest priority Object run first.  On down the line.  

Now I have hear many people on the old boards say that once the round was over (6 sec) the cache of scripts still to be ran is cleared out for the new round to start.  

I know that this is not as True as stated on the old forums.  In the PW I was running rounds where taking 10 seconds to compleate from all the scripts running.   Still I know some where never getting ran consistantly.  

The Priority order I can at this point only guess at.  
I am pretty sure the module is highest.  
Followed by areas.
then creatures
placeables
then doors somewhere towards the end.  

Yea, only a partial list, and i am no where 100 % on any of it.    
I would assume, Or at least hope that there was something in there to up the priority of objects in an area with PC's in them.  But I just do not know.   \\

The differance you are seeing may just be from More happen in the Higher priority scripts in some rounds compaired to others.  

Sorry, I just really do not know the answer on this one.    It is the area of the engine I am digging into,  If I ever find the time again. For now I just do not know.
               
               

               
            

Legacy_DragonTayl

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #12 on: December 12, 2011, 02:44:23 am »


               I thought I remembered talk of this back when NwN was still live and being patched. I thought in one of the updates Bioware had specifically done just what you're talking about - given server priority to areas with PCs in them. Of course, I couldn't find that post now if I wanted to, but I do remember talking about it with my fellow developers at the time. We had guards walking beats between zones and they would start bunching because the ones with PCs in their zones would walk faster. Areas with no PCs in them were not completely ignored, but they got a lower priority.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #13 on: December 12, 2011, 03:48:28 am »


               

Lightfoot8 wrote...
Sorry, I just really do not know the answer on this one.    It is the area of the engine I am digging into,  If I ever find the time again. For now I just do not know.


Priority is a nice theory, but I had far too few objects to cause a good 2-3 second extra wait time.  When I spawned in hostile creatures into the remote area I switched to who had HB scripts going at full blast the excess time didn't seem to change.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Making Onheartbeat happen in only one area
« Reply #14 on: December 13, 2011, 02:06:31 pm »


               

WhiZard wrote...

Lightfoot8 wrote...
Sorry, I just really do not know the answer on this one.    It is the area of the engine I am digging into,  If I ever find the time again. For now I just do not know.


Priority is a nice theory, but I had far too few objects to cause a good 2-3 second extra wait time.  When I spawned in hostile creatures into the remote area I switched to who had HB scripts going at full blast the excess time didn't seem to change.


I have isolated the creature heartbeat issue in non-PC areas down to the AI level used.  Creature AI levels that register as AI_LEVEL_VERY_LOW (which includes default/invalid AI in an area without player characters) will use a 9 second heart beat.  All other creature AI levels use the 6 second heartbeat.  Default/Invalid AI level in an area with player characters registers as AI_LEVEL_LOW.