
ModderInfo for the NPC PotionSaver code by DinkumThinkum:
*********************************************************

This document includes a copy of the actual PotionSaver code, ready to be copied
and pasted into the local script for a companion or any other NPC.  It also
includes an explanation of the code's logic, some details on why I coded it the
way I did, and other information and tips that may be helpful for modders when
using or modifying the code.


Updated this modder info file August 5, 2005: added or updated information about
creatures and potions, updating mods that use this code, credits, contact
information, and permission for using this code.

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

First, I should point out that the PotionSaver code can be used for any NPC in
the game; it's not just for companions. The PotionSaver code works fine as a
stand-alone script: there's no need for a full-fledged companion script to go
with it. (I did most of my testing and development on a guard NPC with just the
PotionSaver code attached as a local script.)

One possible use would be a quest NPC in a mod who joins the player character
for a specific battle or adventure, but isn't meant to be an actual companion.
Attach the PotionSaver code as their local script and put some Restore Health
(Standard, Quality, or Exclusive) potions in their inventory to give them a
better chance of surviving.

Or use the PotionSaver code and some potions to make a hostile NPC a more
challenging opponent.

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

Added Aug. 2005:

One thing I just tested very recently: creatures can also use potions.  I put
some Restore Health potions in a mud crab's inventory, then beat on it, and the
mud crab guzzled the potions just like an NPC.

I haven't had a chance to test the actual PotionSaver code with a creature,
however I don't know of any reasons at all why there would be any differences
from using it with an NPC.

So if you're using a creature as a companion, or just want to make a non-
companion creature tougher, you could give it some potions and put my PotionSave
code on it as part of its local script.

To me, it would certainly make sense for intelligent creatures, such as Golden
Saints, Dremora, etc., to have a supply of potions to use, but I'm not sure how
believable it would be for cliff racers, guars, and other unintelligent animals
to be drinking potions. :)

As I said: I haven't had a chance (as of this writing) to test my code on a
creature, but I don't know any reason why it wouldn't work.  If anybody does try
it and you run into problems, let me know and I'll try to figure out what's
going on.  But moving things in and out of inventory works the same for creaturs
as it does for NPCs, so there shouldn't be any issues.

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

I'm fairly certain my code doesn't use any script functions that were added or
changed by Tribunal/Bloodmoon, so the PotionSaver should work fine for
companions and other NPCs with just the original game and no expansions
installed.

(I did all my testing with Tribunal and Bloodmoon installed, so you probably
should double-check to be sure nothing slipped into the code that wasn't in the
original game.)

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

Added Aug. 2005:

Updating your mods that use the PotionSaver code:

If you distribute an updated version of you mod and it's meant to be installed
by players into an ongoing game, then include instructions for the player to
remove all Restore Health potions from their companion's inventory (and save
their game) before installing the updated mod.  Once they've installed the
update and reloaded their save game, they can give the potions back to their
companion.

This only applies if your update will be installed into ongoing games, rather
than requiring the player to start a new game.

The reason for this is that updating a mod that's in use may reset variables in
the mod to zero.  And if the PotionSaver's variables are reset to zero, that
could cause it to lose track of the companion's potions.

(Doesn't matter if the player keeps the companion's potions in his character's
inventory or just drops them on the ground; just need to temporarily remove them
from the companion's inventory for safekeeping during the update.)

Updating or modifying a mod that's already part of a saved game is always
risky, but this will at least keep the companion's potions from disappearing.

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

If you just want to use the code and aren't interested in the details, adding it
to a local script is literally just copy and paste, IF your mod doesn't have any
code of it's own that deals with the same potion types my code handles.  If your
mod does include code that deals with potions, see further down for tips on
making adjustments to avoid conflicts.


To implement the PotionSaver code:

Just copy and paste it into the NPC's local script ABOVE any 'Return' statements
in the local script.

Note: in this text file, a couple of the lines in the code are long enough to be
word-wrapped by my text editor.  I'll try to remember to fix them before posting
this, but I suggest double checking the code after you paste it into your local
script, just in case. :)

Put the seven variable declarations with your other declarations, and the actual
code (the two 'If' blocks) wherever you want, as long as all the code is placed
before any 'Return' statements or other code that might prevent the PotionSaver
from running every frame.

Once pasted into an NPC's local script, the PotionSaver works automatically.  No
customizing, globable variables, etc. needed.

PotionSaver code:
-----------------

Short DTNPS_MoveOnce_NotMenu
Short DTNPS_HandlePotions

Long DTNPS_Count_HealthExclusive
Long DTNPS_Count_HealthQuality
Long DTNPS_Count_HealthStandard
Long DTNPS_Count_HealthTotal

Float DTNPS_Timer_Health

If ( GetHealth < 1 )
  Set DTNPS_HandlePotions to 0
ElseIf ( GetFatigue < 1 )
  Set DTNPS_HandlePotions to 0
ElseIf ( MenuMode == 1 )
  Set DTNPS_HandlePotions to 0
Else
  Set DTNPS_HandlePotions to 1
EndIf

If ( DTNPS_HandlePotions == 0 )
    Set DTNPS_MoveOnce_NotMenu to 0
    Set DTNPS_Timer_Health to 99
    Set DTNPS_Count_HealthTotal to ( DTNPS_Count_HealthExclusive + DTNPS_Count_HealthQuality + DTNPS_Count_HealthStandard )
  If ( DTNPS_Count_HealthTotal > 0 )
  While ( DTNPS_Count_HealthExclusive >= 64 )
    AddItem "p_restore_health_e" 64
    Set DTNPS_Count_HealthExclusive  to ( DTNPS_Count_HealthExclusive - 64 )
  EndWhile
  While ( DTNPS_Count_HealthExclusive >= 8 )
    AddItem "p_restore_health_e" 8
    Set DTNPS_Count_HealthExclusive  to ( DTNPS_Count_HealthExclusive - 8 )
  EndWhile
  While ( DTNPS_Count_HealthExclusive >= 1 )
    AddItem "p_restore_health_e" 1
    Set DTNPS_Count_HealthExclusive  to ( DTNPS_Count_HealthExclusive - 1 )
  EndWhile
  While ( DTNPS_Count_HealthQuality >= 64 )
    AddItem "p_restore_health_q" 64
    Set DTNPS_Count_HealthQuality  to ( DTNPS_Count_HealthQuality - 64 )
  EndWhile
  While ( DTNPS_Count_HealthQuality >= 8 )
    AddItem "p_restore_health_q" 8
    Set DTNPS_Count_HealthQuality  to ( DTNPS_Count_HealthQuality - 8 )
  EndWhile
  While ( DTNPS_Count_HealthQuality >= 1 )
    AddItem "p_restore_health_q" 1
    Set DTNPS_Count_HealthQuality  to ( DTNPS_Count_HealthQuality - 1 )
  EndWhile
  While ( DTNPS_Count_HealthStandard >= 64 )
    AddItem "p_restore_health_s" 64
    Set DTNPS_Count_HealthStandard  to ( DTNPS_Count_HealthStandard - 64 )
  EndWhile
  While ( DTNPS_Count_HealthStandard >= 8 )
    AddItem "p_restore_health_s" 8
    Set DTNPS_Count_HealthStandard  to ( DTNPS_Count_HealthStandard - 8 )
  EndWhile
  While ( DTNPS_Count_HealthStandard >= 1 )
    AddItem "p_restore_health_s" 1
    Set DTNPS_Count_HealthStandard  to ( DTNPS_Count_HealthStandard - 1 )
  EndWhile
  EndIf
ElseIf ( DTNPS_HandlePotions == 1 )
  If ( DTNPS_MoveOnce_NotMenu == 0 )
    Set DTNPS_MoveOnce_NotMenu to 1
  While ( GetItemCount "p_restore_health_e" > 64 )
    RemoveItem "p_restore_health_e" 64
    Set DTNPS_Count_HealthExclusive to ( DTNPS_Count_HealthExclusive + 64 )
  EndWhile
  While ( GetItemCount "p_restore_health_e" > 8 )
    RemoveItem "p_restore_health_e" 8
    Set DTNPS_Count_HealthExclusive to ( DTNPS_Count_HealthExclusive + 8 )
  EndWhile
  While ( GetItemCount "p_restore_health_e" > 1 )
    RemoveItem "p_restore_health_e" 1
    Set DTNPS_Count_HealthExclusive to ( DTNPS_Count_HealthExclusive + 1 )
  EndWhile
  While ( GetItemCount "p_restore_health_q" >= 64 )
    RemoveItem "p_restore_health_q" 64
    Set DTNPS_Count_HealthQuality to ( DTNPS_Count_HealthQuality + 64 )
  EndWhile
  While ( GetItemCount "p_restore_health_q" >= 8 )
    RemoveItem "p_restore_health_q" 8
    Set DTNPS_Count_HealthQuality to ( DTNPS_Count_HealthQuality + 8 )
  EndWhile
  While ( GetItemCount "p_restore_health_q" >= 1 )
    RemoveItem "p_restore_health_q" 1
    Set DTNPS_Count_HealthQuality to ( DTNPS_Count_HealthQuality + 1 )
  EndWhile
  While ( GetItemCount "p_restore_health_s" >= 64 )
    RemoveItem "p_restore_health_s" 64
    Set DTNPS_Count_HealthStandard to ( DTNPS_Count_HealthStandard + 64 )
  EndWhile
  While ( GetItemCount "p_restore_health_s" >= 8 )
    RemoveItem "p_restore_health_s" 8
    Set DTNPS_Count_HealthStandard to ( DTNPS_Count_HealthStandard + 8 )
  EndWhile
  While ( GetItemCount "p_restore_health_s" >= 1 )
    RemoveItem "p_restore_health_s" 1
    Set DTNPS_Count_HealthStandard to ( DTNPS_Count_HealthStandard + 1 )
  EndWhile
  EndIf

  Set DTNPS_Count_HealthTotal to ( DTNPS_Count_HealthExclusive + DTNPS_Count_HealthQuality + DTNPS_Count_HealthStandard )

  If ( DTNPS_Count_HealthTotal > 0 )
    Set DTNPS_Timer_Health to ( DTNPS_Timer_Health + GetSecondsPassed )
  If ( GetItemCount "p_restore_health_e" > 0 )
    Set DTNPS_Timer_Health to 0
  ElseIf ( GetItemCount "p_restore_health_q" > 0 )
    Set DTNPS_Timer_Health to 0
  ElseIf ( GetItemCount "p_restore_health_s" > 0 )
    Set DTNPS_Timer_Health to 0
  ElseIf ( DTNPS_Timer_Health >= 1 )
  If ( DTNPS_Count_HealthExclusive > 0 )
    AddItem "p_restore_health_e" 1
    Set DTNPS_Count_HealthExclusive to ( DTNPS_Count_HealthExclusive - 1 )
  ElseIf ( DTNPS_Count_HealthQuality > 0 )
    AddItem "p_restore_health_q" 1
    Set DTNPS_Count_HealthQuality to ( DTNPS_Count_HealthQuality - 1 )
  ElseIf ( DTNPS_Count_HealthStandard > 0 )
    AddItem "p_restore_health_s" 1
    Set DTNPS_Count_HealthStandard to ( DTNPS_Count_HealthStandard - 1 )
  EndIf
  EndIf
  EndIf
EndIf

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

Modder's tips for DT's NPC PotionSaver code:

The ReadMe text file has a general overview of how the PotionSaver works; you
probably should read that first (if you haven't already).

When I refer to 'potions' in the following, I'm talking about the potions
handled by the PotionSaver code: Standard, Quality, and Exclusive Restore Health
potions. My code doesn't handle any other types of potions: it doesn't have any
affect on them and just ignores them completely.

A. Adding the PotionSaver code to a companion:

The code is completely self-contained, so adding it to a companion is just a
matter of copy and paste. Copy the local variable declarations and code from
Constance's local script, and paste them into the local script for another
companion.

No extra scripts, no global variables, no customizing, etc. required; just two
minor details to keep in mind:

1. The NPC PotionSaver code needs to be inserted into the companion's local
script before any 'Return' statements in that script.

The PotionSaver code includes code that has to run in menu mode, outside menu
mode, when the companion is dead, when the companion is unconscious, etc. So it
needs to be added to the companion local script before any 'Return' statements
that might interfere with the code being able to run every single frame.

2. As mentioned in the readme file, the PotionSaver code works by removing
potions from the companion's inventory when the companion is alive, conscious,
and the game is not in menu mode.  When the companion dies, become unconscious,
or the game goes into menu mode, my code places all the potions into the
companion's inventory and then ignores them until the companion revives or the
game leaves menu mode.

So if your script or dialogue needs to count or manipulate potions, make sure
your code does NOT try to do anything with the potions at the same time my code
is handling them.  Wait until thecompanion is dead, unconscious, or when the
game is in menu mode and my code has finished putting all the potions back into
the companion's inventory.

For example, add a block of code similar to the following to your companion's
local script after the PotionSaver code:

If ( MenuMode == 1 )

;put your code for counting (i.e., 'GetItemCount') or otherwise manipulating
; potions here

EndIf


That will make sure my code has placed all the potions back into the companion's
inventory before your code tries to work with them.

B. What to copy and paste:

1. Variables: all the PotionSaver variables start with 'DTNPS_' (DT's NPC
PotionSaver); seven total.

Just paste them in with the variables already in your companion's local script.

2. Code: one small 'If' block and one large 'If' block, one right after the
other.

The PotionSaver code starts with

If ( GetHealth < 1 )
 Set DTNPS_HandlePotions to 0

and ends with

   Set DTNPS_Count_HealthStandard to ( DTNPS_Count_HealthStandard - 1 )
 EndIf
 EndIf
 EndIf
EndIf


Just copy that entire block of code and paste it into you companion's local
script, somewhere before any 'Return' statements.


C. Performance impact:

None that I ever noticed.

I didn't do any formal timing tests, but I did test with several NPCs in my game
all running the Potionsaver script at the same time, and I didn't see any signs
of slow downs or other problems.

Note that the PotionSaver looks like a lot of code, but most of that is 'While'
blocks that move the potions in and out of inventory as needed. That code only
runs once each time the companion dies, goes unconscious or revives, or the game
goes in or out of menu mode.

Most of the time, only a few lines of code are running, and none of that
includes any functions that impose much CPU load.

D. Stability:

1. Bugs: I'm not aware of any bugs remaining in the PotionSaver code, and I'm
keeping my fingers crossed that none show up now that it's been publicly
released.

2. Conflicts: the only possible conflict I can think of is if other code or
dialogue for the companion is trying to deal with potions at the same time my
code is handling them. As long as other code only tries to manipulate potions
after my code has returned them to the companion's inventory, there shouldn't be
any conflicts. See A.2. above for suggestions.

3.  As of now, the current (and probably final) version of the code has been
around for roughly eight months without any changes.  I'm not aware of any
problem reports to date, so it looks like the code is pretty solid.

E. Trimming the code size:

Most of the bulk of the PotionSaver code is in the 'While' blocks which move the
handled potions in and out of the companion's inventory.

If the code is too big to fit into your companion's local script, some of the
'While' blocks could be eliminated:

Currently, there are three sets of 'While' blocks to move each type of potion
into inventory, and three sets to move each type of potion out of inventory. In
each case, the 'While' blocks move potions in increments of 64, then 8, then 1
at a time.

Increments of 64, 8, and 1 work well even with very large numbers of potions: no
noticeable pauses going in and out of menu mode even with several companions
each carrying several thousand potions.

To make the code smaller, you could use just two 'While' blocks for each type of
potion. If I were doing this, I'd probably try using increments of 20 and 1 to
start with, then fine tune after testing. I haven't personally tested this, but
I would guess that two pairs of 'While' blocks for each type of potion would
still work fine (i.e., no noticeable pauses), unless a player gives their
companion(s) ridiculous numbers of potions.

C. Code notes:

1. The variables:

Short DTNPS_MoveOnce_NotMenu: 'Do Once' control variable for the 'While' blocks
that move potions out of the companion's inventory and into the control of the
PotionSaver code.

Short DTNPS_HandlePotions: Control variable used by the large 'If' block: when
this is zero, the first 'If' branch is used and the potions are placed into the
companion's inventory and left alone. When this is one, the second branch is
used and potions are removed from the companion's inventory and handled by the
PotionSaver code.

Long DTNPS_Count_HealthExclusive; Long DTNPS_Count_HealthQuality; Long
DTNPS_Count_HealthStandard: counters used to keep track of how many of each type
of potion are currently being handled by the PotionSaver code. When all the
potions have been placed into inventory (i.e., companion dead or unconscious, or
the game in menu mode), all these will be zero.

Long DTNPS_Count_HealthTotal: tempory counter, set to the total of the above
three counters. Used as a 'Do Once' variable when moving potions into the
companion's inventory, and used to skip the main brains of the PotionSaver code
when there aren't any potions to handle.

Note: the second use of this variable, besides saving a few cycles by skipping
some code when it's not needed, also stops the delay timer, thus keeping it from
trying to count up to infinity and overflowing if the companion runs out of
potions.

Float DTNPS_Timer_Health: counts out the one second time delay after a potion is
used before putting another one into the companion's inventory.


2. About the code:

Most of the code bulk is just the 'While' blocks that move potions in and out of
the companion's inventory.

The actual 'brains' of the PotionSaver code is the small section near the end,
just after the last 'While' blocks. This keeps track of how many potions are in
inventory and how many are being handled by the PotionSaver code (i.e., stored
as the 'count' variables).

As long as there's at least one potion in the companion's inventory, this
section of code just keeps resettting the timer to zero and exiting. Once the
last potion in inventory has been used, the counter is allowed to count up; when
the timer reaches one second, another potion is placed into the companion's
inventory ready to be used.

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

The above should be more than enough information for modders who just want to
use my code for their companions without any major changes. The rest of this
document is mostly more detailed information that may help out modders who want
modify my code or write their own scripts based on my ideas.

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

Overall layout of the code:

The original concept for the PotionSaver code was to just remove the potions
from the companion's inventory and replace them one at a time as they were used.
Grumpy pointed out that there should be some way for the player to see how many
potions the companion had and suggested putting them back into the companion's
inventory when the inventory window was open.

This led to the final organization of the PotionSaver code: most of it is a
single large 'If' block with two branches. One branch to put the potions into
the companion's inventory for convenient access by the player, and another
branch to remove the potions from inventory so the PotionSaver can ration the
potions and prevent the game's AI from guzzling them.

End result, thanks to Grumpy's idea, is that the PotionSaver code is effectively
invisible to the player: anytime the player checks the companion's inventory the
potions will be there.

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

Reason the small (first) 'If' block checks for death and unconsciousness, in
addition to MenuMode, when setting the variable 'DTNPS_HandlePotions' (which
tells the main 'If' block when to move potions in or out of the companion's
inventory):

This was done to avoid a bug I encountered in the game engine. If an NPC's
inventory window is already open when a script uses 'AddItem' to add items to
the NPC's inventory, the inventory display won't always be updated to show the
new items.

For example, if the companion has one potion in their inventory and a script
adds ten more while the inventory window is open, the window will often continue
to show just one potion in the inventory listing; the display won't be updated
to reflect the added potions.

The original version of the code used a single large 'If' block, which moved
potions in and out of inventory based on just 'MenuMode'. This worked fine when
the companion was alive and conscious: the potions would be moved as soon as the
dialogue window was opened, so they'd already be in inventory when the companion
share window was opened.

However, if the companion was dead or unconscious, clicking on them would go
straight to the inventory display (no dialogue window), so the script would add
potions to the inventory after the inventory window was already open. End result
was that the inventory display window would only list that potions that were
already in inventory when the companion died, and wouldn't list ones added by
the PotionSaver code after the inventory window was opened.

Adding the small 'If' block and the variable 'DTNPS_HandlePotions' corrected the
problem: now the potions are moved back into the companion's inventory as soon
as they die or become unconscious (before the inventory window is opened), so
the inventory display will show the correct number of potions.

Note 1:

I originally thought this was a problem in my code that was somehow losing
potions. By the time I figured out that it was a display bug in the game engine
and found the correct way to code around it, I had probably spent as much time
on this one part of the code as I did on all the rest of the PotionSaver.

So if you want to modify any of the logic that controls when potions are moved
in or out of the companion's inventory, please be careful!

Note 2: this is only a display problem. The items actually are added to the NPC
inventory; they just don't show up in the display if they're added while the
window is open. Manually adding or removing inventory items (with the mouse)
while the window is open will trigger a display update and cause the added items
to be correctly listed.

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

Time delay:

This line, near the end of the code (in the 'brains' section after the last
'While' block), sets the one second delay used to keep the companion from
guzzling potions:

 ElseIf ( DTNPS_Timer_Health >= 1 )


Change the '1' to change the delay. Larger numbers will increase the delay and
slow down the companion's use of potions, but may make the companion more likely
to die. Smaller numbers will let the companion drink faster, possibly wasting
more potions but increasing their chances of staying alive.

One second seems to hit a good balance between keeping the companion alive and
stopping the AI's wasteful potion guzzling.

----

One possible tweak to the timing: instead of just a fixed one second time delay,
change the delay based on how badly injured the companion is. (Check their
current health with 'GetHealthGetRatio'.)

For example, if the companion's health drops below 10%, reduce the time delay or
just set it to zero. This would allow the companion to drink potions faster if
they were getting really beat up in a tough fight.

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

How the game's NPC AI appears to use restore health potions:

1. From my testing, the game's AI only seemed to use potions when an NPC was in
combat: actually trying to attack an opponent. If their health dropped, even to
a very low level, when they weren't in combat (i.e., just standing around), they
would just ignore any restore health potions in their inventory until they
started fighting something.

Another tester reported that he could get NPCs to drink potions even when they
weren't in combat: use the console to lower their health, and they'd drink a
potion immediatey even if they were just standing around.

No idea why the discrepency: different AI settings or packages, observer error,
the phase of the moon, or what...

2. The trigger point for drinking restore health seems to be 50%: NPCs won't use
restore health potions unless their health is below 50% of maximum.

Most of the time, NPCs will drink a potion as soon as their health drops below
1/2. But sometimes they'll wait longer.

I've seen NPCs wait until their health was at 20% or 10% of maximum before
drinking a restore health potion that was in their inventory.

And sometimes the NPCs would go all the way to 0% health and die without ever
drinking a potion, even though they had one or more potions available in their
inventory. (I tested this extensively, and it's definitely caused by the game
itself, not by anything in my code: even without my code, NPCs would sometimes
die without drinking restore health potions that were in their inventory.)

No idea why there's a variation in when NPCs will drink available potions: it
could be intentional randomeness in the AI or it could just be a glitch.

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

Some other potions besides restore health:

1. Restore Fatigue:

Restore Fatigue potions seem to work the same way as Restore Health potions,
with the same problem with the AI guzzling them too fast. I didn't write code to
handle Restore Fatigue, since the Restore Health potions are the ones that are
critical for keeping companions alive.

If somebody wants to expand the PotionSaver code to also handle Restore Fatigue
potions, it should be trivial to accomplish:

Add a third large 'If' block that duplicates the existing one, then change some
of the variable names as necessary to avoid conflicts, and change the object IDs
to refer to Restore Fatigue potions instead of Restore Health potions.

(During discussions with Grumpy and Emma, the consensus was not to bother with
Restore Fatigue potions, which was fine with me.  But if other companion modders
want to do it, it wouldn't take much work.)

2. Restore Magicka potions:

As far as I can tell, the game's NPC AI just ignores Restore Magicka potions. If
a spell caster runs out of magicka, they'll charge into battle with a weapon
even if they have a good supply of restore magicka potions in their inventory.

Since my code depends on the game's built-in AI to actually drink the potions,
code to use Restore Magicka potions would have to written from scratch; my
PotionSaver code can't be adapted for this.

Maybe something like this would work:

1. Timer to wait out a delay after the last Restore Magicka was used (to prevent
guzzling problems).  A one second delay might be a reasonable value to start
with.

2. Code to compare the NPC's current magicka to their maximum.

3. If the current magicka is below a trigger point (maybe 50%), select an
appropriate restore magicka potion from their inventory and force the NPC to use
it.

Since the AI doesn't use Restore Magicka potions, there's no need to move them
in and out of inventory the way my PotionSaver code does.

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

Support for the PotionSaver code:

I'm active as DinkumThinkum on several Morrowind-related web forums, and you
should be able to reach me by PM on any forum where you see me posting
regularly.  I should always be reachable at Bethesda's official TES forums.

-------
Credits:
-------

Grumpy, Emma, and The Other Felix for ideas and inspiration that led to this
bug workaround. GhanBuriGhan for "Scripting for Dummies", without which I'd
never have been able to do anything like this. Bethesda for Morrowind and the
whole TES series.

------------
Permissions:
------------

I wrote this code as a modders' resource: something for modders to use in their
own mods.  I do ask that you give me credit when you use this in your own mods,
but you don't need to ask me for permission.

You're also free to adapt or modify my code as needed for your own mods, but
please document what you change, in case any problems come up and we need to
figure out what's what.


