Sostrmnn Posted April 26, 2015 Share Posted April 26, 2015 Hi I haven't got much experience with CK but I'm trying to build myself a utility mod that can cycle through the idle animations from pinup poser (PP). So far I've figured out how PP stores its animations and how its interface works. I've written some code that works with normal idles but gives me an error when I try to play one of the PP idles. I'm guessing the error is because I'm referencing an idle from another esp. The error I get is: Error: Cannot play a None idle on an actorMy code is: Scriptname AutoPoserKBScript extends Quest Idle[] Property ListOfObjectsFLST Auto Idle Property MyFNISspellc1 Auto ;When I set this to "IdleSalute" it works. When it's set to "MyFNISspellc1" it fails. Idle Property MyFNISspellc10 Auto ;When I set this to "IdleLockPick" it works. When it's set to "MyFNISspellc10" it fails. Actor Property PlayerREF Auto ; Least 'expensive' way to refer to the player Event OnInit() ; This event will run once, when the script is initialized RegisterForKey(48) ;N RegisterForKey(49) ;B ;register idles ListOfObjectsFLST = new Idle[2] ListOfObjectsFLST[0] = MyFNISspellc1 ListOfObjectsFLST[1] = MyFNISspellc10 EndEvent Event OnKeyUp(int keyCode, float holdTime) if keyCode == 49 Debug.Notification("KeyPressed N") if PlayerREF.PlayIdle(MyFNISspellc1) ;Error: Cannot play a None idle on an actor Debug.Notification("Playing idle c1") else Debug.Notification("failed") endif endif if keyCode == 48 Debug.Notification("KeyPressed B") if PlayerREF.PlayIdle(MyFNISspellc10) ;Error: Cannot play a None idle on an actor Debug.Notification("Playing idle c10") else Debug.Notification("failed :(") endif endif EndEventI will appreciate any help and insight on this. Link to comment Share on other sites More sharing options...
sevencardz Posted April 26, 2015 Share Posted April 26, 2015 (edited) PP either needs to be listed as a master on your ESP so it can access PP's resources and auto-fill them in the script (be sure to select auto fill in the CK and that a form ID is assigned) - OR - You can pull the Idle resources in to your script using http://www.creationkit.com/GetFormFromFile_-_Game to avoid listing PP as a master (although it would still need PP installed to work correctly).EDIT: Just in case you're not aware - for PP to be listed as a master, load it with Skyrim.esm and Update.esm when you load up your mod in the CK and save it. You can then go back with TES5Edit to see it listed in the header and/or remove the dependency if you decide to go with the GetFormFromFile route. Edited April 26, 2015 by sevencardz Link to comment Share on other sites More sharing options...
Sostrmnn Posted April 26, 2015 Author Share Posted April 26, 2015 (edited) PP either needs to be listed as a master on your ESP so it can access PP's resources and auto-fill them in the script (be sure to select auto fill in the CK and that a form ID is assigned) - OR - You can pull the Idle resources in to your script using http://www.creationkit.com/GetFormFromFile_-_Game to avoid listing PP as a master (although it would still need PP installed to work correctly). EDIT: Just in case you're not aware - for PP to be listed as a master, load it with Skyrim.esm and Update.esm when you load up your mod in the CK and save it. You can then go back with TES5Edit to see it listed in the header and/or remove the dependency if you decide to go with the GetFormFromFile route. I would like to use the first method you suggested. In the CK, when I open my mod I select "Skyrim.esm", "Update.esm" and "Pinup Poser.esp" together with my "testplugin1.esp". testplugin1.esp is set as the active file. I go to my quest properties and set the idle to one of the PP idles. I've double checked that the names are the same as what the real PP uses for its idles. I'm also using auto-fill as you suggested. A form ID is assigned. If I save and load the game, I get the error in the Papyrus log. If I close CK and then open CK again, loading again as before, the form ID's on my quest are mysteriously set to "NONE". Top part is before saving and closing. Bottom part is after reloading CK and opening same dialog:http://i.imgur.com/kTjFEbu.png You mention, "for PP to be listed as a master, load it with Skyrim.esm and Update.esm when you load up your mod in the CK and save it". I do select it when I load my mod in the CK but it's just listed as an ESP. Do I need to do something in TES5Edit to get it to be listed as ESM? Edit: adding screenshot of the loading dialogs:http://i.imgur.com/wh5Sv6V.png I want to avoid doing the GetFormFromFile route because looking up all the form ID's for PP's idles will take me hours. Edited April 26, 2015 by Sostrmnn Link to comment Share on other sites More sharing options...
Sostrmnn Posted April 27, 2015 Author Share Posted April 27, 2015 I seem to have found a way to get this to work. Not 100% sure if it's overkill or not. I was searching google and found this thread http://forums.nexusmods.com/index.php?/topic/595124-reference-object-created-in-another-esp/ which referenced the following page http://cs.elderscrolls.com/index.php/De-Isolation_Tutorial Following the "de-isolation tutorial" I used Wrye Bash to "Esmify" the Pinup Poser.esp and then loaded Construction Kit and selected it together with Skyrim.esm and Update.esm. I set my testplugin1.esp as the active file and loaded. Then I went and auto-filled the properties on my quest. Saved. Went back to Wrye Bash and right click Pinup Poser.esp and "Espify" again. (This is apparently very important to do before launching the game). I then launched Skyrim (with CK still open and happily thinking that PP is an ESM) and I was able to play the idles from PP. Awesome! :blush: Couple things I learned:if you "Esmify" the esp file it does not change the extension, just tricks the CK into thinking that it's an ESM so that your ESP can become dependent on it.you can ESMify the mod before you load CK and then ESPify it back before you run the game, now the CK will work correctly and the game will also run. The downside with this is that you have to remember to ESMify the mod again next time you open CK Link to comment Share on other sites More sharing options...
fore Posted April 27, 2015 Share Posted April 27, 2015 It's so much easier. :smile: You have to make sure that PP is installed, and FNIS is run. Then simply go through all animations PP has defined inthe animation lists. For example, open animation/Pinups/FNIS_Pinups_List.txt. THe first definition reads b PUPStand1 Pinups_Stand1.hkxThis animation can be activated by Debug.SendAnimationEvent(<actor>, "PUPStand1")Usually, if the FNIS definition does NOT have the -a parameter, these animations are cyclic. You can terminate then by activating another animation, or with Debug.SendAnimationEvent(<actor>, "IdleForceDefaultState") Link to comment Share on other sites More sharing options...
Sostrmnn Posted April 27, 2015 Author Share Posted April 27, 2015 Wow, that's awesome. Waaaaaaaaaaaay easier! Thanks fore! :blush: I ran into an issue with my approach anyway because CK forbids the huge amount of properties I tried to have on my script. I also found out that Papyrus won't compile if you have an array with size larger than 128. Wtf!! No wonder TES games are so buggy, their SDK is pretty crap. I'll work around the array limit by having separate arrays for each of the FNIS groups that are defined in PP. Results of my handiwork thus far:http://i.imgur.com/boXMsoc.gif Code for anyone who's interested: Scriptname AutoPoserKBScript extends Quest int Property activeAnimation auto int Property animationCount auto Actor Property PlayerREF Auto ; Least 'expensive' way to refer to the player String[] animList Event OnInit() ; This event will run once, when the script is initialized RegisterForKey(48) ;B RegisterForKey(49) ;N activeAnimation = 1 ;register idles animationCount = 128 ;Remember to update size of animList array animList = new String[128] ;Remember to update animationCount animList[0] = "PUP2Stand1" animList[1] = "PUP2Stand2" animList[2] = "PUP2Stand3" animList[3] = "PUP2Stand4" animList[4] = "PUP2Stand5" animList[5] = "PUP2Stand6" animList[6] = "PUP2Stand7" animList[7] = "PUP2Stand8" animList[8] = "PUP2Stand9" animList[9] = "PUP2Stand10" animList[10] = "PUP2Stand11" animList[11] = "PUP2Stand12" animList[12] = "PUP2Stand13" animList[13] = "PUP2Stand14" animList[14] = "PUP2Stand15" animList[15] = "PUP2Stand16" animList[16] = "PUP2Stand17" animList[17] = "PUP2Stand18" animList[18] = "PUP2Stand19" animList[19] = "PUP2Stand20" animList[20] = "PUP2Stand21" animList[21] = "PUP2Stand22" animList[22] = "PUP2Stand23" animList[23] = "PUP2Stand24" animList[24] = "PUP2Stand25" animList[25] = "PUP2Stand26" animList[26] = "PUP2Stand27" animList[27] = "PUP2Stand28" animList[28] = "PUP2Stand29" animList[29] = "PUP2Stand30" animList[30] = "PUP2Stand31" animList[31] = "PUP2Stand32" animList[32] = "PUP2Stand33" animList[33] = "PUP2Stand34" animList[34] = "PUP2Stand35" animList[35] = "PUP2Stand36" animList[36] = "PUP2Stand37" animList[37] = "PUP2Stand38" animList[38] = "PUP2Stand39" animList[39] = "PUP2Stand40" animList[40] = "PUP2Stand41" animList[41] = "PUP2Stand42" animList[42] = "PUP2Stand43" animList[43] = "PUP2Stand44" animList[44] = "PUP2Stand45" animList[45] = "PUP2Stand46" animList[46] = "PUP2Stand47" animList[47] = "PUP2Stand48" animList[48] = "PUP2Stand49" animList[49] = "PUP2Stand50" animList[50] = "PUP2Stand51" animList[51] = "PUP2Stand52" animList[52] = "PUP2Stand53" animList[53] = "PUP2Stand54" animList[54] = "PUP2Stand55" animList[55] = "PUP2Stand56" animList[56] = "PUP2Stand57" animList[57] = "PUP2Stand58" animList[58] = "PUP2Stand59" animList[59] = "PUP2Stand60" animList[60] = "PUP2Stand61" animList[61] = "PUP2Stand62" animList[62] = "PUP2Stand63" animList[63] = "PUP2Stand64" animList[64] = "PUP2Stand65" animList[65] = "PUP2Stand66" animList[66] = "PUP2Stand67" animList[67] = "PUP2Stand68" animList[68] = "PUP2Stand69" animList[69] = "PUP2Stand70" animList[70] = "PUP2Stand71" animList[71] = "PUP2Stand72" animList[72] = "PUP2Stand73" animList[73] = "PUP2Stand74" animList[74] = "PUP2Stand75" animList[75] = "PUP2Stand76" animList[76] = "PUP2Stand77" animList[77] = "PUP2Stand78" animList[78] = "PUP2Stand79" animList[79] = "PUP2Stand80" animList[80] = "PUP2Stand81" animList[81] = "PUPStand1" animList[82] = "PUPStand2" animList[83] = "PUPStand3" animList[84] = "PUPStand4" animList[85] = "PUPStand5" animList[86] = "PUPStand6" animList[87] = "PUPStand7" animList[88] = "PUPStand8" animList[89] = "PUPStand9" animList[90] = "PUPStand10" animList[91] = "PUPStand11" animList[92] = "PUPStand12" animList[93] = "PUPStand13" animList[94] = "PUPStand14" animList[95] = "PUPStand15" animList[96] = "PUPStand16" animList[97] = "PUPStand17" animList[98] = "PUPStand18" animList[99] = "PUPStand19" animList[100] = "PUPStand20" animList[101] = "PUPStand21" animList[102] = "PUPStand22" animList[103] = "PUPStand23" animList[104] = "PUPStand24" animList[105] = "PUPStand25" animList[106] = "PUPStand26" animList[107] = "PUPStand27" animList[108] = "PUPStand28" animList[109] = "PUPStand29" animList[110] = "PUPStand30" animList[111] = "PUPStand31" animList[112] = "PUPStand32" animList[113] = "PUPStand33" animList[114] = "PUPStand34" animList[115] = "PUPStand35" animList[116] = "PUPStand36" animList[117] = "PUPStand37" animList[118] = "PUPStand38" animList[119] = "PUPStand39" animList[120] = "PUPStand40" animList[121] = "PUPStand41" animList[122] = "PUPStand42" animList[123] = "PUPStand43" animList[124] = "PUPStand44" animList[125] = "PUPStand45" animList[126] = "PUPStand46" animList[127] = "PUPStand47" EndEvent Event OnKeyUp(int keyCode, float holdTime) if keyCode == 49 ;N activeAnimation = (activeAnimation + 1) % animationCount endif if keyCode == 48 ;B activeAnimation = activeAnimation - 1 if activeAnimation < 0 ; modulus on negative numbers doesn't work as expected in papyrus activeAnimation = animationCount - 1 endif endif Debug.Trace("activeAnimation = " + activeAnimation) Debug.Notification("Playing idle: " + activeAnimation) Debug.SendAnimationEvent(PlayerREF, animList[activeAnimation]) EndEventThank you to sevencardz and fore for the help! :thumbsup: Link to comment Share on other sites More sharing options...
fore Posted April 27, 2015 Share Posted April 27, 2015 You can make this much smaller, without the need for so many big arrays. Remember they will be included in the saves and cause save bloats. This works, because PPs animations are nicely grouped. Define groups without numbers, and keep the the upper bound in a string variable. From what I have seen works for all animations except the paired ones. animGroup[0] = "PinupsStand" animGroup[1] = "PinupsSit" animGroup[2] = "PinupsLay" ............................... animGroupLen = "162027027........................"Then you make a nested loop and read the upper bound for each group with int upperBound = StringUtil.substring(animGroupLen, outerIndex * 3, 3) as int Link to comment Share on other sites More sharing options...
Sostrmnn Posted April 27, 2015 Author Share Posted April 27, 2015 You can make this much smaller, without the need for so many big arrays. Remember they will be included in the saves and cause save bloats. This works, because PPs animations are nicely grouped. Define groups without numbers, and keep the the upper bound in a string variable. From what I have seen works for all animations except the paired ones. animGroup[0] = "PinupsStand" animGroup[1] = "PinupsSit" animGroup[2] = "PinupsLay" ............................... animGroupLen = "162027027........................"Then you make a nested loop and read the upper bound for each group with int upperBound = StringUtil.substring(animGroupLen, outerIndex * 3, 3) as int That's a very good point! I will rewrite it as you suggest. ;D I've been having fun with this helper functionality, much more convenient than going through the menus (for me). Quite chuffed :) Link to comment Share on other sites More sharing options...
Sostrmnn Posted April 27, 2015 Author Share Posted April 27, 2015 In case anyone wants the final code, here it is. It doesn't work for paired animations but that's not something I'm interested in at the moment - might look at it later if I feel like figuring out how to write spells. Scriptname AutoPoserKBScript extends Quest Actor Property PlayerREF Auto ; Least 'expensive' way to refer to the player String[] animGroup String animGroupCounts int animGroupCount int activeAnimation ;activeAnimation is 1-based because of the way the animations are named int activeGroup int activeGroupCount Event OnInit() ; This event will run once, when the script is initialized Debug.Trace("AutoPoserKBScript initialising ===================") RegisterForKey(47) ;V RegisterForKey(48) ;B RegisterForKey(49) ;N activeAnimation = 1 ;Group names animGroupCount = 20 ; <--+-- Update these values together animGroup = new String[20] ; <--/ animGroup[0] = "APose1HSword" animGroup[1] = "APoseBow" animGroup[2] = "APoseCBow" animGroup[3] = "APoseDual" animGroup[4] = "APoseFist" animGroup[5] = "APoseZwei" animGroup[6] = "PPair" animGroup[7] = "PUPStand" animGroup[8] = "PUP2Stand" animGroup[9] = "PUP3Kneel" animGroup[10] = "PUP3Lay" animGroup[11] = "PUP3Sit" animGroup[12] = "PUP4Stand" animGroup[13] = "PUP5Kneel" animGroup[14] = "PUP5Lay" animGroup[15] = "PUP5Sit" animGroup[16] = "PUPMKneel" animGroup[17] = "PUPMLay" animGroup[18] = "PUPMSit" animGroup[19] = "PUPMStand" ;Group counts, for reference: ;APose1HSword: 18 ;APoseBow: 5 ;APoseCBow: 4 ;APoseDual: 18 ;APoseFist: 18 ;APoseZwei: 18 ;PPair: 40 ;PUPStand: 81 ;PUP2Stand: 81 ;PUP3Kneel: 27 ;PUP3Lay: 27 ;PUP3Sit: 27 ;PUP4Stand: 81 ;PUP5Kneel: 27 ;PUP5Lay: 27 ;PUP5Sit: 27 ;PUPMKneel: 9 ;PUPMLay: 9 ;PUPMSit: 9 ;PUPMStand: 54 animGroupCounts = "1805041818184081812727278127272709090954" activeGroup = 7 activeGroupCount = StringUtil.substring(animGroupCounts, activeGroup * 2, 2) as int EndEvent Event OnKeyUp(int keyCode, float holdTime) if keyCode == 47 ;V activeGroup = (activeGroup + 1) % animGroupCount activeGroupCount = StringUtil.substring(animGroupCounts, activeGroup * 2, 2) as int activeAnimation = 1 Debug.Notification("Active group: " + animGroup[activeGroup] + " activeGroupCount = " + activeGroupCount) endif if keyCode == 48 ;B activeAnimation = activeAnimation - 1 if activeAnimation <= 0 activeAnimation = activeGroupCount endif endif if keyCode == 49 ;N activeAnimation = activeAnimation + 1 if activeAnimation > activeGroupCount activeAnimation = 1 endif endif Debug.Trace("activeGroup = " + activeGroup + " activeAnimation = " + activeAnimation + " Playing idle: " + animGroup[activeGroup] + activeAnimation) Debug.Notification("Playing idle: " + animGroup[activeGroup] + activeAnimation) Debug.SendAnimationEvent(PlayerREF, animGroup[activeGroup] + activeAnimation) EndEvent Link to comment Share on other sites More sharing options...
Recommended Posts