Using a "Lock" in underwater caves. Script Help plz

Post » Fri Dec 05, 2014 4:27 pm

Hi all.

I have an underwater cave system which I want to work like a Canol Boat Lock. There are tow exits/entrances in this system. Because the caves are under the ocean I've set up a "Lock" using two sliding doors (secret doors) in a small hallway and a length of passage between them. Let's say the player enters the underwater cave from the ocean entrance. Player swims to the external door of the Lock, which is open (passage is filled with water), player now HAS TO close the external door before he/she can activate the pump to drain the water, Once water has drained the external door becomes inactive (can't be opened because there is an ocean outside) and the internal door (which was inactive when passage was full of water), now is active. Player can now leave the drained passage by activating the internal door. When player enters from the internal door entrance the opposite happens - internal door, open or closed, can be used but external door cannot until passage is flooded. In both cases BOTH doors must be closed when pulling the drain/flood passage lever and only the external or internal doors become active, depending if passage is drained or flooded. I hope this is clear.

Can anybody help me script this please? I have a vague idea and am mashing scripts together but my thoughts get lost a lot thinking about all the checks that have to be made.

Thanks.

User avatar
Cody Banks
 
Posts: 3393
Joined: Thu Nov 22, 2007 9:30 am

Post » Sat Dec 06, 2014 1:37 am

Here's a hastily scribbled script:

Spoiler
Scriptname AirlockPump Extends ObjectReferenceObjectReference Property kWaterPlane Auto ;The water plane that is moved up and down to fill/empty the passage with/of waterObjectReference Property kExternalDoor Auto ;The outer doorObjectReference Property kInternalDoor Auto ;The inner doorObjectReference Property kFloodedMarker Auto ;The marker that sets the point where the plane of water should be at when the passage is filled with waterObjectReference Property kEmptiedMarker Auto ;The marker that sets the point where the plane of water should be when the passage is emptied of waterFloat fTranslationSpeed = 2.5 ;The speed at which the plane of water is moved between the two markers (current value is a random value)Bool bFlooded = TrueBool bProcessingInputEvent OnInit()	kWaterPlane.TranslateToRef(kFloodedMarker, fTranslationSpeed)	kInternalDoor.BlockActivation()EndEventEvent OnActivate(ObjectReference akActionRef)	If(!bProcessingInput)		bProcessingInput = True		Self.BlockActivation()		If((kExternalDoor.GetOpenState() == 3) && (kInternalDoor.GetOpenState() == 3))			If(bFlooded)				bFlooded = False				kExternalDoor.BlockActivation()				kWaterPlane.TranslateToRef(kEmptiedMarker, fTranslationSpeed)				;Wait until the passage is empty either by waiting a set time or by checking the position of the water plane				kInternalDoor.BlockActivation(False)			Else				bFlooded = True				kInternalDoor.BlockActivation()				kWaterPlane.TranslateToRef(kFilledMarker, fTranslationSpeed)							;Wait until the passage is filled either by waiting a set time or by checking the position of the water plane				kExternalDoor.BlockActivation(False)			EndIf		EndIf		Self.BlockActivation(False)		bProcessingInput = False	EndIfEndEvent

The script would be attached to (the device controlling) the pump. You will need to, as the comments in the OnActivate event state, figure out an appropriate way of determining when the passage is considered to have been filled or emptied.

User avatar
Miss K
 
Posts: 3458
Joined: Sat Jan 20, 2007 2:33 pm

Post » Sat Dec 06, 2014 12:41 am

Bit rushed now, so I attach it to the lever controlling the pump then?

User avatar
krystal sowten
 
Posts: 3367
Joined: Fri Mar 09, 2007 6:25 pm

Post » Sat Dec 06, 2014 2:42 am

Yes.

User avatar
SHAWNNA-KAY
 
Posts: 3444
Joined: Mon Dec 18, 2006 1:22 pm

Post » Sat Dec 06, 2014 2:36 am

One error my friend.

.psc(32,31): variable kFilledMarker is undefined

User avatar
Felix Walde
 
Posts: 3333
Joined: Sat Jun 02, 2007 4:50 pm

Post » Fri Dec 05, 2014 10:43 pm

Oops. Change it to kFloodedMarker:

kWaterPlane.TranslateToRef(kFloodedMarker, fTranslationSpeed)
User avatar
Leah
 
Posts: 3358
Joined: Wed Nov 01, 2006 3:11 pm

Post » Fri Dec 05, 2014 4:26 pm

Thanks MrJack. Excellent scripting - all works perfect. :tops:

EDIT: Spoke too soon. When pump is activated and water level begins to fall the internal door can be opened immediately before the Lock has drained. Vice=versa when activating the pump to raise the water level the external door can be opened immediately.

User avatar
meghan lock
 
Posts: 3451
Joined: Thu Jan 11, 2007 10:26 pm

Post » Sat Dec 06, 2014 12:31 am

Did you implement some kind of way for the script to wait until the passage has been filled/emptied? The script I posted didn't contain that, but I did place comments where such measures had to be taken (lines 27 and 33 in the original version). Otherwise the script will immediately call BlockActivation(False) on the door, which should be possible to open once the passage has been filled/emptied, and resulting in the problem you are encountering. You could either wait a static amount of time (Utility.Wait(X), where X is a float value) or use a while-loop to check if the water plane is in a certain position or within a certain distance from the marker it is moving towards.

EDIT: Assuming that the translation speed is in CK's length units per second, then you could probably use a function like this:

Float Function GetTranslationTime(ObjectReference akFirst, ObjectReference akSecond, Float afTranslationSpeed)	If((akFirst != None) && (akSecond != None) && (afTranslationSpeed > 0.0))		Float fDistance = akFirst.GetDistance(akSecond)		Return fDistance / afTranslationSpeed	Else		Return 0.0	EndIfEndFunction

Then call Utility.Wait(GetTranslationTime(kWaterPlane, kEmptiedMarker, fTranslationSpeed)) and the same, but with kFloodedMarker as the second parameter. The result would be:

Spoiler
Scriptname AirlockPump Extends ObjectReferenceObjectReference Property kWaterPlane Auto ;The water plane that is moved up and down to fill/empty the passage with/of waterObjectReference Property kExternalDoor Auto ;The outer doorObjectReference Property kInternalDoor Auto ;The inner doorObjectReference Property kFloodedMarker Auto ;The marker that sets the point where the plane of water should be at when the passage is filled with waterObjectReference Property kEmptiedMarker Auto ;The marker that sets the point where the plane of water should be when the passage is emptied of waterFloat fTranslationSpeed = 2.5 ;The speed at which the plane of water is moved between the two markers (current value is a random value)Bool bFlooded = TrueBool bProcessingInputEvent OnInit()	kWaterPlane.TranslateToRef(kFloodedMarker, fTranslationSpeed)	kInternalDoor.BlockActivation()EndEventEvent OnActivate(ObjectReference akActionRef)	If(!bProcessingInput)		bProcessingInput = True		Self.BlockActivation()		If((kExternalDoor.GetOpenState() == 3) && (kInternalDoor.GetOpenState() == 3))			If(bFlooded)				bFlooded = False				kExternalDoor.BlockActivation()				kWaterPlane.TranslateToRef(kEmptiedMarker, fTranslationSpeed)				Utility.Wait(GetTranslationTime(kWaterPlane, kEmptiedMarker, fTranslationSpeed))				kInternalDoor.BlockActivation(False)			Else				bFlooded = True				kInternalDoor.BlockActivation()				kWaterPlane.TranslateToRef(kFloodedMarker, fTranslationSpeed)							Utility.Wait(GetTranslationTime(kWaterPlane, kFloodedMarker, fTranslationSpeed))				kExternalDoor.BlockActivation(False)			EndIf		EndIf		Self.BlockActivation(False)		bProcessingInput = False	EndIfEndEventFloat Function GetTranslationTime(ObjectReference akFirst, ObjectReference akSecond, Float afTranslationSpeed)	If((akFirst != None) && (akSecond != None) && (afTranslationSpeed > 0.0))		Float fDistance = akFirst.GetDistance(akSecond)		Return fDistance / afTranslationSpeed	Else		Return 0.0	EndIfEndFunction 

Using a while-loop to check whether or not the water plane has reached its destination could also be used to make the script wait. There's more than one way to skin a cat.

User avatar
Phillip Hamilton
 
Posts: 3457
Joined: Wed Oct 10, 2007 3:07 pm

Post » Fri Dec 05, 2014 11:41 am

Thanks MrJack all is good now. Can I impose on your scripting skill again please? Let me explain. The scenario I talked about previously works perfect if the player explores the submerged caves from the ocean entrance. There is another way in. Eventually I am going to construct a prison, the ground level construction part is already done, just need to complete the underground section. The player, through quest, will either break himself/herself or himself/herself and a few convict NPCs out of the prison. To escape he/she/they have to fall down a shaft which leads to the submerged cave system but at the opposite end to the ocean entrance. Now in this case the Lock needs to be empty in order for the player to activate the internal door and make good the escape. I am assuming the easiest way to achieve this would be at some point during the escape through the cave system, the player passes through a triggerbox which sets the water plane to its lowest level, therefore allowing the internal door active. Can you help me with this script please? Thank you for previous help, I hope I am not bothering you too much.

User avatar
Nomee
 
Posts: 3382
Joined: Thu May 24, 2007 5:18 pm

Post » Fri Dec 05, 2014 6:28 pm

I think this would work for a trigger volume:

AirlockPump Property Pump Auto ;Fill this with the ObjectReference that you attached the previous script to (modify the AirlockPump type to whatever you might have changed the name to)Auto State Initial	Event OnTriggerEnter(ObjectReference akActionRef)		If(akActionRef == Game.GetPlayer())			(Pump.kWaterPlane).TranslateToRef((Pump.kEmptiedMarker), (Pump.fTranslationSpeed))			(Pump.kExternalDoor).BlockActivation()			(Pump.kInternalDoor).BlockActivation(False)			GoToState(Triggered)		EndIf	EndEvent	EndStateState Triggered	Event OnTriggerEnter(ObjectReference akActionRef)	EndEventEndState 

If you want to use a quest stage, then you would basically add the property to the script fragment and then just use the three lines inside the if-block.

EDIT: Just noticed that fTranslationSpeed isn't a property in the earlier script. Might want to change that or this new script won't be able to access it like it is now. So change the following line in the first script from:

Float fTranslationSpeed = X.Y

to

Float Property fTranslationSpeed = X.Y Auto

Replace X.Y with whatever value you've found to be ideal in your situation.

Alternatively replace Pump.fTranslationSpeed in the second script with a static speed.

EDIT2: Forgot to make the trigger inert after it was triggered for the first time. Updated the script in this post.

User avatar
Paula Rose
 
Posts: 3305
Joined: Fri Feb 16, 2007 8:12 am

Post » Fri Dec 05, 2014 11:25 pm

Two errors compiling the amended script. They are...

psc(8,35): no viable alternative at input 'X'

psc(8,149): mismatched input '\\n' expecting STATE

User avatar
Sabrina Steige
 
Posts: 3396
Joined: Mon Aug 20, 2007 9:51 pm

Post » Sat Dec 06, 2014 1:37 am

Sounds like you left "X.Y" as the value for fTranslationSpeed. Since fTranslationSpeed is now (or should be) a property, you can omit the " = X.Y" from the property declaration and just give it a value like you would for any other property.

If that doesn't fix it, then could you post the script in its current state?

User avatar
Emerald Dreams
 
Posts: 3376
Joined: Sun Jan 07, 2007 2:52 pm


Return to V - Skyrim