Nymra Posted May 15, 2020 Posted May 15, 2020 Beware, I m a total noob. I am currently in the process of learning to understand papyrus and managed to change some MCM values and poses, that is all. But now I want to dig deeper and start modifying existing mods to learn. I want to add a "Success Chance" to a function that is currently only causing stamina damage and then has automatic success. Mod is Naked Dungeons (link below). 1. the PC gets locked into Zaz Furniture 2. the PC can press Space to pop up a dialogue with three options. And one option is to "wiggle free" This must be the following code lines. They apply 100 stamina damage and then automatically issue a "success". I want to change ONE thing (another if possible only). 1. I want to add a success chance to the script. So if I press the option and the stamina damage is applied, I want XX% chance of success. For example 10% (so each time I choose the option I have 10% chance of success but also lose 100 stamina even when I fail. If Success, go to Debug.MessageBox("Your bindings finally feel looser than before... ") If no: Debug.MessageBox("Your bindings are stronger than you thought... ") I suspect it can maybe be changed in this part, but as I said... me no clue :D' EDIT: In the meantime I understand as much as that this is meant to be a skill check that references DD. But it does not look like the skill check code I found when searching, so my original request will be the same (if possible) to make it a fixed chance not dependend on skill or a DD difficulty setting. If that is not possible of course restoring this to work as skill check might be a possibility Quote endif Success = Success || (Utility.RandomInt(1, MaxVal) <= Skill) if Success Debug.MessageBox("Your bindings finally feel looser than before... ") else 2. if possible, I would like to see a cooldown added in reallife seconds (for example 60 seconds) before I can try again. This is a highly optional and secondary target, tho. Code in spoiler, source in attachment Thx a hole damn fucking lot. (I can compile the script myself if there are no errors, but I cannot change code that complex yet sadly, sorry) Spoiler Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !UI.IsMenuOpen("BarterMenu") && !UI.IsMenuOpen("ContainerMenu") && !UI.IsMenuOpen("Sleep/Wait Menu") CanShowMenu = false Float stamina = libs.PlayerRef.GetActorValue("Stamina") Float damage = StaminaChange*libs.PlayerRef.GetBaseActorValue("Stamina") int choice = ndun_CaptMsg.Show() if choice == 0 ;take off if Success SetObjectiveCompleted(20, true) SetStage(100) else Debug.MessageBox("Your bindings are too tight to break out of them.") CanShowMenu = true endif elseif choice == 1 ;struggle if stamina < damage Debug.MessageBox("You are too tired to move your body.") else libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) if !(sla.IsActorArousalLocked(libs.PlayerRef) || sla.IsActorArousalBlocked(libs.PlayerRef)) exposure = sla.GetActorExposure(libs.PlayerRef) + cfgqst.ExposureChange[0] if exposure > 100 exposure = 100 endif sla.SetActorExposure(libs.PlayerRef, exposure) endif Success = Success || (Utility.RandomInt(1, MaxVal) <= Skill) if Success Debug.MessageBox("Your bindings finally feel looser than before... ") else Skill += 10 Debug.MessageBox("Your bindings are stronger than you thought... ") endif endif CanShowMenu = true endif endif endif EndEvent Mod: ndun_captivequest_qf_scr.psc
Seijin8 Posted May 15, 2020 Posted May 15, 2020 Random chances via papyrus are generally going to use Utility.RandomInt(). Within the function, you specify a list of values, so Utility.RandomInt(0, 11) will give a random int from 0 to 11, so 12 total options. With that, you just separate out what you want to happen based on the result. Sample for 1-in-10 chance: int iRND = Utility.RandomInt(0, 9) If iRND == 9 ; 1 chance in 10 DoTheThing() EndIf
Nymra Posted May 15, 2020 Author Posted May 15, 2020 29 minutes ago, Seijin8 said: Random chances via papyrus are generally going to use Utility.RandomInt(). Within the function, you specify a list of values, so Utility.RandomInt(0, 11) will give a random int from 0 to 11, so 12 total options. With that, you just separate out what you want to happen based on the result. Sample for 1-in-10 chance: int iRND = Utility.RandomInt(0, 9) If iRND == 9 ; 1 chance in 10 DoTheThing() EndIf I found something in the meantime and put it like this: Quote endif Success = Success || (Utility.RandomInt(0, 100) <= 50) if Success Debug.MessageBox("Your bindings finally feel looser than before... ") else Skill += 10 Debug.MessageBox("Your bindings are stronger than you thought... ") endif It looks different than urs, but if I understand it correctly it will generate a random number between 0 and 100 and if 50 is same or higher it will succeed, correct? I tried it ingame and at least I did not have alot of success, but also cannot see the "roll" so can only guess how high the chances actually are.
Seijin8 Posted May 15, 2020 Posted May 15, 2020 15 minutes ago, Nymra said: Success = Success || (Utility.RandomInt(0, 100) <= 50) I have no idea what that will generate. I'm a little surprised that compiled. At minimum, I'd rewrite it as: If !Success int iRND = Utility.RandomInt(0, 100) ; <--- that is finding 101 numbers, btw... If iRND <= 50 Success = true EndIf EndIf 16 minutes ago, Nymra said: but also cannot see the "roll" Add a line like: Debug.Notification("Success is " +Success+ ", and random is "+iRND+ ".") So then you will be able to see what transpired. Take it out once you are satisfied everything is working.
Monoman1 Posted May 15, 2020 Posted May 15, 2020 Generally you'll compare it to an Mcm variable (if you want the user to be able to configure the chance of success) If Menu.SuccessChance >= Utility.RandomInt(0, 100) DoTheThing() Else DoTheOtherThing() EndIf You might also want to use: Utility.IsInMenuMode() As key presses can occur while in console as well (which is really annoying) and that line above should (I think) cover all menus except dialogue.
Nymra Posted May 15, 2020 Author Posted May 15, 2020 thx alot. will try both and test. this script stuff feels like doing magic
Seijin8 Posted May 15, 2020 Posted May 15, 2020 3 minutes ago, Nymra said: this script stuff feels like doing magic That never really goes away. Welcome to wizarding school!
Guest Posted May 15, 2020 Posted May 15, 2020 If you are using it for percentage values, use RandomFloat with no arguments. float roll = Utility.RandomFloat() MiscUtil.PrintConsole("Roll: " + (roll * 100) as int) if roll >= 0.75 ; 25% chance do something elseif roll >= 0.5 ; 50% chance do something elseif roll >= 0.25 ; 75% chance do something elseif roll >= 0.05 ; 95% chance do something else do something else endif if roll < 0.25 ; 25% chance do something elseif roll < 0.5 ; 50% chance do something elseif roll < 0.75 ; 75% chance do something elseif roll < 0.95 ; 95% chance do something else do something else endif Inline conditionals such as Success = Success || (Utility.RandomInt(0, 100) <= 50) is fine too. Success = Success || (Utility.RandomFloat() >= 0.5) Mind you, it will always be a success if Success is already true, the second conditional will only be evaluated if Success is currently false.
Nymra Posted May 15, 2020 Author Posted May 15, 2020 1 hour ago, Monoman1 said: Generally you'll compare it to an Mcm variable (if you want the user to be able to configure the chance of success) If Menu.SuccessChance >= Utility.RandomInt(0, 100) DoTheThing() Else DoTheOtherThing() EndIf You might also want to use: Utility.IsInMenuMode() As key presses can occur while in console as well (which is really annoying) and that line above should (I think) cover all menus except dialogue. this is true. the keys trigger while in console. but sorry I have to ask how "Utility.IsInMenuMode()" is integrated. I have no idea where to put that in this script part. The Key press is at the start but there is no utlity?! like : "Event OnKeyDown.Utility.IsInMenuMode(Int KeyCode) ?! sorry Quote Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !UI.IsMenuOpen("BarterMenu") && !UI.IsMenuOpen("ContainerMenu") && !UI.IsMenuOpen("Sleep/Wait Menu") CanShowMenu = false Float stamina = libs.PlayerRef.GetActorValue("Stamina") Float damage = StaminaChange*libs.PlayerRef.GetBaseActorValue("Stamina") int choice = ndun_CaptMsg.Show() if choice == 0 ;take off if Success SetObjectiveCompleted(20, true) SetStage(100) else Debug.Notification("Your bindings are too tight to break out of them.") CanShowMenu = true endif elseif choice == 1 ;struggle if stamina < damage Debug.Notification("You are too tired to move your body.") else libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) if !(sla.IsActorArousalLocked(libs.PlayerRef) || sla.IsActorArousalBlocked(libs.PlayerRef)) exposure = sla.GetActorExposure(libs.PlayerRef) + cfgqst.ExposureChange[0] if exposure > 100 exposure = 100 endif sla.SetActorExposure(libs.PlayerRef, exposure) endif If !Success int iRND = Utility.RandomInt(0, 100) ; <--- that is finding 101 numbers, btw... If iRND <= 10 Success = true Debug.Notification("Success is " +Success+ ", and random is "+iRND+ ".") EndIf EndIf if Success Debug.Notification("Your bindings finally feel looser than before... ") else libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(10) libs.SexLabMoan(libs.PlayerRef) Debug.Notification("Your bindings are stronger than you thought... ") endif endif CanShowMenu = true endif endif endif EndEvent 13 minutes ago, Hawk9969 said: If you are using it for percentage values, use RandomFloat with no arguments. float roll = Utility.RandomFloat() MiscUtil.PrintConsole("Roll: " + (roll * 100) as int) if roll >= 0.75 ; 25% chance do something elseif roll >= 0.5 ; 50% chance do something elseif roll >= 0.25 ; 75% chance do something elseif roll >= 0.05 ; 95% chance do something else do something else endif if roll < 0.95 ; 95% chance do something elseif roll < 0.75 ; 75% chance do something elseif roll < 0.5 ; 50% chance do something elseif roll < 0.25 ; 25% chance do something else do something else endif Inline conditionals such as Success = Success || (Utility.RandomInt(0, 100) <= 50) is fine too. are there any advantages/disadvantegs in the different methods? Like is your method better for consecutive rolls? At least it looks on point and needs only one line. It seems all three worked by my rough game tests. the printconsole seems to be elegant 13 minutes ago, Hawk9969 said: Success = Success || (Utility.RandomFloat() >= 0.5) Mind you, it will always be a success if Success is already true, the second conditional will only be evaluated if Success is currently false. yeah I know and it is all that is required for the task at hand at least. much appreciated.
Guest Posted May 15, 2020 Posted May 15, 2020 8 minutes ago, Nymra said: are there any advantages/disadvantegs in the different methods? Like is your method better for consecutive rolls? At least it looks on point and needs only one line. Most languages these days will have a function that generates a random floating point ranging from 0.0 to 1.0. The main usage for those functions are as the backbone for other PRNG algorithms and as a random percentage function. Since most PRNG algorithms will call that anyway, it will be faster than the other random range functions. There is also an advantage if you need a percentage value with digits after the decimal point. With RandomInt, you would need to always have a fixed set of digits after the decimal point while at the same time risking going over the scope of a signed 32-bits int. This is Python's crypto-safe PRNG implementation: def random(self): """Get the next random number in the range [0.0, 1.0).""" return (long(_hexlify(_urandom(7)), 16) >> 3) * RECIP_BPF Every other range function calls random() to get a floating point from 0.0 to 1.0 to use as base for the algorithm.
Monoman1 Posted May 15, 2020 Posted May 15, 2020 50 minutes ago, Nymra said: like : "Event OnKeyDown.Utility.IsInMenuMode(Int KeyCode) ?! sorry I mean instead of: Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !UI.IsMenuOpen("BarterMenu") && !UI.IsMenuOpen("ContainerMenu") && !UI.IsMenuOpen("Sleep/Wait Menu") Do: Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !Utility.IsInMenuMode() Now I will say it might be a good thing to test this with the mod 'souls menu' - that mod that unpauses all the menus because apparently IsInMenuMode() returns true if you're in a menu and the game is paused. However, I'm nearly sure I've used it before ok. Also, just a personal preference but I would create my own PlayerRef property instead of constantly accessing it through devious devices like: lib.PlayerRef.Blah I don't think it makes a huge difference but you are accessing an external script to get something that is freely available. Just create your own property for the player Actor Property PlayerRef Auto fill in the property and change all the: libs.PlayerRef to just: PlayerRef.
Nymra Posted May 15, 2020 Author Posted May 15, 2020 38 minutes ago, Monoman1 said: I mean instead of: Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !UI.IsMenuOpen("BarterMenu") && !UI.IsMenuOpen("ContainerMenu") && !UI.IsMenuOpen("Sleep/Wait Menu") Do: Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !Utility.IsInMenuMode() Now I will say it might be a good thing to test this with the mod 'souls menu' - that mod that unpauses all the menus because apparently IsInMenuMode() returns true if you're in a menu and the game is paused. However, I'm nearly sure I've used it before ok. I m just now booting to see if I failed or not 38 minutes ago, Monoman1 said: Also, just a personal preference but I would create my own PlayerRef property instead of constantly accessing it through devious devices like: lib.PlayerRef.Blah I don't think it makes a huge difference but you are accessing an external script to get something that is freely available. Just create your own property for the player Actor Property PlayerRef Auto fill in the property and change all the: libs.PlayerRef to just: PlayerRef. hmm, I dont know why this is in the code. I m just editing existing code its not written by me. I dont know if it is causing trouble if I change the player lib because there are 100 other scripts in the mod
Nymra Posted May 15, 2020 Author Posted May 15, 2020 Yay! I might not look so pretty but it works. (also the in console block for the activation!) I completly rearranged the code, removed the pop up menu compeltly (they are the bane of my existence in skyrim mods lol) and managed to find a logic to achieve the same goal with only one repeated key press. More Moaning, more stamina damage, more time consumption, yay! Following questions remain: 1. How can I prevent spamming they hotkey? The function to "wiggle free" takes rougly 15 seconds now. But when u press the hotkey several times it starts the function parallel to each other. 2. How can I add phonemes to the code? I found the mfg console source but I cannot get it to compile. Guess I need to "bool" and "int" something someplace first i guess... Here is the code without MFG console stuff yet: Spoiler Event OnKeyDown(Int KeyCode) if KeyCode == 57 Int exposure Float stamina = libs.PlayerRef.GetActorValue("Stamina") Float damage = StaminaChange*libs.PlayerRef.GetBaseActorValue("Stamina") if CanShowMenu && !UI.IsMenuOpen("Dialogue Menu") && !Utility.IsInMenuMode() ;struggle if stamina < damage Debug.Notification("You are too tired to move your body.") else libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) if !(sla.IsActorArousalLocked(libs.PlayerRef) || sla.IsActorArousalBlocked(libs.PlayerRef)) exposure = sla.GetActorExposure(libs.PlayerRef) + cfgqst.ExposureChange[0] if exposure > 100 exposure = 100 endif sla.SetActorExposure(libs.PlayerRef, exposure) endif If !Success int iRND = Utility.RandomInt(0, 100) If iRND <= 10 Success = true Debug.Notification("Success is " +Success+ ", and random is "+iRND+ ".") EndIf EndIf if Success Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Debug.Notification("Your bindings finally feel looser than before... ") Free = true else libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) libs.PlayerRef.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Utility.Wait(2) libs.SexLabMoan(libs.PlayerRef) Debug.Notification("Your bindings are stronger than you thought... ") endif endif if Free libs.SexLabMoan(libs.PlayerRef) SetObjectiveCompleted(20, true) Utility.Wait(10) SetStage(100) endif endif endif EndEvent
Guest Posted May 15, 2020 Posted May 15, 2020 bool bLocked = false Event OnKeyDown(Int KeyCode) if KeyCode != 57 || bLocked return endif bLocked = true if !CanShowMenu || Utility.IsInMenuMode() || UI.IsMenuOpen("Dialogue Menu") bLocked = false return endif Actor player = libs.PlayerRef Float stamina = player.GetActorValue("Stamina") Float damage = StaminaChange * player.GetBaseActorValue("Stamina") ;struggle if stamina < damage Debug.Notification("You are too tired to move your body.") bLocked = false return endif player.DamageActorValue("Stamina", damage) Utility.Wait(2) libs.SexLabMoan(player) if !sla.IsActorArousalLocked(player) && !sla.IsActorArousalBlocked(player) Int exposure = sla.GetActorExposure(player) + cfgqst.ExposureChange[0] if exposure > 100 exposure = 100 endif sla.SetActorExposure(player, exposure) endif If Success || Utility.RandomFloat() < 0.1 Success = true ; Is this a global variable? Utility.Wait(2) libs.SexLabMoan(player) Debug.Notification("Your bindings finally feel looser than before... ") Free = true ; Is this a global variable? SetObjectiveCompleted(20, true) Utility.Wait(10) SetStage(100) else Int i = 2 while i i -= 1 player.DamageActorValue("Stamina", damage) Int j = 3 while j j -= 1 Utility.Wait(2) libs.SexLabMoan(player) endwhile endwhile Debug.Notification("Your bindings are stronger than you thought... ") endif bLocked = false EndEvent Changed some things a starting programmer should take into account: Flat is better than nested. Sparse is better than dense. Avoid repetition. Loops exist for a reason. Also showed how you can do a non blocking lock for the hotkey in Papyrus. For phonemes just add: MfgConsoleFunc.SetPhoneme(player, 0-15, 0-100)
Nymra Posted May 15, 2020 Author Posted May 15, 2020 39 minutes ago, Hawk9969 said: Change somethings a starting programmer should take into account: Very cool, thx. So elegant. Quote Flat is better than nested. Sparse is better than dense. Avoid repetition. Loops exist for a reason. I knew something like that Loops existed but this is virtually my first 24 hours of doing this and I just try to get my head arround the stuff bit by bit. Quote Also showed how you can do a non blocking lock for the hotkey in Papyrus. For phonemes just add: MfgConsoleFunc.SetPhoneme(player, 0-15, 0-100) so easy... wow. Now I wonder what I failed to ask google because nothing even remotely close to that showed up o_O AS for the "Success" and "Free" part. The Sucess was there before. It was a... what is it called, a whatever I guess: I made the "Free" thing up myself to allow the function to work at the same hotkey with progressing conditions. Sorry for my talk, I have zero knowlegde of the "professional" language and terms Quote CanShowMenu = falseSuccess = false Free = false libs.GlobalEventFlag = false StaminaChange = cfgqst.GetStruggleStaminaChange() Skill = Math.Floor(libs.PlayerRef.GetActorValue("Lockpicking")) MaxVal = zcfg.UnlockThreshold Quote ndun_configquest_scr Property cfgqst Auto Message Property ndun_CaptMsg Auto slaFrameworkScr Property sla Auto sslSystemConfig property Config auto zadlibs Property libs Auto zadConfig Property zcfg Auto Quest Property calmqst Auto Bool CanShowMenu = falseBool Success = false Bool Free = false Int Skill = 0 Int MaxVal = 185 Float StaminaChange = 1.0 the last source file (before I copy paste ur stuff and start playing with MFG ndun_captivequest_qf_scr.psc
Recommended Posts
Archived
This topic is now archived and is closed to further replies.