| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //-----------------------------------------------------------------------------
- // Trigger-derrived teleporter object. Teleports an object from it's entrance to
- // it's exit if one is defined.
- function TeleporterTrigger::onAdd( %this, %teleporter )
- {
-
- // Setup default parameters.
- if ( %teleporter.exit $= "" )
- %teleporter.exit = "NameOfTeleporterExit";
- if ( %teleporter.teleporterCooldown $= "" )
- %teleporter.teleporterCooldown = %this.teleporterCooldown;
- if ( %teleporter.exitVelocityScale $= "" )
- %teleporter.exitVelocityScale = %this.exitVelocityScale;
- if ( %teleporter.reorientPlayer $= "" )
- %teleporter.reorientPlayer = %this.reorientPlayer;
- if ( %teleporter.oneSided $= "" )
- %teleporter.oneSided = %this.oneSided;
- if ( %teleporter.entranceEffect $= "" )
- %teleporter.entranceEffect = %this.entranceEffect;
- if ( %teleporter.exitEffect $= "" )
- %teleporter.exitEffect = %this.exitEffect;
-
- // We do not want to save this variable between levels,
- // clear it out every time the teleporter is added
- // to the scene.
- %teleporter.timeOfLastTeleport = "";
- }
- function TeleporterTrigger::onLeaveTrigger(%this,%trigger,%obj)
- {
- // This is called after onEnterTrigger for BOTH
- // The teleporter's entrance and exit
- %obj.isTeleporting = false;
- }
- //ARGS:
- // %this - The teleporter datablock.
- // %entrance - The teleporter the player has entered (The one calling this function).
- // %obj - The object that entered the teleporter.
- function TeleporterTrigger::onEnterTrigger(%this, %entrance, %obj)
- {
- // Get the location of our target position
- %exit = nameToID(%entrance.exit);
-
- // Check if the the teleport is valid.
- %valid = %this.verifyObject(%obj, %entrance, %exit);
-
- // Bail out early if we cannot complete this teleportation
- if (!%valid)
- return;
-
- // Kill any players in the exit teleporter.
- %this.telefrag(%obj, %exit);
-
- // Create our entrance effects on all clients.
- if (isObject(%entrance.entranceEffect))
- {
- for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
- commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %entrance.position, %entrance.entranceEffect.getId());
- }
-
- // Teleport the player to the exit teleporter.
- %this.teleportPlayer(%obj, %exit);
-
- // Create our exit effects on all clients.
- if (isObject(%exit.exitEffect))
- {
- for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
- commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %exit.position, %exit.exitEffect.getId());
- }
-
- // Record what time we last teleported so we can determine if enough
- // time has elapsed to teleport again
- %entrance.timeOfLastTeleport = getSimTime();
-
- // If this is a bidirectional teleporter, log it's exit too.
- if (%exit.exit $= %entrance.name)
- %exit.timeOfLastTeleport = %entrance.timeOfLastTeleport;
-
- // Tell the client to play the 2D sound for the player that teleported.
- if (isObject(%this.teleportSound) && isObject(%obj.client))
- %obj.client.play2D(%this.teleportSound);
- }
- // Here we verify that the teleport is valid.
- // Tests go here like if the object is of a 'teleportable' type, if the
- // given teleporter has an exit defined, etc.
- function TeleporterTrigger::verifyObject(%this, %obj, %entrance, %exit)
- {
-
- // Bail out early if we couldn't find an exit for this teleporter.
- if (!isObject(%exit))
- {
- logError("Cound not find an exit for " @ %entrance.name @ ".");
- return false;
- }
-
- // If the entrance is once sided, make sure the object
- // approached it from it's front.
- if (%entrance.oneSided)
- {
- %dotProduct = VectorDot(%entrance.getForwardVector(), %obj.getVelocity());
-
- if (%dotProduct > 0)
- return false;
- }
-
- // If we are coming directly from another teleporter and it happens
- // to be bidirectional, We need to avoid ending sending objects through
- // an infinite loop.
- if (%obj.isTeleporting)
- return false;
-
- // We only want to teleport players
- // So bail out early if we have found any
- // other object.
- if (!%obj.isMemberOfClass("Player"))
- return false;
-
- if (%entrance.timeOfLastTeleport > 0 && %entrance.teleporterCooldown > 0)
- {
- // Get the current time, subtract it from the time it last teleported
- // And compare the difference to see if enough time has elapsed to
- // activate the teleporter again.
- %currentTime = getSimTime();
- %timeDifference = %currentTime - %entrance.timeOfLastTeleport;
- %db = %entrance.getDatablock();
- if (%timeDifference <= %db.teleporterCooldown)
- return false;
- }
-
- return true;
- }
- // Function to teleport object %player to teleporter %exit.
- function TeleporterTrigger::teleportPlayer(%this, %player, %exit)
- {
- // Teleport our player to the exit teleporter.
- if (%exit.reorientPlayer)
- %targetPosition = %exit.getTransform();
- else
- {
- %pos = %exit.getPosition();
- %rot = getWords(%player.getTransform(), 3, 6);
- %targetPosition = %pos SPC %rot;
- }
- %player.setTransform(%targetPosition);
-
- // Adjust the player's velocity by the Exit location's scale.
- %player.setVelocity(vectorScale(%player.getVelocity(), %exit.exitVelocityScale));
-
- // Prevent the object from doing an immediate second teleport
- // In the case of a bidirectional teleporter
- %player.isTeleporting = true;
- }
- // Telefrag is a term used in multiplayer gaming when a player takes a teleporter
- // while another player is occupying it's exit. The player at the exit location
- // is killed, allowing the original player to arrive at the teleporter.
- function TeleporterTrigger::teleFrag(%this, %player, %exit)
- {
- // When a telefrag happens, there are two cases we have to consider.
- // The first case occurs when the player's bounding box is much larger than the exit location,
- // it is possible to have players colide even though a player is not within the bounds
- // of the trigger Because of this we first check a radius the size of a player's bounding
- // box around the exit location.
-
- // Get the bounding box of the player
- %boundingBoxSize = %player.getDatablock().boundingBox;
- %radius = getWord(%boundingBoxSize, 0);
- %boxSizeY = getWord(%boundingBoxSize, 1);
- %boxSizeZ = getWord(%boundingBoxSize, 2);
-
- // Use the largest dimention as the radius to check
- if (%boxSizeY > %radius)
- %radius = %boxSizeY;
- if (%boxSizeZ > %radius)
- %radius = %boxSizeZ;
-
- %position = %exit.getPosition();
- %mask = $TypeMasks::PlayerObjectType;
-
- // Check all objects within the found radius of the exit location, and telefrag
- // any players that meet the conditions.
- initContainerRadiusSearch( %position, %radius, %mask );
- while ( (%objectNearExit = containerSearchNext()) != 0 )
- {
- if (!%objectNearExit.isMemberOfClass("Player"))
- continue;
-
- // Avoid killing the player that is teleporting in the case of two
- // Teleporters near eachother.
- if (%objectNearExit == %player)
- continue;
-
- %objectNearExit.damage(%player, %exit.getTransform(), 10000, "Telefrag");
- }
- // The second case occurs when the bounds of the trigger are much larger
- // than the bounding box of the player. (So multiple players can exist within the
- // same trigger). For this case we check all objects contained within the trigger
- // and telefrag all players.
- %objectsInExit = %exit.getNumObjects();
-
- // Loop through all objects in the teleporter exit
- // And kill any players
- for(%i = 0; %i < %objectsInExit; %i++)
- {
- %objectInTeleporter = %exit.getObject(%i);
-
- if (!%objectInTeleporter.isMemberOfClass("Player"))
- continue;
-
- // Avoid killing the player that is teleporting in the case of two
- // Teleporters near eachother.
- if (%objectInTeleporter == %player)
- continue;
-
- %objectInTeleporter.damage(%player, %exit.getTransform(), 10000, "Telefrag");
- }
- }
- // Customized kill message for telefrag deaths
- function sendMsgClientKilled_Telefrag(%msgType, %client, %sourceClient, %damLoc)
- {
- messageAll(%msgType, '%1 was telefragged by %2!', %client.playerName, %sourceClient.playerName);
- }
|