robotmonkey

SA-MP - rTurret v1.5

Jul 1st, 2015
526
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ================================================================
  2. //  rTurret
  3. //      Version 1.5.1
  4. //      Created for SA-MP 0.3.7
  5. //      Copyright © 2014 - 2015 by Corekt
  6. //
  7. //      This program is free software: you can redistribute it and/or modify
  8. //      it under the terms of the GNU General Public License as published by
  9. //      the Free Software Foundation, either version 3 of the License, or
  10. //      (at your option) any later version.
  11. //
  12. //      This program is distributed in the hope that it will be useful,
  13. //      but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. //      GNU General Public License for more details.
  16. //
  17. //      You should have received a copy of the GNU General Public License
  18. //      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. //
  20. //  Changelog:
  21. //      Version 1.5.1 (7/18/2015)
  22. //          Fixed bugs and removed warnings
  23. //          Added TurretDamagePlayer
  24. //          Added (Get/Set)TurretBulletOffset
  25. //          Added (Get/Set)TurretBulletRot
  26. //      Version 1.5 (7/1/2015)
  27. //          Improved predictive aim algorithm
  28. //          Added Turret Health system:
  29. //              GetTurretHealth
  30. //              SetTurretHealth
  31. //              ToggleTurretHealth
  32. //              OnPlayerShootTurret
  33. //              OnTurretDeath
  34. //          Added LoS feature (requires ColAndreas):
  35. //              ToggleTurretLOS
  36. //              ToggleTurretLOSAim
  37. //              OnTurretBulletCollision
  38. //          Minor bug fixes/tweaks
  39. //      Version 1.1 (7/19/2014)
  40. //          Added ToggleTurretTargetFocus,
  41. //          Added GetTurretOwner, SetTurretOwner,
  42. //          Added SetTurretMaterial, GetTurretMaterial
  43. //          Added definitions for British English spelling
  44. //          Minor bug fixes
  45. //      Version 1.0 (7/14/2014)
  46. //          First release
  47. //
  48. //  Description:
  49. //      rTurret allows you to create highly customizable interactive turrets
  50. //
  51. //  Installation:
  52. //      Requires -
  53. //          Streamer Plugin -   http://forum.sa-mp.com/showthread.php?t=102865
  54. //          ColAndreas Plugin - http://forum.sa-mp.com/showthread.php?t=560218
  55. //          foreach include -   http://forum.sa-mp.com/showthread.php?t=570868
  56. //      If using this in a filterscript, define FILTERSCRIPT
  57. //      before including this file.
  58. //
  59. //  Thanks to:
  60. //      Y_Less                                  foreach
  61. //      Incognito                               Streamer Plugin
  62. //      [uL]Slice, [uL]Chris420, [uL]Pottus     ColAndreas Plugin
  63. //      Kye/Kalcor and the SA-MP Team           SA-MP
  64. //
  65. //  Core Functions:
  66. //      CreateTurret(behavior = TURRET_BEHAVIOR_STATIONARY, playerid = INVALID_PLAYER_ID, Float:x = 0.0, Float:y = 0.0, Float:z = 0.0, Float:rx = 0.0, Float:ry = 0.0, Float:rz = 1000.0, world = -1, interior = -1, rate = 100, Float:speed = 20.0, Float:dmg = 25.0, Float:range = 50.0, Float:streamdistance = 200.0);
  67. //      DestroyTurret(turretid, &iter_next = -1);
  68. //      IsValidTurret(turretid);
  69. //
  70. //  Callbacks:
  71. //      OnTurretCreate(turretid);
  72. //      OnTurretDestroy(turretid);
  73. //      OnTurretDeath(turretid, killerid, weaponid);
  74. //      OnTurretHitPlayer(turretid, playerid);
  75. //      OnPlayerTakeTurretDamage(playerid, turretid, Float:damage);
  76. //      OnPlayerShootTurret(playerid, weaponid, turretid, Float:fX, Float:fY, Float:fZ);
  77. //      OnTurretMoved(turretid);
  78. //      OnTurretCustomShoot(turretid);
  79. //      OnTurretBulletCollision(turretid, Float:x, Float:y, Float:z)
  80. //
  81. //  For more documentation and updates visit:
  82. //      http://forum.sa-mp.com/showthread.php?t=525988
  83. // ================================================================
  84.  
  85. #if !defined _samp_included
  86.     #error You must include a_samp before rTurret.
  87. #endif
  88.  
  89. #if defined _rTurret_included
  90.     #endinput
  91. #endif  
  92. #define _rTurret_included
  93.  
  94. #if !defined COLANDREAS
  95.     #include <colandreas>
  96. #endif
  97.  
  98. #include <streamer>
  99. #include <foreach>
  100.  
  101. #if !defined MAX_TURRETS
  102.     #define MAX_TURRETS                             (256)
  103. #endif
  104.  
  105. #if !defined MIN_TURRET_RATE
  106.     #define MIN_TURRET_RATE                         (100)
  107. #endif
  108.  
  109. #if !defined MAX_TURRET_VISIBLE_BULLETS
  110.     #define MAX_TURRET_VISIBLE_BULLETS              (32)
  111. #endif
  112.  
  113. #define INVALID_TURRET                              (-1)
  114. #define INVALID_TURRET_ID                           INVALID_TURRET
  115.  
  116. // Streamer data identifiers
  117. // Do not reuse these values!
  118. #define TURRET_INT                                  (-706637)
  119. #define TURRET_BIG_AREA_INT                         (-316)
  120. #define TURRET_SHOOT_AREA_INT                       (-56007)
  121. #define TURRET_BULLET_AREA_INT                      (-4234)
  122. #define TURRET_BULLET_OBJECT_INT                    (-801137)
  123.  
  124. // Turret moveids
  125. #define TURRET_MOVE_ROTATE_CLOCKWISE_1              (-1)
  126. #define TURRET_MOVE_ROTATE_CLOCKWISE_2              (-2)
  127. #define TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1       (-3)
  128. #define TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2       (-4)
  129. #define TURRET_MOVE_OTHER                           (-5)
  130.  
  131. // Turret Behaviors
  132. #define TURRET_BEHAVIOR_STATIONARY                  (0)
  133. #define TURRET_BEHAVIOR_ROTATE_CLOCKWISE            (1)
  134. #define TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE     (2)
  135. #define TURRET_BEHAVIOR_AIM_CLOSEST                 (3)
  136. #define TURRET_BEHAVIOR_AIM_FARTHEST                (4)
  137. #define TURRET_BEHAVIOR_AIM_WEAKEST                 (5)
  138. #define TURRET_BEHAVIOR_AIM_STRONGEST               (6)
  139. #define TURRET_BEHAVIOR_AIM_RANDOM                  (7)
  140. #define TURRET_BEHAVIOR_AIM_SINGLE                  (8)
  141. #define TURRET_BEHAVIOR_AIM_CUSTOM                  (9)
  142. #define TURRET_BEHAVIOR_MAX                         (10)
  143.  
  144. // ======================================================
  145. // Callbacks
  146. // ======================================================
  147. forward OnTurretCreate(turretid);
  148. forward OnTurretDestroy(turretid);
  149. forward OnTurretDeath(turretid, killerid, weaponid);
  150. forward OnTurretHitPlayer(turretid, playerid);
  151. forward OnPlayerTakeTurretDamage(playerid, turretid, Float:damage);
  152. forward OnPlayerShootTurret(playerid, weaponid, turretid, Float:fX, Float:fY, Float:fZ);
  153. forward OnTurretMoved(turretid);
  154. forward OnTurretCustomShoot(turretid);
  155. forward OnTurretBulletCollision(turretid, Float:x, Float:y, Float:z);
  156.  
  157. enum E_TURRET_DATA
  158. {
  159.     e_turr_objectid,
  160.     e_turr_behavior,
  161.     e_turr_owner,
  162.     e_turr_team,
  163.     e_turr_world,
  164.     e_turr_interior,
  165.     e_turr_area,
  166.     e_turr_bigarea,
  167.     e_turr_rate,
  168.     Text3D:e_turr_3dtext,
  169.     Float:e_turr_3dtext_xoffset,
  170.     Float:e_turr_3dtext_yoffset,
  171.     Float:e_turr_3dtext_zoffset,
  172.     Float:e_turr_3dtext_draw,
  173.     e_turr_3dtext_testlos,
  174.     Float:e_turr_health,
  175.     Float:e_turr_speed,
  176.     Float:e_turr_dmg,
  177.     Float:e_turr_range,
  178.     Float:e_turr_stream,
  179.     Float:e_turr_rotspeed,
  180.     Float:e_turr_bullet_radius,
  181.     e_turr_bullet_model,
  182.     e_turr_bullet_color,
  183.     Float:e_turr_bullet_xoffset,
  184.     Float:e_turr_bullet_yoffset,
  185.     Float:e_turr_bullet_zoffset,
  186.     Float:e_turr_bullet_rx,
  187.     Float:e_turr_bullet_ry,
  188.     Float:e_turr_bullet_rz,
  189.     e_turr_timer,
  190.     e_turr_visible_bullets,
  191.     e_turr_max_visible_bullets,
  192.     bool:e_turr_active,
  193.     bool:e_turr_has_health,
  194.     bool:e_turr_3dspace,
  195.     bool:e_turr_predict,
  196.     bool:e_turr_los,
  197.     bool:e_turr_los_aim,
  198.     bool:e_turr_checkarea,
  199.     bool:e_turr_playsound,
  200.     bool:e_turr_target_focus,
  201.     e_turr_soundid,
  202.     e_turr_target
  203. }
  204.  
  205. static
  206.     rTurret_Killed[MAX_PLAYERS char],
  207.     rTurret_KilledBy[MAX_PLAYERS],
  208.     rTurretData[MAX_TURRETS][E_TURRET_DATA];
  209.    
  210. static stock
  211.     bool:rTurret_Is_Duplicate = false;
  212.    
  213. new
  214.     Iterator:rTurrets<MAX_TURRETS>,
  215.     Iterator:rTurretTargets[MAX_TURRETS]<MAX_PLAYERS>,
  216.     Iterator:rTurretPlayersInBigArea[MAX_TURRETS]<MAX_PLAYERS>;
  217.  
  218. // ======================================================
  219. // Core Functions
  220. // ======================================================
  221.  
  222. stock CreateTurret(behavior = TURRET_BEHAVIOR_STATIONARY, playerid = INVALID_PLAYER_ID, Float:x = 0.0, Float:y = 0.0, Float:z = 0.0, Float:rx = 0.0, Float:ry = 0.0, Float:rz = 1000.0, world = -1, interior = -1, rate = 100, Float:speed = 20.0, Float:dmg = 25.0, Float:range = 50.0, Float:streamdistance = 200.0)
  223. {
  224.     new
  225.         turretid = Iter_Free(rTurrets);
  226.        
  227.     if (turretid == -1) {
  228.         printf("rTurret error: Max turrets of %d reached. Please define the #MAX_TURRETS macro to a higher value.", MAX_TURRETS);
  229.         return INVALID_TURRET;
  230.     }
  231.    
  232.     if (behavior < 0 || behavior >= TURRET_BEHAVIOR_MAX) {
  233.         printf("rTurret warning: Invalid turret behavior! Turret %d's behavior has been changed from %d to TURRET_BEHAVIOR_STATIONARY (%d).", turretid, behavior, TURRET_BEHAVIOR_STATIONARY);
  234.         behavior = TURRET_BEHAVIOR_STATIONARY;
  235.     }
  236.    
  237.     if (rate < MIN_TURRET_RATE) {
  238.         printf("rTurret warning: Turret %d's rate of %d has been set to MIN_TURRET_RATE %d.", turretid, rate, MIN_TURRET_RATE);
  239.         rate = MIN_TURRET_RATE;
  240.     }
  241.    
  242.     Iter_Add(rTurrets, turretid);
  243.     rTurretData[turretid][e_turr_behavior] =            behavior;
  244.     rTurretData[turretid][e_turr_team] =                255;
  245.     rTurretData[turretid][e_turr_owner] =               playerid;
  246.     rTurretData[turretid][e_turr_world] =               world;
  247.     rTurretData[turretid][e_turr_interior] =            interior;
  248.     rTurretData[turretid][e_turr_rate] =                rate;
  249.     rTurretData[turretid][e_turr_3dtext_xoffset] =      0;
  250.     rTurretData[turretid][e_turr_3dtext_yoffset] =      0;
  251.     rTurretData[turretid][e_turr_3dtext_zoffset] =      0;
  252.     rTurretData[turretid][e_turr_3dtext_draw] =         25;
  253.     rTurretData[turretid][e_turr_3dtext_testlos] =      0;
  254.     rTurretData[turretid][e_turr_health] =              100.0;
  255.     rTurretData[turretid][e_turr_speed] =               floatabs(speed);
  256.     rTurretData[turretid][e_turr_dmg] =                 dmg;
  257.     rTurretData[turretid][e_turr_range] =               range;
  258.     rTurretData[turretid][e_turr_stream] =              streamdistance;
  259.     rTurretData[turretid][e_turr_rotspeed] =            0.0005;
  260.     rTurretData[turretid][e_turr_bullet_radius] =       2.0;
  261.     rTurretData[turretid][e_turr_bullet_model] =        2352;
  262.     rTurretData[turretid][e_turr_bullet_color] =        0;
  263.     rTurretData[turretid][e_turr_bullet_xoffset] =      0.0;
  264.     rTurretData[turretid][e_turr_bullet_yoffset] =      0.0;
  265.     rTurretData[turretid][e_turr_bullet_zoffset] =      0.0;
  266.     rTurretData[turretid][e_turr_bullet_rx] =           0.0;
  267.     rTurretData[turretid][e_turr_bullet_ry] =           270.0;
  268.     rTurretData[turretid][e_turr_bullet_rz] =           0.0;
  269.     rTurretData[turretid][e_turr_max_visible_bullets] = MAX_TURRET_VISIBLE_BULLETS;
  270.     rTurretData[turretid][e_turr_active] =              true;
  271.     rTurretData[turretid][e_turr_has_health] =          false;
  272.     rTurretData[turretid][e_turr_3dspace] =             true;
  273.     rTurretData[turretid][e_turr_predict] =             true;
  274.     rTurretData[turretid][e_turr_los] =                 true;
  275.     rTurretData[turretid][e_turr_los_aim] =             true;
  276.     rTurretData[turretid][e_turr_checkarea] =           true;
  277.     rTurretData[turretid][e_turr_playsound] =           true;
  278.     rTurretData[turretid][e_turr_soundid] =             1130;
  279.     rTurretData[turretid][e_turr_target] =              INVALID_PLAYER_ID;
  280.     rTurretData[turretid][e_turr_target_focus] =        false;
  281.    
  282.     rTurretData[turretid][e_turr_objectid] =    CreateDynamicObject(2985, x, y, z, rx, ry, (behavior != TURRET_BEHAVIOR_ROTATE_CLOCKWISE && behavior != TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE) ? rz : 0.0, world, interior, .streamdistance = streamdistance);
  283.     rTurretData[turretid][e_turr_area] =        CreateDynamicSphere(0, 0, 0, range, world, interior);
  284.     rTurretData[turretid][e_turr_bigarea] =     CreateDynamicSphere(0, 0, 0, 60.0, world, interior);
  285.     rTurretData[turretid][e_turr_3dtext] =      CreateDynamic3DTextLabel(" ", -1, x, y, z + 2, 25, .testlos = 0, .worldid = world, .interiorid = interior, .streamdistance = 50);
  286.    
  287.     AttachDynamicAreaToObject(rTurretData[turretid][e_turr_area], rTurretData[turretid][e_turr_objectid]);
  288.     AttachDynamicAreaToObject(rTurretData[turretid][e_turr_bigarea], rTurretData[turretid][e_turr_objectid]);
  289.     // Turret object array data (identifier, turretid, moveid (below))
  290.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_INT);
  291.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, turretid);
  292.     // Shoot area array data (turretid, identifier)
  293.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, turretid);
  294.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  295.     // Big area array data (turretid, identifier)
  296.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_bigarea], E_STREAMER_EXTRA_ID, turretid);
  297.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_bigarea], E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT);
  298.    
  299.     CallLocalFunction("OnTurretCreate", "d", turretid);
  300.    
  301.     if (behavior == TURRET_BEHAVIOR_ROTATE_CLOCKWISE) {
  302.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  303.         MoveDynamicObject(rTurretData[turretid][e_turr_objectid], x, y, z + 0.001, rTurretData[turretid][e_turr_rotspeed], rx, ry, -179);
  304.     } else if (behavior == TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE) {
  305.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  306.         MoveDynamicObject(rTurretData[turretid][e_turr_objectid], x, y, z + 0.001, rTurretData[turretid][e_turr_rotspeed], rx, ry, 179);
  307.     } else
  308.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  309.  
  310.     rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rate, true, "d", turretid);
  311.    
  312.     return turretid;
  313. }
  314.  
  315. stock DestroyTurret(turretid, &iter_next = -1)
  316. {
  317.     if (!Iter_Contains(rTurrets, turretid))
  318.         return 0;
  319.        
  320.     CallLocalFunction("OnTurretDestroy", "d", turretid);
  321.    
  322.     DestroyDynamicArea(rTurretData[turretid][e_turr_area]);
  323.     DestroyDynamicArea(rTurretData[turretid][e_turr_bigarea]);
  324.        
  325.     if (rTurretData[turretid][e_turr_timer] != -1) {
  326.         KillTimer(rTurretData[turretid][e_turr_timer]);
  327.         rTurretData[turretid][e_turr_timer] = -1;
  328.     }
  329.    
  330.     //rTurretData[turretid][e_turr_visible_bullets] = -1;
  331.     DestroyDynamicObject(rTurretData[turretid][e_turr_objectid]);
  332.     //DestroyDynamicArea(rTurretData[turretid][e_turr_area]);
  333.     //DestroyDynamicArea(rTurretData[turretid][e_turr_bigarea]);
  334.     DestroyDynamic3DTextLabel(rTurretData[turretid][e_turr_3dtext]);
  335.     rTurretData[turretid][e_turr_objectid] = INVALID_OBJECT_ID;
  336.     Iter_Clear(rTurretTargets[turretid]);
  337.     Iter_Clear(rTurretPlayersInBigArea[turretid]);
  338.     Iter_SafeRemove(rTurrets, turretid, iter_next);
  339.     return 1;
  340. }
  341.  
  342. stock IsValidTurret(turretid)
  343. {
  344.     return Iter_Contains(rTurrets, turretid);
  345. }
  346.  
  347. // ======================================================
  348. // Getter Functions
  349. // ======================================================
  350.  
  351. stock GetTurretObject(turretid)
  352. {
  353.     if (!Iter_Contains(rTurrets, turretid))
  354.         return INVALID_OBJECT_ID;
  355.        
  356.     return rTurretData[turretid][e_turr_objectid];
  357. }
  358.  
  359. stock Text3D:GetTurret3DTextLabel(turretid)
  360. {
  361.     if (!Iter_Contains(rTurrets, turretid))
  362.         return Text3D:INVALID_3DTEXT_ID;
  363.        
  364.     return rTurretData[turretid][e_turr_3dtext];
  365. }
  366.  
  367. stock GetTurretOwner(turretid)
  368. {
  369.     if (!Iter_Contains(rTurrets, turretid))
  370.         return INVALID_PLAYER_ID;
  371.        
  372.     return rTurretData[turretid][e_turr_owner];
  373. }
  374.  
  375. stock GetTurretBehavior(turretid)
  376. {
  377.     if (!Iter_Contains(rTurrets, turretid))
  378.         return -1;
  379.        
  380.     return rTurretData[turretid][e_turr_behavior];
  381. }
  382.  
  383. stock GetTurretTeam(turretid)
  384. {
  385.     if (!Iter_Contains(rTurrets, turretid))
  386.         return 255;
  387.        
  388.     return rTurretData[turretid][e_turr_team];
  389. }
  390.  
  391. stock Float:GetTurretHealth(turretid)
  392. {
  393.     if (!Iter_Contains(rTurrets, turretid) || !rTurretData[turretid][e_turr_has_health])
  394.         return -1.0;
  395.        
  396.     return rTurretData[turretid][e_turr_health];
  397. }
  398.  
  399. stock GetTurretPos(turretid, &Float:x, &Float:y, &Float:z)
  400. {
  401.     if (!Iter_Contains(rTurrets, turretid))
  402.         return 0;
  403.        
  404.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], x, y, z);
  405.     return 1;
  406. }
  407.  
  408. stock GetTurretRot(turretid, &Float:rotx, &Float:roty, &Float:rotz)
  409. {
  410.     if (!Iter_Contains(rTurrets, turretid))
  411.         return 0;
  412.        
  413.     GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], rotx, roty, rotz);
  414.     return 1;
  415. }
  416.  
  417. stock Float:GetTurretRotSpeed(turretid)
  418. {
  419.     if (!Iter_Contains(rTurrets, turretid))
  420.         return 0.0;
  421.        
  422.     return rTurretData[turretid][e_turr_rotspeed] / speed;
  423. }
  424.  
  425. stock Float:GetTurretBulletRadius(turretid)
  426. {
  427.     if (!Iter_Contains(rTurrets, turretid))
  428.         return 0.0;
  429.        
  430.     return rTurretData[turretid][e_turr_bullet_radius];
  431. }
  432.  
  433. stock GetTurretWorld(turretid)
  434. {
  435.     if (!Iter_Contains(rTurrets, turretid))
  436.         return -2;
  437.        
  438.     return rTurretData[turretid][e_turr_world];
  439. }
  440.  
  441. stock GetTurretInterior(turretid)
  442. {
  443.     if (!Iter_Contains(rTurrets, turretid))
  444.         return -2;
  445.        
  446.     return rTurretData[turretid][e_turr_interior];
  447. }
  448.  
  449. stock GetTurretText(turretid, text[], maxlength = sizeof(text))
  450. {
  451.     if (!Iter_Contains(rTurrets, turretid))
  452.         return 0;
  453.        
  454.     GetDynamic3DTextLabelText(rTurretData[turretid][e_turr_3dtext], text, sizeof(text));
  455.     return 1;
  456. }
  457.  
  458. stock GetTurretTextOffset(turretid, &Float:offsetx, &Float:offsety, &Float:offsetz)
  459. {
  460.     if (!Iter_Contains(rTurrets, turretid))
  461.         return 0;
  462.        
  463.     offsetx = rTurretData[turretid][e_turr_3dtext_xoffset];
  464.     offsety = rTurretData[turretid][e_turr_3dtext_yoffset];
  465.     offsetz = rTurretData[turretid][e_turr_3dtext_zoffset];
  466.     return 1;
  467. }
  468.  
  469. stock GetTurretFireRate(turretid)
  470. {
  471.     if (!Iter_Contains(rTurrets, turretid))
  472.         return 0;
  473.        
  474.     return rTurretData[turretid][e_turr_rate];
  475. }
  476.  
  477. stock Float:GetTurretBulletSpeed(turretid)
  478. {
  479.     if (!Iter_Contains(rTurrets, turretid))
  480.         return 0.0;
  481.        
  482.     return rTurretData[turretid][e_turr_speed];
  483. }
  484.  
  485. stock Float:GetTurretDamage(turretid)
  486. {
  487.     if (!Iter_Contains(rTurrets, turretid))
  488.         return 0.0;
  489.        
  490.     return rTurretData[turretid][e_turr_dmg];
  491. }
  492.  
  493. stock Float:GetTurretRange(turretid)
  494. {
  495.     if (!Iter_Contains(rTurrets, turretid))
  496.         return 0.0;
  497.        
  498.     return rTurretData[turretid][e_turr_range];
  499. }
  500.  
  501. stock Float:GetTurretStreamDistance(turretid)
  502. {
  503.     if (!Iter_Contains(rTurrets, turretid))
  504.         return 0.0;
  505.        
  506.     return rTurretData[turretid][e_turr_stream];
  507. }
  508.  
  509. stock GetTurretMaterial(turretid, materialindex, &modelid, txdname[], texturename[], &materialcolor, maxtxdname = sizeof txdname, maxtexturename = sizeof texturename)
  510. {
  511.     if (!Iter_Contains(rTurrets, turretid))
  512.         return 0;
  513.        
  514.     GetDynamicObjectMaterial(rTurretData[turretid][e_turr_objectid], materialindex, &modelid, txdname, texturename, &materialcolor, maxtxdname, maxtexturename);
  515.     return 1;
  516. }
  517.  
  518. stock GetTurretBulletModel(turretid)
  519. {
  520.     if (!Iter_Contains(rTurrets, turretid))
  521.         return -1;
  522.        
  523.     return rTurretData[turretid][e_turr_bullet_model];
  524. }
  525.  
  526. stock GetTurretBulletColor(turretid)
  527. {
  528.     if (!Iter_Contains(rTurrets, turretid))
  529.         return -1;
  530.        
  531.     return rTurretData[turretid][e_turr_bullet_color];
  532. }
  533.  
  534. stock GetTurretBulletOffset(turretid, &Float:offsetx, &Float:offsety, &Float:offsetz)
  535. {
  536.     if (!Iter_Contains(rTurrets, turretid))
  537.         return 0;
  538.        
  539.     offsetx = rTurretData[turretid][e_turr_bullet_offsetx];
  540.     offsety = rTurretData[turretid][e_turr_bullet_offsety];
  541.     offsetz = rTurretData[turretid][e_turr_bullet_offsetz];
  542.     return 1;
  543. }
  544.  
  545. stock GetTurretBulletRot(turretid, &Float:rx, &Float:ry, &Float:rz)
  546. {
  547.     if (!Iter_Contains(rTurrets, turretid))
  548.         return 0;
  549.        
  550.     rx = rTurretData[turretid][e_turr_bullet_rx];
  551.     ry = rTurretData[turretid][e_turr_bullet_ry];
  552.     rz = rTurretData[turretid][e_turr_bullet_rz];
  553.     return 1;
  554. }
  555.  
  556. stock GetTurretVisibleBullets(turretid)
  557. {
  558.     if (!Iter_Contains(rTurrtts, turretid))
  559.         return 0;
  560.        
  561.     return rTurretData[turretid][e_turr_visible_bullets];
  562. }
  563.  
  564. stock GetTurretMaxVisibleBullets(turretid)
  565. {
  566.     if (!Iter_Contains(rTurrets, turretid))
  567.         return 0;
  568.  
  569.     return rTurretData[turretid][e_turr_max_visible_bullets];
  570. }
  571.  
  572. stock GetTurretSound(turretid)
  573. {
  574.     if (!Iter_Contains(rTurrets, turretid))
  575.         return 0;
  576.        
  577.     return rTurretData[turretid][e_turr_soundid];
  578. }
  579.  
  580. stock GetTurretKiller(playerid)
  581. {
  582.     return rTurret_KilledBy[playerid];
  583. }
  584.  
  585. // ======================================================
  586. // Setter Functions
  587. // ======================================================
  588.  
  589. stock SetTurretOwner(turretid, playerid)
  590. {
  591.     if (!Iter_Contains(rTurrets, turretid))
  592.         return 0;
  593.        
  594.     if (playerid == rTurretData[turretid][e_turr_owner])
  595.         return 0;
  596.     else
  597.         rTurretData[turretid][e_turr_owner] = playerid;
  598.     return 1;
  599. }
  600.  
  601. stock SetTurretBehavior(turretid, behavior)
  602. {
  603.     if (!Iter_Contains(rTurrets, turretid) || behavior < 0 || behavior >= TURRET_BEHAVIOR_MAX)
  604.         return 0;
  605.    
  606.     if (IsDynamicObjectMoving(rTurretData[turretid][e_turr_objectid]))
  607.         StopDynamicObject(rTurretData[turretid][e_turr_objectid]);
  608.        
  609.     switch(rTurretData[turretid][e_turr_behavior]) {
  610.         case TURRET_BEHAVIOR_ROTATE_CLOCKWISE: {
  611.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  612.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  613.         }
  614.         case TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE: {
  615.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  616.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  617.         }
  618.         default:
  619.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  620.     }
  621.    
  622.     rTurretData[turretid][e_turr_behavior] = behavior;
  623.    
  624.     switch(behavior) {
  625.         case TURRET_BEHAVIOR_ROTATE_CLOCKWISE: {
  626.             new
  627.                 Float:turPX,
  628.                 Float:turPY,
  629.                 Float:turPZ,
  630.                 Float:turRX,
  631.                 Float:turRY,
  632.                 Float:turRZ;
  633.                
  634.             GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  635.             GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  636.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, 0.0);
  637.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  638.             MoveDynamicObject(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ + 0.001, rTurretData[turretid][e_turr_rotspeed], turRX, turRY, -179.0);
  639.         }
  640.         case TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE: {
  641.             new
  642.                 Float:turPX,
  643.                 Float:turPY,
  644.                 Float:turPZ,
  645.                 Float:turRX,
  646.                 Float:turRY,
  647.                 Float:turRZ;
  648.                
  649.             GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  650.             GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  651.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, 0.0);
  652.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  653.             MoveDynamicObject(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ + 0.001, rTurretData[turretid][e_turr_rotspeed], turRX, turRY, 179.0);
  654.         }
  655.         default:
  656.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  657.     }
  658.     return 1;
  659. }
  660.  
  661. stock SetTurretTeam(turretid, team)
  662. {
  663.     if (!Iter_Contains(rTurrets, turretid))
  664.         return 0;
  665.        
  666.     rTurretData[turretid][e_turr_team] = team;
  667.     return 1;
  668. }
  669.  
  670. stock SetTurretHealth(turretid, Float:health)
  671. {
  672.     if (!Iter_Contains(rTurrets, turretid) || floatcmp(0.0, health) == 1)
  673.         return 0;
  674.  
  675.     rTurretData[turretid][e_turr_health] = health;
  676.     return 1;
  677. }
  678.  
  679. stock SetTurretPos(turretid, Float:x, Float:y, Float:z)
  680. {
  681.     if (!Iter_Contains(rTurrets, turretid))
  682.         return 0;
  683.  
  684.     SetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], x, y, z);
  685.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + rTurretData[turretid][e_turr_3dtext_xoffset]);
  686.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + rTurretData[turretid][e_turr_3dtext_yoffset]);
  687.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + rTurretData[turretid][e_turr_3dtext_zoffset]);
  688.     return 1;
  689. }
  690.  
  691. stock SetTurretRot(turretid, Float:rotx, Float:roty, Float:rotz)
  692. {
  693.     if (!Iter_Contains(rTurrets, turretid))
  694.         return 0;
  695.  
  696.     SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], rotx, roty, rotz);
  697.     return 1;
  698. }
  699.  
  700. stock SetTurretRotSpeed(turretid, Float:speed)
  701. {
  702.     if (!Iter_Contains(rTurrets, turretid))
  703.         return 0;
  704.        
  705.     rTurretData[turretid][e_turr_rotspeed] = 0.0005 * floatabs(speed);
  706.     return 1;
  707. }
  708.  
  709. stock SetTurretBulletRadius(turretid, Float:radius)
  710. {
  711.     if (!Iter_Contains(rTurrets, turretid))
  712.         return 0;
  713.        
  714.     rTurretData[turretid][e_turr_bullet_radius] = radius;
  715.     return 1;
  716. }
  717.  
  718. stock SetTurretWorld(turretid, world)
  719. {
  720.     if (!Iter_Contains(rTurrets, turretid))
  721.         return 0;
  722.        
  723.     rTurretData[turretid][e_turr_world] = world;
  724.     Streamer_SetIntData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_WORLD_ID, world);
  725.     Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_WORLD_ID, world);
  726.     return 1;
  727. }
  728.  
  729. stock SetTurretInterior(turretid, interior)
  730. {
  731.     if (!Iter_Contains(rTurrets, turretid))
  732.         return 0;
  733.        
  734.     rTurretData[turretid][e_turr_interior] = interior;
  735.     Streamer_SetIntData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_INTERIOR_ID, interior);
  736.     Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_INTERIOR_ID, interior);
  737.     return 1;
  738. }
  739.  
  740. stock SetTurretText(turretid, color, const text[])
  741. {
  742.     if (!Iter_Contains(rTurrets, turretid))
  743.         return 0;
  744.        
  745.     UpdateDynamic3DTextLabelText(rTurretData[turretid][e_turr_3dtext], color, text);
  746.     return 1;
  747. }
  748.  
  749. stock SetTurretTextOffset(turretid, Float:offsetx, Float:offsety, Float:offsetz, Float:drawdistance = -1.0, testlos = -1)
  750. {
  751.     if (!Iter_Contains(rTurrets, turretid))
  752.         return 0;
  753.        
  754.     new
  755.         Float:turPX,
  756.         Float:turPY,
  757.         Float:turPZ;
  758.        
  759.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  760.        
  761.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + offsetx);
  762.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + offsety);
  763.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + offsetz);
  764.    
  765.     if (floatcmp(drawdistance, -1.0) != 0) {
  766.         Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_DRAW_DISTANCE, drawdistance);
  767.         Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_STREAM_DISTANCE, drawdistance + 25);
  768.         rTurretData[turretid][e_turr_3dtext_draw] = drawdistance;
  769.     }
  770.     if (testlos != -1) {
  771.         Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_TEST_LOS, testlos);
  772.         rTurretData[turretid][e_turr_3dtext_testlos] = testlos;
  773.     }
  774.        
  775.     rTurretData[turretid][e_turr_3dtext_xoffset] = offsetx;
  776.     rTurretData[turretid][e_turr_3dtext_yoffset] = offsety;
  777.     rTurretData[turretid][e_turr_3dtext_zoffset] = offsetz;
  778.     return 1;
  779. }
  780.  
  781. stock SetTurretFireRate(turretid, rate)
  782. {
  783.     if (!Iter_Contains(rTurrets, turretid))
  784.         return 0;
  785.        
  786.     if (rate < MIN_TURRET_RATE) {
  787.         printf("rTurret warning: Turret %d's rate of %d has been set to MIN_TURRET_RATE %d.", turretid, rate, MIN_TURRET_RATE);
  788.         rate = MIN_TURRET_RATE;
  789.     }
  790.     rTurretData[turretid][e_turr_rate] = rate;
  791.     if (rTurretData[turretid][e_turr_timer] != -1 && rTurretData[turretid][e_turr_active]) {
  792.         KillTimer(rTurretData[turretid][e_turr_timer]);
  793.         rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rate, true, "d", turretid);
  794.     }
  795.     return 1;
  796. }
  797.  
  798. stock SetTurretBulletSpeed(turretid, Float:speed)
  799. {
  800.     if (!Iter_Contains(rTurrets, turretid))
  801.         return 0;
  802.        
  803.     rTurretData[turretid][e_turr_speed] = floatabs(speed);
  804.     return 1;
  805. }
  806.  
  807. stock SetTurretDamage(turretid, Float:damage)
  808. {
  809.     if (!Iter_Contains(rTurrets, turretid))
  810.         return 0;
  811.        
  812.     rTurretData[turretid][e_turr_dmg] = damage;
  813.     return 1;
  814. }
  815.  
  816. stock SetTurretRange(turretid, Float:range)
  817. {
  818.     if (!Iter_Contains(rTurrets, turretid))
  819.         return 0;
  820.        
  821.     rTurretData[turretid][e_turr_range] = range;
  822.     return 1;
  823. }
  824.  
  825. stock SetTurretStreamDistance(turretid, Float:streamdistance)
  826. {
  827.     if (!Iter_Contains(rTurrets, turretid))
  828.         return 0;
  829.        
  830.     rTurretData[turretid][e_turr_stream] = streamdistance;
  831.     Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, streamdistance);
  832.     return 1;
  833. }
  834.  
  835. stock SetTurretMaterial(turretid, materialindex, modelid, const txdname[], const texturename[], materialcolor = 0)
  836. {
  837.     if (!Iter_Contains(rTurrets, turretid))
  838.         return 0;
  839.        
  840.     SetDynamicObjectMaterial(rTurretData[turretid][e_turr_objectid], materialindex, modelid, txdname, texturename, materialcolor);
  841.     return 1;
  842. }
  843.  
  844. stock SetTurretBulletModel(turretid, modelid)
  845. {
  846.     if (!Iter_Contains(rTurrets, turretid))
  847.         return 0;
  848.        
  849.     rTurretData[turretid][e_turr_bullet_model] = modelid;
  850.     return 1;
  851. }
  852.  
  853. stock SetTurretBulletColor(turretid, color = 0)
  854. {
  855.     if (!Iter_Contains(rTurrets, turretid))
  856.         return 0;
  857.        
  858.     rTurretData[turretid][e_turr_bullet_color] = color;
  859.     return 1;
  860. }
  861.  
  862. stock SetTurretBulletOffset(turretid, Float:offsetx, Float:offsety, Float:offsetz)
  863. {
  864.     if (!Iter_Contains(rTurrets, turretid))
  865.         return 0;
  866.        
  867.     rTurretData[turretid][e_turr_bullet_xoffset] = offsetx;
  868.     rTurretData[turretid][e_turr_bullet_yoffset] = offsety;
  869.     rTurretData[turretid][e_turr_bullet_zoffset] = offsetz;
  870.     return 1;
  871. }
  872.  
  873. stock SetTurretBulletRot(turretid, Float:rx, Float:ry, Float:rz)
  874. {
  875.     if (!Iter_Contains(rTurrets, turretid))
  876.         return 0;
  877.        
  878.     rTurretData[turretid][e_turr_bullet_rx] = rx;
  879.     rTurretData[turretid][e_turr_bullet_ry] = ry;
  880.     rTurretData[turretid][e_turr_bullet_rz] = rz;
  881.     return 1;
  882. }
  883.  
  884. stock SetTurretMaxVisibleBullets(turretid, maxbullets)
  885. {
  886.     if (!Iter_Contains(rTurrets, turretid))
  887.         return 0;
  888.     if (maxbullets >= MAX_TURRET_VISIBLE_BULLETS) {
  889.         printf("rTurret Warning: Max visible bullets for turret %d has been lowered from %d to MAX_TURRET_VISIBLE_BULLETS %d", turretid, maxbullets, MAX_TURRET_VISIBLE_BULLETS);
  890.         maxbullets = MAX_TURRET_VISIBLE_BULLETS;
  891.     } else if (maxbullets < 1) {
  892.         printf("rTurret Warning: Max visible bullets for turret %d has been raised from %d to %d", turretid, maxbullets, 1);
  893.         maxbullets = 1;
  894.     }
  895.     rTurretData[turretid][e_turr_max_visible_bullets] = maxbullets;
  896.     return 1;
  897. }
  898.  
  899. stock SetTurretSound(turretid, soundid)
  900. {
  901.     if (!Iter_Contains(rTurrets, turretid))
  902.         return 0;
  903.        
  904.     rTurretData[turretid][e_turr_soundid] = soundid;
  905.     return 1;
  906. }
  907.  
  908. stock SetTurretSingleTarget(turretid, targetid)
  909. {
  910.     if (!Iter_Contains(rTurrets, turretid))
  911.         return 0;
  912.        
  913.     if (!IsPlayerConnected(targetid))
  914.         return 0;
  915.        
  916.     rTurretData[turretid][e_turr_target] = targetid;
  917.     return 1;
  918. }
  919.  
  920. // ======================================================
  921. // Extra Functions
  922. // ======================================================
  923.  
  924. stock ToggleTurretActive(turretid, toggle)
  925. {
  926.     if (!Iter_Contains(rTurrets, turretid))
  927.         return 1;
  928.        
  929.     if (toggle) {
  930.         if (rTurretData[turretid][e_turr_active])
  931.             return 0;
  932.         if (rTurretData[turretid][e_turr_timer] == -1)
  933.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  934.         else {
  935.             KillTimer(rTurretData[turretid][e_turr_timer]);
  936.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  937.         }
  938.         rTurretData[turretid][e_turr_active] = true;
  939.     } else {
  940.         if (!rTurretData[turretid][e_turr_active])
  941.             return 0;
  942.         if (rTurretData[turretid][e_turr_timer] != -1) {
  943.             KillTimer(rTurretData[turretid][e_turr_timer]);
  944.             rTurretData[turretid][e_turr_timer] = -1;
  945.         }
  946.         rTurretData[turretid][e_turr_active] = false;
  947.     }
  948.     return 1;
  949. }
  950.  
  951. stock ToggleTurretHealth(turretid, toggle, Float:sethealth = -1.0)
  952. {
  953.     if (!Iter_Contains(rTurrets, turretid))
  954.         return 0;
  955.        
  956.     if (toggle) {
  957.         if (rTurretData[turretid][e_turr_has_health])
  958.             return 0;
  959.         rTurretData[turretid][e_turr_has_health] = true;
  960.     } else {
  961.         if (!rTurretData[turretid][e_turr_has_health])
  962.             return 0;
  963.         rTurretData[turretid][e_turr_has_health] = false;
  964.     }
  965.     if (floatcmp(0.0, sethealth) != 1)
  966.         rTurretData[turretid][e_turr_health] = sethealth;
  967.        
  968.     return 1;
  969. }
  970.  
  971. stock ToggleTurretCheckArea(turretid, toggle)
  972. {
  973.     if (!Iter_Contains(rTurrets, turretid))
  974.         return 0;
  975.        
  976.     if (toggle) {
  977.         if (rTurretData[turretid][e_turr_checkarea])
  978.             return 0;
  979.         rTurretData[turretid][e_turr_checkarea] = true;
  980.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, -1);
  981.         Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  982.     } else {
  983.         if (!rTurretData[turretid][e_turr_checkarea])
  984.             return 0;
  985.         rTurretData[turretid][e_turr_checkarea] = false;
  986.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  987.         Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, -1);
  988.     }
  989.     return 1;
  990. }
  991.  
  992. stock ToggleTurretPlaySound(turretid, toggle)
  993. {
  994.     if (!Iter_Contains(rTurrets, turretid))
  995.         return 0;
  996.        
  997.     if (toggle) {
  998.         if (rTurretData[turretid][e_turr_playsound])
  999.             return 0;
  1000.         rTurretData[turretid][e_turr_playsound] = true;
  1001.     } else {
  1002.         if (!rTurretData[turretid][e_turr_playsound])
  1003.             return 0;
  1004.         rTurretData[turretid][e_turr_playsound] = false;
  1005.     }
  1006.     return 1;
  1007. }
  1008.  
  1009. stock ToggleTurretVisible(turretid, toggle)
  1010. {
  1011.     if (!Iter_Contains(rTurrets, turretid))
  1012.         return 0;
  1013.        
  1014.     new
  1015.         Float:sd;
  1016.        
  1017.     Streamer_GetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, sd);
  1018.    
  1019.     if (toggle) {
  1020.         if (floatcmp(sd, rTurretData[turretid][e_turr_stream]) == 0)
  1021.             return 0;
  1022.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, rTurretData[turretid][e_turr_stream]);
  1023.     } else {
  1024.         if (floatcmp(sd, 0.0) == 0)
  1025.             return 0;
  1026.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, 0.0);
  1027.     }
  1028.     return 1;
  1029. }
  1030.  
  1031. stock ToggleTurretAim3dSpace(turretid, toggle)
  1032. {
  1033.     if (!Iter_Contains(rTurrets, turretid))
  1034.         return 0;
  1035.        
  1036.     if (toggle) {
  1037.         if (rTurretData[turretid][e_turr_3dspace])
  1038.             return 0;
  1039.         rTurretData[turretid][e_turr_3dspace] = true;
  1040.     } else {
  1041.         if (!rTurretData[turretid][e_turr_3dspace])
  1042.             return 0;
  1043.         rTurretData[turretid][e_turr_3dspace] = false;
  1044.     }
  1045.     return 1;
  1046. }
  1047.  
  1048. stock ToggleTurretPredictiveAim(turretid, toggle)
  1049. {
  1050.     if (!Iter_Contains(rTurrets, turretid))
  1051.         return 0;
  1052.        
  1053.     if (toggle) {
  1054.         if (rTurretData[turretid][e_turr_predict])
  1055.             return 0;
  1056.         rTurretData[turretid][e_turr_predict] = true;
  1057.     } else {
  1058.         if (!rTurretData[turretid][e_turr_predict])
  1059.             return 0;
  1060.         rTurretData[turretid][e_turr_predict] = false;
  1061.     }
  1062.     return 1;
  1063. }
  1064.  
  1065. stock ToggleTurretLOS(turretid, toggle)
  1066. {
  1067.     if (!Iter_Contains(rTurrets, turretid))
  1068.         return 0;
  1069.        
  1070.     if (toggle) {
  1071.         if (rTurretData[turretid][e_turr_los])
  1072.             return 0;
  1073.         rTurretData[turretid][e_turr_los] = true;
  1074.     } else {
  1075.         if (!rTurretData[turretid][e_turr_los])
  1076.             return 0;
  1077.         rTurretData[turretid][e_turr_los] = false;
  1078.     }
  1079.     return 1;
  1080. }
  1081.  
  1082. stock ToggleTurretLOSAim(turretid, toggle)
  1083. {
  1084.     if (!Iter_Contains(rTurrets, turretid))
  1085.         return 0;
  1086.        
  1087.     if (toggle) {
  1088.         if (rTurretData[turretid][e_turr_los_aim])
  1089.             return 0;
  1090.         rTurretData[turretid][e_turr_los_aim] = true;
  1091.     } else {
  1092.         if (!rTurretData[turretid][e_turr_los_aim])
  1093.             return 0;
  1094.         rTurretData[turretid][e_turr_los_aim] = false;
  1095.     }
  1096.     return 1;
  1097. }
  1098.  
  1099. stock ToggleTurretTargetFocus(turretid, toggle)
  1100. {
  1101.     if (!Iter_Contains(rTurrets, turretid))
  1102.         return 0;
  1103.        
  1104.     if (toggle) {
  1105.         if (rTurretData[turretid][e_turr_target_focus])
  1106.             return 0;
  1107.         rTurretData[turretid][e_turr_target_focus] = true;
  1108.     } else {
  1109.         if (!rTurretData[turretid][e_turr_target_focus])
  1110.             return 0;
  1111.         rTurretData[turretid][e_turr_target_focus] = false;
  1112.     }
  1113.     return 1;
  1114. }
  1115.  
  1116. stock UpdateTurretTextPos(turretid)
  1117. {
  1118.     if (!Iter_Contains(rTurrets, turretid))
  1119.         return 0;
  1120.        
  1121.     new
  1122.         Float:turPX,
  1123.         Float:turPY,
  1124.         Float:turPZ;
  1125.        
  1126.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  1127.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + rTurretData[turretid][e_turr_3dtext_xoffset]);
  1128.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + rTurretData[turretid][e_turr_3dtext_yoffset]);
  1129.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + rTurretData[turretid][e_turr_3dtext_zoffset]);
  1130.     return 1;
  1131. }
  1132.  
  1133. stock MoveTurret(turretid, Float:X, Float:Y, Float:Z, Float:Speed, Float:RotX = -1000.0, Float:RotY = -1000.0, Float:RotZ = -1000.0)
  1134. {
  1135.     if (!Iter_Contains(rTurrets, turretid) ||
  1136.         rTurretData[turretid][e_turr_behavior] == TURRET_BEHAVIOR_ROTATE_CLOCKWISE ||
  1137.         rTurretData[turretid][e_turr_behavior] == TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE)
  1138.             return 0;
  1139.            
  1140.     MoveDynamicObject(rTurretData[turretid][e_turr_objectid], X, Y, Z, Speed, RotX, RotY, RotZ);
  1141.     return 1;
  1142. }
  1143.  
  1144. stock TurretDamagePlayer(turretid, playerid)
  1145. {
  1146.     if (!Iter_Contains(rTurrets, turretid))
  1147.         return 0;
  1148.     if (funcidx("OnTurretHitPlayer") == -1 || CallLocalFunction("OnTurretHitPlayer", "dd", turretid, playerid)) {
  1149.         // Damage player
  1150.         new
  1151.             Float:a,
  1152.             Float:h,
  1153.             Float:dif;
  1154.            
  1155.         GetPlayerArmour(playerid, a);
  1156.         GetPlayerHealth(playerid, h);
  1157.         if (floatcmp(a, 0.0) != 1) {
  1158.             // No armor
  1159.             dif = h - rTurretData[turretid][e_turr_dmg];
  1160.             if (floatcmp(dif, 0.0) == -1 || floatcmp(dif, 0.0) == 0) {
  1161.                 // Dead
  1162.                 rTurret_Killed{playerid} = true;
  1163.                 rTurret_KilledBy[playerid] = turretid;
  1164.                 SetPlayerHealth(playerid, 0.0);
  1165.             } else
  1166.                 SetPlayerHealth(playerid, dif);
  1167.         } else {
  1168.             // Has armor
  1169.             dif = a - rTurretData[turretid][e_turr_dmg];
  1170.             if (floatcmp(dif, 0.0) == -1) {
  1171.                 // Damage health
  1172.                 new
  1173.                     Float:newdif = h - floatabs(dif);
  1174.                    
  1175.                 SetPlayerArmour(playerid, 0.0);
  1176.                
  1177.                 if (floatcmp(newdif, 0.0) == -1 || floatcmp(newdif, 0.0) == 0) {
  1178.                     // Dead
  1179.                     rTurret_Killed{playerid} = true;
  1180.                     rTurret_KilledBy[playerid] = turretid;
  1181.                     SetPlayerHealth(playerid, 0.0);
  1182.                 } else
  1183.                     SetPlayerHealth(playerid, newdif);
  1184.             } else
  1185.                 SetPlayerArmour(playerid, dif);
  1186.         }
  1187.         CallLocalFunction("OnPlayerTakeTurretDamage", "ddf", playerid, turretid, rTurretData[turretid][e_turr_dmg]);
  1188.     }
  1189.     return 1;
  1190. }
  1191.  
  1192. // ======================================================
  1193. // Hooks
  1194. // ======================================================
  1195.  
  1196. #if defined FILTERSCRIPT
  1197. public OnFilterScriptInit()
  1198. {
  1199.     new dupli_value = getproperty(.name = "rTurret_Duplicate_Prop");
  1200.     if (dupli_value == 126382) {
  1201.         printf("Warning: Duplicate instance of rTurret detected! Remove the include from your filterscript or gamemode.");
  1202.         rTurret_Is_Duplicate = true;
  1203.     } else {
  1204.         setproperty(.name = "rTurret_Duplicate_Prop", .value = 126382);
  1205.     }
  1206.        
  1207.     Iter_Init(rTurretTargets);
  1208.     Iter_Init(rTurretPlayersInBigArea);
  1209.     foreach(new i : Player) {
  1210.         rTurret_Killed{i} = false;
  1211.         rTurret_KilledBy[i] = INVALID_TURRET;
  1212.     }
  1213.     for (new i = 0; i < MAX_TURRETS; i++) {
  1214.         rTurretData[i][e_turr_timer] = -1;
  1215.         rTurretData[i][e_turr_visible_bullets] = -1;
  1216.         rTurretData[i][e_turr_objectid] = INVALID_OBJECT_ID;
  1217.     }
  1218.     return CallLocalFunction("rTurret_OnFilterScriptInit", "");
  1219. }
  1220.     #if defined _ALS_OnFilterScriptInit
  1221.         #undef OnFilterScriptInit
  1222.     #else
  1223.         #define _ALS_OnFilterScriptInit
  1224.     #endif
  1225.     #define OnFilterScriptInit rTurret_OnFilterScriptInit
  1226.     forward rTurret_OnFilterScriptInit();
  1227.    
  1228. public OnFilterScriptExit()
  1229. {
  1230.     if (!rTurret_Is_Duplicate) {
  1231.         deleteproperty(0, "", 126382);
  1232.     }
  1233.     foreach(new i : rTurrets)
  1234.         DestroyTurret(i);
  1235.        
  1236.     Streamer_DestroyAllItems(STREAMER_TYPE_OBJECT, 0);
  1237.     Streamer_DestroyAllItems(STREAMER_TYPE_AREA, 0);
  1238.     Streamer_DestroyAllItems(STREAMER_TYPE_3D_TEXT_LABEL, 0);
  1239.     return CallLocalFunction("rTurret_OnFilterScriptExit", "");
  1240. }
  1241.     #if defined _ALS_OnFilterScriptExit
  1242.         #undef OnFilterScriptExit
  1243.     #else
  1244.         #define _ALS_OnFilterScriptExit
  1245.     #endif
  1246.     #define OnFilterScriptExit rTurret_OnFilterScriptExit
  1247.     forward rTurret_OnFilterScriptExit();
  1248.    
  1249. #else
  1250. public OnGameModeInit()
  1251. {
  1252.     new dupli_value = getproperty(.name = "rTurret_Duplicate_Prop");
  1253.     if (dupli_value == 126382) {
  1254.         printf("Warning: Duplicate instance of rTurret detected! Remove the include from your filterscript or gamemode.");
  1255.         rTurret_Is_Duplicate = true;
  1256.     } else {
  1257.         setproperty(.name = "rTurret_Duplicate_Prop", .value = 126382);
  1258.     }
  1259.     Iter_Init(rTurretTargets);
  1260.     Iter_Init(rTurretPlayersInBigArea);
  1261.     foreach(new i : Player) {
  1262.         rTurret_Killed{i} = false;
  1263.         rTurret_KilledBy[i] = INVALID_TURRET;
  1264.     }
  1265.     for (new i = 0; i < MAX_TURRETS; i++) {
  1266.         rTurretData[i][e_turr_timer] = -1;
  1267.         rTurretData[i][e_turr_visible_bullets] = -1;
  1268.         rTurretData[i][e_turr_objectid] = INVALID_OBJECT_ID;
  1269.     }
  1270.     return CallLocalFunction("rTurret_OnGameModeInit", "");
  1271. }
  1272.     #if defined _ALS_OnGameModeInit
  1273.         #undef OnGameModeInit
  1274.     #else
  1275.         #define _ALS_OnGameModeInit
  1276.     #endif
  1277.     #define OnGameModeInit rTurret_OnGameModeInit
  1278.     forward rTurret_OnGameModeInit();
  1279.    
  1280. public OnGameModeExit()
  1281. {
  1282.     if (!rTurret_Is_Duplicate) {
  1283.         deleteproperty(0, "", 126382);
  1284.     }
  1285.     foreach(new i : rTurrets)
  1286.         DestroyTurret(i);
  1287.        
  1288.     Streamer_DestroyAllItems(STREAMER_TYPE_OBJECT, 0);
  1289.     Streamer_DestroyAllItems(STREAMER_TYPE_AREA, 0);
  1290.     Streamer_DestroyAllItems(STREAMER_TYPE_3D_TEXT_LABEL, 0);
  1291.     return CallLocalFunction("rTurret_OnGameModeExit", "");
  1292. }
  1293.     #if defined _ALS_OnGameModeExit
  1294.         #undef OnGameModeExit
  1295.     #else
  1296.         #define _ALS_OnGameModeExit
  1297.     #endif
  1298.     #define OnGameModeExit rTurret_OnGameModeExit
  1299.     forward rTurret_OnGameModeExit();
  1300. #endif
  1301.  
  1302. public OnPlayerConnect(playerid)
  1303. {
  1304.     rTurret_Killed{playerid} = false;
  1305.     rTurret_KilledBy[playerid] = INVALID_TURRET;
  1306.     return CallLocalFunction("rTurret_OnPlayerConnect", "d", playerid);
  1307. }
  1308. #if defined _ALS_OnPlayerConnect
  1309.     #undef OnPlayerConnect
  1310. #else
  1311.     #define _ALS_OnPlayerConnect
  1312. #endif
  1313. #define OnPlayerConnect rTurret_OnPlayerConnect
  1314. forward rTurret_OnPlayerConnect(playerid);
  1315.  
  1316. public OnPlayerSpawn(playerid)
  1317. {
  1318.     if (rTurret_Killed{playerid})
  1319.         // Prevent taking turret damage upon spawning
  1320.         SetTimerEx("Timer_ResetTurretKilled", 1000, false, "d", playerid);
  1321.     return CallLocalFunction("rTurret_OnPlayerSpawn", "d", playerid);
  1322. }
  1323. #if defined _ALS_OnPlayerSpawn
  1324.     #undef OnPlayerSpawn
  1325. #else
  1326.     #define _ALS_OnPlayerSpawn
  1327. #endif
  1328. #define OnPlayerSpawn rTurret_OnPlayerSpawn
  1329. forward rTurret_OnPlayerSpawn(playerid);
  1330.  
  1331. public OnPlayerDeath(playerid, killerid, reason)
  1332. {      
  1333.     if (rTurret_Killed{playerid}) {
  1334.         if (Iter_Contains(rTurrets, rTurret_KilledBy[playerid])) {
  1335.             new
  1336.                 turretid = rTurret_KilledBy[playerid];
  1337.                
  1338.             killerid = rTurretData[turretid][e_turr_owner];
  1339.             reason = 47;
  1340.             if (Iter_Contains(rTurretTargets[turretid], playerid))
  1341.                 Iter_Remove(rTurretTargets[turretid], playerid);
  1342.         }
  1343.     }
  1344.     return CallLocalFunction("rTurret_OnPlayerDeath", "ddd", playerid, killerid, reason);
  1345. }
  1346. #if defined _ALS_OnPlayerDeath
  1347.     #undef OnPlayerDeath
  1348. #else
  1349.     #define _ALS_OnPlayerDeath
  1350. #endif
  1351. #define OnPlayerDeath rTurret_OnPlayerDeath
  1352. forward rTurret_OnPlayerDeath(playerid, killerid, reason);
  1353.  
  1354. public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
  1355. {
  1356.     if (hittype == BULLET_HIT_TYPE_PLAYER_OBJECT) {
  1357.         new
  1358.             streamerid = Streamer_GetItemStreamerID(playerid, STREAMER_TYPE_OBJECT, hitid);
  1359.         if (IsValidDynamicObject(streamerid)) {
  1360.             if (Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, streamerid, E_STREAMER_EXTRA_ID, TURRET_INT)) {
  1361.                 // Turret object
  1362.                 new
  1363.                     data[3],
  1364.                     turretid;
  1365.                    
  1366.                 Streamer_GetArrayData(STREAMER_TYPE_OBJECT, streamerid, E_STREAMER_EXTRA_ID, data);
  1367.                 turretid = data[1];
  1368.                
  1369.                 if (rTurretData[turretid][e_turr_has_health]) {
  1370.                     // Deplete health
  1371.                     // Credits to Slice for weapon damage values - https://github.com/oscar-broman/samp-weapon-config
  1372.                     static Float:rTurret_weapon_damage[] = {
  1373.                         1.0, // 0 - Fist
  1374.                         1.0, // 1 - Brass knuckles
  1375.                         1.0, // 2 - Golf club
  1376.                         1.0, // 3 - Nitestick
  1377.                         1.0, // 4 - Knife
  1378.                         1.0, // 5 - Bat
  1379.                         1.0, // 6 - Shovel
  1380.                         1.0, // 7 - Pool cue
  1381.                         1.0, // 8 - Katana
  1382.                         1.0, // 9 - Chainsaw
  1383.                         1.0, // 10 - Dildo
  1384.                         1.0, // 11 - Dildo 2
  1385.                         1.0, // 12 - Vibrator
  1386.                         1.0, // 13 - Vibrator 2
  1387.                         1.0, // 14 - Flowers
  1388.                         1.0, // 15 - Cane
  1389.                         82.5, // 16 - Grenade
  1390.                         0.0, // 17 - Teargas
  1391.                         1.0, // 18 - Molotov
  1392.                         9.9, // 19 - Vehicle M4 (custom)
  1393.                         46.2, // 20 - Vehicle minigun (custom)
  1394.                         0.0, // 21
  1395.                         8.25, // 22 - Colt 45
  1396.                         13.2, // 23 - Silenced
  1397.                         46.2, // 24 - Deagle
  1398.                         3.3, // 25 - Shotgun
  1399.                         3.3, // 26 - Sawed-off
  1400.                         4.95, // 27 - Spas
  1401.                         6.6, // 28 - UZI
  1402.                         8.25, // 29 - MP5
  1403.                         9.9, // 30 - AK47
  1404.                         9.9, // 31 - M4
  1405.                         6.6, // 32 - Tec9
  1406.                         24.75, // 33 - Cuntgun
  1407.                         41.25, // 34 - Sniper
  1408.                         82.5, // 35 - Rocket launcher
  1409.                         82.5, // 36 - Heatseeker
  1410.                         1.0, // 37 - Flamethrower
  1411.                         46.2, // 38 - Minigun
  1412.                         82.5, // 39 - Satchel
  1413.                         0.0, // 40 - Detonator
  1414.                         0.33, // 41 - Spraycan
  1415.                         0.33, // 42 - Fire extinguisher
  1416.                         0.0, // 43 - Camera
  1417.                         0.0, // 44 - Night vision
  1418.                         0.0, // 45 - Infrared
  1419.                         0.0, // 46 - Parachute
  1420.                         0.0, // 47 - Fake pistol
  1421.                         2.64, // 48 - Pistol whip (custom)
  1422.                         9.9, // 49 - Vehicle
  1423.                         330.0, // 50 - Helicopter blades
  1424.                         82.5, // 51 - Explosion
  1425.                         1.0, // 52 - Car park (custom)
  1426.                         1.0, // 53 - Drowning
  1427.                         165.0  // 54 - Splat
  1428.                     };
  1429.                    
  1430.                     if (CallLocalFunction("OnPlayerShootTurret", "dddfff", playerid, weaponid, turretid, fX, fY, fZ) == 1) {
  1431.                         new
  1432.                             Float:diff = rTurretData[turretid][e_turr_health] - rTurret_weapon_damage[weaponid];
  1433.                         if (floatcmp(0.0, diff) == 1) {
  1434.                             CallLocalFunction("OnTurretDeath", "ddd", turretid, playerid, weaponid);
  1435.                             DestroyTurret(turretid);
  1436.                         } else {
  1437.                             rTurretData[turretid][e_turr_health] = diff;
  1438.                         }
  1439.                     } else {
  1440.                         if (floatcmp(0.0, rTurretData[turretid][e_turr_health]) == 1) {
  1441.                             CallLocalFunction("OnTurretDeath", "ddd", turretid, playerid, weaponid);
  1442.                             DestroyTurret(turretid);
  1443.                         }
  1444.                     }
  1445.                 }
  1446.             }
  1447.         }
  1448.     }
  1449.     return CallLocalFunction("rTurret_OnPlayerWeaponShot", "ddddfff", playerid, weaponid, hittype, hitid, fX, fY, fZ);
  1450. }
  1451. #if defined _ALS_OnPlayerWeaponShot
  1452.     #undef OnPlayerWeaponShot
  1453. #else
  1454.     #define _ALS_OnPlayerWeaponShot
  1455. #endif
  1456. #define OnPlayerWeaponShot rTurret_OnPlayerWeaponShot
  1457. forward rTurret_OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ);
  1458.  
  1459. public OnDynamicObjectMoved(objectid)
  1460. {
  1461.     if (!IsValidDynamicObject(objectid)) {
  1462.         return CallLocalFunction("rTurret_OnDynamicObjectMoved", "d", objectid);
  1463.     }
  1464.     if (Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, TURRET_BULLET_OBJECT_INT)) {
  1465.         // Destroy bullet and its area
  1466.         new
  1467.             data[4],
  1468.             turretid,
  1469.             bullet_areaid,
  1470.             colliPath;
  1471.            
  1472.         Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, data);
  1473.         turretid = data[1];
  1474.         bullet_areaid = data[2];
  1475.         colliPath = data[3];
  1476.        
  1477.         if (colliPath == 1) {
  1478.             new
  1479.                 Float:bX, Float:bY, Float:bZ;
  1480.                
  1481.             GetDynamicObjectPos(objectid, bX, bY, bZ);
  1482.             CallLocalFunction("OnTurretBulletCollision", "dfff", turretid, bX, bY, bZ);
  1483.         }
  1484.            
  1485.         DestroyDynamicArea(bullet_areaid);
  1486.         DestroyDynamicObject(objectid);
  1487.         rTurretData[turretid][e_turr_visible_bullets]--;
  1488.         //return CallLocalFunction("rTurret_OnDynamicObjectMoved", "d", objectid);
  1489.         return 1;
  1490.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, TURRET_INT)) {
  1491.         // Turret object
  1492.         new
  1493.             data[3],
  1494.             turretid,
  1495.             Float:oX,
  1496.             Float:oY,
  1497.             Float:oZ,
  1498.             Float:oRX,
  1499.             Float:oRY,
  1500.             Float:oRZ,
  1501.             movestate;
  1502.            
  1503.         Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, data);
  1504.         turretid = data[1];
  1505.         movestate = data[2];
  1506.         GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], oX, oY, oZ);
  1507.         GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, oRZ);
  1508.         switch(movestate) {
  1509.             case TURRET_MOVE_ROTATE_CLOCKWISE_1:{
  1510.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  1511.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  1512.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ - 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, -359.0);
  1513.             }
  1514.             case TURRET_MOVE_ROTATE_CLOCKWISE_2: {
  1515.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  1516.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  1517.                 SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, 0);
  1518.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ + 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, -179.0);
  1519.             }
  1520.             case TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1: {
  1521.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  1522.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  1523.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ - 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, 359.0);
  1524.             }
  1525.             case TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2: {
  1526.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  1527.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  1528.                 SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, 0);
  1529.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ + 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, 179.0);
  1530.             }
  1531.             default: CallLocalFunction("OnTurretMoved", "d", turretid);
  1532.         }
  1533.         return 1;
  1534.     }
  1535.     return CallLocalFunction("rTurret_OnDynamicObjectMoved", "d", objectid);
  1536. }
  1537. #if defined _ALS_OnDynamicObjectMoved
  1538.     #undef OnDynamicObjectMoved
  1539. #else
  1540.     #define _ALS_OnDynamicObjectMoved
  1541. #endif
  1542. #define OnDynamicObjectMoved rTurret_OnDynamicObjectMoved
  1543. forward rTurret_OnDynamicObjectMoved(objectid);
  1544.  
  1545. public OnPlayerEnterDynamicArea(playerid, areaid)
  1546. {
  1547.     // Check if player is dead or not spawned
  1548.     if (rTurret_Killed{playerid})
  1549.         return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1550.        
  1551.     if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT)) {
  1552.         // Destroy bullet and its area
  1553.         new
  1554.             data[4],
  1555.             turretid = INVALID_TURRET,
  1556.             bulletid,
  1557.             target_focusid;
  1558.            
  1559.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1560.         turretid = data[1];
  1561.         bulletid = data[2];
  1562.         target_focusid = data[3];
  1563.        
  1564.         if (!Iter_Contains(rTurrets, turretid))
  1565.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1566.            
  1567.         if (rTurretData[turretid][e_turr_owner] == playerid || (rTurretData[turretid][e_turr_team] != 255 && rTurretData[turretid][e_turr_team] == GetPlayerTeam(playerid)))
  1568.             return 1;
  1569.            
  1570.         if (rTurretData[turretid][e_turr_target_focus])
  1571.             if (target_focusid != INVALID_PLAYER_ID && target_focusid != playerid)
  1572.                 // playerid is not focus target and is therefore immune to damage
  1573.                 return 1;
  1574.            
  1575.         // "*** Streamer_GetArrayData: Invalid ID specified" message shows if you destroy area here.
  1576.         // To avoid this, hide object and efficiently "disable" area. Object and area will be destroyed under OnDynamicObjectMoved.
  1577.        
  1578.         // DestroyDynamicArea(areaid);
  1579.         // DestroyDynamicObject(bulletid);
  1580.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT);
  1581.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_STREAM_DISTANCE, 0.0);
  1582.            
  1583.         rTurretData[turretid][e_turr_visible_bullets]--;
  1584.         TurretDamagePlayer(turretid, playerid);
  1585.         return 1;
  1586.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT)) {
  1587.         // Turret within hearing range of player
  1588.         new
  1589.             data[2],
  1590.             turretid = INVALID_TURRET;
  1591.            
  1592.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1593.         turretid = data[0];
  1594.         if (!Iter_Contains(rTurrets, turretid))
  1595.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1596.         Iter_Add(rTurretPlayersInBigArea[data[0]], playerid);
  1597.         return 1;
  1598.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT)) {
  1599.         // Player within target range of turret
  1600.         new
  1601.             data[2],
  1602.             turretid = INVALID_TURRET;
  1603.            
  1604.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1605.         turretid = data[0];
  1606.         if (!Iter_Contains(rTurrets, turretid))
  1607.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1608.         if (rTurretData[turretid][e_turr_owner] == playerid || (rTurretData[turretid][e_turr_team] != 255 && rTurretData[turretid][e_turr_team] == GetPlayerTeam(playerid)))
  1609.             return 1;
  1610.         Iter_Add(rTurretTargets[turretid], playerid);
  1611.         if (rTurretData[turretid][e_turr_timer] == -1 && rTurretData[turretid][e_turr_active])
  1612.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  1613.         return 1;
  1614.     }
  1615.     return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1616. }
  1617. #if defined _ALS_OnPlayerEnterDynamicArea
  1618.     #undef OnPlayerEnterDynamicArea
  1619. #else
  1620.     #define _ALS_OnPlayerEnterDynamicArea
  1621. #endif
  1622. #define OnPlayerEnterDynamicArea rTurret_OnPlayerEnterArea
  1623. forward rTurret_OnPlayerEnterArea(playerid, areaid);
  1624.  
  1625. public OnPlayerLeaveDynamicArea(playerid, areaid)
  1626. {
  1627.     if (!IsValidDynamicArea(areaid)) {
  1628.         return CallLocalFunction("rTurret_OnPlayerLeaveArea", "dd", playerid, areaid);
  1629.     }
  1630.     if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT)) {
  1631.         // Turret out of hearing range for player
  1632.         new
  1633.             data[2],
  1634.             turretid = INVALID_TURRET;
  1635.            
  1636.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1637.         turretid = data[0];
  1638.         if (!Iter_Contains(rTurrets, turretid))
  1639.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1640.         Iter_Remove(rTurretPlayersInBigArea[turretid], playerid);
  1641.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT)) {
  1642.         // Player out of turret target range
  1643.         new
  1644.             data[2],
  1645.             turretid = INVALID_TURRET;
  1646.            
  1647.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1648.         turretid = data[0];
  1649.         if (!Iter_Contains(rTurrets, turretid))
  1650.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1651.         Iter_Remove(rTurretTargets[turretid], playerid);
  1652.         if (!Iter_Count(rTurretTargets[turretid]) && rTurretData[turretid][e_turr_checkarea]) {
  1653.             if (rTurretData[turretid][e_turr_timer] != -1) {
  1654.                 KillTimer(rTurretData[turretid][e_turr_timer]);
  1655.                 rTurretData[turretid][e_turr_timer] = -1;
  1656.             }
  1657.         }
  1658.     }
  1659.     return CallLocalFunction("rTurret_OnPlayerLeaveArea", "dd", playerid, areaid);
  1660. }
  1661. #if defined _ALS_OnPlayerLeaveDynamicArea
  1662.     #undef OnPlayerLeaveDynamicArea
  1663. #else
  1664.     #define _ALS_OnPlayerLeaveDynamicArea
  1665. #endif
  1666. #define OnPlayerLeaveDynamicArea rTurret_OnPlayerLeaveArea
  1667. forward rTurret_OnPlayerLeaveArea(playerid, areaid);
  1668.  
  1669. // ======================================================
  1670. // Internal Functions
  1671. // ======================================================
  1672.  
  1673. forward Timer_TurretShoot(turretid);
  1674. forward Timer_ResetTurretKilled(playerid);
  1675.  
  1676. public Timer_TurretShoot(turretid)
  1677. {
  1678.     if (!Iter_Contains(rTurrets, turretid) || (!Iter_Count(rTurretTargets[turretid]) && rTurretData[turretid][e_turr_checkarea])) {
  1679.         // Turret doesn't "exist" or no targets within range to shoot for aim behavior
  1680.         if (rTurretData[turretid][e_turr_timer] != -1) {
  1681.             KillTimer(rTurretData[turretid][e_turr_timer]);
  1682.             rTurretData[turretid][e_turr_timer] = -1;
  1683.         }
  1684.         return 0;
  1685.     }
  1686.        
  1687.     new
  1688.         areaid,
  1689.         bulletid,
  1690.         targetid = INVALID_PLAYER_ID,
  1691.         // Player Pos
  1692.         Float:pX,
  1693.         Float:pY,
  1694.         Float:pZ,
  1695.         // Turret Pos and Rot
  1696.         Float:turPX,
  1697.         Float:turPY,
  1698.         Float:turPZ,
  1699.         Float:turRX,
  1700.         Float:turRY,
  1701.         Float:turRZ,
  1702.         Float:newPX,
  1703.         Float:newPY,
  1704.         Float:newPZ,
  1705.         target_focusid = INVALID_PLAYER_ID,
  1706.         // LoS
  1707.         Float:colliX, Float:colliY, Float:colliZ;
  1708.    
  1709.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  1710.     GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  1711.     newPZ = turPZ + 1.15;
  1712.    
  1713.     if (TURRET_BEHAVIOR_AIM_CLOSEST <= rTurretData[turretid][e_turr_behavior] <= TURRET_BEHAVIOR_AIM_CUSTOM) {
  1714.         // Set turret facing target
  1715.         new
  1716.             Float:targDist;
  1717.                        
  1718.         switch(rTurretData[turretid][e_turr_behavior]) {
  1719.             case TURRET_BEHAVIOR_AIM_CLOSEST: {
  1720.                 targDist = 100000.0;
  1721.                 foreach(new i : rTurretTargets[turretid]) {
  1722.                     if (floatcmp(targDist, GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ)) == 1) {
  1723.                         // Closest player so far
  1724.                         targetid = i;
  1725.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1726.                         GetPlayerPos(i, pX, pY, pZ);
  1727.                     }
  1728.                 }
  1729.             }
  1730.             case TURRET_BEHAVIOR_AIM_FARTHEST: {
  1731.                 foreach(new i : rTurretTargets[turretid]) {
  1732.                     if (floatcmp(targDist, GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ)) == -1) {
  1733.                         // Farthest player so far
  1734.                         targetid = i;
  1735.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1736.                         GetPlayerPos(i, pX, pY, pZ);
  1737.                     }
  1738.                 }
  1739.             }
  1740.             case TURRET_BEHAVIOR_AIM_WEAKEST: {
  1741.                 new
  1742.                     Float:a,
  1743.                     Float:h,
  1744.                     Float:smallSum = 1000.0;
  1745.                    
  1746.                 foreach(new i : rTurretTargets[turretid]) {
  1747.                     GetPlayerArmour(i, a);
  1748.                     GetPlayerHealth(i, h);
  1749.                     if (floatcmp(smallSum, a + h) == 1) {
  1750.                         // Player with lowest health and armour so far
  1751.                         smallSum = a + h;
  1752.                         targetid = i;
  1753.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1754.                         GetPlayerPos(i, pX, pY, pZ);
  1755.                     }
  1756.                 }
  1757.             }
  1758.             case TURRET_BEHAVIOR_AIM_STRONGEST: {
  1759.                 new
  1760.                     Float:a,
  1761.                     Float:h,
  1762.                     Float:bigSum = 0.0;
  1763.                    
  1764.                 foreach(new i : rTurretTargets[turretid]) {
  1765.                     GetPlayerArmour(i, a);
  1766.                     GetPlayerHealth(i, h);
  1767.                     if (floatcmp(bigSum, a + h) == -1) {
  1768.                         // Player with highest health and armour so far
  1769.                         bigSum = a + h;
  1770.                         targetid = i;
  1771.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1772.                         GetPlayerPos(i, pX, pY, pZ);
  1773.                     }
  1774.                 }
  1775.             }
  1776.             case TURRET_BEHAVIOR_AIM_SINGLE: {
  1777.                 if (IsPlayerConnected(rTurretData[turretid][e_turr_target])) {
  1778.                     targetid = rTurretData[turretid][e_turr_target];
  1779.                     targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1780.                     GetPlayerPos(targetid, pX, pY, pZ);
  1781.                 }
  1782.             }
  1783.             case TURRET_BEHAVIOR_AIM_CUSTOM: {
  1784.                 if (funcidx("OnTurretCustomShoot") != -1) {
  1785.                     new
  1786.                         rtn = CallLocalFunction("OnTurretCustomShoot", "d", turretid);
  1787.                        
  1788.                     if (IsPlayerConnected(rtn)) {
  1789.                         targetid = rtn;
  1790.                         targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1791.                         GetPlayerPos(targetid, pX, pY, pZ);
  1792.                     }
  1793.                 }
  1794.             }
  1795.             case TURRET_BEHAVIOR_AIM_RANDOM: {
  1796.                 if (Iter_Count(rTurretTargets[turretid]) > 0) {
  1797.                     targetid = Iter_Random(rTurretTargets[turretid]);
  1798.                     targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1799.                     GetPlayerPos(targetid, pX, pY, pZ);
  1800.                 }
  1801.             }
  1802.         }
  1803.            
  1804.         if (targetid != INVALID_PLAYER_ID) {
  1805.             // Set turret facing target
  1806.             new
  1807.                 Float:vX,
  1808.                 Float:vY,
  1809.                 Float:vZ,
  1810.                 Float:Speed;
  1811.                
  1812.             if (rTurretData[turretid][e_turr_target_focus])
  1813.                 // Set turret's target focus (all other players will be immune to damage)
  1814.                 target_focusid = targetid;
  1815.                
  1816.             if (rTurretData[turretid][e_turr_3dspace])
  1817.                 // Turret aims in 3d space
  1818.                 // Bullet's destination z value changes
  1819.                 newPZ = newPZ + (rTurretData[turretid][e_turr_range] * ((pZ - newPZ) / (targDist)));
  1820.  
  1821.             turRZ = atan2(pY - turPY, pX - turPX);
  1822.            
  1823.             if (IsPlayerInAnyVehicle(targetid))
  1824.                 GetVehicleVelocity(GetPlayerVehicleID(targetid), vX, vY, vZ);
  1825.             else
  1826.                 GetPlayerVelocity(targetid, vX, vY, vZ);
  1827.                
  1828.             // player speed in units per second
  1829.             Speed = floatsqroot(((vX * vX) + (vY * vY) + (vZ * vZ))) * 81.137;
  1830.            
  1831.             if (floatcmp(Speed, 0.0) != 0) {
  1832.                 if (!rTurretData[turretid][e_turr_predict]) {
  1833.                     newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1834.                     newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1835.                 } else {
  1836.                     // Predictive aim algorithm (improved)
  1837.                     // Issues: Overcompensates angle adjustment while target is jumping due to short burst of high velocity
  1838.                     new
  1839.                         Float:pA;
  1840.                        
  1841.                     GetPlayerFacingAngle(targetid, pA);
  1842.                     pA = -pA + 360;
  1843.                    
  1844.                     new
  1845.                         Float:ppX = pX - turPX,
  1846.                         Float:ppY = pY - turPY;
  1847.                    
  1848.                     new
  1849.                         Float:bulletCross = ppX * (vY * 40.5685) - ppY * (vX * 40.5685),
  1850.                         Float:magR = floatsqroot(ppX * ppX + ppY * ppY),
  1851.                         Float:angleAdjust = asin(bulletCross / (rTurretData[turretid][e_turr_speed] * magR)),
  1852.                         Float:finalAngle = angleAdjust + atan2(ppY, ppX);
  1853.  
  1854.                     if (angleAdjust == angleAdjust) {
  1855.                         turRZ = finalAngle;
  1856.                         newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1857.                         newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1858.                     } else {
  1859.                         // NaN
  1860.                         newPX = pX;
  1861.                         newPY = pY;
  1862.                     }
  1863.                 }
  1864.             } else {
  1865.                 // Idle targets don't get hit by very fast bullets (speed >= 20 && rate >= 250)
  1866.                 // This part won't matter anyway
  1867.                 newPX = pX;
  1868.                 newPY = pY;
  1869.                 newPZ = pZ;
  1870.             }
  1871.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  1872.         } else {
  1873.             // Turret doesn't change direction
  1874.             newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1875.             newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1876.         }
  1877.     } else {
  1878.         // Redundant? I don't remember
  1879.         newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1880.         newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1881.     }
  1882.    
  1883.     new
  1884.         // Bullet origin
  1885.         Float:bOriginX = turPX + (1.0 * floatsin(-(turRZ + 270), degrees)),
  1886.         Float:bOriginY = turPY + (1.0 * floatcos(-(turRZ + 270), degrees)),
  1887.         Float:bOriginZ = turPZ + 1.15;
  1888.    
  1889.     // LoS aim
  1890.     if (rTurretData[turretid][e_turr_los]) {
  1891.         // LOS detection - if collision coordinates stored, bullet path is blocked
  1892.         CA_RayCastLine(bOriginX, bOriginY, bOriginZ, newPX, newPY, newPZ, colliX, colliY, colliZ);
  1893.         if (rTurretData[turretid][e_turr_los_aim]) {
  1894.             // Don't shoot if there is no LoS
  1895.             if (floatcmp(colliX, 0.0) != 0 || floatcmp(colliY, 0.0) != 0 || floatcmp(colliZ, 0.0) != 0) {
  1896.                 // Path leads to object collision, check if any targets ahead of collision
  1897.                 new
  1898.                     Float:distToColli;
  1899.                    
  1900.                 Streamer_GetDistanceToItem(colliX, colliY, colliZ, STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], distToColli, 3);
  1901.                
  1902.                 if (floatcmp(GetPlayerDistanceFromPoint(targetid, turPX, turPY, turPZ), distToColli) == 1) {
  1903.                     // Turret to player > Turret to obj collision
  1904.                     return 0;
  1905.                 }
  1906.             }
  1907.         }
  1908.     }
  1909.    
  1910.     // Bullet creation set to go!
  1911.     new
  1912.         bool:colliPath = false,
  1913.         visibleBullets = rTurretData[turretid][e_turr_visible_bullets] + 1;
  1914.    
  1915.     if (visibleBullets >= rTurretData[turretid][e_turr_max_visible_bullets])
  1916.         // Cancel bullet creation
  1917.         return 0;
  1918.     else
  1919.         rTurretData[turretid][e_turr_visible_bullets]++;
  1920.        
  1921.     if (!rTurretData[turretid][e_turr_playsound]) {
  1922.         // Stream in bullets for players in range
  1923.         foreach(new i : rTurretPlayersInBigArea[turretid]) {
  1924.             Streamer_Update(i, 0);
  1925.         }
  1926.     } else {
  1927.         // Same as above, but also play sound
  1928.         foreach(new i : rTurretPlayersInBigArea[turretid]) {
  1929.             Streamer_Update(i, 0);
  1930.             if (IsPlayerInRangeOfPoint(i, 20.0, turPX, turPY, turPZ))
  1931.                 PlayerPlaySound(i, rTurretData[turretid][e_turr_soundid], 0, 0, 0);
  1932.             else {
  1933.                 GetPlayerPos(i, pX, pY, pZ);
  1934.                 PlayerPlaySound(i, rTurretData[turretid][e_turr_soundid], pX, pY, pZ + 7);
  1935.             }
  1936.         }
  1937.     }
  1938.    
  1939.     if (targetid != INVALID_PLAYER_ID) {
  1940.         new
  1941.             Float:vX, Float:vY, Float:vZ,
  1942.             Float:Speed;
  1943.        
  1944.         if (IsPlayerInAnyVehicle(targetid))
  1945.             GetVehicleVelocity(GetPlayerVehicleID(targetid), vX, vY, vZ);
  1946.         else
  1947.             GetPlayerVelocity(targetid, vX, vY, vZ);
  1948.            
  1949.         // player speed in units per second
  1950.         Speed = floatsqroot(((vX * vX) + (vY * vY) + (vZ * vZ))) * 81.137;
  1951.         if (floatcmp(Speed, 0.0) == 0) {
  1952.             // Idle players don't take damage so we'll have to force damage
  1953.             TurretDamagePlayer(turretid, targetid);
  1954.             return 0;
  1955.         }
  1956.     }
  1957.        
  1958.     if (floatcmp(colliX, 0.0) == 0 && floatcmp(colliY, 0.0) == 0 && floatcmp(colliZ, 0.0) == 0) {
  1959.         // LOS detection - if collision coordinates stored, bullet path is blocked
  1960.         colliPath = false;
  1961.     } else {
  1962.         colliPath = true;
  1963.     }
  1964.        
  1965.     if ((TURRET_BEHAVIOR_AIM_CLOSEST <= rTurretData[turretid][e_turr_behavior] <= TURRET_BEHAVIOR_AIM_CUSTOM) && targetid != INVALID_PLAYER_ID)
  1966.         // Don't want the turret rotating when it's not shooting due to no LoS
  1967.         SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  1968.        
  1969.     bulletid =
  1970.         CreateDynamicObject(rTurretData[turretid][e_turr_bullet_model],
  1971.             bOriginX + rTurretData[turretid][e_turr_bullet_xoffset],
  1972.             bOriginY + rTurretData[turretid][e_turr_bullet_yoffset],
  1973.             bOriginZ + rTurretData[turretid][e_turr_bullet_zoffset],
  1974.             rTurretData[turretid][e_turr_bullet_rx],
  1975.             rTurretData[turretid][e_turr_bullet_ry],
  1976.             turRZ + rTurretData[turretid][e_turr_bullet_rz],
  1977.             rTurretData[turretid][e_turr_world],
  1978.             rTurretData[turretid][e_turr_interior],
  1979.             .streamdistance = rTurretData[turretid][e_turr_stream]);
  1980.            
  1981.     if (rTurretData[turretid][e_turr_bullet_color] != 0)
  1982.         SetDynamicObjectMaterial(bulletid, 0, -1, "none", "none", rTurretData[turretid][e_turr_bullet_color]);
  1983.  
  1984.     areaid = CreateDynamicSphere(0, 0, 0, rTurretData[turretid][e_turr_bullet_radius], rTurretData[turretid][e_turr_world], rTurretData[turretid][e_turr_interior]);
  1985.     // Replace when cuboids become attachable to objects
  1986.     //areaid = CreateDynamicCuboid(0 - rTurretData[turretid][e_turr_bullet_radius], 0 - rTurretData[turretid][e_turr_bullet_radius], -3.0, rTurretData[turretid][e_turr_bullet_radius], 0 - rTurretData[turretid][e_turr_bullet_radius], 3.0, rTurretData[turretid][e_turr_world], rTurretData[turretid][e_turr_interior]);
  1987.     AttachDynamicAreaToObject(areaid, bulletid);
  1988.        
  1989.     // Bullet object array data (identifier, turretid, areaid)
  1990.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, TURRET_BULLET_OBJECT_INT);
  1991.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, turretid);
  1992.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, areaid);
  1993.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, (colliPath) ? 1 : 0);
  1994.    
  1995.     // Area array data (identifier, turretid, bullet objectid)
  1996.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT);
  1997.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, turretid);
  1998.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, bulletid);
  1999.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, target_focusid);
  2000.    
  2001.     if (rTurretData[turretid][e_turr_los]) {
  2002.         // LOS detection - if collision coordinates stored, bullet path is blocked
  2003.         if (!colliPath)
  2004.             MoveDynamicObject(bulletid, newPX, newPY, newPZ, rTurretData[turretid][e_turr_speed]);
  2005.         else
  2006.             MoveDynamicObject(bulletid, colliX, colliY, colliZ, rTurretData[turretid][e_turr_speed]);
  2007.     } else {
  2008.         MoveDynamicObject(bulletid, newPX, newPY, newPZ, rTurretData[turretid][e_turr_speed]);
  2009.     }
  2010.     return 1;
  2011. }
  2012.  
  2013. public Timer_ResetTurretKilled(playerid)
  2014. {
  2015.     rTurret_Killed{playerid} = false;
  2016.     rTurret_KilledBy[playerid] = INVALID_TURRET;
  2017. }
  2018.  
  2019. // ======================================================
  2020. // British English Macros
  2021. // ======================================================
  2022.  
  2023. #define TURRET_BEHAVIOUR_STATIONARY                 TURRET_BEHAVIOR_STATIONARY
  2024. #define TURRET_BEHAVIOUR_ROTATE_CLOCKWISE           TURRET_BEHAVIOR_ROTATE_CLOCKWISE
  2025. #define TURRET_BEHAVIOUR_ROTATE_COUNTERCLOCKWISE    TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE
  2026. #define TURRET_BEHAVIOUR_AIM_CLOSEST                TURRET_BEHAVIOR_AIM_CLOSEST
  2027. #define TURRET_BEHAVIOUR_AIM_FARTHEST               TURRET_BEHAVIOR_AIM_FARTHEST
  2028. #define TURRET_BEHAVIOUR_AIM_WEAKEST                TURRET_BEHAVIOR_AIM_WEAKEST
  2029. #define TURRET_BEHAVIOUR_AIM_STRONGEST              TURRET_BEHAVIOR_AIM_STRONGEST
  2030. #define TURRET_BEHAVIOUR_AIM_RANDOM                 TURRET_BEHAVIOR_AIM_RANDOM
  2031. #define TURRET_BEHAVIOUR_AIM_SINGLE                 TURRET_BEHAVIOR_AIM_SINGLE
  2032. #define TURRET_BEHAVIOUR_AIM_CUSTOM                 TURRET_BEHAVIOR_AIM_CUSTOM
  2033.  
  2034. #define GetTurretBehaviour                          GetTurretBehavior
  2035. #define SetTurretBehaviour                          SetTurretBehavior
  2036. #define GetTurretBulletColour                       GetTurretBulletColor
  2037. #define SetTurretBulletColour                       SetTurretBulletColor
RAW Paste Data