Swimmable Water
From FleshWorks
by Rantako
Contents |
Intro
This tutorial will show you how to create swimmable water in T3ed. Since T3’s Flesh engine does not support actual water, this is really just a scripted set up to simulate water as closely as possible – in fact, it consists mainly of invisible elevators. The tutorial will take you through the complete process of making pools, setting up a limited air supply, and expanding the underwater area.
Part 1: A Simple Pool
Note: for this to work, many volumes have to be positioned exactly in the right place. You can measure distances easily using the builder brush.
Firstly we will make a simple square pool. Open T3ed and make a large room of any size you want, and texture it however you like. In the floor of this room subtract a brush 24 ft wide by 24 ft long (384 x 384 uu), which you can make as deep as you like (preferably more than 20 ft).
Now open the Actor Class Browser and place a WorldObj -> Moving -> Elevator -> MUSFloorPanelElevator in your map. This actor is 24 ft x 24 ft, which is why we made the pool that size. In order to make the elevator invisible, you need to reskin it. In the matlib T3_Characters is a texture called ‘BF’. This is a special texture because the game does not render it, making anything which uses it invisible. Select your elevator, select this texture, then Alt-LeftClick the elevator. The texture will be pasted onto the elevator mesh. Make sure all the surfaces have been textured, then RightClick the elevator, select Static Mesh -> Add Skin. Type something obvious like Transparent in the box, and click OK. This saves the skin so you can use it again. If you switch to FleshRenderer mode, the elevator should be completely invisible.
Next we need to change some of the elevator’s properties. Add the properties:
- Elevator -> ElevatorCrushStim -> Amount: 0, StimulusType_None
- Physics -> ElevatorController -> ElevatorSpeed: 50
- Render -> CastShadows: ShadowCasting_False
- Scripts -> bEnableScriptInherit: False
Then add the property Scripts -> TriggerScripts. You will see that the elevator has two scripts already – delete them both – we don’t want it to make a noise when it moves. The elevator itself is now finished.
Next create a volume 24 ft wide by 24 ft deep by 5 ft high. Make a RigidAttachment link from the elevator to the volume, and in the link’s properties set Offset -> m_translationOffset -> Z: 30. When you move the elevator, the volume will jump into place with it. This volume will be used to control the motion of the elevator.
Move the elevator into position within your pool. Lower it down so that it is at the very bottom of the pool, then RightClick it, and select Drop Waypoint Marker. Then move the elevator up so that the top of it is exactly 7 ft below the top of the pool. Drop another waypoint marker. Create an ElevatorFloorMarker link from the volume to the WaypointMarker at the bottom of the pool, and call it Down (see LinkFilters if you don’t know how to do this). Create an ElevatorFloorMarker link from the volume to the WaypointMarker at the top of the pool, and call it Up.
It’s now time for our first two Trigger Scripts (out of 22 you will have by the end). Create two scripts:
Add these two scripts to the volume. If you test your map now (making sure the elevator is at the top marker to begin with), when you step onto the elevator you breach the volume, making it sink to the bottom of the pool. When you jump, you exit the volume, making it rise up. To ‘swim’ upwards, you just have to jump repeatedly. This is the ‘swimming’ mechanism effectively finished.
Part 2: Environmental Effects
However, your pool at this point does not look (or sound) anything like water – it’s just an invisible elevator. To remedy that requires a few more volumes and some more scripts. Underwater vision has its own tutorial here, but for the sake of tidy scripting we are going to combine the scripts for this with some of the parts needed for breath (the rest of which will be dealt with later).
Firstly open the Static Mesh Browser and place the mesh Nature -> WATtile512x512 with the skin WaterSheetA02. Position this so that it covers your pool and is 2 ft (32 uu) below the top of the pool. You might notice that it is only textured on one side in Flesh Render mode, so duplicate it and flip the new mesh upside down, then line it up with the existing one. This will form the visible surface of the water.
Next you need to create some Global Variables (they will be used for breath later, but will be combined with these scripts). Open the Flags window by selecting View -> Global Variables -> Flags, and create a new flag called Water_Underwater. Then open the Ints window by selecting View -> Global variables -> Ints and create a new int called Water_BreathCounter with a ‘Max’ value of 30, a ‘Min’ value of 0, and an ‘Expire On Mission’ value of -1.
We want a looping schema to play while underwater, but because T3 does not have such a sound, you can either use one of the existing sounds (such as pipelp) as an alternative, or you can create a new schema of your own (I converted the underwater sound from T2 and made a schema called Underwater1 (which I have used in the scripts below – if the schema you want to use has a different name, replace ‘Underwater1’ as appropriate)). This sound will be activated and deactivated by scripts.
Now create two more Trigger Scripts:
Create a volume the same width and length as your pool (it can be any height) and position it so that its top is 3.5 ft (56 uu) below the top of the pool. Give this volume the scripts WaterVisionEnter1, Breath1EnterWater, and ForceFirstPerson (this script already exists and can be found under ‘CameraFunctions’). Thus when you enter this volume the environmental effects will be activated, and the all-important flag Water_Underwater (used for breath) is set to True.
Create another script:
Set [Water_BreathCounter] to [0]
Set flag [Water_Underwater] to [FALSE] expires on map change [FALSE] expires on mission [-1]
Stop playing 2D sound from [Underwater1]
Set [BaseFOV] to [85.00] on linked objects of [PLAYER]
Change level fog range settings to Start: [0.00], End: [0.00], over [0.01] seconds
Deactivate screen tinting
Send a camera command [unlockmode]
Reset script conditions and actions
Finally, create a volume 24 ft x 24 ft by 10 ft high and align the bottom of it with the top of the volume you created previously. Add the script WaterVisionBreathExit1 to the new volume.
All your water’s environmental effects will now work. When you enter the pool they will activate, and when you exit the pool they will deactivate. (Note: the action ‘Deactivate screen tinting’ does not always fire properly, meaning you may be left with a blue tint after exiting the water. To fix this you simply need to go back into the water and leave it again.)
Part 3: Breath
However, at the moment you can stay underwater for as long as you want; Garrett’s air supply never runs out. To remedy this we must first create 3 new scripts:
These scripts will continue to loop and add 1 to ‘Water_BreathCounter’ every second, but will only do so if the player is still underwater.
The player will be able to stay underwater for thirty seconds before taking damage (the same as in T1/2). To set this up you need to make another 3 scripts:
These scripts will loop, once started, until the player leaves the water or is killed.
However, you currently have no way of knowing how much air you have left! Due to limitations in the game’s non-blocking text system (how text is displayed when you read a plaque, for example), to create a visible counter we will make T3 display the number of seconds of air you have left by adding the corresponding number of a special object to the player’s inventory.
Open the Actor Class Browser and create a new archetype under WorldObj -> InventoryObject -> PowerUp -> Potion called WaterBreathCounter (this will give it most of the properties we want by default). Give it the property Inventory -> InvName: <string=t_Blackjack> (actually it doesn’t matter what you use here, because the player will never see it. It needs to have something, or else it won’t work properly). Give it the property Inventory -> MaxInventoryStack: 150. Then give it the property Render -> ObjectMesh. You can set this property to whatever you want; it will be the ‘image’ the player sees along with the number of seconds of air. I used the mesh GENdoor4x8A with a custom bubbles texture. Save the gamesys.
Now for 7 more scripts:
To make these scripts work, we need to add them to something. Place three InvisibleMarkers anywhere in your map (these can be found under Marker -> Keypoint -> InvisibleMarker). To the first one add the scripts Breath1Count, Breath1Count2 and Breath1Damage1. To the second one add the scripts Breath1BeginDamage, Breath1Damage2 and Breath1Count1. To the third marker add the scripts Breath1Display05, Breath1Display10, Breath1Display15, Breath1Display20, Breath1Display25, Breath1Display30 and Breath1ClearCounters.
You only need to do this once per map; these three markers will control breath for all the pools in the map.
There is a reason for using three markers – if scripts which receive trigger messages are on the same actor as the script which sent the message, the scripts sometimes don’t work properly.
And that’s it. Save everything, build all, and go into the game. If everything has worked, you will now have a fully working pool complete with environmental effects and a limited air supply!
Part 4: Complex Water – More Pools and Joining Them Together
One square pool isn’t very exciting, and won’t be much of a challenge for a skilled swimmer like Garrett. In this part of the tutorial we will make another pool and connect it to the first by an underwater tunnel. We will be using teleport destinations to ensure that wherever you enter a pool from (the surface or the tunnel) an elevator will always be waiting there for you.
To make another pool you can work through the first two parts of the tutorial again, or simply select and duplicate your existing one. Before going any further you should go into the game and check that the new pool does work properly.
Note: to line things up precisely we will be entering coordinates. You can see and edit an actor’s XYZ coordinates by looking under its Movement -> Location property.
First of all make a tunnel between your two pools. This can simply be a rectangular brush, and make it high enough to stand up in (8 ft or higher is good). This tunnel should be completely underwater.
We will set up everything for the first pool first, then repeat it for the second. It is important for scripting purposes that you know which pool is Pool 1 and which is Pool 2 – if they get muddled up at some point things will go seriously wrong!
Place a PlayerStart in your map and give it the property Teleport -> TeleportDestName: Water1Top. Using coordinates, position it directly below the WaypointMarker at the top of Pool 1 (same X and Y coordinates as the Marker, and 44 less Z coordinates – this seems to be a good position for it).
Create a volume 30 ft x 30 ft x 10 ft high and position it so that it completely encloses the top of the pool (so that you cannot enter the pool without going through the volume.) Create a TriggerScript link from the volume to the elevator, and create an ElevatorFloorMarker link to the WaypointMarker at the top of Pool 1.
Now create the following script:
Give this script to the volume you just created.
We then need to set up the same thing for the tunnel opening. Move the elevator down so the top of it is aligned with the bottom of the tunnel and drop another WaypointMarker. Place a PlayerStart and give it the TeleportDestName Water1Mid1. Position it below your new marker as you did with the top one. Then create a volume in the tunnel so that the player will always pass through it when they leave the tunnel into the pool. Create a TriggerScript link from the volume to the elevator, and an ElevatorFloorMarker link from the volume to the new WaypointMarker. Then create this script:
and give it to the volume. Pool 1 should now work perfectly so that wherever you enter the pool from, the elevator will be waiting for you.
To set up Pool 2, just do exactly the same, but replace everything that says Water1 (in the scripts and the PlayerStarts) with Water2. Remember that every entrance to the pool needs its own volume, WaypointMarker, PlayerStart with a unique name, and its own unique script using that teleport name. If all has gone correctly, you should now have two fully working interconnected pools of water.
Back to Mission Design: Environmental
