teleporter.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //-----------------------------------------------------------------------------
  23. // Trigger-derrived teleporter object. Teleports an object from it's entrance to
  24. // it's exit if one is defined.
  25. function TeleporterTrigger::onAdd( %this, %teleporter )
  26. {
  27. // Setup default parameters.
  28. if ( %teleporter.exit $= "" )
  29. %teleporter.exit = "NameOfTeleporterExit";
  30. if ( %teleporter.teleporterCooldown $= "" )
  31. %teleporter.teleporterCooldown = %this.teleporterCooldown;
  32. if ( %teleporter.exitVelocityScale $= "" )
  33. %teleporter.exitVelocityScale = %this.exitVelocityScale;
  34. if ( %teleporter.reorientPlayer $= "" )
  35. %teleporter.reorientPlayer = %this.reorientPlayer;
  36. if ( %teleporter.oneSided $= "" )
  37. %teleporter.oneSided = %this.oneSided;
  38. if ( %teleporter.entranceEffect $= "" )
  39. %teleporter.entranceEffect = %this.entranceEffect;
  40. if ( %teleporter.exitEffect $= "" )
  41. %teleporter.exitEffect = %this.exitEffect;
  42. // We do not want to save this variable between levels,
  43. // clear it out every time the teleporter is added
  44. // to the scene.
  45. %teleporter.timeOfLastTeleport = "";
  46. }
  47. function TeleporterTrigger::onLeaveTrigger(%this,%trigger,%obj)
  48. {
  49. // This is called after onEnterTrigger for BOTH
  50. // The teleporter's entrance and exit
  51. %obj.isTeleporting = false;
  52. }
  53. //ARGS:
  54. // %this - The teleporter datablock.
  55. // %entrance - The teleporter the player has entered (The one calling this function).
  56. // %obj - The object that entered the teleporter.
  57. function TeleporterTrigger::onEnterTrigger(%this, %entrance, %obj)
  58. {
  59. // Get the location of our target position
  60. %exit = nameToID(%entrance.exit);
  61. // Check if the the teleport is valid.
  62. %valid = %this.verifyObject(%obj, %entrance, %exit);
  63. // Bail out early if we cannot complete this teleportation
  64. if (!%valid)
  65. return;
  66. // Kill any players in the exit teleporter.
  67. %this.telefrag(%obj, %exit);
  68. // Create our entrance effects on all clients.
  69. if (isObject(%entrance.entranceEffect))
  70. {
  71. for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
  72. commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %entrance.position, %entrance.entranceEffect.getId());
  73. }
  74. // Teleport the player to the exit teleporter.
  75. %this.teleportPlayer(%obj, %exit);
  76. // Create our exit effects on all clients.
  77. if (isObject(%exit.exitEffect))
  78. {
  79. for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
  80. commandToClient(ClientGroup.getObject(%idx), 'PlayTeleportEffect', %exit.position, %exit.exitEffect.getId());
  81. }
  82. // Record what time we last teleported so we can determine if enough
  83. // time has elapsed to teleport again
  84. %entrance.timeOfLastTeleport = getSimTime();
  85. // If this is a bidirectional teleporter, log it's exit too.
  86. if (%exit.exit $= %entrance.name)
  87. %exit.timeOfLastTeleport = %entrance.timeOfLastTeleport;
  88. // Tell the client to play the 2D sound for the player that teleported.
  89. if (isObject(%this.teleportSound) && isObject(%obj.client))
  90. %obj.client.play2D(%this.teleportSound);
  91. }
  92. // Here we verify that the teleport is valid.
  93. // Tests go here like if the object is of a 'teleportable' type, if the
  94. // given teleporter has an exit defined, etc.
  95. function TeleporterTrigger::verifyObject(%this, %obj, %entrance, %exit)
  96. {
  97. // Bail out early if we couldn't find an exit for this teleporter.
  98. if (!isObject(%exit))
  99. {
  100. logError("Cound not find an exit for " @ %entrance.name @ ".");
  101. return false;
  102. }
  103. // If the entrance is once sided, make sure the object
  104. // approached it from it's front.
  105. if (%entrance.oneSided)
  106. {
  107. %dotProduct = VectorDot(%entrance.getForwardVector(), %obj.getVelocity());
  108. if (%dotProduct > 0)
  109. return false;
  110. }
  111. // If we are coming directly from another teleporter and it happens
  112. // to be bidirectional, We need to avoid ending sending objects through
  113. // an infinite loop.
  114. if (%obj.isTeleporting)
  115. return false;
  116. // We only want to teleport players
  117. // So bail out early if we have found any
  118. // other object.
  119. if (!%obj.isMemberOfClass("Player"))
  120. return false;
  121. if (%entrance.timeOfLastTeleport > 0 && %entrance.teleporterCooldown > 0)
  122. {
  123. // Get the current time, subtract it from the time it last teleported
  124. // And compare the difference to see if enough time has elapsed to
  125. // activate the teleporter again.
  126. %currentTime = getSimTime();
  127. %timeDifference = %currentTime - %entrance.timeOfLastTeleport;
  128. %db = %entrance.getDatablock();
  129. if (%timeDifference <= %db.teleporterCooldown)
  130. return false;
  131. }
  132. return true;
  133. }
  134. // Function to teleport object %player to teleporter %exit.
  135. function TeleporterTrigger::teleportPlayer(%this, %player, %exit)
  136. {
  137. // Teleport our player to the exit teleporter.
  138. if (%exit.reorientPlayer)
  139. %targetPosition = %exit.getTransform();
  140. else
  141. {
  142. %pos = %exit.getPosition();
  143. %rot = getWords(%player.getTransform(), 3, 6);
  144. %targetPosition = %pos SPC %rot;
  145. }
  146. %player.setTransform(%targetPosition);
  147. // Adjust the player's velocity by the Exit location's scale.
  148. %player.setVelocity(vectorScale(%player.getVelocity(), %exit.exitVelocityScale));
  149. // Prevent the object from doing an immediate second teleport
  150. // In the case of a bidirectional teleporter
  151. %player.isTeleporting = true;
  152. }
  153. // Telefrag is a term used in multiplayer gaming when a player takes a teleporter
  154. // while another player is occupying it's exit. The player at the exit location
  155. // is killed, allowing the original player to arrive at the teleporter.
  156. function TeleporterTrigger::teleFrag(%this, %player, %exit)
  157. {
  158. // When a telefrag happens, there are two cases we have to consider.
  159. // The first case occurs when the player's bounding box is much larger than the exit location,
  160. // it is possible to have players colide even though a player is not within the bounds
  161. // of the trigger Because of this we first check a radius the size of a player's bounding
  162. // box around the exit location.
  163. // Get the bounding box of the player
  164. %boundingBoxSize = %player.getDatablock().boundingBox;
  165. %radius = getWord(%boundingBoxSize, 0);
  166. %boxSizeY = getWord(%boundingBoxSize, 1);
  167. %boxSizeZ = getWord(%boundingBoxSize, 2);
  168. // Use the largest dimention as the radius to check
  169. if (%boxSizeY > %radius)
  170. %radius = %boxSizeY;
  171. if (%boxSizeZ > %radius)
  172. %radius = %boxSizeZ;
  173. %position = %exit.getPosition();
  174. %mask = $TypeMasks::PlayerObjectType;
  175. // Check all objects within the found radius of the exit location, and telefrag
  176. // any players that meet the conditions.
  177. initContainerRadiusSearch( %position, %radius, %mask );
  178. while ( (%objectNearExit = containerSearchNext()) != 0 )
  179. {
  180. if (!%objectNearExit.isMemberOfClass("Player"))
  181. continue;
  182. // Avoid killing the player that is teleporting in the case of two
  183. // Teleporters near eachother.
  184. if (%objectNearExit == %player)
  185. continue;
  186. %objectNearExit.damage(%player, %exit.getTransform(), 10000, "Telefrag");
  187. }
  188. // The second case occurs when the bounds of the trigger are much larger
  189. // than the bounding box of the player. (So multiple players can exist within the
  190. // same trigger). For this case we check all objects contained within the trigger
  191. // and telefrag all players.
  192. %objectsInExit = %exit.getNumObjects();
  193. // Loop through all objects in the teleporter exit
  194. // And kill any players
  195. for(%i = 0; %i < %objectsInExit; %i++)
  196. {
  197. %objectInTeleporter = %exit.getObject(%i);
  198. if (!%objectInTeleporter.isMemberOfClass("Player"))
  199. continue;
  200. // Avoid killing the player that is teleporting in the case of two
  201. // Teleporters near eachother.
  202. if (%objectInTeleporter == %player)
  203. continue;
  204. %objectInTeleporter.damage(%player, %exit.getTransform(), 10000, "Telefrag");
  205. }
  206. }
  207. // Customized kill message for telefrag deaths
  208. function sendMsgClientKilled_Telefrag(%msgType, %client, %sourceClient, %damLoc)
  209. {
  210. messageAll(%msgType, '%1 was telefragged by %2!', %client.playerName, %sourceClient.playerName);
  211. }