player.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. // Timeouts for corpse deletion.
  23. $CorpseTimeoutValue = 45 * 1000;
  24. //----------------------------------------------------------------------------
  25. // Player Datablock methods
  26. //----------------------------------------------------------------------------
  27. function PlayerData::onAdd(%this, %obj)
  28. {
  29. // Vehicle timeout
  30. %obj.mountVehicle = true;
  31. // Default dynamic armor stats
  32. %obj.setRechargeRate(%this.rechargeRate);
  33. %obj.setRepairRate(0);
  34. }
  35. function PlayerData::onRemove(%this, %obj)
  36. {
  37. if (%obj.client.player == %obj)
  38. %obj.client.player = 0;
  39. }
  40. function PlayerData::onNewDataBlock(%this, %obj)
  41. {
  42. }
  43. //----------------------------------------------------------------------------
  44. function PlayerData::onMount(%this, %obj, %vehicle, %node)
  45. {
  46. // Node 0 is the pilot's position, we need to dismount his weapon.
  47. if (%node == 0)
  48. {
  49. %obj.setTransform("0 0 0 0 0 1 0");
  50. %obj.setActionThread(%vehicle.getDatablock().mountPose[%node], true, true);
  51. %obj.lastWeapon = %obj.getMountedImage($WeaponSlot);
  52. %obj.unmountImage($WeaponSlot);
  53. %obj.setControlObject(%vehicle);
  54. if(%obj.getClassName() $= "Player")
  55. commandToClient(%obj.client, 'toggleVehicleMap', true);
  56. }
  57. else
  58. {
  59. if (%vehicle.getDataBlock().mountPose[%node] !$= "")
  60. %obj.setActionThread(%vehicle.getDatablock().mountPose[%node]);
  61. else
  62. %obj.setActionThread("root", true);
  63. }
  64. }
  65. function PlayerData::onUnmount(%this, %obj, %vehicle, %node)
  66. {
  67. if (%node == 0)
  68. {
  69. %obj.mountImage(%obj.lastWeapon, $WeaponSlot);
  70. %obj.setControlObject("");
  71. }
  72. }
  73. function PlayerData::doDismount(%this, %obj, %forced)
  74. {
  75. //echo("\c4PlayerData::doDismount(" @ %this @", "@ %obj.client.nameBase @", "@ %forced @")");
  76. // This function is called by player.cc when the jump trigger
  77. // is true while mounted
  78. %vehicle = %obj.mVehicle;
  79. if (!%obj.isMounted() || !isObject(%vehicle))
  80. return;
  81. // Vehicle must be at rest!
  82. if ((VectorLen(%vehicle.getVelocity()) <= %vehicle.getDataBlock().maxDismountSpeed ) || %forced)
  83. {
  84. // Position above dismount point
  85. %pos = getWords(%obj.getTransform(), 0, 2);
  86. %rot = getWords(%obj.getTransform(), 3, 6);
  87. %oldPos = %pos;
  88. %vec[0] = " -1 0 0";
  89. %vec[1] = " 0 0 1";
  90. %vec[2] = " 0 0 -1";
  91. %vec[3] = " 1 0 0";
  92. %vec[4] = "0 -1 0";
  93. %impulseVec = "0 0 0";
  94. %vec[0] = MatrixMulVector(%obj.getTransform(), %vec[0]);
  95. // Make sure the point is valid
  96. %pos = "0 0 0";
  97. %numAttempts = 5;
  98. %success = -1;
  99. for (%i = 0; %i < %numAttempts; %i++)
  100. {
  101. %pos = VectorAdd(%oldPos, VectorScale(%vec[%i], 3));
  102. if (%obj.checkDismountPoint(%oldPos, %pos))
  103. {
  104. %success = %i;
  105. %impulseVec = %vec[%i];
  106. break;
  107. }
  108. }
  109. if (%forced && %success == -1)
  110. %pos = %oldPos;
  111. %obj.mountVehicle = false;
  112. %obj.schedule(4000, "mountVehicles", true);
  113. // Position above dismount point
  114. %obj.unmount();
  115. %obj.setTransform(%pos SPC %rot);//%obj.setTransform(%pos);
  116. //%obj.playAudio(0, UnmountVehicleSound);
  117. %obj.applyImpulse(%pos, VectorScale(%impulseVec, %obj.getDataBlock().mass));
  118. // Set player velocity when ejecting
  119. %vel = %obj.getVelocity();
  120. %vec = vectorDot( %vel, vectorNormalize(%vel));
  121. if(%vec > 50)
  122. {
  123. %scale = 50 / %vec;
  124. %obj.setVelocity(VectorScale(%vel, %scale));
  125. }
  126. //%obj.vehicleTurret = "";
  127. }
  128. else
  129. messageClient(%obj.client, 'msgUnmount', '\c2Cannot exit %1 while moving.', %vehicle.getDataBlock().nameTag);
  130. }
  131. //----------------------------------------------------------------------------
  132. function PlayerData::onCollision(%this, %obj, %col)
  133. {
  134. if (!isObject(%col) || %obj.getState() $= "Dead")
  135. return;
  136. // Try and pickup all items
  137. if (%col.getClassName() $= "Item")
  138. {
  139. %obj.pickup(%col);
  140. return;
  141. }
  142. // Mount vehicles
  143. if (%col.getType() & $TypeMasks::GameBaseObjectType)
  144. {
  145. %db = %col.getDataBlock();
  146. if ((%db.getClassName() $= "WheeledVehicleData" ) && %obj.mountVehicle && %obj.getState() $= "Move" && %col.mountable)
  147. {
  148. // Only mount drivers for now.
  149. ServerConnection.setFirstPerson(0);
  150. // For this specific example, only one person can fit
  151. // into a vehicle
  152. %mount = %col.getMountNodeObject(0);
  153. if(%mount)
  154. return;
  155. // For this specific FPS Example, always mount the player
  156. // to node 0
  157. %node = 0;
  158. %col.mountObject(%obj, %node);
  159. %obj.mVehicle = %col;
  160. }
  161. }
  162. }
  163. function PlayerData::onImpact(%this, %obj, %collidedObject, %vec, %vecLen)
  164. {
  165. %obj.damage(0, VectorAdd(%obj.getPosition(), %vec), %vecLen * %this.speedDamageScale, "Impact");
  166. }
  167. //----------------------------------------------------------------------------
  168. function PlayerData::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
  169. {
  170. if (!isObject(%obj) || %obj.getState() $= "Dead" || !%damage)
  171. return;
  172. %obj.applyDamage(%damage);
  173. %location = "Body";
  174. // Deal with client callbacks here because we don't have this
  175. // information in the onDamage or onDisable methods
  176. %client = %obj.client;
  177. %sourceClient = %sourceObject ? %sourceObject.client : 0;
  178. if (isObject(%client))
  179. {
  180. // Determine damage direction
  181. if (%damageType !$= "Suicide")
  182. %obj.setDamageDirection(%sourceObject, %position);
  183. if (%obj.getState() $= "Dead")
  184. %client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
  185. }
  186. }
  187. function PlayerData::onDamage(%this, %obj, %delta)
  188. {
  189. // This method is invoked by the ShapeBase code whenever the
  190. // object's damage level changes.
  191. if (%delta > 0 && %obj.getState() !$= "Dead")
  192. {
  193. // Apply a damage flash
  194. %obj.setDamageFlash(1);
  195. // If the pain is excessive, let's hear about it.
  196. if (%delta > 10)
  197. %obj.playPain();
  198. }
  199. }
  200. // ----------------------------------------------------------------------------
  201. // The player object sets the "disabled" state when damage exceeds it's
  202. // maxDamage value. This is method is invoked by ShapeBase state mangement code.
  203. // If we want to deal with the damage information that actually caused this
  204. // death, then we would have to move this code into the script "damage" method.
  205. function PlayerData::onDisabled(%this, %obj, %state)
  206. {
  207. // Release the main weapon trigger
  208. %obj.setImageTrigger(0, false);
  209. // Toss current mounted weapon and ammo if any
  210. %item = %obj.getMountedImage($WeaponSlot).item;
  211. if (isObject(%item))
  212. {
  213. %amount = %obj.getInventory(%item.image.ammo);
  214. if (!%item.image.clip)
  215. warn("No clip exists to throw for item ", %item);
  216. if(%amount)
  217. %obj.throw(%item.image.clip, 1);
  218. }
  219. // Toss out a health patch
  220. %obj.tossPatch();
  221. %obj.playDeathCry();
  222. %obj.playDeathAnimation();
  223. //%obj.setDamageFlash(0.75);
  224. // Disable any vehicle map
  225. commandToClient(%obj.client, 'toggleVehicleMap', false);
  226. // Schedule corpse removal. Just keeping the place clean.
  227. %obj.schedule($CorpseTimeoutValue - 1000, "startFade", 1000, 0, true);
  228. %obj.schedule($CorpseTimeoutValue, "delete");
  229. }
  230. //-----------------------------------------------------------------------------
  231. function PlayerData::onLeaveMissionArea(%this, %obj)
  232. {
  233. //echo("\c4Leaving Mission Area at POS:"@ %obj.getPosition());
  234. // Inform the client
  235. %obj.client.onLeaveMissionArea();
  236. // Damage over time and kill the coward!
  237. //%obj.setDamageDt(0.2, "MissionAreaDamage");
  238. }
  239. function PlayerData::onEnterMissionArea(%this, %obj)
  240. {
  241. //echo("\c4Entering Mission Area at POS:"@ %obj.getPosition());
  242. // Inform the client
  243. %obj.client.onEnterMissionArea();
  244. // Stop the punishment
  245. //%obj.clearDamageDt();
  246. }
  247. //-----------------------------------------------------------------------------
  248. function PlayerData::onEnterLiquid(%this, %obj, %coverage, %type)
  249. {
  250. //echo("\c4this:"@ %this @" object:"@ %obj @" just entered water of type:"@ %type @" for "@ %coverage @"coverage");
  251. }
  252. function PlayerData::onLeaveLiquid(%this, %obj, %type)
  253. {
  254. //
  255. }
  256. //-----------------------------------------------------------------------------
  257. function PlayerData::onTrigger(%this, %obj, %triggerNum, %val)
  258. {
  259. // This method is invoked when the player receives a trigger move event.
  260. // The player automatically triggers slot 0 and slot one off of triggers #
  261. // 0 & 1. Trigger # 2 is also used as the jump key.
  262. }
  263. //-----------------------------------------------------------------------------
  264. function PlayerData::onPoseChange(%this, %obj, %oldPose, %newPose)
  265. {
  266. // Set the script anim prefix to be that of the current pose
  267. %obj.setImageScriptAnimPrefix( $WeaponSlot, addTaggedString(%newPose) );
  268. }
  269. //-----------------------------------------------------------------------------
  270. function PlayerData::onStartSprintMotion(%this, %obj)
  271. {
  272. %obj.setImageGenericTrigger($WeaponSlot, 0, true);
  273. }
  274. function PlayerData::onStopSprintMotion(%this, %obj)
  275. {
  276. %obj.setImageGenericTrigger($WeaponSlot, 0, false);
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Player methods
  280. //-----------------------------------------------------------------------------
  281. //----------------------------------------------------------------------------
  282. function Player::kill(%this, %damageType)
  283. {
  284. %this.damage(0, %this.getPosition(), 10000, %damageType);
  285. }
  286. //----------------------------------------------------------------------------
  287. function Player::mountVehicles(%this, %bool)
  288. {
  289. // If set to false, this variable disables vehicle mounting.
  290. %this.mountVehicle = %bool;
  291. }
  292. function Player::isPilot(%this)
  293. {
  294. %vehicle = %this.getObjectMount();
  295. // There are two "if" statements to avoid a script warning.
  296. if (%vehicle)
  297. if (%vehicle.getMountNodeObject(0) == %this)
  298. return true;
  299. return false;
  300. }
  301. //----------------------------------------------------------------------------
  302. function Player::playDeathAnimation(%this)
  303. {
  304. %numDeathAnimations = %this.getNumDeathAnimations();
  305. if ( %numDeathAnimations > 0 )
  306. {
  307. if (isObject(%this.client))
  308. {
  309. if (%this.client.deathIdx++ > %numDeathAnimations)
  310. %this.client.deathIdx = 1;
  311. %this.setActionThread("Death" @ %this.client.deathIdx);
  312. }
  313. else
  314. {
  315. %rand = getRandom(1, %numDeathAnimations);
  316. %this.setActionThread("Death" @ %rand);
  317. }
  318. }
  319. }
  320. function Player::playCelAnimation(%this, %anim)
  321. {
  322. if (%this.getState() !$= "Dead")
  323. %this.setActionThread("cel"@%anim);
  324. }
  325. //----------------------------------------------------------------------------
  326. function Player::playDeathCry(%this)
  327. {
  328. %this.playAudio(0, DeathCrySound);
  329. }
  330. function Player::playPain(%this)
  331. {
  332. %this.playAudio(0, PainCrySound);
  333. }
  334. // ----------------------------------------------------------------------------
  335. function Player::setDamageDirection(%player, %sourceObject, %damagePos)
  336. {
  337. if (isObject(%sourceObject))
  338. {
  339. if (%sourceObject.isField(initialPosition))
  340. {
  341. // Projectiles have this field set to the muzzle point of
  342. // the firing weapon at the time the projectile was created.
  343. // This gives a damage direction towards the firing player,
  344. // turret, vehicle, etc. Bullets and weapon fired grenades
  345. // are examples of projectiles.
  346. %damagePos = %sourceObject.initialPosition;
  347. }
  348. else
  349. {
  350. // Other objects that cause damage, such as mines, use their own
  351. // location as the damage position. This gives a damage direction
  352. // towards the explosive origin rather than the person that lay the
  353. // explosives.
  354. %damagePos = %sourceObject.getPosition();
  355. }
  356. }
  357. // Rotate damage vector into object space
  358. %damageVec = VectorSub(%damagePos, %player.getWorldBoxCenter());
  359. %damageVec = VectorNormalize(%damageVec);
  360. %damageVec = MatrixMulVector(%player.client.getCameraObject().getInverseTransform(), %damageVec);
  361. // Determine largest component of damage vector to get direction
  362. %vecComponents = -%damageVec.x SPC %damageVec.x SPC -%damageVec.y SPC %damageVec.y SPC -%damageVec.z SPC %damageVec.z;
  363. %vecDirections = "Left" SPC "Right" SPC "Bottom" SPC "Front" SPC "Bottom" SPC "Top";
  364. %max = -1;
  365. for (%i = 0; %i < 6; %i++)
  366. {
  367. %value = getWord(%vecComponents, %i);
  368. if (%value > %max)
  369. {
  370. %max = %value;
  371. %damageDir = getWord(%vecDirections, %i);
  372. }
  373. }
  374. commandToClient(%player.client, 'setDamageDirection', %damageDir);
  375. }
  376. function Player::use(%player, %data)
  377. {
  378. // No mounting/using weapons when you're driving!
  379. if (%player.isPilot())
  380. return(false);
  381. Parent::use(%player, %data);
  382. }