General:

Some of you may remember my releases "Snow in Los Santos" and "Snow in Desert", and now I present you an easy way to cover any part of San Andreas map by simply inserting minimum X, Y and maximum X, Y coordinates or range arguments (and some additional arguments).



Required files:
Streamer plugin by Incognito,
All GTA SA Object Array include by Pottus,
Model sizes include by ******.

You can download the script here, rather than copying every chunk of code from the tutorial.




Code:

You'll need function which will retexture your objects with snow texture.
pawn Code:
stock AddSnowObject(modelid, Float:x, Float:y, Float:z, Float:rx, Float:ry, Float:rz, Float:d_stream = 200.0)
{
new
object = CreateDynamicObject(modelid, (x + 0.075), (y + 0.15), (z + 0.15), rx, ry, rz, .streamdistance = d_stream);
for(new a = 0; a < 30; a++)
SetDynamicObjectMaterial(object, a, 17944, "lngblok_lae2", "white64bumpy");
return object;
}

Area creation:

Next, you'll need a function to check if position is in specified area.
pawn Code:
stock IsPosInArea(Float:pos_x, Float:pos_y, Float:min_x, Float:min_y, Float:max_x, Float:max_y)
{
if(pos_x >= min_x && pos_x <= max_x
&& pos_y >= min_y && pos_y <= max_y)
return true;
return false;
}

Now, this function will create snow objects based on your area arguments (minimum X&Y and maximum X&Y), maximum Z and minimum model size of the snow objects. Make sure to read more information below this code.
pawn Code:
stock CreateSnowInArea(Float:min_x, Float:min_y, Float:max_x, Float:max_y, Float:max_z = 300.0, Float:min_obj_model_size = 30.0)
{
new
count;
for(new a = 0; a < SEARCH_DATA_SIZE; a++)
{
if(SearchData[a][SearchZ] > max_z)
continue;
if(!IsPosInArea(SearchData[a][SearchX], SearchData[a][SearchY], min_x, min_y, max_x, max_y))
continue;
if(GetColSphereRadius(SearchData[a][Search_Model]) < min_obj_model_size)
continue;
if(IsObjectRemoved(SearchData[a][Search_Model], SearchData[a][SearchX], SearchData[a][SearchY], SearchData[a][SearchZ]))
continue;
AddSnowObject(
SearchData[a][Search_Model],
SearchData[a][SearchX],
SearchData[a][SearchY],
SearchData[a][SearchZ],
SearchData[a][SearchRX],
SearchData[a][SearchRY],
SearchData[a][SearchRZ],
(100.0 + GetColSphereRadius(SearchData[a][Search_Model]))
);
count++;
}
printf("Total snow objects: %i", count);
return true;
}
This function will loop through every San Andreas map object and create the snow copies based on your arguments (min_x, min_y, max_x, max_y, max_z, min_obj_model_size). I do not encourage you to use this as it is, so you should rather use printing function below.

This function will print your raw snow object codes, which you can later copy from your "server_log.txt" file.
pawn Code:
stock PrintSnowForArea(Float:min_x, Float:min_y, Float:max_x, Float:max_y, Float:max_z = 300.0, Float:min_obj_model_size = 30.0)
{
new
count;
for(new a = 0; a < SEARCH_DATA_SIZE; a++)
{
if(SearchData[a][SearchZ] > max_z)
continue;
if(!IsPosInArea(SearchData[a][SearchX], SearchData[a][SearchY], min_x, min_y, max_x, max_y))
continue;
if(GetColSphereRadius(SearchData[a][Search_Model]) < min_obj_model_size)
continue;
if(IsObjectRemoved(SearchData[a][Search_Model], SearchData[a][SearchX], SearchData[a][SearchY], SearchData[a][SearchZ]))
continue;
printf("AddSnowObject(%i, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.1f);",
SearchData[a][Search_Model],
SearchData[a][SearchX],
SearchData[a][SearchY],
SearchData[a][SearchZ],
SearchData[a][SearchRX],
SearchData[a][SearchRY],
SearchData[a][SearchRZ],
(100.0 + GetColSphereRadius(SearchData[a][Search_Model]))
);
count++;
}
printf("Total snow objects: %i", count);
return true;
}
The streaming distance of every object if based on the model size of the object. The streaming distance is 100.0 units + the model size.

Range creation:

Next, you'll need a function to check if position is in specified range.
pawn Code:
stock IsPosInRangeOfPoint2D(Float:pos_x, Float:pos_y, Float:range, Float:range_x, Float:range_y)
{
pos_x -= range_x;
pos_y -= range_y;
return ((pos_x * pos_x) + (pos_y * pos_y)) < (range * range);
}

Now, this function will create snow objects based on your range arguments (X&Y center coordinates and range), maximum Z and minimum model size of the snow objects. Make sure to read more information below this code.
pawn Code:
stock CreateSnowInRange(Float:pos_x, Float:pos_y, Float:range, Float:max_z = 300.0, Float:min_obj_model_size = 30.0)
{
new
count;
for(new a = 0; a < SEARCH_DATA_SIZE; a++)
{
if(SearchData[a][SearchZ] > max_z)
continue;
if(!IsPosInRangeOfPoint2D(SearchData[a][SearchX], SearchData[a][SearchY], range, pos_x, pos_y))
continue;
if(GetColSphereRadius(SearchData[a][Search_Model]) < min_obj_model_size)
continue;
if(IsObjectRemoved(SearchData[a][Search_Model], SearchData[a][SearchX], SearchData[a][SearchY], SearchData[a][SearchZ]))
continue;
AddSnowObject(
SearchData[a][Search_Model],
SearchData[a][SearchX],
SearchData[a][SearchY],
SearchData[a][SearchZ],
SearchData[a][SearchRX],
SearchData[a][SearchRY],
SearchData[a][SearchRZ],
(100.0 + GetColSphereRadius(SearchData[a][Search_Model]))
);
count++;
}
printf("Total snow objects: %i", count);
return true;
}
This function will loop through every San Andreas map object and create the snow copies based on your arguments (pos_x, pos_y, range, max_z, min_obj_model_size). I do not encourage you to use this as it is, so you should rather use printing function below.

This function will print your raw snow object codes, which you can later copy from your "server_log.txt" file.
pawn Code:
stock PrintSnowForRange(Float:pos_x, Float:pos_y, Float:range, Float:max_z = 300.0, Float:min_obj_model_size = 30.0)
{
new
count;
for(new a = 0; a < SEARCH_DATA_SIZE; a++)
{
if(SearchData[a][SearchZ] > max_z)
continue;
if(!IsPosInRangeOfPoint2D(SearchData[a][SearchX], SearchData[a][SearchY], range, pos_x, pos_y))
continue;
if(GetColSphereRadius(SearchData[a][Search_Model]) < min_obj_model_size)
continue;
if(IsObjectRemoved(SearchData[a][Search_Model], SearchData[a][SearchX], SearchData[a][SearchY], SearchData[a][SearchZ]))
continue;
printf("AddSnowObject(%i, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.1f);",
SearchData[a][Search_Model],
SearchData[a][SearchX],
SearchData[a][SearchY],
SearchData[a][SearchZ],
SearchData[a][SearchRX],
SearchData[a][SearchRY],
SearchData[a][SearchRZ],
(100.0 + GetColSphereRadius(SearchData[a][Search_Model]))
);
count++;
}
printf("Total snow objects: %i", count);
return true;
}
The streaming distance of every object if based on the model size of the object. The streaming distance is 100.0 units + the model size.



Function arguments:

Area creation:
@FLOat: min_x - minimum X coordinate for your area
@FLOat: min_y - minimum Y coordinate for your area
@FLOat: max_x - maximum X coordinate for your area
@FLOat: max_y - maximum Y coordinate for your area
@FLOat: max_z - maximum Z coordinate (this limit is useful for stopping snow object creation on interior objects which are located at 1000.0 units approximately)
@FLOat: min_obj_model_size - minimum object radius of the collision sphere

Range creation:
@FLOat: pos_x - center X coordinate for your range
@FLOat: pos_y - center Y coordinate for your range
@FLOat: range - range
@FLOat: max_z - maximum Z coordinate (this limit is useful for stopping snow object creation on interior objects which are located at 1000.0 units approximately)
@FLOat: min_obj_model_size - minimum object radius of the collision sphere



How to get minimum and maximum X, Y area coordinates:

You can read more about the area checking here.

Area example (Los Santos area).


Coordinate 1 (minimum): A1(X: 50.0, Y: -3000.0)
Coordinate 2 (maximum): A2(X: 3000.0, Y: -750.0)

Range example (San Andreas map center at 0.0 with range of 1000.0).


Use the SA-MP command "/save" while in-game to gather coordinates.



Example:

pawn Code:
public OnGameModeInit()
{
PrintSnowForArea(50.0, -3000.0, 3000.0, -750.0, 300.0, 30.0);
return true;
}
This code will print 1506 snow objects for Los Santos area (marked on area map above).

pawn Code:
public OnGameModeInit()
{
PrintSnowForRange(0.0, 0.0, 1000.0, 500.0, 30.0);
return true;
}
This code will print 367 snow objects for 1000.0 range of 0.0 center (marked on range map above).

Once you compile your script and execute it, it will print raw snow object code. Close the server and open your "server_log.txt" file. Clear the unnecessary logs and time prints from object code (CTRL + H "Search for: [hh : mm : ss]" and leave "Replace with:" empty).

Put your printed snow objects in your script and don't forget to include the streamer plugin include file in the script and to run the plugin.

This is the result for LS area.


You can download the LS area raw snow objects here (1506 snow objects).




Removed objects support:

You can skip the snow creating on areas where you removed objects (with "RemoveBuildingForPlayer" function) for your maps.

This is the code you'll need. The checking code is already added to the Create/Print functions.
pawn Code:
#define MAX_REMOVED_OBJECTS (500) // Value of maximum objects which can be removed. Set your own value.

pawn Code:
enum ObjectRemoved
{
Model,
Float:Location[3]
}

pawn Code:
new
RemovedObject[MAX_REMOVED_OBJECTS][ObjectRemoved],
g_SlotID = -1
;

pawn Code:
stock IsPosInRangeOfPoint3D(Float:pos_x, Float:pos_y, Float:pos_z, Float:range, Float:range_x, Float:range_y, Float:range_z)
{
pos_x -= range_x;
pos_y -= range_y;
pos_z -= range_z;
return ((pos_x * pos_x) + (pos_y * pos_y) + (pos_z * pos_z)) < (range * range);
}

pawn Code:
stock RemoveObject(modelid, Float:pos_x, Float:pos_y, Float:pos_z)
{
g_SlotID++;
if(g_SlotID == MAX_REMOVED_OBJECTS)
{
printf("Error: Limit for removed objects is reached. Open your script and change "MAX_REMOVED_OBJECTS" definition to a bigger value if you want to have more removed objects.");
g_SlotID--;
return -1;
}
if(g_SlotID == 1000)
{
printf("SA-MP limit: There appears to be a limit of around 1000 lines/objects. There is no workaround.");
g_SlotID--;
return -1;
}
RemovedObject[g_SlotID][Model] = modelid;
RemovedObject[g_SlotID][Location][0] = pos_x;
RemovedObject[g_SlotID][Location][1] = pos_y;
RemovedObject[g_SlotID][Location][2] = pos_z;
return g_SlotID;
}

pawn Code:
stock GetNumberOfRemovedObjects()
return (g_SlotID + 1);

pawn Code:
stock IsObjectRemoved(modelid, Float:pos_x, Float:pos_y, Float:pos_z)
{
if(!GetNumberOfRemovedObjects())
return false;
for(new a = 0; a < GetNumberOfRemovedObjects(); a++)
{
if(modelid == RemovedObject[a][Model])
{
if(IsPosInRangeOfPoint3D(pos_x, pos_y, pos_z, 0.5, RemovedObject[a][Location][0], RemovedObject[a][Location][1], RemovedObject[a][Location][2]))
return true;
}
}
return false;
}

Example how to use the removing function.
pawn Code:
public OnGameModeInit()
{
/*
@modelid - model of your object
@FLOat: pos_x - X coordinate for your object
@FLOat: pos_y - Y coordinate for your object
@FLOat: pos_z - Z coordinate for your object
*/
RemoveObject(4024, 1479.8672, -1790.3984, 56.0234);
RemoveObject(4044, 1481.1875, -1785.0703, 22.3828);
RemoveObject(4045, 1479.3359, -1802.2891, 12.5469);
RemoveObject(4046, 1479.5234, -1852.6406, 24.5156);
RemoveObject(4047, 1531.6328, -1852.6406, 24.5156);
return true;
}

Don't forget to remove all the objects when player connects to the server.
pawn Code:
public OnPlayerConnect(playerid)
{
if(GetNumberOfRemovedObjects())
{
for(new a = 0; a < GetNumberOfRemovedObjects(); a++)
{
RemoveBuildingForPlayer(
playerid,
RemovedObject[a][Model],
RemovedObject[a][Location][0],
RemovedObject[a][Location][1],
RemovedObject[a][Location][2],
0.5
);
}
}
return true;
}

Example with removed objects.




Problems:



Textures on some objects like trees, bushes and electrical wires will look a bit wierd, so you may want to exclude these objects from the creating/printing code. I don't think there's an easy way to do that. Only way I see it, is to open the Map Editor, search for every tree, bush, electrical wire and similar objects and exclude them.