Merge server stuff from alfadur
authorWuzzy <Wuzzy2@mail.ru>
Thu, 08 Mar 2018 21:05:10 +0100
changeset 13128 2f7c8e2ebe8e
parent 13127 a7b67247784d (diff)
parent 13119 1e39b8749072 (current diff)
child 13129 9a328734e469
Merge server stuff from alfadur
--- a/ChangeLog.txt	Thu Mar 08 15:01:18 2018 -0500
+++ b/ChangeLog.txt	Thu Mar 08 21:05:10 2018 +0100
@@ -54,6 +54,7 @@
  + Control: Always remove TimeBox and Resurrector
  * Battalion: Some texts in the mission panel were wrong and misleading
  * Construction Mode: Remove drill strike if added by weapon scheme (it's broken)
+ * Construction Mode, Racer, HedgeEditor: No longer play Incoming voice for building stuff, fix other sound problems
  * Capture the Flag: Fix many bugs caused by playing with >2 teams
  * Capture the Flag: Properly place flag when first hog uses kamikaze or TimeBox
  * Capture the Flag: Fix flag not being dropped when carrier uses piano strike
@@ -92,6 +93,8 @@
  + New call: SpawnSupplyCrate(x, y, content, [, amount]): Spawn ammo or utility crate, depending on content
  + New call: HealHog(gearUid, healthBoost[, showMessage[, tint]]): Heal hedgehog with graphical effects and message
  + New call: SetTeamLabel(teamname[, label]): Set an arbitrary label for a team, will be displayed next to the team bar
+ + New call: SetSoundMask(soundId, isMasked): Allows to disable playing a sound effect from engine
+ + New param: PlaySound accepts 3rd parameter for voices: instaVoice: If true, sound plays instantly instead of being queued
  + New callback: onEndTurn(): Called at the end of a turn (when gears have settled)
  + New hedgehog effect: heArtillery: Per-hedgehog artillery mode (can't walk). Values: 1 = permanently active. 2 = temporarily active (sniper rifle). 0 = not active
  * AddAmmo now automatically unselects weapon if it would remove current ammo from current hedgehog
--- a/hedgewars/uScript.pas	Thu Mar 08 15:01:18 2018 -0500
+++ b/hedgewars/uScript.pas	Thu Mar 08 21:05:10 2018 +0100
@@ -2048,29 +2048,57 @@
 function lc_playsound(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
     n, s: LongInt;
+    instaVoice: boolean;
 const
     call = 'PlaySound';
-    params = 'soundId [, hhGearUid]';
+    params = 'soundId [, hhGearUid [, instaVoice]]';
 begin
-    if CheckAndFetchParamCount(L, 1, 2, call, params, n) then
+    if CheckAndFetchParamCountRange(L, 1, 3, call, params, n) then
         begin
         s:= LuaToSoundOrd(L, 1, call, params);
         if s >= 0 then
             begin
             // no gear specified
             if n = 1 then
-                PlaySound(TSound(s))
+                PlaySound(TSound(s), false, true)
             else
                 begin
                 gear:= GearByUID(Trunc(lua_tonumber(L, 2)));
                 if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
-                    AddVoice(TSound(s),gear^.Hedgehog^.Team^.Voicepack)
+                    begin
+                    instaVoice:= false;
+                    if n = 3 then
+                        instaVoice:= lua_toboolean(L, 3);
+                    if instaVoice then
+                        PlaySoundV(TSound(s), gear^.Hedgehog^.Team^.Voicepack, false, true)
+                    else
+                        AddVoice(TSound(s), gear^.Hedgehog^.Team^.Voicepack, true);
+                    end;
                 end;
             end;
         end;
     lc_playsound:= 0;
 end;
 
+function lc_setsoundmask(L : Plua_State) : LongInt; Cdecl;
+var s: LongInt;
+    soundState: boolean;
+const
+    call = 'SetSoundMasked';
+    params = 'soundId, isMasked]';
+begin
+    if CheckLuaParamCount(L, 2, call, params) then
+        begin
+        s:= LuaToSoundOrd(L, 1, call, params);
+        if s <> Ord(sndNone) then
+            begin
+            soundState:= lua_toboolean(L, 2);
+            MaskedSounds[TSound(s)]:= soundState;
+            end;
+        end;
+    lc_setsoundmask:= 0;
+end;
+
 function lc_addteam(L : Plua_State) : LongInt; Cdecl;
 var np: LongInt;
 begin
@@ -3785,6 +3813,7 @@
 lua_register(luaState, _P'SetAmmo', @lc_setammo);
 lua_register(luaState, _P'SetAmmoDelay', @lc_setammodelay);
 lua_register(luaState, _P'PlaySound', @lc_playsound);
+lua_register(luaState, _P'SetSoundMask', @lc_setsoundmask);
 lua_register(luaState, _P'GetTeamName', @lc_getteamname);
 lua_register(luaState, _P'GetTeamIndex', @lc_getteamindex);
 lua_register(luaState, _P'GetTeamClan', @lc_getteamclan);
--- a/hedgewars/uSound.pas	Thu Mar 08 15:01:18 2018 -0500
+++ b/hedgewars/uSound.pas	Thu Mar 08 21:05:10 2018 +0100
@@ -63,8 +63,10 @@
 // then the sound's playback won't be interrupted if asked to play again.
 procedure PlaySound(snd: TSound);
 procedure PlaySound(snd: TSound; keepPlaying: boolean);
+procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean);
 
 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in.
 // Returns sound channel of the looped sound.
@@ -80,6 +82,7 @@
 procedure StopSoundChan(chn, fadems: LongInt);
 
 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
+procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
 procedure PlayNextVoice;
 
 
@@ -414,20 +417,30 @@
 
 procedure PlaySound(snd: TSound);
 begin
-    PlaySoundV(snd, nil, false);
+    PlaySoundV(snd, nil, false, false);
 end;
 
 procedure PlaySound(snd: TSound; keepPlaying: boolean);
 begin
-    PlaySoundV(snd, nil, keepPlaying);
+    PlaySoundV(snd, nil, keepPlaying, false);
+end;
+
+procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
+begin
+    PlaySoundV(snd, nil, keepPlaying, ignoreMask);
 end;
 
 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
 begin
-    PlaySoundV(snd, voicepack, false);
+    PlaySoundV(snd, voicepack, false, false);
 end;
 
 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+begin
+    PlaySoundV(snd, voicepack, keepPlaying, false);
+end;
+
+procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean);
 var s:shortstring;
 rwops: PSDL_RWops;
 begin
@@ -437,6 +450,9 @@
     if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
         exit;
 
+    if (ignoreMask = false) and (MaskedSounds[snd] = true) then
+        exit;
+
     if (voicepack <> nil) then
         begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
@@ -486,10 +502,19 @@
 end;
 
 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
+begin
+    AddVoice(snd, voicepack, false);
+end;
+
+procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
 var i : LongInt;
 begin
+
     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and  (LastVoice.voicepack = voicepack)) then
         exit;
+    if (ignoreMask = false) and (MaskedSounds[snd] = true) then
+        exit;
+
     if (snd = sndVictory) or (snd = sndFlawless) then
         begin
         Mix_FadeOutChannel(-1, 800);
--- a/hedgewars/uVariables.pas	Thu Mar 08 15:01:18 2018 -0500
+++ b/hedgewars/uVariables.pas	Thu Mar 08 21:05:10 2018 +0100
@@ -254,6 +254,8 @@
     LuaEndTurnRequested: boolean;
     LuaNoEndTurnTaunts: boolean;
 
+    MaskedSounds : array[TSound] of boolean;
+
     LastVoice : TVoice;
 
     mobileRecord: TMobileRecord;
@@ -2640,6 +2642,7 @@
 procedure initModule;
 var s: shortstring;
     i: integer;
+    t: TSound;
 begin
     // init LastVoice
     LastVoice.snd:= sndNone;
@@ -2901,6 +2904,9 @@
     LuaEndTurnRequested:= false;
     LuaNoEndTurnTaunts:= false;
 
+    for t:= Low(TSound) to High(TSound) do
+        MaskedSounds[t]:= false;
+
     UIDisplay:= uiAll;
     LocalMessage:= 0;
 
--- a/share/hedgewars/Data/Missions/Campaign/A_Classic_Fairytale/shadow.lua	Thu Mar 08 15:01:18 2018 -0500
+++ b/share/hedgewars/Data/Missions/Campaign/A_Classic_Fairytale/shadow.lua	Thu Mar 08 21:05:10 2018 +0100
@@ -616,7 +616,7 @@
 
   AddTeam(loc("Weaklings"), 14483456, "skull", "Island", "Pirate","cm_vampire")
   cannibals = {}
-  cannibals[1] = AddHog(loc("Brainiac"), 1, 20, "Zombi")
+  cannibals[1] = AddHog(loc("Brainiac"), 5, 20, "Zombi")
 
   for i = 2, 5 do
     cannibals[i] = AddHog(HogNames[i], 5, 20, "Zombi")
--- a/share/hedgewars/Data/Scripts/Multiplayer/Construction_Mode.lua	Thu Mar 08 15:01:18 2018 -0500
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Construction_Mode.lua	Thu Mar 08 21:05:10 2018 +0100
@@ -1081,6 +1081,9 @@
 			-- Pay the price
 			clanPower[GetHogClan(CurrentHedgehog)] = clanPower[GetHogClan(CurrentHedgehog)] - placedExpense
 			RenderClanPower()
+			if cat[cIndex] == "Girder Placement Mode" or cat[cIndex] == "Rubber Placement Mode" then
+				PlaySound(sndPlaced)
+			end
 		else
 			if IsHogLocal(CurrentHedgehog) then
 				AddCaption(loc("Invalid Placement"), colorMessageError, capgrpVolume)
@@ -1203,6 +1206,17 @@
 			updated = true
 		end
 
+		if curWep == amCMStructurePlacer or curWep == amCMCratePlacer or curWep == amCMObjectPlacer then
+			SetSoundMask(sndIncoming, true)
+		else
+			SetSoundMask(sndIncoming, false)
+		end
+		if curWep == amGirder or curWep == amRubber then
+			SetSoundMask(sndDenied, true)
+		else
+			SetSoundMask(sndDenied, false)
+		end
+
 		if updated then
 			AddCaption(loc(cat[cIndex]), GetClanColor(GetHogClan(CurrentHedgehog)), capgrpMessage)
 			showModeMessage()
Binary file share/hedgewars/Data/Scripts/Multiplayer/HedgeEditor.hwp has changed
--- a/share/hedgewars/Data/Scripts/Multiplayer/HedgeEditor.lua	Thu Mar 08 15:01:18 2018 -0500
+++ b/share/hedgewars/Data/Scripts/Multiplayer/HedgeEditor.lua	Thu Mar 08 21:05:10 2018 +0100
@@ -569,7 +569,7 @@
   sprTargetBee, sprAmGirder, sprAmRubber, sprIceTexture, sprHHTelepMask,
   sprAMAmmos, sprAMAmmosBW, sprAMSlot, sprAMCorners, sprTurnsLeft, sprBotlevels,
   sprSpeechCorner, sprSpeechEdge, sprSpeechTail, sprThoughtCorner, sprThoughtEdge, sprThoughtTail,
-  sprShoutCorner, sprShoutEdge, sprShoutTail, sprCustom1, sprCustom2, }
+  sprShoutCorner, sprShoutEdge, sprShoutTail, }
 
  -- Set in onGameInit
  local reducedSpriteIDArrayFrames
@@ -578,7 +578,7 @@
   "sprTargetBee", "sprAmGirder", "sprAmRubber", "sprIceTexture", "sprHHTelepMask",
   "sprAMAmmos", "sprAMAmmosBW", "sprAMSlot",  "sprAMCorners", "sprTurnsLeft", "sprBotlevels",
   "sprSpeechCorner", "sprSpeechEdge", "sprSpeechTail", "sprThoughtCorner", "sprThoughtEdge", "sprThoughtTail",
-  "sprShoutCorner", "sprShoutEdge", "sprShoutTail", "sprCustom1", "sprCustom2", }
+  "sprShoutCorner", "sprShoutEdge", "sprShoutTail", }
 
 ----------------------------
 -- placement shite
@@ -593,7 +593,8 @@
 local helpDisabled = false  --determines whether help popups pop up
 local CG = nil -- this is the visual gear displayed at CursorX, CursorY
 local crateSprite = nil-- this is a visual gear aid for crate placement
-local tSpr = {}
+local crateSpriteBorer = nil
+local waypointPreviewSprite = nil
 
 local cGear = nil -- detects placement of girders and objects (using airattack)
 local curWep = amNothing
@@ -654,6 +655,8 @@
 local closestGear = nil
 local closestSpriteID = nil
 
+local wpRadius = 450
+
 ------------------------
 -- SOME GENERAL METHODS
 ------------------------
@@ -902,8 +905,8 @@
 	placedSprite[placedCount] = vgtCircle
 	placedSpec[placedCount] = AddVisualGear(x,y,vgtCircle,0,true)
 	placedTint[placedCount] = 0xFF0000FF
-	placedFrame[placedCount] = 1										--rad is 450
-	SetVisualGearValues(placedSpec[placedCount], x, y, 164, 224, 1, 10, 0, 450, 5, placedTint[placedCount])
+	placedFrame[placedCount] = 1
+	SetVisualGearValues(placedSpec[placedCount], x, y, 164, 224, 1, 10, 0, wpRadius, 5, placedTint[placedCount])
 	placedCount = placedCount +1
 
 end
@@ -963,7 +966,11 @@
 
 end
 
-function CallPlaceSprite(pID)
+function CallPlaceSprite(pID, silent)
+
+	if silent == nil then
+		silent = false
+	end
 
 	if landType == lfIce then
 		placedLandFlags[pID] = "lfIce"
@@ -986,12 +993,22 @@
 		actualDisplayedImage = ammoFrameAirAttack
 	end
 
-	return PlaceSprite(placedX[pID], placedY[pID], placedSprite[pID], actualDisplayedImage,
+	local success = PlaceSprite(placedX[pID], placedY[pID], placedSprite[pID], actualDisplayedImage,
 		placedTint[pID],
 		nil, -- overrite existing land
 		nil, nil, -- this stuff specifies flipping
 		landType)
 
+	if not silent then
+		if success then
+			PlaySound(sndPlaced)
+		else
+			PlaySound(sndDenied)
+		end
+	end
+
+	return success
+
 end
 
 function SelectClosestSprite()
@@ -1030,6 +1047,8 @@
                     nil, -- flip sprite vertically
                     placedLandFlags[closestSpriteID])
 
+                PlaySound(sndBump)
+
 		placedX[closestSpriteID] = nil
 		placedY[closestSpriteID] = nil
 		placedSpec[closestSpriteID] = nil
@@ -1040,6 +1059,8 @@
 		placedLandFlags[closestSpriteID] = nil
 		closestSpriteID = nil
 		SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
+	else
+		PlaySound(sndDenied)
 	end
 end
 
@@ -1051,16 +1072,15 @@
 
 	for i = 0, (placedCount-1) do
 		if (placedType[i] == loc("Waypoint Editing Mode")) then
-				q = placedX[i] - placedX[placedCount]
-				w = placedY[i] - placedY[placedCount]
-				d = ( (q*q) + (w*w) )
-				if d < closestDist then
-					closestDist = d
-					closestSpriteID = i
-
-					SetVisualGearValues(sSprite, placedX[i], placedY[i], 0, 0, nil, placedFrame[i], 10000, placedSprite[i], 10000, newTint )
-
-				end
+			local q = placedX[i] - placedX[placedCount]
+			local w = placedY[i] - placedY[placedCount]
+			local d = ( (q*q) + (w*w) )
+			if d < closestDist then
+				closestDist = d
+				closestSpriteID = i
+
+				SetVisualGearValues(sSprite, placedX[i], placedY[i], 0, 0, nil, placedFrame[i], 10000, placedSprite[i], 10000, newTint )
+			end
 		end
 	end
 
@@ -1076,6 +1096,9 @@
 		placedLandFlags[closestSpriteID] = nil
 		closestSpriteID = nil
 		SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
+		PlaySound(sndBump)
+	else
+		PlaySound(sndDenied)
 	end
 end
 
@@ -1139,8 +1162,10 @@
 				elseif CGR == 2 then placedHWMapFlag[placedCount] = 126
 				elseif CGR == 3 then placedHWMapFlag[placedCount] = 127
 				end
+				PlaySound(sndPlaced)
 			else
 				placedType[placedCount] = "bogus"
+				PlaySound(sndDenied)
 			end
 		else
 			placedType[placedCount] = "bogus"
@@ -1184,18 +1209,25 @@
 
 		if pMode[pIndex] == loc("Selection Mode") then
 			sGear = GetClosestGear()
+			if sGear ~= nil then
+				PlaySound(sndPortalSwitch)
+			end
 		elseif pMode[pIndex] == loc("Placement Mode") then
 			if sGear ~= nil then
 				SetGearPosition(sGear, x, y)
+				PlaySound(sndWarp)
 			end
 		elseif pMode[pIndex] == loc("Deletion Mode") then
 			sGear = GetClosestGear()
 			if (sGear == nil) then
 				AddCaption(loc("Please click on a gear."), colorErrorMessage, capgrpVolume)
+				PlaySound(sndDenied)
 			elseif (GetGearType(sGear) == gtHedgehog) then
 				AddCaption(loc("Hedgehogs can not be deleted."), colorErrorMessage, capgrpVolume)
+				PlaySound(sndDenied)
 			else
 				DeleteGear(sGear)
+				PlaySound(sndBump)
 			end
 			sGear = nil
 		end
@@ -1209,8 +1241,10 @@
 			else -- set for the whole team
 				SetTeamIdentity(sGear)
 			end
+			PlaySound(sndHello, sGear)
 		else
 			AddCaption(loc("Please click on a hedgehog."), colorErrorMessage, capgrpVolume)
+			PlaySound(sndDenied)
 		end
 
 
@@ -1220,13 +1254,21 @@
 		sGear = GetClosestGear()
 		local gt = GetGearType(sGear)
 		if gt == gtHedgehog or gt == gtExplosives or (gt == gtCase and GetGearPos(sGear) == 0x2) then
+			local oldHealth, hDiff = GetHealth(sGear)
 			if pMode[pIndex][2] == "set" then
 				SetHealth(sGear, pMode[pIndex][1])
+				hDiff = pMode[pIndex][1] - oldHealth
 			elseif pMode[pIndex][2] == "mod" then
 				local min
 				if gt == gtCase then min = 0 else min = 1 end
 				local newHealth = math.max(min, GetHealth(sGear) + tonumber(pMode[pIndex][1]))
 				SetHealth(sGear, newHealth)
+				hDiff = newHealth - oldHealth
+			end
+			PlaySound(sndPortalSwitch)
+			if gt == gtHedgehog and hDiff < 0 then
+				local snd = { sndOw1, sndOw2, sndOw3 }
+				PlaySound(snd[math.random(1, #snd)], sGear)
 			end
 		elseif gt == gtMine and GetHealth(sGear) == 0 then
 			local newHealth 
@@ -1240,9 +1282,11 @@
 			end
 			if newHealth ~= nil then
 				SetGearValues(sGear, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 36 - newHealth)
+				PlaySound(sndPortalSwitch)
 			end
 		else
 			AddCaption(loc("Please click on a hedgehog, barrel, health crate or dud mine."), colorErrorMessage, capgrpVolume)
+			PlaySound(sndDenied)
 		end
 
 	elseif cat[cIndex] == loc("Sprite Modification Mode") then
@@ -1252,16 +1296,21 @@
 		if closestSpriteID ~= nil then
 			if pMode[pIndex] == loc("LandFlag Modification Mode") then
 				EraseSprite(placedX[closestSpriteID], placedY[closestSpriteID], placedSprite[closestSpriteID], placedFrame[closestSpriteID], nil, nil, nil, nil, placedLandFlags[closestSpriteID])
-				placementSucceeded = CallPlaceSprite(closestSpriteID)
+				placementSucceeded = CallPlaceSprite(closestSpriteID, true)
 				if placementSucceeded then
 					closestSpriteID = nil
 					SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
+					PlaySound(sndPortalSwitch)
+				else
+					PlaySound(sndDenied)
 				end
 			elseif pMode[pIndex] == loc("Sprite Erasure Mode") then
 
 				EraseClosestSprite()
 
 			end
+		else
+			PlaySound(sndDenied)
 		end
 
 
@@ -1275,14 +1324,18 @@
 				if pMode[pIndex] == loc("Victory Condition: Collect") then
 					if GetGearType(sGear) == gtCase then
 						setGearValue(sGear, "tag","collection")
+						PlaySound(sndPortalSwitch)
 					else
 						AddCaption(loc("Please click on a crate."), colorErrorMessage, capgrpVolume)
+						PlaySound(sndDenied)
 					end
 				else
 					if pMode[pIndex] == loc("Victory Condition: Destroy") then
 						setGearValue(sGear, "tag","victory")
+						PlaySound(sndPortalSwitch)
 					elseif pMode[pIndex] == loc("Losing Condition: Destroy") then
 						setGearValue(sGear, "tag","failure")
+						PlaySound(sndPortalSwitch)
 					end
 				end
 
@@ -1291,6 +1344,7 @@
 				setGearValue(sGear, "tag", nil)
 				DeleteVisualGear(getGearValue(sGear,"tCirc"))
 				setGearValue(sGear, "tCirc", nil)
+				PlaySound(sndBump)
 			end
 
 
@@ -1304,9 +1358,6 @@
 			placedFrame[placedCount] = sFrame
 			placedSprite[placedCount] = reducedSpriteIDArray[pIndex]
 			placementSucceeded = CallPlaceSprite(placedCount)
-			if placementSucceeded then
-				PlaySound(sndPlaced)
-			end
 		else
 			placedType[placedCount] = "bogus"
 			SelectClosestSprite()
@@ -2850,7 +2901,6 @@
 
 		genTimer = genTimer + 1
 
-
 		tSprCol = 0x00000000
 		tempFrame = 0
 		xDisplacement = 42
@@ -2858,19 +2908,18 @@
 
 		if (curWep == amCMGearPlacementTool) then
 
+			SetSoundMask(sndIncoming, true)
+
 			--wowaweewa, holyeeeee shite this is badly hacked (please rewrite when less lazy/morefeatures)
 			dCol = 0xFFFFFFFF
 			dFrame = 0
 			dAngle = 0
 			if (cat[cIndex] == loc("Mine Placement Mode")) then
-				dSprite = sprBotlevels--sprMineOff
-				dFrame = 1
+				dSprite = sprCustom2
 			elseif (cat[cIndex] == loc("Dud Mine Placement Mode")) then
-				dSprite = sprBotlevels--sprMineDead
-				dFrame = 3
+				dSprite = sprCustom4
 			elseif (cat[cIndex] == loc("Sticky Mine Placement Mode")) then
-				dSprite = sprBotlevels--sprSMineOff
-				dFrame = 2
+				dSprite = sprCustom3
 			elseif (cat[cIndex] == loc("Air Mine Placement Mode")) then
 				dSprite = sprAirMine
 			elseif (cat[cIndex] == loc("Barrel Placement Mode")) then
@@ -2907,9 +2956,7 @@
 
 			if crateSprite == nil then
 				crateSprite = AddVisualGear(CursorX, CursorY-35, vgtStraightShot,0,true,3)
-				for i = 1, 4 do
-					tSpr[i] = AddVisualGear(CursorX, CursorY-35, vgtStraightShot,0,true,3)
-				end
+				crateSpriteBorder = AddVisualGear(CursorX, CursorY-35, vgtStraightShot,0,true,3)
 			end
 
 
@@ -2931,18 +2978,29 @@
 				end
 			end
 
+			-- Waypoint outline
+			if (cat[cIndex] == loc("Waypoint Editing Mode")) and (pMode[pIndex] == loc("Place Waypoint")) then
+				if not waypointPreviewSprite then
+					waypointPreviewSprite = AddVisualGear(CursorX, CursorY, vgtCircle, 1, true)
+					SetVisualGearValues(waypointPreviewSprite, CursorX, CursorY, 244, 224, 0, 0, 0, wpRadius/5, 5, 0xFF0000FF)
+				end
+			elseif waypointPreviewSprite then
+				DeleteVisualGear(waypointPreviewSprite)
+				waypointPreviewSprite = nil
+			end
+			if waypointPreviewSprite then
+				SetVisualGearValues(waypointPreviewSprite, CursorX, CursorY)
+			end
+
 		else
+			SetSoundMask(sndIncoming, false)
 			if CG ~= nil then
 				SetVisualGearValues(CG, 0, 0, 0, 0, 0, 0, 1000, sprArrow, 1000, 0xFFFFFF00)
 			end
 		end
 
 		SetVisualGearValues(crateSprite, CursorX+xDisplacement, CursorY+yDisplacement, 0, 0, dAngle, tempFrame, 1000, sprAMAmmos, 1000, tSprCol)
-		SetVisualGearValues(tSpr[1], CursorX+xDisplacement-2, CursorY+yDisplacement-2, 0, 0, dAngle, 1, 1000, sprTarget, 1000, tSprCol)
-		SetVisualGearValues(tSpr[2], CursorX+xDisplacement-2, CursorY+yDisplacement+2, 0, 0, dAngle, 1, 1000, sprTarget, 1000, tSprCol)
-		SetVisualGearValues(tSpr[3], CursorX+xDisplacement+2, CursorY+yDisplacement-2, 0, 0, dAngle, 1, 1000, sprTarget, 1000, tSprCol)
-		SetVisualGearValues(tSpr[4], CursorX+xDisplacement+2, CursorY+yDisplacement+2, 0, 0, dAngle, 1, 1000, sprTarget, 1000, tSprCol)
-
+		SetVisualGearValues(crateSpriteBorder, CursorX+xDisplacement, CursorY+yDisplacement, 0, 0, 0, 0, 1000, sprCustom1, 1000, tSprCol)
 
 		if genTimer >= 100 then
 
@@ -2971,6 +3029,12 @@
 				RedefineSubset()
 			end
 
+			if curWep == amGirder or curWep == amRubber then
+				SetSoundMask(sndDenied, true)
+			else
+				SetSoundMask(sndDenied, false)
+			end
+
 			-- update display selection criteria
 			if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMGearPlacementTool) then
 				AddCaption(cat[cIndex], colorPlaceMode1, capgrpMessage)
--- a/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Thu Mar 08 15:01:18 2018 -0500
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Thu Mar 08 21:05:10 2018 +0100
@@ -666,6 +666,9 @@
         SendHealthStatsOff()
 	SendAchievementsStatsOff()
 
+        SetSoundMask(sndIncoming, true)
+        SetSoundMask(sndMissed, true)
+
         roundN = 0
         lastRound = TotalRounds
         RoundHasChanged = false
@@ -735,6 +738,7 @@
 
             if placedByUser then
                 AddCaption(string.format(loc("Waypoint placed. Available points remaining: %d"), wpLimit-wpCount))
+                PlaySound(sndPlaced)
             end
         end
     end