Schneider1988

[FS]Keep your Lane (Stand Alone) - by Schneider

Dec 16th, 2014
330
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 14.39 KB | None | 0 0
  1. #include <a_samp>
  2. #include <sscanf2>
  3.  
  4. #define MAX_ROADPOINTS_PER_ZONE 500  // This value will define the size of the array in which the RoadPoints in each zone will be stored.
  5.                                      // If this value is too small (there are more RoadPoints in a zone than this value) this system will be terminated.
  6.                                      // On the other hand, if this value is too large your server will be less efficient. Keep an eye on the serverlog...
  7.                                      // ...it will show you the ideal value based on the number of RoadPoints found.
  8.  
  9.  
  10. #define ANGLE_TOLERANCE 25   // Example: if this value is set at 25 degrees and a given RoadPoint has an original angle of 150 degrees, the script will...
  11.                              //          ...trigger OnPlayerWrongLane when a player passes this point with an angle between 125 and 175 degrees.
  12.  
  13.  
  14. #define ROADPOINT_CHECK_INTERVAL 100   // This the interval in milliseconds of which the script will check each player if it's driving on the wrong side of the road.
  15.                              // The lower this value the more precice this system will work, but with many players or having a large script it might slow it down.
  16.  
  17.  
  18. #define BUILD "1.1.2"
  19.  
  20. //New Variables:
  21. new TRP;  //Will store the total amout of RoadPoints created.  (wont get lowered when RoadPoints gets removed until restart. Used to give new Roadpoints an unique ID).
  22.  
  23. //Roadpoint Enum
  24. enum rpinfo
  25. {
  26.     ID,      //Holds the unique ID of each RoadPoint
  27.     Float:X,  // Holds the X coordinate of each RoadPoint
  28.     Float:Y,  // Holds the Y coordinate of each RoadPoint
  29.     Float:Z,  // Holds the Z coordinate of each RoadPoint
  30.     Float:A,  // Holds the angle of each roadpoint (Note: this value should be the angle the players are supposed to drive!)
  31.     Float:D,  // Holds the maximum distance a player has to be from this RoadPoint before it's triggered.
  32. }
  33.  
  34. //This is the main array that stores all info about each RoadPoint.
  35. //The first dimention (37) is the number of zones (36 zones as described above + 1 extra zone in case players have custom roads build on the oceans around the map.
  36. //Each zone has (MAX_ROADPOINTS_PER_ZONE) slots available.
  37. new RP[145][MAX_ROADPOINTS_PER_ZONE][rpinfo];
  38. new RPInZone[145];
  39.  
  40. //Publics
  41. public OnFilterScriptInit()
  42. {
  43.     ResetRoadPointInfo(); //Will destroy and reset all values and pickups.
  44.  
  45.     print("\n--------------------------------------------");
  46.     printf(" [FS]Keep Your Lane - StandAlone - Build %s", BUILD);
  47.     print("            by Schneider 2014");
  48.     print("---------------------------------------------\n");
  49.    
  50.     //This timer will trigger a function that will calculate the optimal value of MAX_ROADPOINTS_PER_ZONE...
  51.     SetTimer("CheckEfficiency", 3000, 0);
  52.     //SetTimer("SpeedTest", 4000, 0);
  53.     SetTimer("CheckRoadPoints", ROADPOINT_CHECK_INTERVAL, 1);   //Start the main timer that checks each players position on the road.
  54.  
  55.     ReadRoadPoints(); // This function will read and load all RoadPoints from the KYLRoadPoints.txt file.
  56.     return 1;
  57. }
  58.  
  59. public OnFilterScriptExit()
  60. {
  61.     ResetRoadPointInfo(); //Will destroy and reset all values and pickups.
  62.     return 1;
  63. }
  64.  
  65. stock GetZone(Float:vX, Float:vY)  // This function returns the zone-number based on given X- and Y-coord.
  66. {
  67.     new Float:H1, H2, Float:V1, V2, zone;  //Create variables
  68.     if((vX <= -3000.0) || (vY <= -3000.0) || (vX > 3000.0) || (vY > 3000.0))   // If position is outside of San Andreas (on the ocean), return zone #144
  69.     {
  70.         zone = 144;
  71.     }
  72.     else  // If the given position is inside the main land:
  73.     {
  74.         //The mainland is divided in 144 (12x12) zones, each 500x500 units wide.
  75.         H1 = floatdiv(vX, 500.0);   //Divide the X-coord by 500
  76.         V1 = floatdiv(vY, 500.0);   //Divide the Y-coord by 500
  77.        
  78.         H2 = floatround(H1);   //Temporarily round the horizantal row (H1)
  79.         V2 = floatround(V1);  // Temporarily round the vertical row( V1)
  80.  
  81.         if(H2 < H1) { H1 = floatadd(H1, 1.0); }  // If horizontal row get rounded down, add 1.
  82.         if(V2 < V1) { V1 = floatadd(V1, 1.0); }  // If vertical row get rounded down, add 1.
  83.         zone = (((floatround(H1)+5)*12)+(floatround(V1)+6))-1;   // Calculate the zone by adding and multiplying the horizontal and vertical rows with eachother.
  84.     }
  85.     return zone; // Return the zone (0-144)
  86. }
  87.  
  88. stock ResetRoadPointInfo()  // This Function will reset all RoadPoint-related variables and destroys the pickups.
  89. {
  90.     for(new zone; zone<145; zone++) // Loop through all 37 zones.
  91.     {
  92.         for(new slot; slot<MAX_ROADPOINTS_PER_ZONE; slot++)  // Loop through each slot in current zone
  93.         {
  94.             RP[zone][slot][X] = 0.0;  //Reset X Coordinate
  95.             RP[zone][slot][Y] = 0.0;  //Reset Y Coordinate
  96.             RP[zone][slot][Z] = 0.0;  //Reset Z Coordinate
  97.             RP[zone][slot][A] = 0.0;  //Reset Angle
  98.             RP[zone][slot][D] = 0;  //Reset Max Distance
  99.             RP[zone][slot][ID] = -1;  //Reset ID
  100.         }
  101.     }
  102.     return 1;
  103. }
  104.  
  105. stock ReadRoadPoints() //  This function will read and load all RoadPoints from the KYLRoadPoints.txt file
  106. {
  107.     new File:file;
  108.     if (!fexist("KYLRoadPoints.txt"))
  109.     {
  110.         file = fopen("KYLRoadPoints.txt",io_write);
  111.         fclose(file);
  112.     }
  113.     file=fopen("KYLRoadPoints.txt", io_read);
  114.     new str[64], zone, slot;  // Create new variables to store the string, zone and slot
  115.     new Float:rX, Float:rY, Float:rZ, Float:rA, Float:rType; // Create new temprorarily variables to store the coordinates, angle and distance
  116.     while(fread(file, str))  // Loop through each line in the file
  117.     {
  118.         sscanf(str, "fffff", rX, rY, rZ, rA, rType);  // Retrieve all values from the line and store them in the temporarily variables
  119.         {
  120.             zone = GetZone(rX, rY);  // Get the zone ID based on the X and Y coordinate
  121.             slot = GetFreeSlot(zone);  // Get the ID of the first free slot in this zone
  122.             if(slot != -1)   // If there is an empty slot found
  123.             {
  124.                 RP[zone][slot][X] = rX;  // Store the temporarily X value in the global array
  125.                 RP[zone][slot][Y] = rY;  // Store the temporarily Y value in the global array
  126.                 RP[zone][slot][Z] = rZ;  // Store the temporarily Z value in the global array
  127.                 RP[zone][slot][A] = rA;  // Store the temporarily angle in the global array
  128.                 RP[zone][slot][D] = rType;  // Store the temporarily distance in the global array
  129.                 RP[zone][slot][ID] = TRP; // Give the new RoadPoint an unique ID (based on total amount of created RoadPoints)
  130.                 TRP++;  // Increae number of total created RoadPoints by 1
  131.                 RPInZone[zone]++;
  132.             }
  133.             else  // if no empty slot is found in the current zone:
  134.             {
  135.                 //Send error message to the ServerLog
  136.                 print("------------------------------------------------------------------");
  137.                 printf("FATAL ERROR: Too many RoadPoints in Zone #%02d (Limit: %d)", zone, MAX_ROADPOINTS_PER_ZONE);
  138.                 print("Loading of the RoadPoints has failed");
  139.                 print("Increase the value of MAX_ROADPOINTS_PER_ZONE");
  140.                 print("at the top of the filterscript and reload");
  141.                 print("------------------------------------------------------------------");
  142.                 ResetRoadPointInfo(); // Reset all RoadPoints related info.
  143.                 fclose(file); // Close the fille
  144.                 return 0; // Abort the function
  145.             }
  146.         }
  147.     }
  148.     fclose(file);  // Close the file
  149.     printf("%d roadpoints loaded", TRP); // Show in ServerLog the total amound of created RoadPoints.
  150.     return 1;
  151. }
  152.  
  153. forward CheckRoadPoints();
  154. public CheckRoadPoints()   // This is the main function that checks the players position and sees if he's driving on the wrong side of the road:
  155. {
  156.     new zone, currentzone, slot, rtrn; // Create some variables to temporarily store values.
  157.     for(new i; i<MAX_PLAYERS; i++) // Loop through all players
  158.     {
  159.         if(GetPlayerState(i) == PLAYER_STATE_DRIVER) // Check if the player is driving a vehicle
  160.         {
  161.             // My original plan was to only scan the players current zone for RoadPoints and check if the player is near any of them, but it caused problems when...
  162.             //... because RoadPoints near its zone-border wont get triggered if the player is within reach, but on the other side of the border (in an different zone)...
  163.             //... To solve this problem this script will not only scan the players current zone, but also the 4 surrounding zones for RoadPoints (if none have been found already).
  164.            
  165.             currentzone = GetPlayerZone(i);  // First get the player current zone
  166.            
  167.             // I created the funtion 'IsPlayerOnWrongWay' to check if the player is near a Roadpoint and, if so, check if the player is driving the right or wrong direction.
  168.             // It will return '-1' if the player is not near any roadpoint in the given zone. Return '0' if the player is near a RoadPoint, but driving the right direction...
  169.             //..and it will return '1' if the player is near a RoadPoint AND driving the wrong direction.
  170.             //... this function also returns the slot of the found RoadPoint.
  171.            
  172.             rtrn = IsPlayerOnWrongWay(i, currentzone, slot);   // Check if the player is near any RoadPoint in his current zone.
  173.             //// If the player is Ghost Driving, the remote callback 'OnPlayerGhostDriving' will be called (in your gamemode), it passes the playerid, zone, XYZ-coords and angle of the RoadPoint
  174.             if(rtrn == 1) CallRemoteFunction("OnPlayerGhostDriving", "ddffff", i, zone, RP[currentzone][slot][X], RP[currentzone][slot][Y], RP[currentzone][slot][Z], RP[currentzone][slot][A]);
  175.             else if(rtrn == -1)  // If no close RoadPoint is found... scan the next surrounding zone and repeat if for all 4 surrounding zones (unless a point is found.
  176.             {
  177.                 zone = currentzone+1;
  178.                 rtrn = IsPlayerOnWrongWay(i, zone, slot);
  179.                 if(rtrn == 1) CallRemoteFunction("OnPlayerGhostDriving", "ddffff", i, zone, RP[zone][slot][X], RP[zone][slot][Y], RP[zone][slot][Z], RP[zone][slot][A]);
  180.                 else if(rtrn == -1)
  181.                 {
  182.                     zone = currentzone-1;
  183.                     rtrn = IsPlayerOnWrongWay(i, zone, slot);
  184.                     if(rtrn == 1) CallRemoteFunction("OnPlayerGhostDriving", "ddffff", i, zone, RP[zone][slot][X], RP[zone][slot][Y], RP[zone][slot][Z], RP[zone][slot][A]);
  185.                     else if(rtrn == -1)
  186.                     {
  187.                         zone = currentzone+12;
  188.                         rtrn = IsPlayerOnWrongWay(i, zone, slot);
  189.                         if(rtrn == 1) CallRemoteFunction("OnPlayerGhostDriving", "ddffff", i, zone, RP[zone][slot][X], RP[zone][slot][Y], RP[zone][slot][Z], RP[zone][slot][A]);
  190.                         else if(rtrn == -1)
  191.                         {
  192.                             zone = currentzone-12;
  193.                             rtrn = IsPlayerOnWrongWay(i, zone, slot);
  194.                             if(rtrn == 1) CallRemoteFunction("OnPlayerGhostDriving", "ddffff", i, zone, RP[zone][slot][X], RP[zone][slot][Y], RP[zone][slot][Z], RP[zone][slot][A]);
  195.                         }
  196.                     }
  197.                 }
  198.             }
  199.         }
  200.     }
  201.     return 1;
  202. }
  203.  
  204. // This function will scan the given zone for RoadPoints and check if the given player is near them and driving in the right or wrong direction...
  205. //.. it will return the slot of the Roadpoint in that zone and will return -1, 0, or 1, depending on if any points are found.
  206. IsPlayerOnWrongWay(playerid, zone, &slot)
  207. {
  208.     new Float:cA, Float:MinAngle, Float:MaxAngle;
  209.     new isfound = -1;  // On default no RoadPoint is found near the player
  210.     for(slot = 0; slot<MAX_ROADPOINTS_PER_ZONE; slot++)  // Loop through all RoadPoints in the given zone
  211.     {
  212.         if(IsPlayerInRangeOfPoint(playerid, RP[zone][slot][D], RP[zone][slot][X], RP[zone][slot][Y], RP[zone][slot][Z])) // Check if player is in range of the RoadPoint
  213.         {
  214.             isfound = 0; // Set the variable to '0', this means the player is near a RoadPoint, now we should check if the player is driving the right/wrong direction:
  215.             GetVehicleZAngle(GetPlayerVehicleID(playerid), cA);  // Get the current driving direction of the player
  216.             cA = floatsub(cA, 180);  // Invert the direction by subtracting 180 degrees.
  217.             if(cA < 0)  // check if the angle is below '0'
  218.             {
  219.                 cA = floatadd(cA, 360.0);  // add 360 to get it above 0 degrees again.
  220.             }
  221.             MinAngle = floatsub(RP[zone][slot][A], ANGLE_TOLERANCE); // Calculate the minimum angle by subtracting the angle tolerance (defined at top of this script)
  222.             MaxAngle = floatadd(RP[zone][slot][A], ANGLE_TOLERANCE); // Calculate the maximum angle by adding the angle tolerance (defined at top of this script)
  223.             if((cA > MinAngle) && (cA < MaxAngle))  // Check if the players driving direction is between the mininmum and maximum angle (if yes, he's driving in the wrong direction)
  224.             {
  225.                 isfound = 1; // If the player is indeed Ghost Driving, set the varible to '1'.
  226.             }
  227.             break; // stop the loop.
  228.         }
  229.     }
  230.     return isfound; // Return the result
  231. }
  232.  
  233. stock GetPlayerZone(playerid)  // This function returns the zone the player is currently in
  234. {
  235.     if(!IsPlayerInAnyVehicle(playerid)) return -1;
  236.     new vid = GetPlayerVehicleID(playerid);
  237.     new Float:zX, Float:zY, Float:zZ;
  238.     GetVehiclePos(vid, zX, zY, zZ);
  239.     return GetZone(zX, zY);
  240. }
  241.  
  242. stock GetFreeSlot(zone) // This funtion returns the ID of the first empty slot in the given zone. (Returns -1 if no empty slot is found in this zone).
  243. {
  244.     new freeslot = -1;
  245.     for(new slot; slot<MAX_ROADPOINTS_PER_ZONE; slot++)
  246.     {
  247.         if(RP[zone][slot][ID] == -1)
  248.         {
  249.             freeslot = slot;
  250.             break;
  251.         }
  252.     }
  253.     return freeslot;
  254. }
  255.  
  256. stock GetLargestZone() // This function returns the zone ID which holds the most RoadPoints. (Used in the CheckEfficiency function).
  257. {
  258.     new largestzone = -1;
  259.     new highestvalue = -1, tmp;
  260.     for(new zone; zone<145; zone++)
  261.     {
  262.         tmp = GetFreeSlot(zone);
  263.         if(tmp == -1)  //Zone is full
  264.         {
  265.             largestzone = zone;
  266.             highestvalue = MAX_ROADPOINTS_PER_ZONE;
  267.         }
  268.         if(tmp > highestvalue)
  269.         {
  270.             largestzone = zone;
  271.             highestvalue = tmp;
  272.         }
  273.     }
  274.     return largestzone;
  275. }
  276.  
  277. forward CheckEfficiency();
  278. public CheckEfficiency() // This function will check if the defined value of MAX_ROADPOINTS_PER_ZONE is optimal
  279. {
  280.     new zone = GetLargestZone();  // Retreive the zone which holds the most RoadPoints
  281.     new amount = GetFreeSlot(zone);  // Get the amount of RoadPoints in that zone.
  282.     if((amount <= MAX_ROADPOINTS_PER_ZONE) && (amount > 1))  // Check if this amount is lower than the defined MAX_ROADPOINTS_PER_ZONE
  283.     {
  284.         // If so, send a message to the serverlog suggesting the optimal value:
  285.         print("------------------------------------------------------------------");
  286.         print("[TIP]: If you are done with creating new RoadPoints you can");
  287.         print("increase your server's performance by lowering the value");
  288.         printf("of 'MAX_ROADPOINTS_PER_ZONE' to %d at the top of the Filterscript", amount);
  289.         print("-------------------------------------------------------------------");
  290.     }
  291.     return 1;
  292. }
Advertisement
Add Comment
Please, Sign In to add comment