Author Topic: UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)  (Read 536 times)

Legacy_MagicalMaster

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


               I developed this system for my recent February Adventure Building Challenge module, Siege of the Heavens to display health percentages and increase the maximum health a creature can have.  I figured other people might find it useful so I thought I'd share it.  You should be able to easily integrate the health percentage half into any module (regardless if you built it) - can easily install it in any module in a few minutes at most - while the massive health pools part takes slightly more work, mainly if you want healing to work properly with it.

Installation is literally this for the health percentages:

1. Download file from vault
2. Open module in toolset
3. Import erf with the script
4. Copy/paste one line of code into the OnSpawn script
5. Copy/paste a six line block of code into the OnPerception script

Done!

-----------------------------------------------------------------------------

Vault Page: http://nwvault.ign.c....Detail&id=3879

Video below is slightly out of date - the general concept is the same but the script is called in the OnPerception instead of OnSpawn and the script shuts down if no PCs are in the creature's area. See change log for v1 to v2.

Video Demonstration:

------------------------------------------------------------------------------

UpdateHP is a system with two primary features - the ability to display the health percentage of creatures and to allow effective hit points far beyond what the toolset can provide by default (toolset limit is roughly 13,000 whereas this system can support a little over two billion if somehow needed) without actually appearing to do anything special.  These two features are independent - you can use either or both of them as you desire.  The system can also be used to defend against the default Devastating Critical - see "Immortality" under Miscellaneous Information (though using the entire script for just that purpose is somewhat overkill).  The system is extremely easy to set up and configure in general, though if you use MassiveHP there are some special details you should know (regarding interaction with other scripts/effects, primarily healing and extreme burst damage).

In general, the system works by starting the script once the creature perceives an enemy or PC.  It then checks the creature every second (the frequency can be adjusted as per your needs).  If the creature's hit points have changed (taken damage or been healed) and the health percentage has changed, it updates the creature's health percentage.  If MassiveHP is enabled and the creature's hit points have changed, it updates the creature's effective hit points.  If hit points have not changed, it simply checks again in a second.  The checking speeds up to every half second if the creature is using MassiveHP and is below 3000 raw hit points.

If there are no PCs in the with the creature, the script shuts down and starts back up once the creature perceives another enemy or PC.  This prevents the script from using resources when it does not need to be running (it does not start until needed and stops when not needed).

If you use this system, I ask that you do not make major modifications to the script without asking me - I would prefer to be able to incorporate any significant improvements into the base system so everyone can take advantage of it (giving credit for the improvement, of course).  This does not apply to the frequency at which the script runs, adjust that as you would like.  There is also a function called "Special" which can be freely customized to suit your module if you need something special done every time the bulk of the script runs.  And, of course, feel free to comment out either ShowHP or MassiveHP if you only care about one of the features.  Thank you.

Have fun!

--------------------------------------------------------------------------

Version 4 is up.  Needed to fix a potential bug introduced in v3 that ONLY occurs if you use the advanced option. Specifically, the advanced option would call the script on any creature in the area, even if the script was not meant to run on the creature. New version will only run on creatures who previously had the script running on them.

- Fixed bug in advanced option introduced in v3 that would call the script on any creature in the area, even those who weren't meant to have the script run on them (potentially henchmen, summons, etc). No impact if you weren't using the advanced option

Version 3 is up.  Chunk of code provided to cover a fringe scenario.  Extra work to install for little gain, but possible if you want to cover it (more details in ReadMe under "Advanced Option"):

- Chunk of code provided in script header to place in OnEnter script for areas to avoid having an incorrect health percentage for a few seconds if a player attacks a regenerating creature and retreats (leaving the area entirely) without killing it and returns before the monster despawns (player would see an incorrect health percent for a few seconds upon returning before the script started running again)

Version 2 is up. Takes one additional (simple) step to install with the following improvements:

- Called with OnPerception when an enemy or PC approaches to avoid using resources until needed
- Shuts down if all PCs leave the creature's area and starts back up when approached again
- Calls itself every second by default once triggered (compared to previous 0.5 seconds), speeding up to 0.5 seconds if the creature is using MassiveHP and below 3000 raw hit points
               
               

               


                     Modifié par MagicalMaster, 18 mars 2013 - 07:03 .
                     
                  


            

Legacy_ffbj

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


               Really Cool!  Thanks.  Personally I would not mind a 30k hp monster only being healed back to 20k.
I suppose WM doing 2k a hit would be justification enough for something like this, why in the world did they ever made that possible.  Oh well!
               
               

               
            

Legacy_MagicalMaster

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


               Vault page is up.  Thanks, Rolo.

ffbj wrote...

Really Cool!  Thanks.  Personally I would not mind a 30k hp monster only being healed back to 20k.


Fair enough!  If if you change your mind, healing to full health is simple - just heal the monster to full natural hp and set the "hpbonus" int to "hpmax" - 10000.

In general, you just also need to increment the "hpbonus" int by however much you want to heal and make sure the current hit points plus "hpbonus" don't exceed "hpmax."  It mainly gets tricky when you cross one of the health thresholds if you're trying to make the illusion perfect - if the monster is at 4999 actual HP, 9000 bonus HP, and thus 13999 effectuive HP, you don't want to heal the ACTUAL hit points by 500, you want to increment the bonus (so it stays at Badly Wounded).

On the flip side, if the monster is at 4999 actual HP, 10000 bonus HP, and thus 14999 effective HP...you'd WANT to heal the actual HP by 500, because it SHOULD transition back up to Injured.

Again, that's mainly about preserving the illusion - simply incrementing "hpbonus" (as long as actual HP + "hpbonus" doesn't exceed "hpmax") will always provide the correct amount of healing, it just won't look exactly perfect.

ffbj wrote...

I suppose WM doing 2k a hit would be justification enough for something like this, why in the world did they ever made that possible.  Oh well!


That's with mundane gear too, sadly: http://nwnecbguild.4...22-t515455.html

If you're on a world with high weapon enhancements and tons of bonus damage, the numbers can get far higher.
               
               

               


                     Modifié par MagicalMaster, 14 mars 2013 - 09:45 .
                     
                  


            

Legacy_Shadooow

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


               i managed to make 20k hp boss simply via gff edit raising the bonusHP above 10k, not sure if there is limit, but seems like a better option than this...
               
               

               
            

Legacy_MagicalMaster

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


               

ShaDoOoW wrote...

i managed to make 20k hp boss simply via gff edit raising the bonusHP above 10k


How universally applicable is that - one of my goals was to make an easy and simple way to accomplish this.

ShaDoOoW wrote...

seems like a better option than this...


Are you concerned with the principle (healing behind the scenes to simulate HP) or the method (psuedo heartbeat every x seconds)?
               
               

               
            

Legacy_Shadooow

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


               
Quote
MagicalMaster wrote...

Quote
ShaDoOoW wrote...

i managed to make 20k hp boss simply via gff edit raising the bonusHP above 10k


How universally applicable is that - one of my goals was to make an easy and simple way to accomplish this.

open the creature utc file from modules/temp0 in GFF editor, modify the field MaxHitPoints, CurrentHitPoints and HitPoints to desired value. Save file, save module, thats it. Little drawback is that this modification is often erased to 10k when that creature is opened and changed in toolset later, but not always probably only in cases when the changes touches HPs.

Quote

Quote
ShaDoOoW wrote...

seems like a better option than this...


Are you concerned with the principle (healing behind the scenes to simulate HP) or the method (psuedo heartbeat every x seconds)?
[/quote]The concept is brilliant the method to accomplish that a litttle less, but given there is easy way to get around that 10k hp limit, I don't see much of use for this.
               
               

               


                     Modifié par ShaDoOoW, 15 mars 2013 - 02:02 .
                     
                  


            

Legacy_ffbj

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


               While your method of fiddiling with the gif to add hits works, it could add a layer of difficulty for some who want to raise hp and offers no additional feedback.  In addition there are  two pieces to  his method. 
I wonder how it would work combined with one of the hitpoint bar graphs.  
               
               

               


                     Modifié par ffbj, 15 mars 2013 - 01:06 .
                     
                  


            

Legacy_Shadooow

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


               

ffbj wrote...

Well he did show how this method could be used to create an absurd 20 billion hit point monster to, to demonstrate the flexibility and capability of this method.  While you would never use such a thing you could create a creature with 100k 200k etc...Somehow your method of fiddiling with the gif to double the creatures hp's up to a max of 20k, a change that, by you own admission, is lost if the creature is edited later on, does not seem to equate with that.  Mainly since at high levels characters can do thousands of points of damage in a round.  It is something mainly for campaigns like higher ground or others with high powered equipment or where you can go beyond 40th level.

i didnt said 20k hp is max, just that thats what I achieved, i expected this cap to be much higher, though now I went to test that and it seems that cap is somewhere around 32ksomething, (meaning bonus hitpoints, still creature can get additonal hitpoints from constitution) 254con = 121mod*180lvl + 180toughness + 200epic toughness + 32k bonus hp = 86160maximum hitpoints in theory (untested)

Dont forget that MM's solution (same as my immunity to dev crit script) has downsides like immunity to any mind-affecting effect, devastating critical hit, death magic etc.

I was admin of a PW like that (legendary levels above 40, magic gear +9) and we didnt needed such absurd numbers especially if you can balance that with high regeneration, damage immunity or damage resistance

but yes - if you insist you need such massive ammount of HPs, than this is a good technique to achieve that
               
               

               
            

Legacy_ffbj

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


               Oh sorry I edited my reply after I reread your earlier response while you were writing it.
I was thinking of ways to make monster tougher too, like you mentioned, immunities and resistance and such. So that seems to make it clear that you addressed the problem as most would, in only way you could. Yeah you could give every powerful monster 90% immunities to everything. As far as immunities to death magic and dev critical, I would weep no tears to see them gone, but maybe that is just me. Immunity to mind effects though is not something I would want.
But tell me how many of you super-powered monsters where immune to such effects?
I am less knowlegable in these high-powered creature areas but it seems useful to me, since as you have indicated you really have to a lot to buff your boss monsters, high regen, immunities, and resists. Just seems like a different approach, and in some ways preferable to the standard methods.
Thanks for the input.
               
               

               


                     Modifié par ffbj, 15 mars 2013 - 01:27 .
                     
                  


            

Legacy_Shadooow

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


               Again the concept is brilliant, but the method of doing that less so. Also for very massive hit points, 10k hp base is not enought to make proper illusion of the default HP percentage so for a more than 100k hp editing the creature's base hitpoint via the method I suggested would be preferred anyway.

My point is that this isnt any big breakthrough since need for massive hitpoints over this 30k is rare circumstance even in extremely high magic really. In cases builder wants more than 30k hp without need to alter constitution/levels from any reason, this would be ideal method though.
               
               

               


                     Modifié par ShaDoOoW, 15 mars 2013 - 02:02 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)
« Reply #10 on: March 15, 2013, 03:44:18 pm »


               

MagicalMaster wrote...
How universally applicable is that - one of my goals was to make an easy and simple way to accomplish this.


It isn't. We're aware of Shad's approach, and we still don't use it, because it's such a pain. Tracking which creatures are modified so that you don't inadvertently revert them just isn't worth it. By contrast, we DO do this with areas, because there's no other way to achieve what gff edits can with them, and because we have to edit them much less often than creatures.

We found regeneration to be a much more palatable alternative. But then, that also seems to be the case with Shad:

ShaDoOoW wrote...
I was admin of a PW like that (legendary
levels above 40, magic gear +9) and we didnt needed such absurd numbers
especially if you can balance that with high regeneration, damage
immunity or damage resistance


That said, I wouldn't use your approach either - it sounds like an immense amount of unnecessary overhead. Was there no way to achieve this via ondamaged?

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)
« Reply #11 on: March 15, 2013, 04:10:49 pm »


               

FunkySwerve wrote...

MagicalMaster wrote...
How universally applicable is that - one of my goals was to make an easy and simple way to accomplish this.


It isn't. We're aware of Shad's approach, and we still don't use it, because it's such a pain. Tracking which creatures are modified so that you don't inadvertently revert them just isn't worth it. By contrast, we DO do this with areas, because there's no other way to achieve what gff edits can with them, and because we have to edit them much less often than creatures.

Right. I have to admit I do use this approach only for a few bosses which also have a huge regeneration as a bonus. Using this approach for a general creatures could be really pain I guess.
               
               

               
            

Legacy_painofdungeoneternal

  • Sr. Member
  • ****
  • Posts: 313
  • Karma: +0/-0
UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)
« Reply #12 on: March 15, 2013, 05:37:31 pm »


               I'd imagine you could implement ShaDoOoW's approach easier by setting variables on the creature, then on loading of the blueprint or other script event, do the adjustment via something like NWNx instead - basically use other tools to do it in a way that does not compete with the toolset, or which undoes any capped values put in by the toolset back to their above the cap values.

( or when the module is assembled via various means if you use a source repository, more like how elven's nwnlib lets you do it, basically dynamically adjust the GFFs via tool to ensure the toolset has not messed anything up. )

But it is a brilliant idea which solves the problem in a new way, and even if it's not used by everyone, it might inspire other similar ideas.
               
               

               
            

Legacy_MagicalMaster

  • Hero Member
  • *****
  • Posts: 2712
  • Karma: +0/-0
UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)
« Reply #13 on: March 15, 2013, 08:39:04 pm »


               

ShaDoOoW wrote...

Dont forget that MM's solution (same as my immunity to dev crit script) has downsides like immunity to any mind-affecting effect, devastating critical hit, death magic etc.


Only if you're worried about the creatures taking >2500 damage between calls of the script, and that's only a worry during the last 25% of the creature's effective health (because otherwise they'd need to take >5000 damage).

And of course it's independent of the health percentage display.

ShaDoOoW wrote...

I was admin of a PW like that (legendary levels above 40, magic gear +9) and we didnt needed such absurd numbers especially if you can balance that with high regeneration, damage immunity or damage resistance


The main problem with damage immunity is that it doesn't play nicely because it's additive.  For example, let's say you make a boss with 50% immunity to everything and also give him Elemental Shield.  Instead of taking 25% damage from Fire and Cold, he takes 0%.  Stuff like that means you need to be careful.  Regeneration can also have issues (such as the boss having more hit points the longer the fight goes on) which need to be considerd.

ShaDoOoW wrote...

Again the concept is brilliant, but the method of doing that less so. Also for very massive hit points, 10k hp base is not enought to make proper illusion of the default HP percentage so for a more than 100k hp editing the creature's base hitpoint via the method I suggested would be preferred anyway.


See below regarding method (in response to Funky).

Why do you think 10k isn't enough to make a proper illusion?  Unless you take 2500 or more damage between calls of the script, the illusion should be (nearly) perfect.

FunkySwerve wrote...

Was there no way to achieve this via ondamaged?


You could remove main, some of the arguments being passed, and the DelayCommand call and stick the UpdateHP funtion in OnDamage (would take like 5-10 minutes to adjust it, I suspect).  However, that does raise additional problems:

1, it won't account for regeneration until you get damaged again (scripted or natural).
2, it won't account for any healing period until you get damaged again, though you could call the UpdateHP function every time a healing spell is cast at the creature or something
3, if you had, say, 10 mages unloading the default IGMS (20 missiles) at a target, that's already calling OnDamaged 200 times in about 3 seconds.  You wouldn't want/need to call this function that often, so you'd probably want to use a local int or something to make sure it doesn't fire more often than every 0.5-1.0 seconds or whatever.

In other words, it'd be workable, but requires more effort to set up and I don't know how much of a performance gain it would be (meaning I really have no idea, not that I'm sure they're roughly equal, see below).

FunkySwerve wrote...

That said, I wouldn't use your approach either - it sounds like an immense amount of unnecessary overhead.


Well, admittedly I understand very little of the technical aspects of NWN - you're the expert in that regard.  My thought process was to make the "heartbeat" extremely extremely simple to avoid the overhead.  The following is all that happens if the creature has NOT taken damage or healing since the previous call.

void UpdateHP(int nPrev, int nMax)
{

    int nCurrent = GetCurrentHitPoints(), nMassive;

    if (nPrev != nCurrent)
    {
    }

    DelayCommand(0.5, UpdateHP(nCurrent + nMassive, nMax));
}

1. Receive the arguments from the previous call
2. Retrieve the current hit points and set up another int called nMassive (which is 0)
3. Compare one of the arguments to currentHP and since they're equal do nothing
4. Call itself again in 0.5 (or 1.0 or 2.0 or whatever) seconds with equivalent arguments (since nMassive is still 0)

The main problem is that I don't know how expensive function calls are (and how DelayCommand affects that).  I assumed they were trivial, but if simply calling the function is a large constant while the work within the function is relatively immaterial, then obviously this approach could be made far more efficient by any of the following:

1, rework it to be put in OnDamaged  (and if the extra code within one script is seriously inconsequential compared to having another script running, then maybe you wouldn't even need the cooldown on running Update (though it might still be a good idea)).

2, have it run every, say, 6 seconds out of combat and every 0.5-1.0 seconds in combat.  I originally had it set up like this but it means you could go 5.99 seconds without any update if the creature entered combat right after the heartbeat ticked.  Not the end of the world, but I wasn't sure how much of a performance improvement it actually was.

3. Check to see whether an enemy is within 50 yards, and if so start running every second.  If not, don't run again for 12-18 seconds or whatever.

4. Only run while an enemy is in the area.  If no enemies are in the area, then stop running.  Start it back up with the OnEnter script for the area if enemies return.

1 and 4 require more work to set up, 2 and 3 have the potential problem of taking a few seconds to kick in.  In 3, for example, if an enemy moves from 51 yards to 30 yards in like 5 seconds and starts attacking with a ranged weapon, it could take 13 seconds for the percent/health pool to start updating.

So, yeah, it largely depends on how the engine handles things (and I don't know).  Is a separate script running a single line of code far more expensive than an existing script running 20 additional lines of code (obviously the actual operations matter, just as a general principle)?  How do psuedo heartbeat functions factor into that?

By default, my script has like 3 main actual operations per heartbeat.  If I added a while loop that checked the surrounding area or something, that would greatly increase the number of operations per heartbeat - but it still might be more efficient overall if the heartbeat itself was very expensive (regardless of the code in it).  #4 in the list up there seems like it might technically be the best solution (in OnExit, set a local int to 1 that indicates UpdateHP should stop running and then in OnEnter set it to 0 and call UpdateHP to restart the process, so only creatures in an area with enemies would have the heartbeat running), but you'd have to integrate that into every area's OnEnter/OnExit, which might be very complicated for some modules.
               
               

               


                     Modifié par MagicalMaster, 15 mars 2013 - 08:42 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
UpdateHP System v4 (Put Health Percentages Into Any Module Easily and More)
« Reply #14 on: March 15, 2013, 09:49:33 pm »


               

MagicalMaster wrote...

So, yeah, it largely depends on how the engine handles things (and I
don't know).  Is a separate script running a single line of code far
more expensive than an existing script running 20 additional lines of
code (obviously the actual operations matter, just as a general
principle)?  

I don't think so, but I can't say with any certainty.

How do psuedo heartbeat functions factor into that?

Psuedos take up about 5x the cpu of an equivalent heartbeat. You should use generally heartbeats instead on creatures, where they suit your needs. My general rule is to use a heartbeat instead of a psuedo if a) the function will be running less than ~20% of server uptime, 'B)' it will actually run (some heartbeats are very low in engine priority, like those on spawned-in placeables and AoEs), and c) a heartbeat meets your needs. Here, I would still use a psuedo despite a and b, because you need a pseudo for the faster-than-6-second cycling - a heartbeat just doesn't meet your needs ©.


By default, my script has like 3 main actual operations per heartbeat.  If I added a while loop that checked the surrounding area or something, that would greatly increase the number of operations per heartbeat - but it still might be more efficient overall if the heartbeat itself was very expensive (regardless of the code in it).  #4 in the list up there seems like it might technically be the best solution (in OnExit, set a local int to 1 that indicates UpdateHP should stop running and then in OnEnter set it to 0 and call UpdateHP to restart the process, so only creatures in an area with enemies would have the heartbeat running), but you'd have to integrate that into every area's OnEnter/OnExit, which might be very complicated for some modules.

I agree, I would absolutely cut off the pseudo if there's no pcs in the area. Looping pcs and comparing their area to that of the caller is a very fast operation. After all, it's the players' perceptions your script is concerned with.

Anyway, I can understand why you did use ondamaged. I don't really see many good alternatives if you're concerned with universalizibility. Otherwise, I would just use nwnx_funcs' SetMaxHitPoints, though frankly, we haven't had to, given regen, damage reduction/resist/immunity, etc, and acaos WROTE the darn function. '<img'>

Funky
               
               

               


                     Modifié par FunkySwerve, 15 mars 2013 - 09:50 .