about summary refs log tree commit diff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/client/components/chat.cpp24
-rw-r--r--src/game/client/components/console.cpp18
-rw-r--r--src/game/client/components/menus.cpp2
-rw-r--r--src/game/client/components/menus_browser.cpp2
-rw-r--r--src/game/client/components/menus_ingame.cpp2
-rw-r--r--src/game/client/components/menus_settings.cpp51
-rw-r--r--src/game/client/components/voting.cpp10
-rw-r--r--src/game/client/gameclient.cpp4
-rw-r--r--src/game/client/render.cpp3
-rw-r--r--src/game/client/render_map.cpp5
-rw-r--r--src/game/editor/editor.cpp196
-rw-r--r--src/game/editor/editor.h4
-rw-r--r--src/game/editor/io.cpp2
-rw-r--r--src/game/editor/layer_quads.cpp5
-rw-r--r--src/game/editor/layer_tiles.cpp12
-rw-r--r--src/game/editor/popups.cpp1
-rw-r--r--src/game/server/entities/character.cpp7
-rw-r--r--src/game/server/entities/character.h1
-rw-r--r--src/game/server/gamecontext.cpp10
-rw-r--r--src/game/server/gamecontroller.cpp4
-rw-r--r--src/game/server/gamemodes/ctf.cpp2
-rw-r--r--src/game/server/player.cpp1
-rw-r--r--src/game/version.h4
23 files changed, 243 insertions, 127 deletions
diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp
index 340b9da1..f3370f94 100644
--- a/src/game/client/components/chat.cpp
+++ b/src/game/client/components/chat.cpp
@@ -112,13 +112,25 @@ bool CChat::OnInput(IInput::CEvent Event)
 	{
 		if(m_Input.GetString()[0])
 		{
+			bool AddEntry = false;
+
 			if(m_LastChatSend+time_freq() < time_get())
+			{
 				Say(m_Mode == MODE_ALL ? 0 : 1, m_Input.GetString());
-			else
+				AddEntry = true;
+			}
+			else if(m_PendingChatCounter < 3)
+			{
 				++m_PendingChatCounter;
-			CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry)+m_Input.GetLength());
-			pEntry->m_Team = m_Mode == MODE_ALL ? 0 : 1;
-			mem_copy(pEntry->m_aText, m_Input.GetString(), m_Input.GetLength()+1);
+				AddEntry = true;
+			}
+
+			if(AddEntry)
+			{
+				CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry)+m_Input.GetLength());
+				pEntry->m_Team = m_Mode == MODE_ALL ? 0 : 1;
+				mem_copy(pEntry->m_aText, m_Input.GetString(), m_Input.GetLength()+1);
+			}
 		}
 		m_pHistoryEntry = 0x0;
 		m_Mode = MODE_NONE;
@@ -265,9 +277,9 @@ void CChat::OnMessage(int MsgType, void *pRawMsg)
 
 void CChat::AddLine(int ClientID, int Team, const char *pLine)
 {
-	if(ClientID != -1 && (m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client
+	if(*pLine == 0 || (ClientID != -1 && (m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client
 		m_pClient->m_aClients[ClientID].m_ChatIgnore ||
-		(m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend)))
+		(m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend))))
 		return;
 
 	bool Highlighted = false;
diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp
index d16d56cd..01bf5351 100644
--- a/src/game/client/components/console.cpp
+++ b/src/game/client/components/console.cpp
@@ -434,12 +434,6 @@ void CGameConsole::OnRender()
 
 		x = Cursor.m_X;
 
-		// render console input (wrap line)
-		int Lines = TextRender()->TextLineCount(0, FontSize, pConsole->m_Input.GetString(), Screen.w - 10.0f - x);
-		y -= (Lines - 1) * FontSize;
-		TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
-		Cursor.m_LineWidth = Screen.w - 10.0f - x;
-
 		//hide rcon password
 		char aInputString[256];
 		str_copy(aInputString, pConsole->m_Input.GetString(), sizeof(aInputString));
@@ -449,10 +443,22 @@ void CGameConsole::OnRender()
 				aInputString[i] = '*';
 		}
 
+		// render console input (wrap line)
+		TextRender()->SetCursor(&Cursor, x, y, FontSize, 0);
+		Cursor.m_LineWidth = Screen.w - 10.0f - x;
+		TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset());
+		TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1);
+		int Lines = Cursor.m_LineCount;
+		
+		y -= (Lines - 1) * FontSize;
+		TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
+		Cursor.m_LineWidth = Screen.w - 10.0f - x;
+		
 		TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset());
 		static float MarkerOffset = TextRender()->TextWidth(0, FontSize, "|", -1)/3;
 		CTextCursor Marker = Cursor;
 		Marker.m_X -= MarkerOffset;
+		Marker.m_LineWidth = -1;
 		TextRender()->TextEx(&Marker, "|", -1);
 		TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1);
 
diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp
index d27307f4..8d0bdb16 100644
--- a/src/game/client/components/menus.cpp
+++ b/src/game/client/components/menus.cpp
@@ -1045,7 +1045,7 @@ int CMenus::Render()
 					}
 
 					// update download speed
-					float Diff = Client()->MapDownloadAmount()-m_DownloadLastCheckSize;
+					float Diff = (Client()->MapDownloadAmount()-m_DownloadLastCheckSize)/((int)((Now-m_DownloadLastCheckTime)/time_freq()));
 					float StartDiff = m_DownloadLastCheckSize-0.0f;
 					if(StartDiff+Diff > 0.0f)
 						m_DownloadSpeed = (Diff/(StartDiff+Diff))*(Diff/1.0f) + (StartDiff/(Diff+StartDiff))*m_DownloadSpeed;
diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp
index a9c434b3..b560b8cd 100644
--- a/src/game/client/components/menus_browser.cpp
+++ b/src/game/client/components/menus_browser.cpp
@@ -225,7 +225,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
 	{
 		int ItemIndex = i;
 		const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex);
-		NumPlayers += pItem->m_NumPlayers;
+		NumPlayers += g_Config.m_BrFilterSpectators ? pItem->m_NumPlayers : pItem->m_NumClients;
 		CUIRect Row;
 		CUIRect SelectHitBox;
 
diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp
index a9cf35e9..084520d9 100644
--- a/src/game/client/components/menus_ingame.cpp
+++ b/src/game/client/components/menus_ingame.cpp
@@ -183,7 +183,7 @@ void CMenus::RenderPlayers(CUIRect MainView)
 		ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
 		Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button);
 		Button.VSplitLeft(Button.h, &Button, 0);
-		if(&g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
+		if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
 			DoButton_Toggle(&s_aPlayerIDs[Index][0], 1, &Button, false);
 		else
 			if(DoButton_Toggle(&s_aPlayerIDs[Index][0], m_pClient->m_aClients[Index].m_ChatIgnore, &Button, true))
diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp
index 553195b1..b2434d91 100644
--- a/src/game/client/components/menus_settings.cpp
+++ b/src/game/client/components/menus_settings.cpp
@@ -613,11 +613,13 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
 	static int s_GfxScreenWidth = g_Config.m_GfxScreenWidth;
 	static int s_GfxScreenHeight = g_Config.m_GfxScreenHeight;
 	static int s_GfxColorDepth = g_Config.m_GfxColorDepth;
+	static int s_GfxBorderless = g_Config.m_GfxBorderless;
 	static int s_GfxFullscreen = g_Config.m_GfxFullscreen;
 	static int s_GfxVsync = g_Config.m_GfxVsync;
 	static int s_GfxFsaaSamples = g_Config.m_GfxFsaaSamples;
 	static int s_GfxTextureQuality = g_Config.m_GfxTextureQuality;
 	static int s_GfxTextureCompression = g_Config.m_GfxTextureCompression;
+	static int s_GfxThreaded = g_Config.m_GfxThreaded;
 
 	CUIRect ModeList;
 	MainView.VSplitLeft(300.0f, &MainView, &ModeList);
@@ -668,9 +670,20 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
 
 	// switches
 	MainView.HSplitTop(20.0f, &Button, &MainView);
+	if(DoButton_CheckBox(&g_Config.m_GfxBorderless, Localize("Borderless window"), g_Config.m_GfxBorderless, &Button))
+	{
+		g_Config.m_GfxBorderless ^= 1;
+		if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen)
+			g_Config.m_GfxFullscreen = 0;
+		CheckSettings = true;
+	}
+
+	MainView.HSplitTop(20.0f, &Button, &MainView);
 	if(DoButton_CheckBox(&g_Config.m_GfxFullscreen, Localize("Fullscreen"), g_Config.m_GfxFullscreen, &Button))
 	{
 		g_Config.m_GfxFullscreen ^= 1;
+		if(g_Config.m_GfxFullscreen && g_Config.m_GfxBorderless)
+			g_Config.m_GfxBorderless = 0;
 		CheckSettings = true;
 	}
 
@@ -687,8 +700,25 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
 		g_Config.m_GfxFsaaSamples = (g_Config.m_GfxFsaaSamples+1)%17;
 		CheckSettings = true;
 	}
+	
+	MainView.HSplitTop(20.0f, &Button, &MainView);
+	if(DoButton_CheckBox(&g_Config.m_GfxThreaded, Localize("Threaded rendering"), g_Config.m_GfxThreaded, &Button))
+	{
+		g_Config.m_GfxThreaded ^= 1;
+		CheckSettings = true;
+	}
 
-	MainView.HSplitTop(40.0f, &Button, &MainView);
+	MainView.HSplitTop(20.0f, &Button, &MainView);
+	if(g_Config.m_GfxThreaded)
+	{
+		Button.VSplitLeft(20.0f, 0, &Button);
+		if(DoButton_CheckBox(&g_Config.m_GfxAsyncRender, Localize("Handle rendering async from updates"), g_Config.m_GfxAsyncRender, &Button))
+		{
+			g_Config.m_GfxAsyncRender ^= 1;
+			CheckSettings = true;
+		}
+	}
+		
 	MainView.HSplitTop(20.0f, &Button, &MainView);
 	if(DoButton_CheckBox(&g_Config.m_GfxTextureQuality, Localize("Quality Textures"), g_Config.m_GfxTextureQuality, &Button))
 	{
@@ -713,11 +743,13 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
 		if(s_GfxScreenWidth == g_Config.m_GfxScreenWidth &&
 			s_GfxScreenHeight == g_Config.m_GfxScreenHeight &&
 			s_GfxColorDepth == g_Config.m_GfxColorDepth &&
+			s_GfxBorderless == g_Config.m_GfxBorderless &&
 			s_GfxFullscreen == g_Config.m_GfxFullscreen &&
 			s_GfxVsync == g_Config.m_GfxVsync &&
 			s_GfxFsaaSamples == g_Config.m_GfxFsaaSamples &&
 			s_GfxTextureQuality == g_Config.m_GfxTextureQuality &&
-			s_GfxTextureCompression == g_Config.m_GfxTextureCompression)
+			s_GfxTextureCompression == g_Config.m_GfxTextureCompression &&
+			s_GfxThreaded == g_Config.m_GfxThreaded)
 			m_NeedRestartGraphics = false;
 		else
 			m_NeedRestartGraphics = true;
@@ -781,16 +813,23 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
 	if(DoButton_CheckBox(&g_Config.m_SndMusic, Localize("Play background music"), g_Config.m_SndMusic, &Button))
 	{
 		g_Config.m_SndMusic ^= 1;
-		if(g_Config.m_SndMusic)
-			m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f);
-		else
-			m_pClient->m_pSounds->Stop(SOUND_MENU);
+		if(Client()->State() == IClient::STATE_OFFLINE)
+		{
+			if(g_Config.m_SndMusic)
+				m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f);
+			else
+				m_pClient->m_pSounds->Stop(SOUND_MENU);
+		}
 	}
 
 	MainView.HSplitTop(20.0f, &Button, &MainView);
 	if(DoButton_CheckBox(&g_Config.m_SndNonactiveMute, Localize("Mute when not active"), g_Config.m_SndNonactiveMute, &Button))
 		g_Config.m_SndNonactiveMute ^= 1;
 
+	MainView.HSplitTop(20.0f, &Button, &MainView);
+	if(DoButton_CheckBox(&g_Config.m_ClThreadsoundloading, Localize("Threaded sound loading"), g_Config.m_ClThreadsoundloading, &Button))
+		g_Config.m_ClThreadsoundloading ^= 1;
+
 	// sample rate box
 	{
 		char aBuf[64];
diff --git a/src/game/client/components/voting.cpp b/src/game/client/components/voting.cpp
index 675d6770..13dbc8a2 100644
--- a/src/game/client/components/voting.cpp
+++ b/src/game/client/components/voting.cpp
@@ -120,7 +120,12 @@ void CVoting::Vote(int v)
 CVoting::CVoting()
 {
 	ClearOptions();
-	OnReset();
+	
+	m_Closetime = 0;
+	m_aDescription[0] = 0;
+	m_aReason[0] = 0;
+	m_Yes = m_No = m_Pass = m_Total = 0;
+	m_Voted = 0;
 }
 
 void CVoting::AddOption(const char *pDescription)
@@ -164,6 +169,9 @@ void CVoting::ClearOptions()
 
 void CVoting::OnReset()
 {
+	if(Client()->State() == IClient::STATE_LOADING)	// do not reset active vote while connecting
+		return;
+
 	m_Closetime = 0;
 	m_aDescription[0] = 0;
 	m_aReason[0] = 0;
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index 86fb5ad0..f9b8b671 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -449,7 +449,7 @@ void CGameClient::OnRender()
 	m_NewPredictedTick = false;
 
 	// check if client info has to be resent
-	if(m_LastSendInfo && Client()->State() == IClient::STATE_ONLINE && m_Snap.m_LocalClientID >= 0 && !m_pMenus->IsActive() && m_LastSendInfo+time_freq()*5 < time_get())
+	if(m_LastSendInfo && Client()->State() == IClient::STATE_ONLINE && m_Snap.m_LocalClientID >= 0 && !m_pMenus->IsActive() && m_LastSendInfo+time_freq()*6 < time_get())
 	{
 		// resend if client info differs
 		if(str_comp(g_Config.m_PlayerName, m_aClients[m_Snap.m_LocalClientID].m_aName) ||
@@ -571,7 +571,7 @@ void CGameClient::OnEnterGame() {}
 
 void CGameClient::OnGameOver()
 {
-	if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
+	if(Client()->State() != IClient::STATE_DEMOPLAYBACK && g_Config.m_ClEditor == 0)
 		Client()->AutoScreenshot_Start();
 }
 
diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp
index 278ed51a..71589191 100644
--- a/src/game/client/render.cpp
+++ b/src/game/client/render.cpp
@@ -314,7 +314,7 @@ void CRenderTools::RenderTilemapGenerateSkip(class CLayers *pLayers)
 				CTile *pTiles = (CTile *)pLayers->Map()->GetData(pTmap->m_Data);
 				for(int y = 0; y < pTmap->m_Height; y++)
 				{
-					for(int x = 1; x < pTmap->m_Width; x++)
+					for(int x = 1; x < pTmap->m_Width;)
 					{
 						int sx;
 						for(sx = 1; x+sx < pTmap->m_Width && sx < 255; sx++)
@@ -324,6 +324,7 @@ void CRenderTools::RenderTilemapGenerateSkip(class CLayers *pLayers)
 						}
 
 						pTiles[y*pTmap->m_Width+x].m_Skip = sx-1;
+						x += sx;
 					}
 				}
 			}
diff --git a/src/game/client/render_map.cpp b/src/game/client/render_map.cpp
index 23fa42e0..a854b4a7 100644
--- a/src/game/client/render_map.cpp
+++ b/src/game/client/render_map.cpp
@@ -99,9 +99,10 @@ void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, ENV
 		}
 
 		bool Opaque = false;
+		/* TODO: Analyze quadtexture
 		if(a < 0.01f || (q->m_aColors[0].a < 0.01f && q->m_aColors[1].a < 0.01f && q->m_aColors[2].a < 0.01f && q->m_aColors[3].a < 0.01f))
 			Opaque = true;
-
+		*/
 		if(Opaque && !(RenderFlags&LAYERRENDERFLAG_OPAQUE))
 			continue;
 		if(!Opaque && !(RenderFlags&LAYERRENDERFLAG_TRANSPARENT))
@@ -236,7 +237,7 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4
 				unsigned char Flags = pTiles[c].m_Flags;
 
 				bool Render = false;
-				if(Flags&TILEFLAG_OPAQUE)
+				if(Flags&TILEFLAG_OPAQUE && Color.a*a > 254.0f/255.0f)
 				{
 					if(RenderFlags&LAYERRENDERFLAG_OPAQUE)
 						Render = true;
diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp
index fa1024e0..28a4eda9 100644
--- a/src/game/editor/editor.cpp
+++ b/src/game/editor/editor.cpp
@@ -37,6 +37,11 @@ enum
 CEditorImage::~CEditorImage()
 {
 	m_pEditor->Graphics()->UnloadTexture(m_TexID);
+	if(m_pData)
+	{
+		mem_free(m_pData);
+		m_pData = 0;
+	}
 }
 
 CLayerGroup::CLayerGroup()
@@ -1013,7 +1018,7 @@ void CEditor::DoToolbar(CUIRect ToolBar)
 	}
 }
 
-static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation)
+static void Rotate(const CPoint *pCenter, CPoint *pPoint, float Rotation)
 {
 	int x = pPoint->x - pCenter->x;
 	int y = pPoint->y - pCenter->y;
@@ -1403,99 +1408,126 @@ void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V)
 	Graphics()->QuadsDraw(&QuadItem, 1);
 }
 
-void CEditor::DoQuadEnvelopes(CQuad *pQuad, int Index, int TexID)
+void CEditor::DoQuadEnvelopes(const array<CQuad> &lQuads, int TexID)
 {
-	CEnvelope *pEnvelope = 0x0;
-	if(pQuad->m_PosEnv >= 0 && pQuad->m_PosEnv < m_Map.m_lEnvelopes.size())
-		pEnvelope = m_Map.m_lEnvelopes[pQuad->m_PosEnv];
-	if (!pEnvelope)
-		return;
-
-	//QuadParams
-	CPoint *pPoints = pQuad->m_aPoints;
+	int Num = lQuads.size();
+	CEnvelope **apEnvelope = new CEnvelope*[Num];
+	mem_zero(apEnvelope, sizeof(CEnvelope*)*Num);
+	for(int i = 0; i < Num; i++)
+	{
+		if((m_ShowEnvelopePreview == 1 && lQuads[i].m_PosEnv == m_SelectedEnvelope) || m_ShowEnvelopePreview == 2)
+			if(lQuads[i].m_PosEnv >= 0 && lQuads[i].m_PosEnv < m_Map.m_lEnvelopes.size())
+				apEnvelope[i] = m_Map.m_lEnvelopes[lQuads[i].m_PosEnv];
+	}
 
 	//Draw Lines
 	Graphics()->TextureSet(-1);
 	Graphics()->LinesBegin();
-		Graphics()->SetColor(80.0f/255, 150.0f/255, 230.f/255, 0.5f);
-		for(int i = 0; i < pEnvelope->m_lPoints.size()-1; i++)
+	Graphics()->SetColor(80.0f/255, 150.0f/255, 230.f/255, 0.5f);
+	for(int j = 0; j < Num; j++)
+	{
+		if(!apEnvelope[j])
+			continue;
+
+		//QuadParams
+		const CPoint *pPoints = lQuads[j].m_aPoints;
+		for(int i = 0; i < apEnvelope[j]->m_lPoints.size()-1; i++)
 		{
-			float OffsetX =  fx2f(pEnvelope->m_lPoints[i].m_aValues[0]);
-			float OffsetY = fx2f(pEnvelope->m_lPoints[i].m_aValues[1]);
+			float OffsetX =  fx2f(apEnvelope[j]->m_lPoints[i].m_aValues[0]);
+			float OffsetY = fx2f(apEnvelope[j]->m_lPoints[i].m_aValues[1]);
 			vec2 Pos0 = vec2(fx2f(pPoints[4].x)+OffsetX, fx2f(pPoints[4].y)+OffsetY);
 
-			OffsetX = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[0]);
-			OffsetY = fx2f(pEnvelope->m_lPoints[i+1].m_aValues[1]);
+			OffsetX = fx2f(apEnvelope[j]->m_lPoints[i+1].m_aValues[0]);
+			OffsetY = fx2f(apEnvelope[j]->m_lPoints[i+1].m_aValues[1]);
 			vec2 Pos1 = vec2(fx2f(pPoints[4].x)+OffsetX, fx2f(pPoints[4].y)+OffsetY);
 
 			IGraphics::CLineItem Line = IGraphics::CLineItem(Pos0.x, Pos0.y, Pos1.x, Pos1.y);
 			Graphics()->LinesDraw(&Line, 1);
 		}
-		Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+	}
+	Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
 	Graphics()->LinesEnd();
 
 	//Draw Quads
-	for(int i = 0; i < pEnvelope->m_lPoints.size(); i++)
+	Graphics()->TextureSet(TexID);
+	Graphics()->QuadsBegin();
+	
+	for(int j = 0; j < Num; j++)
 	{
-		Graphics()->TextureSet(TexID);
-		Graphics()->QuadsBegin();
-		
-		//Calc Env Position
-		float OffsetX =  fx2f(pEnvelope->m_lPoints[i].m_aValues[0]);
-		float OffsetY = fx2f(pEnvelope->m_lPoints[i].m_aValues[1]);
-		float Rot = fx2f(pEnvelope->m_lPoints[i].m_aValues[2])/360.0f*pi*2;
-
-		//Set Colours
-		float Alpha = (m_SelectedQuadEnvelope == pQuad->m_PosEnv && m_SelectedEnvelopePoint == i) ? 0.65f : 0.35f;
-		IGraphics::CColorVertex aArray[4] = {
-			IGraphics::CColorVertex(0, pQuad->m_aColors[0].r, pQuad->m_aColors[0].g, pQuad->m_aColors[0].b, Alpha),
-			IGraphics::CColorVertex(1, pQuad->m_aColors[1].r, pQuad->m_aColors[1].g, pQuad->m_aColors[1].b, Alpha),
-			IGraphics::CColorVertex(2, pQuad->m_aColors[2].r, pQuad->m_aColors[2].g, pQuad->m_aColors[2].b, Alpha),
-			IGraphics::CColorVertex(3, pQuad->m_aColors[3].r, pQuad->m_aColors[3].g, pQuad->m_aColors[3].b, Alpha)};
-		Graphics()->SetColorVertex(aArray, 4);
-
-		//Rotation
-		if(Rot != 0)
-		{
-			static CPoint aRotated[4];
-			aRotated[0] = pQuad->m_aPoints[0];
-			aRotated[1] = pQuad->m_aPoints[1];
-			aRotated[2] = pQuad->m_aPoints[2];
-			aRotated[3] = pQuad->m_aPoints[3];
-			pPoints = aRotated;
-
-			Rotate(&pQuad->m_aPoints[4], &aRotated[0], Rot);
-			Rotate(&pQuad->m_aPoints[4], &aRotated[1], Rot);
-			Rotate(&pQuad->m_aPoints[4], &aRotated[2], Rot);
-			Rotate(&pQuad->m_aPoints[4], &aRotated[3], Rot);
-		}
-
-		//Set Texture Coords
-		Graphics()->QuadsSetSubsetFree(
-			fx2f(pQuad->m_aTexcoords[0].x), fx2f(pQuad->m_aTexcoords[0].y),
-			fx2f(pQuad->m_aTexcoords[1].x), fx2f(pQuad->m_aTexcoords[1].y),
-			fx2f(pQuad->m_aTexcoords[2].x), fx2f(pQuad->m_aTexcoords[2].y),
-			fx2f(pQuad->m_aTexcoords[3].x), fx2f(pQuad->m_aTexcoords[3].y)
-		);
-
-		//Set Quad Coords & Draw
-		IGraphics::CFreeformItem Freeform(
-			fx2f(pPoints[0].x)+OffsetX, fx2f(pPoints[0].y)+OffsetY,
-			fx2f(pPoints[1].x)+OffsetX, fx2f(pPoints[1].y)+OffsetY,
-			fx2f(pPoints[2].x)+OffsetX, fx2f(pPoints[2].y)+OffsetY,
-			fx2f(pPoints[3].x)+OffsetX, fx2f(pPoints[3].y)+OffsetY);
-		Graphics()->QuadsDrawFreeform(&Freeform, 1);
+		if(!apEnvelope[j])
+			continue;
 
-		Graphics()->QuadsEnd();
-		
-		Graphics()->TextureSet(-1);
-		Graphics()->QuadsBegin();
-		DoQuadEnvPoint(pQuad, Index, i);
-		Graphics()->QuadsEnd();
+		//QuadParams
+		const CPoint *pPoints = lQuads[j].m_aPoints;
+
+		for(int i = 0; i < apEnvelope[j]->m_lPoints.size(); i++)
+		{
+			//Calc Env Position
+			float OffsetX =  fx2f(apEnvelope[j]->m_lPoints[i].m_aValues[0]);
+			float OffsetY = fx2f(apEnvelope[j]->m_lPoints[i].m_aValues[1]);
+			float Rot = fx2f(apEnvelope[j]->m_lPoints[i].m_aValues[2])/360.0f*pi*2;
+
+			//Set Colours
+			float Alpha = (m_SelectedQuadEnvelope == lQuads[j].m_PosEnv && m_SelectedEnvelopePoint == i) ? 0.65f : 0.35f;
+			IGraphics::CColorVertex aArray[4] = {
+				IGraphics::CColorVertex(0, lQuads[j].m_aColors[0].r, lQuads[j].m_aColors[0].g, lQuads[j].m_aColors[0].b, Alpha),
+				IGraphics::CColorVertex(1, lQuads[j].m_aColors[1].r, lQuads[j].m_aColors[1].g, lQuads[j].m_aColors[1].b, Alpha),
+				IGraphics::CColorVertex(2, lQuads[j].m_aColors[2].r, lQuads[j].m_aColors[2].g, lQuads[j].m_aColors[2].b, Alpha),
+				IGraphics::CColorVertex(3, lQuads[j].m_aColors[3].r, lQuads[j].m_aColors[3].g, lQuads[j].m_aColors[3].b, Alpha)};
+			Graphics()->SetColorVertex(aArray, 4);
+
+			//Rotation
+			if(Rot != 0)
+			{
+				static CPoint aRotated[4];
+				aRotated[0] = lQuads[j].m_aPoints[0];
+				aRotated[1] = lQuads[j].m_aPoints[1];
+				aRotated[2] = lQuads[j].m_aPoints[2];
+				aRotated[3] = lQuads[j].m_aPoints[3];
+				pPoints = aRotated;
+
+				Rotate(&lQuads[j].m_aPoints[4], &aRotated[0], Rot);
+				Rotate(&lQuads[j].m_aPoints[4], &aRotated[1], Rot);
+				Rotate(&lQuads[j].m_aPoints[4], &aRotated[2], Rot);
+				Rotate(&lQuads[j].m_aPoints[4], &aRotated[3], Rot);
+			}
+
+			//Set Texture Coords
+			Graphics()->QuadsSetSubsetFree(
+				fx2f(lQuads[j].m_aTexcoords[0].x), fx2f(lQuads[j].m_aTexcoords[0].y),
+				fx2f(lQuads[j].m_aTexcoords[1].x), fx2f(lQuads[j].m_aTexcoords[1].y),
+				fx2f(lQuads[j].m_aTexcoords[2].x), fx2f(lQuads[j].m_aTexcoords[2].y),
+				fx2f(lQuads[j].m_aTexcoords[3].x), fx2f(lQuads[j].m_aTexcoords[3].y)
+			);
+
+			//Set Quad Coords & Draw
+			IGraphics::CFreeformItem Freeform(
+				fx2f(pPoints[0].x)+OffsetX, fx2f(pPoints[0].y)+OffsetY,
+				fx2f(pPoints[1].x)+OffsetX, fx2f(pPoints[1].y)+OffsetY,
+				fx2f(pPoints[2].x)+OffsetX, fx2f(pPoints[2].y)+OffsetY,
+				fx2f(pPoints[3].x)+OffsetX, fx2f(pPoints[3].y)+OffsetY);
+			Graphics()->QuadsDrawFreeform(&Freeform, 1);
+		}
 	}
+	Graphics()->QuadsEnd();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+
+	// Draw QuadPoints
+	for(int j = 0; j < Num; j++)
+	{
+		if(!apEnvelope[j])
+			continue;
+
+		//QuadParams
+		for(int i = 0; i < apEnvelope[j]->m_lPoints.size()-1; i++)
+			DoQuadEnvPoint(&lQuads[j], j, i);
+	}
+	Graphics()->QuadsEnd();
+	delete[] apEnvelope;
 }
 
-void CEditor::DoQuadEnvPoint(CQuad *pQuad, int QIndex, int PIndex)
+void CEditor::DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int PIndex)
 {
 	enum
 	{
@@ -2088,12 +2120,7 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar)
 		if(pLayer->m_Image >= 0 && pLayer->m_Image < m_Map.m_lImages.size())
 			TexID = m_Map.m_lImages[pLayer->m_Image]->m_TexID;
 
-		for(int i = 0; i < pLayer->m_lQuads.size(); i++)
-		{
-			if((m_ShowEnvelopePreview == 1 && pLayer->m_lQuads[i].m_PosEnv == m_SelectedEnvelope) || m_ShowEnvelopePreview == 2)
-				DoQuadEnvelopes(&pLayer->m_lQuads[i], i, TexID);
-		}
-
+		DoQuadEnvelopes(pLayer->m_lQuads, TexID);
 		m_ShowEnvelopePreview = 0;
     }
 
@@ -2287,8 +2314,6 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN))
 					s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f);
 			}
-			else
-				ScrollNum = 0;
 		}
 	}
 
@@ -2423,11 +2448,17 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser)
 	CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage];
 	int External = pImg->m_External;
 	pEditor->Graphics()->UnloadTexture(pImg->m_TexID);
+	if(pImg->m_pData)
+	{
+		mem_free(pImg->m_pData);
+		pImg->m_pData = 0;
+	}
 	*pImg = ImgInfo;
 	pImg->m_External = External;
 	pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName));
 	pImg->m_AutoMapper.Load(pImg->m_aName);
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
+	ImgInfo.m_pData = 0;
 	pEditor->SortImages();
 	for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i)
 	{
@@ -2456,6 +2487,7 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
 	CEditorImage *pImg = new CEditorImage(pEditor);
 	*pImg = ImgInfo;
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
+	ImgInfo.m_pData = 0;
 	pImg->m_External = 1;	// external by default
 	str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName));
 	pImg->m_AutoMapper.Load(pImg->m_aName);
@@ -2603,8 +2635,6 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN))
 					s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f);
 			}
-			else
-				ScrollNum = 0;
 		}
 	}
 
diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h
index a81474d9..19a8752e 100644
--- a/src/game/editor/editor.h
+++ b/src/game/editor/editor.h
@@ -761,8 +761,8 @@ public:
 
 	vec4 ButtonColorMul(const void *pID);
 
-	void DoQuadEnvelopes(CQuad *pQuad, int Index, int TexID = -1);
-	void DoQuadEnvPoint(CQuad *pQuad, int QIndex, int pIndex);
+	void DoQuadEnvelopes(const array<CQuad> &m_lQuads, int TexID = -1);
+	void DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int pIndex);
 	void DoQuadPoint(CQuad *pQuad, int QuadIndex, int v);
 
 	void DoMapEditor(CUIRect View, CUIRect Toolbar);
diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp
index 463147e1..529638cf 100644
--- a/src/game/editor/io.cpp
+++ b/src/game/editor/io.cpp
@@ -391,6 +391,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
 	}
 
 	df.AddItem(MAPITEMTYPE_ENVPOINTS, 0, TotalSize, pPoints);
+	mem_free(pPoints);
 
 	// finish the data file
 	df.Finish();
@@ -479,6 +480,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 					{
 						*pImg = ImgInfo;
 						pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
+						ImgInfo.m_pData = 0;
 						pImg->m_External = 1;
 					}
 				}
diff --git a/src/game/editor/layer_quads.cpp b/src/game/editor/layer_quads.cpp
index d0b66405..321a28f8 100644
--- a/src/game/editor/layer_quads.cpp
+++ b/src/game/editor/layer_quads.cpp
@@ -27,7 +27,10 @@ void CLayerQuads::Render()
 	if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size())
 		Graphics()->TextureSet(m_pEditor->m_Map.m_lImages[m_Image]->m_TexID);
 
-	m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, m_pEditor->EnvelopeEval, m_pEditor);
+	Graphics()->BlendNone();
+	m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE, m_pEditor->EnvelopeEval, m_pEditor);
+	Graphics()->BlendNormal();
+	m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_TRANSPARENT, m_pEditor->EnvelopeEval, m_pEditor);
 }
 
 CQuad *CLayerQuads::NewQuad()
diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp
index 9a21e5ce..032f391f 100644
--- a/src/game/editor/layer_tiles.cpp
+++ b/src/game/editor/layer_tiles.cpp
@@ -64,7 +64,11 @@ void CLayerTiles::Render()
 		m_TexID = m_pEditor->m_Map.m_lImages[m_Image]->m_TexID;
 	Graphics()->TextureSet(m_TexID);
 	vec4 Color = vec4(m_Color.r/255.0f, m_Color.g/255.0f, m_Color.b/255.0f, m_Color.a/255.0f);
-	m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT,
+	Graphics()->BlendNone();
+	m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE,
+												m_pEditor->EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset);
+	Graphics()->BlendNormal();
+	m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_TRANSPARENT,
 												m_pEditor->EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset);
 }
 
@@ -334,6 +338,7 @@ void CLayerTiles::ShowInfo()
 	float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
 	Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
 	Graphics()->TextureSet(m_pEditor->Client()->GetDebugFont());
+	Graphics()->QuadsBegin();
 
 	int StartY = max(0, (int)(ScreenY0/32.0f)-1);
 	int StartX = max(0, (int)(ScreenX0/32.0f)-1);
@@ -348,17 +353,18 @@ void CLayerTiles::ShowInfo()
 			{
 				char aBuf[64];
 				str_format(aBuf, sizeof(aBuf), "%i", m_pTiles[c].m_Index);
-				m_pEditor->Graphics()->QuadsText(x*32, y*32, 16.0f, 1,1,1,1, aBuf);
+				m_pEditor->Graphics()->QuadsText(x*32, y*32, 16.0f, aBuf);
 
 				char aFlags[4] = {	m_pTiles[c].m_Flags&TILEFLAG_VFLIP ? 'V' : ' ',
 									m_pTiles[c].m_Flags&TILEFLAG_HFLIP ? 'H' : ' ',
 									m_pTiles[c].m_Flags&TILEFLAG_ROTATE? 'R' : ' ',
 									0};
-				m_pEditor->Graphics()->QuadsText(x*32, y*32+16, 16.0f, 1,1,1,1, aFlags);
+				m_pEditor->Graphics()->QuadsText(x*32, y*32+16, 16.0f, aFlags);
 			}
 			x += m_pTiles[c].m_Skip;
 		}
 
+	Graphics()->QuadsEnd();
 	Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
 }
 
diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp
index 2382823d..f281c6aa 100644
--- a/src/game/editor/popups.cpp
+++ b/src/game/editor/popups.cpp
@@ -554,7 +554,6 @@ int CEditor::PopupPoint(CEditor *pEditor, CUIRect View)
 		{
 			if(pEditor->m_SelectedPoints&(1<<v))
 			{
-				Color = 0;
 				pQuad->m_aColors[v].r = (NewVal>>24)&0xff;
 				pQuad->m_aColors[v].g = (NewVal>>16)&0xff;
 				pQuad->m_aColors[v].b = (NewVal>>8)&0xff;
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index dc70641a..d7da2498 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -79,6 +79,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
 	}
     /* end zCatch */
 	
+	m_LastNoAmmoSound = -1;
 	m_QueuedWeapon = -1;
 
 	m_pPlayer = pPlayer;
@@ -293,7 +294,11 @@ void CCharacter::FireWeapon()
 	{
 		// 125ms is a magical limit of how fast a human can click
 		m_ReloadTimer = 125 * Server()->TickSpeed() / 1000;
-		GameServer()->CreateSound(m_Pos, SOUND_WEAPON_NOAMMO);
+		if(m_LastNoAmmoSound+Server()->TickSpeed() <= Server()->Tick())
+		{
+			GameServer()->CreateSound(m_Pos, SOUND_WEAPON_NOAMMO);
+			m_LastNoAmmoSound = Server()->Tick();
+		}
 		return;
 	}
 
diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h
index dae01bd4..8bd1d3da 100644
--- a/src/game/server/entities/character.h
+++ b/src/game/server/entities/character.h
@@ -100,6 +100,7 @@ private:
 
 	// last tick that the player took any action ie some input
 	int m_LastAction;
+	int m_LastNoAmmoSound;
 
 	// these are non-heldback inputs
 	CNetObj_PlayerInput m_LatestPrevInput;
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index e08f1b44..66829db2 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -682,9 +682,12 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 
 	if(!pRawMsg)
 	{
-		char aBuf[256];
-		str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn());
-		Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
+		if(g_Config.m_Debug)
+		{
+			char aBuf[256];
+			str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn());
+			Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
+		}
 		return;
 	}
 
@@ -1076,7 +1079,6 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		{
 			OptionMsg.m_NumOptions = NumOptions;
 			Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID);
-			NumOptions = 0;
 		}
 
 		// send tuning parameters to client
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index 7001ca32..0ee250e8 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -281,8 +281,8 @@ void IGameController::CycleMap()
 		pNextMap = pMapRotation;
 
 	// cut out the next map
-	char aBuf[512];
-	for(int i = 0; i < 512; i++)
+	char aBuf[512] = {0};
+	for(int i = 0; i < 511; i++)
 	{
 		aBuf[i] = pNextMap[i];
 		if(IsSeparator(pNextMap[i]) || pNextMap[i] == 0)
diff --git a/src/game/server/gamemodes/ctf.cpp b/src/game/server/gamemodes/ctf.cpp
index 9e45c1fe..140dadf9 100644
--- a/src/game/server/gamemodes/ctf.cpp
+++ b/src/game/server/gamemodes/ctf.cpp
@@ -98,7 +98,7 @@ bool CGameControllerCTF::CanBeMovedOnBalance(int ClientID)
 		for(int fi = 0; fi < 2; fi++)
 		{
 			CFlag *F = m_apFlags[fi];
-			if(F->m_pCarryingCharacter == Character)
+			if(F && F->m_pCarryingCharacter == Character)
 				return false;
 		}
 	}
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index 993f9182..7e07c07f 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -289,6 +289,7 @@ void CPlayer::SetTeam(int Team, bool DoChatMsg)
 
 	m_Team = Team;
 	m_LastActionTick = Server()->Tick();
+	m_SpectatorID = SPEC_FREEVIEW;
 	// we got to wait 0.5 secs before respawning
 	m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
 	str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", m_ClientID, Server()->ClientName(m_ClientID), m_Team);
diff --git a/src/game/version.h b/src/game/version.h
index 3d909e36..76d95dd0 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -3,7 +3,7 @@
 #ifndef GAME_VERSION_H
 #define GAME_VERSION_H
 #include "generated/nethash.cpp"
-#define GAME_VERSION "0.6 trunk"
+#define GAME_VERSION "0.6.2"
 #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
-static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '1', 0};
+static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '.', '2', 0};
 #endif