Game Development Community

dev|Pro Game Development Curriculum

Teleport script

by Stefan Beffy Moises · 07/09/2002 (10:11 am) · 44 comments

Download Code File

The basic idea was to combine 2 (or more) triggers, animated dts shapes
for the basic effect, particle effects, a little script
swapping the player location/transform and finally some "buzz" sound.

Okay, so lets start with the function doing the actual teleport...

I've put it into "server/scripts/commands.cs" and it looks like this:
function serverCmdTeleportPlayer(%client, %clientId, %targetObj)
{
    %player = %clientId.player;
    %currPlayerPos = %player.getPosition();
    %targetPos = %targetObj.getPosition();
    %x = getWord(%targetPos, 0);
    %y = getWord(%targetPos, 1);
    %z = getWord(%targetPos, 2);
    // adjust z value to prevent player from falling through the terrain... :-P
    %z += 3.0;
    %finalPos = %x SPC %y SPC %z;
    echo("Transforing from" SPC %currPlayerPos SPC "to" SPC %finalPos);
    %player.setTransform(%finalPos);
}
Well, pretty basic, all it does is get the player's position and the position of the
target object indicated by %targetObj, adjusts the z value to prevent the player from
falling through the terrain and sends him to the %finalPos position.

Now lets look at the trigger, I've made a new file "fps/server/teleportTrigger.cs" which I execute in
"fps/server/game.cs" (as always), and it looks like this:



datablock TriggerData(TeleportTrigger)
{
   tickPeriodMS = 500;
};
datablock AudioProfile(TeleportBuzz)
{
   fileName = "~/data/sound/fx/electricity.wav";
   description = AudioClose3d;
	preload = true;
};

function TeleportTrigger::onEnterTrigger(%data, %obj, %colObj)
{
   %checkname = %obj.getName();
   %client = %colObj.client;
   if(!%client)
   {
      echo("not a client!");
      return;
   }
   echo("Teleport client:" SPC %client);

   if(%checkname $= "TeleportTrigger1")
   {
      // if the player didn't recently beam over here... otherwise
      // he would be looping around between the two, I guess...
      if(!$from2to1)
      {
         %target = "TeleportTrigger2";
         CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck!!",2,10);
         $teleSched = schedule(2000,0,"goScotty",%client,%target);
        	$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
         %client.player.setCloaked(true);
         $from1to2 = true;
         $from2to1 = false;
      }
   }
   else
   {
      if(!$from1to2)
      {
         %target = "TeleportTrigger1";
         CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck!!",2,10);
         $teleSched = schedule(2000,0,"goScotty",%client, %target);
        	$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
         %client.player.setCloaked(true);
         $from2to1 = true;
         $from1to2 = false;
      }
   }
}

function TeleportTrigger::onLeaveTrigger(%data, %obj, %colObj)
{
   %checkname = %obj.getName();
   %client = %colObj.client;
   echo("TeleportTrigger::onLeaveTrigger called!");
   cancel($teleSched);
   alxStop($teleSound);
   %client.player.setCloaked(false);
   // if the player leaves the target trigger,
   // he can use it, too...
   if(%checkname $= "TeleportTrigger1")
   {
      $from2to1 = false;
   }
   else if(%checkname $= "TeleportTrigger2")
   {
      $from1to2 = false;
   }
}

function goScotty(%client, %target)
{
   echo("goScotty called!");
   // beam me up!
   commandToServer('TeleportPlayer', %client, %target);
}
function TeleportTrigger::onTickTrigger(%data, %obj)
{
}

I've got two trigger objects in my mission file named "TeleportTrigger1" and "TeleportTrigger2",
furthermore there are the two shape files, which have their own datablock (btw., I took these shapefiles
and their datablock file "fxShapes.cs" from the latest RWTA build - thanks Phil :-).

Here is the datablock:
datablock StaticShapeData(MeshEffect)
{
   category = "Effects";
   shapeFile = "~/data/shapes/markers/flame.dts";
};
I use two vars "$from1to2" and "$from2to1" to keep track if the player already was teleported to the
recent teleport, and if he was, he has to step out of it (onLeaveTrigger), before he can use it again...
otherwise he would be trapped, I guess... ;-)

To make it more realistic and to not just move the player, I put a little timeout of two seconds in,
and, what adds quite a lot to it, I set

%client.player.setCloaked(true);
which kinda fades the player out and makes him semi-transparent, and after he's teleported, he "fades back in"... make sure to try it in 3rd person perspective...!! :-)

So here is how all that looks in my mission file:
new StaticShape(TeleportEffect1) {
      position = "-27.6876 21.0268 100.362";
      rotation = "1 0 0 90.5273";
      scale = "1 1 1";
      dataBlock = "MeshEffect";
   };
   new ParticleEmitterNode(TeleportParticle1) {
      position = "-27.1392 22.8644 101.253";
      rotation = "1 0 0 0";
      scale = "1 1 1";
      dataBlock = "defaultParticleEmitterNode";
      emitter = "TeleportEmitter";
      velocity = "1";
   };
   new StaticShape(TeleportEffect2) {
      position = "-28.3129 125.469 100.391";
      rotation = "1 0 0 90.5273";
      scale = "1 1 1";
      dataBlock = "MeshEffect";
   };
   new ParticleEmitterNode(TeleportParticle2) {
      position = "-28.3129 127.069 101.391";
      rotation = "1 0 0 0";
      scale = "1 1 1";
      dataBlock = "defaultParticleEmitterNode";
      emitter = "TeleportEmitter";
      velocity = "1";
   };
   new Trigger(TeleportTrigger2) {
      position = "-29.4077 128.417 99.849";
      rotation = "1 0 0 0";
      scale = "3 2 2";
      dataBlock = "TeleportTrigger";
      polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000
	  -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
   };
   new Trigger(TeleportTrigger1) {
      position = "-29.2559 23.685 99.5474";
      rotation = "1 0 0 0";
      scale = "3 2 2";
      dataBlock = "TeleportTrigger";
      polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000
	  -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
   };

The ParticleEmitter looks like this, I keep all of my particle stuff in a file named "customParticles.cs",
which is also executed in ... well, you guess it!
datablock ParticleData(TeleportParticle)
{
    dragCoefficient = 1.11437;
    gravityCoefficient = -0.735043;
    windCoefficient = 0;
    inheritedVelFactor = 0.483366;
    constantAcceleration = 0;
    lifetimeMS = 1056;
    lifetimeVarianceMS = 256;
    useInvAlpha = 0;
    spinRandomMin = -159;
    spinRandomMax = 172;
    textureName = "fps/data/shapes/rifle/smokeParticle";
    times[0] = 0;
    times[1] = 1;
    colors[0] = "0.102362 0.070866 0.000000 0.370079";
    colors[1] = "0.000000 0.102362 0.000000 0.740157";
    sizes[0] = 6.08863;
    sizes[1] = 0;
};

datablock ParticleEmitterData(TeleportEmitter)
{
    ejectionPeriodMS = 10;
    periodVarianceMS = 2;
    ejectionVelocity = 2.75;
    velocityVariance = 1.62;
    ejectionOffset = 0;
    thetaMin = 47;
    thetaMax = 90;
    phiReferenceVel = 144;
    phiVariance = 360;
    overrideAdvances = 0;
    orientParticles= 0;
    orientOnVelocity = 1;
    particles = "TeleportParticle";
};

Okay, so here are the "step-by-step" instructions...
1) download the zip :-P
2) put flame.dts and flame.png in "fps\data\shapes\markers"
3) put electricity.wav in "\fps\data\sound\fx"
4) put fxShapes.cs, teleportTrigger.cs and customParticles.cs in "fps\server\scripts"
5) put
exec("./teleportTrigger.cs");
exec("./customParticles.cs");
exec("./fxShapes.cs");
in "fps\server\scripts\game.cs"
6) put the function serverCmdTeleportPlayer(%client, %targetObj) in "fps\server\scripts\commands.cs"
7) add all the objects needed to your mission file (use the world editor by pressing F11 -> F4)
Note: it may be hard to add and place the particle emitters in the editor, so if you have problems, simply add
the shapes and the triggers with the editor, then save your mission and add the emitters manually - you can copy
the positions of the triggers and then adjust them later in the editor).

Well, as always, hope you enjoyed it - happy teleporting! :-))

PLEASE NOTE: The download file available here comes without the sound file for the effect (too large for the resource), but you can find this tutorial and ALL the files here!

EDIT: Fixed the multiplayer issues, everything is working now in multiplayer, too! The zip files here and on our website have been updated! Thanks to Ed Gardner who helped me out on IRC! :-)
#21
07/15/2002 (5:18 pm)
Ya dude, my torking is limited to the weekends for the summer, the delay and message shouldn
#22
12/27/2002 (11:01 am)
Hey Stefan, have you gotten around to testing any of the teleport stuff over a network connection? I can't believe I haven't gotten to this before. I was testing client connections because of some other problems and noticed the teleporters don't work for clients. They work fine as a single player server game. Just wondered if they work for you. I'm not sure, but the radar-teleport selection gui part might be causing a client connection crash as well (again, works fine as a server connection). It seems to for me at least. I'll post again if I find out any thing more.

Edit: Never mind, got it working with client connections now :)
#23
04/13/2003 (4:14 pm)
Stephen,

What would you do to modify this to teleport a player to a location in another mission? Would this be fairly easy to do?

Thanks!
#24
05/10/2004 (9:19 pm)
I didnt like the way your teleporters were set up.. so i decided to edit them a bit and post back here.. my code it actually quite shorter.. Hope you dont mind :) I'll go ahead and post my changes here..

//------------------------------------------------
//  Teleport Datablocks  -Originally by beffy        
//------------------------------------------------

datablock TriggerData(Teleport0)
{
   className = Teleport;
   tickPeriodMS = 500;
   TeleportTarget = "Teleport1";
};

datablock TriggerData(Teleport1)
{
   className = Teleport;
   tickPeriodMS = 500;
   TeleportTarget = "Teleport0";
};


datablock AudioProfile(TeleportBuzz)
{
   fileName = "~/data/sound/fx/Teleport.wav";
   description = AudioClose3d;
	preload = true;
};

function Teleport::onEnterTrigger(%data, %obj, %colObj)
{
   if($Arrived)
      return;

   %client = %colObj.client;
   if(!%client)
      return;

   %target = %data.TeleportTarget;

   CommandToClient(%client,'bottomprint',"-Teleporter Initializing-",2,10);
   $teleSched = schedule(2000,0,"Teleport",%client,%target);
   $teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
   %client.player.setCloaked(true);
   $Arrived = true;

}

function Teleport::onLeaveTrigger(%data, %obj, %colObj)
{
   %client = %colObj.client;
   cancel($teleSched);
   alxStop($teleSound);
   %client.player.setCloaked(false);

   $Arrived = false;

}

function Teleport(%client, %target)
{
   // Teleport Me
   echo("Tele- Teleport Target:" SPC %target);
   commandToServer('TeleportPlayer', %client, %target);
}

function Teleport::onTickTrigger(%data, %obj)
{
}
#25
05/11/2004 (7:46 pm)
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3028

Single player level exits, down at the bottom of that thread is the latest resource for level exits
#26
11/14/2004 (3:38 pm)
Hi all.

I have implemented a slightly different version of this, using one of the teleporter objects (source or destination) to hold the return value of the schedule command etc. I have basically removed all global variables from this functionality.

Just wanting to know if there is anything really wrong with that and WHY global variables where chosen for this and why they are better?

The only side effect I can see (or maybe it's a benifit) is that these variables (and their values) are then listed under Dynamic values(?) in the editor.
#27
12/12/2004 (12:15 am)
Put it into 1.3 HEAD.
Works perfect, as well as the GUI resource.
Thanks again Beffy!

Ari Rule (Lead Programmer)
"I'll sleep when I'm dead."
#28
05/05/2005 (7:00 am)
The code don't work for me as is. I think the problem is that the servercommand function takes three arguments:

function serverCmdTeleportPlayer(%client, %clientId, %targetObj)

but the calling code is only sending it two:

commandToServer('TeleportPlayer', %client, %target);

The echoes in the server command never display because it's never being called.
#29
07/25/2005 (8:06 pm)
J.C., that is not the problem. It is the functionality of commandToServer to "add" the extra client variable into the function call. The problem is that in dedicated server mode the trigger functions are called server side and using commandToServer attempts to send the server its own message and fails. This works in listen server mode because the line between client and server is blurry.

The fix is simple:

--------------------
function serverCmdTeleportPlayer(%client, %clientId, %targetObj)
----becomes-----
function TeleportPlayer(%client, %targetObj)
--------------------

and

--------------------
commandToServer('TeleportPlayer', %client, %target);
----becomes-----
TeleportPlayer(%client, %target);
--------------------

This will allow the server to call its own TeleportPlayer function. This should still work in listen mode as well but I have not tested that yet.
#30
10/04/2005 (7:21 pm)
I'm having serious issues with this line in the commands.cs

function serverCmdTeleportPlayer(%client, %targetObj)
{
%player = %client.player;
%currPlayerPos = %player.getPosition();
-----> %targetPos = %targetObj.getPosition();
x = getWord(%targetPos, 0);
y = getWord(%targetPos, 1);
z = getWord(%targetPos, 2);
// adjust z value to prevent player from falling through the terrain... :-P
z += 3.0;
finalPos = %x SPC %y SPC %z;
cho("Transforing from" SPC %currPlayerPos SPC "to" SPC %finalPos);
player.setTransform(%finalPos);
}

Every time I enter the trigger it errors saying that getPostion() is an unknown function! HELP!
#31
10/05/2005 (7:30 am)
Are you sure you are getting %targetObj as a valid object in that function? If it doesn't know what %targetObj is, it won't be able to get its position. I'll look at my code later and see if there is anything else going on.
#32
11/01/2005 (11:43 pm)
Did anyone figure this out? I'm getting the same target.getposition() error.

Your right: The line thats failing is really in "onTriggerEnter()" in file TeleportTrigger.cs.
%target = %data.TeleportTarget;


[edit]FIXED!
The above mentioned line of code should read:

%target = %obj.TeleportTarget;
[/edit]
#33
01/14/2006 (7:02 pm)
Has anyone got the custom particles and the flame.dts working in a binary 1.3 build? Could I get some help with that?
#34
03/27/2006 (9:51 pm)
Ok, I have everything working when I run on my machine. We even have a custom model, particles, and everything.

The only problem is that when I run in dedicated server mode, the teleporter doesn't ACTUALLY teleport us. It will just turn us invisible and keep us there.

Any idea why this doesn't work in dedicated mode?
#35
07/01/2006 (11:06 am)
My guess for the dedicated mode is that teleport() calls CommandToServer(teleportPlayer), I dont think a server can send a command to itself. Actually, looking at the code theres no reason for it to *ever* be commandtoserver, since a client shouldnt be calling any of those functions.

Only reason it does work normally is that theres a client and server in the same process.
#36
08/11/2006 (5:06 pm)
does it work in multiplayer tho?
#37
12/29/2007 (11:34 pm)
Has anyone actually got this working on a dedicated server? I can only get it to work on singleplayer. If someone has got it working can you please post how?

Thanks.
#38
02/11/2008 (5:45 am)
How do I make this work? I downloaded all of the files, and followed the instructions to the best of my ability, but when I go to add the trigger, it's not in the "datablock" list... am I doing something wrong?
#39
08/01/2008 (8:02 am)
Great Work ! Ty;) i want ask something i use npc chat dialog system and i add my npc's talk area "teleport me". when i click "teleport me" how can i call this teleport function???

One Example for "killplayer".
_____
function KillPlayer(%client,%sender,%npcFile)
{
%client.player.kill("Sudden");
CloseDialog(%client,%sender,%npcFile);
}
_____
Help Me Please
#40
07/26/2009 (1:38 am)
So I'm having an issue. I added another set of teleports in, and all of the paths work except for one, entering the first teleport always sends me to the third one instead of the second one, though if i enter the second , it always sends me to the first one. (from 3 to for and in reverse work perfectly also). Here's what I have:
//port set 1===========================================================================================
if(%checkname $= "TeleportTrigger1")
{
// if the player didn't recently beam over here... otherwise
// he would be looping around between the two, I guess...
if(!$from2to1)
{
%target = "TeleportTrigger2";
CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck... buahahaha!!",2,10);
$teleSched = schedule(2000,0,"goScotty",%client,%target);
$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
%client.player.setCloaked(true);
$from1to2 = true;
$from2to1 = false;
}
}
else
{
if(!$from1to2)
{
%target = "TeleportTrigger1";
CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck... buahahaha!!",2,10);
$teleSched = schedule(2000,0,"goScotty",%client, %target);
$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
%client.player.setCloaked(true);
$from2to1 = true;
$from1to2 = false;
}
}
// end port set 1 ==========================================================================================================
//portset2
//====================================================================================================================
if(%checkname $= "TeleportTrigger3")
{
// if the player didn't recently beam over here... otherwise
// he would be looping around between the two, I guess...
if(!$from4to3)
{
%target = "TeleportTrigger4";
CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck... buahahaha!!",2,10);
$teleSched = schedule(2000,0,"goScotty",%client,%target);
$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
%client.player.setCloaked(true);
$from3to4 = true;
$from4to3 = false;

}
}
else
{
if(!$from3to4)
{
%target = "TeleportTrigger3";
CommandToClient(%client,'bottomprint',"Teleporter initializing... good luck... buahahaha!!",2,10);
$teleSched = schedule(2000,0,"goScotty",%client, %target);
$teleSound = serverPlay3D(TeleportBuzz,%client.player.getTransform());
%client.player.setCloaked(true);
$from4to3 = true;
$from3to4 = false;

}
}
// end port set 2=========================================================================================================================
}

function TeleportTrigger::onLeaveTrigger(%data, %obj, %colObj)
{
%checkname = %obj.getName();
%client = %colObj.client;
echo("TeleportTrigger::onLeaveTrigger called!");
cancel($teleSched);
alxStop($teleSound);
%client.player.setCloaked(false);
// if the player leaves the target trigger,
// he can use it, too...
if(%checkname $= "TeleportTrigger1")
{
$from2to1 = false;

}
else if(%checkname $= "TeleportTrigger2")
{
$from1to2 = false;

}
if(%checkname $= "TeleportTrigger3")
{
$from4to3 = false;

}
else if(%checkname $= "TeleportTrigger4")
{
$from3to4 = false;

}
}