Hoamaii Posted March 16, 2016 Share Posted March 16, 2016 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 More sharing options...
sLoPpYdOtBiGhOlE Posted March 17, 2016 Share Posted March 17, 2016 (edited) 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 EndEventNo 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 March 17, 2016 by sLoPpYdOtBiGhOlE Link to comment Share on other sites More sharing options...
Hoamaii Posted March 17, 2016 Author Share Posted March 17, 2016 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 More sharing options...
sLoPpYdOtBiGhOlE Posted March 17, 2016 Share Posted March 17, 2016 (edited) 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 March 17, 2016 by sLoPpYdOtBiGhOlE Link to comment Share on other sites More sharing options...
Hoamaii Posted March 17, 2016 Author Share Posted March 17, 2016 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 More sharing options...
sLoPpYdOtBiGhOlE Posted March 17, 2016 Share Posted March 17, 2016 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 More sharing options...
Hoamaii Posted March 17, 2016 Author Share Posted March 17, 2016 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 More sharing options...
sLoPpYdOtBiGhOlE Posted March 18, 2016 Share Posted March 18, 2016 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...lolBasically 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 More sharing options...
Hoamaii Posted March 18, 2016 Author Share Posted March 18, 2016 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 More sharing options...
Recommended Posts