merg with the latest rev of 22nd (end of GSoC) hedgeroid
author= Xeli
Wed, 24 Aug 2011 12:34:37 +0200
branchhedgeroid
changeset 5655 44c2d19f79e2
parent 5647 28ab6763da9d (current diff)
parent 5653 fa58dea8a9ad (diff)
child 5657 4dad72a8f514
merg with the latest rev of 22nd (end of GSoC)
hedgewars/uGame.pas
hedgewars/uScript.pas
hedgewars/uSound.pas
hedgewars/uTypes.pas
hedgewars/uVariables.pas
--- a/QTfrontend/about.cpp	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/about.cpp	Wed Aug 24 12:34:37 2011 +0200
@@ -26,20 +26,19 @@
   QWidget(parent)
 {
     QGridLayout *mainLayout = new QGridLayout(this);
-        QLabel *imageLabel = new QLabel;
-        QImage image(":/res/Hedgehog.png");
-
-        imageLabel->setPixmap(QPixmap::fromImage(image));
-        imageLabel->setScaledContents(true);
 
-        imageLabel->setMinimumWidth(2.8);
-        imageLabel->setMaximumWidth(280);
-        imageLabel->setMinimumHeight(30);
-        imageLabel->setMaximumHeight(300);
-        mainLayout->addWidget(imageLabel, 0, 0, 2, 1);
+    QLabel *imageLabel = new QLabel;
+    QImage image(":/res/Hedgehog.png");
+    imageLabel->setPixmap(QPixmap::fromImage(image));
+    imageLabel->setScaledContents(true);
+    imageLabel->setMinimumWidth(2.8);
+    imageLabel->setMaximumWidth(280);
+    imageLabel->setMinimumHeight(30);
+    imageLabel->setMaximumHeight(300);
+
+    mainLayout->addWidget(imageLabel, 0, 0, 2, 1);
 
     QLabel *lbl1 = new QLabel(this);
-
     lbl1->setOpenExternalLinks(true);
     lbl1->setText(
             "<style type=\"text/css\">"
@@ -80,6 +79,7 @@
             "Maze maps: Henning K&uuml;hn &lt;<a href=\"mailto:prg@cooco.de\">prg@cooco.de</a>&gt;<br>"
             "Engine and frontend improvements: Henrik Rostedt &lt;<a href=\"mailto:henrik.rostedt@gmail.com\">henrik.rostedt@gmail.com</a>&gt;<br>"
             "Lua game modes and missions: John Lambert &lt;<a href=\"mailto:redgrinner@gmail.com\">redgrinner@gmail.com</a>&gt;<br>"
+            "Frontend improvements: Mayur Pawashe &lt;<a href=\"mailto:zorgiepoo@gmail.com\">zorgiepoo@gmail.com</a>&gt;<br>"
             "Android port: Richard Deurwaarder &lt;<a href=\"mailto:xeli@xelification.com\">xeli@xelification.com</a>&gt;<br>"
             "</p><h2>" +
 
--- a/QTfrontend/hwform.cpp	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/hwform.cpp	Wed Aug 24 12:34:37 2011 +0200
@@ -37,6 +37,7 @@
 #include <QCryptographicHash>
 #include <QSignalMapper>
 #include <QShortcut>
+#include <QDesktopServices>
 
 #include "hwform.h"
 #include "game.h"
@@ -218,6 +219,7 @@
     connect(ui.pageRoomsList->BtnAdmin, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageRoomsList->BtnAdmin, ID_PAGE_ADMIN);
 
+    connect(ui.pageInfo->BtnSnapshots, SIGNAL(clicked()), this, SLOT(OpenSnapshotFolder()));
     connect(ui.pageInfo->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
 
     connect(ui.pageGameStats->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
@@ -576,6 +578,12 @@
         ammoSchemeModel->Save();
 }
 
+void HWForm::OpenSnapshotFolder()
+{
+    QString path = QDir::toNativeSeparators(cfgdir->absolutePath() + "/Screenshots");
+    QDesktopServices::openUrl(QUrl("file:///" + path));
+}
+
 void HWForm::btnExitPressed()
 {
     eggTimer.start();
--- a/QTfrontend/hwform.h	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/hwform.h	Wed Aug 24 12:34:37 2011 +0200
@@ -72,6 +72,7 @@
     void GoToNewScheme();
     void GoToPage(int id);
     void GoBack();
+    void OpenSnapshotFolder();
     QString getDemoArguments();
     void AssociateFiles();
     void btnExitPressed();
--- a/QTfrontend/pageinfo.cpp	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/pageinfo.cpp	Wed Aug 24 12:34:37 2011 +0200
@@ -29,6 +29,7 @@
     pageLayout->setColumnStretch(1, 1);
     pageLayout->setColumnStretch(2, 1);
 
+    BtnSnapshots = addButton(":/res/Star.png", pageLayout, 1, 2, true);
     BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true);
 
     about = new About(this);
--- a/QTfrontend/pageinfo.h	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/pageinfo.h	Wed Aug 24 12:34:37 2011 +0200
@@ -30,6 +30,7 @@
 public:
     PageInfo(QWidget* parent = 0);
 
+    QPushButton *BtnSnapshots;
     QPushButton *BtnBack;
     About *about;
 };
--- a/QTfrontend/pagemain.cpp	Mon Aug 22 03:57:11 2011 +0200
+++ b/QTfrontend/pagemain.cpp	Wed Aug 24 12:34:37 2011 +0200
@@ -104,14 +104,12 @@
         Tips << tr("Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice!", "Tips");
         // The following tip will require links to app store entries first.
         //Tips << tr("Want to play Hedgewars any time? Grab the Mobile version for %1 and %2.", "Tips").arg("").arg("");
+        // the ios version is located here: http://itunes.apple.com/us/app/hedgewars/id391234866
         Tips << tr("Keep your video card drivers up to date to avoid issues playing the game.", "Tips");
-        //Tips << tr("", "Tips");
-#ifndef __APPLE__
         Tips << tr("You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.", "Tips");
-#endif
 #ifdef _WIN32
         Tips << tr("You can find your Hedgewars configuration files under \"My Documents\\Hedgewars\". Create backups or take the files with you, but don't edit them by hand.", "Tips");
-#elif defined __APPLE__                                                                                                                     
+#elif defined __APPLE__
         Tips << tr("You can find your Hedgewars configuration files under \"Library/Application Support/Hedgewars\" in your home directory. Create backups or take the files with you, but don't edit them by hand.", "Tips");
 #else  
         Tips << tr("You can find your Hedgewars configuration files under \".hedgewars\" in your home directory. Create backups or take the files with you, but don't edit them by hand.", "Tips");
--- a/hedgewars/GSHandlers.inc	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/GSHandlers.inc	Wed Aug 24 12:34:37 2011 +0200
@@ -2300,8 +2300,7 @@
     Gear^.doStep := @doStepFirePunchWork;
     DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5);
 
-    PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), HHGear^.Hedgehog^.Team^.
-    voicepack)
+    AddVoice(TSound(ord(sndFirePunch1) + GetRandom(6)), HHGear^.Hedgehog^.Team^.voicepack)
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/hedgewars/HHHandlers.inc	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/HHHandlers.inc	Wed Aug 24 12:34:37 2011 +0200
@@ -215,7 +215,7 @@
 
         if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then xx:= - xx;
         if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
-           PlaySound(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
+           AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
 
 // Initiating alt attack
         if  (CurAmmoGear <> nil) and
@@ -741,8 +741,11 @@
 var da: LongWord;
 begin
 with HHGear^.Hedgehog^ do
-    if (CurAmmoType = amRope)
-    and ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving) then da:= 2 else da:= 1;
+    if ((CurAmmoType = amRope) and 
+        ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving)) or
+       ((CurAmmoType = amPortalGun) and 
+        ((HHGear^.State and gstMoving) <> 0)) then da:= 2
+    else da:= 1;
 
 if (((HHGear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
     if ((HHGear^.Message and gmUp) <> 0) and (HHGear^.Angle >= CurMinAngle + da) then dec(HHGear^.Angle, da)
--- a/hedgewars/uAIAmmoTests.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -43,6 +43,7 @@
 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 
 type TAmmoTestProc = function (Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
     TAmmoTest = record
@@ -101,7 +102,7 @@
             (proc: @TestShotgun;     flags: 0), // amSineGun
             (proc: nil;              flags: 0), // amFlamethrower
             (proc: @TestGrenade;     flags: 0), // amSMine
-            (proc: @TestFirePunch;   flags: 0), // amHammer
+            (proc: @TestHammer;      flags: 0), // amHammer
             (proc: nil;              flags: 0), // amResurrector
             (proc: nil;              flags: 0), // amDrillStrike
             (proc: @TestSnowball;    flags: 0), // amSnowball
@@ -558,10 +559,13 @@
      begin
      x:= x + vX * 8;
      y:= y + vY * 8;
-     valueResult:= RateShotgun(Me, rx, ry) * 2;
-     if valueResult = 0 then valueResult:= - Metric(Targ.X, Targ.Y, rx, ry) div 64
-                   else dec(valueResult, Level * 4000);
-     exit(valueResult)
+     valueResult:= RateShotgun(Me, rx, ry);
+     
+     if valueResult = 0 then 
+        valueResult:= - Metric(Targ.X, Targ.Y, rx, ry) div 64
+        else 
+        dec(valueResult, Level * 4000);
+     exit(valueResult * 27 div 20) // 27/20 is reuse bonus
      end
 until (Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 4)
     or (x.isNegative)
@@ -662,6 +666,23 @@
 TestFirePunch:= valueResult;
 end;
 
+function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+var rate: LongInt;
+begin
+Level:= Level; // avoid compiler hint
+ap.ExplR:= 0;
+ap.Time:= 0;
+ap.Power:= 1;
+ap.Angle:= 0;
+         
+if (Abs(hwRound(Me^.X) + hwSign(Me^.dX) * 10 - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) > 20) then
+    rate:= 0
+    else
+    rate:= RateHammer(Me);
+if rate = 0 then rate:= BadTurn;
+TestHammer:= rate;
+end;
+
 function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 const cShift = 4;
 var X, Y, dY: hwFloat;
--- a/hedgewars/uAIMisc.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uAIMisc.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -56,6 +56,7 @@
 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
 function RateShove(Me: PGear; x, y, r, power: LongInt): LongInt;
 function RateShotgun(Me: PGear; x, y: LongInt): LongInt;
+function RateHammer(Me: PGear): LongInt;
 function HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean;
 function AIrndSign(num: LongInt): LongInt;
 
@@ -231,10 +232,11 @@
 for i:= 0 to Targets.Count do
     with Targets.ar[i] do
          begin
-         dmg:= r + cHHRadius div 2 - hwRound(DistanceI(Point.x - x, Point.y - y));
+         dmg:= hwRound(_0_01 * cDamageModifier
+            * min((r + cHHRadius div 2 - DistanceI(Point.x - x, Point.y - y).Round) div 2, r) * cDamagePercent);
+
          if dmg > 0 then
             begin
-            dmg:= min(dmg div 2, r);
             if dmg >= abs(Score) then
                if Score > 0 then inc(rate, KillScore)
                             else dec(rate, KillScore * friendlyfactor div 100)
@@ -255,6 +257,7 @@
     with Targets.ar[i] do
          begin
          dmg:= r - hwRound(DistanceI(Point.x - x, Point.y - y));
+         dmg:= hwRound(_0_01 * cDamageModifier * dmg * cDamagePercent);
          if dmg > 0 then
             begin
             if power >= abs(Score) then
@@ -269,8 +272,6 @@
 end;
 
 function RateShotgun(Me: PGear; x, y: LongInt): LongInt;
-const
-  REUSE_BONUS = 1.35;
 var i, dmg, rate: LongInt;
 begin
 rate:= 0;
@@ -285,16 +286,39 @@
 for i:= 0 to Targets.Count do
     with Targets.ar[i] do
          begin
-         dmg:= min(cHHRadius + cShotgunRadius - hwRound(DistanceI(Point.x - x, Point.y - y)), 25);
-         dmg := round(dmg * REUSE_BONUS);
+         dmg:= min(cHHRadius + cShotgunRadius + 4 - hwRound(DistanceI(Point.x - x, Point.y - y)), 25);
+         dmg:= hwRound(_0_01 * cDamageModifier * dmg * cDamagePercent);
          if dmg > 0 then
             begin
                 if dmg >= abs(Score) then dmg := KillScore;
                 if Score > 0 then inc(rate, dmg)
                 else dec(rate, dmg * friendlyfactor div 100);
             end;
+         end;        
+RateShotgun:= rate * 1024;
+end;
+
+function RateHammer(Me: PGear): LongInt;
+var x, y, i, r, rate: LongInt;
+begin
+// hammer hit shift against attecker hog is 10
+x:= hwRound(Me^.X) + hwSign(Me^.dX) * 10;
+y:= hwRound(Me^.Y);
+rate:= 0;
+
+for i:= 0 to Pred(Targets.Count) do
+    with Targets.ar[i] do
+         begin
+         // hammer hit radius is 8, shift is 10
+         r:= hwRound(DistanceI(Point.x - x, Point.y - y));
+
+         if r <= 18 then
+            if Score > 0 then 
+                inc(rate, Score div 3)
+                else 
+                inc(rate, Score div 3 * friendlyfactor div 100)
          end;
-RateShotgun:= rate * 1024;
+RateHammer:= rate * 1024;
 end;
 
 function HHJump(Gear: PGear; JumpType: TJumpType; var GoInfo: TGoInfo): boolean;
--- a/hedgewars/uAmmos.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uAmmos.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -111,7 +111,8 @@
            ((a = amInvulnerable) and ((GameFlags and gfInvulnerable) <> 0)) or
            ((a = amLaserSight) and ((GameFlags and gfLaserSight) <> 0)) or
            ((a = amVampiric) and ((GameFlags and gfVampiric) <> 0)) or
-           ((a = amExtraTime) and (cHedgehogTurnTime >= 1000000)) then
+           ((a = amExtraTime) and (cHedgehogTurnTime >= 1000000)) or
+            (a = amStructure) then
             begin
             cnt:= 0;
             Ammoz[a].Probability:= 0
--- a/hedgewars/uGame.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uGame.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -45,7 +45,7 @@
     if isSpeed then Lag:= Lag * 10
     else
         if cOnlyStats then Lag:= High(LongInt);
-
+PlayNextVoice;
 i:= 1;
 while (GameState <> gsExit) and (i <= Lag) do
     begin
--- a/hedgewars/uGears.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uGears.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -962,11 +962,11 @@
                     and (not PlacingHogs)
                     and (CurrentHedgehog^.Gear <> nil)
                     and ((CurrentHedgehog^.Gear^.State and gstAttacked) = 0) then
-                        PlaySound(sndHurry, CurrentTeam^.voicepack);
+                        AddVoice(sndHurry, CurrentTeam^.voicepack);
                 if ReadyTimeLeft > 0 then
                     begin
                     if ReadyTimeLeft = 2000 then
-                        PlaySound(sndComeonthen, CurrentTeam^.voicepack);
+                        AddVoice(sndComeonthen, CurrentTeam^.voicepack);
                     dec(ReadyTimeLeft)
                     end
                 else
@@ -1850,7 +1850,7 @@
     FindPlace(FollowGear, true, 0, LAND_WIDTH);
 
     if (FollowGear <> nil) then
-        PlaySound(sndReinforce, CurrentTeam^.voicepack)
+        AddVoice(sndReinforce, CurrentTeam^.voicepack)
     end
 end;
 
--- a/hedgewars/uScript.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uScript.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -1109,7 +1109,7 @@
         begin
         gear:= GearByUID(lua_tointeger(L, 2));
         if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
-            PlaySound(TSound(lua_tointeger(L, 1)),gear^.Hedgehog^.Team^.Voicepack)
+            AddVoice(TSound(lua_tointeger(L, 1)),gear^.Hedgehog^.Team^.Voicepack)
         end
     else LuaError('Lua: Wrong number of parameters passed to PlaySound!');
     lc_playsound:= 0;
--- a/hedgewars/uSound.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uSound.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -77,6 +77,9 @@
 procedure StopSound(chn: LongInt);
 procedure StopSound(chn, fadems: LongInt);
 
+procedure AddVoice(snd: TSound; voicepack: PVoicepack);
+procedure PlayNextVoice;
+
 
 // MISC
 
@@ -255,9 +258,9 @@
         exit;
 
     if (voicepack <> nil) then
-    begin
+        begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
-        begin
+            begin
             s:= UserPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             if not FileExists(s) then s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
@@ -266,22 +269,50 @@
                 WriteLnToConsole(msgFailed)
             else
                 WriteLnToConsole(msgOK)
-        end;
+            end;
         lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
-    end
+        end
     else
-    begin
+        begin
         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
-        begin
+            begin
             s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             if not FileExists(s) then s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
             defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             TryDo(defVoicepack^.chunks[snd] <> nil, msgFailed, true);
             WriteLnToConsole(msgOK);
-        end;
+            end;
         lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
-    end;
+        end;
+end;
+
+procedure AddVoice(snd: TSound; voicepack: PVoicepack);
+var i : LongInt;
+begin
+    if (not isSoundEnabled) or fastUntilLag then exit;
+    i:= 0;
+    while (i<8) and (VoiceList[i].snd <> sndNone) do inc(i);
+
+    VoiceList[i].snd:= snd;
+    VoiceList[i].voicepack:= voicepack;
+end;
+
+procedure PlayNextVoice;
+var i : LongInt;
+begin
+    if (not isSoundEnabled) or fastUntilLag or (LastVoice.snd = sndNone) or (lastChan[LastVoice.snd] = -1) or (Mix_Playing(lastChan[LastVoice.snd]) = 0) then exit;
+    i:= 0;
+    while (i<8) and (VoiceList[i].snd = sndNone) do inc(i);
+    
+    if (VoiceList[i].snd <> sndNone) then
+        begin
+        LastVoice.snd:= VoiceList[i].snd;
+        LastVoice.voicepack:= VoiceList[i].voicepack;
+        VoiceList[i].snd:= sndNone;
+        PlaySound(LastVoice.snd, LastVoice.voicepack)
+        end
+    else LastVoice.snd:= sndNone;
 end;
 
 function LoopSound(snd: TSound): LongInt;
--- a/hedgewars/uStats.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uStats.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -99,11 +99,11 @@
     inc(CurrentHedgehog^.stats.FinishedTurns);
 
     if (CurrentHedgehog^.stats.DamageGiven = DamageTotal) and (DamageTotal > 0) then
-        PlaySound(sndFirstBlood, CurrentTeam^.voicepack)
+        AddVoice(sndFirstBlood, CurrentTeam^.voicepack)
 
     else if CurrentHedgehog^.stats.StepDamageRecv > 0 then
         begin
-        PlaySound(sndStupid, PreviousTeam^.voicepack);
+        AddVoice(sndStupid, PreviousTeam^.voicepack);
         if CurrentHedgehog^.stats.DamageGiven = CurrentHedgehog^.stats.StepDamageRecv then 
             AddCaption(Format(GetEventString(eidHurtSelf), CurrentHedgehog^.Name), cWhiteColor, capgrpMessage);
         end
@@ -111,32 +111,32 @@
     else if DamageClan <> 0 then
         if DamageTotal > DamageClan then
             if random(2) = 0 then
-                PlaySound(sndNutter, CurrentTeam^.voicepack)
+                AddVoice(sndNutter, CurrentTeam^.voicepack)
             else
-                PlaySound(sndWatchIt, vpHurtSameClan)
+                AddVoice(sndWatchIt, vpHurtSameClan)
         else
             if random(2) = 0 then
-                PlaySound(sndSameTeam, vpHurtSameClan)
+                AddVoice(sndSameTeam, vpHurtSameClan)
             else
-                PlaySound(sndTraitor, vpHurtSameClan)
+                AddVoice(sndTraitor, vpHurtSameClan)
 
     else if CurrentHedgehog^.stats.StepDamageGiven <> 0 then
         if Kills > 0 then
-            PlaySound(sndEnemyDown, CurrentTeam^.voicepack)
+            AddVoice(sndEnemyDown, CurrentTeam^.voicepack)
         else
-            PlaySound(sndRegret, vpHurtEnemy)
+            AddVoice(sndRegret, vpHurtEnemy)
 
     else if AmmoDamagingUsed then
-        PlaySound(sndMissed, PreviousTeam^.voicepack)
+        AddVoice(sndMissed, PreviousTeam^.voicepack)
     else if (AmmoUsedCount > 0) and not isTurnSkipped then
         // nothing ?
     else if isTurnSkipped then
         begin
-        PlaySound(sndBoring, PreviousTeam^.voicepack);
+        AddVoice(sndBoring, PreviousTeam^.voicepack);
         AddCaption(Format(GetEventString(eidTurnSkipped), CurrentHedgehog^.Name), cWhiteColor, capgrpMessage);
         end
     else if not PlacingHogs then
-        PlaySound(sndCoward, PreviousTeam^.voicepack);
+        AddVoice(sndCoward, PreviousTeam^.voicepack);
     end;
 
 
--- a/hedgewars/uTeams.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uTeams.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -81,9 +81,9 @@
                             if (Gear <> nil) then
                                 Gear^.State:= gstWinner;
             if Flawless then
-                PlaySound(sndFlawless, Teams[0]^.voicepack) 
+                AddVoice(sndFlawless, Teams[0]^.voicepack) 
             else
-                PlaySound(sndVictory, Teams[0]^.voicepack);
+                AddVoice(sndVictory, Teams[0]^.voicepack);
 
             AddCaption(s, cWhiteColor, capgrpGameState);
             SendStat(siGameResult, s);
@@ -257,16 +257,16 @@
 if (TurnTimeLeft > 0) and (CurrentHedgehog^.BotLevel = 0) then
     begin
     if CurrentTeam^.ExtDriven then
-        PlaySound(sndIllGetYou, CurrentTeam^.voicepack)
+        AddVoice(sndIllGetYou, CurrentTeam^.voicepack)
     else
-        PlaySound(sndYesSir, CurrentTeam^.voicepack);
+        AddVoice(sndYesSir, CurrentTeam^.voicepack);
     if PlacingHogs or (cHedgehogTurnTime < 1000000) then ReadyTimeLeft:= cReadyDelay;
     AddCaption(Format(shortstring(trmsg[sidReady]), CurrentTeam^.TeamName), cWhiteColor, capgrpGameState)
     end
 else
     begin
     if TurnTimeLeft > 0 then
-        PlaySound(sndIllGetYou, CurrentTeam^.voicepack);
+        AddVoice(sndIllGetYou, CurrentTeam^.voicepack);
     ReadyTimeLeft:= 0
     end;
 
--- a/hedgewars/uTypes.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uTypes.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -314,6 +314,11 @@
         chunks: array [TSound] of PMixChunk;
         end;
 
+    TVoice = record
+        snd: TSound;
+        voicepack: PVoicePack;
+        end;
+
     PHHAmmo = ^THHAmmo;
     THHAmmo = array[0..cMaxSlotIndex, 0..cMaxSlotAmmoIndex] of TAmmo;
 
--- a/hedgewars/uVariables.pas	Mon Aug 22 03:57:11 2011 +0200
+++ b/hedgewars/uVariables.pas	Wed Aug 24 12:34:37 2011 +0200
@@ -213,6 +213,17 @@
     cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13);
     cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0);
 
+    VoiceList : array[0..7] of TVoice =  (
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil),
+                    ( snd: sndNone; voicepack: nil));
+    LastVoice : TVoice = ( snd: sndNone; voicepack: nil );
+
     Fontz: array[THWFont] of THHFont = (
             (Handle: nil;
             Height: 12;
--- a/share/hedgewars/Data/Locale/ru.txt	Mon Aug 22 03:57:11 2011 +0200
+++ b/share/hedgewars/Data/Locale/ru.txt	Wed Aug 24 12:34:37 2011 +0200
@@ -72,6 +72,12 @@
 01:12=Последний раунд до потопа!
 01:13=%1 раундов до потопа!
 01:14=Приготовься, %1!
+01:15=Незначительный
+01:16=Низкий
+01:17=Нормальный
+01:18=Высокий
+01:19=Экстремальный
+01:20=%1 отскок
 
 ; Event messages
 ; Hog (%1) died