Engine:
authorsmxx
Thu, 04 Feb 2010 14:48:49 +0000
changeset 2745 11fce231f24a
parent 2744 803d0142594e
child 2746 55593f8a490b
Engine: + Split PlaySound into PlaySound and LoopSound + Added overloaded versions of PlaySound/LoopSound that won't require voicepack parameter + LoopSound now allows multiple copies of the same sound to play looped and returns the channel used for playback (to stop them later) + StopSound now allows either a specific sound (single playback) or channel (single playback as well as looped playback) to be stopped + SoundChannel attribute for Gears to be used when looping sounds
hedgewars/GSHandlers.inc
hedgewars/HHHandlers.inc
hedgewars/uGears.pas
hedgewars/uMisc.pas
hedgewars/uSound.pas
hedgewars/uStats.pas
hedgewars/uTeams.pas
--- a/hedgewars/GSHandlers.inc	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/GSHandlers.inc	Thu Feb 04 14:48:49 2010 +0000
@@ -27,15 +27,15 @@
 		if (d > 1) and (gi^.Kind = gtHedgehog) and not gi^.Invulnerable and (GetRandom(2) = 0) then
 			begin
 			if (CurrentHedgehog^.Gear = gi) then
-				PlaySound(sndOops, false, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
+				PlaySound(sndOops, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
 			else
 				begin
 				if (gi^.State and gstMoving) = 0 then
 					gi^.State:= gi^.State or gstLoser;
 				if d > r div 2 then
-					PlaySound(sndNooo, false, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
+					PlaySound(sndNooo, PHedgehog(gi^.Hedgehog)^.Team^.voicepack)
 				else
-					PlaySound(sndUhOh, false, PHedgehog(gi^.Hedgehog)^.Team^.voicepack);
+					PlaySound(sndUhOh, PHedgehog(gi^.Hedgehog)^.Team^.voicepack);
 				end;
 			end;
 		gi:= gi^.NextGear
@@ -74,7 +74,7 @@
 			AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage);
 			end
         end;
-    PlaySound(sndSplash, false, nil)
+    PlaySound(sndSplash)
     end
     else
 	CheckGearDrowning:= false
@@ -97,9 +97,9 @@
     if dmg < 1 then exit;
 
 	if _0_6 < Gear^.dY then
-		PlaySound(sndOw4, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
+		PlaySound(sndOw4, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
 	else
-		PlaySound(sndOw1, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+		PlaySound(sndOw1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
 
     ApplyDamage(Gear, dmg);
 	end
@@ -240,7 +240,7 @@
 
 if Gear^.Kind = gtHellishBomb then
 	begin
-	if Gear^.Timer = 3000 then PlaySound(sndHellish, false, nil);
+	if Gear^.Timer = 3000 then PlaySound(sndHellish);
 
 	if (GameTicks and $3F) = 0 then
 		if (Gear^.State and gstCollision) = 0 then
@@ -250,7 +250,7 @@
 if (Gear^.State and (gstCollision or gstMoving)) = (gstCollision or gstMoving) then
 	if (hwAbs(Gear^.dX) > _0_1) or
 	   (hwAbs(Gear^.dY) > _0_1) then
-		PlaySound(sndGrenadeImpact, false, nil)
+		PlaySound(sndGrenadeImpact)
 end;
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepMolotov(Gear: PGear);
@@ -264,7 +264,7 @@
 	CalcRotationDirAngle(Gear);
 
 	if (Gear^.State and gstCollision) <> 0 then begin
-		PlaySound(sndMolotov, false, nil);
+		PlaySound(sndMolotov);
 		//doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 5, EXPLAutoSound);
 		for i:= 0 to 20 do begin
 				dX:= AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandom + _1);
@@ -382,7 +382,7 @@
          begin
          Gear^.Active:= false;
          exit
-         end else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact, false, nil)
+         end else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact)
       end;
 
 Gear^.Y:= Gear^.Y + Gear^.dY;
@@ -416,7 +416,7 @@
 dec(Gear^.Timer);
 if ((Gear^.State and gstCollision) <> 0) or (Gear^.Timer = 0) then
    begin
-   StopSound(sndUFO);
+   StopSound(Gear^.SoundChannel);
    doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
    DeleteGear(Gear);
    end;
@@ -438,7 +438,7 @@
 dec(Gear^.Timer);
 if Gear^.Timer = 0 then
    begin
-   PlaySound(sndUFO, true, nil);
+   Gear^.SoundChannel:= LoopSound(sndUFO);
    Gear^.Timer:= 5000;
    Gear^.doStep:= @doStepUFOWork
    end;
@@ -466,7 +466,7 @@
 	dec(Gear^.Timer);
 	if Gear^.Timer = 0 then
 		begin
-		PlaySound(sndShotgunFire, false, nil);
+		PlaySound(sndShotgunFire);
 		Gear^.State:= Gear^.State or gstAnimation
 		end;
 	exit
@@ -536,7 +536,7 @@
 
 procedure doStepDEagleShot(Gear: PGear);
 begin
-PlaySound(sndGun, false, nil);
+PlaySound(sndGun);
 Gear^.doStep:= @doStepBulletWork
 end;
 
@@ -559,7 +559,7 @@
 	Gear^.State:= Gear^.State or gstAnimation;
     Gear^.dX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
     Gear^.dY:= -AngleCos(HHGear^.Angle) * _0_5;
-    PlaySound(sndGun, false, nil);
+    PlaySound(sndGun);
     Gear^.doStep:= @doStepBulletWork;
     end
 else
@@ -621,7 +621,7 @@
 dec(Gear^.Timer);
 if (Gear^.Timer = 0)or((Gear^.Message and gm_Destroy) <> 0)or((HHGear^.State and gstHHDriven) = 0) then
 	begin
-	StopSound(sndPickhammer);
+	StopSound(Gear^.SoundChannel);
 	DeleteGear(Gear);
 	AfterAttack;
 	exit
@@ -696,7 +696,7 @@
 Gear^.dY:= HHGear^.dY;
 DeleteCI(HHGear);
 
-PlaySound(sndPickhammer, true, nil);
+Gear^.SoundChannel:= LoopSound(sndPickhammer);
 doStepPickHammerWork(Gear);
 Gear^.doStep:= @doStepPickHammerWork
 end;
@@ -1173,7 +1173,7 @@
 		end else // gstAttacking <> 0
 		begin
 		AllInactive:= false;
-		if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick, false, nil);
+		if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
 		if Gear^.Timer = 0 then
 			begin
 			doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
@@ -1243,7 +1243,7 @@
 		begin
 		Gear^.dY:= - Gear^.dY * Gear^.Elasticity;
 		if Gear^.dY > - _0_001 then Gear^.dY:= _0
-			else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact, false, nil);
+			else if Gear^.dY < - _0_03 then PlaySound(sndGraveImpact);
 		end;
 	CheckGearDrowning(Gear);
 	end;
@@ -1257,7 +1257,7 @@
 procedure doStepTarget(Gear: PGear);
 begin
 if (Gear^.Timer = 0) and (Gear^.Tag = 0) then
-	PlaySound(sndWarp, false, nil);
+	PlaySound(sndWarp);
 
 if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
 	inc(Gear^.Timer)
@@ -1360,7 +1360,7 @@
 		begin
 		for i:= 0 to 3 do
 			AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 16 + Random(16), vgtSteam);
-		PlaySound(sndVaporize, false, nil);
+		PlaySound(sndVaporize);
 		DeleteGear(Gear);
 		exit
 		end
@@ -1474,7 +1474,7 @@
 Gear^.doStep:= @doStepFirePunchWork;
 DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
 
-PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), false, PHedgehog(HHGear^.Hedgehog)^.Team^.voicepack)
+PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), PHedgehog(HHGear^.Hedgehog)^.Team^.voicepack)
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1624,7 +1624,7 @@
                       TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
                       sprAmGirder, Gear^.State, true) then
 	begin
-    PlaySound(sndDenied, false, nil);
+    PlaySound(sndDenied);
 	HHGear^.Message:= HHGear^.Message and not gm_Attack;
 	HHGear^.State:= HHGear^.State and not gstAttacking;
 	HHGear^.State:= HHGear^.State or gstHHChooseTarget;
@@ -1632,7 +1632,7 @@
 	DeleteGear(Gear)
 	end
 else begin
-    PlaySound(sndPlaced, false, nil);
+    PlaySound(sndPlaced);
 	DeleteGear(Gear);
     OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
     ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^)
@@ -1685,7 +1685,7 @@
 		HHGear^.State:= HHGear^.State or gstHHChooseTarget;
 		DeleteGear(Gear);
 		isCursorVisible:= true;
-		PlaySound(sndDenied, false, nil);
+		PlaySound(sndDenied)
 		end
 	else begin
 		DeleteCI(HHGear);
@@ -1696,7 +1696,7 @@
 		HHGear^.X:= int2hwFloat(TargetPoint.X);
 		HHGear^.Y:= int2hwFloat(TargetPoint.Y);
 		HHGear^.State:= HHGear^.State or gstMoving;
-		playSound(sndWarp, false, nil);
+		playSound(sndWarp)
 		end;
 TargetPoint.X:= NoPointX;
 
@@ -1735,7 +1735,7 @@
 	RemoveGearFromList(HHGear);
 	InsertGearToList(HHGear);
 
-	PlaySound(sndSwitchHog, false, nil);
+	PlaySound(sndSwitchHog);
 	
 	repeat
 		CurrentTeam^.CurrHedgehog:= Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
@@ -1864,7 +1864,7 @@
 if Gear^.Timer = 0 then
 	begin
 	Gear^.Pos:= 1;
-	PlaySound(sndKamikaze, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+	PlaySound(sndKamikaze, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
 	Gear^.doStep:= @doStepKamikazeWork
 	end
 end;
@@ -1929,7 +1929,7 @@
 		gi:= gi^.NextGear
 		end;
 	Gear^.doStep:= @doStepCakeExpl;
-	PlaySound(sndCake, false, nil)
+	PlaySound(sndCake)
 	end else dec(Gear^.Pos)
 end;
 
@@ -2096,7 +2096,7 @@
 	Gear^.Timer:= 0;
 	inc(Gear^.Pos);
 	if Gear^.Pos = 5 then
-		PlaySound(sndYoohoo, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
+		PlaySound(sndYoohoo, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
 	end;
 
 if Gear^.Pos = 14 then
@@ -2151,7 +2151,7 @@
 	DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 2, 6);
     if(CheckGearDrowning(Gear)) then
         begin
-        StopSound(sndPickhammer);
+        StopSound(Gear^.SoundChannel);
 	    exit
         end
 	end;
@@ -2163,7 +2163,7 @@
 and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))
 or (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] = COLOR_INDESTRUCTIBLE) then
 	begin //out of time or exited ground
-    StopSound(sndPickhammer);
+    StopSound(Gear^.SoundChannel);
 	doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
 	DeleteGear(Gear);
 	exit
@@ -2203,7 +2203,7 @@
 		exit;
 		end;
 
-    PlaySound(sndPickhammer, true, nil);
+    Gear^.SoundChannel:= LoopSound(sndPickhammer);
 	Gear^.doStep:= @doStepDrillDrilling;
 	dec(Gear^.Timer)
 	end
@@ -2228,7 +2228,7 @@
 				AngleCos(HHGear^.Angle) * ( - _0_8) + ry,
 				0);
 
-		PlaySound(sndGun, false, nil);
+		PlaySound(sndGun);
 		end;
 
 	if (Gear^.Timer = 0) or (HHGear^.Damage <> 0) then
@@ -2323,7 +2323,7 @@
 		begin
 		Gear^.State:= Gear^.State or gsttmpFlag;
 		PauseMusic;
-		playSound(sndRideOfTheValkyries, false, nil);
+		playSound(sndRideOfTheValkyries);
 		end;
 
 	// pickup bonuses
@@ -2342,7 +2342,7 @@
 		begin
 		if t^.Tag <> 0 then // collect it only once
 			exit;
-		PlaySound(sndShotgunReload, false, nil);
+		PlaySound(sndShotgunReload);
 		t^.Tag:= 1;
 		TrainingTargetGear:= nil; // remove target cursor
 		exit;
@@ -2358,7 +2358,7 @@
 	or CheckGearDrowning(Gear) then
 	begin
 	if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (TimeTrialStopTime = 0) then TimeTrialStopTime:= RealTicks;
-	StopSound(sndRCPlane);
+	StopSound(Gear^.SoundChannel);
 	StopSound(sndRideOfTheValkyries);
 	ResumeMusic;
 
--- a/hedgewars/HHHandlers.inc	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/HHHandlers.inc	Thu Feb 04 14:48:49 2010 +0000
@@ -120,7 +120,7 @@
              if Power = 0 then
                 begin
                 AttackBar:= CurrentTeam^.AttackBar;
-                PlaySound(sndThrowPowerUp, false, nil)
+                PlaySound(sndThrowPowerUp)
                 end;
              inc(Power)
              end;
@@ -129,7 +129,7 @@
         if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Power) <> 0 then
            begin
            StopSound(sndThrowPowerUp);
-           PlaySound(sndThrowRelease, false, nil);
+           PlaySound(sndThrowRelease);
            end;
 
         xx:= SignAs(AngleSin(Angle), dX);
@@ -137,7 +137,7 @@
 
         if ((Gear^.State and gstHHHJump) <> 0) then xx:= - xx;
         if Ammo^[CurSlot, CurAmmo].AttackVoice <> sndNone then
-           PlaySound(Ammo^[CurSlot, CurAmmo].AttackVoice, false, CurrentTeam^.voicepack);
+           PlaySound(Ammo^[CurSlot, CurAmmo].AttackVoice, CurrentTeam^.voicepack);
              case Ammo^[CurSlot, CurAmmo].AmmoType of
                       amGrenade: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtAmmo_Bomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
                       amMolotov: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtMolotov,      0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
@@ -145,7 +145,7 @@
                       amBazooka: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtAmmo_Grenade, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                           amUFO: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtUFO,          0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                       amShotgun: begin
-                                 PlaySound(sndShotgunReload, false, nil);
+                                 PlaySound(sndShotgunReload);
                                  CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtShotgunShot,  0, xx * _0_5, yy * _0_5, 0);
                                  end;
                    amPickHammer: CurAmmoGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius, gtPickHammer, 0, _0, _0, 0);
@@ -158,11 +158,11 @@
                     amFirePunch: CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 10, hwRound(Y), gtFirePunch, 0, xx, _0, 0);
                          amWhip: begin
                                  CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 10, hwRound(Y), gtWhip, 0, SignAs(_1, dX), - _0_8, 0);
-                                 PlaySound(sndWhipCrack, false, nil)
+                                 PlaySound(sndWhipCrack)
                                  end;
                   amBaseballBat: begin
 								 CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 10, hwRound(Y), gtShover, gsttmpFlag, xx * _0_5, yy * _0_5, 0);
-								 PlaySound(sndBaseballBat, false, nil);
+								 PlaySound(sndBaseballBat)
 								 end;
                     amParachute: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtParachute, 0, _0, _0, 0);
                     amAirAttack: AddGear(Ammo^[CurSlot, CurAmmo].Pos, 0, gtAirAttack, 0, _0, _0, 0);
@@ -172,12 +172,12 @@
                      amTeleport: CurAmmoGear:= AddGear(0, 0, gtTeleport, 0, _0, _0, 0);
                        amSwitch: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtSwitcher, 0, _0, _0, 0);
                        amMortar: begin
-				playSound(sndMortar, false, nil);
+				playSound(sndMortar);
 				FollowGear:= AddGear(hwRound(X), hwRound(Y), gtMortar,  0, xx*cMaxPower/cPowerDivisor, yy*cMaxPower/cPowerDivisor, 0);
 				 end;
                       amRCPlane: begin
                                  CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtRCPlane,  0, xx * cMaxPower / cPowerDivisor / 4, yy * cMaxPower / cPowerDivisor / 4, 0);
-                                 PlaySound(sndRCPlane, true, nil)
+                                 CurAmmoGear^.SoundChannel:= LoopSound(sndRCPlane, nil)
                                  end;
                        amKamikaze: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
                          amCake: CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 3, hwRound(Y), gtCake, 0, xx, _0, 0);
@@ -288,7 +288,7 @@
 	Gear^.Z:= cCurrHHZ;
 	RemoveGearFromList(Gear);
 	InsertGearToList(Gear);
-	PlaySound(sndByeBye, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+	PlaySound(sndByeBye, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
 	Gear^.Pos:= 0;
 	Gear^.Timer:= timertime
 	end
@@ -301,7 +301,7 @@
 	i: Integer;
 begin
 Gear^.Message:= gm_Destroy;
-PlaySound(sndShotgunReload, false, nil);
+PlaySound(sndShotgunReload);
 case Gear^.Pos of
        posCaseUtility,
        posCaseAmmo: begin
@@ -376,7 +376,7 @@
          Gear^.dY:= -_0_15;
          if not cArtillery then Gear^.dX:= SignAs(_0_15, Gear^.dX);
          Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
-         PlaySound(sndJump1, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+         PlaySound(sndJump1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
          exit
          end;
       end;
@@ -389,7 +389,7 @@
       Gear^.dY:= -_0_2;
       SetLittle(Gear^.dX);
       Gear^.State:= Gear^.State or gstMoving or gstHHJumping;
-      PlaySound(sndJump3, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+      PlaySound(sndJump3, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
       exit
       end;
 
@@ -563,7 +563,7 @@
 	if Gear^.FlightTime = 2000 then
 		begin
 		AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
-		PlaySound(sndHomerun, false, nil)
+		PlaySound(sndHomerun)
 		end;
 	end
 else
@@ -596,7 +596,7 @@
 if (Gear^.State and gstAnimation) <> 0 then
 	begin
 	Gear^.Message:= 0;
-	if (Gear^.Pos = Wavez[TWave(Gear^.Tag)].VoiceDelay) and (Gear^.Timer = 0) then PlaySound(Wavez[TWave(Gear^.Tag)].Voice, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+	if (Gear^.Pos = Wavez[TWave(Gear^.Tag)].VoiceDelay) and (Gear^.Timer = 0) then PlaySound(Wavez[TWave(Gear^.Tag)].Voice, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
 	inc(Gear^.Timer);
 	if Gear^.Timer = Wavez[TWave(Gear^.Tag)].Interval then
 		begin
@@ -671,7 +671,7 @@
 			Gear^.State:= Gear^.State or gstHHHJump;
 			Gear^.dY:= -_0_25;
 			if not cArtillery then Gear^.dX:= -SignAs(_0_02, Gear^.dX);
-			PlaySound(sndJump2, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
+			PlaySound(sndJump2, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
 			end;
 
 	Gear^.Message:= Gear^.Message and not (gm_LJump or gm_HJump);
--- a/hedgewars/uGears.pas	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/uGears.pas	Thu Feb 04 14:48:49 2010 +0000
@@ -56,7 +56,8 @@
 			IntersectGear: PGear;
 			TriggerId: Longword;
 			FlightTime: Longword;
-			uid: Longword
+			uid: Longword;
+			SoundChannel: LongInt
 		end;
 
 var AllInactive: boolean;
@@ -235,6 +236,7 @@
 gear^.Z:= cUsualZ;
 gear^.FlightTime:= 0;
 gear^.uid:= Counter;
+gear^.SoundChannel:= -1;
 
 if CurrentTeam <> nil then
 	begin
@@ -613,7 +615,7 @@
 				begin
 				cHealthDecrease:= 5;
 				AddCaption(trmsg[sidSuddenDeath], cWhiteColor, capgrpGameState);
-				playSound(sndSuddenDeath, false, nil);
+				playSound(sndSuddenDeath)
 				end;
 
 			if (cHealthDecrease = 0)
@@ -665,7 +667,7 @@
 				if (TurnTimeLeft = 5000)
 					and (CurrentHedgehog^.Gear <> nil)
 					and ((CurrentHedgehog^.Gear^.State and gstAttacked) = 0) then
-						PlaySound(sndHurry, false, CurrentTeam^.voicepack);
+						PlaySound(sndHurry, CurrentTeam^.voicepack);
 				dec(TurnTimeLeft)
 				end;
 
@@ -1603,7 +1605,7 @@
 TargetPoint.X:= NoPointX;
 {$IFDEF DEBUGFILE}if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');{$ENDIF}
 if (Radius > 10) then AddGear(X, Y, gtExplosion, 0, _0, _0, 0);
-if (Mask and EXPLAutoSound) <> 0 then PlaySound(sndExplosion, false, nil);
+if (Mask and EXPLAutoSound) <> 0 then PlaySound(sndExplosion);
 
 if (Mask and EXPLAllDamageInRadius) = 0 then
 	dmgRadius:= Radius shl 1
@@ -1965,7 +1967,7 @@
 	FindPlace(FollowGear, true, 0, LAND_WIDTH);
 
 	if (FollowGear <> nil) then
-		PlaySound(sndReinforce, false, CurrentTeam^.voicepack)
+		PlaySound(sndReinforce, CurrentTeam^.voicepack)
 	end
 end;
 
--- a/hedgewars/uMisc.pas	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/uMisc.pas	Thu Feb 04 14:48:49 2010 +0000
@@ -521,7 +521,7 @@
 	);
 {$ENDIF}
 begin
-playSound(sndShutter, false, nil);
+playSound(sndShutter);
 
 size:= cScreenWidth * cScreenHeight * 3;
 p:= GetMem(size);
--- a/hedgewars/uSound.pas	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/uSound.pas	Thu Feb 04 14:48:49 2010 +0000
@@ -36,12 +36,15 @@
 procedure InitSound;
 procedure ReleaseSound;
 procedure SoundLoad;
-procedure PlaySound(snd: TSound; infinite: boolean; voicepack: PVoicepack);
-procedure LoopSound(snd: TSound; voicepack: PVoicepack);
+procedure PlaySound(snd: TSound);
+procedure PlaySound(snd: TSound; voicepack: PVoicepack);
+function LoopSound(snd: TSound): LongInt;
+function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
 procedure PlayMusic;
 procedure PauseMusic;
 procedure ResumeMusic;
 procedure StopSound(snd: TSound);
+procedure StopSound(chn: LongInt);
 function  ChangeVolume(voldelta: LongInt): LongInt;
 function  AskForVoicepack(name: shortstring): Pointer;
 
@@ -152,28 +155,34 @@
 {$ENDIF}	
 end;
 
-procedure PlaySound(snd: TSound; infinite: boolean; voicepack: PVoicepack);
-var loops: LongInt;
+procedure PlaySound(snd: TSound);
+begin
+	PlaySound(snd, nil);
+end;
+
+procedure PlaySound(snd: TSound; voicepack: PVoicepack);
 begin
 if (not isSoundEnabled) or fastUntilLag then exit;
-if infinite and (lastChan[snd] <> -1) then exit;
-if infinite then loops:= -1 else loops:= 0;
 
 if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
-	lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], loops, -1)
+	lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
 else
-	lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], loops, -1)
+	lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
 end;
 
-procedure LoopSound(snd: TSound; voicepack: PVoicepack);
+function LoopSound(snd: TSound): LongInt;
+begin
+	LoopSound:= LoopSound(snd, nil)
+end;
+
+function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
 begin
 if (not isSoundEnabled) or fastUntilLag then exit;
-if lastChan[snd] <> -1 then exit;
 
 if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
-	lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
+	LoopSound:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
 else
-	lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1)
+	LoopSound:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1)
 end;
 
 procedure StopSound(snd: TSound);
@@ -186,6 +195,11 @@
 	end;
 end;
 
+procedure StopSound(chn: LongInt);
+begin
+	if (chn <> -1) and (Mix_Playing(chn) <> 0) then Mix_HaltChannel(chn);
+end;
+
 procedure PlayMusic;
 var s: string;
 begin
--- a/hedgewars/uStats.pas	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/uStats.pas	Thu Feb 04 14:48:49 2010 +0000
@@ -107,41 +107,41 @@
 	inc(CurrentHedgehog^.stats.FinishedTurns);
 
 	if (DamageGiven = DamageTotal) and (DamageTotal > 0) then
-		PlaySound(sndFirstBlood, false, CurrentTeam^.voicepack)
+		PlaySound(sndFirstBlood, CurrentTeam^.voicepack)
 
 	else if CurrentHedgehog^.stats.StepDamageRecv > 0 then
 		begin
-		PlaySound(sndStupid, false, PreviousTeam^.voicepack);
+		PlaySound(sndStupid, PreviousTeam^.voicepack);
 		if DamageGiven = CurrentHedgehog^.stats.StepDamageRecv then AddCaption(Format(GetEventString(eidHurtSelf), CurrentHedgehog^.Name), cWhiteColor, capgrpMessage);
 		end
 	else if DamageClan <> 0 then
 		if DamageTotal > DamageClan then
 			if random(2) = 0 then
-				PlaySound(sndNutter, false, CurrentTeam^.voicepack)
+				PlaySound(sndNutter, CurrentTeam^.voicepack)
 			else
-				PlaySound(sndWatchIt, false, vpHurtSameClan)
+				PlaySound(sndWatchIt, vpHurtSameClan)
 		else
 			if random(2) = 0 then
-				PlaySound(sndSameTeam, false, vpHurtSameClan)
+				PlaySound(sndSameTeam, vpHurtSameClan)
 			else
-				PlaySound(sndTraitor, false, vpHurtSameClan)
+				PlaySound(sndTraitor, vpHurtSameClan)
 	else if DamageGiven <> 0 then
 		if Kills > 0 then
-			PlaySound(sndEnemyDown, false, CurrentTeam^.voicepack)
+			PlaySound(sndEnemyDown, CurrentTeam^.voicepack)
 		else
-			PlaySound(sndRegret, false, vpHurtEnemy)
+			PlaySound(sndRegret, vpHurtEnemy)
 
 	else if AmmoDamagingUsed then
-		PlaySound(sndMissed, false, PreviousTeam^.voicepack)
+		PlaySound(sndMissed, PreviousTeam^.voicepack)
 	else if (AmmoUsedCount > 0) and not isTurnSkipped then
 		// nothing ?
 	else if isTurnSkipped then
 		begin
-		PlaySound(sndBoring, false, PreviousTeam^.voicepack);
+		PlaySound(sndBoring, PreviousTeam^.voicepack);
 		AddCaption(Format(GetEventString(eidTurnSkipped), CurrentHedgehog^.Name), cWhiteColor, capgrpMessage);
 		end
 	else
-		PlaySound(sndCoward, false, PreviousTeam^.voicepack);
+		PlaySound(sndCoward, PreviousTeam^.voicepack);
 	end;
 
 
--- a/hedgewars/uTeams.pas	Thu Feb 04 14:35:31 2010 +0000
+++ b/hedgewars/uTeams.pas	Thu Feb 04 14:48:49 2010 +0000
@@ -242,9 +242,9 @@
 bShowFinger:= true;
 
 if (CurrentTeam^.ExtDriven or (CurrentHedgehog^.BotLevel > 0)) then
-	PlaySound(sndIllGetYou, false, CurrentTeam^.voicepack)
+	PlaySound(sndIllGetYou, CurrentTeam^.voicepack)
 else
-	PlaySound(sndYesSir, false, CurrentTeam^.voicepack);
+	PlaySound(sndYesSir, CurrentTeam^.voicepack);
 
 TurnTimeLeft:= cHedgehogTurnTime
 end;