turret.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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. // Respawntime is the amount of time it takes for a static "auto-respawn"
  23. // turret to re-appear after it's been picked up. Any turret marked as "static"
  24. // is automaticlly respawned.
  25. $TurretShape::RespawnTime = 30 * 1000;
  26. // DestroyedFadeDelay is the how long a destroyed turret sticks around before it
  27. // fades out and is deleted.
  28. $TurretShape::DestroyedFadeDelay = 5 * 1000;
  29. // ----------------------------------------------------------------------------
  30. // TurretShapeData
  31. // ----------------------------------------------------------------------------
  32. function TurretShapeData::onAdd(%this, %obj)
  33. {
  34. %obj.setRechargeRate(%this.rechargeRate);
  35. %obj.setEnergyLevel(%this.MaxEnergy);
  36. %obj.setRepairRate(0);
  37. if (%obj.mountable || %obj.mountable $= "")
  38. %this.isMountable(%obj, true);
  39. else
  40. %this.isMountable(%obj, false);
  41. if (%this.nameTag !$= "")
  42. %obj.setShapeName(%this.nameTag);
  43. // Mount weapons
  44. for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
  45. {
  46. // Handle inventory
  47. %obj.incInventory(%this.weapon[%i], 1);
  48. %obj.incInventory(%this.weaponAmmo[%i], %this.weaponAmmoAmount[%i]);
  49. // Mount the image
  50. %obj.mountImage(%this.weapon[%i].image, %i, %this.startLoaded);
  51. %obj.setImageGenericTrigger(%i, 0, false); // Used to indicate the turret is destroyed
  52. }
  53. if (%this.enterSequence !$= "")
  54. {
  55. %obj.entranceThread = 0;
  56. %obj.playThread(%obj.entranceThread, %this.enterSequence);
  57. %obj.pauseThread(%obj.entranceThread);
  58. }
  59. else
  60. {
  61. %obj.entranceThread = -1;
  62. }
  63. }
  64. function TurretShapeData::onRemove(%this, %obj)
  65. {
  66. //echo("\c4TurretShapeData::onRemove("@ %this.getName() @", "@ %obj.getClassName() @")");
  67. // if there are passengers/driver, kick them out
  68. for(%i = 0; %i < %this.numMountPoints; %i++)
  69. {
  70. if (%obj.getMountNodeObject(%i))
  71. {
  72. %passenger = %obj.getMountNodeObject(%i);
  73. %passenger.getDataBlock().doDismount(%passenger, true);
  74. }
  75. }
  76. }
  77. // This is on MissionGroup so it doesn't happen when the mission has ended
  78. function MissionGroup::respawnTurret(%this, %datablock, %className, %transform, %static, %respawn)
  79. {
  80. %turret = new (%className)()
  81. {
  82. datablock = %datablock;
  83. static = %static;
  84. respawn = %respawn;
  85. };
  86. %turret.setTransform(%transform);
  87. MissionGroup.add(%turret);
  88. return %turret;
  89. }
  90. // ----------------------------------------------------------------------------
  91. // TurretShapeData damage state
  92. // ----------------------------------------------------------------------------
  93. // This method is called by weapons fire
  94. function TurretShapeData::damage(%this, %turret, %sourceObject, %position, %damage, %damageType)
  95. {
  96. //echo("\TurretShapeData::damage(" @ %turret @ ", "@ %sourceObject @ ", " @ %position @ ", "@ %damage @ ", "@ %damageType @ ")");
  97. if (%turret.getState() $= "Dead")
  98. return;
  99. %turret.applyDamage(%damage);
  100. // Update the numerical Health HUD
  101. %mountedObject = %turret.getObjectMount();
  102. if (%mountedObject)
  103. %mountedObject.updateHealth();
  104. // Kill any occupants
  105. if (%turret.getState() $= "Dead")
  106. {
  107. for (%i = 0; %i < %this.numMountPoints; %i++)
  108. {
  109. %player = %turret.getMountNodeObject(%i);
  110. if (%player != 0)
  111. %player.killWithSource(%sourceObject, "InsideTurret");
  112. }
  113. }
  114. }
  115. function TurretShapeData::onDamage(%this, %obj, %delta)
  116. {
  117. // This method is invoked by the ShapeBase code whenever the
  118. // object's damage level changes.
  119. }
  120. function TurretShapeData::onDestroyed(%this, %obj, %lastState)
  121. {
  122. // This method is invoked by the ShapeBase code whenever the
  123. // object's damage state changes.
  124. // Fade out the destroyed object. Then schedule a return.
  125. %obj.startFade(1000, $TurretShape::DestroyedFadeDelay, true);
  126. %obj.schedule($TurretShape::DestroyedFadeDelay + 1000, "delete");
  127. if (%obj.doRespawn())
  128. {
  129. MissionGroup.schedule($TurretShape::RespawnTime, "respawnTurret", %this, %obj.getClassName(), %obj.getTransform(), true, true);
  130. }
  131. }
  132. function TurretShapeData::onDisabled(%this, %obj, %lastState)
  133. {
  134. // This method is invoked by the ShapeBase code whenever the
  135. // object's damage state changes.
  136. }
  137. function TurretShapeData::onEnabled(%this, %obj, %lastState)
  138. {
  139. // This method is invoked by the ShapeBase code whenever the
  140. // object's damage state changes.
  141. }
  142. // ----------------------------------------------------------------------------
  143. // TurretShapeData player mounting and dismounting
  144. // ----------------------------------------------------------------------------
  145. function TurretShapeData::isMountable(%this, %obj, %val)
  146. {
  147. %obj.mountable = %val;
  148. }
  149. function TurretShapeData::onMountObject(%this, %turret, %player, %node)
  150. {
  151. if (%turret.entranceThread >= 0)
  152. {
  153. %turret.setThreadDir(%turret.entranceThread, true);
  154. %turret.setThreadPosition(%turret.entranceThread, 0);
  155. %turret.playThread(%turret.entranceThread, "");
  156. }
  157. }
  158. function TurretShapeData::onUnmountObject(%this, %turret, %player)
  159. {
  160. if (%turret.entranceThread >= 0)
  161. {
  162. // Play the entrance thread backwards for an exit
  163. %turret.setThreadDir(%turret.entranceThread, false);
  164. %turret.setThreadPosition(%turret.entranceThread, 1);
  165. %turret.playThread(%turret.entranceThread, "");
  166. }
  167. }
  168. function TurretShapeData::mountPlayer(%this, %turret, %player)
  169. {
  170. //echo("\c4TurretShapeData::mountPlayer("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
  171. if (isObject(%turret) && %turret.getDamageState() !$= "Destroyed")
  172. {
  173. //%player.startFade(1000, 0, true);
  174. //%this.schedule(1000, "setMountTurret", %turret, %player);
  175. //%player.schedule(1500, "startFade", 1000, 0, false);
  176. %this.setMountTurret(%turret, %player);
  177. }
  178. }
  179. function TurretShapeData::setMountTurret(%this, %turret, %player)
  180. {
  181. //echo("\c4TurretShapeData::setMountTurret("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
  182. if (isObject(%turret) && %turret.getDamageState() !$= "Destroyed")
  183. {
  184. %node = %this.findEmptySeat(%turret, %player);
  185. if (%node >= 0)
  186. {
  187. //echo("\c4Mount Node: "@ %node);
  188. %turret.mountObject(%player, %node);
  189. //%player.playAudio(0, MountVehicleSound);
  190. %player.mVehicle = %turret;
  191. }
  192. }
  193. }
  194. function TurretShapeData::findEmptySeat(%this, %turret, %player)
  195. {
  196. //echo("\c4This turret has "@ %this.numMountPoints @" mount points.");
  197. for (%i = 0; %i < %this.numMountPoints; %i++)
  198. {
  199. %node = %turret.getMountNodeObject(%i);
  200. if (%node == 0)
  201. return %i;
  202. }
  203. return -1;
  204. }
  205. function TurretShapeData::switchSeats(%this, %turret, %player)
  206. {
  207. for (%i = 0; %i < %this.numMountPoints; %i++)
  208. {
  209. %node = %turret.getMountNodeObject(%i);
  210. if (%node == %player || %node > 0)
  211. continue;
  212. if (%node == 0)
  213. return %i;
  214. }
  215. return -1;
  216. }
  217. function TurretShapeData::onMount(%this, %turret, %player, %node)
  218. {
  219. //echo("\c4TurretShapeData::onMount("@ %this.getName() @", "@ %turret @", "@ %player.client.nameBase @")");
  220. %player.client.RefreshVehicleHud(%turret, %this.reticle, %this.zoomReticle);
  221. //%player.client.UpdateVehicleHealth(%turret);
  222. }
  223. function TurretShapeData::onUnmount(%this, %turret, %player, %node)
  224. {
  225. //echo("\c4TurretShapeData::onUnmount(" @ %this.getName() @ ", " @ %turret @ ", " @ %player.client.nameBase @ ")");
  226. %player.client.RefreshVehicleHud(0, "", "");
  227. }
  228. // ----------------------------------------------------------------------------
  229. // TurretShape damage
  230. // ----------------------------------------------------------------------------
  231. // This method is called by weapons fire
  232. function TurretShape::damage(%this, %sourceObject, %position, %damage, %damageType)
  233. {
  234. //echo("\TurretShape::damage(" @ %this @ ", "@ %sourceObject @ ", " @ %position @ ", "@ %damage @ ", "@ %damageType @ ")");
  235. %this.getDataBlock().damage(%this, %sourceObject, %position, %damage, %damageType);
  236. }
  237. // ----------------------------------------------------------------------------
  238. // TurretDamage
  239. // ----------------------------------------------------------------------------
  240. // Customized kill message for deaths caused by turrets
  241. function sendMsgClientKilled_TurretDamage( %msgType, %client, %sourceClient, %damLoc )
  242. {
  243. if ( %sourceClient $= "" ) // editor placed turret
  244. messageAll( %msgType, '%1 was shot down by a turret!', %client.playerName );
  245. else if ( %sourceClient == %client ) // own mine
  246. messageAll( %msgType, '%1 kill by his own turret!', %client.playerName );
  247. else // enemy placed mine
  248. messageAll( %msgType, '%1 was killed by a turret of %2!', %client.playerName, %sourceClient.playerName );
  249. }
  250. // ----------------------------------------------------------------------------
  251. // AITurretShapeData
  252. // ----------------------------------------------------------------------------
  253. function AITurretShapeData::onAdd(%this, %obj)
  254. {
  255. Parent::onAdd(%this, %obj);
  256. %obj.mountable = false;
  257. }
  258. // Player has thrown a deployable turret. This copies from ItemData::onThrow()
  259. function AITurretShapeData::onThrow(%this, %user, %amount)
  260. {
  261. // Remove the object from the inventory
  262. if (%amount $= "")
  263. %amount = 1;
  264. if (%this.maxInventory !$= "")
  265. if (%amount > %this.maxInventory)
  266. %amount = %this.maxInventory;
  267. if (!%amount)
  268. return 0;
  269. %user.decInventory(%this,%amount);
  270. // Construct the actual object in the world, and add it to
  271. // the mission group so it's cleaned up when the mission is
  272. // done. The turret's rotation matches the player's.
  273. %rot = %user.getEulerRotation();
  274. %obj = new AITurretShape()
  275. {
  276. datablock = %this;
  277. rotation = "0 0 1 " @ getWord(%rot, 2);
  278. count = 1;
  279. sourceObject = %user;
  280. client = %user.client;
  281. isAiControlled = true;
  282. };
  283. MissionGroup.add(%obj);
  284. // Let the turret know that we're a firend
  285. %obj.addToIgnoreList(%user);
  286. // We need to add this turret to a list on the client so that if we die,
  287. // the turret will still ignore our player.
  288. %client = %user.client;
  289. if (%client)
  290. {
  291. if (!%client.ownedTurrets)
  292. {
  293. %client.ownedTurrets = new SimSet();
  294. }
  295. // Go through the client's owned turret list. Make sure we're
  296. // a friend of every turret and every turret is a friend of ours.
  297. // Commence hugging!
  298. for (%i=0; %i<%client.ownedTurrets.getCount(); %i++)
  299. {
  300. %turret = %client.ownedTurrets.getObject(%i);
  301. %turret.addToIgnoreList(%obj);
  302. %obj.addToIgnoreList(%turret);
  303. }
  304. // Add ourselves to the client's owned list.
  305. %client.ownedTurrets.add(%obj);
  306. }
  307. return %obj;
  308. }
  309. function AITurretShapeData::onDestroyed(%this, %turret, %lastState)
  310. {
  311. // This method is invoked by the ShapeBase code whenever the
  312. // object's damage state changes.
  313. %turret.playAudio(0, TurretDestroyed);
  314. %turret.setAllGunsFiring(false);
  315. %turret.resetTarget();
  316. %turret.setTurretState( "Destroyed", true );
  317. // Set the weapons to destoryed
  318. for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
  319. {
  320. %turret.setImageGenericTrigger(%i, 0, true);
  321. }
  322. Parent::onDestroyed(%this, %turret, %lastState);
  323. }
  324. function AITurretShapeData::OnScanning(%this, %turret)
  325. {
  326. //echo("AITurretShapeData::OnScanning: " SPC %this SPC %turret);
  327. %turret.startScanForTargets();
  328. %turret.playAudio(0, TurretScanningSound);
  329. }
  330. function AITurretShapeData::OnTarget(%this, %turret)
  331. {
  332. //echo("AITurretShapeData::OnTarget: " SPC %this SPC %turret);
  333. %turret.startTrackingTarget();
  334. %turret.playAudio(0, TargetAquiredSound);
  335. }
  336. function AITurretShapeData::OnNoTarget(%this, %turret)
  337. {
  338. //echo("AITurretShapeData::OnNoTarget: " SPC %this SPC %turret);
  339. %turret.setAllGunsFiring(false);
  340. %turret.recenterTurret();
  341. %turret.playAudio(0, TargetLostSound);
  342. }
  343. function AITurretShapeData::OnFiring(%this, %turret)
  344. {
  345. //echo("AITurretShapeData::OnFiring: " SPC %this SPC %turret);
  346. %turret.setAllGunsFiring(true);
  347. }
  348. function AITurretShapeData::OnThrown(%this, %turret)
  349. {
  350. //echo("AITurretShapeData::OnThrown: " SPC %this SPC %turret);
  351. %turret.playAudio(0, TurretThrown);
  352. }
  353. function AITurretShapeData::OnDeploy(%this, %turret)
  354. {
  355. //echo("AITurretShapeData::OnDeploy: " SPC %this SPC %turret);
  356. // Set the weapons to loaded
  357. for(%i = 0; %i < %this.numWeaponMountPoints; %i++)
  358. {
  359. %turret.setImageLoaded(%i, true);
  360. }
  361. %turret.playAudio(0, TurretActivatedSound);
  362. }
  363. // ----------------------------------------------------------------------------
  364. // Player deployable turret
  365. // ----------------------------------------------------------------------------
  366. // Cannot use the Weapon class for deployable turrets as it is already tied
  367. // to ItemData.
  368. function DeployableTurretWeapon::onUse(%this, %obj)
  369. {
  370. Weapon::onUse(%this, %obj);
  371. }
  372. function DeployableTurretWeapon::onPickup(%this, %obj, %shape, %amount)
  373. {
  374. Weapon::onPickup(%this, %obj, %shape, %amount);
  375. }
  376. function DeployableTurretWeapon::onInventory(%this, %obj, %amount)
  377. {
  378. if (%obj.client !$= "" && !%obj.isAiControlled)
  379. {
  380. %obj.client.setAmmoAmountHud( 1, %amount );
  381. }
  382. // Cycle weapons if we are out of ammo
  383. if ( !%amount && ( %slot = %obj.getMountSlot( %this.image ) ) != -1 )
  384. %obj.cycleWeapon( "prev" );
  385. }
  386. function DeployableTurretWeaponImage::onMount(%this, %obj, %slot)
  387. {
  388. // The turret doesn't use ammo from a player's perspective.
  389. %obj.setImageAmmo(%slot, true);
  390. %numTurrets = %obj.getInventory(%this.item);
  391. if (%obj.client !$= "" && !%obj.isAiControlled)
  392. %obj.client.RefreshWeaponHud( 1, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %numTurrets);
  393. }
  394. function DeployableTurretWeaponImage::onUnmount(%this, %obj, %slot)
  395. {
  396. if (%obj.client !$= "" && !%obj.isAiControlled)
  397. %obj.client.RefreshWeaponHud(0, "", "");
  398. }
  399. function DeployableTurretWeaponImage::onFire(%this, %obj, %slot)
  400. {
  401. //echo("\DeployableTurretWeaponImage::onFire( "@%this.getName()@", "@%obj.client.nameBase@", "@%slot@" )");
  402. // To fire a deployable turret is to throw it. Schedule the throw
  403. // so that it doesn't happen during this ShapeBaseImageData's state machine.
  404. // If we throw the last one then we end up unmounting while the state machine
  405. // is still being processed.
  406. %obj.schedule(0, "throw", %this.item);
  407. }