Jump to content

Help needed from an array "proof-reader" - thanks!


Hoamaii

Recommended Posts

Hi guys,

 

Not much used to scripting arrays, I'd be very grateful if someone who knows better than me could proof read the following script - many thanks in advance :).

 

It does compile (I had to move things around a bit before it did) but since I'm using two mixed arrays, I'm not too sure I got this right.

 

What I'm trying to do here is to make an actor unequip and reequip gear (armors) but only for some given slots. I'm targetting 21 slots here, thus 21 possible armor forms. The way I understand it this makes 2 arrays: 1 for slotmasks, 1 for the armors currently worn by the actor. Not sure how to declare this chosen slotmasks, I set them up one by one in the onInit() block - but there's probably a much cleaner way to do that?

Scriptname StripUnstripArrayScript extends activemagiceffect  

;Properties
Actor ActorRef
Armor[] WornOutfit
Int[] iSlot
; Form WornItem

Event OnInit()
	WornOutfit = new Armor[21]
	iSlot = new Int[21]
	iSlot[0] = 0x00000004 ; body slot 32
	iSlot[1] = 0x00000002 ; head slot 31
	iSlot[2] = 0x00000008 ; hands slot 33
	iSlot[3] = 0x00000010 ; slot 34 - forearms
	iSlot[4] = 0x00000080 ; feet slot 37
	iSlot[5] = 0x00000100 ; slot 38 - calves
	iSlot[6] = 0x00004000 ; slot 44 - face-mouth
	iSlot[7] = 0x00008000 ; slot 45 - neck, scarfs
	iSlot[8] = 0x00010000 ; slot 46 - cloaks
	iSlot[9] = 0x00020000 ; slot 47 - backpacks, wings
	iSlot[10] = 0x00040000 ; slot 48 - misc
	iSlot[11] = 0x00080000 ; slot 49 - pelvis primary
	iSlot[12] = 0x00400000 ; slot 52 - pelvis secondary
	iSlot[13] = 0x00800000 ; slot 53 - legs primary
	iSlot[14] = 0x01000000 ; slot 54 - legs secondary
	iSlot[15] = 0x02000000 ; slot 55 - face alternate, jewelry, lanterns
	iSlot[16] = 0x04000000 ; slot 56  - chest secondary
	iSlot[17] = 0x08000000 ; slot 57 - shoulder
	iSlot[18] = 0x10000000 ; slot 58 - arms secondary, undergarment
	iSlot[19] = 0x20000000 ; slot 59 - arms primary, bracelets
	iSlot[20] = 0x40000000 ; slot 60 - misc or FX, bandanas
EndEvent

Function UnequipWornOutfit()
	Int iItem = WornOutfit.Length
	Int i = iSlot.Length
		While iItem >= 0
			iItem -= 1
			Armor WornItem = ActorRef.GetWornForm(iSlot[i]) as Armor
				If WornItem != None
					ActorRef.UnEquipItem(WornItem)
				EndIf
			If iItem > 0
				WornOutfit[iItem] = WornItem
			EndIf		
		EndWhile
EndFunction

Function EquipWornOutfit()
	Int iItem = WornOutfit.Length
		While iItem >= 0
			iItem -= 1
			If WornOutfit[iItem]
				ActorRef.EquipItem(WornOutfit[iItem], false, true)
			EndIf
		EndWhile
EndFunction

Two questions for you:

 

1. Does this look right?

I was not sure about the way to call my slotmasks array in "Armor WornItem = ActorRef.GetWornForm(iSlot)" line - Papyrus made me rewrite this a lot of times. Not sure either how to redefine the new WornOutfit 2 lines further down, to match the list of WornItems found on the actor...

 

2. Is there a simpler or cleaner way to do this?

 

A million thanks in advance!.. :D

 

 

 

 

PS. Yeah, I know there's a much faster way to strip NPCs with UnequipAll() and then adding and removing any type of armor piece to their inventory to make them reequip their gear - but AddItem causes real bad latency as far as I can tell + I need to get used to arrays anyway!.. ;)

 

Link to comment
Share on other sites

I used a modified version of the function on the ck wiki page:

http://www.creationkit.com/Slot_Masks_-_Armor

Scriptname StripMEScript Extends ActiveMagicEffect

Form[] WornForm

Event OnEffectStart(Actor akTarget, Actor akCaster)
    Int iChecked = (0x00100000 + 0x00200000 + 0x80000000)
    Int iSlot = 0x01
    While (iSlot < 0x80000000)
        If (Math.LogicalAnd(iChecked, iSlot) != iSlot)
            Armor CurArmor = akTarget.GetWornForm(iSlot) As Armor
            If CurArmor
                WornForm = Utility.ResizeFormArray(WornForm, WornForm.Length + 1, CurArmor)
                akTarget.UnEquipItem(CurArmor, False, True)
                iChecked += CurArmor.GetSlotMask()
            Else
                iChecked += iSlot
            EndIf
        EndIf
        iSlot *= 2
    EndWhile
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
    If WornForm
        Int i = WornForm.Length
        While i
            i -= 1
            If WornForm[i]
                If (akTarget.GetItemCount(WornForm[i]) > 0) && (!akTarget.IsEquipped(WornForm[i]))
                    akTarget.EquipItem(WornForm[i], False, True)
                EndIf
            EndIf
        EndWhile
    EndIf
EndEvent

No need to fill properties or declare array sizes.

Just attach the script to magic effect.

Add the magic effect to a spell, apply the spell to an actor.

 

EG: Trigger Volume that applies the spell when an actor walks in, removes the spell when the actor leaves the trigger.

Edited by sLoPpYdOtBiGhOlE
Link to comment
Share on other sites

Thanks a lot for replying, SloppyDot.

 

Yeah I saw that too but I believe he checks every possible slot in that script (that's 32 or 34 of them I think) whereas I don't want to do that, for some I may only unequip 4 or 5 slots. Plus I'm not sure I understand what the Math function does (compare variables I'd guess, but not sure).

 

In the modified version you made here, you're only checking the 3 'iChecked' slots, right? So that'd mean if I want to check 21 slots, I'd have to list all of them between parenthesis up there? (Sorry to ask, but I like to fully understand what I'm doing... ;)).

 

I was unsure about adding array sizes but for some reason Papyrus wouldn't compile if I didn't. Also it kept complaining it could not compare CurArmor and WornForm, that's why I defined them.

Link to comment
Share on other sites

That script I posted above compiles fine for me and actually works as well (quickly at that) :smile:

 

The SKSE array functions are great for creating dynamic arrays the actual size you need.

Unlike papyrus native array has to be a literal int and not a variable to initialize the array.

 

The Slots you want to skip just add them to eg:

Int iChecked = (0x00100000 + 0x00200000 + 0x80000000 + skipslot + skipslot)

 

skipslot = the slot you want to not check

 

iChecked is slot masks that are already checked.

So your looping through each Slot Mask, If a Slot Mask Is Already checked the the loop skips to the next slot mask.

 

This is what checks if the current slot mask has already been checked:

If (Math.LogicalAnd(iChecked, iSlot) != iSlot)

 

Basically Math.LogicalAnd is a bitwise AND operation.

(Well that's what I call it due to another scripting language I use, also from playing in windows API)

 

I'm honestly pretty hopeless with maths myself as I dropped out of school at a young age.

Edited by sLoPpYdOtBiGhOlE
Link to comment
Share on other sites

Thanks again man! Yeah, I'm kind of hopeless at Maths too, I have to think twice as hard when i deal with it - Papyrus compiles but I don't, obviously ;). Plus I'm only getting started with arrays.

 

Just so I get it right, you mean 'iChecked' ONLY lists inside parenthesis the slots you want to skip - none of those you want to check?

Link to comment
Share on other sites

Yep, that it, iChecked is what has been checked.

So in the beginning where Int iChecked = (XXXXXXXXX + XXXXXXXXX + XXXXXXXXX + etc)

Would mean the loop will not check those slots and just skip past them.

 

Each iteration of the loop the current SlotMask gets added to iChecked.

If an armor uses more then one SlotMask then all slot masks the armor uses gets added to the iChecked variable.

 

So the next iteration of the loop checks if the current Slotmask is already been accounted for as maybe the prior loop iteration of armor may have already used the next slot mask that is checked.

If that's the case then the loop continues skipping the check on that SlotMask.

Link to comment
Share on other sites

Thanks again, SloppyDot, and kudos for you help. :smile:. That's exactly what I was looking for.

 

For some reason, Papyrus can't compile this though - it tells me 'ResizeFormArray' is not a function - I checked the Wiki and SKSE Utility.psc and I can't find it. Is that a custom function or you're using another framework maybe?

 

Edit: My fault, I hadn't realized I was still using SKSE 1.07.2 instead of 1.07.3!.. :rolleyes:

 

Works just perfect for what I need - I just hope I'm gonna be able to get as "Array-fluent" as you are someday! :D

Link to comment
Share on other sites

Your welcome, Glad you got it sorted.

 

Arrays to me are a street of letterboxes.

Each letterbox could be any number in the street.

Each letterbox may contain what I'm looking for or may not.

 

When I think of arrays and looping through them I see them a different way...

 

I picture a Ferris Wheel.

The Ferris Wheel is the loop and the Carriages of the Ferris Wheel are the Array Indexes, the place where I put my passengers :)

 

Me I'm the bloke that pulls the lever that makes the wheel go round and every carriage will pass my view as the wheel goes round.

I can decide what to do depending if the Carriage has someone or something in it or not as it passes my view :)

 

This type of analogy probably doesn't doesn't help you, but is best if you can mentally visualize something that relates to your own view.

May sound silly, but it's the way I originally got a grasp of arrays and loops.

 

i won't go into what i see Multi-Dimensional arrays as...lol

Basically when I play with Multi-Dimensional arrays I can get a little lost at times, but usually wrap my mind around it pretty quickly.

Link to comment
Share on other sites

Not silly at all, quite the opposite actually! Your analogy is a very good one and helped me "figure" (visualize?) how much faster and cleaner it can be than listing a whole bunch of properties and going through "If" and "EndIf" for each one of them. I knew that, in theory, but your metaphore helped me better grasp the idea - there's a huge difference between knowing something and understanding it.

 

I use metaphores a lot in my work and I believe one only truly understands something when he's able to make it clear to others in the simplest possible way. People who can do that have a real gift to make others feel smarter. No matter the complexity of the concept to describe, there are 3 possible attitudes when facing someone who knows less than you - one can shrug it off with a "not for you, forget it", or try to explain it in some obscure, specialist jargon, or do what you just did: make it simple and clear. People able to do that are not just smart and knowledgeable, they also have empathy - it's a true gift in my book, really :).

 

I wish there was more of that on the Wiki (though it's probably not the place for it - and there's a bit of that in the Discussion tabs anyway) - and I must say that coming from no coding background plus speaking another language (French) possibly doesn't help. Took me a fair while to fully grasp simple ideas like "Attach" or "Detach" for instance - or functions like "onInit() which can fire at different times depending on what it's attached to (MagicEffect, or quests, or Aliases, persistent refs, placed refs, etc.). Maths are even worse for me in English if the operation name is too different from French or has no Latin root to help me get it, that makes it harder for me to remember them, even when I've used them a few times already.

 

Now at the risk of sounding demanding, I'm truly interested in your analogy for multi-dimensionak arrays, 'cause unfortunately these are probably the ones I'll be needing for what I'm working on... ;)

Link to comment
Share on other sites

  • Recently Browsing   0 members

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