Tutorial Link:
http://quakeone.com/forums/quake-help/quake-clients/6869-tut-creating-rain-snow-fog-darkplaces.html


------------------------

29.04.2011:

I added rain sounds into LordHavocs rain code.
This gives much much more atmosphere. Sometimes a thunder sound will appear as well ;-)


------------------------


Dear all,

Inspired by the great tutorials at inside3D, I wanted to try something like this as well.

The fact that DarkPlaces also has beautiful weather features, has been overlooked by many people for a long time. Even some experienced DP-users have not been aware of it.
Reason for it is that rain and snow in DP is not only engine coded but also QC coded “hidden” inside dpmod.
Fog is available out of the box in DarkPlaces (no need to have dpmod code !).

1.) Rain+Snow QC code
First of all you must implement LordHavoc´s rain and snow code into regular Quake 1.06 QC.
The only file you have to edit is “misc.qc”
Add this to the very end:

Code:
// ============================================================================
/*  Rain effect from dpmod
*/

void() rain_think =
{
	self.nextthink = time + 0.1;
	te_particlerain(self.absmin, self.absmax, self.dest, self.count, self.cnt);
//	te_particlesnow(self.absmin, self.absmax, self.dest * 0.25, self.count, self.cnt);
//	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
//	WriteByte (MSG_BROADCAST, TE_PARTICLERAIN);
//	WriteVec (MSG_BROADCAST, self.absmin);
//	WriteVec (MSG_BROADCAST, self.absmax);
//	WriteVec (MSG_BROADCAST, self.dest);
//	WriteShort (MSG_BROADCAST, self.count);
//	WriteByte (MSG_BROADCAST, self.cnt);
};

/*QUAKED func_rain (0 .5 .8) ?
This is an invisible area like a trigger, which rain falls inside of.

Keys:
"velocity"
 falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
"cnt"
 sets color of rain (default 12 - white)
"count"
 adjusts rain density, this many particles fall every second, experiment to see the effects (default is based on area size)
*/
void() func_rain =
{
	self.dest = self.velocity;
	self.velocity = '0 0 0';
	if (!self.dest)
		self.dest = '0 0 -700';
	self.angles = '0 0 0';
	self.movetype = MOVETYPE_NONE;
	self.solid = SOLID_NOT;
	setmodel(self, self.model);
	setorigin(self, self.origin);
	setsize(self, self.mins, self.maxs);
	self.model = "";
	if (!self.cnt)
		self.cnt = 12;
	if (!self.count)
		self.count = (self.absmax_x - self.absmin_x)*(self.absmax_y - self.absmin_y)/8192;
	if (self.count < 1)
	{
		remove(self);
		return;
	}
	// convert from per second to per 0.1 sec,
	self.count = ceil(self.count * 0.1);
	self.think = rain_think;
	self.nextthink = time + 0.5;
};

// ============================================================================
/*  Snow effect from dpmod
*/

void() snow_think =
{
	self.nextthink = time + 0.1;
	te_particlesnow(self.absmin, self.absmax, self.dest, self.count, self.cnt);
//	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
//	WriteByte (MSG_BROADCAST, TE_PARTICLESNOW);
//	WriteVec (MSG_BROADCAST, self.absmin);
//	WriteVec (MSG_BROADCAST, self.absmax);
//	WriteVec (MSG_BROADCAST, self.dest);
//	WriteShort (MSG_BROADCAST, self.count);
//	WriteByte (MSG_BROADCAST, self.cnt);
};

/*QUAKED func_snow (0 .5 .8) ?
This is an invisible area like a trigger, which snow falls inside of.

Keys:
"velocity"
 falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
"cnt"
 sets color of rain (default 12 - white)
"count"
 adjusts snow density, this many particles fall every second, experiment to see the effects (default is based on area size)
*/
void() func_snow =
{
	self.dest = self.velocity;
	self.velocity = '0 0 0';
	if (!self.dest)
		self.dest = '0 0 -300';
	self.angles = '0 0 0';
	self.movetype = MOVETYPE_NONE;
	self.solid = SOLID_NOT;
	setmodel(self, self.model);
	setorigin(self, self.origin);
	setsize(self, self.mins, self.maxs);
	self.model = "";
	if (!self.cnt)
		self.cnt = 12;
	if (!self.count)
		self.count = (self.absmax_x - self.absmin_x)*(self.absmax_y - self.absmin_y)/8192;
	if (self.count < 1)
	{
		remove(self);
		return;
	}
	// convert from per second to per 0.1 sec,
	self.count = ceil(self.count * 0.1);
	self.think = snow_think;
	self.nextthink = time + 0.5;
};

Now copy the file "dpextensions.qc" (from either dpmod source or find it in regular DP builds as well) to your QC folder.
Open "progs.src" and write: dpextensions.qc after "defs.qc".
Compile it and you get your "progs.dat" file (which you put into your ID1 folder).

Alternatively you can also use my “small mod compilation” (I included the code into it), if you are not familiar with QC editing or compiling.

Now we have the possibility to have rain and snow in DarkPlaces.
The only thing that is left is telling DP were it should fall and how it shall look like (continue with point 2.)


2.) Creating .ent files for the rain and snow effect in maps
It is mandatory to use an .ent file to have rain and snow in the maps.
Reason: There is no in-game option to enable / disable weather effects in DarkPlaces.
We have to tell DarkPlaces via the .ent file where and how the rain and snow shall fall and how it shall look like.

2a) Creating an .ent file
You first have to create the .ent file, which we will modify with rain or snow later on.
Start your map (example: e1m1.bsp) and type: sv_saveentfile in the console.
The e1m1.ent file is now in your maps folder (be careful, existing files will be overwritten).

2b) Finding the area (coordinates) for the rain or snow to fall
Fortunately LordHavoc gave us the tool with which we can do this in no time as a gift in DarkPlaces.
We will misuse his RTLIGHTS Editor for it ;)
Type: r_editlights 1 in the console.
A cursor will appear which will tell you exactly the X/Y/Z coordinates of everything you want.
The weather code in DP needs to have the cube coordinates in which the rain or snow shall fall.
The cube is defined by 2 coordinates: its 2 opposite corners.
What you want to do now is to fly (with noclip) to the roof cutout and detect one corner of it (X2/Y2/Z2).
Now fly to the opposite corner and detect (X1/Y1). The Z1 value is the lowest point (=floor) beneath the cutout,
So fly down to the ground again and detect the Z1 coordinate.
I named the XYZ coordinates (1 and 2) with purpose !
You must always enter the low corner first, then the opposite upper corner.
The cube coordinates which we will add into the .ent files should be slightly taller:
X1 / Y1 / Z1-50 (= min)
X2 / Y2 / Z2+20 (= max)

2c) Declare the rain / snow properties
Now all that is left to do is to tell DarkPlaces how the rain / snow shall look like and how it shall fall.
- Velocity = X / Y / Z (standard should be for rain: 0/0/-700 ; for snow: 0/0/-100 (sometimes you must use Z=-190 to spawn snowflakes !))
You can simulate wind as well, by using X or Y values other than 0.
- Visual of rain/snow and rainfall/snowfall rate
You have the “count” parameter and the “cnt” parameter for it.
“count” is directly related to the size of the cube and declares the rainfall/snowfall rate. Standard for a medium cube should be (for rain: “4”; for snow: "10").
In a small cube value “4” will have heavier rain than in a big cube with “4”.
“cnt” declares the visual. Such as: color, thickness and transparency.
My “cnt” favorite for rain is: “2”. (A value of “2” is realistic rain). For snow: "11".
The bigger the value gets (until around “15”), the thicker, opaque and whiter the rain/snow gets.
Values bigger than “15” brings colored rain/snow (example: red), which is maybe interesting for some hellish maps.

The beautiful rain splashes (when the rain touches the floor or water surface) is part of the code and follows the params automatically.

2d) Edit the .ent file
Now you have everything you need and can edit your .ent file, which you created in 2a).
Each cube has one block in the .ent file.
If you have a complicated map geometry like in e1m1, you will need a lot of cubes to have the weather effect in all corners,
and avoid rain/snow in the inside areas. It took me around 60 minutes to have beautiful rain in e1m1.
Add the rain/snow blocks after the first block in the .ent file ! (You DON’T need a special rain/snow block order then)

One block looks like this (example):

For rain in e1m1:
{
"classname" "info_notnull"
"mins" "-460 1730 -230"
"maxs" "-84 500 200"
"absmin" "-460 1730 -230"
"absmax" "-84 500 200"
"nextthink" "0.1"
"think" "rain_think"
"dest" "0 0 -700"
"count" "4"
"cnt" "2"
}

For snow in start.ent:
{
"classname" "info_notnull"
"mins" "604 2108 -704"
"maxs" "1618 2760 360"
"absmin" "604 2108 -704"
"absmax" "1618 2760 360"
"nextthink" "0.1"
"think" "snow_think"
"dest" "0 0 -100"
"count" "10"
"cnt" "11"
}

Save it and you are done. Next time DarkPlaces starts, the .ent file will be used and you see the result.

With a little exercise (after 1-2 maps) you will be able to create the .ent file in 20 minutes per map.
Depending on the geometry of the roof cutouts or the outside area geometry.
As mentioned above, in complicated maps it can take up to 60 minutes (or more) due to many necessary cubes.


3.) Fog in DarkPlaces
Of course you can add fog in the .ent file as well (independent if you have rain/snow blocks or not).
Fog must be included in the end of first block and needs only one line (command).
You do NOT need the rain/snow code to have fog in DarkPlaces (fog can be used out of the box) !

Fog syntax is as follows:
fog : set global fog parameters (density red green blue [alpha [mindist [maxdist [top [fadedepth]]]]])

Fog example (for start.ent):
{
"sounds" "4"
"classname" "worldspawn"
"wad" "gfx/start.wad"
"message" "Introduction"
"worldtype" "0"
"fog" ".3 .32 .25 .2 .6 20 2000 1500 30"
}

You can also have fog in DarkPlaces without an .ent file.
Just bind the fog command to a key and enable/disable it whenever you want (example):
bind f "fog .3 .32 .25 .2 .6 20 2000 1500 30"


Enjoy the beautiful weather effects in DarkPlaces.
…be sure to not forget your umbrella ;)
And dont worry, it is easier than you think. I only wrote so much because I wanted to leave no open questions.

I will add some of my own .ent files in the following post(s).

Kind regards,
Seven

-------------


ATTENTION:
If you want to enable or disable the .ent file (= weather) usage, use this cvar:
sv_entpatch 0   (Disables .ent file usage)
sv_entpatch 1   (Enables .ent file usage = default)

You can bind these cvars to a key for your convenience.
Be sure to "restart" (you can bind "restart" to a key as well) the map to take effect.
