Nexussfire Posted January 21, 2023 Posted January 21, 2023 I have tried to wrap my head around making a papyrus script to move a actor (player or NPC) behind a chair when they exit it so not as to get stuck against a table that is in front of it. I've tried GetPosition, GetAngle, SetPosition & SetAngle but can't seem to grasp how to grab the enter / exit event. I thought to track GetSitting of the ActorReference to then SetPosition when that state is registered as "standing", but nothing I have poorly conjured has compiled. Scriptname ExitChairBehind extends ObjectReference Event OnActivate(ObjectReference akActionRef) ;Get the Actor who activated Actor akActivator = akActionRef.GetActorReference() ;Get Rotation of the furniture Float fObjectAngle = GetAngle() ;Get Current XYZ pos of Furniture Float fObjectPos = GetPosition() ;Get Activated Actor Sitting State ActorID.GetSitting() endEvent Event OnActivate(Objectreference akActionRef) If GetSitting = 0 AkActor SetPosition(-1, -1, -1) ;SetPosition should be relative to the furniture position, and opposite its current Z rotation to X or Y Position. EndEvent This isn't a completed script as I've tried to scrub out stuff that was just not correct. I realize this is very complicated for someone who isn't good at coding. So any help would be appreciated, or if someone can write this, even better. I am frustrated at this point.
Seijin8 Posted January 21, 2023 Posted January 21, 2023 (edited) 53 minutes ago, Nexussfire said: I have tried to wrap my head around making a papyrus script to move a actor (player or NPC) behind a chair when they exit it so not as to get stuck against a table that is in front of it. I've tried GetPosition, GetAngle, SetPosition & SetAngle but can't seem to grasp how to grab the enter / exit event. I thought to track GetSitting of the ActorReference to then SetPosition when that state is registered as "standing", but nothing I have poorly conjured has compiled. Scriptname ExitChairBehind extends ObjectReference Event OnActivate(ObjectReference akActionRef) ;Get the Actor who activated Actor akActivator = akActionRef.GetActorReference() ;Get Rotation of the furniture Float fObjectAngle = GetAngle() ;Get Current XYZ pos of Furniture Float fObjectPos = GetPosition() ;Get Activated Actor Sitting State ActorID.GetSitting() endEvent Event OnActivate(Objectreference akActionRef) If GetSitting = 0 AkActor SetPosition(-1, -1, -1) ;SetPosition should be relative to the furniture position, and opposite its current Z rotation to X or Y Position. EndEvent This isn't a completed script as I've tried to scrub out stuff that was just not correct. I realize this is very complicated for someone who isn't good at coding. So any help would be appreciated, or if someone can write this, even better. I am frustrated at this point. Problem: Actor gets stuck in front of chair when standing. Solution 1) Use the correct kind of chair for the area. Chairs have up to three approach/exit positions (left, right, front). Behind is not one of them. Sounds like a "front" type chair is being used where a left/right chair would be needed instead. Look at the chair names in CK or xEdit and you'll see "Chair01L" meaning left-side entry/exit, "Chair01R", etc. If it has no letter, it is usually using all three approaches. Replacing this chair with one that has the correct approach angles (and doesn't have front) may fix the issue. Solution 2) Re-navmesh the area or tweak the table position. Assuming the chair isn't the problem then in general the AI can find its own way around (may teleport if it can't) if the area is set up right. That you are having this issue is a sign that the area itself is messed up in relation to the furniture. "Solution?" 3) Create a script-based (potentially performance-reducing) "band-aid" to fix something better solved with a non-scripted solution. Given that I don't think its a great solution, I'm only going to point out some of the issues with the script: - Two OnActivate() Events likely won't trigger correctly. - "If GetSitting" should be == 0 and would need to be called on the actor, not the furniture/objectreference. - If the fObjectAngle etc need to be called by a separate function/event, they need to be initially defined outside of it, so put "float fObjectAngle" etc under the scriptname section and feed their values from the event. - GetPosition() needs to be linked to something to work, so "self.Getposition()" should return the position of whatever objectreference the script gets attached to. tl;dr/Conclusion: Don't script this. The issue is the chair. Or the navmesh. Or both. Edited January 21, 2023 by Seijin8
Nexussfire Posted January 21, 2023 Author Posted January 21, 2023 (edited) One side has the chairs fairly close to the table in this example screenshot. They are custom chairs, I've changed the entry flags to Left / Right. The issue is with that is the exit does not happen at all, but rather just makes the exiting actor (player at the moment) just stand on the chair. Front before would exit correctly, however even with a LOT of unnatural space between chair & table it'd be easy to be stuck between them. This is fairly specific use case. A simple solution to what I want is to place X markers for each chair and then move actors to them when they get up. Which requires scripting. I know benches are usually used for this kind of arrangement in the game but that's not really the aesthetic I want here, and why I am asking for help on scripting. If its really not possible via script then I will forgo the chairs I guess. Edited January 21, 2023 by Nexussfire
Seijin8 Posted January 21, 2023 Posted January 21, 2023 (edited) 22 minutes ago, Nexussfire said: One side has the chairs fairly close to the table in this example screenshot. They are custom chairs, I've changed the entry flags to Left / Right. The issue is with that is the exit does not happen at all, but rather just makes the exiting actor (player at the moment) just stand on the chair. Front before would exit correctly, however even with a LOT of unnatural space between chair & table it'd be easy to be stuck between them. This is fairly specific use case. A simple solution to what I want is to place X markers for each chair and then move actors to them when they get up. Which requires scripting. I know benches are usually used for this kind of arrangement in the game but that's not really the aesthetic I want here, and why I am asking for help on scripting. If its really not possible via script then I will forgo the chairs I guess. Fair enough on the setup. IRL the chairs get moved. In game, that really isn't a thing. One solution is to use the bench entry animation for the middle chairs (look like the rest can be accessed normally from the sides) and ignore the actor clipping through it. I dunno if that is more or less realistic than chairs that are indestructibly linked to the spacetime continuum or not. Seeing what you're shooting for, adding a linkedref XMarker to the chair simplifies the scripting, but honestly if you're going to script things anyway... 1) Start with the middle chairs turned sideways, say using only a right entry. 2) Make a triggerbox around the chair with a script that watches for NPCs entering and then checks periodically if they are sitting down. 3) Once the actor finishes the sitting animation, rotate the chair 90° to face the table -- I don't know if the actor will automatically turn with the chair. If not, maybe either manually rotate them too or use actor.moveto(Chair) to reset them on the moved chair. May need to experiment with this. 4) Triggerbox now looks to see if the actor is getting up (should still try to exit sideways) 5) If the actor is moving, turn the chair -90° to original position and do the same trick again if they are getting stuck. They should now have a way to exit smoothly without hitting the table or getting stuck. Keep in mind "actor.moveto(furniture)" results in them "using" the furniture. If used on a bed they go right to the laying part of the animation, skipping the enter animation. Same with chairs. Edited January 21, 2023 by Seijin8
Nexussfire Posted January 21, 2023 Author Posted January 21, 2023 (edited) Quote -- I don't know if the actor will automatically turn with the chair. If not, maybe either manually rotate them too or use actor.moveto(Chair) to reset them on the moved chair. May need to experiment with this. For rotating the actor sitting I believe there is ; Look 90 degrees to the left Game.SetSittingRotation(-90.0) I haven't the slightest clue how to do any of that, however. My understanding of writing correct Papyrus is primitive. I get what the functions are for the most part but putting it all together right isn't something I am doing. Seems like more work to rotate the chairs in place? I was trying to figure out what the listen event is for furniture being used is. It is a marker that creates a animated idle state so I thought it'd be easiest to get the exit event from the marker, wait a few seconds for the anim to play and then just teleport actor to Xmarker reference via Script Property that lets me pick which marker to move them to. There is IsFurnitureMarkerInUse Example ; Is the first marker on the bed in use (or someone has reserved it)? if Bed.IsFurnitureMarkerInUse(0) Debug.Trace("Bed marker 0 is being used") endIf Though I am not certain on how to call on this without having the chairs constantly script ticking away to see if anything has used them recently, which from what I've read would be a rather dirty script. Also I have been searching for the relevant syntax on this page : https://www.creationkit.com/index.php?title=List_of_Papyrus_Functions Edited January 21, 2023 by Nexussfire
Seijin8 Posted January 21, 2023 Posted January 21, 2023 (edited) 5 hours ago, Nexussfire said: For rotating the actor sitting I believe there is ; Look 90 degrees to the left Game.SetSittingRotation(-90.0) I haven't the slightest clue how to do any of that, however. My understanding of writing correct Papyrus is primitive. I get what the functions are for the most part but putting it all together right isn't something I am doing. Seems like more work to rotate the chairs in place? I was trying to figure out what the listen event is for furniture being used is. It is a marker that creates a animated idle state so I thought it'd be easiest to get the exit event from the marker, wait a few seconds for the anim to play and then just teleport actor to Xmarker reference via Script Property that lets me pick which marker to move them to. There is IsFurnitureMarkerInUse Example ; Is the first marker on the bed in use (or someone has reserved it)? if Bed.IsFurnitureMarkerInUse(0) Debug.Trace("Bed marker 0 is being used") endIf Though I am not certain on how to call on this without having the chairs constantly script ticking away to see if anything has used them recently, which from what I've read would be a rather dirty script. Also I have been searching for the relevant syntax on this page : https://www.creationkit.com/index.php?title=List_of_Papyrus_Functions Okay, keeping in mind I just woke up and haven't had my full measure of caffeine yet... the general papyrus for it would be something like this: Scriptname ChairRotationScript extends ObjectReference ;attach this to a triggerbox ObjectReference property ChairToRot auto ; the chair Actor aSitting ; whoever comes into the triggerbox bool bRot = false ; whether or not the chair has been rotated float fT = 1.5 ; arbitrary time (in seconds) for script cycles, easier to adjust here than everywhere float fRot = 500.0 ; catches original rotation amount, this nonsense value is a stand-in saying it hasn't been set yet ; could also just feed this manually float fWind ; the angleZ we want the chair to rotate to Event OnTriggerEnter(ObjectReference TriggerRef) aSitting = TriggerRef as Actor If aSitting If fRot != 500.0 fRot = ChairToRot.GetAngleZ() fWind = (fRot - 90.0) If fWind < 0.0 fWind += 360.0 ; should make sure the values are between 0 and 359.999 EndIf EndIf RegisterForSingleUpdate(fT) EndIf EndEvent Event OnTriggerLeave(ObjectReference TriggerRef) If aSitting == TriggerRef UnregisterForUpdate() If bRot Rotchair(false, false) EndIf EndIf EndEvent Event OnUpdate() If bRot ; already rotated If aSitting.GetSitState() != 3 ; no longer sitting RotChair(false) EndIf Else ; not rotated If aSitting.GetSitState() == 3 ; is sitting RotChair(true) EndIf EndIf RegisterForSingleUpdate(fT) EndEvent Function RotChair(bool bWindLeft, bool bMoveActor = true) If bWindLeft If ChairToRot.GetAngleZ() == fRot ChairToRot.SetAngle(0.0, 0.0, fWind) ;If in testing, the actor automatically moves to the chair's new rotation, this can be deleted Utility.Wait(0.5) aSitting.MoveTo(ChairToRot) ;end deletion segment EndIf bRot = true Else If ChairToRot.GetAngleZ() == (fWind) ChairToRot.SetAngle(0.0, 0.0, fWind) ;If in testing, the actor automatically moves to the chair's new rotation, this can be deleted If bMoveActor Utility.Wait(0.5) aSitting.MoveTo(ChairToRot) EndIf ;end deletion segment EndIf bRot = false EndIf EndFunction This will need extensive testing of course. No doubt there's a simpler way to do this, too. EDIT: My code sucks... Edited January 21, 2023 by Seijin8
Nexussfire Posted January 21, 2023 Author Posted January 21, 2023 (edited) 55 minutes ago, Seijin8 said: Okay, keeping in mind I just woke up and haven't had my full measure of caffeine yet... the general papyrus for it would be something like this: Scriptname ChairRotationScript extends ObjectReference ;attach this to a triggerbox ObjectReference property ChairToRot auto ; the chair Actor aSitting ; whoever comes into the triggerbox bool bRot = false ; whether or not the chair has been rotated float fT = 1.5 ; arbitrary time (in seconds) for script cycles, easier to adjust here than everywhere float fRot = 500.0 ; catches original rotation amount, this nonsense value is a stand-in saying it hasn't been set yet ; could also just feed this manually float fWind ; the angleZ we want the chair to rotate to Event OnTriggerEnter(ObjectReference TriggerRef) aSitting = TriggerRef as Actor If aSitting If fRot != 500.0 fRot = ChairToRot.GetAngleZ() fWind = (fRot - 90.0) If fWind < 0.0 fWind += 360.0 ; should make sure the values are between 0 and 359.999 EndIf EndIf RegisterForSingleUpdate(fT) EndIf EndEvent Event OnTriggerLeave(ObjectReference TriggerRef) If aSitting == TriggerRef UnregisterForUpdate() If bRot Rotchair(false, false) EndIf EndIf EndEvent Event OnUpdate() If bRot ; already rotated If aSitting.GetSitState() != 3 ; no longer sitting RotChair(false) EndIf Else ; not rotated If aSitting.GetSitState() == 3 ; is sitting RotChair(true) EndIf EndIf RegisterForSingleUpdate(fT) EndEvent Function RotChair(bool bWindLeft, bool bMoveActor = true) If bWindLeft If ChairToRot.GetAngleZ() == fRot ChairToRot.SetAngle(0.0, 0.0, fWind) ;If in testing, the actor automatically moves to the chair's new rotation, this can be deleted Utility.Wait(0.5) aSitting.MoveTo(ChairToRot) ;end deletion segment EndIf bRot = true Else If ChairToRot.GetAngleZ() == (fWind) ChairToRot.SetAngle(0.0, 0.0, fWind) ;If in testing, the actor automatically moves to the chair's new rotation, this can be deleted If bMoveActor Utility.Wait(0.5) aSitting.MoveTo(ChairToRot) EndIf ;end deletion segment EndIf bRot = false EndIf EndFunction This will need extensive testing of course. No doubt there's a simpler way to do this, too. EDIT: My code sucks... Well your code compiles which is more than mine does so not really. However I do not see anything happening as intended when said compiled script is applied to a triggerbox and linking the relative chair in script properties. The character sometimes is facing to the left or the right more after a few stumbles out of it, but the chair itself never moves / rotates. And the exit still just boots the character to standing on top of the chair. This is such a over-complicated process. What I think will need to happen is I will need to attach the chairs to a RotateHelper (Specifically : DLC2DunFahlbtharzRotateHelper90CW) Which will force move any static object attached to it like an animated object. I have no idea what will happen doing this to a furniture object, may do nothing... or the game might have an aneurysm. But I would still need a script with an event that paused the animation to get into the chair, rotate it 90*, then play the anim to sit, then play the rotatehelper to "close" again from open. Thank you for providing some help, I appreciate it. Edit: The exit animation from left or right seems to be related to the furniture marker I used for the custom chairs and the arms of the chair being in the way. Not much of a fix. So it is Front Anim only that works correctly. I may forgo the chairs and just put a bench down. Edited January 21, 2023 by Nexussfire
Seijin8 Posted January 21, 2023 Posted January 21, 2023 20 minutes ago, Nexussfire said: I may forgo the chairs and just put a bench down. Yeah, a lot of modding for me turns into that. Amount of work needed to get effect is vastly over what I'm trying to fix. Generally settle for a less than optimal solution and stew on it over time until something better pops into mind or I forget about it.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now