Jump to content

[WIP] Break Undies Framework


JosefGrey

Recommended Posts

 

why the clothes is transparent in my game?when I give the clothes to female npc it just display a nude body canyou help me?

 

Try a thing. Drop down armor, take it again and equip. Vualá.

 

It didn't work.....I cound't see anything when I droped the armor on the ground........

Link to comment
  • 3 weeks later...

If the clothes are not set for a custom race (or even a vanilla race) then they won't show.  That's one thing the Racial Compatibility Mod is supposed to fix (for custom races).

 

You'd have to look at the mod in the CK to see if it supports the race you are playing.

Link to comment
  • 1 month later...

I really wish the CK allowed deeper changes to the game (such as assigning multiple keywords to crafting categories or creating new categories altogether), because I just had an idea regarding BU that might have been feasible if I could just introduce new tempering qualities to the game. Also if there was a function to set armor quality.

 

Basically I wanted to add three new qualities below the standard quality, so the progression would look like this: Broken -> Damaged -> Poor -> Standard -> Fine - > Superior -> Exquisite -> Flawless -> Epic -> Legendary. Whenever a BU-scripted armor gets hit, it will check the damage against its armor value, if it exceeds a certain threshold it will increase a counter by 1 (say damage is twice the armor value, for example), and once you hit 10 it knocks your quality down one level (and resets the counter to 0). To repair the armor you simply temper it again, so there would already be a built-in system for damage persistence and repairing functionality; it would also reflect the fact that it takes longer and more severe hits for high quality armor to start breaking up.

 

Ah well, if wishes were horses I'd be smelling of horse shit all day.

Link to comment
  • 1 month later...
  • 2 weeks later...

Oh god, why am I doing this? I'm the last person who should be doing this. I feel like Dan Aykroyd in the operating scene in "Spies Like Us".

 

Anyway, I was asked to try modifying this BU framework to work on a per hit basis instead of current health basis, so after some Googling, quality brainstorming on the can, and tea leaves reading, I've come up with an idea. Basically it'll be two scripts: the one attached to the armor will use JosefGrey's DAF function and second script will be attached to a quest, which is the only (annoyingly enough) way to attach OnHit to the player. Rough (non-working) version looks like this:

 

 

 

Scriptname aaDAFArmorScript extends ObjectReference  

Armor[] Property DynamicArmorProperty  Auto  

int count
int numStages
int newStage
int currentStage

int Function GetNumStages(Armor[] DynArmProp) global
    int index = 1
    While (DynArmProp[index] != None)
        index += 1
    EndWhile
    index -= 1
    Return index
EndFunction

;--------------------------------------------------------------------------------------------------------------------------

Event OnEquipped(Actor akActor)
    Debug.Notification("BU armor equipped")
    count = 0
    currentStage = 1
    numStages = GetNumStages(DynamicArmorProperty)
    
    GoToState("")
    akActor.EquipItem(DynamicArmorProperty[currentStage], false, true)
    GoToState("Inactive")
    
    ; Start BU quest here
    
endEvent

;--------------------------------------------------------------------------------------------------------------------------

Event OnUnequipped(Actor akActor)
    Debug.Notification("BU armor unequipped")
    count = 1
    while (count <= numStages)
        akActor.UnequipItem(DynamicArmorProperty[count], true, true)
        akActor.RemoveItem(DynamicArmorProperty[count], 1, true)
        count += 1
    endwhile
    
    ; Stop BU quest here
    
endEvent

 

 

 

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

Armor[] Property DynamicArmorProperty  Auto  

int count
int numStages
int newStage
int currentStage

; States are to prevent psychotic AI behavior that causes threading issues.
Auto State Inactive

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    Actor akActor = Game.GetPlayer()
    Debug.Notification("Hit detected")
    if ((abHitBlocked != true) && (akProjectile == None))
        Debug.Notification("Hit was not blocked and not a projectile")
        if (abPowerAttack == true)
            Debug.Notification("The armor suffers some heavy damage. Count: " + count)
            count += 2
        else
            Debug.Notification("The armor suffers some light damage. Count: " + count)
            count += 1
        endif
    endif
    if (count >= 5)
        Debug.Notification("Count above threshold, changing stages.")
        newStage = currentStage + 1
        if (newStage <= numStages)
            Debug.Notification("Advance to next stage of damage.")
            if (akActor.GetItemCount(DynamicArmorProperty[newStage]) == 0)
                akActor.EquipItem(DynamicArmorProperty[newStage], false, true)
            endIf
            akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)
            currentStage = newStage
        else
            Debug.Notification("Armor destroyed.")
            ;akActor.UnequipItem(DynamicArmorProperty[currentStage], true, true)
            akActor.UnequipItem(DynamicArmorProperty, true, true)
            akActor.RemoveItem(DynamicArmorProperty, 1, true)
        endif
        count = 0
    endif
endEvent

EndState

 

 

 

The behavior described in these scripts will basically be:

 

- The armor starts off at full health whenever you put it on and return to full health when you take it off.

- Each stage of the armor will have 5 hit points, each unblocked melee attack deals 1 damage, while each unblocked power attack deals 2, blocked and ranged attacks will not damage the armor.

- The armor will be completely unequipped and removed (might change this to dropped) once you run out of stages.

 

Eventually I hope to implement things like using the quest stages to retain damage level even when the armor is unequipped/re-equipped, repairing whenever you interact with a forge or armor improvement table, and seeing if BU can be extended to NPCs as well (at the moment it only references the player). Currently, however, I just need to wrap my head around how I'm supposed to pass variables between scripts (declaring all the variables as globals?) and cleaning it up so it'll actually work.

 

I'll welcome any scripting advice people may have, I'll need them :D

Link to comment
  • 2 weeks later...

Oh god, why am I doing this? I'm the last person who should be doing this. I feel like Dan Aykroyd in the operating scene in "Spies Like Us".

 

Anyway, I was asked to try modifying this BU framework to work on a per hit basis instead of current health basis, so after some Googling, quality brainstorming on the can, and tea leaves reading, I've come up with an idea. Basically it'll be two scripts: the one attached to the armor will use JosefGrey's DAF function and second script will be attached to a quest, which is the only (annoyingly enough) way to attach OnHit to the player. Rough (non-working) version looks like this:

 

 

 

Scriptname aaDAFArmorScript extends ObjectReference  

 

Armor[] Property DynamicArmorProperty  Auto  

 

int count

int numStages

int newStage

int currentStage

 

int Function GetNumStages(Armor[] DynArmProp) global

    int index = 1

    While (DynArmProp[index] != None)

        index += 1

    EndWhile

    index -= 1

    Return index

EndFunction

 

;--------------------------------------------------------------------------------------------------------------------------

 

Event OnEquipped(Actor akActor)

    Debug.Notification("BU armor equipped")

    count = 0

    currentStage = 1

    numStages = GetNumStages(DynamicArmorProperty)

    

    GoToState("")

    akActor.EquipItem(DynamicArmorProperty[currentStage], false, true)

    GoToState("Inactive")

    

    ; Start BU quest here

    

endEvent

 

;--------------------------------------------------------------------------------------------------------------------------

 

Event OnUnequipped(Actor akActor)

    Debug.Notification("BU armor unequipped")

    count = 1

    while (count <= numStages)

        akActor.UnequipItem(DynamicArmorProperty[count], true, true)

        akActor.RemoveItem(DynamicArmorProperty[count], 1, true)

        count += 1

    endwhile

    

    ; Stop BU quest here

    

endEvent

 

 

 

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

 

Armor[] Property DynamicArmorProperty  Auto  

 

int count

int numStages

int newStage

int currentStage

 

; States are to prevent psychotic AI behavior that causes threading issues.

Auto State Inactive

 

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

    Actor akActor = Game.GetPlayer()

    Debug.Notification("Hit detected")

    if ((abHitBlocked != true) && (akProjectile == None))

        Debug.Notification("Hit was not blocked and not a projectile")

        if (abPowerAttack == true)

            Debug.Notification("The armor suffers some heavy damage. Count: " + count)

            count += 2

        else

            Debug.Notification("The armor suffers some light damage. Count: " + count)

            count += 1

        endif

    endif

    if (count >= 5)

        Debug.Notification("Count above threshold, changing stages.")

        newStage = currentStage + 1

        if (newStage <= numStages)

            Debug.Notification("Advance to next stage of damage.")

            if (akActor.GetItemCount(DynamicArmorProperty[newStage]) == 0)

                akActor.EquipItem(DynamicArmorProperty[newStage], false, true)

            endIf

            akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

            currentStage = newStage

        else

            Debug.Notification("Armor destroyed.")

            ;akActor.UnequipItem(DynamicArmorProperty[currentStage], true, true)

            akActor.UnequipItem(DynamicArmorProperty, true, true)

            akActor.RemoveItem(DynamicArmorProperty, 1, true)

        endif

        count = 0

    endif

endEvent

 

EndState

 

 

 

The behavior described in these scripts will basically be:

 

- The armor starts off at full health whenever you put it on and return to full health when you take it off.

- Each stage of the armor will have 5 hit points, each unblocked melee attack deals 1 damage, while each unblocked power attack deals 2, blocked and ranged attacks will not damage the armor.

- The armor will be completely unequipped and removed (might change this to dropped) once you run out of stages.

 

Eventually I hope to implement things like using the quest stages to retain damage level even when the armor is unequipped/re-equipped, repairing whenever you interact with a forge or armor improvement table, and seeing if BU can be extended to NPCs as well (at the moment it only references the player). Currently, however, I just need to wrap my head around how I'm supposed to pass variables between scripts (declaring all the variables as globals?) and cleaning it up so it'll actually work.

 

I'll welcome any scripting advice people may have, I'll need them :D

 

Hi, what kind of help do you need for this work? I can try to help for the script part if you need it.

Link to comment
  • 3 weeks later...
  • 3 weeks later...

 

Hi, what kind of help do you need for this work? I can try to help for the script part if you need it.

 

 

Oh man, sorry for the excessively late reply. Life decided to hand me a few more lemons (slipped discs, long story, lots of pain) and got it sorted out last week, but really didn't have the drive to work on this again until yesterday. I was just looking for general scripting advice, like how I should go around passing states between the scripts and such or if there are any convenient functions I should probably look into.

 

That being said, I finally got a working version done this afternoon:

 

The armor script:

 

 

Scriptname aaDAFArmorScript extends ObjectReference  

 

Armor[] Property DynamicArmorProperty  Auto  

 

GlobalVariable Property BUEquipped auto

GlobalVariable Property BUAdvanced auto

int count

int numStages

int newStage

int currentStage

;--------------------------------------------------------------------------------------------------------------------------

int Function GetNumStages(Armor[] DynArmProp) global

    int index = 1

    while (DynArmProp[index] != None)

        index += 1

    endwhile

    index -= 1

    return index

endFunction

;--------------------------------------------------------------------------------------------------------------------------

; States are to prevent psychotic AI behavior that causes threading issues.

Auto State Inactive

 

Event OnEquipped(Actor akActor)

    BUEquipped.SetValueInt(1)

    BUAdvanced.SetValueInt(0)

    numStages = GetNumStages(DynamicArmorProperty)

    currentStage = 1

    count = 1

    

    ; Check if there is a stage token in the inventory and sets that as current, in case I implement repairing

    while (count <= numStages)

        if (akActor.GetItemCount(DynamicArmorProperty[currentStage]) == 1)

            currentStage = count

        endif

        count += 1

    endwhile

    

    GoToState("")

    akActor.EquipItem(DynamicArmorProperty[currentStage], false, true)

    GoToState("Inactive")

    

    ; Check if the OnHit event in the quest script signals a stage change

    while (akActor.IsEquipped(DynamicArmorProperty[0]))

        newStage = (currentStage + (BUAdvanced.GetValueInt()))

        if ((newStage != currentStage) && (newStage <= numStages))

            Debug.Notification("Armor has been damaged.")

            if (akActor.GetItemCount(DynamicArmorProperty[newStage]) == 0)

                akActor.EquipItem(DynamicArmorProperty[newStage], false, true)

            endif

            akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

            currentStage = newStage

        elseif (newStage > numStages)

            Debug.Notification("Armor has been destroyed.")

            akActor.UnequipItem(DynamicArmorProperty[0], true, true)

            akActor.UnequipItem(DynamicArmorProperty[currentStage], true, true)

            akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

        endif

        BUAdvanced.SetValueInt(0)

    endwhile

    

endEvent

;--------------------------------------------------------------------------------------------------------------------------

Event OnUnequipped(Actor akActor)

    count = 1

    while (count <= numStages)

        akActor.UnequipItem(DynamicArmorProperty[count], true, true)

        akActor.RemoveItem(DynamicArmorProperty[count], 1, true)

        count += 1

    endwhile

    BUEquipped.SetValueInt(0)

endEvent

 

endState

 

 

 

The quest script:

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

 

GlobalVariable Property BUEquipped auto

GlobalVariable Property BUAdvanced auto

int isEquipped

int count

;--------------------------------------------------------------------------------------------------------------------------

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

    isEquipped = BUEquipped.GetValueInt()

    if (isEquipped == 1)

        if ((abHitBlocked != true) && (akProjectile == None))

            if (abPowerAttack == true)

                count += 2

            else

                count += 1

            endif

        endif

        if (count >= 5)

            BUAdvanced.SetValueInt(1)

            count = 0

        endif

    endif

endEvent

 

 

 

So what this version does is rather than track health, a quest will track OnHit events on the player. Each stage of the armor has 5 "hp", a regular melee attack deals 1 damage, a power attack deals 2, and blocking negates damage from attacks; projectiles won't damage the armor at all, but I think magic (particularly magic that ticks a lot of damage quickly) is going to shred up the armor. Once it has gone through all the stages, the armor will automatically be unequipped; I originally wanted to remove the armor from inventory entirely, but decided against it since that seemed too punitive.

 

Current reservations about this code is 1) it's not going to work when equipped on NPCs, 2) each DAF-BU-enabled armor is going to come with two scripts, which could create some stability issues as more armors are added, and 3) I couldn't avoid using a while loop in the armor script (not a fan of constantly running while loops, that chews up processes, is one of the things that can bloat orphaned scripts, and should really be what event listeners are for).

 

So now that the proof-of-concept is out of the way, I'm going to have to think about how to implement repairing. Ideally I would like something that I can just add to the quest script that waits for the player to interact with the armoring bench/blacksmith's forge and just remove all armor stage tokens in the inventory, but it's likely not going to be that easy. Additionally I would like to implement armor HP scaling based on material (so instead of a flat 5hp for each armor, it'll be something like cloth gets 5hp while dragonbone gets 20hp), which I might be able to accomplish by examining the armor's form and passing the material as a variable to the quest script.

 

But for now I should actually update the FNISEIS mod, which has been neglected for some time in my absence.

 

Edit: hmm, does anyone know if interacting with workbenches is considered an OnActivate or OnSit event? I'm leaning toward OnSit, since using Miscellaneous items in your inventory is considered an Equip event.

 

Edit Edit: It's OnSit. Used the example script on the creation kit site "Debug.Notification("Interacting with: " + akFurniture)" in an OnSit event listener and it coughed up the incredibly useless message "Interacting with: [ObjectReferenc" (in all its truncated glory) when I used a chair and a forge. At least that's something.

 

Edit à trois: Non working code time again!

 

The armor script:

 

 

Scriptname aaDAFArmorScript extends ObjectReference  

 

Armor[] Property DynamicArmorProperty  Auto  

 

GlobalVariable Property BUEquipped auto

GlobalVariable Property BUAdvanced auto

GlobalVariable Property BUStage auto

int count

int numStages

int newStage

int currentStage

;--------------------------------------------------------------------------------------------------------------------------

int Function GetNumStages(Armor[] DynArmProp) global

    int index = 1

    while (DynArmProp[index] != None)

        index += 1

    endwhile

    index -= 1

    return index

endFunction

;--------------------------------------------------------------------------------------------------------------------------

; States are to prevent psychotic AI behavior that causes threading issues.

Auto State Inactive

 

Event OnEquipped(Actor akActor)

    BUEquipped.SetValueInt(1)

    BUAdvanced.SetValueInt(0)

    numStages = GetNumStages(DynamicArmorProperty)

    currentStage = BUStage.GetValueInt

    

    ; currentStage should only be 0 if it's the first time wearing the armor or was repaired.

    ; alternatively I could just set BUStage in the CK to have a starting value of 1 and have

    ; repairing armor also set BUStage to 1, thereby eliminating this check entirely.

    if (currentStage == 0)

        currentStage = 1

    endif

    

    GoToState("")

    akActor.EquipItem(DynamicArmorProperty[currentStage], false, true)

    GoToState("Inactive")

    

    ; Check if the armor is wearable

    if (currentStage <= numStages)

        ; Check if the OnHit event in the quest script signals a stage change.

        while (akActor.IsEquipped(DynamicArmorProperty[0]))

            newStage = (currentStage + (BUAdvanced.GetValueInt()))

            if ((newStage != currentStage) && (newStage <= numStages))

                Debug.Notification("Armor has been damaged.")

                if (akActor.GetItemCount(DynamicArmorProperty[newStage]) == 0)

                    akActor.EquipItem(DynamicArmorProperty[newStage], false, true)

                endif

                akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

                currentStage = newStage

                BUAdvanced.SetValueInt(0)

            elseif (newStage > numStages)

                Debug.Notification("Armor has been destroyed.")

                akActor.UnequipItem(DynamicArmorProperty[0], true, true)

                akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

                currentStage = newStage

                BUAdvanced.SetValueInt(0)

            endif

        endwhile

    else

        Debug.Notification("This armor is too damaged to wear.")

        akActor.UnequipItem(DynamicArmorProperty[0], true, true)

    endif

    

    ; Remove stage token once armor has been removed, save the stage to global variable.

    akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)

    BUStage.SetValueInt(currentStage)

    BUEquipped.SetValueInt(0)

endEvent

 

endState

 

 

 

The quest script:

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

 

GlobalVariable Property BUEquipped auto

GlobalVariable Property BUAdvanced auto

GlobalVariable Property BUStage auto

int isEquipped

int count

int stageHP

;--------------------------------------------------------------------------------------------------------------------------

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

    stageHP = 5 ; I'll just make this a constant for now

    if (BUEquipped.GetValueInt() == 1)

        if ((abHitBlocked != true) && (akProjectile == None))

            if (abPowerAttack == true)

                count += 2

            else

                count += 1

            endif

        endif

        if (count >= stageHP)

            BUAdvanced.SetValueInt(1)

            count = 0

        endif

    endif

endEvent

;--------------------------------------------------------------------------------------------------------------------------

Event OnSit(ObjectReference akFurniture)

    ;Debug.Notification("Interacting with: " + akFurniture)

    if ((BUEquipped.GetValueInt() == 0) && (akFurniture == whateverthefuckforgesandarmortablesare))

        Debug.Notification("Repairing armor...")

        BUStage.SetValueInt(0)

    endif

endEvent

 

 

 

Changed some things around (got rid of the OnUnequipped event listener because that was just me being pedantic) and theoretically this should be how the repair implementation will look like. Basically the armor script will just save the current armor stage to a global variable instead of relying on tokens lying around the inventory and once the armor breaks you won't be able to wear it until you visit a workbench; this should allow you to unequip the armor, throw it on the ground, or toss it in a chest and it'll still be in the same damaged state when you put it back on.

 

Of course, the main obstacle to me actually compiling and testing it is that red bit in the quest script.

 

Oh, and here's the Amiella armor with my script (just realized I also forgot to hide the armor stage tokens):

Link to comment

Figured out the red bit in the test script above, so armor stage persistence and basic repairing have been implemented. You can only repair damaged armor when it isn't equipped, visiting a forge or armor workbench (not the anvils you find outside the estates in Hearthfire though, those lack the isBlacksmithForge/isBlacksmithWorkbench keyword) will instantly restore it to the first stage without consuming any material or checking the player's blacksmithing skill (might try to change this later, but taking baby steps here), and you'll get a notification preventing you from equipping armor that's been completely destroyed.

 

Armor HP scaling to material hasn't been implemented yet, but it will be relatively easy now that I discovered the HasKeyword function; I would like to adapt JosefGrey's idea to scale the frequency of stage changes to the armor's HP (say Leather has 50HP, a ten stage leather armor will have 5HP each stage, or a five stage leather armor will have 10HP each stage); I wanted to give weapons the same treatment and scale the amount of damage they do to armor based on material, but gave up on that idea because claws and magic don't have keywords (and giving attacks without keywords a default value would either make dragons as effective against armor as rats or rats as dangerous as dragons).

 

That being said, that while loop in the armor script still annoys me, so I'm going to give moving everything into a single quest script a shot again.

 

The quest script:

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

Keyword Property isBlacksmithForge Auto
Keyword Property isBlacksmithWorkbench Auto

GlobalVariable Property BUEquipped auto
GlobalVariable Property BUAdvanced auto
GlobalVariable Property BUStage auto
int isEquipped
int count
;--------------------------------------------------------------------------------------------------------------------------
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    isEquipped = BUEquipped.GetValueInt()
    if (isEquipped == 1)
        if ((abHitBlocked != true) && (akProjectile == None))
            if (abPowerAttack == true)
                count += 2
            else
                count += 1
            endif
        endif
        if (count >= 5)
            BUAdvanced.SetValueInt(1)
            count = 0
        endif
    endif
endEvent
;--------------------------------------------------------------------------------------------------------------------------
Event OnSit(ObjectReference akFurniture)
    isEquipped = BUEquipped.GetValueInt()
    if ((isEquipped == 0) && (akFurniture.HasKeyword(isBlacksmithForge) || akFurniture.HasKeyword(isBlacksmithWorkbench)))
        Debug.Notification("Repairing armor...")
        BUStage.SetValueInt(0)
    endif
endEvent

 

 

 

Edit: v0.04 deleted pending update.

Link to comment

Managed to make the changes I wanted earlier than expected, so now everything is contained in a single script - no global variables, no constantly-running while loops, and no dodgy RegisterForUpdate (almost went that way to avoid the while loop until I saw it's prone to causing massive bloating) voodoo.

 

The script:

 

 

Scriptname aaDAFQuestScript extends ReferenceAlias  

Armor[] Property DynamicArmorProperty Auto
Keyword Property ArmorClothing Auto
Keyword Property ArmorLight Auto
Keyword Property ArmorHeavy Auto
Keyword Property ArmorMaterialDaedric Auto
Keyword Property ArmorMaterialDragonplate Auto
Keyword Property ArmorMaterialDragonScale Auto
Keyword Property ArmorMaterialDwarven Auto
Keyword Property ArmorMaterialEbony Auto
Keyword Property ArmorMaterialElven Auto
Keyword Property ArmorMaterialElvenGilded Auto
Keyword Property ArmorMaterialGlass Auto
Keyword Property ArmorMaterialHide Auto
Keyword Property ArmorMaterialImperialHeavy Auto
Keyword Property ArmorMaterialImperialLight Auto
Keyword Property ArmorMaterialImperialStudded Auto
Keyword Property ArmorMaterialIron Auto
Keyword Property ArmorMaterialIronBanded Auto
Keyword Property ArmorMaterialLeather Auto
Keyword Property ArmorMaterialOrcish Auto
Keyword Property ArmorMaterialScaled Auto
Keyword Property ArmorMaterialSteel Auto
Keyword Property ArmorMaterialSteelPlate Auto
Keyword Property ArmorMaterialStormcloak Auto
Keyword Property ArmorMaterialStudded Auto
Keyword Property isBlacksmithAnvil Auto
Keyword Property isBlacksmithForge Auto
Keyword Property isBlacksmithWorkbench Auto
;GlobalVariable Property DAFBUcurrentStage auto
;GlobalVariable Property DAFBUcurrentDamage auto
Actor akActor
int numStages
int newStage
int currentStage
int currentDamage
int armorHealth
int damagePerStage
;--------------------------------------------------------------------------------------------------------------------------
int Function GetNumStages(Armor[] DynArmProp) global
    int index = 1
    while (DynArmProp[index] != None)
        index += 1
    endwhile
    index -= 1
    return index
endFunction
;--------------------------------------------------------------------------------------------------------------------------
int Function GetArmorHealth(Armor[] DynArmProp)
    int total = 0
    
    ; Assigns a base HP of 30 to clothes, 40 to light armor, and 50 to heavy armor
    if (DynArmProp[0].HasKeyword(ArmorClothing))
        total += 30
    elseif (DynArmProp[0].HasKeyword(ArmorLight))
        total += 40
    elseif (DynArmProp[0].HasKeyword(ArmorHeavy))
        total += 50
    endif
    
    ; Assigns additional HP according to material type
    if (DynArmProp[0].HasKeyword(ArmorMaterialHide))
        total += 5
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialLeather) || DynArmProp[0].HasKeyword(ArmorMaterialStudded) || DynArmProp[0].HasKeyword(ArmorMaterialImperialLight) || DynArmProp[0].HasKeyword(ArmorMaterialImperialStudded) || DynArmProp[0].HasKeyword(ArmorMaterialStormcloak))
        total += 10
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialSteel) || DynArmProp[0].HasKeyword(ArmorMaterialSteelPlate) || DynArmProp[0].HasKeyword(ArmorMaterialScaled) || DynArmProp[0].HasKeyword(ArmorMaterialImperialHeavy))
        total += 15
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialElven) || DynArmProp[0].HasKeyword(ArmorMaterialElvenGilded))
        total += 20
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialDwarven) || DynArmProp[0].HasKeyword(ArmorMaterialGlass))
        total += 25
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialOrcish) || DynArmProp[0].HasKeyword(ArmorMaterialEbony))
        total += 30
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialDragonScale) || DynArmProp[0].HasKeyword(ArmorMaterialDragonplate))
        total += 35
    elseif (DynArmProp[0].HasKeyword(ArmorMaterialDaedric))
        total += 40
    endif
    
    return total
endFunction
;--------------------------------------------------------------------------------------------------------------------------
; States are to prevent psychotic AI behavior that causes threading issues.
Auto State Inactive
;--------------------------------------------------------------------------------------------------------------------------
Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
    if (akBaseObject == DynamicArmorProperty[0])
        akActor = Game.GetPlayer()
        numStages = GetNumStages(DynamicArmorProperty)
        armorHealth = GetArmorHealth(DynamicArmorProperty)
        damagePerStage = armorHealth / numStages
        if (currentStage == 0)
            currentStage = 1
        endif

        GoToState("")
        akActor.EquipItem(DynamicArmorProperty[currentStage], false, true)
        GoToState("Inactive")
        
        ; Check if the armor is wearable
        if (currentStage > numStages)
            Debug.Notification("This armor is too damaged to wear.")
            akActor.UnequipItem(DynamicArmorProperty[0], true, true)
        endif
    endif
endEvent
;--------------------------------------------------------------------------------------------------------------------------
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    if (akActor.IsEquipped(DynamicArmorProperty[0]))
        if ((abHitBlocked != true) && (akProjectile == None))
            if (abPowerAttack == true)
                currentDamage += 2
            else
                currentDamage += 1
            endif
        endif
        if (currentDamage >= damagePerStage)
            newStage = currentStage + 1
            if (newStage <= numStages)
                Debug.Notification("Armor has been damaged.")
                akActor.EquipItem(DynamicArmorProperty[newStage], false, true)
            elseif (newStage > numStages)
                Debug.Notification("Armor has been destroyed.")
                akActor.UnequipItem(DynamicArmorProperty[0], true, true)
            endif
            akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)
            currentStage = newStage
            currentDamage = 0
        endif
    endif
endEvent
;--------------------------------------------------------------------------------------------------------------------------
Event OnObjectUnequipped(Form akBaseObject, ObjectReference akReference)
    if (akBaseObject == DynamicArmorProperty[0])
        akActor.RemoveItem(DynamicArmorProperty[currentStage], 1, true)
    endif
endEvent
;--------------------------------------------------------------------------------------------------------------------------
Event OnSit(ObjectReference akFurniture)
    if ((akActor.IsEquipped(DynamicArmorProperty[0]) == 0) && (akFurniture.HasKeyword(isBlacksmithForge) || akFurniture.HasKeyword(isBlacksmithWorkbench) || akFurniture.HasKeyword(isBlacksmithAnvil)) && (currentStage != 1))
        Debug.Notification("Repairing armor...")
        currentStage = 1
        currentDamage = 0
    endif
endEvent
;--------------------------------------------------------------------------------------------------------------------------
endState
;--------------------------------------------------------------------------------------------------------------------------

 

 

 

What the mod can do for now:

- Armor will now have HP based on its type: 30HP for clothes, 40 for light armor, and 50 for heavy.

- Materials will add additional HP: 5 for fur, 10 for leather (includes studded, imperial, and stormcloak), 15 for steel (includes plate, scaled, and imperial heavy), 20 for elven, 25 for dwarven/glass, 30 for orcish/ebony, 35 for dragon, and 40 for daedric. I know this doesn't reflect the armor rating, but it's supposed to represent how much abuse the materials the armor is made from can take rather than how much it can deflect from the wearer.

- A regular attack will deal 1 point of damage to the armor, while a power attack will deal 2; blocked attacks, projectiles, and magic will not damage the armor.

- The number of stages will affect how many hits it takes to change stages, for example a suit of heavy daedric armor (90 HP) with 10 stages will take 9 points of damage before it changes stage, while the same suit with 5 stages can take 18 points of damage between stages.

- Damage stage and hit points will persist after you unequip, drop, or shelve your armor (kinda necessary for the next part); completely broken armors will automatically unequip themselves.

- Armor will be repaired when you interact with a blacksmith's forge, an armorer's workbench, or a standalone anvil (anything with the keywords isBlacksmithForge, isBlacksmithWorkbench, and isBlacksmithAnvil); you can only repair an armor when it's not equipped and when it is visibly damaged (Stage 2 and above) so as to avoid spamming people with "Repairing armor..." every time you visit a forge/workbench/anvil.

 

What the mod can't do:

- Be used by NPCs; attaching the script to a quest pointing to the player was the only way to get OnHit to work, but I don't know how to have this quest point at NPCs at the same time.

- Track multiple copies of the same armor differently; I don't know how to save the values for current stage and damage directly to the armor itself, so if you have ten Amiella outfits in your inventory, damaging one will damage the rest.

- Let you repair your armor a little by interacting with a blacksmith's hammer in your inventory; I just thought of this just now, not sure if it's really necessary though. Should be a simple addition though.

- Scale the amount of damage the armor receives to the material and strength of the attack; I could scale it to material, but that would make natural attacks from dragons and trolls comparatively weak, and I have no idea how to scale to damage taken because OnHit doesn't pass that as a parameter.

 

Edit: deleted attachment in this post, file now available in downloads section.

Link to comment

Well, great, just came across a bug: for whatever reason if you get poisoned shortly before a stage change, it will prevent the script from equipping the new stage. You have to unequip the armor and re-equip it for it to show up properly, otherwise you'll be naked for that stage (script chugs on just fine otherwise). I have no idea what's causing this, if any other status/spell/whatever effect triggers the same bug, or where to even begin fixing it.

 

So far I know it's not the slot (44) the armor token occupies and there doesn't appear to be anything wrong with the script itself (peppered it with debug statements, I can see everything before and after the equip function fires normally), but that's about the extent of my knowledge.

Link to comment

Only Imperial Light is working yet?

 

Well, technically both armors (and their respective code) work, but being alphas there's still a lot of changes ahead so you really wouldn't want to use either on a permanent basis at the moment.

 

As for actual BU armors: brainsperm is trying to figure out how to implement body-swapping with JosefGrey's DAF system; he has a few standalone broken armors that he uses for screenshots but some of them have unique body shapes (like a breast squeezing out of a cracked suit of plate armor) and the way it's set up now isn't letting him do that (if he tries to make the skin visible on the broken armor models they inherit Argonian textures instead of the base texture).

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use