Multi-stop elevators: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
m (Setting bug notice hidetested=1 param on page where the bug might not need tested in param specified)
 
(22 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{cleanup}}
{{pov}}
Multi-stop elevators can be used in maps to allow players to move freely between three or more floors without having to cycle all the way through every floor.


Multi-stop elevators can be used in single-player maps to allow the player to move freely between three or more floors without having to cycle all the way through every floor, as happens with [[wiseElevators|this tutorial's elevator]].
{{warning|This will be a long tutorial, as creating a multi-stop elevator is a long process. Before you decide to make a fully controllable, multi-story elevator, be sure that you need it!}}


{{warning|This will be a long tutorial, as creating a multi-stop elevator is a long process. Before you decide to make a fully controllable, multi-story elevator, be sure that you need it! I will eventually upload a working example map file, but as the original elevator is part of a university project I do not want to upload that (it's also an eleven-story elevator, which is far more than most people will ever need to create).}}
{{note|It is advised to use the same entity names as used in this tutorial to minimize confusion.}}


== Construction ==
== Brush Work ==
=== Architecture ===
Start by opening up Hammer and creating a new map, then save your map. Call the map whatever you want, but remember the name of the file. I'm going to use the example name of "<code>ni_elev_demo.vmf</code>".


Construct your elevator the way you want it to look. This tutorial assumes you want a realistic, fully-enclosed elevator with opening and closing doors, so that is what I will build (''see Fig. 1'').
=== Making the Elevator ===
[[File:1_Elevator_Properties.png|thumb|200px|right|Figure 1 - The func_tracktrain properties box.]]


[[Image:NiElevDemoStep1.JPG|thumb|200px|right|Fig. 1 - Note that I haven't cut a hole for the doors yet. That will come later.]]
We start off by making the elevator. You want to make the walls as tall as the space in between your level's floor and ceiling, in my case 128 units. Make the elevator floor and ceiling as thick as your level's floor and ceiling. Make sure the elevator floor is flush with the floor of your level. Cut out a hole for the doors. I have made the front wall 1 unit thinner so the doors can go in and wont clip through the wall. After that is done, pick a texture of your choice and texture only the inside. Leave the rest nodraw, unless someone can get inside your elevator shaft or see outside of your elevator.


Now that you've got your box (for that's all it is at this point), you need to determine how big your doors will be. I'm going to make mine 32 inches wide each, for a total door width of 64 inches. The doors will be 112 inches tall.
Now select all the elevator brushes and tie them to a [[func_tracktrain]]. Refer to ''Figure 1'' for the properties. You can set the sounds and speed to whatever you like. For the flags, check only <code>No User Control</code>, <code>Fixed Orientation</code>, & <code>Is unblockable by player</code>. Then move the origin (the little blue ball) to the X (in the 2D view) of the floor of the elevator (''Figure 2'').


Make your doors 2 inches thick (assuming the walls of your elevator are 8 inches thick, like mine) and arrange them in a staggered pattern (''see Fig. 2'').
[[File:2_3D_Helper.png|thumb|200px|right|Figure 2 - Location of the blue ball.]]


[[Image:NiElevDemoStep2.PNG|thumb|200px|right|Fig. 2 - Top view of staggered doors.]]
[[File:3_Elevator.png|thumb|200px|right|Figure 3 - The appearance of the elevator.]]


Don't put them inside the elevator's wall yet. Cut a hole in the wall big enough for your doors, and place them so that they are centered between the two faces of the cut wall.
=== Making the Shaft ===


These doors will be parented to the elevator later. For now, select them individually and tie them to [[func_door]] entities. Leave them alone for now, we'll get back to them later.
Now you will want to make a shaft that encloses the elevator and goes all the way up to the first floor. It's really just 3 tall brushes and then a floor and ceiling. Make sure that you have door holes cut out that are the same size as the elevator's door hole. You want to keep the entire shaft nodraw unless someone can somehow see it.


=== Creating the lift entities ===
=== Making the Doors ===


Select your elevator's walls, ceiling and floor. Tie it all to a [[func_tracktrain]] entity. I've named mine "ni_elev" but you can name yours whatever you wish. Place the doors in their proper location inside the door frame you've cut into your elevator. If you've done the same as me, you can use my numbers for the door settings, but if you haven't, the idea is to get the first door (topmost in the "step 2" view) to have one inch sticking out when it is fully open (the "lip" should be 1 regardless of your door size) and for the second door to stick out one inch farther (so your lip should be [(individual door width) - 2] * [-1], or -30, if you're following my dimensions.
First we will make doors for the actual elevator. Just make 2 brushes that fit into the door hole you have cut out. I have mine 2 units thick, 112 units tall, and 32 units wide each. You can texture the doors with anything you like, but I recommend <code>metal/offelevdrsa</code>. It may take a while adjusting the texture so it fits with the door. Now tie each door to a [[func_door]]. Refer to ''Figure 4'' for the properties. Be sure to name both doors the same name and parent them to the elevator. You also might need to change move direction. Again, you can change the sounds and speed to whatever you like. Now go to the flags and uncheck <code>Touch Opens</code>.


In my map, you can see that the doors will be moving "North" in the x/y view, so I've set their <code>movedir</code> (Move Direction) to "0 90 0". You can use the compass for this. The northernmost door has a lip of 1, while the southernmost door has a lip of -30. Set the door <code>movespeed</code>  keys so that their ratio is equal to the ratio of their movement amounts. For example, in my demo my north door is moving only 31 units (width - lip), while my south door is moving 62 units (again, width - lip). This gives a ratio of 1:2, north:south. Thus, I've set the north door speed to 31 and the south door speed to 62 (''see Fig. 3''). I know this is the easiest ratio, but elevator doors move pretty slowly and this means it will take one second from start to finish, which is slow enough. Check the "Toggle" spawnflag box, and uncheck the "Touch Opens" spawnflag box. This will make the elevator doors open and close only when we want them to (when told to by the elevator).
[[File:4_Door_Properties.png|thumb|200px|right|Figure 4 - The elevator door properties box.]]


[[Image:NiElevDemoStep3.PNG|thumb|200px|right|Fig. 3 - Object Properties window for south door.]]
Next we will make doors for each floor. You can simply copy the doors you made for the elevator and paste them to match with the door hole you made when building the shaft. The only difference is that for each floor they have to be named something different. For example for the first floor I used "elev_doors_1" and for the second floor "elev_doors_2", while for the elevator doors I used "elev_doors". Keep in mind both doors have to be named the same thing. The name only changes for different floors.


Give both doors the same <code>targetname</code>. In my case, they're named "ni_elev_doors" as you can see in the above image. Parent them to the elevator ("ni_elev" in my case) and let them be. The parented doors, for the most part, are done.
== Entity Work ==


Now what's an elevator without any floors to travel to? If you said a box, you're right! Create a tube that exactly fits around your elevator (mine is a square tube made of concrete, but yours could be any size as long as it fits your elevator snugly). It's a good idea to make the walls of the tube 8 inches thick, as well. Cap the tube at both ends (no leaks here!) without overlapping your elevator. Cut holes (arbitrarily if you wish) that are equal to the size of your combination doors at the places they would be to access your floors. I've made five holes (therefore five floors) separated by arbitrary distances which are not equal. Build up a floor around each one, and assign all the walls except the tube to a visgroup called "ExtWalls" for "exterior walls". Hide "ExtWalls" (''see Fig. 4'').
=== Making the Path ===


[[Image:NiElevDemoStep4.JPG|thumb|200px|right|Fig. 4: ''Your map should look something like this after hiding "ExtWalls".'']]
We begin our work with the entities by making a [[path_track]]. Line this <code>path_track</code> up with the center X of the floor, just like with the blue ball. Then name it something like "elev_stop_1" (''Figure 5''). Set the <code>Orientation Type</code> to <code>No change</code>. Now copy this path_track and paste it, lining it up with the x in the second floor. Do this for all your floors, making sure to change the name for each <code>path_track</code> to correspond with its floor.


Now, the fun part begins. Clone (select, then drag while holding <code>Shift</code>) your elevator doors into the opening of the first floor door. Mirror them (so that the south doors are close together and the north doors are farther apart) using <code>Ctrl-L</code> (if you're following my demo). Rename them so that you can tell they're the first-floor doors (I used "ni_elev_doors_1"). When you've done that, and removed the "Parent" information from them, clone them into each of the other door frames, renaming them appropriately (e.g. "ni_elev_doors_2", "ni_elev_doors_3", and so on).
[[File:5_Path_track_Lineup2.png|thumb|200px|right|Figure 5 - How to place the path_tracks.]]


Select the elevator. It should have an <code>origin</code> point somewhere near (or exactly in) the middle. Drag it down to the center of the elevator floor, so that the blue ball representing the origin appears half-buried in the floor of the elevator. In math terms, the origin point should be on the plane that contains the topmost horizontal surface of the elevator's floor.
Now go back to your first <code>path_track</code> and set its <code>Next Stop Target</code> to "elev_stop_2", or your second floor's <code>path_track</code>. Do this for all your floors except the top floor. Once you've finished that, go to your top floor's <code>path track</code> and set its <code>Branch Path</code> to the <code>path_track</code> below it (elev_stop 3). Do this for all your <code>path_tracks</code> except for the first one (elev_stop_1). Once you've done all this your shaft should look something like ''Figure 6''.


{{Note|If you do not have the blue ball indicator, you can view copy the origins from the elevator and input them in View > Go to Coordinates. Alternatively, you can pretend to create a box brush, starting from the centre of the map and dragging it to the same x y z coordinates provided}}
{{bug|hidetested=1|It appears as though for some levels the elevator doesn't line up with the floor. I don't know why this is cause because I have all possible properties set to a value that makes sure the elevator wont move out of its origin.}}


=== Path creation and implementation ===
[[File:6_Shaft.png|thumb|200px|right|Figure 6 - The appearance of the elevator shaft.]]
Now, create a [[path_track]] entity centered below the elevator's origin (or at the same point as the origin) that is on the same x/y plane as the topmost surface of the first floor brush (''see Fig. 5b''). Name this <code>path_track</code> whatever you wish, but follow it up with a "_1". For example, mine is called "ni_elev_stop_1".


Now, with your first <code>path_track</code> made, clone the <code>path_track</code> to the same place relative to the other floors' brushes (''see Fig. 5a''). In short, this means that each <code>path_track</code> should be level with the walking surface of each floor, and on a vertical line which intercepts the elevator's origin point. Set your elevator's "First Stop Target" field to the name of your first floor (or whichever floor you wish) elevator stop, and set the "No User Control" and "Fixed Orientation" spawnflags.
=== Logic Entities ===


[[Image:NiElevDemoStep5a.JPG|thumb|200px|right|Fig. 5a - The <code>path_track</code> entities line up with the walking surface of their respective floors.]][[Image:NiElevDemoStep5b.PNG|thumb|200px|right|Fig. 5b - Note, each <code>path_track</code> is level with each of the floors, and that the elevator is currently in the first floor position, so that its origin is exactly the same point as the <code>path_track</code>'s center.]]
==== Opening Doors ====


Now the tricky part. Look at the Object Properties dialog box of each path_track. Each one has a "Next Stop Target" already assigned, correct? All but the last one. That's because [[Valve Hammer Editor|Hammer]] has done the boring naming stuff for you, but not quite entirely...
To open and close the doors automatically, we will first create a [[logic_relay]]. Name it something like "elev_dooropen_1" and set start disabled to "Yes". Now add these outputs:


In the "Branch Path" field, type in the name of the stop immediately before the selected stop. So, if you're looking at "elev_stop_3" the branch path for that stop would be "elev_stop_2". This also means that "elev_stop_1" has no branch path. These "branch paths" will come into play when you try and take the elevator down a floor or two later.
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnTrigger || elev_doors_1 || Open ||  || 0.00
|-
|[[File:Io11.png]] || OnTrigger || elev_doors || Open ||  || 0.00
|-
|[[File:Io11.png]] || OnTrigger || elev_doors_1 || Close ||  || 5.00
|-
|[[File:Io11.png]] || OnTrigger || elev_doors || Close ||  || 5.00
|}


When you've got this done, you should have two paths. A "Next Stop Target" path, and a "Branch Path" path. The paths should be as follows:
If you have different names for the doors be sure to change the outputs to yours. Now copy that <code>logic_relay</code> and rename it to correspond with the next floor. Change the outputs to correspond with the next floor too (e.g. for floor 3 <code>"elev_doors_1</code> would become <code>elev_doors_3</code>).
* '''Normal''' - Next Stop Target: elev_stop_1 -> elev_stop_2 -> elev_stop_3 -> elev_stop_4 -> elev_stop_5
* '''Alternate''' - Branch Path: elev_stop_5 -> elev_stop_4 -> elev_stop_3 -> elev_stop_2 -> elev_stop_1


=== Making it all work ===
Now make another <code>logic_relay</code> and name it something like "elev_stop". This one is NOT starting disabled. Set these outputs for it:
Now for the programming shtick. Create a logic_compare outside your elevator (but within the map) on the first floor. Name it something obvious. I used "ni_elev_compare". Set both the "Initial Value" and "Compare Value" to 1. Now select the first floor <code>path_track</code> entity. Go to the "Outputs" tab in its Object Properties dialog and click "Add..." Set the output to "OnPass", the target entity should be the name of your <code>logic_compare</code> (e.g. ni_elev_compare), the input should be "SetValueCompare" with a parameter override of 1. Repeat for all of the other <code>path_track</code> entities, but change the parameter override to the floor number (i.e. 2, 3, 4, and 5).


[[Image:Logic_compare_outputs.PNG|thumb|200px|right|logic_compare "Outputs" tab.]]
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnTrigger || elev || Stop ||  || 0.00
|-
|[[File:Io11.png]] || OnTrigger || elev_doors || Open ||  || 0.50
|-
|[[File:Io11.png]] || OnTrigger || elev_dooropen* || Trigger ||  || 0.50
|}


Now, how to control the elevator? Buttons! Create a button for each floor, and place them on the inside of the elevator wall, near the door (''see Fig. 6'').
{{note|Don't worry if <code>elev_dooropen*</code> is in red, it will work.}}


[[Image:NiElevDemoStep6.JPG|thumb|200px|right|Fig. 6 - Elevator buttons at reasonable height near door (<code>info_player_start</code> present for reference).]]
==== Making It All Move ====


The buttons don't really need names, but if you want to be able to debug later through the console it'd be useful to give them some. I named them "ni_elev_button_1" through "ni_elev_button_5". This will make it easy to tell where input and output commands are from. All must be parented to the elevator ("ni_elev" in my case). In each button's "Outputs" tab, create five outputs.
Create a [[logic_compare]] and name it something like "elev_compare". Set the <code>Intitial value</code> and <code>Compare value</code> to the floor the elevator starts on, in my case, 1 or the 1st floor. Now add these outputs:


The first should happen when "OnPressed", and should target "ni_elev_doors*". The asterisk '*' acts as a wildcard. This is beneficial because otherwise you would need to create a seperate output for every set of doors. Set this output as "Close".
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnEqualTo || elev_stop || Trigger ||  || 0.00
|-
|[[File:Io11.png]] || OnGreaterThan || elev_stop_1 || EnableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnGreaterThan || elev_stop_2 || EnableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnGreaterThan || elev_stop_3 || EnableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnGreaterThan || elev_stop_4 || EnableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnGreaterThan || elev || StartForward ||  || 1.00
|-
|[[File:Io11.png]] || OnLessThan || elev_stop_1 || DisableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnLessThan || elev_stop_2 || DisableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnLessThan || elev_stop_3 || DisableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnLessThan || elev_stop_4 || DisableAlternatePath ||  || 0.50
|-
|[[File:Io11.png]] || OnLessThan || elev || StartForward ||  || 1.00
|}


The second output should, when "OnPressed", target "ni_elev_dooropen*" with an input of "Disable". What's that you say? You don't have an entity called "ni_elev_dooropen"? That's because we haven't made them yet. Just have faith and press onward.
Now go to your first <code>path_track</code> and add this output:


The third output, again when "OnPressed", should target "ni_elev_dooropen_#" where you should substitute the button's floor number in place of "#". Again, this entity doesn't exist, but we'll get to it soon. Set the delay on triggering "ni_elev_dooropen_#" to 0.20 seconds, and the input value to "Enable".
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnPass || elev_compare || SetValueCompare || 1 || 0.00
|}


The fourth output acts as another "OnPressed", this time for the "ni_elev_doors", via the "Close" input.
Do this for the rest of your <code>path_tracks</code>, changing the parameter to correspond with the floor (e.g. Floor 4 will have a <code>parameter</code> of 4).


The fifth output, again "OnPressed", should target "ni_elev_compare" with an input of "SetCompareValue" (note the difference between SetCompareValue and SetValueCompare) and a parameter of #, where "#" is the same as before. Delay this command by 0.50 seconds.
=== Buttons ===


The final output should also target "ni_elev_compare", with an input of "Compare", and a delay of 1.00 second.
For our final step we will be adding buttons. Create a brush for each floor, texture it to your likings, and tie each to a [[func_button]]. Name each button corresponding to the floor it's for (such as elev_button_1) and parent each button to the elevator. Now go to the flags and check only <code>Don't Move</code> and <code>Use Activates</code>. After that, go to the outputs tab and add these:


Do this for each button inside the elevator, set each button's "Don't Move" spawnflag, and ensure that all of the names of entities are correct. Obviously I'm referring to them by the names I'm using, but if you're using your own names just remember which is which and set accordingly.
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnPressed || elev_doors* || Close ||  || 0.00
|-
|[[File:Io11.png]] || OnPressed || elev_compare || Compare ||  || 2.00
|-
|[[File:Io11.png]] || OnPressed || elev_dooropen_* || Disable ||  || 0.00
|-
|[[File:Io11.png]] || OnPressed || elev_dooropen_1 || Enable ||  || 0.20
|-
|[[File:Io11.png]] || OnPressed || elev_compare || SetCompareValue || 1 || 0.50
|}


{{note|If you are unable to set some of the input values, leave them for now and come back to this section later to complete the buttons.}}
For each button be sure to change the parameter override for <code>SetCompareValue</code> to the value that corresponds to the floor the button is for.  


Now, you need a set of <code>logic_relay</code> entities. Create one to stop the elevator (named, for example, "ni_elev_stopper"). This will be triggered any time the elevator stops at a floor, and controls the elevator doors and the elevator's cessation of motion. Create a second <code>logic_relay</code> called "ni_elev_stopperstart" which will control the stopper at the beginning of the level. In the "Outputs" tab of "ni_elev_stopperstart" create an output called "OnTrigger" which targets "ni_elev_stopper" with the command "Enable". Check the "Only Trigger Once" spawnflag in "ni_elev_stopperstart".
Copy all the buttons and place each button on the outside of the elevator on the floor that it's for. Then change the name to something like elev_button_call_# (# being the floor number) and unparent the buttons from the elevator. Go to the outputs tab and change the delay of the output for elev_compare to 1.50.


In the "Outputs" tab of "ni_elev_stopper", create three "OnTrigger" outputs. First create one to stop the elevator by targeting "ni_elev" and issuing the "Stop" input. Next, target "ni_elev_doors" and tell them to "Open" after 0.50 seconds. Also, target "ni_elev_dooropen*" with a "Trigger" command at 0.50 seconds.
==== Locking the Buttons ====


Next, create five <code>logic_relay</code> entities, one for each floor. Name them "ni_elev_dooropen_1" through "ni_elev_dooropen_5" and place them where you can find them near their respective doors. For each dooropen_#, there must be two "OnTrigger" outputs. One telling the target doors to "Open" ("ni_elev_doors_#" where "#" is the appropriate floor number), and one set for "Close" with a delay of 5.00 seconds. The "Start Disabled" flag must also be set.
You wouldn't want someone spamming the buttons and causing the elevator to glitch, so to fix this we will lock the buttons when the elevator is in use. To do this, first add this output to your <code>logic_compare</code>:


Select your <code>logic_compare</code> entity. Create an output called "OnEqualTo" and have it target "ni_elev_stopper" with the command "Trigger". Create an identical one but replace "ni_elev_stopper" with "ni_elev_stopperstart" to enable the stopper when the level starts, and check the "Fire once only" box. Then, for each floor, create two outputs called "OnGreaterThan" and "OnLessThan". "OnGreaterThan" should target the given floor's "ni_elev_stop_#" with a command of "EnableAlternatePath" and a delay of 0.50 seconds, while "OnLessThan" should target the same entity with a "DisableAlternatePath" command.
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnEqualTo || elev_button* || Unlock ||  || 0.10
|}


Once all of those outputs are added, create two more, again one each called "OnGreaterThan" and "OnLessThan" and set both to target "ni_elev" with a command of "StartForward" and a delay of 1.00 second.
{{note|For some reason [[Hammer]] says the output is invalid, but it still works, so ignore it.}}


You're almost done! Create a copy of each button next to the elevator doors on the level which corresponds to each respective button. Then clear the new buttons' "Parent" fields. This will allow you to call the elevator to whatever floor you are on. Now, drop an <code>info_player_start</code> somewhere and test your map! The elevator should be functional, and should move to any of the five floors without passing any more floors than necessary.
Now add this output to ALL your elevator buttons (including the call ones):


=== Further editing ===
{| class=standard-table
It would be advisable to texture the elevator to look realistic. The buttons used in this tutorial aren't very good, as they're just small brushes. Sprites, sounds, a counterweight, some lighting, and perhaps even a bit of scripting could make this elevator a very useful and versatile tool in appropriate situations.
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnPressed || elev_button* || Lock || 1 || 0.00
|}


== Another type of elevator ==
== Further Editing ==
=== Construction ===
Now, this tutorial will show you how to make a multistop elevator that can go to really any height.


Create an elevator, and shaft + floors as shown above.
That's it! You have made a multi-stop elevator. Now you can make it better with lights, sprites, sounds, etc.
OK, now make a small shaft next to the main shaft. It must reach as high as the main.
inside it put some func_doors the same height as the elevator.


For discussion sake, say you placed the elevator pylons (the func doors in the mini-shaft) at 0 height.
=== Bell Sound ===
If the elevator is 50" high, these pylons MUST be 50" high each. their length/Width should be 1x1 or 2x2.
The bottom of the elevator must be in-line with the bottom of the pylons, at 0.


Set their speed/lip to whatever you feel necessary.
For an elevator bell sound, I found that <code>plats/elevbell1.wav</code> works well. You can implement it into your elevator with an [[ambient_generic]] and some outputs.  
Now, make sure the pylons are numbered/lettered. select one at the end, and name it 1 [or equivalent]
Now name the next 2, 3 and so on until done. (for simplicity lets say mine is 5)
Now, parent 5 to 4, 4 to 3, 3 to 2 and 2 to 1.
Parent the main plate of the elevator to 5.
Ok, now simply create 5 buttons and start coding them to the pylons.
like this:


(Button A)
=== Shake ===
[[File:7_Env_shake_Properties.png|thumb|200px|right|Figure 7 - The env_shake properties box.]]


On pressed | 1 | open
You can also add an [[env_shake]]. You can use two outputs to make it work. In your <code>logic_compare</code> add this output:
On pressed | 2 | close
On pressed | 3 | close
On pressed | 4 |close
On pressed | 5 |close


(Button D)
{| class=standard-table
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnEqualTo || elev_shake || StopShake ||  || 0.00
|}


On pressed | 1 | open
and this output in your <code>func_tracktrain</code> (your elevator):
On pressed | 2 | open
On pressed | 3 | open
On pressed | 4 | open
On pressed | 5 | close


Please note, that if you have set all the pylon's speed to the same, the elevator will always take the same amount of time to reach the next destination whether it be from floor 1 to 5 or 1-2.
{| class=standard-table
It is reccomended that you add up all the pylon speeds, and total them. for when someone goes from 1 to 5 it will be moving at 100 (if each was 20). Try not to exceed 500 speed.
! || Output named || Target entities || Via this input || Parameter || Delay
|-
|[[File:Io11.png]] || OnStart || elev_shake || StartShake ||  || 0.10
|}


=== more editing ===
Refer to ''Figure 7'' for <code>env_shake</code> propeties.
If you wish you can add vents, sounds ("Fourth Floor" when you reach 4th floor etc.) and the pylons can be scripted to activate sequences and doors. Making your own button textures is also a good idea.
 
Simply use Paint (or other program) to make the texture, then use VTF edit to transform the .bmp (or other) into a .VTF and .VMF files required for textures. Place these in your game files (Eg. Garrysmod/garrysmod/materials/doors/Door1.vtf)
== Hammer Map File ==
[[Category:Level Design Tutorials]]
 
A [http://www.mediafire.com/download/xeay3upiwd1ni7g/elev_tut.vmf vmf] that contains what can be constructed if one follows this tutorial is included.
 
[[Category:Level Design]]
[[Category:Tutorials]]

Latest revision as of 07:13, 20 May 2025

Broom icon.png
This article or section should be converted to third person to conform to wiki standards.

Multi-stop elevators can be used in maps to allow players to move freely between three or more floors without having to cycle all the way through every floor.

Warning.pngWarning:This will be a long tutorial, as creating a multi-stop elevator is a long process. Before you decide to make a fully controllable, multi-story elevator, be sure that you need it!
Note.pngNote:It is advised to use the same entity names as used in this tutorial to minimize confusion.

Brush Work

Making the Elevator

Figure 1 - The func_tracktrain properties box.

We start off by making the elevator. You want to make the walls as tall as the space in between your level's floor and ceiling, in my case 128 units. Make the elevator floor and ceiling as thick as your level's floor and ceiling. Make sure the elevator floor is flush with the floor of your level. Cut out a hole for the doors. I have made the front wall 1 unit thinner so the doors can go in and wont clip through the wall. After that is done, pick a texture of your choice and texture only the inside. Leave the rest nodraw, unless someone can get inside your elevator shaft or see outside of your elevator.

Now select all the elevator brushes and tie them to a func_tracktrain. Refer to Figure 1 for the properties. You can set the sounds and speed to whatever you like. For the flags, check only No User Control, Fixed Orientation, & Is unblockable by player. Then move the origin (the little blue ball) to the X (in the 2D view) of the floor of the elevator (Figure 2).

Figure 2 - Location of the blue ball.
Figure 3 - The appearance of the elevator.

Making the Shaft

Now you will want to make a shaft that encloses the elevator and goes all the way up to the first floor. It's really just 3 tall brushes and then a floor and ceiling. Make sure that you have door holes cut out that are the same size as the elevator's door hole. You want to keep the entire shaft nodraw unless someone can somehow see it.

Making the Doors

First we will make doors for the actual elevator. Just make 2 brushes that fit into the door hole you have cut out. I have mine 2 units thick, 112 units tall, and 32 units wide each. You can texture the doors with anything you like, but I recommend metal/offelevdrsa. It may take a while adjusting the texture so it fits with the door. Now tie each door to a func_door. Refer to Figure 4 for the properties. Be sure to name both doors the same name and parent them to the elevator. You also might need to change move direction. Again, you can change the sounds and speed to whatever you like. Now go to the flags and uncheck Touch Opens.

Figure 4 - The elevator door properties box.

Next we will make doors for each floor. You can simply copy the doors you made for the elevator and paste them to match with the door hole you made when building the shaft. The only difference is that for each floor they have to be named something different. For example for the first floor I used "elev_doors_1" and for the second floor "elev_doors_2", while for the elevator doors I used "elev_doors". Keep in mind both doors have to be named the same thing. The name only changes for different floors.

Entity Work

Making the Path

We begin our work with the entities by making a path_track. Line this path_track up with the center X of the floor, just like with the blue ball. Then name it something like "elev_stop_1" (Figure 5). Set the Orientation Type to No change. Now copy this path_track and paste it, lining it up with the x in the second floor. Do this for all your floors, making sure to change the name for each path_track to correspond with its floor.

Figure 5 - How to place the path_tracks.

Now go back to your first path_track and set its Next Stop Target to "elev_stop_2", or your second floor's path_track. Do this for all your floors except the top floor. Once you've finished that, go to your top floor's path track and set its Branch Path to the path_track below it (elev_stop 3). Do this for all your path_tracks except for the first one (elev_stop_1). Once you've done all this your shaft should look something like Figure 6.

Icon-Bug.pngBug:It appears as though for some levels the elevator doesn't line up with the floor. I don't know why this is cause because I have all possible properties set to a value that makes sure the elevator wont move out of its origin.
Figure 6 - The appearance of the elevator shaft.

Logic Entities

Opening Doors

To open and close the doors automatically, we will first create a logic_relay. Name it something like "elev_dooropen_1" and set start disabled to "Yes". Now add these outputs:

Output named Target entities Via this input Parameter Delay
Io11.png OnTrigger elev_doors_1 Open 0.00
Io11.png OnTrigger elev_doors Open 0.00
Io11.png OnTrigger elev_doors_1 Close 5.00
Io11.png OnTrigger elev_doors Close 5.00

If you have different names for the doors be sure to change the outputs to yours. Now copy that logic_relay and rename it to correspond with the next floor. Change the outputs to correspond with the next floor too (e.g. for floor 3 "elev_doors_1 would become elev_doors_3).

Now make another logic_relay and name it something like "elev_stop". This one is NOT starting disabled. Set these outputs for it:

Output named Target entities Via this input Parameter Delay
Io11.png OnTrigger elev Stop 0.00
Io11.png OnTrigger elev_doors Open 0.50
Io11.png OnTrigger elev_dooropen* Trigger 0.50
Note.pngNote:Don't worry if elev_dooropen* is in red, it will work.

Making It All Move

Create a logic_compare and name it something like "elev_compare". Set the Intitial value and Compare value to the floor the elevator starts on, in my case, 1 or the 1st floor. Now add these outputs:

Output named Target entities Via this input Parameter Delay
Io11.png OnEqualTo elev_stop Trigger 0.00
Io11.png OnGreaterThan elev_stop_1 EnableAlternatePath 0.50
Io11.png OnGreaterThan elev_stop_2 EnableAlternatePath 0.50
Io11.png OnGreaterThan elev_stop_3 EnableAlternatePath 0.50
Io11.png OnGreaterThan elev_stop_4 EnableAlternatePath 0.50
Io11.png OnGreaterThan elev StartForward 1.00
Io11.png OnLessThan elev_stop_1 DisableAlternatePath 0.50
Io11.png OnLessThan elev_stop_2 DisableAlternatePath 0.50
Io11.png OnLessThan elev_stop_3 DisableAlternatePath 0.50
Io11.png OnLessThan elev_stop_4 DisableAlternatePath 0.50
Io11.png OnLessThan elev StartForward 1.00

Now go to your first path_track and add this output:

Output named Target entities Via this input Parameter Delay
Io11.png OnPass elev_compare SetValueCompare 1 0.00

Do this for the rest of your path_tracks, changing the parameter to correspond with the floor (e.g. Floor 4 will have a parameter of 4).

Buttons

For our final step we will be adding buttons. Create a brush for each floor, texture it to your likings, and tie each to a func_button. Name each button corresponding to the floor it's for (such as elev_button_1) and parent each button to the elevator. Now go to the flags and check only Don't Move and Use Activates. After that, go to the outputs tab and add these:

Output named Target entities Via this input Parameter Delay
Io11.png OnPressed elev_doors* Close 0.00
Io11.png OnPressed elev_compare Compare 2.00
Io11.png OnPressed elev_dooropen_* Disable 0.00
Io11.png OnPressed elev_dooropen_1 Enable 0.20
Io11.png OnPressed elev_compare SetCompareValue 1 0.50

For each button be sure to change the parameter override for SetCompareValue to the value that corresponds to the floor the button is for.

Copy all the buttons and place each button on the outside of the elevator on the floor that it's for. Then change the name to something like elev_button_call_# (# being the floor number) and unparent the buttons from the elevator. Go to the outputs tab and change the delay of the output for elev_compare to 1.50.

Locking the Buttons

You wouldn't want someone spamming the buttons and causing the elevator to glitch, so to fix this we will lock the buttons when the elevator is in use. To do this, first add this output to your logic_compare:

Output named Target entities Via this input Parameter Delay
Io11.png OnEqualTo elev_button* Unlock 0.10
Note.pngNote:For some reason Hammer says the output is invalid, but it still works, so ignore it.

Now add this output to ALL your elevator buttons (including the call ones):

Output named Target entities Via this input Parameter Delay
Io11.png OnPressed elev_button* Lock 1 0.00

Further Editing

That's it! You have made a multi-stop elevator. Now you can make it better with lights, sprites, sounds, etc.

Bell Sound

For an elevator bell sound, I found that plats/elevbell1.wav works well. You can implement it into your elevator with an ambient_generic and some outputs.

Shake

Figure 7 - The env_shake properties box.

You can also add an env_shake. You can use two outputs to make it work. In your logic_compare add this output:

Output named Target entities Via this input Parameter Delay
Io11.png OnEqualTo elev_shake StopShake 0.00

and this output in your func_tracktrain (your elevator):

Output named Target entities Via this input Parameter Delay
Io11.png OnStart elev_shake StartShake 0.10

Refer to Figure 7 for env_shake propeties.

Hammer Map File

A vmf that contains what can be constructed if one follows this tutorial is included.