robotmonkey

SA-MP - rTurret v1.0

Jul 14th, 2014
318
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ================================================================
  2. //  rTurret
  3. //      Version 1.0
  4. //      Created for SA-MP 0.3z
  5. //      © 2014 by Corekt/robotmonkey
  6. //
  7. //  Changelog:
  8. //      Version 1.0 (7/14/2014)
  9. //          First release
  10. //
  11. //  Description:
  12. //      Designed with flexibility in mind, rTurret allows you to
  13. //      easily create and customize interactive turrets to your
  14. //      liking.
  15. //
  16. //  Installation:
  17. //      Requires -
  18. //          Streamer Plugin - http://forum.sa-mp.com/showthread.php?t=102865
  19. //          foreach include - http://forum.sa-mp.com/showthread.php?t=92679
  20. //      If using this in a filterscript, define FILTERSCRIPT
  21. //      before including this file.
  22. //
  23. //  Thanks to:
  24. //      Y_Less - foreach
  25. //      Incognito - Streamer Plugin
  26. //      Kye/Kalcor and the SA-MP Team - SA-MP
  27. //
  28. //  Core Functions:
  29. //      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);
  30. //      DestroyTurret(turretid, &iter_next = -1);
  31. //      IsValidTurret(turretid);
  32. //
  33. //  Callbacks:
  34. //      OnTurretCreate(turretid);
  35. //      OnTurretDestroy(turretid);
  36. //      OnTurretHitPlayer(turretid, playerid);
  37. //      OnPlayerTakeTurretDamage(playerid, turretid, Float:damage);
  38. //      OnTurretMoved(turretid);
  39. //      OnTurretCustomShoot(turretid);
  40. //
  41. //  For more documentation and updates visit:
  42. //      http://forum.sa-mp.com/showthread.php?p=3121654
  43. // ================================================================
  44.  
  45. #if !defined _samp_included
  46.     #error You must include a_samp before rTurret.
  47. #endif
  48.  
  49. #include <streamer>
  50. #include <foreach>
  51.  
  52. #if !defined MAX_TURRETS
  53.     #define MAX_TURRETS                             (256)
  54. #endif
  55.  
  56. #if !defined MIN_TURRET_RATE
  57.     #define MIN_TURRET_RATE                         (100)
  58. #endif
  59.  
  60. #if !defined MAX_TURRET_VISIBLE_BULLETS
  61.     #define MAX_TURRET_VISIBLE_BULLETS              (32)
  62. #endif
  63.  
  64. #define INVALID_TURRET                              (-1)
  65.  
  66. // Streamer data identifiers
  67. // Although highly unlikely, make sure your
  68. // streamer extra data don't contain these values
  69. #define TURRET_INT                                  (-706637)
  70. #define TURRET_BIG_AREA_INT                         (-316)
  71. #define TURRET_SHOOT_AREA_INT                       (-56007)
  72. #define TURRET_BULLET_AREA_INT                      (-4234)
  73. #define TURRET_BULLET_OBJECT_INT                    (-801137)
  74.  
  75. // Turret moveids
  76. #define TURRET_MOVE_ROTATE_CLOCKWISE_1              (-1)
  77. #define TURRET_MOVE_ROTATE_CLOCKWISE_2              (-2)
  78. #define TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1       (-3)
  79. #define TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2       (-4)
  80. #define TURRET_MOVE_OTHER                           (-5)
  81.  
  82. // Turret Behaviors
  83. #define TURRET_BEHAVIOR_STATIONARY                  (0)
  84. #define TURRET_BEHAVIOR_ROTATE_CLOCKWISE            (1)
  85. #define TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE     (2)
  86. #define TURRET_BEHAVIOR_AIM_CLOSEST                 (3)
  87. #define TURRET_BEHAVIOR_AIM_FARTHEST                (4)
  88. #define TURRET_BEHAVIOR_AIM_WEAKEST                 (5)
  89. #define TURRET_BEHAVIOR_AIM_STRONGEST               (6)
  90. #define TURRET_BEHAVIOR_AIM_RANDOM                  (7)
  91. #define TURRET_BEHAVIOR_AIM_SINGLE                  (8)
  92. #define TURRET_BEHAVIOR_AIM_CUSTOM                  (9)
  93. #define TURRET_BEHAVIOR_MAX                         (10)
  94.  
  95. // ======================================================
  96. // Callbacks
  97. // ======================================================
  98. forward OnTurretCreate(turretid);
  99. forward OnTurretDestroy(turretid);
  100. forward OnTurretHitPlayer(turretid, playerid);
  101. forward OnPlayerTakeTurretDamage(playerid, turretid, Float:damage);
  102. forward OnTurretMoved(turretid);
  103. forward OnTurretCustomShoot(turretid);
  104.  
  105. enum E_TURRET_DATA
  106. {
  107.     e_turr_objectid,
  108.     e_turr_behavior,
  109.     e_turr_owner,
  110.     e_turr_team,
  111.     e_turr_world,
  112.     e_turr_interior,
  113.     e_turr_area,
  114.     e_turr_bigarea,
  115.     e_turr_rate,
  116.     Text3D:e_turr_3dtext,
  117.     Float:e_turr_3dtext_xoffset,
  118.     Float:e_turr_3dtext_yoffset,
  119.     Float:e_turr_3dtext_zoffset,
  120.     Float:e_turr_3dtext_draw,
  121.     e_turr_3dtext_testlos,
  122.     Float:e_turr_speed,
  123.     Float:e_turr_dmg,
  124.     Float:e_turr_range,
  125.     Float:e_turr_stream,
  126.     Float:e_turr_rotspeed,
  127.     Float:e_turr_bullet_radius,
  128.     e_turr_bullet_model,
  129.     e_turr_bullet_color,
  130.     e_turr_timer,
  131.     e_turr_visible_bullets,
  132.     e_turr_max_visible_bullets,
  133.     bool:e_turr_active,
  134.     bool:e_turr_3dspace,
  135.     bool:e_turr_predict,
  136.     bool:e_turr_checkarea,
  137.     bool:e_turr_playsound,
  138.     e_turr_soundid,
  139.     e_turr_target
  140. }
  141.  
  142. static
  143.     rTurret_Killed[MAX_PLAYERS char],
  144.     rTurret_KilledBy[MAX_PLAYERS],
  145.     rTurretData[MAX_TURRETS][E_TURRET_DATA];
  146.    
  147. new
  148.     Iterator:rTurrets<MAX_TURRETS>,
  149.     Iterator:rTurretTargets[MAX_TURRETS]<MAX_PLAYERS>,
  150.     Iterator:rTurretPlayersInBigArea[MAX_TURRETS]<MAX_PLAYERS>;
  151.  
  152. // ======================================================
  153. // Core Functions
  154. // ======================================================
  155.  
  156. 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)
  157. {
  158.     new
  159.         turretid = Iter_Free(rTurrets);
  160.        
  161.     if (turretid == -1) {
  162.         printf("rTurret error: Max turrets of %d reached. Please define the #MAX_TURRETS macro to a higher value.", MAX_TURRETS);
  163.         return INVALID_TURRET;
  164.     }
  165.    
  166.     if (behavior < 0 || behavior >= TURRET_BEHAVIOR_MAX) {
  167.         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);
  168.         behavior = TURRET_BEHAVIOR_STATIONARY;
  169.     }
  170.    
  171.     if (rate < MIN_TURRET_RATE) {
  172.         printf("rTurret warning: Turret %d's rate of %d has been set to MIN_TURRET_RATE %d.", turretid, rate, MIN_TURRET_RATE);
  173.         rate = MIN_TURRET_RATE;
  174.     }
  175.    
  176.     Iter_Add(rTurrets, turretid);
  177.     rTurretData[turretid][e_turr_behavior] =            behavior;
  178.     rTurretData[turretid][e_turr_team] =                255;
  179.     rTurretData[turretid][e_turr_owner] =               playerid;
  180.     rTurretData[turretid][e_turr_world] =               world;
  181.     rTurretData[turretid][e_turr_interior] =            interior;
  182.     rTurretData[turretid][e_turr_rate] =                rate;
  183.     rTurretData[turretid][e_turr_3dtext_xoffset] =      0;
  184.     rTurretData[turretid][e_turr_3dtext_yoffset] =      0;
  185.     rTurretData[turretid][e_turr_3dtext_zoffset] =      0;
  186.     rTurretData[turretid][e_turr_3dtext_draw] =         25;
  187.     rTurretData[turretid][e_turr_3dtext_testlos] =      0;
  188.     rTurretData[turretid][e_turr_speed] =               floatabs(speed);
  189.     rTurretData[turretid][e_turr_dmg] =                 dmg;
  190.     rTurretData[turretid][e_turr_range] =               range;
  191.     rTurretData[turretid][e_turr_stream] =              streamdistance;
  192.     rTurretData[turretid][e_turr_rotspeed] =            0.0005;
  193.     rTurretData[turretid][e_turr_bullet_radius] =       1.2;
  194.     rTurretData[turretid][e_turr_bullet_model] =        2352;
  195.     rTurretData[turretid][e_turr_bullet_color] =        0;
  196.     rTurretData[turretid][e_turr_max_visible_bullets] = MAX_TURRET_VISIBLE_BULLETS;
  197.     rTurretData[turretid][e_turr_active] =              true;
  198.     rTurretData[turretid][e_turr_3dspace] =             false;
  199.     rTurretData[turretid][e_turr_predict] =             false;
  200.     rTurretData[turretid][e_turr_checkarea] =           true;
  201.     rTurretData[turretid][e_turr_playsound] =           true;
  202.     rTurretData[turretid][e_turr_soundid] =             1130;
  203.     rTurretData[turretid][e_turr_target] =              INVALID_PLAYER_ID;
  204.    
  205.     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);
  206.     rTurretData[turretid][e_turr_area] =        CreateDynamicSphere(0, 0, 0, range, world, interior);
  207.     rTurretData[turretid][e_turr_bigarea] =     CreateDynamicSphere(0, 0, 0, 60.0, world, interior);
  208.     rTurretData[turretid][e_turr_3dtext] =      CreateDynamic3DTextLabel(" ", -1, x, y, z + 2, 25, .testlos = 0, .worldid = world, .interiorid = interior, .streamdistance = 50);
  209.    
  210.     AttachDynamicAreaToObject(rTurretData[turretid][e_turr_area], rTurretData[turretid][e_turr_objectid]);
  211.     AttachDynamicAreaToObject(rTurretData[turretid][e_turr_bigarea], rTurretData[turretid][e_turr_objectid]);
  212.     // Turret object array data (identifier, turretid, moveid (below))
  213.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_INT);
  214.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, turretid);
  215.     // Shoot area array data (turretid, identifier)
  216.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, turretid);
  217.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  218.     // Big area array data (turretid, identifier)
  219.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_bigarea], E_STREAMER_EXTRA_ID, turretid);
  220.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_bigarea], E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT);
  221.    
  222.     CallLocalFunction("OnTurretCreate", "d", turretid);
  223.    
  224.     if (behavior == TURRET_BEHAVIOR_ROTATE_CLOCKWISE) {
  225.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  226.         MoveDynamicObject(rTurretData[turretid][e_turr_objectid], x, y, z + 0.001, rTurretData[turretid][e_turr_rotspeed], rx, ry, -179);
  227.     } else if (behavior == TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE) {
  228.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  229.         MoveDynamicObject(rTurretData[turretid][e_turr_objectid], x, y, z + 0.001, rTurretData[turretid][e_turr_rotspeed], rx, ry, 179);
  230.     } else
  231.         Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  232.  
  233.     rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rate, true, "d", turretid);
  234.     return turretid;
  235. }
  236.  
  237. stock DestroyTurret(turretid, &iter_next = -1)
  238. {
  239.     if (!Iter_Contains(rTurrets, turretid))
  240.         return 0;
  241.        
  242.     CallLocalFunction("OnTurretDestroy", "d", turretid);
  243.        
  244.     if (rTurretData[turretid][e_turr_timer] != -1) {
  245.         KillTimer(rTurretData[turretid][e_turr_timer]);
  246.         rTurretData[turretid][e_turr_timer] = -1;
  247.     }
  248.    
  249.     //rTurretData[turretid][e_turr_visible_bullets] = -1;
  250.     DestroyDynamicObject(rTurretData[turretid][e_turr_objectid]);
  251.     DestroyDynamicArea(rTurretData[turretid][e_turr_area]);
  252.     DestroyDynamicArea(rTurretData[turretid][e_turr_bigarea]);
  253.     DestroyDynamic3DTextLabel(rTurretData[turretid][e_turr_3dtext]);
  254.     rTurretData[turretid][e_turr_objectid] = INVALID_OBJECT_ID;
  255.     Iter_Clear(rTurretTargets[turretid]);
  256.     Iter_Clear(rTurretPlayersInBigArea[turretid]);
  257.     Iter_SafeRemove(rTurrets, turretid, iter_next);
  258.     return 1;
  259. }
  260.  
  261. stock IsValidTurret(turretid)
  262. {
  263.     return Iter_Contains(rTurrets, turretid);
  264. }
  265.  
  266. // ======================================================
  267. // Getter Functions
  268. // ======================================================
  269.  
  270. stock GetTurretObject(turretid)
  271. {
  272.     if (!Iter_Contains(rTurrets, turretid))
  273.         return INVALID_OBJECT_ID;
  274.        
  275.     return rTurretData[turretid][e_turr_objectid];
  276. }
  277.  
  278. stock GetTurretBehavior(turretid)
  279. {
  280.     if (!Iter_Contains(rTurrets, turretid))
  281.         return -1;
  282.        
  283.     return rTurretData[turretid][e_turr_behavior];
  284. }
  285.  
  286. stock GetTurretTeam(turretid)
  287. {
  288.     if (!Iter_Contains(rTurrets, turretid))
  289.         return 255;
  290.        
  291.     return rTurretData[turretid][e_turr_team];
  292. }
  293.  
  294. stock GetTurretPos(turretid, &Float:x, &Float:y, &Float:z)
  295. {
  296.     if (!Iter_Contains(rTurrets, turretid))
  297.         return 0;
  298.        
  299.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], x, y, z);
  300.     return 1;
  301. }
  302.  
  303. stock GetTurretRot(turretid, &Float:rotx, &Float:roty, &Float:rotz)
  304. {
  305.     if (!Iter_Contains(rTurrets, turretid))
  306.         return 0;
  307.        
  308.     GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], rotx, roty, rotz);
  309.     return 1;
  310. }
  311.  
  312. stock Float:GetTurretRotSpeed(turretid)
  313. {
  314.     if (!Iter_Contains(rTurrets, turretid))
  315.         return 0.0;
  316.        
  317.     return rTurretData[turretid][e_turr_rotspeed] / speed;
  318. }
  319.  
  320. stock Float:GetTurretBulletRadius(turretid)
  321. {
  322.     if (!Iter_Contains(rTurrets, turretid))
  323.         return 0.0;
  324.        
  325.     return rTurretData[turretid][e_turr_bullet_radius];
  326. }
  327.  
  328. stock GetTurretWorld(turretid)
  329. {
  330.     if (!Iter_Contains(rTurrets, turretid))
  331.         return -2;
  332.        
  333.     return rTurretData[turretid][e_turr_world];
  334. }
  335.  
  336. stock GetTurretInterior(turretid)
  337. {
  338.     if (!Iter_Contains(rTurrets, turretid))
  339.         return -2;
  340.        
  341.     return rTurretData[turretid][e_turr_interior];
  342. }
  343.  
  344. stock GetTurretText(turretid, text[], maxlength = sizeof(text))
  345. {
  346.     if (!Iter_Contains(rTurrets, turretid))
  347.         return 0;
  348.        
  349.     GetDynamic3DTextLabelText(rTurretData[turretid][e_turr_3dtext], text, sizeof(text));
  350.     return 1;
  351. }
  352.  
  353. stock GetTurretTextOffset(turretid, &Float:offsetx, &Float:offsety, &Float:offsetz)
  354. {
  355.     if (!Iter_Contains(rTurrets, turretid))
  356.         return 0;
  357.        
  358.     offsetx = rTurretData[turretid][e_turr_3dtext_xoffset];
  359.     offsety = rTurretData[turretid][e_turr_3dtext_yoffset];
  360.     offsetz = rTurretData[turretid][e_turr_3dtext_zoffset];
  361.     return 1;
  362. }
  363.  
  364. stock GetTurretFireRate(turretid)
  365. {
  366.     if (!Iter_Contains(rTurrets, turretid))
  367.         return 0;
  368.        
  369.     return rTurretData[turretid][e_turr_rate];
  370. }
  371.  
  372. stock Float:GetTurretBulletSpeed(turretid)
  373. {
  374.     if (!Iter_Contains(rTurrets, turretid))
  375.         return 0.0;
  376.        
  377.     return rTurretData[turretid][e_turr_speed];
  378. }
  379.  
  380. stock Float:GetTurretDamage(turretid)
  381. {
  382.     if (!Iter_Contains(rTurrets, turretid))
  383.         return 0.0;
  384.        
  385.     return rTurretData[turretid][e_turr_dmg];
  386. }
  387.  
  388. stock Float:GetTurretRange(turretid)
  389. {
  390.     if (!Iter_Contains(rTurrets, turretid))
  391.         return 0.0;
  392.        
  393.     return rTurretData[turretid][e_turr_range];
  394. }
  395.  
  396. stock Float:GetTurretStreamDistance(turretid)
  397. {
  398.     if (!Iter_Contains(rTurrets, turretid))
  399.         return 0.0;
  400.        
  401.     return rTurretData[turretid][e_turr_stream];
  402. }
  403.  
  404. stock GetTurretBulletModel(turretid)
  405. {
  406.     if (!Iter_Contains(rTurrets, turretid))
  407.         return -1;
  408.        
  409.     return rTurretData[turretid][e_turr_bullet_model];
  410. }
  411.  
  412. stock GetTurretBulletColor(turretid)
  413. {
  414.     if (!Iter_Contains(rTurrets, turretid))
  415.         return -1;
  416.        
  417.     return rTurretData[turretid][e_turr_bullet_color];
  418. }
  419.  
  420. stock GetTurretVisibleBullets(turretid)
  421. {
  422.     if (!Iter_Contains(rTurrtts, turretid))
  423.         return 0;
  424.        
  425.     return rTurretData[turretid][e_turr_visible_bullets];
  426. }
  427.  
  428. stock GetTurretMaxVisibleBullets(turretid)
  429. {
  430.     if (!Iter_Contains(rTurrets, turretid))
  431.         return 0;
  432.  
  433.     return rTurretData[turretid][e_turr_max_visible_bullets];
  434. }
  435.  
  436. stock GetTurretSound(turretid)
  437. {
  438.     if (!Iter_Contains(rTurrets, turretid))
  439.         return 0;
  440.        
  441.     return rTurretData[turretid][e_turr_soundid];
  442. }
  443.  
  444. stock GetTurretKiller(playerid)
  445. {
  446.     return rTurret_KilledBy[playerid];
  447. }
  448.  
  449. // ======================================================
  450. // Setter Functions
  451. // ======================================================
  452.  
  453. stock SetTurretBehavior(turretid, behavior)
  454. {
  455.     if (!Iter_Contains(rTurrets, turretid) || behavior < 0 || behavior >= TURRET_BEHAVIOR_MAX)
  456.         return 0;
  457.    
  458.     if (IsDynamicObjectMoving(rTurretData[turretid][e_turr_objectid]))
  459.         StopDynamicObject(rTurretData[turretid][e_turr_objectid]);
  460.        
  461.     switch(rTurretData[turretid][e_turr_behavior]) {
  462.         case TURRET_BEHAVIOR_ROTATE_CLOCKWISE: {
  463.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  464.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  465.         }
  466.         case TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE: {
  467.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  468.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  469.         }
  470.         default:
  471.             Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  472.     }
  473.    
  474.     rTurretData[turretid][e_turr_behavior] = behavior;
  475.    
  476.     switch(behavior) {
  477.         case TURRET_BEHAVIOR_ROTATE_CLOCKWISE: {
  478.             new
  479.                 Float:turPX,
  480.                 Float:turPY,
  481.                 Float:turPZ,
  482.                 Float:turRX,
  483.                 Float:turRY,
  484.                 Float:turRZ;
  485.                
  486.             GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  487.             GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  488.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, 0.0);
  489.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  490.             MoveDynamicObject(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ + 0.001, rTurretData[turretid][e_turr_rotspeed], turRX, turRY, -179);
  491.         }
  492.         case TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE: {
  493.             new
  494.                 Float:turPX,
  495.                 Float:turPY,
  496.                 Float:turPZ,
  497.                 Float:turRX,
  498.                 Float:turRY,
  499.                 Float:turRZ;
  500.                
  501.             GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  502.             GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  503.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, 0.0);
  504.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  505.             MoveDynamicObject(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ + 0.001, rTurretData[turretid][e_turr_rotspeed], turRX, turRY, 179);
  506.         }
  507.         default:
  508.             Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_OTHER);
  509.     }
  510.     return 1;
  511. }
  512.  
  513. stock SetTurretTeam(turretid, team)
  514. {
  515.     if (!Iter_Contains(rTurrets, turretid))
  516.         return 0;
  517.        
  518.     rTurretData[turretid][e_turr_team] = team;
  519.     return 1;
  520. }
  521.  
  522. stock SetTurretPos(turretid, Float:x, Float:y, Float:z)
  523. {
  524.     if (!Iter_Contains(rTurrets, turretid))
  525.         return 0;
  526.  
  527.     SetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], x, y, z);
  528.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + rTurretData[turretid][e_turr_3dtext_xoffset]);
  529.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + rTurretData[turretid][e_turr_3dtext_yoffset]);
  530.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + rTurretData[turretid][e_turr_3dtext_zoffset]);
  531.     return 1;
  532. }
  533.  
  534. stock SetTurretRot(turretid, Float:rotx, Float:roty, Float:rotz)
  535. {
  536.     if (!Iter_Contains(rTurrets, turretid))
  537.         return 0;
  538.  
  539.     SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], rotx, roty, rotz);
  540.     return 1;
  541. }
  542.  
  543. stock SetTurretRotSpeed(turretid, Float:speed)
  544. {
  545.     if (!Iter_Contains(rTurrets, turretid))
  546.         return 0;
  547.        
  548.     rTurretData[turretid][e_turr_rotspeed] = 0.0005 * floatabs(speed);
  549.     return 1;
  550. }
  551.  
  552. stock SetTurretBulletRadius(turretid, Float:radius)
  553. {
  554.     if (!Iter_Contains(rTurrets, turretid))
  555.         return 0;
  556.        
  557.     rTurretData[turretid][e_turr_bullet_radius] = radius;
  558.     return 1;
  559. }
  560.  
  561. stock SetTurretWorld(turretid, world)
  562. {
  563.     if (!Iter_Contains(rTurrets, turretid))
  564.         return 0;
  565.        
  566.     rTurretData[turretid][e_turr_world] = world;
  567.     Streamer_SetIntData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_WORLD_ID, world);
  568.     Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_WORLD_ID, world);
  569.     return 1;
  570. }
  571.  
  572. stock SetTurretInterior(turretid, interior)
  573. {
  574.     if (!Iter_Contains(rTurrets, turretid))
  575.         return 0;
  576.        
  577.     rTurretData[turretid][e_turr_interior] = interior;
  578.     Streamer_SetIntData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_INTERIOR_ID, interior);
  579.     Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_INTERIOR_ID, interior);
  580.     return 1;
  581. }
  582.  
  583. stock SetTurretText(turretid, color, const text[])
  584. {
  585.     if (!Iter_Contains(rTurrets, turretid))
  586.         return 0;
  587.        
  588.     UpdateDynamic3DTextLabelText(rTurretData[turretid][e_turr_3dtext], color, text);
  589.     return 1;
  590. }
  591.  
  592. stock SetTurretTextOffset(turretid, Float:offsetx, Float:offsety, Float:offsetz, Float:drawdistance = -1.0, testlos = -1)
  593. {
  594.     if (!Iter_Contains(rTurrets, turretid))
  595.         return 0;
  596.        
  597.     new
  598.         Float:turPX,
  599.         Float:turPY,
  600.         Float:turPZ;
  601.        
  602.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  603.        
  604.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + offsetx);
  605.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + offsety);
  606.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + offsetz);
  607.    
  608.     if (floatcmp(drawdistance, -1.0) != 0) {
  609.         Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_DRAW_DISTANCE, drawdistance);
  610.         Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_STREAM_DISTANCE, drawdistance + 25);
  611.         rTurretData[turretid][e_turr_3dtext_draw] = drawdistance;
  612.     }
  613.     if (testlos != -1) {
  614.         Streamer_SetIntData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_TEST_LOS, testlos);
  615.         rTurretData[turretid][e_turr_3dtext_testlos] = testlos;
  616.     }
  617.        
  618.     rTurretData[turretid][e_turr_3dtext_xoffset] = offsetx;
  619.     rTurretData[turretid][e_turr_3dtext_yoffset] = offsety;
  620.     rTurretData[turretid][e_turr_3dtext_zoffset] = offsetz;
  621.     return 1;
  622. }
  623.  
  624. stock SetTurretFireRate(turretid, rate)
  625. {
  626.     if (!Iter_Contains(rTurrets, turretid))
  627.         return 0;
  628.        
  629.     if (rate < MIN_TURRET_RATE) {
  630.         printf("rTurret warning: Turret %d's rate of %d has been set to MIN_TURRET_RATE %d.", turretid, rate, MIN_TURRET_RATE);
  631.         rate = MIN_TURRET_RATE;
  632.     }
  633.     rTurretData[turretid][e_turr_rate] = rate;
  634.     if (rTurretData[turretid][e_turr_timer] != -1 && rTurretData[turretid][e_turr_active]) {
  635.         KillTimer(rTurretData[turretid][e_turr_timer]);
  636.         rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rate, true, "d", turretid);
  637.     }
  638.     return 1;
  639. }
  640.  
  641. stock SetTurretBulletSpeed(turretid, Float:speed)
  642. {
  643.     if (!Iter_Contains(rTurrets, turretid))
  644.         return 0;
  645.        
  646.     rTurretData[turretid][e_turr_speed] = floatabs(speed);
  647.     return 1;
  648. }
  649.  
  650. stock SetTurretDamage(turretid, Float:damage)
  651. {
  652.     if (!Iter_Contains(rTurrets, turretid))
  653.         return 0;
  654.        
  655.     rTurretData[turretid][e_turr_dmg] = damage;
  656.     return 1;
  657. }
  658.  
  659. stock SetTurretRange(turretid, Float:range)
  660. {
  661.     if (!Iter_Contains(rTurrets, turretid))
  662.         return 0;
  663.        
  664.     rTurretData[turretid][e_turr_range] = range;
  665.     return 1;
  666. }
  667.  
  668. stock SetTurretStreamDistance(turretid, Float:streamdistance)
  669. {
  670.     if (!Iter_Contains(rTurrets, turretid))
  671.         return 0;
  672.        
  673.     rTurretData[turretid][e_turr_stream] = streamdistance;
  674.     Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, streamdistance);
  675.     return 1;
  676. }
  677.  
  678. stock SetTurretBulletModel(turretid, modelid)
  679. {
  680.     if (!Iter_Contains(rTurrets, turretid))
  681.         return 0;
  682.        
  683.     rTurretData[turretid][e_turr_bullet_model] = modelid;
  684.     return 1;
  685. }
  686.  
  687. stock SetTurretBulletColor(turretid, color = 0)
  688. {
  689.     if (!Iter_Contains(rTurrets, turretid))
  690.         return 0;
  691.        
  692.     rTurretData[turretid][e_turr_bullet_color] = color;
  693.     return 1;
  694. }
  695.  
  696. stock SetTurretMaxVisibleBullets(turretid, maxbullets)
  697. {
  698.     if (!Iter_Contains(rTurrets, turretid))
  699.         return 0;
  700.     if (maxbullets >= MAX_TURRET_VISIBLE_BULLETS) {
  701.         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);
  702.         maxbullets = MAX_TURRET_VISIBLE_BULLETS;
  703.     } else if (maxbullets < 1) {
  704.         printf("rTurret Warning: Max visible bullets for turret %d has been raised from %d to %d", turretid, maxbullets, 1);
  705.         maxbullets = 1;
  706.     }
  707.     rTurretData[turretid][e_turr_max_visible_bullets] = maxbullets;
  708.     return 1;
  709. }
  710.  
  711. stock SetTurretSound(turretid, soundid)
  712. {
  713.     if (!Iter_Contains(rTurrets, turretid))
  714.         return 0;
  715.        
  716.     rTurretData[turretid][e_turr_soundid] = soundid;
  717.     return 1;
  718. }
  719.  
  720. stock SetTurretSingleTarget(turretid, targetid)
  721. {
  722.     if (!Iter_Contains(rTurrets, turretid))
  723.         return 0;
  724.        
  725.     if (!IsPlayerConnected(targetid))
  726.         return 0;
  727.        
  728.     rTurretData[turretid][e_turr_target] = targetid;
  729.     return 1;
  730. }
  731.  
  732. // ======================================================
  733. // Extra Functions
  734. // ======================================================
  735.  
  736. stock ToggleTurretActive(turretid, toggle)
  737. {
  738.     if (!Iter_Contains(rTurrets, turretid))
  739.         return 1;
  740.        
  741.     if (toggle) {
  742.         if (rTurretData[turretid][e_turr_active])
  743.             return 0;
  744.         if (rTurretData[turretid][e_turr_timer] == -1)
  745.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  746.         else {
  747.             KillTimer(rTurretData[turretid][e_turr_timer]);
  748.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  749.         }
  750.         rTurretData[turretid][e_turr_active] = true;
  751.     } else {
  752.         if (!rTurretData[turretid][e_turr_active])
  753.             return 0;
  754.         if (rTurretData[turretid][e_turr_timer] != -1) {
  755.             KillTimer(rTurretData[turretid][e_turr_timer]);
  756.             rTurretData[turretid][e_turr_timer] = -1;
  757.         }
  758.         rTurretData[turretid][e_turr_active] = false;
  759.     }
  760.     return 1;
  761. }
  762.  
  763. stock ToggleTurretCheckArea(turretid, toggle)
  764. {
  765.     if (!Iter_Contains(rTurrets, turretid))
  766.         return 0;
  767.        
  768.     if (toggle) {
  769.         if (rTurretData[turretid][e_turr_checkarea])
  770.             return 0;
  771.         rTurretData[turretid][e_turr_checkarea] = true;
  772.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, -1);
  773.         Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  774.     } else {
  775.         if (!rTurretData[turretid][e_turr_checkarea])
  776.             return 0;
  777.         rTurretData[turretid][e_turr_checkarea] = false;
  778.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT);
  779.         Streamer_AppendArrayData(STREAMER_TYPE_AREA, rTurretData[turretid][e_turr_area], E_STREAMER_EXTRA_ID, -1);
  780.     }
  781.     return 1;
  782. }
  783.  
  784. stock ToggleTurretPlaySound(turretid, toggle)
  785. {
  786.     if (!Iter_Contains(rTurrets, turretid))
  787.         return 0;
  788.        
  789.     if (toggle) {
  790.         if (rTurretData[turretid][e_turr_playsound])
  791.             return 0;
  792.         rTurretData[turretid][e_turr_playsound] = true;
  793.     } else {
  794.         if (!rTurretData[turretid][e_turr_playsound])
  795.             return 0;
  796.         rTurretData[turretid][e_turr_playsound] = false;
  797.     }
  798.     return 1;
  799. }
  800.  
  801. stock ToggleTurretVisible(turretid, toggle)
  802. {
  803.     if (!Iter_Contains(rTurrets, turretid))
  804.         return 0;
  805.        
  806.     new
  807.         Float:sd;
  808.        
  809.     Streamer_GetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, sd);
  810.    
  811.     if (toggle) {
  812.         if (floatcmp(sd, rTurretData[turretid][e_turr_stream]) == 0)
  813.             return 0;
  814.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, rTurretData[turretid][e_turr_stream]);
  815.     } else {
  816.         if (floatcmp(sd, 0.0) == 0)
  817.             return 0;
  818.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_STREAM_DISTANCE, 0.0);
  819.     }
  820.     return 1;
  821. }
  822.  
  823. stock ToggleTurretAim3dSpace(turretid, toggle)
  824. {
  825.     if (!Iter_Contains(rTurrets, turretid))
  826.         return 0;
  827.        
  828.     if (toggle) {
  829.         if (rTurretData[turretid][e_turr_3dspace])
  830.             return 0;
  831.         rTurretData[turretid][e_turr_3dspace] = true;
  832.     } else {
  833.         if (!rTurretData[turretid][e_turr_3dspace])
  834.             return 0;
  835.         rTurretData[turretid][e_turr_3dspace] = false;
  836.     }
  837.     return 1;
  838. }
  839.  
  840. stock ToggleTurretPredictiveAim(turretid, toggle)
  841. {
  842.     if (!Iter_Contains(rTurrets, turretid))
  843.         return 0;
  844.        
  845.     if (toggle) {
  846.         if (rTurretData[turretid][e_turr_predict])
  847.             return 0;
  848.         rTurretData[turretid][e_turr_predict] = true;
  849.     } else {
  850.         if (!rTurretData[turretid][e_turr_predict])
  851.             return 0;
  852.         rTurretData[turretid][e_turr_predict] = false;
  853.     }
  854.     return 1;
  855. }
  856.  
  857. stock UpdateTurretTextPos(turretid)
  858. {
  859.     if (!Iter_Contains(rTurrets, turretid))
  860.         return 0;
  861.        
  862.     new
  863.         Float:turPX,
  864.         Float:turPY,
  865.         Float:turPZ,
  866.        
  867.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  868.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_X, turPX + rTurretData[turretid][e_turr_3dtext_xoffset]);
  869.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Y, turPY + rTurretData[turretid][e_turr_3dtext_yoffset]);
  870.     Streamer_SetFloatData(STREAMER_TYPE_3D_TEXT_LABEL, rTurretData[turretid][e_turr_3dtext], E_STREAMER_Z, turPZ + 2 + rTurretData[turretid][e_turr_3dtext_zoffset]);
  871.     return 1;
  872. }
  873.  
  874. stock MoveTurret(turretid, Float:X, Float:Y, Float:Z, Float:Speed, Float:RotX = -1000.0, Float:RotY = -1000.0, Float:RotZ = -1000.0)
  875. {
  876.     if (!Iter_Contains(rTurrets, turretid) ||
  877.         rTurretData[turretid][e_turr_behavior] == TURRET_BEHAVIOR_ROTATE_CLOCKWISE ||
  878.         rTurretData[turretid][e_turr_behavior] == TURRET_BEHAVIOR_ROTATE_COUNTERCLOCKWISE)
  879.             return 0;
  880.            
  881.     MoveDynamicObject(rTurretData[turretid][e_turr_objectid], X, Y, Z, Speed, RotX, RotY, RotZ);
  882.     return 1;
  883. }
  884.  
  885. // ======================================================
  886. // Hooks
  887. // ======================================================
  888.  
  889. #if defined FILTERSCRIPT
  890. public OnFilterScriptInit()
  891. {
  892.     Iter_Init(rTurretTargets);
  893.     Iter_Init(rTurretPlayersInBigArea);
  894.     foreach(new i : Player) {
  895.         rTurret_Killed{i} = false;
  896.         rTurret_KilledBy[i] = INVALID_TURRET;
  897.     }
  898.     for (new i = 0; i < MAX_TURRETS; i++) {
  899.         rTurretData[i][e_turr_timer] = -1;
  900.         rTurretData[i][e_turr_visible_bullets] = -1;
  901.         rTurretData[i][e_turr_objectid] = INVALID_OBJECT_ID;
  902.     }
  903.     return CallLocalFunction("rTurret_OnFilterScriptInit", "");
  904. }
  905.     #if defined _ALS_OnFilterScriptInit
  906.         #undef OnFilterScriptInit
  907.     #else
  908.         #define _ALS_OnFilterScriptInit
  909.     #endif
  910.     #define OnFilterScriptInit rTurret_OnFilterScriptInit
  911.     forward rTurret_OnFilterScriptInit();
  912.    
  913. public OnFilterScriptExit()
  914. {
  915.     foreach(new i : rTurrets)
  916.         DestroyTurret(i);
  917.        
  918.     Streamer_DestroyAllItems(STREAMER_TYPE_OBJECT, 0);
  919.     Streamer_DestroyAllItems(STREAMER_TYPE_AREA, 0);
  920.     Streamer_DestroyAllItems(STREAMER_TYPE_3D_TEXT_LABEL, 0);
  921.     return CallLocalFunction("rTurret_OnFilterScriptExit", "");
  922. }
  923.     #if defined _ALS_OnFilterScriptExit
  924.         #undef OnFilterScriptExit
  925.     #else
  926.         #define _ALS_OnFilterScriptExit
  927.     #endif
  928.     #define OnFilterScriptExit rTurret_OnFilterScriptExit
  929.     forward rTurret_OnFilterScriptExit();
  930.    
  931. #else
  932. public OnGameModeInit()
  933. {
  934.     Iter_Init(rTurretTargets);
  935.     Iter_Init(rTurretPlayersInBigArea);
  936.     foreach(new i : Player) {
  937.         rTurret_Killed{i} = false;
  938.         rTurret_KilledBy[i] = INVALID_TURRET;
  939.     }
  940.     for (new i = 0; i < MAX_TURRETS; i++) {
  941.         rTurretData[i][e_turr_timer] = -1;
  942.         rTurretData[i][e_turr_visible_bullets] = -1;
  943.         rTurretData[i][e_turr_objectid] = INVALID_OBJECT_ID;
  944.     }
  945.     return CallLocalFunction("rTurret_OnGameModeInit", "");
  946. }
  947.     #if defined _ALS_OnGameModeInit
  948.         #undef OnGameModeInit
  949.     #else
  950.         #define _ALS_OnGameModeInit
  951.     #endif
  952.     #define OnGameModeInit rTurret_OnGameModeInit
  953.     forward rTurret_OnGameModeInit();
  954. #endif
  955.  
  956. public OnPlayerConnect(playerid)
  957. {
  958.     rTurret_Killed{playerid} = false;
  959.     rTurret_KilledBy[playerid] = INVALID_TURRET;
  960.     return CallLocalFunction("rTurret_OnPlayerConnect", "d", playerid);
  961. }
  962. #if defined _ALS_OnPlayerConnect
  963.     #undef OnPlayerConnect
  964. #else
  965.     #define _ALS_OnPlayerConnect
  966. #endif
  967. #define OnPlayerConnect rTurret_OnPlayerConnect
  968. forward rTurret_OnPlayerConnect(playerid);
  969.  
  970. public OnPlayerSpawn(playerid)
  971. {
  972.     if (rTurret_Killed{playerid})
  973.         // Prevent taking turret damage upon spawning
  974.         SetTimerEx("Timer_ResetTurretKilled", 1000, false, "d", playerid);
  975.     return CallLocalFunction("rTurret_OnPlayerSpawn", "d", playerid);
  976. }
  977. #if defined _ALS_OnPlayerSpawn
  978.     #undef OnPlayerSpawn
  979. #else
  980.     #define _ALS_OnPlayerSpawn
  981. #endif
  982. #define OnPlayerSpawn rTurret_OnPlayerSpawn
  983. forward rTurret_OnPlayerSpawn(playerid);
  984.  
  985. public OnPlayerDeath(playerid, killerid, reason)
  986. {
  987.     if (rTurret_Killed{playerid}) {
  988.         if (Iter_Contains(rTurrets, rTurret_KilledBy[playerid])) {
  989.             new
  990.                 turretid = rTurret_KilledBy[playerid];
  991.                
  992.             killerid = rTurretData[turretid][e_turr_owner];
  993.             reason = 47;
  994.             if (Iter_Contains(rTurretTargets[turretid], playerid))
  995.                 Iter_Remove(rTurretTargets[turretid], playerid);
  996.         }
  997.     }
  998.     return CallLocalFunction("rTurret_OnPlayerDeath", "ddd", playerid, killerid, reason);
  999. }
  1000. #if defined _ALS_OnPlayerDeath
  1001.     #undef OnPlayerDeath
  1002. #else
  1003.     #define _ALS_OnPlayerDeath
  1004. #endif
  1005. #define OnPlayerDeath rTurret_OnPlayerDeath
  1006. forward rTurret_OnPlayerDeath(playerid, killerid, reason);
  1007.  
  1008. public OnDynamicObjectMoved(objectid)
  1009. {      
  1010.     if (Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, TURRET_BULLET_OBJECT_INT)) {
  1011.         // Destroy bullet and its area
  1012.         new
  1013.             data[3],
  1014.             turretid,
  1015.             bullet_areaid;
  1016.            
  1017.         Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, data);
  1018.         turretid = data[1];
  1019.         bullet_areaid = data[2];
  1020.            
  1021.         DestroyDynamicArea(bullet_areaid);
  1022.         DestroyDynamicObject(objectid);
  1023.         rTurretData[turretid][e_turr_visible_bullets]--;
  1024.         return 1;
  1025.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, TURRET_INT)) {
  1026.         // Turret object
  1027.         new
  1028.             data[3],
  1029.             turretid,
  1030.             Float:oX,
  1031.             Float:oY,
  1032.             Float:oZ,
  1033.             Float:oRX,
  1034.             Float:oRY,
  1035.             Float:oRZ,
  1036.             movestate;
  1037.            
  1038.         Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, data);
  1039.         turretid = data[1];
  1040.         movestate = data[2];
  1041.         GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], oX, oY, oZ);
  1042.         GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, oRZ);
  1043.         switch(movestate) {
  1044.             case TURRET_MOVE_ROTATE_CLOCKWISE_1:{
  1045.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  1046.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  1047.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ - 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, -359);
  1048.             }
  1049.             case TURRET_MOVE_ROTATE_CLOCKWISE_2: {
  1050.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_2);
  1051.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_CLOCKWISE_1);
  1052.                 SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, 0);
  1053.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ + 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, -179);
  1054.             }
  1055.             case TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1: {
  1056.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  1057.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  1058.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ - 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, 359);
  1059.             }
  1060.             case TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2: {
  1061.                 Streamer_RemoveArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_2);
  1062.                 Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, rTurretData[turretid][e_turr_objectid], E_STREAMER_EXTRA_ID, TURRET_MOVE_ROTATE_COUNTERCLOCKWISE_1);
  1063.                 SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], oRX, oRY, 0);
  1064.                 MoveDynamicObject(rTurretData[turretid][e_turr_objectid], oX, oY, oZ + 0.001, rTurretData[turretid][e_turr_rotspeed], oRX, oRY, 179);
  1065.             }
  1066.             default: CallLocalFunction("OnTurretMoved", "d", turretid);
  1067.         }
  1068.         return 1;
  1069.     }
  1070.     return CallLocalFunction("rTurret_OnDynamicObjectMoved", "d", objectid);
  1071. }
  1072. #if defined _ALS_OnDynamicObjectMoved
  1073.     #undef OnDynamicObjectMoved
  1074. #else
  1075.     #define _ALS_OnDynamicObjectMoved
  1076. #endif
  1077. #define OnDynamicObjectMoved rTurret_OnDynamicObjectMoved
  1078. forward rTurret_OnDynamicObjectMoved(objectid);
  1079.  
  1080. public OnPlayerEnterDynamicArea(playerid, areaid)
  1081. {
  1082.     // Check if player is dead or not spawned
  1083.     if (rTurret_Killed{playerid})
  1084.         return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1085.        
  1086.     if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT)) {
  1087.         // Destroy bullet and its area
  1088.         new
  1089.             data[3],
  1090.             turretid = INVALID_TURRET,
  1091.             bulletid;
  1092.            
  1093.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1094.         turretid = data[1];
  1095.         bulletid = data[2];
  1096.        
  1097.         if (!Iter_Contains(rTurrets, turretid))
  1098.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1099.            
  1100.         // "*** Streamer_GetArrayData: Invalid ID specified" message shows if you destroy area here.
  1101.         // To avoid this, hide object and efficiently "disable" area. Object and area will be destroyed under OnDynamicObjectMoved.
  1102.        
  1103.         // DestroyDynamicArea(areaid);
  1104.         // DestroyDynamicObject(bulletid);
  1105.         Streamer_RemoveArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT);
  1106.         Streamer_SetFloatData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_STREAM_DISTANCE, 0.0);
  1107.            
  1108.         rTurretData[turretid][e_turr_visible_bullets]--;
  1109.         if (rTurretData[turretid][e_turr_owner] == playerid || (rTurretData[turretid][e_turr_team] != 255 && rTurretData[turretid][e_turr_team] == GetPlayerTeam(playerid)))
  1110.             return 1;
  1111.         if (funcidx("OnTurretHitPlayer") != -1 && CallLocalFunction("OnTurretHitPlayer", "dd", turretid, playerid)) {
  1112.             // Damage player
  1113.             new
  1114.                 Float:a,
  1115.                 Float:h,
  1116.                 Float:dif;
  1117.                
  1118.             GetPlayerArmour(playerid, a);
  1119.             GetPlayerHealth(playerid, h);
  1120.             if (floatcmp(a, 0.0) != 1) {
  1121.                 // No armor
  1122.                 dif = h - rTurretData[turretid][e_turr_dmg];
  1123.                 if (floatcmp(dif, 0.0) == -1 || floatcmp(dif, 0.0) == 0) {
  1124.                     // Dead
  1125.                     rTurret_Killed{playerid} = true;
  1126.                     rTurret_KilledBy[playerid] = turretid;
  1127.                     SetPlayerHealth(playerid, 0.0);
  1128.                 } else
  1129.                     SetPlayerHealth(playerid, dif);
  1130.             } else {
  1131.                 // Has armor
  1132.                 dif = a - rTurretData[turretid][e_turr_dmg];
  1133.                 if (floatcmp(dif, 0.0) == -1) {
  1134.                     // Damage health
  1135.                     SetPlayerArmour(playerid, 0);
  1136.                     SetPlayerHealth(playerid, h - floatabs(dif));
  1137.                 } else
  1138.                     SetPlayerArmour(playerid, dif);
  1139.             }
  1140.             CallLocalFunction("OnPlayerTakeTurretDamage", "ddf", playerid, turretid, rTurretData[turretid][e_turr_dmg]);
  1141.         }
  1142.         return 1;
  1143.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT)) {
  1144.         // Turret within hearing range of player
  1145.         new
  1146.             data[2],
  1147.             turretid = INVALID_TURRET;
  1148.            
  1149.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1150.         turretid = data[0];
  1151.         if (!Iter_Contains(rTurrets, turretid))
  1152.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1153.         Iter_Add(rTurretPlayersInBigArea[data[0]], playerid);
  1154.         return 1;
  1155.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT)) {
  1156.         // Player within target range of turret
  1157.         new
  1158.             data[2],
  1159.             turretid = INVALID_TURRET;
  1160.            
  1161.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1162.         turretid = data[0];
  1163.         if (!Iter_Contains(rTurrets, turretid))
  1164.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1165.         if (rTurretData[turretid][e_turr_owner] == playerid || (rTurretData[turretid][e_turr_team] != 255 && rTurretData[turretid][e_turr_team] == GetPlayerTeam(playerid)))
  1166.             return 1;
  1167.         Iter_Add(rTurretTargets[turretid], playerid);
  1168.         if (rTurretData[turretid][e_turr_timer] == -1 && rTurretData[turretid][e_turr_active])
  1169.             rTurretData[turretid][e_turr_timer] = SetTimerEx("Timer_TurretShoot", rTurretData[turretid][e_turr_rate], true, "d", turretid);
  1170.         return 1;
  1171.     }
  1172.     return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1173. }
  1174. #if defined _ALS_OnPlayerEnterDynamicArea
  1175.     #undef OnPlayerEnterDynamicArea
  1176. #else
  1177.     #define _ALS_OnPlayerEnterDynamicArea
  1178. #endif
  1179. #define OnPlayerEnterDynamicArea rTurret_OnPlayerEnterArea
  1180. forward rTurret_OnPlayerEnterArea(playerid, areaid);
  1181.  
  1182. public OnPlayerLeaveDynamicArea(playerid, areaid)
  1183. {
  1184.     if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BIG_AREA_INT)) {
  1185.         // Turret out of hearing range for player
  1186.         new
  1187.             data[2],
  1188.             turretid = INVALID_TURRET;
  1189.            
  1190.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1191.         turretid = data[0];
  1192.         if (!Iter_Contains(rTurrets, turretid))
  1193.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1194.         Iter_Remove(rTurretPlayersInBigArea[turretid], playerid);
  1195.     } else if (Streamer_IsInArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_SHOOT_AREA_INT)) {
  1196.         // Player out of turret target range
  1197.         new
  1198.             data[2],
  1199.             turretid = INVALID_TURRET;
  1200.            
  1201.         Streamer_GetArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, data);
  1202.         turretid = data[0];
  1203.         if (!Iter_Contains(rTurrets, turretid))
  1204.             return CallLocalFunction("rTurret_OnPlayerEnterArea", "dd", playerid, areaid);
  1205.         Iter_Remove(rTurretTargets[turretid], playerid);
  1206.         if (!Iter_Count(rTurretTargets[turretid]) && rTurretData[turretid][e_turr_checkarea]) {
  1207.             if (rTurretData[turretid][e_turr_timer] != -1) {
  1208.                 KillTimer(rTurretData[turretid][e_turr_timer]);
  1209.                 rTurretData[turretid][e_turr_timer] = -1;
  1210.             }
  1211.         }
  1212.     }
  1213.     return CallLocalFunction("rTurret_OnPlayerLeaveArea", "dd", playerid, areaid);
  1214. }
  1215. #if defined _ALS_OnPlayerLeaveDynamicArea
  1216.     #undef OnPlayerLeaveDynamicArea
  1217. #else
  1218.     #define _ALS_OnPlayerLeaveDynamicArea
  1219. #endif
  1220. #define OnPlayerLeaveDynamicArea rTurret_OnPlayerLeaveArea
  1221. forward rTurret_OnPlayerLeaveArea(playerid, areaid);
  1222.  
  1223. // ======================================================
  1224. // Internal Timers
  1225. // ======================================================
  1226.  
  1227. forward Timer_TurretShoot(turretid);
  1228. forward Timer_ResetTurretKilled(playerid);
  1229.  
  1230. public Timer_TurretShoot(turretid)
  1231. {      
  1232.     if (!Iter_Contains(rTurrets, turretid)) {
  1233.         if (rTurretData[turretid][e_turr_timer] != -1) {
  1234.             KillTimer(rTurretData[turretid][e_turr_timer]);
  1235.             rTurretData[turretid][e_turr_timer] = -1;
  1236.         }
  1237.         return 0;
  1238.     }
  1239.    
  1240.     new
  1241.         visibleBullets = rTurretData[turretid][e_turr_visible_bullets] + 1;
  1242.    
  1243.     if (visibleBullets >= rTurretData[turretid][e_turr_max_visible_bullets])
  1244.         // Cancel bullet creation
  1245.         return 0;
  1246.     else
  1247.         rTurretData[turretid][e_turr_visible_bullets]++;
  1248.        
  1249.     new
  1250.         areaid,
  1251.         bulletid,
  1252.         // Player Pos
  1253.         Float:pX,
  1254.         Float:pY,
  1255.         Float:pZ,
  1256.         // Turret Pos and Rot
  1257.         Float:turPX,
  1258.         Float:turPY,
  1259.         Float:turPZ,
  1260.         Float:turRX,
  1261.         Float:turRY,
  1262.         Float:turRZ,
  1263.         Float:newPX,
  1264.         Float:newPY,
  1265.         Float:newPZ;
  1266.    
  1267.     GetDynamicObjectPos(rTurretData[turretid][e_turr_objectid], turPX, turPY, turPZ);
  1268.     GetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  1269.     newPZ = turPZ + 1.15;
  1270.    
  1271.     if (TURRET_BEHAVIOR_AIM_CLOSEST <= rTurretData[turretid][e_turr_behavior] <= TURRET_BEHAVIOR_AIM_CUSTOM) {
  1272.         // Set turret facing target
  1273.         new
  1274.             targetid = INVALID_PLAYER_ID,
  1275.             Float:targDist;
  1276.            
  1277.         switch(rTurretData[turretid][e_turr_behavior]) {
  1278.             case TURRET_BEHAVIOR_AIM_CLOSEST: {
  1279.                 targDist = 100000.0;
  1280.                 foreach(new i : rTurretTargets[turretid]) {
  1281.                     if (floatcmp(targDist, GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ)) == 1) {
  1282.                         // Closest player so far
  1283.                         targetid = i;
  1284.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1285.                         GetPlayerPos(i, pX, pY, pZ);
  1286.                     }
  1287.                 }
  1288.             }
  1289.             case TURRET_BEHAVIOR_AIM_FARTHEST: {
  1290.                 foreach(new i : rTurretTargets[turretid]) {
  1291.                     if (floatcmp(targDist, GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ)) == -1) {
  1292.                         // Farthest player so far
  1293.                         targetid = i;
  1294.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1295.                         GetPlayerPos(i, pX, pY, pZ);
  1296.                     }
  1297.                 }
  1298.             }
  1299.             case TURRET_BEHAVIOR_AIM_WEAKEST: {
  1300.                 new
  1301.                     Float:a,
  1302.                     Float:h,
  1303.                     Float:smallSum = 1000.0;
  1304.                    
  1305.                 foreach(new i : rTurretTargets[turretid]) {
  1306.                     GetPlayerArmour(i, a);
  1307.                     GetPlayerHealth(i, h);
  1308.                     if (floatcmp(smallSum, a + h) == 1) {
  1309.                         // Player with lowest health and armour so far
  1310.                         smallSum = a + h;
  1311.                         targetid = i;
  1312.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1313.                         GetPlayerPos(i, pX, pY, pZ);
  1314.                     }
  1315.                 }
  1316.             }
  1317.             case TURRET_BEHAVIOR_AIM_STRONGEST: {
  1318.                 new
  1319.                     Float:a,
  1320.                     Float:h,
  1321.                     Float:bigSum = 0.0;
  1322.                    
  1323.                 foreach(new i : rTurretTargets[turretid]) {
  1324.                     GetPlayerArmour(i, a);
  1325.                     GetPlayerHealth(i, h);
  1326.                     if (floatcmp(bigSum, a + h) == -1) {
  1327.                         // Player with highest health and armour so far
  1328.                         bigSum = a + h;
  1329.                         targetid = i;
  1330.                         targDist = GetPlayerDistanceFromPoint(i, turPX, turPY, newPZ);
  1331.                         GetPlayerPos(i, pX, pY, pZ);
  1332.                     }
  1333.                 }
  1334.             }
  1335.             case TURRET_BEHAVIOR_AIM_SINGLE: {
  1336.                 if (IsPlayerConnected(rTurretData[turretid][e_turr_target])) {
  1337.                     targetid = rTurretData[turretid][e_turr_target];
  1338.                     targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1339.                     GetPlayerPos(targetid, pX, pY, pZ);
  1340.                 }
  1341.             }
  1342.             case TURRET_BEHAVIOR_AIM_CUSTOM: {
  1343.                 if (funcidx("OnTurretCustomShoot") != -1) {
  1344.                     new
  1345.                         rtn = CallLocalFunction("OnTurretCustomShoot", "d", turretid);
  1346.                        
  1347.                     if (IsPlayerConnected(rtn)) {
  1348.                         targetid = rtn;
  1349.                         targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1350.                         GetPlayerPos(targetid, pX, pY, pZ);
  1351.                     }
  1352.                 }
  1353.             }
  1354.             case TURRET_BEHAVIOR_AIM_RANDOM: {
  1355.                 if (Iter_Count(rTurretTargets[turretid]) > 0) {
  1356.                     targetid = Iter_Random(rTurretTargets[turretid]);
  1357.                     targDist = GetPlayerDistanceFromPoint(targetid, turPX, turPY, newPZ);
  1358.                     GetPlayerPos(targetid, pX, pY, pZ);
  1359.                 }
  1360.             }
  1361.         }
  1362.         if (targetid != INVALID_PLAYER_ID) {
  1363.             // Set turret facing target
  1364.             new
  1365.                 Float:vX,
  1366.                 Float:vY,
  1367.                 Float:vZ,
  1368.                 Float:Speed;
  1369.                
  1370.             if (rTurretData[turretid][e_turr_3dspace]) {
  1371.                 // Turret aims in 3d space
  1372.                 // Bullet's destination z value changes
  1373.                 newPZ = newPZ + (rTurretData[turretid][e_turr_range] * ((pZ - newPZ) / (targDist)));
  1374.             }
  1375.             turRZ = atan2(pY - turPY, pX - turPX);
  1376.            
  1377.             if (IsPlayerInAnyVehicle(targetid))
  1378.                 GetVehicleVelocity(GetPlayerVehicleID(targetid), vX, vY, vZ);
  1379.             else
  1380.                 GetPlayerVelocity(targetid, vX, vY, vZ);
  1381.                
  1382.             // Approximate player speed in units per second?
  1383.             Speed = floatsqroot(((vX * vX) + (vY * vY) + (vZ * vZ))) * 81.137;
  1384.            
  1385.             if (floatcmp(Speed, 0.0) != 0) {
  1386.                 if (!rTurretData[turretid][e_turr_predict]) {
  1387.                     newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1388.                     newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1389.                 } else {
  1390.                     // Predictive aim (inaccurate atm, needs improvement)
  1391.                     new
  1392.                         Float:pA;
  1393.                        
  1394.                     GetPlayerFacingAngle(targetid, pA);
  1395.                     pA = -pA + 360;
  1396.                    
  1397.                     new
  1398.                         Float:targetTravelDist = Speed / (1000 / float(rTurretData[turretid][e_turr_rate])),
  1399.                         Float:bulletCross = floatsqroot(floatpower(targetTravelDist, 2) + floatpower(targDist, 2) - 2 * targetTravelDist * targDist * floatcos(pA - turRZ, degrees)),
  1400.                         Float:angleAdjust = asin((floatsin(pA - turRZ) * targetTravelDist) / bulletCross);
  1401.                        
  1402.                     //printf("Speed: %.2f | TravelDist: %.2f | Cross: %.2f | pA: %.2f | Angle: %.2f", Speed, targetTravelDist, bulletCross, pA, angleAdjust);
  1403.  
  1404.                     if (angleAdjust == angleAdjust) {
  1405.                         turRZ = turRZ + angleAdjust;
  1406.                         newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1407.                         newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1408.                     } else {
  1409.                         // Rare case of NaN angle
  1410.                         newPX = pX;
  1411.                         newPY = pY;
  1412.                     }
  1413.                 }
  1414.             } else {
  1415.                 // When standing still, targets don't get hit by very fast bullets (speed >= 20 && rate >= 250)
  1416.                 // Temporary solution
  1417.                 newPX = pX;
  1418.                 newPY = pY;
  1419.             }
  1420.             SetDynamicObjectRot(rTurretData[turretid][e_turr_objectid], turRX, turRY, turRZ);
  1421.         } else {
  1422.             // Turret doesn't change direction
  1423.             newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1424.             newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1425.         }
  1426.     } else {
  1427.         newPX = turPX + (rTurretData[turretid][e_turr_range] * floatsin(-(turRZ + 270), degrees));
  1428.         newPY = turPY + (rTurretData[turretid][e_turr_range] * floatcos(-(turRZ + 270), degrees));
  1429.     }
  1430.        
  1431.     bulletid =
  1432.         CreateDynamicObject(rTurretData[turretid][e_turr_bullet_model],
  1433.             turPX + (1.0 * floatsin(-(turRZ + 270), degrees)),
  1434.             turPY + (1.0 * floatcos(-(turRZ + 270), degrees)),
  1435.             turPZ + 1.15, 0, 270.0, turRZ,
  1436.             rTurretData[turretid][e_turr_world],
  1437.             rTurretData[turretid][e_turr_interior],
  1438.             .streamdistance = rTurretData[turretid][e_turr_stream]);
  1439.            
  1440.     if (rTurretData[turretid][e_turr_bullet_color] != 0)
  1441.         SetDynamicObjectMaterial(bulletid, 0, -1, "none", "none", rTurretData[turretid][e_turr_bullet_color]);
  1442.  
  1443.     areaid = CreateDynamicSphere(0, 0, 0, rTurretData[turretid][e_turr_bullet_radius], rTurretData[turretid][e_turr_world], rTurretData[turretid][e_turr_interior]);
  1444.     AttachDynamicAreaToObject(areaid, bulletid);
  1445.        
  1446.     // Bullet object array data (identifier, turretid, areaid)
  1447.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, TURRET_BULLET_OBJECT_INT);
  1448.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, turretid);
  1449.     Streamer_AppendArrayData(STREAMER_TYPE_OBJECT, bulletid, E_STREAMER_EXTRA_ID, areaid);
  1450.    
  1451.     // Area array data (identifier, turretid, bullet objectid)
  1452.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, TURRET_BULLET_AREA_INT);
  1453.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, turretid);
  1454.     Streamer_AppendArrayData(STREAMER_TYPE_AREA, areaid, E_STREAMER_EXTRA_ID, bulletid);
  1455.  
  1456.     MoveDynamicObject(bulletid, newPX, newPY, newPZ, rTurretData[turretid][e_turr_speed]);
  1457.        
  1458.     if (!rTurretData[turretid][e_turr_playsound])
  1459.         foreach(new i : rTurretPlayersInBigArea[turretid])
  1460.             Streamer_Update(i);
  1461.     else {
  1462.         foreach(new i : rTurretPlayersInBigArea[turretid]) {
  1463.             Streamer_Update(i);
  1464.             if (IsPlayerInRangeOfPoint(i, 20.0, turPX, turPY, turPZ))
  1465.                 PlayerPlaySound(i, rTurretData[turretid][e_turr_soundid], 0, 0, 0);
  1466.             else {
  1467.                 GetPlayerPos(i, pX, pY, pZ);
  1468.                 PlayerPlaySound(i, rTurretData[turretid][e_turr_soundid], pX, pY, pZ + 7);
  1469.             }
  1470.         }
  1471.     }
  1472.     return 1;
  1473. }
  1474.  
  1475. public Timer_ResetTurretKilled(playerid)
  1476. {
  1477.     rTurret_Killed{playerid} = false;
  1478.     rTurret_KilledBy[playerid] = INVALID_TURRET;
  1479. }
RAW Paste Data