A to Z Scripting: Practical exercise: subtle teleportation

From The DarkMod Wiki
Revision as of 11:01, 21 December 2020 by Dragofer (talk | contribs) (Created page with "== Practical exercise: subtly teleporting the player == So far we've seen the basics of scripting, including the basic composition of a script, how variables are made and used...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Practical exercise: subtly teleporting the player

So far we've seen the basics of scripting, including the basic composition of a script, how variables are made and used, how to "get" information about entities in the map, all the ways to call a script, how to use the TDM Script Reference as well as how to set up your .script file. That would already be enough to try an early scripting exercise:

Say you were making some kind of wizard's tower, or had 2 separate areas that should look like they're physically connected: you'd want to teleport the player between 2 rooms without him realising it. That means both rooms should look identical, and the player should be teleported to the exactly same position in the other room.


Brainstorming

Before you start writing any lines of script, it's good to plan this out, maybe even writing down notes somewhere. The more you think of now, the fewer roadblocks there might be down the line:

  • 1) What will be teleported? Just the player, or maybe also moveables and even AIs?
  • 2) How will the script know where the player/etc. should be teleported?
  • 3) How should the rooms be made? Should AIs have access? Should there be extinguishable lamps? Where should the trigger brushes be?


1) What will be teleported? Just the player, or maybe also moveables and even AIs?

Since this is a basic script, it's better to keep things simple, so only the player will be teleported for now. Moveables would be more more advanced, since they would require some way of detecting them (i.e. with a room-filling trigger_touch brush) and a way of running the teleportation script on every one of them. AIs most likely shouldn't be teleported since it would disrupt their pathfinding.


2) How will the script know where the player should be teleported?

To maintain the illusion, we want the player to be teleported to the exact same position in the other room. That means we can't teleport him to a fixed position, but will instead have to get his current position and modify it with an offset.

Say the 2nd room was 1024 units off to the right compared to the first unit. In that case, you can simply add or subtract 1024 from the player's origin on the x axis to move him between the 2 rooms. But if you ever moved these rooms, you'd have to manually update this number.

Therefore it's better to automatically calculate the offset as a variable. All you need is to take the position of some kind of reference point in both rooms, such as the origin of a piece of furniture, and find the difference. This vector will always take you to the corresponding point in the other room.


3) How should the rooms be made? Should AIs have access? Should there be extinguishable lamps? Where should the trigger brushes be?

This is more of a mapping question. We want there to be as few differences as possible between the 2 rooms, so any non-static entities like AIs, loot, moveables or extinguishable lamps shouldn't be found in or near these rooms (unless you want to put in the extra work of synchronising the 2 rooms' copies via script). AIs should have no way of pathing into these rooms.

The next mapping question is layout. Corridors leading to/from the rooms could be L-shaped to minimise what the player can see when the transition happens (to reduce how much you have to keep identical). You will also need to place the trigger brushes so that the player doesn't teleport and immediately stumble into the brush that teleports him back where he came from.


The mapping

Next you will want to do the mapping in DR, as you'll need the entity names later on for the script. After the brainstorming, this is a setup that could work:

These are the key features of the mapping setup:

  • the table in the centre of each room acts as the reference point for calculating the teleportation offset. For easier reference in the script, they've been given special names (table_1, table_2).
  • there are 2 multi-use trigger brushes, arranged in such a way that when the player crosses the room he only activates one of them. One has a "call" spawnarg to call the script "teleport_forward", the other calls "teleport_backward".
  • all 4 corridors are blind and L-shaped. The player enters the setup via the bottom left corridor and leaves via the top right corridor, so you'd attach the rest of your map to these 2 corridors.


The scripting

Now that all the planning and setup are out of the way, the scripting itself can begin. Start with thinking about what important components are involved: there will be 2 scripts (teleport_forward, teleport_backward) and one variable for storing the teleportation offset. Another variable will be needed to tell the script where to teleport the player to.

The variables should be available to both scripts, so they should be defined at the top (making them visible to all scripts below them) and outside of a script (so they're not specific to only one script).

vector teleport_offset;		//the vector for moving between room 1 and room 2
vector teleport_destination;	//the position the player should be teleported to

On to the first teleportation script. Much of the work lies in calculating the variables (the offset and then the destination).

void teleport_forward()
{
	teleport_offset		= $table_2.getOrigin() - $table_1.getOrigin();		//calculate the vector to get to room 2 from room 1, using the tables as reference points
	teleport_destination	= $player1.getOrigin() + teleport_offset;		//modify the player's current position with the "teleport_offset" in order to get the destination

	$player1.setOrigin(teleport_destination);					//perform the teleportation to the position stored as "teleport_destination"
}

For teleporting back, the first script can be copied. The only change needed is to subtract the teleport_offset from the player's origin, rather than adding it.

void teleport_backward()
{
	teleport_offset		= $table_2.getOrigin() - $table_1.getOrigin();		//calculate the vector to get to room 2 from room 1, using the tables as reference points
	teleport_destination	= $player1.getOrigin() - teleport_offset;		//modify the player's current position with the teleportation offset in order to get the destination

	$player1.setOrigin(teleport_destination);					//perform the teleportation
}

The setup is now done. If everything is done right, the player would now teleport seamlessly between the 2 rooms without ever noticing. You could place some kind of unique item in one of the rooms (i.e. a big torch) to demonstrate this more visibly.


Notes:

  • A lot of the work in this case went into the planning and mapping phases, while the scripting itself was quite straightforward (possibly thanks in part to the advance planning). Planning setups like this should become easier the more you've done with scripting in your maps.
  • The variable "teleport_offset" is always the same, so it's not ideal to recalculate it every time a teleportation script is called (even though get() events are very lightweight). Alternatively you could calculate it a single time in void main() or in a 3rd script that gets called after the map starts. The downside would be that your scripts are more spread out. With the above approach, everything is compact and in one place.


Next / previous article