diff --git a/Source/Client/Entities.c b/Source/Client/Entities.c
index 50abcb69..8c7bf9f1 100755
--- a/Source/Client/Entities.c
+++ b/Source/Client/Entities.c
@@ -122,6 +122,30 @@ void CSQC_Ent_Update( float flIsNew ) {
 		self.classname = sprintf( "spray_%s", sLogo );
 		self.predraw = Effect_Spraypaint;
 		self.drawmask = MASK_ENGINE;
+	} else if ( fEntType == ENT_DECAL ) {
+		string decalname = "";
+		string decalshader = "";
+
+		self.origin_x = readcoord();
+		self.origin_y = readcoord();
+		self.origin_z = readcoord();
+		
+		self.angles_x = readcoord();
+		self.angles_y = readcoord();
+		self.angles_z = readcoord();
+		
+		self.color_x = 1.0f - ( readbyte() / 255 );
+		self.color_y = 1.0f - ( readbyte() / 255 );
+		self.color_z = 1.0f - ( readbyte() / 255 );
+		self.classname = readstring();
+		decalname = sprintf("decal_%s", self.classname);
+		decalshader = sprintf("{\npolygonOffset\n{\nclampmap %s\nblendFunc filter\n}\n}", self.classname);
+		shaderforname(decalname, decalshader);
+		self.size = drawgetimagesize(self.classname);
+		self.classname = decalname;
+
+		self.predraw = Effect_Decal;
+		self.drawmask = MASK_ENGINE;
 	}
 }
 
diff --git a/Source/Globals.h b/Source/Globals.h
index 1a5c2589..6f8aa9a5 100755
--- a/Source/Globals.h
+++ b/Source/Globals.h
@@ -87,7 +87,8 @@ enum {
 	ENT_PLAYER = 1,
 	ENT_AMBIENTSOUND,
 	ENT_SPRITE,
-	ENT_SPRAY
+	ENT_SPRAY,
+	ENT_DECAL
 };
 
 enum {
diff --git a/Source/Server/InfoDecal.c b/Source/Server/InfoDecal.c
new file mode 100644
index 00000000..16904063
--- /dev/null
+++ b/Source/Server/InfoDecal.c
@@ -0,0 +1,115 @@
+/*
+	Copyright 2016-2018 Marco "eukara" Hladik
+	
+	MIT LICENSE
+
+	Permission is hereby granted, free of charge, to any person 
+	obtaining a copy of this software and associated documentation 
+	files (the "Software"), to deal in the Software without 
+	restriction, including without limitation the rights to use,
+	copy, modify, merge, publish, distribute, sublicense, and/or
+	sell copies of the Software, and to permit persons to whom the
+	Software is furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be
+	included in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+	OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* decal name */
+.string texture;
+
+/* We need to save trace infos temporarily in order to figure out what to
+ * project the decal against. Half-Life's infodecal entity only stores origin,
+ * but not angles. So we have to figure them out ourselves. */
+typedef struct {
+	float fraction;
+	vector normal;
+	vector endpos;
+} traced_t;
+
+float infodecal_send(entity pvsent, float cflags)
+{
+	WriteByte(MSG_ENTITY, ENT_DECAL);
+	WriteCoord(MSG_ENTITY, self.origin[0]);
+	WriteCoord(MSG_ENTITY, self.origin[1]);
+	WriteCoord(MSG_ENTITY, self.origin[2]);
+	WriteCoord(MSG_ENTITY, self.angles[0]);
+	WriteCoord(MSG_ENTITY, self.angles[1]);
+	WriteCoord(MSG_ENTITY, self.angles[2]);
+	/* Figure this thing out */
+	WriteByte(MSG_ENTITY, 255);
+	WriteByte(MSG_ENTITY, 0);
+	WriteByte(MSG_ENTITY, 0);
+	WriteString(MSG_ENTITY, self.texture );
+	return TRUE;
+}
+
+void infodecal(void)
+{
+	traced_t tmp[6];
+	int i = 0;
+	int b = 0;
+	float frac = 1.0f;
+	vector vpos = self.origin;
+
+	/* Unrolled because I'm lazy */
+	makevectors([0, 0, 0]);
+	traceline(vpos + (v_forward * -1), vpos + (v_forward * 128), 1, self);
+	tmp[0].fraction = trace_fraction;
+	tmp[0].normal = trace_plane_normal;
+	tmp[0].endpos = trace_endpos;
+	traceline(vpos + (v_forward * 1), vpos + (v_forward * -128), 1, self);
+	tmp[1].fraction = trace_fraction;
+	tmp[1].normal = trace_plane_normal;
+	tmp[1].endpos = trace_endpos;
+	traceline(vpos + (v_right * -1), vpos + (v_right * 128), 1, self);
+	tmp[2].fraction = trace_fraction;
+	tmp[2].normal = trace_plane_normal;
+	tmp[2].endpos = trace_endpos;
+	traceline(vpos + (v_right * 1), vpos + (v_right * -128), 1, self);
+	tmp[3].fraction = trace_fraction;
+	tmp[3].normal = trace_plane_normal;
+	tmp[3].endpos = trace_endpos;
+	traceline(vpos + (v_up * -1), vpos + (v_up * 128), 1, self);
+	tmp[4].fraction = trace_fraction;
+	tmp[4].normal = trace_plane_normal;
+	tmp[4].endpos = trace_endpos;
+	traceline(vpos + (v_up * 1), vpos + (v_up * -128), 1, self);
+	tmp[5].fraction = trace_fraction;
+	tmp[5].normal = trace_plane_normal;
+	tmp[5].endpos = trace_endpos;
+
+	for (i = 0; i < 6; i++) {
+		if ( tmp[i].fraction < frac ) {
+			frac = tmp[i].fraction;
+			b = i;
+		}
+	}
+
+	if (frac == 1.0f) {
+		objerror(sprintf("infodecal tracing failed at %v\n", self.origin));
+		return;
+	}
+
+	makevectors(vectoangles(tmp[b].endpos - self.origin ));
+	vector cpl = v_forward - (v_forward * tmp[b].normal) * tmp[b].normal;
+
+	if (tmp[b].normal[2] == 0) {
+		cpl = [0, 0, 1];
+	}
+
+	self.angles = vectoangles(cpl, tmp[b].normal);
+	self.solid = SOLID_NOT;
+	self.pvsflags = PVSF_NOREMOVE | PVSF_IGNOREPVS;
+	self.SendEntity = infodecal_send;
+	self.SendFlags = 1;
+}
diff --git a/Source/Server/Player.c b/Source/Server/Player.c
index 68b3b12b..7d80e8f2 100755
--- a/Source/Server/Player.c
+++ b/Source/Server/Player.c
@@ -94,7 +94,7 @@ void Player_Death( int iHitBody ) {
 	setsize( eCorpse, self.mins, self.maxs );
 	eCorpse.angles = [ 0, self.angles_y, 0 ];
 	eCorpse.movetype = MOVETYPE_BOUNCE;
-	
+
 	// Drop primary weapon as well as the bomb if present
 	if ( self.fSlotPrimary ) {
 		Weapon_DropWeapon( SLOT_PRIMARY );
diff --git a/Source/Server/progs.src b/Source/Server/progs.src
index ec776e98..28dc4b11 100755
--- a/Source/Server/progs.src
+++ b/Source/Server/progs.src
@@ -69,6 +69,7 @@ FuncDoorRotating.c
 FuncVehicle.c
 ArmouryEntity.c
 AmbientSound.c
+InfoDecal.c
 
 
 Bot/Bot.h
diff --git a/Source/Shared/Effects.c b/Source/Shared/Effects.c
index 6da38fc8..deadf3d0 100755
--- a/Source/Shared/Effects.c
+++ b/Source/Shared/Effects.c
@@ -417,3 +417,12 @@ void Effect_BreakModel( vector vMins, vector vMaxs, vector vVel, float fStyle )
 	}
 #endif
 }
+
+#ifdef CSQC
+float Effect_Decal( void ) {
+	makevectors( self.angles );
+	adddecal( self.classname, self.origin, v_up / self.size[0], v_forward / self.size[1], self.color, 1.0f );
+	addentity( self );
+	return PREDRAW_NEXT;
+}
+#endif
diff --git a/freecs/csprogs.dat b/freecs/csprogs.dat
index f464e418..6cabe2fc 100644
Binary files a/freecs/csprogs.dat and b/freecs/csprogs.dat differ
diff --git a/freecs/default.cfg b/freecs/default.cfg
index d08293b9..401d2dab 100755
--- a/freecs/default.cfg
+++ b/freecs/default.cfg
@@ -75,7 +75,7 @@ seta sv_accelerate "8"
 seta con_textsize "12"
 seta con_color "255 170 0"
 seta vgui_color "255 170 0"
-seta cross_color 0 255 0
+seta cross_color "0 255 0"
 
 hostname "FreeCS Server"
 seta vid_conautoscale "1"
@@ -93,6 +93,7 @@ seta r_imageexensions "tga bmp pcx"
 seta gl_blacklist_debug_glsl 0
 seta vid_conautoscale "1"
 seta scr_conalpha "1"
+seta scr_sshot_type "tga"
 seta con_notifylines "0"
 seta con_logcenterprint "0"
 seta maxplayers "8"
diff --git a/freecs/menu.dat b/freecs/menu.dat
index a7ba655a..6fee065b 100755
Binary files a/freecs/menu.dat and b/freecs/menu.dat differ
diff --git a/freecs/progs.dat b/freecs/progs.dat
index 113cc5e4..83087fe9 100644
Binary files a/freecs/progs.dat and b/freecs/progs.dat differ