Jump to content

How to remove an equipped item?


NameNotPresent

Recommended Posts

Used in this context the RemoveMe commands should work.

 

The Wiki page disagrees on its use via explicit referencing, "shield.RemoveMe", but following basic ObScript syntax it should still work regardless.

The OBSE command, however, is documented to work exactly that way.

 

But it depends on how you obtained "shield" in this case.

If the script itself is running on the item (an Object script attached to the item to be removed), the non-explicit use "RemoveMe" or "RemoveMeIR" without any calling reference given (the object the script is running on is implicitly used as the calling reference automatically where omitted) is almost guaranteed to work.

 

Though if the reference "shield" was obtained via basic inventory access functions, like "set shield to actor.GetEquippedObject <slot>" or "set shield to actor.GetEquipmentSlotMask <slotmask>", what those returned were the "Base Objects" of the items equipped, not the actual references, thus their return value cannot be used as a calling reference to "RemoveMe" or "RemoveMeIR".

 

So, could you give us perhaps a little more of the script framework surrounding your use of "RemoveMe" or "RemoveMeIR" so we could spot any possible mistakes in that area as well?

Link to comment
Share on other sites

Here is the whole script. This scripted is called by an event handler. I am also trying to decide/figure out, how to track whether or not the hit was a power attack.

 

I have tried various methods to remove the shield includeing trying to unequip it first, which did not work either.

 

 

scn AAANNPonhitFunction

ref target
ref attacker
ref attackweapon
short KnockawayChance
short knockawayforce
short targetagility
short attackweapontype
float attackweaponSPEED
short shieldbreakChance
float shieldHealth
ref shield

begin function { target, attacker }
set attackweapon to attacker.GetEquippedObject 16
set attackweapontype to attackweapon.GetWeaponType
set attackweaponSPEED to attackweapon.GetWeaponSpeed
if target.IsBlocking ==1
;--------------------------------------------------------------------- Shield Break Chance
if target.IsShieldOut ==0
return
else
set shieldbreakChance to GetRandomPercent + 1
set shieldHealth to target.GetEquippedCurrentHealth 13
if shieldHealth <=100
set shieldHealth to shieldHealth / 2
endif
if attackweapontype ==2 ;Effect of 1H Blunt
if shieldbreakChance <=10
set shield to target.GetEquippedObject 13
shield.UnequipMe
shield.RemoveMeIR
endif
else
if attackweapontype ==3 ;Effect of 2H Blunt
if attackweaponSPEED <=0.65
if shieldbreakChance <=20
set shield to target.GetEquippedObject 13
target.SetEquippedCurrentHealth 0 13
target.RemoveItemNS shield 1
endif
endif
else
return
endif
endif
endif
;---------------------------------------------------------------------------------------
else
;---------------------------------------------------------------------- Knockback chance on attack
;MessageEX "Weapon is %n", attackweapon
if attackweapontype ==3
if attackweaponSPEED <=0.65
set KnockawayChance to GetRandomPercent + 1
if KnockawayChance > 70
set targetagility to target.GetActorValue agility
set knockawayforce to 40/(1+targetagility*-.008)
attacker.PushActorAway target, knockawayforce
endif
endif
endif
;-----------------------------------------------------------------------
endif
;target.PlayMagicShaderVisuals effectFireDamage 1
;attacker.PlayMagicShaderVisuals effectFrostDamage 1
end

Edited by NameNotPresent
Link to comment
Share on other sites

The problem is probably, as Drake said, the part where you set the 'shield' to a "<ref>.GetEquippedObject <slot>" that returns the base object, not the reference currently equipped. That is why RemoveMeIR will not work, as the 'shield' is not referring to the one equipped but the base object of the equipped item.

 

You can get the reference (not base object) using ForEach loop with a ref iterator-sort-of-thingy-whatever-it-is-named, which will return a reference. A ForEach with a ref could probably work like that in your case (also found in OBSE command documentation):

ref rActor  ; Actor, the 'container' in this loop
ref rTemp   ; Temporary ref pointing to the reference, not base object

ForEach rTemp <- rActor
    If ( rTemp.GetEquipmentSlot == 13 )   ; For example
        ; Here, rTemp can be used OR - as you would probably want to do,
        ; as you want to get the refs, store it in another variable, like 'shield'
    ElseIf ( ...)
        ...
    EndIf
Loop
With that one in use, your script, when using references instead of base objects, might look like that (not like that, but maybe work in a way that distantly resembles it):


ScriptName AAANNPonhitFunction

ref    rTemp
ref    rTarget
ref    rAttacker
ref    rAttackerWeapon
short  iAttackerWeaponType
float  fAttackerWeaponSpeed
short  iKnockawayChance
float  fKnockawayForce
short  iTargetAgility
ref    rTargetShield
short  iTargetShieldBreakChance
float  fTargetShieldHealth

Begin Function { rTarget, rAttacker }

    ForEach rTemp <- rAttacker  ; Find attacker's weapon
        If ( rTemp.GetEquipmentSlot == 16 ) && ( rTemp.IsEquipped )
            let rAttackerWeapon := rTemp
        EndIf
    Loop

    ; If attacker has no weapon, and is armed with fists? Should the rest if the script be ignored?
    If ( rAttackerWeapon == 0 )
        MessageEX "%n has no weapon in slot 16", rAttacker
        Return
    EndIf

    ForEach rTemp <- rTarget   ; Find target's shield
        If ( rTemp.GetEquipmentSlot == 13 ) && ( rTemp.IsEquipped )
            let rTargetShield := rTemp
        EndIf
    Loop

    let iAttackerWeaponType  := rAttackerWeapon.GetWeaponType
    let fAttackerWeaponSpeed := rAttackerWeapon.GetWeaponSpeed

    If ( rTarget.IsBlocking )
        ;--------------------------------------------------------------------- Shield Break Chance
        If ( rTarget.IsShieldOut == 0 )
            Return
        EndIf
        let iTargetShieldBreakChance := GetRandomPercent + 1
        let fTargetShieldHealth      := rTargetShield.GetCurrentHealth
        If ( fTargetShieldHealth <= 100 )
            let fTargetShieldHealth /= 2   ; Not sure why this is done... ?
            ; Is this one below what you wanted? I commented it out in case not.
            ;rTargetShield.SetCurrentHealth fTargetShieldHealth
        EndIf
        If ( iAttackerWeaponType == 2 && iTargetShieldBreakChance <= 10 )
            ; Blunt 1H Effect
            ;rTargetShield.UnequipMe ; Probably unnecessary?
            rTargetShield.RemoveMeIR
        ElseIf ( iAttackerWeaponType == 3 && fAttackerWeaponSpeed <= 0.65 && iTargetShieldBreakChance <= 20 )
            ; Blunt 2H Effect
            ;rTargetShield.SetCurrentHealth 0  ; Probably unnecessary?
            ;rTargetShield.UnequipMe           ; Probably unnecessary?
            rTargetShield.RemoveMeIR
        EndIf
        Return
        ;---------------------------------------------------------------------------------------
    Else
        ;----------------------------------------------------------------------        Knockback chance on attack
        ;MessageEX "Weapon is %n", rAttackerWeapon
        If ( iAttackerWeaponType == 3 && fAttackerWeaponSpeed <= 0.65 )
            let iKnockawayChance := GetRandomPercent + 1
            If ( iKnockawayChance > 70 )
                let iTargetAgility  := rTarget.GetActorValue Agility
                let fKnockawayForce := ( 40 / ( 1 + iTargetAgility * ( -1 ) * 0.008 ) )
                rAttacker.PushActorAway rTarget, fKnockawayForce
            EndIf
        EndIf
        ;-----------------------------------------------------------------------
    EndIf

    ;rTarget.PlayMagicShaderVisuals effectFireDamage 1
    ;rAttacker.PlayMagicShaderVisuals effectFrostDamage 1

End
Something like that? It is guaranteed to be 100% untested. But the idea should be clear. Also, from what I have read, Oblivion processes (or at least reads) also every line inside If statements. So making them short is usually recommended. At least the overly long ones. I put all the conditions on the same line because of that. Might not be necessary, but at least it makes the code easier to read and a bit shorter. Or at least in my opinion. :)

 

Edit: Maskar also beat me to it. I really need to learn to type faster. :(

 

Edit 2: Also, I do not know if there are other commands to get inventory references. ForEach two times in a row... looks odd now. But maybe it is fine. I have no idea what its performance impact is compared to possible other functions to get a reference. But maybe it is not too much?

Edited by PhilippePetain
Link to comment
Share on other sites

That is a big help thank you.

 

let fTargetShieldHealth /= 2 ; Not sure why this is done... ?

 

That is done to double the break chance.

 

I have not been using the "&&" for the if statement because the wiki advised against it and I read on the nexus that Oblivion will check both connditions even if it has found one to be false.

 

I should add that return at the begining too.

Link to comment
Share on other sites

All right. You are welcome. But if you want to double the break chance, should you divide the break chance instead, to 'double' it, if the chance to break is greater the smaller the breaking chance variable is? In my example, that would then be

let iTargetShieldBreakChance /= 2

instead of the current one with shield health. As it would seem that you are currently dividing the health by two, instead of the break chance variable. Not just in my example, but also in your original script, there is this:

if shieldHealth <= 100
    set shieldHealth to shieldHealth / 2
endif

When it should probably be this ( to use the "/=" from OBSE to make it easier):

if shieldHealth <= 100
    let shieldBreakChance /= 2
endif

Maybe? I am not sure. You are welcome. :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...