robotmonkey

SA-MP - rTurret v1.1

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