Feliks Posted February 29, 2016 Posted February 29, 2016 So now that I'm back to waiting for this with bated breath, I would like to clarify something: this won't actually be adding animations for the overlooked zaz furniture correct? just a way to interact with it and use the animations if/when someone makes them?
fashgi Posted March 1, 2016 Posted March 1, 2016 good work and please give some selectable situations for rapist such as SEXTOOLS . but in ST we change sex positions after start sex but we must select sex posiions befor start sex scenes . thanks a lot
Nazzzgul666 Posted March 14, 2016 Posted March 14, 2016 Looks very promising If i understand this right, it doesn't matter where the furnitures came from? (Prison Overhaul, Maria Eden,...) Or will only mods which use this framework as requirement support actions?
anubis Posted March 15, 2016 Posted March 15, 2016 Interesting ! bet Zaz & Xaz would have a big smile after watching your video... LoL on Carlotta, 1:05 till end. come on, come on huh, huh, your nothing, huh ! i take that dialog/voices are from your framework since i never heard them before... Wonderful work. And if i understand correctly what your FIF trying to do, your FIF would be a great help for any modder that use furniture/s as part of their mod (DCL,ME,MME,PO, wolfclub and more) Since they can focus on their mod and let furniture interaction being handle by your FIF.
razzor69 Posted March 15, 2016 Posted March 15, 2016 Cant wait to make it happen, i guess we need more of these stuff in the future
Arcturus7777 Posted March 23, 2016 Posted March 23, 2016 I do not think you need to worry about the zaz animation pack, so many mods use it, it seems to be almost universally installed.
zzz72w3r Posted May 12, 2016 Posted May 12, 2016 Hopefully this will inspire Roggvir to keep working on the framework: http://www.loverslab.com/topic/61588-slal-komotors-animations/page-2?do=findComment&comment=1553051
Vykroft Posted May 12, 2016 Posted May 12, 2016 Ok you got my attention now, I hope we'll see an alpha soon.
Roggvir Posted June 15, 2016 Author Posted June 15, 2016 So now that I'm back to waiting for this with bated breath, I would like to clarify something: this won't actually be adding animations for the overlooked zaz furniture correct? just a way to interact with it and use the animations if/when someone makes them? Nope, it wont be adding any new animations, think of this as something like SexLab - a framework that uses existing animations (depending on ppls personal choices - it will be possible to create custom animation sets). Looks very promising If i understand this right, it doesn't matter where the furnitures came from? (Prison Overhaul, Maria Eden,...) Or will only mods which use this framework as requirement support actions? If you mean whether it depends on which mod added that furniture to the worl/interior, then no, it doesnt matter. As long as the furniture is "registered" in the framework, it will be able to recognize it and use it - ie. as we know, Prison Overhaul adds some pillories to Whiterun, and as long as the same kind of pillory is registered in the framework, it will know how to use it. If lets say Zaz adds brand new furniture (as in "a new object in CK, with new formId"), which obviously wont be known and registered by the framework, then such furniture wont be available UNTIL you register it via a custom plugin, or until the framework default furniture registration plugin gets updated. But once the framework "knows" certain furniture object, it doesnt matter which mod adds it to the world - it will be available. (umm, i am trying my best, did i confuse you even more, or is this explanation working? ) Interesting ! bet Zaz & Xaz would have a big smile after watching your video... LoL on Carlotta, 1:05 till end. come on, come on huh, huh, your nothing, huh ! i take that dialog/voices are from your framework since i never heard them before... Wonderful work. And if i understand correctly what your FIF trying to do, your FIF would be a great help for any modder that use furniture/s as part of their mod (DCL,ME,MME,PO, wolfclub and more) Since they can focus on their mod and let furniture interaction being handle by your FIF. ALL of those voices are actually in Vanilla game. I just created a new dialog where i duplicated quite an amount of carefully selected dialog lines/voices (basically, i went over ALL dialog lines in the whole game, including all DLCs, listened to each one, and made selection for every voice type there is, and put that in my special dialog), and the animator thread is forcing the NPC to use that special dialog durign these interactions. That way, every NPC is still speaking with their normal voice. It is still very simple - i need to split those selected lines into more categories, depending on which situation i want them to be used in (ie. you obviously want different set of sounds/voices for consensual soft/hard vs. non-consensual soft/hard, vs. torture/whipping vs. ...whatever else). Yes, the point of this FIF is to make it take care of furniture stuff, allowing modders to focus on their actual work - they will just throw this plugin in, and either let it do its default job, or they can craft custom furniture registrations and custom animations/interaction sets, and even use simple functions to micromanage things in case they need. Any progress? Alpha files? Yeah... about that... as everyone surely noticed, i was away for some time. Not only was i awol, but i wasnt even working on it. I got pissed of by Papyrus and just couldnt go on. It hapens to me quite frequently, i find the Papyrus horrendously lacking, and it is VERY frustrating for me, because i am a perfectionist and i HATE all the workarounds and crazy stuff i have to do in order to make this all work. And even after you do everything you can, there are still things that just wont budge. I just had to take a long break, and reevalute it all again, see if i can do some things differently, etc. It is also very difficult for me to not have second opinion regarding the code, i often wish i had someone who would be working on this together with me, if only so that person could steer me in right direction after i take one of gadzillion detours working on something that may not be really needed but for some reason it bugs the hell out of me. So, sorry, not much progress - i started reviewing all code today again (after my absence, i forgot many things and need to refresh my memory yet again). And no alpha - i do have a kind of working version, that was used in making that video, but i fear releasing it to public, even as Alpha, because i am afraid it would result in tons of question that i'd rather not deal with until i finalize and solve some remaining problems. BUT, if any modder PMs me and asks for this pre-pre-pre-pre-pre-Alpha version, i will gladly give it to them, so they may look at how it works (maybe they might provide some useful pointers or ideas - that would be great), or even take it to dissect it and build something of their own out of it (i am all about sharing - thats how we learn), but dont expect me to serve as a 24/7 support line (i will of course try to explain and help, but i'd rather work than answer questions).
Roggvir Posted June 15, 2016 Author Posted June 15, 2016 In case anyone would find this interesting...This is an example of how an "interaction" is defined: scriptname RoggMagicFx_PilloryAssFuck extends ActiveMagicEffect event OnEffectStart(actor akActorA, actor akActorB) ; Get furniture interaction thread by actorA RoggFF_Thread t = RoggLib.GetThreadByActor(akActorA as objectReference) if !t ERROR("MagicFX: Pillory Ass Fuck - failed to get furniture thread!") return endif ; Prepare reference to the furniture library whose after-act callbacks we register for animation end event RoggFL_DefaultFurniture furnLib = Quest.GetQuest("RoggFL_DefaultFurniture") as RoggFL_DefaultFurniture if !furnLib ERROR("MagicFX: Pillory Ass Fuck - failed to get furniture library.") return endif akActorA.SetFactionRank(t.RoggFF.RoggFactInThread, _Rank_ThreadAnimating) akActorB.SetFactionRank(t.RoggFF.RoggFactInThread, _Rank_ThreadAnimating) akActorB.SetFactionRank(t.RoggFF.RoggFactHighHeelsOff, 0) ; Set animations t.ClearAnimationStages() faction RoggFctTouchedDislikedFirst = Game.GetFormFromFile(0x00000D69, "RoggVoiceover.esp") as faction faction RoggFctTouchedDislikedSeq = Game.GetFormFromFile(0x00005915, "RoggVoiceover.esp") as faction faction RoggFctFuckingViolent = Game.GetFormFromFile(0x00000D62, "RoggVoiceover.esp") as faction faction RoggFctFuckedViolent = Game.GetFormFromFile(0x00000D64, "RoggVoiceover.esp") as faction int i = 0 int c = 0 ;==================== Rubbing the pussy (80% chance) if Utility.RandomInt(0, 100) < 50 ;-------------------- First stage is to make actorA play the surprised 'first contact' voiceover t.SetAnimation(i, akActorA, "ZazAPPillTorPussRub1B", timeout=2) t.SetAnimation(i, akActorB, "ZazAPPillTorPussRub1A") t.SetAnimVoice(i, akActorA, RoggFctTouchedDislikedFirst, 999) ; actorA startled response ('first contact' response) ; TODO: implement actorB intro voiceover (things like "what do we have here?" and "Aren't you a sight for sore eyes", etc.) i += 1 ;-------------------- Add at least one more stage after the first surprise, now with voiceover for begging, laments, cries for help c = Utility.RandomInt(1, 4) while (c > 0) c -= 1 t.SetAnimation(i, akActorA, "ZazAPPillTorPussRub1B", timeout=4) t.SetAnimation(i, akActorB, "ZazAPPillTorPussRub1A") t.SetAnimVoice(i, akActorA, RoggFctTouchedDislikedSeq, 3) ; actorA threatens, lamments, begs or cries for help ; TODO: implement actorB taunts/dominant-talk voiceover i += 1 endWhile endif ;==================== Entering int r = Utility.RandomInt(0, 100) if r < 40 Debug.Notification("Slow entry") ;-------------------- Slow entry t.SetAnimation(i, akActorA, "ZazAPPillSXHip01B", timeout=4) ; actorB entering actorA while holding hips (must play only once, duration=3.333) t.SetAnimation(i, akActorB, "ZazAPPillSXHip01A") t.SetAnimVoice(i, akActorA, RoggFctTouchedDislikedSeq, 0.3) ; actorA threatens, lamments, begs or cries for help t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.3) ; actorB grunts, heavy breaths, insults, threats, taunts, laughs, etc. ; TODO: implement slightly gentler voiceover for actorB here i += 1 elseif r < 70 Debug.Notification("Hard entry") ;-------------------- Hard entry t.SetAnimation(i, akActorA, "ZazAPPillSXEnterB", timeout=2) t.SetAnimation(i, akActorB, "ZazAPPillSXEnterA") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.3) ; actorA grunts, heavy breaths, insults, threats, begging or crying for help t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.3) ; actorB grunts, heavy breaths, insults, threats, taunts, laughs, etc. i += 1 else ;-------------------- Violent entry r = Utility.RandomInt(0, 100) if r < 33 Debug.Notification("Violent entry 1") ; SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=3) t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.3) ; actorA grunts, heavy breaths, insults, threats, begging or crying for help t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.3) ; actorB grunts, heavy breaths, insults, threats, taunts, laughs, etc. elseif r < 66 Debug.Notification("Violent entry 2") ; NOT-SO-FAST fucking with HARD and FAST pushes while holding right arm (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHand02B", timeout=3) t.SetAnimation(i, akActorB, "ZazAPPillSXHand02A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; actorA grunts, heavy breaths, insults, threats, begging or crying for help t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) ; actorB grunts, heavy breaths, insults, threats, taunts, laughs, etc. else Debug.Notification("Violent entry 3") ; SLOWER fucking while holding across belly (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHold02B", timeout=3) t.SetAnimation(i, akActorB, "ZazAPPillSXHold02A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; actorA grunts, heavy breaths, insults, threats, begging or crying for help t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) ; actorB grunts, heavy breaths, insults, threats, taunts, laughs, etc. endif ; TODO: implement voiceovers for both actors, more suited for a violent/forced entry (or at least the victim, actorA, could use a more vocal reaction) i += 1 endif ;==================== Fucking in progress string animStr ; selected animation name int animRpt ; how many times to repeat selected anim float animDur ; duration of the selected anim until it start to repeat float voiceRpt ; timeout for repeating voice sounds for selected anim int sets = Utility.RandomInt(5, 8) ; how many anim sets will have the whole fucking process while (sets > 4) ; TODO: this should be ZERO! we want 5 sets minimum and 8 max ; choose random anim int a = Utility.RandomInt(0, 6); if a == 0 animStr = "ZazAPPillSXHip02"; FAST and HARD fucking while holding hips (duration=4.666) animDur = 4.666 voiceRpt = 0.2; Grunt and moan every 0.2 sec elseIf a == 1 animStr = "ZazAPPillSXHip03"; SLOW and HARD fucking while holding hips (duration=1) animDur = 1.0 voiceRpt = 0.4; Grunt and moan every 0.4 sec elseIf a == 2 animStr = "ZazAPPillSXHand01"; FAST and HARD rythmic fucking while holding right arm (duration=2.333) animDur = 2.333 voiceRpt = 1.1; Grunt and moan every 1.1 sec elseIf a == 3 animStr = "ZazAPPillSXHand02"; NOT-SO-FAST fucking with HARD and FAST pushes while holding right arm (duration=1) animDur = 1.0 voiceRpt = 0.4; Grunt and moan every 0.4 sec elseIf a == 4 animStr = "ZazAPPillSXHold01"; NOT-SO-FAST fucking while holding across belly (duration=0.633) animDur = 0.633 voiceRpt = 0.3; Grunt and moan every 0.3 sec elseIf a == 5 animStr = "ZazAPPillSXHold02"; SLOWER fucking while holding across belly (duration=1) animDur = 1.0 voiceRpt = 0.4; Grunt and moan every 0.4 sec elseIf a == 6 && i > 10 animStr = "ZazAPPillSXSpank01"; FAST fucking while spanking with right hand (duration=2.333) animDur = 2.333 voiceRpt = 1.1; Grunt and moan every 1.1 sec endif animRpt = Utility.RandomInt(10, 20); how many times to repeat the animation while (animRpt > 0) ; let actorA randomly alternate fast anims for more variety, lets see how it will look... r = Utility.RandomInt(0, 100) if animStr == "ZazAPPillSXHip02" && r < 50 if Utility.RandomInt(0, 100) < 50 t.SetAnimation(i, akActorA, "ZazAPPillSXHand01B", timeout=animDur) else t.SetAnimation(i, akActorA, "ZazAPPillSXSpank01B", timeout=animDur) endIf elseIf animStr == "ZazAPPillSXHand01" && r < 50 if Utility.RandomInt(0, 100) < 50 t.SetAnimation(i, akActorA, "ZazAPPillSXHip02B", timeout=animDur) else t.SetAnimation(i, akActorA, "ZazAPPillSXSpank01B", timeout=animDur) endIf elseIf animStr == "ZazAPPillSXSpank01" && r < 50 if Utility.RandomInt(0, 100) < 50 t.SetAnimation(i, akActorA, "ZazAPPillSXHip02B", timeout=animDur) else t.SetAnimation(i, akActorA, "ZazAPPillSXHand01B", timeout=animDur) endIf else t.SetAnimation(i, akActorA, animStr+"B", timeout=animDur) endif t.SetAnimation(i, akActorB, animStr+"A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, voiceRpt) t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, voiceRpt) i += 1 animRpt -= 1 endWhile sets -= 1 endWhile ;==================== Climax (combines several anims for better effect) ; TODO: implement climax voiceover (at least for actorB here) ; ZazAPPillSXHip03, SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=0.6) ; make it last only for the push-in t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; Grunt and moan every 0.4 sec t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) i += 1 ; ZazAPPillSXEND01, Climax while holding hips (duration=3.300, should be preceeded by other hip anim, and can be quickly switched with it a few times while prolonging duration of this one for better effect) t.SetAnimation(i, akActorA, "ZazAPPillSXEND01B", timeout=0.3) ; make it last only 0.3 secs t.SetAnimation(i, akActorB, "ZazAPPillSXEND01A") i += 1 ; ZazAPPillSXHip03, SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=0.6) ; make it last only for the push-in t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; Grunt and moan every 0.4 sec t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) i += 1 ; ZazAPPillSXEND01, Climax while holding hips (duration=3.300, should be preceeded by other hip anim, and can be quickly switched with it a few times while prolonging duration of this one for better effect) t.SetAnimation(i, akActorA, "ZazAPPillSXEND01B", timeout=0.7) ; make it last a bit longer than last time t.SetAnimation(i, akActorB, "ZazAPPillSXEND01A") i += 1 ; ZazAPPillSXHip03, SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=0.6) ; make it last only for the push-in t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; Grunt and moan every 0.4 sec t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) i += 1 ; ZazAPPillSXEND01, Climax while holding hips (duration=3.300, should be preceeded by other hip anim, and can be quickly switched with it a few times while prolonging duration of this one for better effect) t.SetAnimation(i, akActorA, "ZazAPPillSXEND01B", timeout=0.3) ; a short one again t.SetAnimation(i, akActorB, "ZazAPPillSXEND01A") i += 1 ; ZazAPPillSXHip03, SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=0.5) ; make it last only for the push-in t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; Grunt and moan every 0.4 sec t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) i += 1 ; ZazAPPillSXEND01, Climax while holding hips (duration=3.300, should be preceeded by other hip anim, and can be quickly switched with it a few times while prolonging duration of this one for better effect) t.SetAnimation(i, akActorA, "ZazAPPillSXEND01B", timeout=0.9) ; make it last a bit longer than the long one before t.SetAnimation(i, akActorB, "ZazAPPillSXEND01A") i += 1 ; ZazAPPillSXHip03, SLOW and HARD fucking while holding hips (duration=1) t.SetAnimation(i, akActorA, "ZazAPPillSXHip03B", timeout=0.5) ; make it last only for the push-in t.SetAnimation(i, akActorB, "ZazAPPillSXHip03A") t.SetAnimVoice(i, akActorA, RoggFctFuckedViolent, 0.4) ; Grunt and moan every 0.4 sec t.SetAnimVoice(i, akActorB, RoggFctFuckingViolent, 0.4) i += 1 ; ZazAPPillSXEND01, Climax while holding hips (duration=3.300, should be preceeded by other hip anim, and can be quickly switched with it a few times while prolonging duration of this one for better effect) t.SetAnimation(i, akActorA, "ZazAPPillSXEND01B", timeout=Utility.RandomInt(2, 7)) ; finally climaxing, make it last a longer but random duration t.SetAnimation(i, akActorB, "ZazAPPillSXEND01A") i += 1 t.SetAnimation(i, akActorA, "ZazAPPillSXExitB", timeout=2) t.SetAnimation(i, akActorB, "ZazAPPillSXExitA") ; Register the appropriate library after-act maintenance callback function for primary actor t.InteractionEndEventName = "PilloryAssFuckEnd" + t.id + "X" + akActorA.GetFormID() Debug.Trace("MagicFX: Pillory Ass Fuck - thread InteractionEndEventName set.") furnLib.RegisterForModEvent(t.InteractionEndEventName, "OnPilloryAssFuck_End") Debug.Trace("MagicFX: Pillory Ass Fuck - end event registered.") t.reposActors = "AB" ; Allow repositioning actors A and B while animating t.aliasScriptA.Undress(0x00000004+0x00080000+0x00400000) t.aliasScriptB.Undress(0x00000001+0x00000004+0x00000008+0x00000010+0x00000200+0x00080000+0x00080000+0x00400000) t.StartAnimating() endEvent Yeah, i know it looks horrible, and long.This is kind of crappy WIP full of stuff that is not neccessary.What it does is to prepare arrays that tell the animator thread what to do and when - different stages with different animations and even different voices (controled via assigning actors into special "voice factions").As you can see it generates somewhat randomized flow, so no interaction is exactly the same nor exactly the same length.Player cannot influence it much, except via optional manual stage advancement (similar to sexlab). I am now trying to think about all possible scenarios and their requirements (for example, the whipping interaction is slightly more complicated, because it requires the actor to be given a weapon -cane- and make the actor to draw it, and then take it away at the end), and a way how to make it possible to define all this in simpler ways (as a JSON maybe?).
74wolfram Posted June 18, 2016 Posted June 18, 2016 This looks so very promising, and something that will without a doubt be very appreciated by everybody. Thanks a bunch for working on this:)
Roggvir Posted June 19, 2016 Author Posted June 19, 2016 For those of you that are wondering whats going on right now... After my long absence, it took me quite some time to get my development environment working again, and reinstalling everything, using latest versions of all neccessary or optional mods. Then i got a bit sidetracked for almost two days, working on a proof of concept for something i'd like ZAP to add, and after that got lost in time a bit while pushing my luck with some attempts at modeling in 3ds Max (a great fiasco!). And to top it off, after finally getting back to what i am supposed to work on, i found that even after successfully recompiling all scripts, some crucial functionality doesnt work. And that is because last time i didn't make any notes about what i just started rewriting at that time and how. So, i am now in the process of rewriting those broken parts, instead of trying to fix them (which seems more difficult). ...but you shouldn't feel sad or angry - at least its not dead, right?
Roggvir Posted June 20, 2016 Author Posted June 20, 2016 Progress update... Remove all DLC dependency: DONEI think there was some furniture added by some of the DLCs, but support for any of those will be added by separate plugins.Main reason behind this decision was to make testing easier for me (if only to make tes5edit load faster).After i acually release something, i might reconsider and merge it. Replace spell and faction based functionality by keywords: CANCELEDFor reasons i dont remember now ('twas probably mere stupidity), i used spells and factions to drive some of the mechanisms like which interaction options are available based on furniture the actor is in, etc. by adding some special spells to actors and checking if they have them, or assigning actors to factions and checking later whether they are member of this and that, or which rank it is, etc. Using keywords will be cleaner and much more lightweight in comparison. Rewriting Actor Script (yep, again): WIPAs i already mentioned in some post, i started making some changes before i took the last long break, changes that breaks everything.Instead of fixing it, i decided it will be better to rewrite the affected parts from scratch, as i have some new ideas and improvements on my mind anyway.(last update: 2016-06-20) Unplanned rewrite of Furniture Scanner (for player): WIP (98% done)Moved almost all functionality from scripts to native game functions (should run better, and its way easier to maintain).Now using Find Matching Reference to fill up to 10 aliases with nearest furniture objects of any of the registered types, and then setting appropriate global variables according to whats in the aliases.(last update: 2016-06-22) Unplanned rewrite of Mod Configuration Menu: WIP (90% done)Unplanned, but very much needed, now providing following features:- stop/restart the framework and all of its parts (usefull when uninstalling or before updating)- clear/refresh/unregister selected furniture library (usefull when updating or uninstalling libraries)- removing individual furniture registrations (useful if you want to keep given library but get rid of some furniture that causes any problems)- releasing individual framework threads (mostly for testing purposes, but may find its use in normal play too)- releasing individual actors from a framework thread (mostly for testing purposes - usually to get rid of the cow, when the randomizer tries to match her with a nearby farmer)(last update: 2016-06-24) Added Main Controler: DONERequired by the unplanned MCM rewrite to allow clean stop/restart of all parts of the framework.All quests/script are now started/stopped from this main controler via simple functions it provides,ensuring the proper startup/stopping sequence will be always followed.(last update: 2016-06-22) Once i am done with the above, we'll see...I wanted to do some more major changes, like move some furniture and interaction related settings/definitions to JSON to make it supposedly easier to work with, but i guess it's better to leave that for later once at least the pre-release is out (need to draw a line somewhere, otherwise there wouldn't be end to these neverending changes i do).-------------------------------------------------------------------------------------------------------------------------EDIT 1:While rewriting the actor script, i got a brilliant idea how to simplify handling of packages, and let few more things to the game native functions instead.I'll spare you of the details, but it will a bit more lightweight and much cleaner, so it will also make it easier to maintain.And since i had to rewrite those parts anyway, it shouldn't cost any additional time in comparison to rewriting it the old way.-------------------------------------------------------------------------------------------------------------------------EDIT 2:In regards to "Replace spell and faction based functionality by keywords"Now i know why i didnt do it this way before - because its freaking impossible!I did find it very suspicious, that all this time i completely missed the AddKeyword function, but i was so happy about it i didn't think!So i didn't noticed i am not looking at Skyrim CK wiki at that moment, but Fallout 4 CK wiki instead.Fortunately it didn't take long until i had to compile and test the code and discovered my stupid mistake.I am gonna keep few subtle changes, but otherwise these things will have to be done the same old way.At least the other new stuff, mentioned in EDIT 1, works great.
Roggvir Posted June 22, 2016 Author Posted June 22, 2016 Progress update... See previous post, look for orange date-stamps. (should i consolidate and move these lists into the first post to keep it all in one place? will probably try when i have next progress update)
Roggvir Posted June 24, 2016 Author Posted June 24, 2016 Not really a progress update, but more like a query for opinions... Made a new system for registering Furnitre Library Extensions. And i wonder what any modders thinks about this... How does it work for casual mod user: Install any 3rd party furniture library extensions (ie. put their esp plugins into Data dir, and activate them - via NMM/MO/manually, the usual stuff) On starting new game, or loading save that didn't have the Framework running when saving... Framework automatically checks loaded plugins to discover any new extensions (since its a new game, all of the existing extensions will be flagged as new), registers them with an Extensions Library, and shows notification to player, telling him to use the MCM menu to activate the new extensions. Player opens MCM menu for the Extensions Library, where he can activate all new discovered extensions with one click, or activate only individual selected extensions. When any extension is activated, its quest is started, firing the registration process for actual furniture and interactions the extension provides, registering them in the Furniture Library. On loading save that had the Framework running at the time of saving... Player must go to Extensions Library MCM menu, and click 'Discover' to make the framework run its discovery process. Other than that it works the same as described by #2. Uninstalling extension... - Player goes to Extensions Library MCM menu, selects page dedicated to the extension he wants to uninstall, and clicks the "Disable" button on it. - Framework switches the extension quest script to "stopping" state, making it refuse any new interaction requests, and marks all its registered furniture/interactions as disabled so any processes like the furniture scanner will simply ignore them. - Then it releases all threads and actors currently using any furniture or interactions registered by this extension. - And stops this extension's quest. After that, player can keep the extension still registered and inactive. Or he can click the "Unregister" button in the extension MCM Menu, purging any trace of it from both the Extensions Library and Furniture Library - until a discovery process is run again (automaticlaly on new game start, or manually at any time), it will be like this extension doesn't even exist. If unregistered, player can Save, Quit, and uninstall/remove this extension's esp. What is required from modders (apart from the usuall mod making procedures involved): List extension quest names in esp plugin's description Let's say you made a new esp plugin with two Furniture Library Extensions, or you merged two extension esp's into one, so you have now two extension quests, one having EditorID "fooChairsAndBeds" and the other one is "barThrone" (of course, best way would be to keep only one quest, and merge the contents of the two quest scripts into one -player can still disable individual furniture forms or interactions, so there is no reason for having several extension quests in one esp, except for ppl being lazy). So, you write the following anywhere in your esp plugin's description field...Furniture Library Extensions: fooChairsAndBeds, barThrone ...its case insensitive, the order of the formIDs doesn't matter, the whole string can be at the start of the description, or in the middle, or the last thing, whitespace between formIDs doesn't matter.What does matter: - the string "Furniture Library Extensions:" must be written exactly as you see here (whitespace matters in this case) - formIDs cannot contain any white space (*not sure if CK even allows it, but if your formID would be "fooChairs and Beds", it wouldn't work here) What do you people think about this? I find it nice, that the user has full control over the in-game extension installation process - nothing is automatically started. The description thing is a bit annoying, but i couldn't find any other way, so i think modders can survive that requirement, right?
Musje Posted June 24, 2016 Posted June 24, 2016 It sounds easy enough! Are you already using PapyrusUtils by any chance? If I recall correctly, that has options for sharing data between plugins, like having global variables across mods. Your mod could simply have a global array of candidate plugins, and any mod could announce itself into that array, after which your mod optionally installs the plugin's furniture. And I think SL already installs PapyrusUtils so it's not like you;'re adding something extra just for the registration process.
Roggvir Posted June 24, 2016 Author Posted June 24, 2016 It sounds easy enough! Are you already using PapyrusUtils by any chance? If I recall correctly, that has options for sharing data between plugins, like having global variables across mods. Your mod could simply have a global array of candidate plugins, and any mod could announce itself into that array, after which your mod optionally installs the plugin's furniture. And I think SL already installs PapyrusUtils so it's not like you;'re adding something extra just for the registration process. Yes, i am using PapyrusUtil, but i dont see there anything explicitly for sharing data (globals or not). There is a bunch of functions for various operations, mostly for working with arrays, etc. I can of course use those and other functions to implement such solution, but i guess thats not what you mean, right? Can you go into a bit more details to explain? Anyway, regarding the global array of candidate plugins - would there be some nice advantage over what i did? Right now, i like my solution quite a lot, mostly just because its cool ;-) but also because it takes away some of the usuall baggage carried by similar systems. The plugins do not need to be proactive in any way. They do not need to contain anything to automatically start some script, however tiny, just so they can announce themselves (even if that "script" is just a simple AddForm one-liner, etc). Also, the fewer things a modder needs to do, the better. If i can take away the "burden" of bundling in some activating script, and trade it for the requirement of listing a quest name(s) in the plugin description, then i like doing it - a small difference, but in my opinion every tiny bit counts. Of course, if someone makes a plugin that automatically starts something, i cannot prevent it, and i dont see a reason to (i'd say they have they reasons to do that). It gives people optional flexibility, but it isn't neccessary by default. I dont really mind changing it to make the plugins announce themselves, but it should provide some advantage at this point, because current system is already fully implemented and working. Still, thats why i did asked for opinions - if your or someone elses idea actually does have some advantage, or even if just more people say that writing a string into plugin description bothers them more than adding few lines of code to a script, then it will be changed. So... what was that about PapyrusUtil? (didn't you maybe meant Storage/JsonUtil instead?)
Musje Posted June 24, 2016 Posted June 24, 2016 Yeah StorageUtil. That's part of PapyrusUtil, no? I don't think it matters much one way or the other. As long as your system can cope with other crap being present in the description, and if the description can be long enough, then that's fine. If you are "misusing" the description field in this manner, you have to be prepared for other mods doing the same
Roggvir Posted June 24, 2016 Author Posted June 24, 2016 Yeah StorageUtil. That's part of PapyrusUtil, no? I don't think it matters much one way or the other. As long as your system can cope with other crap being present in the description, and if the description can be long enough, then that's fine. If you are "misusing" the description field in this manner, you have to be prepared for other mods doing the same Regarding position, it doesnt matter, it can be mixed in anywhere (but it must have a space or comma after the last quest name). Regarding the length constraint, that depends on how long the quest's FormID is, and how many are there (ideally there should be just one). The description is limited to 512 bytes (ie. 512 characters). For example, this is exactly 512 chars long: (CR/LF new lines included - i am not sure if CK uses CR/LF or what, but most probably yes) Donec feugiat dolor vitae urna tincidunt finibus. Nullam vestibulum massa in nisl ullamcorper, in scelerisque ante porttitor. Donec sit amet tempus quam, non euismod quam. Proin non erat rutrum, placerat turpis a, maximus magna. Aenean at tristique ante, ultricies accumsan massa. Quisque finibus cursus neque at pharetra. SuspendissFFLibExt: fooQuest1, barQuest2 at mi nisi lacinia odio, ut aliquet sem velit vel odio. Donec in ligula eleifend, tempor neque nec, posuere risus. Suspendisse lacinia in. ...that isn't much to begin with. Do people really put anything in there? anything long enough so they would struggle with the length? Remember, we're talking about special purpose plugin - i dont think there is any need for ppl to put there a list of all provided interactions, or furniture, etc. (i can provide other means for that, if requested), and what else would they put there if not that. I can make the special recognization token shorter, like in the spoiler above, but any less could introduce a problem with falsely matching mods having some other strange abbreviations there as part of their description.
Roggvir Posted June 25, 2016 Author Posted June 25, 2016 Ok, i am gonna keep the plugin discovery system that is using the desription, at least as a default method.As i wrote, auto-registering by plugins themselves is still possible if needed, so its not an issue.But i have a different question to ask now...The way how the furniture and interactions are defined in a library extension pluginsCurrently, the following is an example of a complete script that is used for furniture/interaction definitions in a plugin.This is all your plugin needs, apart from small magic effect fragments that are used to start individual interactions.(example contains only two furniture types registrations and two interactions, just enough to give you an idea, its by far not a complete default library script)I have two questions for you: Any better idea how to store the registrations? (the data inside all the REGISTRATION_ states)I like having them in script, because its more flexible - for example, you can make things conditional - register or do something depending on other addons, or other registered plugins.But maybe it is not needed (i didnt found a real reason for it myself yet), and maybe people would prefer to set it all via CK? (except of course the starting/event handling functions which should remain where they are). Any general improvement tips?Like using different ways to do things, different types (forlists vs. arrays of forms, etc.), or anything to make things either more efficient and optimized, or easier for plugin creators. scriptname rffDefaultFurniture extends rffFurnitureLibrary {Register default furniture types} ;// Name of a furniture group currently being registered ;// Value must be set everytime in each of your registering states string groupName ;// Formlists containing furniture forms - assign in CK ;// Each formlist must only contain furniture forms allowing same types of interactions. formList property rffFmlVanillaChairs auto ;// All kinds of standard sized Vanilla chairs formList property rffFmlZbfPillorySingle auto ;// Zap pillory single and other similar types fitting same animations, including static versions ;// Global variables used for signaling when player is near any type of registered furniture - assign in CK ;// One global per furniture group globalVariable property rffNearVanillaChairs auto globalVariable property rffNearZbfPillorySingle auto ;// Spells used to signal which furniture is being currently used by an actor - assing in CK ;// Used mostly just to filter player dialogue of interaction choices, when talking to actors in furniture or while player is in furniture spell property rffInVanillaChairs auto spell property rffInZbfPillorySingle auto ;// Interaction spells - assign in CK ;// A special spells with own specific magicEffects whose activeMagicEffect script starts particular interaction spell property rffDoChairSpank auto spell property rffDoPilloryFuck auto spell property rffDoPilloryWhip auto ;/============================================================================= // Furniture registration states // NOTE: States must be named REGISTER_#, where # is a number ranging from 0 // up to 127. Gaps in the number sequence are allowed. =============================================================================/; state REGISTER_0 event OnBeginState() groupName = "Zbf Pillory" RegisterGroup(groupName) endEvent event OnRffFL_Registered(int id, string evtGroupName) if evtGroupName != groupName ;// not our group name, means this event was not meant for us here return endIf rffFurnitureInfo info = PickById(id) ;// get info alias script this group has been assigned to SetForms(info, None, rffFmlZbfPillorySingle) ;// push the listed furniture forms into array of the info 'object' (TODO: maybe change the array into a formlist - easier usage? benefits?) info.idSpell = rffInZbfPillorySingle info.globalVar = rffNearZbfPillorySingle info.actionSpells = new spell[2] info.actionSpells[0] = rffDoPilloryFuck info.actionSpells[1] = rffDoPilloryWhip info.idles = new string[5] ;// list of randomly played animations while idle in furniture info.idles[0] = "ZazAPFPillSingle01" info.idles[1] = "ZazAPFPillSingle02" info.idles[2] = "ZazAPFPillSingle03" info.idles[3] = "ZazAPFPillSingle04" info.idles[4] = "ZazAPFPillSingle05" info.hitIdles = new string[3] ;// list of animations played when actor is hurt while in furniture (ie. when being whipped) info.hitIdles[0] = "ZazAPFPillSingle03" info.hitIdles[1] = "ZazAPPillTorSpank1B" info.hitIdles[2] = "ZazAPPillTorSpank2B" GoToState("") endEvent endState state REGISTER_23 event OnBeginState() groupName = "Vanilla Chair" RegisterGroup(groupName) endEvent event OnRffFL_Registered(int id, string evtGroupName) if evtGroupName != groupName ;// not our group name, means this event was not meant for us here return endIf rffFurnitureInfo info = PickById(id) ;// get info alias script this group has been assigned to SetForms(info, None, rffFmlVanillaChairs) ;// push the listed furniture forms into array of the info 'object' (TODO: maybe change the array into a formlist - easier usage? benefits?) info.idSpell = rffInZbfVanillaChairs info.globalVar = rffNearVanillaChairs info.actionSpells = new spell[1] info.actionSpells[0] = rffDoChairSpank ;// info.idles = new string[1] ; list of randomly played animations while idle in furniture (TODO: find out which ones go with the chairs) ;// info.idles[0] = "" ;// info.hitIdles = new string[1] ; list of animations played when actor is hurt while in furniture (no use for chairs, leave empty) ;// info.hitIdles[0] = "" GoToState("") endEvent endState ;/============================================================================= // Interactions // These functions are to be called from external sripts, or dialog fragments. // For most, we could simply call the rffLib.StartInteraction() directly, from // wherever is the interaction initiated, but until this library is finalized, // i like to keep them here in case any happens to require any pre-processing // before the actual StartInteraction() call. // TODO: maybe make it a requirement for the functions to be here? // could be a good idea to have them listed in the plugin script if only // for the sake of order and clarity, for everyone to easily find them. =============================================================================/; ;// Starts the "spanking chair" interaction between given actors (actorA is the one being spanked) function ChairSpank(actor actorA, actor actorB) rffLib.StartInteraction(rffDoChairSpank, actorA, actorB) endFunction ;// Callback to do some post-interaction maintenance or cleanup event OnChairSpank_End(form formActor, int threadId) UnRegisterForModEvent("ChairSpankEnd"+ threadId +"_"+ formActor.GetFormID()) rffMain rff = rffLib.GetAPI() rffThread t = rff.GetThread(threadId) if t t.Release() ;// for now, just release the whole thread (TODO: consider adding a bit of micromanagement) endIf endEvent ;// Starts the "fucking in pillory" interaction between given actors (actorA is the one locked in pillory) function PilloryFuck(actor actorA, actor actorB) rffLib.StartInteraction(rffDoPilloryFuck, actorA, actorB) endFunction ;// Callback to do some post-interaction maintenance or cleanup event OnPilloryFuck_End(form formActor, int threadId) UnRegisterForModEvent("PilloryFuckEnd"+ threadId +"_"+ formActor.GetFormID()) rffMain rff = rffLib.GetAPI() rffThread t = rff.GetThread(threadId) if t actor actorA = t.actorA actor actorB = t.actorB actorA.SetFactionRank(t.rff.RoggFactInThread, 6) actorB.SetFactionRank(t.rff.RoggFactInThread, 5) Debug.SendAnimationEvent(actorA, "ZazAPPillSolo01") ;// reset animation while keeping actor in pillory t.ResetActorPosition(actorA) if !t.actorScriptA.isReleasing t.actorScriptA.GotoState("IN_POSITION") ;// Switch back to sitting state (if not being released) ;// Make actorA (locked in pillory) play a specific idle reflecting his state after this interaction Debug.SendAnimationEvent(actorA, t.furnitureInfo.idles[2]) t.actorScriptA.RegisterForSingleUpdate(20) ;// make this idle last at least 20 seconds endif t.RequestActorRelease(actorB) endif endEvent ;// Starts "whipping in pillory" interaction between given actors (actorA is the one locked in pillory) function PilloryWhip(actor actorA, actor actorB) rffLib.StartInteraction(rffDoPilloryWhip, actorA, actorB) endFunction ;// Callback to do some after-act maintenance or cleanup event OnPilloryWhip_End(form formActor, int threadId) UnRegisterForModEvent("PilloryWhipEnd"+ threadId +"_"+ formActor.GetFormID()) rffMain rff = rffLib.GetAPI() rffThread t = rff.GetThreadById(threadId) if t actor actorA = t.actorA actor actorB = t.actorB actorA.RemoveFromFaction(Game.GetFormFromFile(0x00000D64, "RoggVoiceover.esp") as faction) ;// TODO: fix this ugly thing! actorA.SetFactionRank(t.rff.RoggFactInThread, 6) actorB.SetFactionRank(t.rff.RoggFactInThread, 5) Debug.SendAnimationEvent(actorA, "ZazAPPillSolo01") ;// reset animation while keeping actor in pillory t.ResetActorPosition(actorA) if !t.actorScriptA.isReleasing ; if the actor isn't being released t.actorScriptA.GotoState("IN_POSITION") ; switch back to "sitting" state ;// Make actorA (locked in pillory) play a specific idle reflecting his state after being whipped Debug.SendAnimationEvent(actorA, t.furnitureInfo.idles[2]) t.actorScriptA.RegisterForSingleUpdate(20) endif ;// remove the cane and package we added in the activeMagicEffect script t.actorScriptB.RemovePackage(rff.RffPkgWhipping) ;// Wait a bit - hoping it would give the game some time to sort out packages before we remove ;// the cane, to prevent NPC from sometimes unsheating their default weapon afterwards Utility.Wait(0.2) actorB.EvaluatePackage() ;// not even this seem to be help with removing weapon unsheathing completely actorB.ClearLookAt() ;// Final fix for the weapon unsheathing glitch, if everything else failed... if actorB.IsWeaponDrawn() actorB.SheatheWeapon() endif ;// Remove the cane we added in magix effect script if actorB.GetItemCount(rff.zbfWeaponCane) > 0 if actorB.IsEquipped(rff.zbfWeaponCane) actorB.UnequipItem(rff.zbfWeaponCane) endif actorB.RemoveItem(rff.zbfWeaponCane, 1, true) endif t.RequestActorRelease(actorB) ;// release secondary actor from thread endif endEvent
Musje Posted June 25, 2016 Posted June 25, 2016 This looks easy enough to use (especially with he example script ). The real challenge is going to be to find nice animations to go with different furniture 1) I think the setup method is fine; other mods seem to use arrays and methods to fill them the same way. It would definitely be nice to be able to control the registration programmatically so things can be made optional 2) The _End events contain a lot off stuff that smells like it belongs in the framework rather than the mod. Having the actor remain seated or unequipping stuff should either be done outside the framework with generic functions, or done through very simple, single function calls into the framework with little or no framework specific logic around them. Looking at the script, that may require a few more callbacks though.
Roggvir Posted June 25, 2016 Author Posted June 25, 2016 2) The _End events contain a lot off stuff that smells like it belongs in the framework rather than the mod. Having the actor remain seated or unequipping stuff should either be done outside the framework with generic functions, or done through very simple, single function calls into the framework with little or no framework specific logic around them. Looking at the script, that may require a few more callbacks though. Well, the _End events will be usually very interaction specific. They cannot be all written as a few generic functions, unless you want to account for infinite number of things that all modders might need there. Unequipping of stuff handled "outside of framework"? what do you mean? i dont understand, where should it be? What you see there, is unequipping cane that was added to the actor by the interaction starter script which is part of this extension (in the activeMagicEffect script for that particular interaction), so it makes sense that it gets removed again from a function that is again part of this extension. Take that pillory example - you want to keep the locked actor in pillory, even after the interaction finished, and only let go the other actor, but then other interactions, especially (but not only) those not involving any furniture, will require to let go all actors. That's simple - we could just make two functions for it, but then what about the post-interaction animation that we might want to play? ...you may want the actor to keep shaking for a while, or lying still breathing heavily, or something like that, depending on what you want and what animations you have available. So, that would require passing some parameter into that function, plus another one to specify how long the anim/pose should last. And then maybe AFTER that you want to release the actor, or maybe not - another complication a universal function must handle and we must somehow tell it to do so. Or what if you want to make one of the actor run away after, or you want to immediately initiate other interaction (maybe foreplay just ended, and now you want to finally do the "deed"). Or maybe there were more than two actors involved - A was fucking B while C was getting blowjob from B - maybe A is done, and you want him leave, while C will want to go around to try some fucking for a change (which would be ideally done by immediately starting new different interaction between B and C). Maybe you want to add some special package to some actor, to make him do something complicated like running around, picking flowers, and throwing them at the lady ...i dont know, Maybe you want to do something based on a random chance. There is an infinite number of possibilities. What i want to say is, that simple interactions will have simple endings, probably having only the t.Release() call, or t.Release("A"/"AB"/"DCBA"/...) to release only specific actors in specific order. Any other more complicated interactions will need specific code like you see in that example, and i cannot predict what it should be, so i cannot create a universal functions for that.
Musje Posted June 25, 2016 Posted June 25, 2016 I'll have to get some hands on with this before I can see the design patterns So when is it ready?
Roggvir Posted June 25, 2016 Author Posted June 25, 2016 I'll have to get some hands on with this before I can see the design patterns So when is it ready? I can't really tell - everything always looks like it will be a quick work, and then its days of coding. But i am very intensively working on it. It should be soon - any more precise estimate and i would be lying I wont be adding any new features from now on, until it is out, so that should help speed things up. There is only one thing missing now - finishing the rewrite of the actor script, which isn't a small task. Soon.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.