Jump to content
  • Announcements

    • AndalayBay

      Orphan Attachments   07/31/2018

      I have been doing some housekeeping lately and I've noticed that I had a lot of orphaned attachments. Attachments get orphaned when the PM or post is deleted without removing the attachment first. Deleting a PM or post does not delete the attachment and the file or image remain on the server. I'd like to ask all members to go through their attachments and delete any attachments you don't need anymore or those that have been orphaned. Where can I get a list of my attachments? Click on your display name in the upper right corner of the forums and pick "My Attachments" from the drop-down list. How can I tell an attachment is orphaned? If the PM has been deleted, you'll see a message like this in your attachment list: Unfortunately there is no message if the post has been deleted, so please check your old posts. We do purge old birthday threads every once in a while. Also some hosted projects have been shut down, so you may have orphaned attachments on one of those locations. Thanks!
Sign in to follow this  
Milotek

Poison Kill Script Discussion

Recommended Posts

 

Sorry, I missed your edits earlier. Ob XP never left your character as is. It has always reset your character to level 1. Previously you could delay initializing your character but that's no longer possible because of the new menu design.

 

I don't understand how your sneak skill got set to 85. I usually remove all enchanted items just to make sure my attributes and skills aren't fortified. The Skeleton Key in particular can cause a bug with your security skill.

 

 

Ok so the screen that use to let you either reset or not was just going to delay it, cool.  If I play that character, I'm guessing it will reset once I try to level up for the first time.  To bad, I'd like to be able to add OBXP to an established character.

 

The sneak thing was on a really old high level character and he does have the skeleton key.  Is this piece of information in your readme file? 

 

I think the new version is ready for full release. I used an online translator to fix the rest of the translations and I've fixed up the documentation. Have you guys seen anything that I need to look into?

 

As I stated in a different thread, I do have issues with multiple XP when I use poisons.  I do know what is making it happen.  It is quite simple to recreate.  I will give you a quick explanation of what's going on.

 

I play as an archer and have some long lasting damage fatigue and health poisons, about 7pts for 30 seconds.   just poison a creature/NPC with many poisons and when they die any poisons that are in effect will fall through to your spell finished block.  Since the instances of those posions never made a kill, the condition you use in the spell finished block allows the code to run where you manually call the OnDeath event.   So if 6 poisons are active at time of death you get 6 times the XP.  Now if one of those 6 poisons makes the kill, then that one works fine but you get 5 times the XP because of the other 5 poison.  There is another combination that makes it happen but the reason is the same.

 

I have thought about removing the spell finished block, but I want to know more about what creatures you were having issues with that caused you to add it.  That way I can test some things.  I have found another possible issue within the poison script but I can't test it until I know this information.   I need to be able to recreate the conditions that made you add the spell finished block in the first place.

Share this post


Link to post
Share on other sites

 

Sorry, I missed your edits earlier. Ob XP never left your character as is. It has always reset your character to level 1. Previously you could delay initializing your character but that's no longer possible because of the new menu design.

 

I don't understand how your sneak skill got set to 85. I usually remove all enchanted items just to make sure my attributes and skills aren't fortified. The Skeleton Key in particular can cause a bug with your security skill.

 

Ok so the screen that use to let you either reset or not was just going to delay it, cool.  If I play that character, I'm guessing it will reset once I try to level up for the first time.  To bad, I'd like to be able to add OBXP to an established character.

 

The sneak thing was on a really old high level character and he does have the skeleton key.  Is this piece of information in your readme file?

 

No, I never thought to mention it since it's a well known issue. It affects the vanilla game too, not just Ob XP. I guess I can look at adding a note about it.

 

 

I think the new version is ready for full release. I used an online translator to fix the rest of the translations and I've fixed up the documentation. Have you guys seen anything that I need to look into?

 

As I stated in a different thread, I do have issues with multiple XP when I use poisons.  I do know what is making it happen.  It is quite simple to recreate.  I will give you a quick explanation of what's going on.

 

I play as an archer and have some long lasting damage fatigue and health poisons, about 7pts for 30 seconds.   just poison a creature/NPC with many poisons and when they die any poisons that are in effect will fall through to your spell finished block.  Since the instances of those posions never made a kill, the condition you use in the spell finished block allows the code to run where you manually call the OnDeath event.   So if 6 poisons are active at time of death you get 6 times the XP.  Now if one of those 6 poisons makes the kill, then that one works fine but you get 5 times the XP because of the other 5 poison.  There is another combination that makes it happen but the reason is the same.

 

I have thought about removing the spell finished block, but I want to know more about what creatures you were having issues with that caused you to add it.  That way I can test some things.  I have found another possible issue within the poison script but I can't test it until I know this information.   I need to be able to recreate the conditions that made you add the spell finished block in the first place.

 

Oh, I understand now. I've never thought of piling potions up like that. This will affect saebel too as he's added my poison calcs to SDR. Ok, I'll take the discussion over to our SDR thread since saebel will need to implement the fix there as well. I'll take a look at the code and I'm thinking that all I need to do is to cancel the remaining magic effects, or delete them from the array.

 

Thanks for the info.

Share this post


Link to post
Share on other sites

 

 

Sorry, I missed your edits earlier. Ob XP never left your character as is. It has always reset your character to level 1. Previously you could delay initializing your character but that's no longer possible because of the new menu design.

 

I don't understand how your sneak skill got set to 85. I usually remove all enchanted items just to make sure my attributes and skills aren't fortified. The Skeleton Key in particular can cause a bug with your security skill.

 

Ok so the screen that use to let you either reset or not was just going to delay it, cool.  If I play that character, I'm guessing it will reset once I try to level up for the first time.  To bad, I'd like to be able to add OBXP to an established character.

 

The sneak thing was on a really old high level character and he does have the skeleton key.  Is this piece of information in your readme file?

 

No, I never thought to mention it since it's a well known issue. It affects the vanilla game too, not just Ob XP. I guess I can look at adding a note about it.

 

 

I think the new version is ready for full release. I used an online translator to fix the rest of the translations and I've fixed up the documentation. Have you guys seen anything that I need to look into?

 

As I stated in a different thread, I do have issues with multiple XP when I use poisons.  I do know what is making it happen.  It is quite simple to recreate.  I will give you a quick explanation of what's going on.

 

I play as an archer and have some long lasting damage fatigue and health poisons, about 7pts for 30 seconds.   just poison a creature/NPC with many poisons and when they die any poisons that are in effect will fall through to your spell finished block.  Since the instances of those posions never made a kill, the condition you use in the spell finished block allows the code to run where you manually call the OnDeath event.   So if 6 poisons are active at time of death you get 6 times the XP.  Now if one of those 6 poisons makes the kill, then that one works fine but you get 5 times the XP because of the other 5 poison.  There is another combination that makes it happen but the reason is the same.

 

I have thought about removing the spell finished block, but I want to know more about what creatures you were having issues with that caused you to add it.  That way I can test some things.  I have found another possible issue within the poison script but I can't test it until I know this information.   I need to be able to recreate the conditions that made you add the spell finished block in the first place.

 

Oh, I understand now. I've never thought of piling potions up like that. This will affect saebel too as he's added my poison calcs to SDR. Ok, I'll take the discussion over to our SDR thread since saebel will need to implement the fix there as well. I'll take a look at the code and I'm thinking that all I need to do is to cancel the remaining magic effects, or delete them from the array.

 

Thanks for the info.

 

 

I'd still like to have some information about why the spell finish block was added.  The comment in the code was helpful but I need more.  I am designing a change that will make the poison script obsolete but without knowing the creatures/NPCs that are falling through the crack, I can't test it. 

 

I noticed there is a timer in the spell update block that may be making kills fall through the cracks.  If something dies when the timer isn't allowing the code to run, won't that cause the kill to fall to the spell finish block?   So is it possible that this is what was causing things to go wrong, requiring you to add the spell finished block?  Was the issue that made you add that code random and rare?  If so, I might just remove the spell finished block and live with not getting XP at times.   On rare occasions even with the current version, I don't get XP for poison kills. 

 

Now if you can work this out that would be great.  The idea I am working on the get rid of the poison script works good on paper, but I am not sure the scripting language will allow me to pull it off.

Share this post


Link to post
Share on other sites

The timer is there because that's how poisons work. If they don't have a timer, then the scriptEffectStart will take care of things. The only way to get into a scriptEffectUpdate block is if the poison extends over several seconds. You can't guarantee when a script will fire because other mods will have timing scripts as well, so the scriptEffectFinish catches the cases where the actor didn't die during the start or update blocks.

 

As I said, the only reason the code isn't working is because I didn't consider the case where there could be several poison effects active at once.

Share this post


Link to post
Share on other sites

Ok, all fixed. I had already defined a variable, I just wasn't testing for it being set in the finish block.

 

If you want to have the fix before the next version is released, just edit the script called ObXPPoisonScript. In the ScriptEffectFinish block, insert this code:

 

 

begin ScriptEffectFinish
    ; the resistances of certain creatures aren't captured properly, so they die in between the update cycles
    ; try to capture those cases here - return in update cycle not working.  Also need to account for critter
    ; dying by brute force, in which case the kill will be registered by the regular kill script.
    
    if (killRegistered)
        sv_Destruct effectCode
        return
    endif
    
    if (actor.getDead)
        if ( actor.getObjectType == 35 )
            if ( GetPCMiscStat 6 == npcKills )
                modPCMiscStat 6 1
                PrintToConsole "ObXP: Poison killed %n!" actor
            endif
        elseif ( actor.getObjectType == 36 )
            if ( GetPCMiscStat 5 == creatureKills )
                modPCMiscStat 5 1
                PrintToConsole "ObXP: Poison killed %n!" actor
            endif
        endif
        
        ; don't care about misc stats anymore
        call OBXPfnOnDeath actor, player
        
        if (ObXPMain.debugMode)
            let ckills := GetPCMiscStat 5
            let pkills := GetPCMiscStat 6
            scribe "After kill, finish cycle: Creature kills: %.4f, NPC kills: %.4f" ckills pkills
        endif
    endif
    sv_Destruct effectCode
end

Share this post


Link to post
Share on other sites

I just tested your new code and the problem is the same.  The variable killRegistered is the problem.  Each instance of the poison has its own killRegistered variable.  Only the poison that makes the kill in the Start or Update blocks will set the variable killRegistered to 1.  The other instances of the poisons fall through as their instances of killRegistered are still 0.  This was the same cause of the issue in the old script. 

 

I made a change in the script that seems to work.  I moved the call to the function OBXPfnOnDeath to where you manually increase the creature and NPC kill stats.   I mean if you adding to the stat it is a good place to consider the enemy dead.  There is potential problem with this fix too, but without knowing how to create and how rare it is for an enemy to slip through the cracks into the Finished block, I can't dig into it any deeper.  So please answer me, how rare and can it be created at will?  

 

This new problem actually existed in the original code as well.  It has more to do with how you use the kill stats as a condition for manually updating them.  Under certain situations you may not get stats for a kill, but depending how rare it is for a kill to get to the Finished block will determine if it is something that will be a problem.  Now that I have the OBXPfnOnDeath function within that condition check you may not get XP either.  I can live without getting credit for kills, if it is somewhat rare.

 

Here's my new code using your new version:

begin ScriptEffectFinish
    ; the resistances of certain creatures aren't captured properly, so they die in between the update cycles
    ; try to capture those cases here - return in update cycle not working.  Also need to account for critter
    ; dying by brute force, in which case the kill will be registered by the regular kill script.
    
    if (killRegistered)
        sv_Destruct effectCode
        return
    endif
    
    if (actor.getDead)
        if ( actor.getObjectType == 35 )
            if ( GetPCMiscStat 6 == npcKills )
                modPCMiscStat 6 1
                call OBXPfnOnDeath actor, player
                PrintToConsole "ObXP: Poison killed %n!" actor
            endif
        elseif ( actor.getObjectType == 36 )
            if ( GetPCMiscStat 5 == creatureKills )
                modPCMiscStat 5 1
                call OBXPfnOnDeath actor, player
                PrintToConsole "ObXP: Poison killed %n!" actor
            endif
        endif
        
        if (ObXPMain.debugMode)
            let ckills := GetPCMiscStat 5
            let pkills := GetPCMiscStat 6
            scribe "After kill, finish cycle: Creature kills: %.4f, NPC kills: %.4f" ckills pkills
        endif
    endif
    sv_Destruct effectCode
end
Edited by Milotek

Share this post


Link to post
Share on other sites

I haven't had a chance to test the code yet. My understanding is that you can create the condition by applying multiple poisons to a creature. When it dies, you get multiple rounds of XP. So create several different poisons and shoot an enemy with arrows poisoned with the different poisons. When the enemy drops dead, I think you'll get several kill rewards.

 

You might be right about moving the test to the onDeath event handler. No matter where I process the kill, I need to be able to link the multiple poisons to an actor. I'll have to do some testing and trace the scripts to figure out exactly how the poisons are being processed.

Share this post


Link to post
Share on other sites

You might be right about moving the test to the onDeath event handler. No matter where I process the kill, I need to be able to link the multiple poisons to an actor. I'll have to do some testing and trace the scripts to figure out exactly how the poisons are being processed.

 

I don't think I said anything about moving code to the OnDeath handler.  I just moved where you called the function OBXPfnOnDeath in the Finished block.  Just check the code I posted against what you posted.  Changes should be easy to spot.

 

I have been testing where I put the OBXPfnOnDeath function and so far its been working perfectly. 

 

I haven't had a chance to test the code yet. My understanding is that you can create the condition by applying multiple poisons to a creature. When it dies, you get multiple rounds of XP. So create several different poisons and shoot an enemy with arrows poisoned with the different poisons. When the enemy drops dead, I think you'll get several kill rewards.

 

Wow were having a miscommunication here.  This is not the what I am talking about when I am asking how to recreate the problem.  This is the problem that I presented to you.  I do this test all the time that is why I am telling you about it. 

 

What I am asking is how to setup the conditions to make something fall through the cracks and fire the Finished block in general.  I am trying to figure out why you added the Finished block in the first place.  More importantly how rare is it to happen.   I've yet to have anything legitimately fall through into the Finished block. 

 

So for right this second, forget about the stacked poison issue.  What originally made you add the Finished block? Basic explanation will do.  How can it be recreated, if at all?  How rare is it to happen (important)?  From some sort of testing you must have some of this information or you wouldn't have added the Finished block.  All I have to go by is this comment from the Finished block:

    ; the resistances of certain creatures aren't captured properly, so they die in between the update cycles
    ; try to capture those cases here - return in update cycle not working.  Also need to account for critter
    ; dying by brute force, in which case the kill will be registered by the regular kill script.

For testing purposes I have changed the line:

    if ( scriptTimer >= .98 )

to

    if ( scriptTimer >= 50.98 )

in the Update block that way my 30 second spells will timeout before the Update block runs again.  Now all my poisons legitimately fall into the Finished block.  I am testing the way you use the Oblivion kill stats as a condition in the Finished block for manually updating them as I explained in my last post.  So far I have been able to make this issue happen at will.  I won't know how big of a deal this is until I hear from you about the rarity of kills legitimately falling into the Finished block.   

 

I am also looking into what seems to be you treating Damage Health and Drain Health poisons the same in your calculation for damage in the Start and Update blocks.  This is just theory when I looked at the code.  I have done no testing at all.  I am still trying to wrap my head around it and find ways to test it.  I'm not even sure if it is an issue at all.  I just came up with it a little while ago. 

Edited by Milotek

Share this post


Link to post
Share on other sites

I was just thinking out loud, as it were. Moving the function call as you did might be the ticket since the miscellaneous stat is updated as soon as the enemy dies, so repeated runs of the script after he's dead won't call the onDeath handler again.

 

Sorry, I misread your post. I have no idea how often it can fall through to the finish block, but when I was developing the script, I found that some deaths due to poison weren't being captured, so I added the finish block. Magic scripted effects usually have all three blocks and I found that each block caught deaths at different times. The poison script has worked just fine for a long time. You are the first person to point out a problem with it, and I forgot that it was you who first reported the issue. :) It has been a long time since I wrote the script and I've forgotten the reasons for some things.

 

In terms of damage health versus drain health, I'm just accumulating all the damage. The damage done accumulates each round. It's either a matter of direct damage done to health, or reducing the NPC;'s pool of health. It doesn't really matter: once the damage done exceeds the NPC's health, they die.

 

Edit: Ok, I just remembered why some enemies can fall through to the script effect finish block. Basically the damage tally is just an approximation. It doesn't take into account all the factors. So the actor can die in between updates. When that happens, the finish block kicks in and checks if the actor is dead. If he is, points are awarded. If not, then you still have to kill him, in which case the regular onDeath event handler will process the kill or you've applied another poison and the whole process repeats itself.

Edited by AndalayBay

Share this post


Link to post
Share on other sites

I was just thinking out loud, as it were. Moving the function call as you did might be the ticket since the miscellaneous stat is updated as soon as the enemy dies, so repeated runs of the script after he's dead won't call the onDeath handler again.

 

Sorry, I misread your post. I have no idea how often it can fall through to the finish block, but when I was developing the script, I found that some deaths due to poison weren't being captured, so I added the finish block. Magic scripted effects usually have all three blocks and I found that each block caught deaths at different times. The poison script has worked just fine for a long time. You are the first person to point out a problem with it, and I forgot that it was you who first reported the issue. :) It has been a long time since I wrote the script and I've forgotten the reasons for some things.

 

In terms of damage health versus drain health, I'm just accumulating all the damage. The damage done accumulates each round. It's either a matter of direct damage done to health, or reducing the NPC;'s pool of health. It doesn't really matter: once the damage done exceeds the NPC's health, they die.

 

Edit: Ok, I just remembered why some enemies can fall through to the script effect finish block. Basically the damage tally is just an approximation. It doesn't take into account all the factors. So the actor can die in between updates. When that happens, the finish block kicks in and checks if the actor is dead. If he is, points are awarded. If not, then you still have to kill him, in which case the regular onDeath event handler will process the kill or you've applied another poison and the whole process repeats itself.

Thanks for all the info, I got what I needed.  Knowing that the Kills falling into the Finished are block random and rare,  makes the issue with the miscellaneous stats for NPC and creatures kills that I found even more rare.   I'm still going to look into it.  There is a real easy fix to make it even more rare.   I haven't thoroughly tested it yet.   I will tell you more about it after I make sure it all works. 

 

Actually I dislike working on things and discussing them in forums, its way too slow and hard to get complex points across.  If we were in the same room, we could have hashed this all out in minutes instead of weeks.  Yea technology!!  Plus as I get older I tend to forget things. 

 

I am still going to look into the Damage vs Drain health.  From just looking at the code, it seems that you are calculating the Drain health every second for the duration of the poison when it should just be calculated once for the duration of the poison.  It will be easy to test, I just have to make some Drain Health poisons.  I usually don't use them as my Damage Health poison are far more effective.

 

I downloaded the new version and will test it as soon as I finish this post.

Share this post


Link to post
Share on other sites

That's why saebel and I got on Skype. We had the code sorted in a few minutes. If you'd like to see how the code flows, install Conscribe and turn on Ob XP's debugging. You might need to add a few more debugging statemens.

Share this post


Link to post
Share on other sites

I have tested the poison script and for the most part it works fine.  I did find another problem with it.  This problem existed in the old code too, but I assumed it was an issue with the stacked poisons, now I know it is not.   In a nutshell, if you have an enemy that is one one conventional weapon blow from death and poison your weapon for the final blow. you will get two OPXP kill messages along with the associated XP.  The easiest way to test this is to find a creature, such as a mud crab, that you can kill in one conventional weapon strike and poison the weapon and strike the creature.  Of course the type of poison must be a damage heath type.

 

I spent last night knee deep in the code adding PrintToConsole messages trying to figure out what is going on.  It is quite messy as it seems the conventional part of the kill and the poison part of the kill happen very close or even at the same time.  The flow seems to be poison kill then conventional kill.  The poison kill falls to the Finished block.  In my specific case, the actor dies in the middle of the Start script for the poison.   I added a PrintToConsole message at the start of the code and one at the end of the code that printed if the actor was dead or not.  At the beginning of the code it was alive and at the end of the code it was dead.  Due to the nature of the scripting language and the quirks in Oblivion, the way the messages print may not represent the true flow.     

 

I am about to just remove the Finished block as it seem the be the root of all the trouble.  If the need for it is random and rare, then I can live without  getting XP at times.   How do you feel about that?  Is that block really that necessary?

 

I tested the Drain vs Damage and it work as you said, just fine.   I am new with working with poisons and spells and I haven't quite got a handle on Drain. 

 

I do have Conscribe installed but I haven't turned debugging on yet.  When I first took a look at the code for the mod, I was going to turn on debugging to see how it all works, but when I ran into these issues I starting creating my own statements to get the specific data I needed. 

Edited by Milotek

Share this post


Link to post
Share on other sites

Are you sure you actually got multiple XP? You'll get lots of messages, especially in the console, but I've found that I've only gotten one XP award.

 

Are you running SDR? The assassination bonus is a separate XP award, so you will get two awards if you successfully sneak skill something.

 

I can't really say how often the finish block kicks in. I do know that in 4.2.3, a bug in the finish block meant that you got no points for poison kills at all. I'd say go ahead and remove it and see what happens.

 

I will say that I'd rather get double the number of points periodically than get no points at all. The situation you've managed to create is pretty rare, so I don't think I'll try to fix it. I'm more likely to break something else. :P

Share this post


Link to post
Share on other sites

Are you sure you actually got multiple XP? You'll get lots of messages, especially in the console, but I've found that I've only gotten one XP award.

 

Yes I am sure I got multiple XP awards.  The only console message from your code was a confirmation that the actor was poisoned.  All the other console data was what I put into the code to see what was going on.

 

Are you running SDR? The assassination bonus is a separate XP award, so you will get two awards if you successfully sneak skill something.

 

No I am not running SDR,  it kills my framerate.  Plus, during my testing, I wasn't sneaking.

 

I can't really say how often the finish block kicks in. I do know that in 4.2.3, a bug in the finish block meant that you got no points for poison kills at all. I'd say go ahead and remove it and see what happens.

 

For now, I am not going to remove the Finished block.  I have a good idea on what is going on and a possible fix for it, but more on that later. 

 

I will say that I'd rather get double the number of points periodically than get no points at all. The situation you've managed to create is pretty rare, so I don't think I'll try to fix it. I'm more likely to break something else. :P

 

For this issue, which I am calling the Simultaneous Kill, it isn't that big of a deal.  It seems you can only get double XP points and no more.  So I can see not fixing it.  I would hate to mess things up.  But I might have a solution, again more on that later.

 

Actually this issue isn't that rare.  It has happened to me many times in normal play.  I knew this was an issue before the Stacked Poison issue.  When I then discovered the Stacked Poison issue I assumed it was the cause.  It wasn't until the fix for the Stacked Poison that I realized it was its own issue. 

 

I take a different view on getting XP points or not.  I rather not get XP points if it occurs randomly and rare than to get XP points by exploit or accident.  I can role play not getting points as maybe I didn't learn anything on that kill.  The randomness makes it OK for me as I am not expecting it.  On the other hand, knowing I that I will get extra XP if I do something a certain way ruins the role playing for me just a little.  The main thing that bothers me is I know it isn't right and the coder in me wants to fix it.  So instead of playing I spend hours trying to fix it. 

 

Anyway I have made progress on this Simultaneous Kill issue.  But first I have to correct a couple of mistakes I made in my last post when describing the issue.  One, I stated that 'the actor dies in the middle of the Start script for the poison',  that is wrong.  I had a logic error in my code.  In reality, the actor dies before the Start script.  This is a good thing.  Second, I mentioned that to test the issue you had to use a Damage Health poison, actually any poison will make it happen, this too is a good thing.

 

Here is what I think is going on.  I can't prove it 100% though but the evidence leads me to believe this is what is happening.  I stated in my previous post that I used PrintToConsole to output different messages so that I could see what the flow was.  It showed poison kill from the Finish Block then the conventional kill.  But this doesn't make sense now that I know that any poison could make this happen.  Plus when I used a Damage Health poison the code never got into the section where you manually kill the actor with the KILL command.  Lastly, the actor was dead before the Poison script was even started.  So with this in mind, I believe that the real flow is conventional kill then poison falls through to the Finish Block.  There must be some kind of delay in the Event Handler in calling the function OBXPfnOnDeath that lets the Finished block happen first, or maybe some kind of recursive call going on and as it backs out of the call it reverses the order, or just one of the many quirks with Oblivion.  I really don't know at this point.

 

One thing to know, is that even though the actor is dead and you would think the Poison script shouldn't start, it does.  I was reading on Wiki and it states that when Spell scripts are applied to dead actors it will run a few frames before it stops.  In my testing, I get into the Start block and 3 frames into the Update block and then into the Finished block. 

 

Now that I am operating under these assumptions things make more sense.  I can now come up with a logical reason to why this is happening and it is quite simple.  So when the actor dies the Poison script starts, your code saves the misc stats for NPC and Creature kills to the variables 'pkills' and 'ckills', but since the actor is dead you save the updated stats.  Now the Poison ends and falls to the Finished block.  The first check it runs into is the killRegisterd variable.  Neither the Start or Update block made the kill, so the check fails and continues through.  Next it checks that the actor is dead and it is and continues through.  The next check is the Object Type, which it passes so it continues.  Now here is the issue.  The next check is with the saved variables 'pkills' and 'ckills' where it checks for a change in value.  There is no change as the kill happened before you saved those variable in the Start block, so the variable include the kill and it passes and the function OBXPfnOnDeath is called.  One thing to note is I do get 2 increases in my Creature stats from 872 to 874.  My test is on a Frost Imp.  So that is the theory. 

 

Are you still with me?  We're almost done!!  Hopefully this makes sense.  I have started putting code together to fix it and so far it works.  First thing to me that is a given is, if the Actor is already dead when the Poison script is started, any code in the Poison script should be ignored, skipped, by-passed, or whatever.   So the first thing I do in the Start script is check if the actor is dead.   If its dead I set a variable called 'killedBeforePoisoned' and then do a Return to get it out of that frame.  The next frame the Poison script enters the Update block where I test the variable 'killedBeforePoisoned'.  If it is true I do Return to get out of that frame.  The next frame the Poison script enters the Finished block where I test the variable 'killedBeforePoisoned' once again.  If it is true I do another Return to get out of that frame and end the script.  This last step may or may not happen depending on how many times the Update block is fired.  Doing all this makes sure none of the code, other than these checks are run from the Poison script. 

 

This is a lot like what you did with the 'killRegistered' variable.  I probably could have use that variable but I wasn't sure if it would mess anything up. 

 

So to me there are now three ways in which a death needs to be handled in the poison script; the poison itself, a Simultaneous Kill, and falling through the cracks. 

 

OK I'm done, hope your still awake!!  My head hurts, as this only took me a hour and a half to write.

Edited by Milotek

Share this post


Link to post
Share on other sites

Nope, that makes sense. If the poison kill script fires after the actor is dead, you'll get two batches of points. Ironically I had some code in the update block to check if the actor was already dead and saebel and I didn't think we needed it once we made some other fixes.

 

I don't think I'll even declare a variable. I'll just check if the actor is dead and exit the script. I'll probably have to update the killregistered variable and use that in the finish block though. I don't think I'll do the fix tonight though.

 

Edit: Well, you might be getting too many points, but I'm not getting any at all! I've turned on debugging to see what's going on, and the script that attaches the script effect to the weapon instance seems to be running too many times. I'd hold off on trying to make any script changes. The problem may not be with the poison kill script, but with the derived attributes script that clones the weapon and attaches the script effect.

Edited by AndalayBay

Share this post


Link to post
Share on other sites

Well, I found the first problem:

 

In the poison kill script, change the first line under the Script Effect Start.

 

 

    let poisonRef := ObXPDerivedAttributes.poisonRefOriginal

 

I have no idea wtf I was doing when I changed that to poisonRef. PoisonRef is wrong - it should be poisonRefOriginal. There's still a big problem with the derived attributes script which I'm sorting out right now, but that will fix the poison kill script.

Share this post


Link to post
Share on other sites

I don't think I'll even declare a variable. I'll just check if the actor is dead and exit the script. I'll probably have to update the killregistered variable and use that in the finish block though. I don't think I'll do the fix tonight though.

I thought about doing this too.  I added the check to the Update Block as it does process a few frames even after a Return in the Start Block and under certain circumstances it may be a problem.  I just wanted to be safe and it doesn't hurt anything.  Your right, the Finished Block does need the check for sure.  I used my own variable for safety and testing reasons.  I was going to clean up my code and then look into using the killRegistered variable.

 

 

Edit: Well, you might be getting too many points, but I'm not getting any at all! I've turned on debugging to see what's going on, and the script that attaches the script effect to the weapon instance seems to be running too many times. I'd hold off on trying to make any script changes. The problem may not be with the poison kill script, but with the derived attributes script that clones the weapon and attaches the script effect.

Strange that you're not getting any XP.   I still believe the Poison Script has issues as all my testing points to it.  I will agree that it way not be the only source of the issues.  I haven't looked into the Derived Attributes Script that much.  There are many functions in there that I don't understand as of yet. So for now, I will stop working on anything until you get things sorted. 

 

One thing I would change in the Derived Attributes Script is not to attach the Poison Script to the weapon if no Damage/Drain Health effect is present in the poison.  Some of the problems I am finding are made worse or more common because of this.  The Finished Block doesn't care what type of poison is falling into it. You could do a check on the poison in the Finished Block, but it would be better to fix it in the Derived Attributes Script.  Plus extra processing in the Update Block could be avoided.

Edited by Milotek

Share this post


Link to post
Share on other sites

You have to convert the poison into a scripted effect or you won't get any points for the kill. That's the Oblivion bug that the script corrects. Poison kills are not linked to the actor that delivered the poison. They kill the target with no one getting the credit for the kill - just the poison. So the poison is converted to a scripted effect so that the actor who delivered the poison gets the credit. In this case, it's the player.

 

Now, I've figured out what the problem is and I have the fix, it's just going to take some time to do all the coding. Here's the deal: SirFrederik used the Derived Attributes script to poll for a poison being added to a weapon. Once the script detected that a poison had been added, it would take the poison, clone it and add a scripted effect with the poison kill script being the script source for the scripted effect. When the script ran again in the next frame, it would test to see if the weapon had the same poison as it had in the previous frame and it wouldn't run if the poison was the same. This script has worked fine for many years.

 

The problem now is that when you use getEquippedWeaponPoison, which is the function you use to retrieve the poison on a weapon, it now reports a different form ID every time, thus breaking the script. I don't know when this change occurred. Perhaps it was with the last release of OBSE and nobody noticed. Anyway we can no longer use getEquippedWeaponPoison to detect when a poison is applied to a weapon. We can use it to retrieve the poison, but we'll have to use another mechanism to detect when the poison is applied.

 

Fortunately there is another way. I have set up a menu event handler to detect when the poison confirmation box opens and when the user clicks on the yes button. So I will know when the poison is applied to the weapon. Then I will trigger another script that will take the poison and attach the scripted effect. That script will also have to reset the state of everything so the process can be repeated when the user applies another poison. Once the scripted effect is attached to the poison, the poison kill script will run as it does now.

 

The new process does have one drawback: people won't be able to use mods that stop the confirmation message box from opening. If there was an event that I could tap into that would trigger when the poison is applied to the weapon, that would be better, but no such event exists at the moment.

 

I'll release a new version once I have all the scripting done and tested. I need to release a new version of Black Marsh as well, and that takes priority. Hopefully that won't take long.

Share this post


Link to post
Share on other sites

Hey all.

 

I'm not having any issues with applying/replacing poisons.  When I apply a poison, it only gets swapped out once.

 

Here's the code I am using:

 

 

 

if GetGS iSDRsApplyPoisonBugFix
; check if the player has applied a poison to his weapon
; if so, add poison effect to it - this effect will increase player's kill counter manually
Let rPoisonWeapon := PlayerRef.GetEquippedWeaponPoison
 
if ( rPoisonWeapon ) && ( rPoisonWeapon != sdrQ.rPoison )
 
; store reference to original poison
Let rPoisonOriginal := rPoisonWeapon
 
; clone original poison - we don't want to change the base of the original poison
Let rPoison := CloneForm rPoisonWeapon
 
; go through effects on the poison and store longest duration
Let i := 0
Let iPoisonDuration := 0
while ( i < GetMagicItemEffectCount rPoison )
if ( GetNthEffectItemDuration rPoison i > iPoisonDuration )
Let iPoisonDuration := GetNthEffectItemDuration rPoison i
endif
Let i := i + 1
loop
 
; add poison script effect item
Let iEffectCodeScript := MagicEffectCodeFromChars "SEFF" 
Let iPoisonScriptIndex := AddEffectItemC iEffectCodeScript rPoison
 
; set new effect script
Let rPoisonScript := sdrMEPoisonReplacer
SetNthEffectItemScript rPoisonScript rPoison iPoisonScriptIndex
 
; poison duration correction
Let iPoisonDuration := 4 * iPoisonDuration
SetNthEffectItemDuration iPoisonDuration rPoison iPoisonScriptIndex
 
; poison effect code
Let iEffectCodePoison :=  MagicEffectCodeFromChars "POSN" 
SetNthEffectItemScriptVisualEffectC iEffectCodePoison rPoison iPoisonScriptIndex
 
; set as hostile
SetNthEffectItemScriptHostile 1 rPoison iPoisonScriptIndex
 
; re-apply poison to weapon
Player.RemoveEquippedWeaponPoison
Player.SetEquippedWeaponPoison rPoison
 
if GetGS iSDRsDebugPoisonFix
printC "SDR: Updated poison applied to weapon.  Original:%n (%i)  Cloned:%n (%i)  Duration:%g  Index:%g" rPoisonOriginal rPoisonOriginal rPoison rPoison iPoisonDuration iPoisonScriptIndex
endif
 
Let sdrQ.rPoison := rPoison
endif
 
endif

 

 

Note that I am using a quest variable to store the ref of the new cloned poison. So the next time the script makes a pass, it checks the applied poison against the quest variable. If they are the same, then it knows to leave it alone.

 

This code is built into my player-token script and runs every .1 seconds.

 

EDIT: Really annoyed that the rest of my post keeps getting cut off!

Edited by saebel

Share this post


Link to post
Share on other sites

I don't understand why it's working for you and not in Ob XP. Other than storing the poison reference in another quest script, that's identical to Ob XP's script. In Ob XP, that if condition:

if ( rPoisonWeapon ) && ( rPoisonWeapon != sdrQ.rPoison )

is always different. In my script, the equivalent of rPoisonWeapon had a different form ID every cycle, so it never equalled rPoison, when it should have.

 

Also in the poison effect script, are you using the original poison, without the script effect attached?

 

What do you mean about the rest of your post being cut off?

Share this post


Link to post
Share on other sites

Sometimes when I post using the regular way and I include spoiler or code, everything after the spoiler/code gets dropped. Not sure why.

 

I'd have to look at your script, but I think it's different every time because you aren't storing the resulting poison from the last pass to compare it to.

 

The poison applied to the weapon is the cloned poison with the poison effect script attached.

 

Here's the full poison effect script:

 

 

scn sdrMEPoisonReplacer

;this script was originally created by Andalay Bay and modified to sync with SDR approach

;this is a script effect that is added to any poison on the player's weapon
;it manually increases the player's kill counter if the actor it's applied to was killed by the poison
;the script will only run for the duration of the poison

ref rActor
ref rPoison
short iDebug

float fKillsCreatures
float fKillsNPCs

short iCodeDGHE
short iCodeDRHE
short iCodeFIDG
short iCodeFRDG
short iCodeSHDG

float fDamageDone
short iEffectNum
short iEffectCount

float fResistPoison
float fActorHealth
short iKillRegistered

float fScriptTimer

begin ScriptEffectStart

; get reference to the actor the poison is on (the target of the player)
	let rActor := GetSelf

; exit early in case for some weird reason the target is not an NPC or Creature
	if rActor.GetObjectType < 35 || rActor.GetObjectType > 36
		return
	endif		

; get reference to the original poison
	let rPoison := sdrQ.rPoison

; Check for debug mode
	let iDebug := GetGS iSDRsDebugPoisonFix

; get current values for creature and NPC kills
	let fKillsCreatures := GetPCMiscStat 5
	let fKillsNPCs := GetPCMiscStat 6

; establish effect codes
	let iCodeDGHE := MECodeFromChars "DGHE"
	let iCodeDRHE := MECodeFromChars "DRHE"
	let iCodeFIDG := MECodeFromChars "FIDG"
	let iCodeFRDG := MECodeFromChars "FRDG"
	let iCodeSHDG := MECodeFromChars "SHDG"

;go through all effects on the poison and calculate damage done by each effect
	let fDamageDone := 0
	let iEffectNum := 0
	let iEffectCount := GetMagicItemEffectCount rPoison
	while ( iEffectNum < iEffectCount )
;		initial damage equals spell magnitude
; 		sum up the damage from the health related effects only (damage health, drain health, fire damage, frost damage, shock damage)
; 		need to consider individual resistances before adding to total damage done.  Negative resistance is a weakness, so the damage
; 		will be increased.
		if ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeDGHE )
			let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum
		elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeDRHE )
			let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum
		elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeFIDG )
			let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistFire ) / 100
		elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeFRDG )
			let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistFrost ) / 100
		elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeSHDG )
			let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistShock ) / 100
		endif

		let iEffectNum += 1
	loop

; defenses against poison damage include resist poison, and resist elemental effects, calculated above weakness to poison enhances damage
	let fResistPoison := (100 - rActor.getAV ResistPoison) / 100
	let fDamageDone := fDamageDone * fResistPoison
	let fActorHealth := rActor.getAV Health

; check if damage is enough to kill the rActor - need to compare before and after misc. stats and possibly use kill command to get death to register
	if (( fDamageDone >= fActorHealth ) && ( fActorHealth > 0 ))
		rActor.kill PlayerRef
		if iDebug
			PrintToConsole "SDR: Poison killed %n!" rActor
		endif
		let iKillRegistered := 1
	endif

end

begin ScriptEffectUpdate
	let fScriptTimer := fScriptTimer + ScriptEffectElapsedSeconds 
	if ( fScriptTimer >= 0.98 )
		let fScriptTimer := 0

;		go through all effects on the poison and calculate damage done by each effect
		let fDamageDone := 0
		let iEffectNum := 0
		let iEffectCount := GetMagicItemEffectCount rPoison
		while ( iEffectNum < iEffectCount )
			if ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeDGHE )
				let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum
			elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeDRHE )
				let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum
			elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeFIDG )
				let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistFire ) / 100
			elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeFRDG )
				let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistFrost ) / 100
			elseif ( ( GetNthEffectItemCode rPoison iEffectNum ) == iCodeSHDG )
				let fDamageDone += GetNthEffectItemMagnitude rPoison iEffectNum * ( 100 - rActor.getAV ResistShock ) / 100
			endif
			let iEffectNum += 1
		loop

		let fResistPoison := (100 - rActor.getAV ResistPoison) / 100
		let fDamageDone := fDamageDone * fResistPoison
		let fActorHealth := rActor.getAV Health
;		check if damage is enough to kill the actor
		if (( fDamageDone >= fActorHealth ) && ( fActorHealth > 0 ))
			rActor.kill PlayerRef
			if iDebug
				PrintToConsole "SDR: Poison killed %n! (scenario 1)" rActor
			endif
			let iKillRegistered := 1
		endif
	endif
end

begin ScriptEffectFinish

	let sdrQ.rPoison := 0

; the resistances of certain creatures isn't captured properly, so they die in between the update cycles
; try to capture those cases here - return in update cycle not working.  Also need to account for critter
; dying by brute force, in which case the kill will be registered by the regular kill script.

	if iKillRegistered
		return
	endif

	if rActor.GetDead
		if rActor.IsCreature
			if ( GetPCMiscStat 5 == fKillsCreatures )
				ModPCMiscStat 5 1
				if iDebug
					PrintToConsole "SDR: Poison killed %n! (scenario 2)" rActor
				endif
; 				check for assassination skill up directly, because OnDeath handler probably missed it
				if PlayerRef.isSneaking
					Call sdrEHAssassinationCheck rActor PlayerRef 1
				endif
			endif
		else
			if ( GetPCMiscStat 6 == fKillsNPCs )
				ModPCMiscStat 6 1
				if iDebug
					PrintToConsole "SDR: Poison killed %n! (scenario 3)" rActor
				endif
; 				check for assassination skill up directly, because OnDeath handler probably missed it
				if PlayerRef.isSneaking
					Call sdrEHAssassinationCheck rActor PlayerRef 1
				endif
			endif
		endif

	endif

end

 

 

Hope that helps.

Share this post


Link to post
Share on other sites

No, the script was capturing the base poison from the last round. I think I'll try storing it in a separate script like you are. Perhaps for some odd reason, that's the key. I can use that same reference in the poison effect script, like you are.

 

It's still odd that it's worked all this time and has only broken recently.

 

In terms of posting, there are some bugs with the RT Editor. We're hoping IPS finally gets them fixed in version 4.

Share this post


Link to post
Share on other sites

If you'd like to clean your script up a bit, you don't need the rPoisonOriginal variable. That's what Ob XP was using to track the original poison. It was being used in the poison effect script.

Share this post


Link to post
Share on other sites

No, the script was capturing the base poison from the last round. I think I'll try storing it in a separate script like you are. Perhaps for some odd reason, that's the key. I can use that same reference in the poison effect script, like you are.

 

It's still odd that it's worked all this time and has only broken recently.

 

In terms of posting, there are some bugs with the RT Editor. We're hoping IPS finally gets them fixed in version 4.

It shouldn't be capturing and comparing against the base poison. It needs to capture and compare against the cloned/modified poison with Poison Effect Script.

 

If you'd like to clean your script up a bit, you don't need the rPoisonOriginal variable. That's what Ob XP was using to track the original poison. It was being used in the poison effect script.

I kept it in there for debugging so that I could show the IDs of the original poison as well as the cloned poison. Technically I could use "rPoisonWeapon", but since that variable could potentially store the cloned poison, I like the separation as it eliminates confusion in my head. However, I'm probably going to change rPoison to rPoisonCloned for similar reasons.

 

This really spells it out:

 

 

	if GetGS iSDRsApplyPoisonBugFix
;		check if the player has applied a poison to his weapon
;		if so, add poison effect to it - this effect will increase player's kill counter manually
		Let rPoisonCurrent := PlayerRef.GetEquippedWeaponPoison

		if ( rPoisonCurrent ) && ( rPoisonCurrent != sdrQ.rPoisonCloned )

;			store reference to original poison
			Let rPoisonOriginal := rPoisonCurrent

;			clone original poison - we don't want to change the base of the original poison
			Let rPoisonCloned := CloneForm rPoisonCurrent

;			go through effects on the poison and store longest duration
			Let i := 0
			Let iPoisonDuration := 0
			while ( i < GetMagicItemEffectCount rPoisonCloned )
				if ( GetNthEffectItemDuration rPoisonCloned i > iPoisonDuration )
					Let iPoisonDuration := GetNthEffectItemDuration rPoisonCloned i
				endif
				Let i := i + 1
			loop

;			add poison script effect item
			Let iEffectCodeScript := MagicEffectCodeFromChars "SEFF" 
			Let iPoisonScriptIndex := AddEffectItemC iEffectCodeScript rPoisonCloned

;			set new effect script
			Let rPoisonScript := sdrMEPoisonReplacer
			SetNthEffectItemScript rPoisonScript rPoisonCloned iPoisonScriptIndex

;			poison duration correction
			Let iPoisonDuration := 4 * iPoisonDuration
			SetNthEffectItemDuration iPoisonDuration rPoisonCloned iPoisonScriptIndex

;			poison effect code
			Let iEffectCodePoison :=  MagicEffectCodeFromChars "POSN" 
			SetNthEffectItemScriptVisualEffectC iEffectCodePoison rPoisonCloned iPoisonScriptIndex

;			set as hostile
			SetNthEffectItemScriptHostile 1 rPoisonCloned iPoisonScriptIndex

;			re-apply poison to weapon
			Player.RemoveEquippedWeaponPoison
			Player.SetEquippedWeaponPoison rPoisonCloned

			if GetGS iSDRsDebugPoisonFix
				printC "SDR: Updated poison applied to weapon.  Original:%n (%i)  Cloned:%n (%i)  Duration:%g  Index:%g" rPoisonOriginal rPoisonOriginal rPoisonCloned rPoisonCloned iPoisonDuration iPoisonScriptIndex
			endif

			Let sdrQ.rPoisonCloned := rPoisonCloned
		endif

 

 

Gotta jet. I'll check back later.

Edited by saebel

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×