Question - Unmodified Actor Values

Post » Fri Mar 25, 2016 6:06 am

Hello @ll,



I need some help regarding unmodified actor values.



Despite the two commands, getbaseav (CS) and getbaseav2 (obse) i do utilize the following code snippet (function)


to retrieve a totally unmodified base actor value. As you can see Tejon provided this function to me, because the two aforementioned commands didnt do the work.



scn egmFNgetPUAV
; by Tejon / Fundament

ref myself
int av
int index
array_var each
int tempPUAV1
int tempPUAV2

begin _Function {myself, av} // av is the actor value code to be retrieved in its unaltered form

if (av == 256) // this value is used to query Fatigue, which is Attribute 0, 2, 3, 5 multiplied by Speed
let tempPUAV1 := myself.GetBaseAV 0
let tempPUAV1 += myself.GetBaseAV 2
let tempPUAV1 += myself.GetBaseAV 3
let tempPUAV1 += myself.GetBaseAV 5
let tempPUAV2 := myself.GetBaseAV 4
else // this is the standard case for querying ONE unaltered base value
let tempPUAV1 := myself.GetBaseAV av
let tempPUAV2 := 1
endif

foreach each <- myself.GetActiveEffectCodes
if eval !(myself.IsNthActiveEffectApplied each["key"])
CONTINUE
endif
if eval !((GetSpellType (myself.GetNthAEMagicItem each["key"])) == 4)
CONTINUE
endif
let index := myself.GetNthAEAV each["key"]
if (av == 256) // this is the special case again
if (index < 0) || (index > 5)
CONTINUE
elseif (index == 0)
if eval !(MagicEffectUsesAttribute each["value"])
CONTINUE
endif
elseif (index == 1)
CONTINUE
endif

if(index == 4)
let tempPUAV2 -= myself.GetNthAEMagnitude each["key"]
else
let tempPUAV1 -= myself.GetNthAEMagnitude each["key"]
endif
else // standard query for ONE unaltered base value
if (index != av)
CONTINUE
endif

if (index == 0)
if eval !(MagicEffectUsesAttribute each["value"])
CONTINUE
endif
endif
let tempPUAV1 -= myself.GetNthAEMagnitude each["key"]
endif

Loop

;let each := ar_Null

SetFunctionValue (tempPUAV1 * tempPUAV2)


end
;
; 1062
;


Unfortunately this function is used a lot during EGM modded gameplay, and RuntimeScriptProfiler states this function as the worst cycle eater.


Is it possible to implement a better solution based on a obse function, since I do not understand why this hasnt been done anyway?


This would help a lot.



Thank you for any help.

User avatar
sunny lovett
 
Posts: 3388
Joined: Thu Dec 07, 2006 4:59 am

Post » Fri Mar 25, 2016 6:48 am

Have you tried with http://cs.elderscrolls.com/index.php?title=GetTotalActiveEffectMagnitude?

Let baseVal := (myself.GetAV av) - (myself.GetTotalAEMagnitudeC av) - (myself.GetAVMod av damage)
This should replace that whole function (you may need a specific case for fatigue).


With this idea, you start from the current value, remove any damage (which is not listed in the active effects) to obtain the "undamaged" value. Finally, you remove any modifier in the active effects.


It's not a great idea, but starting from the current value (which is correct) is faster than starting from the base or base2 values, which are both wrong, and you need to make strange (and expensive) calculations to fix them.
User avatar
leni
 
Posts: 3461
Joined: Tue Jul 17, 2007 3:58 pm

Post » Fri Mar 25, 2016 1:12 am


As far as i know GetTotalAEMagnitudeC doesnt do the work.


Look at the special cases Tejon did recognize.


And his function works.



I could try to implement this as well, and do a comparison, test it by trying it some time.


But I remind it didnt work, as I tried this before.

User avatar
Lucky Girl
 
Posts: 3486
Joined: Wed Jun 06, 2007 4:14 pm

Post » Fri Mar 25, 2016 6:23 am



Why shouldnt then



Let baseVal := (myself.GetAV av) - (myself.GetAVMod av damage) - (myself.GetAVMod av max) - (myself.GetAVMod av script)

do the work?



PS:


My proposal did not work.


It didnt recognise Lady's Blessing, an ability which grants +10 endurance.


I think I remember the discussion about fortify effects from birthsigns.



PSPS:


Same problem with your version.

User avatar
Benjamin Holz
 
Posts: 3408
Joined: Fri Oct 19, 2007 9:34 pm

Post » Fri Mar 25, 2016 4:21 am

Ok, let's do an introduction to the REAL problem first:


Attributes are made of 4 components: base, max, script, damage.


  • Base: I hope it doesn't need an explanation

  • Max: altered by Fortify, Drain and Absorb Skill/Attribute effects

  • Script: only altered by scripts with the "ModAV av" or "Set/ModAVMod script" (for some reason, ModAV, if called from console, alter the base value instead!)

  • Damage: altered by getting hit or by falling (health), cast spells (magicka), do actions (fatigue) or altered by magic effects like Fire Damage, Health Damage, Absorb Fatigue, etc...


The command GetBaseAV is not bugged. GetBaseAV correctly return the Base component.



The problem is caused by how the game handle abilities: in abilities, the Fortify, Drain and Absorb Skill/Attribute effects are different: they alter the Base component (instead of the Max component).


Nobody knows what the programmers were smoking when they did this... anyway, this causes many problems like GetAV and GetBaseAV returning wrong values (but it's not their fault!).


The proof is in the OBSE plugin OBME: it adds a flag in every spell which (if enabled) fix this behaviour, so those effects correctly alter the Max component even in abilities (the flag is specific for every spell, so a mod must be made to enable it, one by one, on every spell in the game).



GetBaseAV2 instead is really bugged, as it try to remove the effects from abilities... but http://cs.elderscrolls.com/index.php?title=Talk:GetBaseAV2.


Example: Real Base 100, Ability Fortify = 20, Ability Drain = -5, Total Base = 115.


Expected result: Total Base - Ability Fortify - Ability Drain = 115 - 20 - (-5) = 100.


GetBaseAV2 result: Total Base - Ability Fortify + Ability Drain = 115 - 20 + (-5) = 90





Now, back to the problem:


Abilities alterations are included in the Base component, so getting the Base/Current value and subtracting the Damage, Max and Script components won't fix the problem.


You need to start from Base and remove the fortify/drain/absorb effects from abilities (only doable with the above ForEach or with GetTotalAEMagnitude).



I made 2 errors in my previous answer:


1) GetAV is influenced by the Abilities bug exactly like GetBaseAV, so better use GetBaseAV directly and avoid subtracting the Damage component


2) The GetTotalAEMagnitude doesn't take the attribute code, but the magic effect code. If we need to remove any alteration to (example) Strength, we need to remove all active effects FOAT and DRAT which alter the Strength attribute. My code was obviously wrong, as I was passing the attribute code to the command.

User avatar
Lisa
 
Posts: 3473
Joined: Thu Jul 13, 2006 3:57 am

Post » Fri Mar 25, 2016 1:44 pm


and why is noone able to correct the wrong obse code, and offer the compiled .dll as download?

User avatar
Agnieszka Bak
 
Posts: 3540
Joined: Fri Jun 16, 2006 4:15 pm

Post » Fri Mar 25, 2016 3:04 am

That's a ShadeMe question. He's currently maintaining the OBSE source code.
User avatar
ANaIs GRelot
 
Posts: 3401
Joined: Tue Dec 12, 2006 6:19 pm

Post » Fri Mar 25, 2016 12:39 pm

Because OBSE is abandoned and Alenet is the only one left in the Oblivion community who's able to do such miracle (shadeMe is not working on it anymore), but it's already very busy with OR.



Anyway, can you try with this:



Let baseVal := (GetBaseVal av) - (GetTotalAEMagnitude FOAT av) - (GetTotalAEMagnitude DRAT av) - (GetTotalAEMagnitude ABAT av)

This code should get the base and subtract all FOAT, DRAT and ABAT effects which alter that attribute. This is for attributes.


if you're working on skills, you'll need FOSK, DRSK and ABSK instead.


For Health, Magicka and Fatigue you won't need the Absorb part (as it alter the Damage component for them), and you will need (respectively) FOHE & DRHE, FOSP & DRSP and FOFA & DRFA.



Note 1: You can call the function directly on the actor with "actorRef.Call egmFNgetPUAV, av", so you can avoid to pass myself as parameter.


Note 2: If you call the function directly on the actor, you don't need to do "myself." anymore, as any command will be called automatically on the function calling reference (the actor).

User avatar
Matthew Warren
 
Posts: 3463
Joined: Fri Oct 19, 2007 11:37 pm

Post » Fri Mar 25, 2016 7:51 am


I know, Forli, I already tried this.


Problem is, it should only find spelltype 4, abilities.



Let baseVal := (GetBaseVal av) - (GetTotalAEAbilityMagnitude FOAT av) - (GetTotalAEAbilityMagnitude DRAT av) - (GetTotalAEAbilityMagnitude ABAT av)

This should work, I will try, and give feedback.



PS:



Seems to work!



Thanks everyone. You've been a great help, as always! May Mara bless you. :wave:

User avatar
No Name
 
Posts: 3456
Joined: Mon Dec 03, 2007 2:30 am

Post » Fri Mar 25, 2016 11:32 am

Little typo: it should be GetBaseAV (and not GetBaseVal), but I guess you figured it out yourself.


It's great it works! Is it also faster?

User avatar
joeK
 
Posts: 3370
Joined: Tue Jul 10, 2007 10:22 am

Post » Fri Mar 25, 2016 11:00 am


I will post tonite, after playing for 30 minutes, and update. I think it should run substantially faster. ^_^




PS:


Woah!!



Everything got faster!


Even nGCD and Fundament, which are both now under Duke Patricks Combat Archery.


Somehow my mod took influence on both of Tejons mods, and slowed them down!


What I can't explain right now.


It only run for 5 minutes, I must try longer like half an hour, but it seems to be faster around factor 10.


The whole stuff!

User avatar
Del Arte
 
Posts: 3543
Joined: Tue Aug 01, 2006 8:40 pm

Post » Fri Mar 25, 2016 2:09 am

The (GetTotalAEAbilityMagnitude ABAT av) part can be removed, because Absorb effects can't be of 'ability' type (no self range for them) and use different effect handler anyway.

User avatar
Damien Mulvenna
 
Posts: 3498
Joined: Wed Jun 27, 2007 3:33 pm

Post » Fri Mar 25, 2016 2:38 am

Ok, runs definitely faster now.


Funny, how everything slowed down.


Especially nGCD and Fundament.


On one side I am surprised, but positively.


Now, I understand better why the Oblivion engine is amazing.


The engines "flaws" are scaling issues.


Obviously heavy scripts slow down the whole steam train, as EGM did.


It is wonderful to see how fast it runs now.


Amazing.


And it is great to hear alenet is the obse dev now.



onward. :clap:

User avatar
Danny Blight
 
Posts: 3400
Joined: Wed Jun 27, 2007 11:30 am

Post » Fri Mar 25, 2016 1:48 am

Actually, I said Alenet is the only one left able to do this.


He still hasn't accepted (at least officially) to be the next OBSE developer.


He's still finishing OR and then he already promised SR (Skyrim Reloaded).



Maybe he will be the next OBSE developer... who knows? But he won't be able to work on it for some time.


OR took about 2 years (and it's still not finished). How much will it take for SR?

User avatar
Mandi Norton
 
Posts: 3451
Joined: Tue Jan 30, 2007 2:43 pm

Post » Fri Mar 25, 2016 3:45 am

Generally speaking, anything you can do to reduce the number of lines run and code in memory, the better. For example, let's say you have a massive subroutine built directly into a token script. However, if that routine doesn't get called all the time (maybe it's on a timer or there are specific circumstances that trigger it), then it may be worth moving that subroutine into a function call script.


Also, look for any opportunity to return early out of a script, otherwise the game will look at every line of code, even sections where the "if" or "elseif" criteria isn't satisfied. It doesn't do anything with it, but it wastes time as it goes line by line until it hits a return or gets to the end of the script. You might know that already, but if not, it's important when you have a script heavy mod.


I have personally had tons of performance issues with SDR, and over time I've learned tons about the most efficient methods of coding scripts. I've also been moving a lot of my scripted functions out of the .esp/.esm and directly into my sdr.dll OBSE plugin. I went from having my detection formula completely scripted, to moving some of the chunks outside the formula to scripted updating tokens, to pieces of the formula be calculated with my OBSE plugin. And as of this last pass, the entire detection formula has moved out of the scripts entirely. It's been incredibly difficult. Amd although I'm proud of the bits I figured out on my own, it took real c++ programmers to do the hard stuff.
User avatar
Michael Russ
 
Posts: 3380
Joined: Thu Jul 05, 2007 3:33 am


Return to IV - Oblivion