Smaxx patch with tuning by me:
authorunc0rr
Sun, 29 Nov 2009 16:56:04 +0000
changeset 2647 0e1208e92dfe
parent 2646 6a1185633872
child 2648 415a75d45693
Smaxx patch with tuning by me: - hogs might worry/panic if they're next to explosives (grenade, dynamite, etc.) - play sndVaporice for each fire extinguished only once (not 3 times) - allow "on attack" voices/sounds for weapons (similar to water melon bomb) - allow one voice/sound to be played during emotes - print protocol version in version info (console) - rope sounds (disabled atm) - landscape background - optimized/rewrote explosion drawing - fixed "StopSound" called with an inactive sound to stop some random sound - disabled npott
hedgewars/GSHandlers.inc
hedgewars/HHHandlers.inc
hedgewars/hwengine.pas
hedgewars/tunsetborder.inc
hedgewars/uConsts.pas
hedgewars/uLand.pas
hedgewars/uLandGraphics.pas
hedgewars/uLandObjects.pas
hedgewars/uMisc.pas
hedgewars/uSound.pas
hedgewars/uStore.pas
--- a/hedgewars/GSHandlers.inc	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/GSHandlers.inc	Sun Nov 29 16:56:04 2009 +0000
@@ -16,6 +16,32 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *)
 
+procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
+var gi: PGear;
+     d: LongInt;
+begin
+	gi:= GearsList;
+	while gi <> nil do
+		begin
+		d:= r - hwRound(Distance(gi^.X - x, gi^.Y - y));
+		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)
+			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)
+				else
+					PlaySound(sndUhOh, false, PHedgehog(gi^.Hedgehog)^.Team^.voicepack);
+				end;
+			end;
+		gi:= gi^.NextGear
+		end;
+end;
+////////////////////////////////////////////////////////////////////////////////
 procedure doStepDrowningGear(Gear: PGear); forward;
 
 function CheckGearDrowning(Gear: PGear): boolean;
@@ -161,6 +187,13 @@
 doStepFallingGear(Gear);
 
 dec(Gear^.Timer);
+if Gear^.Timer = 1000 then // might need adjustments
+	case Gear^.Kind of
+		gtAmmo_Bomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
+		gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
+		gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
+		gtHellishBomb: makeHogsWorry(Gear^.X, Gear^.Y, 90);
+	end;
 if Gear^.Timer = 0 then
 	begin
 	case Gear^.Kind of
@@ -251,7 +284,6 @@
 procedure doStepWatermelon(Gear: PGear);
 begin
 AllInactive:= false;
-PlaySound(sndMelon, false, nil);
 Gear^.doStep:= @doStepBomb
 end;
 
@@ -1157,6 +1189,8 @@
 doStepFallingGear(Gear);
 AllInactive:= false;
 if Gear^.Timer mod 166 = 0 then inc(Gear^.Tag);
+if Gear^.Timer = 1000 then // might need better timing
+	makeHogsWorry(Gear^.X, Gear^.Y, 75);
 if Gear^.Timer = 0 then
 	begin
 	doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
@@ -1323,10 +1357,8 @@
 	if (hwRound(Gear^.Y) > cWaterLine) then
 		begin
 		for i:= 0 to 3 do
-			begin
 			AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 16 + Random(16), vgtSteam);
-			PlaySound(sndVaporize, false, nil);
-			end;
+		PlaySound(sndVaporize, false, nil);
 		DeleteGear(Gear);
 		exit
 		end
@@ -1529,7 +1561,6 @@
 
 Gear^.Health:= 6;
 Gear^.doStep:= @doStepAirAttackWork;
-PlaySound(sndIncoming, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2422,6 +2453,7 @@
 	end
 end;
 
+////////////////////////////////////////////////////////////////////////////////
 procedure doStepJetpack(Gear: PGear);
 var HHGear: PGear;
 begin
--- a/hedgewars/HHHandlers.inc	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/HHHandlers.inc	Sun Nov 29 16:56:04 2009 +0000
@@ -136,6 +136,8 @@
         yy:= -AngleCos(Angle);
 
         if ((Gear^.State and gstHHHJump) <> 0) then xx:= - xx;
+        if Ammo^[CurSlot, CurAmmo].AttackVoice <> sndNone then
+           PlaySound(Ammo^[CurSlot, CurAmmo].AttackVoice, false, 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);
@@ -149,16 +151,10 @@
                    amPickHammer: CurAmmoGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius, gtPickHammer, 0, _0, _0, 0);
                          amSkip: ParseCommand('/skip', true);
                          amRope: CurAmmoGear:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtRope, 0, xx, yy, 0);
-                         amMine: begin
-                                 AddGear(hwRound(X) + hwSign(dX) * 7, hwRound(Y), gtMine, 0, SignAs(_0_02, dX), _0, 3000);
-                                 PlaySound(sndLaugh, false, CurrentTeam^.voicepack)
-                                 end;
+                         amMine: AddGear(hwRound(X) + hwSign(dX) * 7, hwRound(Y), gtMine, 0, SignAs(_0_02, dX), _0, 3000);
                        amDEagle: CurAmmoGear:= AddGear(hwRound(X + xx * cHHRadius), hwRound(Y + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
                   amSniperRifle: CurAmmoGear:= AddGear(hwRound(X + xx * cHHRadius), hwRound(Y + yy * cHHRadius), gtSniperRifleShot, 0, xx * _0_5, yy * _0_5, 0);
-                     amDynamite: begin
-                                 AddGear(hwRound(X) + hwSign(dX) * 7, hwRound(Y), gtDynamite, 0, SignAs(_0_03, dX), _0, 5000);
-                                 PlaySound(sndLaugh, false, CurrentTeam^.voicepack)
-                                 end;
+                     amDynamite: AddGear(hwRound(X) + hwSign(dX) * 7, hwRound(Y), gtDynamite, 0, SignAs(_0_03, dX), _0, 5000);
                     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);
@@ -184,10 +180,7 @@
                                  PlaySound(sndRCPlane, true, nil)
                                  end;
                        amKamikaze: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
-                         amCake: begin
-                                 CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 3, hwRound(Y), gtCake, 0, xx, _0, 0);
-                                 PlaySound(sndLaugh, false, CurrentTeam^.voicepack)
-                                 end;
+                         amCake: CurAmmoGear:= AddGear(hwRound(X) + hwSign(dX) * 3, hwRound(Y), gtCake, 0, xx, _0, 0);
                     amSeduction: CurAmmoGear:= AddGear(hwRound(X + xx * cHHRadius * 2), hwRound(Y + yy * cHHRadius * 2), gtSeduction, 0, xx * _0_4, yy * _0_4, 0);
                    amWatermelon: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtWatermelon,  0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
                   amHellishBomb: FollowGear:= AddGear(hwRound(X), hwRound(Y), gtHellishBomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
@@ -603,6 +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);
 	inc(Gear^.Timer);
 	if Gear^.Timer = Wavez[TWave(Gear^.Tag)].Interval then
 		begin
--- a/hedgewars/hwengine.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/hwengine.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -627,7 +627,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 begin
-WriteLnToConsole('Hedgewars ' + cVersionString + ' engine');
+WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (' + inttostr(cNetProtoVersion) + ')');
 GetParams;
 // FIXME -  hack in font with support for CJK
 if (cLocaleFName = 'zh_CN.txt') or (cLocaleFName = 'zh_TW.txt') or (cLocaleFName = 'ja.txt') then
--- a/hedgewars/tunsetborder.inc	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/tunsetborder.inc	Sun Nov 29 16:56:04 2009 +0000
@@ -16,12 +16,12 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *)
 
-        begin
-        X:= X + dX;
-        Y:= Y + dY;
-        tx:= hwRound(X);
-        ty:= hwRound(Y);
-        if ((ty and LAND_HEIGHT_MASK) = 0) and
-           ((tx and LAND_WIDTH_MASK) = 0) and
-           (Land[ty, tx] = COLOR_LAND) then LandPixels[ty, tx]:= cExplosionBorderColor
-	end;
+begin
+X:= X + dX;
+Y:= Y + dY;
+tx:= hwRound(X);
+ty:= hwRound(Y);
+if ((ty and LAND_HEIGHT_MASK) = 0) and
+    ((tx and LAND_WIDTH_MASK) = 0) and
+    ((Land[ty, tx] = COLOR_LAND) or (Land[ty, tx] = COLOR_OBJECT)) then LandPixels[ty, tx]:= cExplosionBorderColor
+end;
--- a/hedgewars/uConsts.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uConsts.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -84,7 +84,8 @@
 
 	TGearsType = set of TGearType;
 
-	TSound = (sndGrenadeImpact, sndExplosion, sndThrowPowerUp, sndThrowRelease,
+	TSound = (sndNone,
+			sndGrenadeImpact, sndExplosion, sndThrowPowerUp, sndThrowRelease,
 			sndSplash, sndShotgunReload, sndShotgunFire, sndGraveImpact,
 			sndMineTick, sndPickhammer, sndGun, sndUFO, sndJump1, sndJump2,
 			sndJump3, sndYesSir, sndLaugh, sndIllGetYou, sndIncoming,
@@ -96,7 +97,9 @@
 			sndMelon, sndHellish, sndYoohoo, sndRCPlane, sndWhipCrack,
 			sndRideOfTheValkyries, sndDenied, sndPlaced, sndBaseballBat,
 			sndVaporize, sndWarp, sndSuddenDeath, sndMortar, sndShutter,
-			sndHomerun, sndMolotov);
+			sndHomerun, sndMolotov, sndWalking, sndCover, sndUhOh,
+			sndOops, sndNooo, sndHello, sndRopeShot, sndRopeAttach,
+			sndRopeRelease);
 
 	TAmmoType  = (amNothing, amGrenade, amClusterBomb, amBazooka, amUFO, amShotgun, amPickHammer,
 			amSkip, amRope, amMine, amDEagle, amDynamite, amFirePunch, amWhip,
@@ -131,6 +134,7 @@
 			Timer: LongWord;
 			Pos: LongWord;
 			AmmoType: TAmmoType;
+			AttackVoice: TSound;
 			end;
 
 	TVertex2f = record
@@ -201,6 +205,7 @@
 
 	COLOR_LAND           = $FFFF;  // white
 	COLOR_INDESTRUCTIBLE = $88FF;  // red
+	COLOR_OBJECT         = $44FF;  // no idea
 
 	// some opengl headers do not have these macros
 	GL_BGR  = $80E0;
@@ -337,7 +342,7 @@
 	htHealth      = $04;
 	htTransparent = $80;
 	
-	cTagsMasks       : array[0..7] of byte = (
+	cTagsMasks : array[0..7] of byte = (
 				htTeamName or htName or htHealth,
 				htName or htHealth,
 				htHealth,
@@ -643,20 +648,23 @@
 			FramesCount: Longword;
 			Interval: Longword;
 			cmd: String[20];
+			Voice: TSound;
+			VoiceDelay: ShortInt;
 			end = (
-			(Sprite:   sprKowtow; FramesCount: 12; Interval: 125; cmd: '/rollup'),
-			(Sprite:      sprSad; FramesCount: 14; Interval: 125; cmd: '/sad'),
-			(Sprite:     sprWave; FramesCount: 16; Interval: 125; cmd: '/wave'),
-			(Sprite:   sprHurrah; FramesCount: 14; Interval: 125; cmd: '/hurrah'),
-			(Sprite: sprLemonade; FramesCount: 24; Interval: 125; cmd: '/ilovelotsoflemonade'),
-			(Sprite:    sprShrug; FramesCount: 24; Interval: 125; cmd: '/shrug'),
-			(Sprite:   sprJuggle; FramesCount: 49; Interval:  38; cmd: '/juggle')
+			(Sprite:   sprKowtow; FramesCount: 12; Interval: 125; cmd: '/rollup'; Voice: sndNone; VoiceDelay: 0),
+			(Sprite:      sprSad; FramesCount: 14; Interval: 125; cmd: '/sad'; Voice: sndNone; VoiceDelay: 0),
+			(Sprite:     sprWave; FramesCount: 16; Interval: 125; cmd: '/wave'; Voice: sndHello; VoiceDelay: 5),
+			(Sprite:   sprHurrah; FramesCount: 14; Interval: 125; cmd: '/hurrah'; Voice: sndNone; VoiceDelay: 0),
+			(Sprite: sprLemonade; FramesCount: 24; Interval: 125; cmd: '/ilovelotsoflemonade'; Voice: sndNone; VoiceDelay: 0),
+			(Sprite:    sprShrug; FramesCount: 24; Interval: 125; cmd: '/shrug'; Voice: sndNone; VoiceDelay: 0),
+			(Sprite:   sprJuggle; FramesCount: 49; Interval:  38; cmd: '/juggle'; Voice: sndNone; VoiceDelay: 0)
 			);
 
 	Soundz: array[TSound] of record
 			FileName: String[25];
 			Path    : TPathType;
 			end = (
+			(FileName:                         ''; Path: ptNone  ),// sndNone
 			(FileName:        'grenadeimpact.ogg'; Path: ptSounds),// sndGrenadeImpact
 			(FileName:            'explosion.ogg'; Path: ptSounds),// sndExplosion
 			(FileName:         'throwpowerup.ogg'; Path: ptSounds),// sndThrowPowerUp
@@ -715,7 +723,16 @@
 			(FileName:               'mortar.ogg'; Path: ptSounds),// sndMortar
 			(FileName:         'shutterclick.ogg'; Path: ptSounds),// sndShutter
 			(FileName:              'homerun.ogg'; Path: ptSounds),// sndHomerun
-			(FileName:              'molotov.ogg'; Path: ptSounds) // sndMolotov
+			(FileName:              'molotov.ogg'; Path: ptSounds),// sndMolotov
+			(FileName:              'walking.ogg'; Path: ptSounds),// sndWalking
+			(FileName:            'Takecover.ogg'; Path: ptVoices),// sndCover
+			(FileName:                'Uh-oh.ogg'; Path: ptVoices),// sndUhOh
+			(FileName:                 'Oops.ogg'; Path: ptVoices),// sndOops
+			(FileName:                 'Nooo.ogg'; Path: ptVoices),// sndNooo
+			(FileName:                'Hello.ogg'; Path: ptVoices),// sndHello
+			(FileName:                         ''; Path: ptSounds),// sndRopeShot
+			(FileName:                         ''; Path: ptSounds),// sndRopeAttach
+			(FileName:                         ''; Path: ptSounds) // sndRopeRelease
 			);
 
 	Ammoz: array [TAmmoType] of record
@@ -742,7 +759,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amNothing);
+					AmmoType: amNothing;
+					AttackVoice: sndNone);
 			Slot: 0;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -762,7 +780,8 @@
 					NumPerTurn: 0;
 					Timer: 3000;
 					Pos: 0;
-					AmmoType: amGrenade);
+					AmmoType: amGrenade;
+					AttackVoice: sndCover);
 			Slot: 1;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -782,7 +801,8 @@
 					NumPerTurn: 0;
 					Timer: 3000;
 					Pos: 0;
-					AmmoType: amClusterBomb);
+					AmmoType: amClusterBomb;
+					AttackVoice: sndCover);
 			Slot: 1;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -801,7 +821,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amBazooka);
+					AmmoType: amBazooka;
+					AttackVoice: sndNone);
 			Slot: 0;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -821,7 +842,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amUFO);
+					AmmoType: amUFO;
+					AttackVoice: sndNone);
 			Slot: 0;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -839,7 +861,8 @@
 					NumPerTurn: 1;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amShotgun);
+					AmmoType: amShotgun;
+					AttackVoice: sndNone);
 			Slot: 2;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -860,7 +883,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amPickHammer);
+					AmmoType: amPickHammer;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -879,7 +903,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amSkip);
+					AmmoType: amSkip;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -899,7 +924,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amRope);
+					AmmoType: amRope;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -920,7 +946,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amMine);
+					AmmoType: amMine;
+					AttackVoice: sndLaugh);
 			Slot: 4;
 			TimeAfterTurn: 5000;
 			minAngle: 0;
@@ -938,7 +965,8 @@
 					NumPerTurn: 3;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amDEagle);
+					AmmoType: amDEagle;
+					AttackVoice: sndNone);
 			Slot: 2;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -959,7 +987,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amDynamite);
+					AmmoType: amDynamite;
+					AttackVoice: sndLaugh);
 			Slot: 4;
 			TimeAfterTurn: 5000;
 			minAngle: 0;
@@ -979,7 +1008,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amFirePunch);
+					AmmoType: amFirePunch;
+					AttackVoice: sndNone);
 			Slot: 3;
 			TimeAfterTurn: 3000;
 			MinAngle: 0;
@@ -997,7 +1027,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amWhip);
+					AmmoType: amWhip;
+					AttackVoice: sndNone);
 			Slot: 3;
 			TimeAfterTurn: 3000;
 			MinAngle: 0;
@@ -1015,7 +1046,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amBaseballBat);
+					AmmoType: amBaseballBat;
+					AttackVoice: sndNone);
 			Slot: 3;
 			TimeAfterTurn: 5000;
 			minAngle: 0;
@@ -1037,7 +1069,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amParachute);
+					AmmoType: amParachute;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1059,7 +1092,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amAirAttack);
+					AmmoType: amAirAttack;
+					AttackVoice: sndIncoming);
 			Slot: 5;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1081,7 +1115,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amMineStrike);
+					AmmoType: amMineStrike;
+					AttackVoice: sndNone);
 			Slot: 5;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1099,7 +1134,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amBlowTorch);
+					AmmoType: amBlowTorch;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 3000;
 			minAngle: 768;
@@ -1119,7 +1155,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amGirder);
+					AmmoType: amGirder;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1141,7 +1178,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amTeleport);
+					AmmoType: amTeleport;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1161,7 +1199,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amSwitch);
+					AmmoType: amSwitch;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1179,7 +1218,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amMortar);
+					AmmoType: amMortar;
+					AttackVoice: sndNone);
 			Slot: 1;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1199,7 +1239,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amKamikaze);
+					AmmoType: amKamikaze;
+					AttackVoice: sndNone);
 			Slot: 3;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1219,7 +1260,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amCake);
+					AmmoType: amCake;
+					AttackVoice: sndLaugh);
 			Slot: 4;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1237,7 +1279,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amSeduction);
+					AmmoType: amSeduction;
+					AttackVoice: sndNone);
 			Slot: 2;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1257,7 +1300,8 @@
 					NumPerTurn: 0;
 					Timer: 3000;
 					Pos: 0;
-					AmmoType: amWatermelon);
+					AmmoType: amWatermelon;
+					AttackVoice: sndMelon);
 			Slot: 1;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1276,7 +1320,8 @@
 					NumPerTurn: 0;
 					Timer: 5000;
 					Pos: 0;
-					AmmoType: amHellishBomb);
+					AmmoType: amHellishBomb;
+					AttackVoice: sndNone);
 			Slot: 4;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1298,7 +1343,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amNapalm);
+					AmmoType: amNapalm;
+					AttackVoice: sndNone);
 			Slot: 5;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1317,7 +1363,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amDrill);
+					AmmoType: amDrill;
+					AttackVoice: sndNone);
 			Slot: 0;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1336,7 +1383,8 @@
 					NumPerTurn: 0;
 					Timer: 5001;
 					Pos: 0;
-					AmmoType: amBallgun);
+					AmmoType: amBallgun;
+					AttackVoice: sndNone);
 			Slot: 2;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1356,7 +1404,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amRCPlane);
+					AmmoType: amRCPlane;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1377,7 +1426,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amLowGravity);
+					AmmoType: amLowGravity;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1398,7 +1448,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amExtraDamage);
+					AmmoType: amExtraDamage;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1419,7 +1470,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amInvulnerable);
+					AmmoType: amInvulnerable;
+					AttackVoice: sndNone);
 			Slot: 8;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1440,7 +1492,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amExtraTime);
+					AmmoType: amExtraTime;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1461,7 +1514,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amLaserSight);
+					AmmoType: amLaserSight;
+					AttackVoice: sndNone);
 			Slot: 7;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1482,7 +1536,8 @@
 					NumPerTurn: 0;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amVampiric);
+					AmmoType: amVampiric;
+					AttackVoice: sndNone);
 			Slot: 6;
 			TimeAfterTurn: 0;
 			minAngle: 0;
@@ -1500,7 +1555,8 @@
 					NumPerTurn: 1;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amSniperRifle);
+					AmmoType: amSniperRifle;
+					AttackVoice: sndNone);
 			Slot: 2;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1522,7 +1578,8 @@
 					NumPerTurn: 1;
 					Timer: 0;
 					Pos: 0;
-					AmmoType: amJetpack);
+					AmmoType: amJetpack;
+					AttackVoice: sndNone);
 			Slot: 3;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
@@ -1542,7 +1599,8 @@
 					NumPerTurn: 0;
 					Timer: 3000;
 					Pos: 0;
-					AmmoType: amMolotov);
+					AmmoType: amMolotov;
+					AttackVoice: sndNone);
 			Slot: 1;
 			TimeAfterTurn: 3000;
 			minAngle: 0;
--- a/hedgewars/uLand.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uLand.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -38,10 +38,12 @@
      hasBorder: boolean; 
      hasGirders: boolean;  
      playHeight, playWidth, leftX, rightX, topY, MaxHedgehogs: Longword;  // idea is that a template can specify height/width.  Or, a map, a height/width by the dimensions of the image.  If the map has pixels near top of image, it triggers border.
+	 LandBackSurface: PSDL_Surface = nil;
 
 procedure GenMap;
 function  GenPreview: TPreview;
 procedure CheckLandDigest(s: shortstring);
+function LandBackPixel(x, y: LongInt): LongWord;
 
 implementation
 uses uConsole, uStore, uMisc, uRandom, uTeams, uLandObjects, uSHA, uIO, uAmmos, uLandTexture;
@@ -307,6 +309,18 @@
       end;
 end;
 
+function LandBackPixel(x, y: LongInt): LongWord;
+var p: PLongWordArray;
+begin
+	if LandBackSurface = nil then
+		LandBackPixel:= 0
+	else
+		begin
+		p:= LandBackSurface^.pixels;
+		LandBackPixel:= p^[LandBackSurface^.w * (y mod LandBackSurface^.h) + (x mod LandBackSurface^.w)];// or $FF000000;
+		end
+end;
+
 procedure ColorizeLand(Surface: PSDL_Surface);
 var tmpsurf: PSDL_Surface;
     r, rr: TSDL_Rect;
@@ -326,6 +340,8 @@
 	end;
 SDL_FreeSurface(tmpsurf);
 
+LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent);
+
 tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent);
 for x:= 0 to LAND_WIDTH - 1 do
 	begin
@@ -835,4 +851,7 @@
 
 initialization
 
+finalization
+if LandBackSurface <> nil then
+	SDL_FreeSurface(LandBackSurface);
 end.
--- a/hedgewars/uLandGraphics.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uLandGraphics.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -30,7 +30,6 @@
 function SweepDirty: boolean;
 function Despeckle(X, Y: LongInt): boolean;
 function CheckLandValue(X, Y: LongInt; Color: Word): boolean;
-procedure Despeckle2(X, Y, Threesold: LongInt);
 procedure DrawExplosion(X, Y, Radius: LongInt);
 procedure DrawHLinesExplosions(ar: PRangeArray; Radius: LongInt; y, dY: LongInt; Count: Byte);
 procedure DrawTunnel(X, Y, dX, dY: hwFloat; ticks, HalfWidth: LongInt);
@@ -42,44 +41,6 @@
 implementation
 uses SDLh, uMisc, uLand, uLandTexture;
 
-procedure Despeckle2(X, Y, Threesold: LongInt);
-var
-	i, j: LongInt;
-	x0, x1, y0, y1: LongInt;        
-	c: byte;
-begin
-	// If the pixel has less than Threesold neightbours, it gets erased
-	// Erasing is outwards recursive
-	c := 0;
-
-	x0 := max(X-1, 0);
-	x1 := min(X+1, LAND_WIDTH - 1);
-	y0 := max(Y-1, 0);
-	y1 := min(Y+1, LAND_HEIGHT - 1);
-
-	for i:=x0 to x1 do begin
-		for j:=y0 to y1 do begin
-			if Land[j, i]<>0 then begin
-				c := c+1;
-			end;
-		end;
-	end;
-	
-	if c<Threesold then begin
-		Land[Y, X] := 0;
-		LandPixels[Y, X] := 0;
-		for i:=x0 to x1 do begin
-			for j:=y0 to y1 do begin
-				if Land[j, i]<>0 then begin
-					LandPixels[j, i] := cExplosionBorderColor;
-					Despeckle2(i, j, 5);
-				end;
-			end;
-		end;
-	end;
-    UpdateLandTexture(x0, x1-x0, y0, y1-y0);
-end;
-
 procedure FillCircleLines(x, y, dx, dy: LongInt; Value: Longword);
 var i: LongInt;
 begin
@@ -184,55 +145,84 @@
 begin
 if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
     for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-        if Land[y + dy, i] = COLOR_LAND then
+        if (Land[y + dy, i] <> COLOR_INDESTRUCTIBLE) then
             LandPixels[y + dy, i]:= 0;
 if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
     for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-        if Land[y - dy, i] = COLOR_LAND then
+        if (Land[y - dy, i] <> COLOR_INDESTRUCTIBLE) then
              LandPixels[y - dy, i]:= 0;
 if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
     for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-        if Land[y + dx, i] = COLOR_LAND then
+        if (Land[y + dx, i] <> COLOR_INDESTRUCTIBLE) then
             LandPixels[y + dx, i]:= 0;
 if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
     for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-        if Land[y - dx, i] = COLOR_LAND then
+        if (Land[y - dx, i] <> COLOR_INDESTRUCTIBLE) then
              LandPixels[y - dx, i]:= 0;
 end;
 
+procedure FillLandCircleLinesBG(x, y, dx, dy: LongInt);
+var i: LongInt;
+begin
+if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
+   for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
+       if (Land[y + dy, i] = COLOR_LAND) then
+          LandPixels[y + dy, i]:= LandBackPixel(i, y + dy)
+       else
+          if (Land[y + dy, i] = COLOR_OBJECT) then LandPixels[y + dy, i]:= 0;
+if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
+   for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
+       if (Land[y - dy, i] = COLOR_LAND) then
+          LandPixels[y - dy, i]:= LandBackPixel(i, y - dy)
+       else
+          if (Land[y - dy, i] = COLOR_OBJECT) then LandPixels[y - dy, i]:= 0;
+if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
+   for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
+       if (Land[y + dx, i] = COLOR_LAND) then
+           LandPixels[y + dx, i]:= LandBackPixel(i, y + dx)
+       else
+          if (Land[y + dx, i] = COLOR_OBJECT) then LandPixels[y + dx, i]:= 0;
+if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
+   for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
+       if (Land[y - dx, i] = COLOR_LAND) then
+          LandPixels[y - dx, i]:= LandBackPixel(i, y - dx)
+       else
+          if (Land[y - dx, i] = COLOR_OBJECT) then LandPixels[y - dx, i]:= 0;
+end;
+
 procedure FillLandCircleLinesEBC(x, y, dx, dy: LongInt);
 var i: LongInt;
 begin
 if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
    for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-       if Land[y + dy, i] = COLOR_LAND then
+       if (Land[y + dy, i] = COLOR_LAND) or (Land[y + dy, i] = COLOR_OBJECT) then
           begin
           LandPixels[y + dy, i]:= cExplosionBorderColor;
-          Despeckle2(i, y + dy, 6);
+          Despeckle(i, y + dy);
           LandDirty[(y + dy) div 32, i div 32]:= 1;
           end;
 if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
    for i:= max(x - dx, 0) to min(x + dx, LAND_WIDTH - 1) do
-       if Land[y - dy, i] = COLOR_LAND then
+       if (Land[y - dy, i] = COLOR_LAND) or (Land[y - dy, i] = COLOR_OBJECT) then
           begin
           LandPixels[y - dy, i]:= cExplosionBorderColor;
-          Despeckle2(i, y - dy, 6);
+          Despeckle(i, y - dy);
           LandDirty[(y - dy) div 32, i div 32]:= 1;
           end;
 if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
    for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-       if Land[y + dx, i] = COLOR_LAND then
+       if (Land[y + dx, i] = COLOR_LAND) or (Land[y + dx, i] = COLOR_OBJECT) then
            begin
            LandPixels[y + dx, i]:= cExplosionBorderColor;
-           Despeckle2(i, y + dx, 6);
+           Despeckle(i, y + dx);
            LandDirty[(y + dx) div 32, i div 32]:= 1;
            end;
 if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
    for i:= max(x - dy, 0) to min(x + dy, LAND_WIDTH - 1) do
-       if Land[y - dx, i] = COLOR_LAND then
+       if (Land[y - dx, i] = COLOR_LAND) or (Land[y - dx, i] = COLOR_OBJECT) then
           begin
           LandPixels[y - dx, i]:= cExplosionBorderColor;
-          Despeckle2(i, y - dy, 6);
+          Despeckle(i, y - dy);
           LandDirty[(y - dx) div 32, i div 32]:= 1;
           end;
 end;
@@ -240,39 +230,70 @@
 procedure DrawExplosion(X, Y, Radius: LongInt);
 var dx, dy, ty, tx, d: LongInt;
 begin
-  dx:= 0;
-  dy:= Radius;
-  d:= 3 - 2 * Radius;
-  while (dx < dy) do
-     begin
-     FillLandCircleLines0(x, y, dx, dy);
-     if (d < 0)
-     then d:= d + 4 * dx + 6
-     else begin
-          d:= d + 4 * (dx - dy) + 10;
-          dec(dy)
-          end;
-     inc(dx)
-     end;
-  if (dx = dy) then FillLandCircleLines0(x, y, dx, dy);
+
+// draw background land texture
+	begin
+	dx:= 0;
+	dy:= Radius;
+	d:= 3 - 2 * Radius;
+
+	while (dx < dy) do
+		begin
+		FillLandCircleLinesBG(x, y, dx, dy);
+		if (d < 0)
+		then d:= d + 4 * dx + 6
+		else begin
+			d:= d + 4 * (dx - dy) + 10;
+			dec(dy)
+			end;
+		inc(dx)
+		end;
+	if (dx = dy) then FillLandCircleLinesBG(x, y, dx, dy);
+	end;
+
+// draw a hole in land
+if Radius > 25 then
+	begin
+	dx:= 0;
+	dy:= Radius - 25;
+	d:= 3 - 2 * dy;
+
+	while (dx < dy) do
+		begin
+		FillLandCircleLines0(x, y, dx, dy);
+		if (d < 0)
+		then d:= d + 4 * dx + 6
+		else begin
+			d:= d + 4 * (dx - dy) + 10;
+			dec(dy)
+			end;
+		inc(dx)
+		end;
+	if (dx = dy) then FillLandCircleLines0(x, y, dx, dy);
+	end;
+
   // FillRoundInLand after erasing land pixels to allow Land 0 check for mask.png to function
-  FillRoundInLand(X, Y, Radius, 0);
-  inc(Radius, 4);
-  dx:= 0;
-  dy:= Radius;
-  d:= 3 - 2 * Radius;
-  while (dx < dy) do
-     begin
-     FillLandCircleLinesEBC(x, y, dx, dy);
-     if (d < 0)
-     then d:= d + 4 * dx + 6
-     else begin
-          d:= d + 4 * (dx - dy) + 10;
-          dec(dy)
-          end;
-     inc(dx)
-     end;
-  if (dx = dy) then FillLandCircleLinesEBC(x, y, dx, dy);
+	FillRoundInLand(X, Y, Radius, 0);
+
+// draw explosion border
+	begin
+	inc(Radius, 4);
+	dx:= 0;
+	dy:= Radius;
+	d:= 3 - 2 * Radius;
+	while (dx < dy) do
+		begin
+		FillLandCircleLinesEBC(x, y, dx, dy);
+		if (d < 0)
+		then d:= d + 4 * dx + 6
+		else begin
+			d:= d + 4 * (dx - dy) + 10;
+			dec(dy)
+			end;
+		inc(dx)
+		end;
+	if (dx = dy) then FillLandCircleLinesEBC(x, y, dx, dy);
+	end;
 
 tx:= max(X - Radius - 1, 0);
 dx:= min(X + Radius + 1, LAND_WIDTH) - tx;
@@ -285,13 +306,15 @@
 var tx, ty, i: LongInt;
 begin
 for i:= 0 to Pred(Count) do
-    begin
-    for ty:= max(y - Radius, 0) to min(y + Radius, LAND_HEIGHT) do
-        for tx:= max(0, ar^[i].Left - Radius) to min(LAND_WIDTH, ar^[i].Right + Radius) do
-            if Land[ty, tx] = COLOR_LAND then
-                LandPixels[ty, tx]:= 0;
-    inc(y, dY)
-    end;
+	begin
+	for ty:= max(y - Radius, 0) to min(y + Radius, LAND_HEIGHT) do
+		for tx:= max(0, ar^[i].Left - Radius) to min(LAND_WIDTH, ar^[i].Right + Radius) do
+			if Land[ty, tx] = COLOR_LAND then
+				LandPixels[ty, tx]:= LandBackPixel(tx, ty)
+			else if Land[ty, tx] = COLOR_OBJECT then
+				LandPixels[ty, tx]:= 0;
+	inc(y, dY)
+	end;
 
 inc(Radius, 4);
 dec(y, Count * dY);
@@ -300,10 +323,10 @@
     begin
     for ty:= max(y - Radius, 0) to min(y + Radius, LAND_HEIGHT) do
         for tx:= max(0, ar^[i].Left - Radius) to min(LAND_WIDTH, ar^[i].Right + Radius) do
-            if Land[ty, tx] = COLOR_LAND then
+            if (Land[ty, tx] = COLOR_LAND) or (Land[ty, tx] = COLOR_OBJECT) then
                 begin
                 LandPixels[ty, tx]:= cExplosionBorderColor;
-                LandDirty[trunc((y + dy)/32), trunc(i/32)]:= 1;
+                LandDirty[(y + dy) shr 5, i shr 5]:= 1;
                 end;
     inc(y, dY)
     end;
@@ -352,11 +375,13 @@
         tx:= hwRound(X);
         ty:= hwRound(Y);
         if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) then
-         if Land[ty, tx] = COLOR_LAND then
-           begin
-           Land[ty, tx]:= 0;
-           LandPixels[ty, tx]:= 0;
-           end
+            begin
+            if Land[ty, tx] = COLOR_LAND then
+                LandPixels[ty, tx]:= LandBackPixel(tx, ty)
+            else if Land[ty, tx] = COLOR_OBJECT then
+                LandPixels[ty, tx]:= 0;
+            Land[ty, tx]:= 0;
+            end
         end;
     for t:= 0 to 7 do
         {$INCLUDE "tunsetborder.inc"}
@@ -438,7 +463,7 @@
             for x:= 0 to Pred(w) do
                 if PLongword(@(p^[x * 4]))^ <> 0 then
                    begin
-                   Land[cpY + y, cpX + x]:= COLOR_LAND;
+                   Land[cpY + y, cpX + x]:= COLOR_OBJECT;
                    LandPixels[cpY + y, cpX + x]:= PLongword(@(p^[x * 4]))^
                    end;
             p:= @(p^[Image^.pitch]);
@@ -474,7 +499,7 @@
 
 	if c < 4 then // 0-3 neighbours
 		begin
-		LandPixels[Y, X]:= 0;
+        LandPixels[Y, X]:= ToggleLongInt(Land[Y, X] = COLOR_LAND, LandBackPixel(X, Y), 0);
 		Land[Y, X]:= 0;
 		exit(true);
 		end;
--- a/hedgewars/uLandObjects.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uLandObjects.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -91,7 +91,7 @@
 		if LandPixels[cpY + y, cpX + x] = 0 then
 			begin
 			LandPixels[cpY + y, cpX + x]:= p^[x];
-			if (p^[x] and AMask) <> 0 then Land[cpY + y, cpX + x]:= COLOR_LAND;
+			if (p^[x] and AMask) <> 0 then Land[cpY + y, cpX + x]:= COLOR_OBJECT;
 			end;
 	p:= @(p^[Image^.pitch shr 2]);
 	end;
--- a/hedgewars/uMisc.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uMisc.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -174,6 +174,9 @@
 procedure MakeScreenshot(s: shortstring);
 {$ENDIF}
 
+function ToggleLongInt(t: Boolean; a, b: LongInt): LongInt;
+function ToggleString(t: Boolean; a, b: string): string;
+
 function modifyDamage(dmg: Longword): Longword;
 
 var CursorPoint: TPoint;
@@ -560,6 +563,24 @@
 end;
 
 
+{$inline on}
+function ToggleLongInt(t: Boolean; a, b: LongInt): LongInt;
+begin
+    if t then
+	    ToggleLongInt:= a
+    else
+        ToggleLongInt:= b;
+end;
+
+function ToggleString(t: Boolean; a, b: string): string;
+begin
+    if t then
+	    ToggleString:= a
+    else
+        ToggleString:= b;
+end;
+{$inline off}
+
 initialization
 cDrownSpeed.QWordValue:= 257698038;// 0.06
 cMaxWindSpeed.QWordValue:= 2147484;// 0.0005
--- a/hedgewars/uSound.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uSound.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -32,6 +32,7 @@
 procedure ReleaseSound;
 procedure SoundLoad;
 procedure PlaySound(snd: TSound; infinite: boolean; voicepack: PVoicepack);
+procedure LoopSound(snd: TSound; voicepack: PVoicepack);
 procedure PlayMusic;
 procedure PauseMusic;
 procedure ResumeMusic;
@@ -67,6 +68,7 @@
 end;
 
 procedure InitSound;
+var i: TSound;
 begin
 if not isSoundEnabled then exit;
 WriteToConsole('Init sound...');
@@ -78,6 +80,9 @@
 Mix_AllocateChannels(Succ(chanTPU));
 if isMusicEnabled then Mix_VolumeMusic(50);
 
+for i:= Low(TSound) to High(TSound) do
+	lastChan[i]:= -1;
+
 Volume:= 0;
 ChangeVolume(cInitVolume)
 end;
@@ -106,7 +111,7 @@
 defVoicepack:= AskForVoicepack('Default');
 
 for i:= Low(TSound) to High(TSound) do
-	if Soundz[i].Path <> ptVoices then
+	if (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
 		begin
 		s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
 		WriteToConsole(msgLoading + s + ' ');
@@ -118,7 +123,7 @@
 for t:= 0 to cMaxTeams do
 	if voicepacks[t].name <> '' then
 		for i:= Low(TSound) to High(TSound) do
-			if Soundz[i].Path = ptVoices then
+			if (Soundz[i].Path = ptVoices) and (Soundz[i].FileName <> '') then
 				begin
 				s:= Pathz[Soundz[i].Path] + '/' + voicepacks[t].name + '/' + Soundz[i].FileName;
 				WriteToConsole(msgLoading + s + ' ');
@@ -142,11 +147,25 @@
 	lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], loops, -1)
 end;
 
+procedure LoopSound(snd: TSound; voicepack: PVoicepack);
+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)
+else
+	lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1)
+end;
+
 procedure StopSound(snd: TSound);
 begin
 if not isSoundEnabled then exit;
-if Mix_Playing(lastChan[snd]) <> 0 then
-	Mix_HaltChannel(lastChan[snd])
+if (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
+	begin
+	Mix_HaltChannel(lastChan[snd]);
+	lastChan[snd]:= -1;
+	end;
 end;
 
 procedure PlayMusic;
--- a/hedgewars/uStore.pas	Sun Nov 29 16:37:12 2009 +0000
+++ b/hedgewars/uStore.pas	Sun Nov 29 16:56:04 2009 +0000
@@ -1126,20 +1126,7 @@
 
 	
 {$IFNDEF IPHONEOS}
-// since ATI seems to be unable to provide proper texture filtering/quality,
-// do not even try to load the extension on ATI cards
-
-{$IFDEF DARWIN}
-if true then
-{$ELSE}
-if cGPUVendor <> gvATI then
-{$ENDIF}
-	SupportNPOTT:= glLoadExtension('GL_ARB_texture_non_power_of_two')
-{$IFDEF DEBUGFILE}
-else
-	AddFileLog('OpenGL: Skipped extension GL_ARB_texture_non_power_of_two due to ATI card')
-{$ENDIF}
-; // do not touch this line! :)
+//SupportNPOTT:= glLoadExtension('GL_ARB_texture_non_power_of_two');
 {$ENDIF}
 
 // set view port to whole window