merge in japanese updates
authornemo
Sun, 17 Apr 2011 13:33:46 -0400
changeset 5152 589f69a9665c
parent 5151 cbadb9fa52fc (diff)
parent 5135 18f9546acb41 (current diff)
child 5153 c1df8a73f916
child 5154 851f36579ed4
merge in japanese updates
--- a/QTfrontend/chatwidget.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/chatwidget.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -409,10 +409,8 @@
 void HWChatWidget::nickRemoved(const QString& nick)
 {
     QList<QListWidgetItem *> items = chatNicks->findItems(nick, Qt::MatchExactly);
-    for(QList<QListWidgetItem *>::iterator it=items.begin(); it!=items.end();) {
-        chatNicks->takeItem(chatNicks->row(*it));
-        ++it;
-    }
+    QListIterator<QListWidgetItem *> it(items);
+    while(it.hasNext()) chatNicks->takeItem(chatNicks->row(it.next()));
 
     lblCount->setText(QString::number(chatNicks->count()));
 }
--- a/QTfrontend/game.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/game.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -82,8 +82,8 @@
 
     if (m_pTeamSelWidget)
     {
-        QList<HWTeam> teams = m_pTeamSelWidget->getPlayingTeams();
-        for(QList<HWTeam>::iterator it = teams.begin(); it != teams.end(); ++it)
+        QListIterator<HWTeam> it(m_pTeamSelWidget->getPlayingTeams());
+        while(it.hasNext())
         {
             HWProto::addStringToBuffer(buf, QString("eammloadt %1").arg(ammostr.mid(0, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber)));
@@ -91,7 +91,8 @@
             HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber)));
             if(!gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore"));
             HWProto::addStringListToBuffer(buf,
-                (*it).TeamGameConfig(gamecfg->getInitHealth()));
+                it.next().TeamGameConfig(gamecfg->getInitHealth()));
+            ;
         }
     }
     RawSendIPC(buf);
@@ -389,9 +390,9 @@
     if (m_pTeamSelWidget)
     {
         QByteArray buf;
-        QList<HWTeam> teams = m_pTeamSelWidget->getPlayingTeams();
-        for(QList<HWTeam>::iterator it = teams.begin(); it != teams.end(); ++it)
-            HWProto::addStringToBuffer(buf, QString("eteamgone %1").arg((*it).TeamName));
+        QListIterator<HWTeam> it(m_pTeamSelWidget->getPlayingTeams());
+        while(it.hasNext())
+            HWProto::addStringToBuffer(buf, QString("eteamgone %1").arg(it.next().TeamName));
         RawSendIPC(buf);
     }
 }
--- a/QTfrontend/hwform.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/hwform.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -244,6 +244,8 @@
 
     connect(ui.pageDrawMap->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
 
+    connect(ui.pageConnecting, SIGNAL(cancelConnection()), this, SLOT(GoBack()));
+
 
     ammoSchemeModel = new AmmoSchemeModel(this, cfgdir->absolutePath() + "/schemes.ini");
     ui.pageScheme->setModel(ammoSchemeModel);
@@ -550,7 +552,7 @@
         if (id == ID_PAGE_NETGAME || id == ID_PAGE_NETGAME)
             GoBack();
 
-    if (curid == ID_PAGE_ROOMSLIST) NetDisconnect();
+    if (curid == ID_PAGE_ROOMSLIST || curid == ID_PAGE_CONNECTING) NetDisconnect();
     if (curid == ID_PAGE_NETGAME && hwnet) hwnet->partRoom();
     // need to work on this, can cause invalid state for admin quit trying to prevent bad state message on kick
     //if (curid == ID_PAGE_NETGAME && (!game || game->gameState != gsStarted)) hwnet->partRoom();
@@ -593,11 +595,10 @@
         curTeamSelWidget = ui.pageNetGame->pNetTeamsWidget;
     }
 
-    QList<HWTeam> teams = curTeamSelWidget->getDontPlayingTeams();
     QStringList tmnames;
-    for(QList<HWTeam>::iterator it = teams.begin(); it != teams.end(); ++it) {
-        tmnames += it->TeamName;
-    }
+    QListIterator<HWTeam> it(curTeamSelWidget->getDontPlayingTeams());
+    while(it.hasNext()) tmnames += it.next().TeamName;
+
     //UpdateTeamsLists(&tmnames); // FIXME: still need more work if teamname is updated while configuring
     UpdateTeamsLists();
 
--- a/QTfrontend/netudpserver.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/netudpserver.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -22,7 +22,8 @@
 #include "netudpserver.h"
 
 HWNetUdpServer::HWNetUdpServer(QObject *parent, const QString & descr, quint16 port) :
-  HWNetRegisterServer(parent, descr, port)
+  HWNetRegisterServer(parent, descr, port),
+  m_descr(descr)
 {
   pUdpSocket = new QUdpSocket(this);
   pUdpSocket->bind(46631);
@@ -37,9 +38,9 @@
     QHostAddress clientAddr;
     quint16 clientPort;
     pUdpSocket->readDatagram(datagram.data(), datagram.size(), &clientAddr, &clientPort);
-    if(QString("%1").arg(datagram.data())==QString("hedgewars client")) {
+    if(datagram.startsWith("hedgewars client")) {
       // send answer to client
-      pUdpSocket->writeDatagram("hedgewars server", clientAddr, clientPort);
+      pUdpSocket->writeDatagram(QString("hedgewars server\n%1").arg(m_descr).toUtf8(), clientAddr, clientPort);
     }
   }
 }
--- a/QTfrontend/netudpserver.h	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/netudpserver.h	Sun Apr 17 13:33:46 2011 -0400
@@ -40,6 +40,7 @@
 
  private:
   QUdpSocket* pUdpSocket;
+  QString m_descr;
 };
 
 #endif // _NET_UDPSERVER_INCLUDED
--- a/QTfrontend/netudpwidget.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/netudpwidget.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -49,9 +49,10 @@
 
         pUdpSocket->readDatagram(datagram.data(), datagram.size(), &clientAddr, &clientPort);
 
-        if(QString("%1").arg(datagram.data())==QString("hedgewars server")) {
+        QString packet = QString::fromUtf8(datagram.data());
+        if(packet.startsWith("hedgewars server")) {
             QStringList sl;
-            sl << "-" << clientAddr.toString() << "46631";
+            sl << packet.remove(0, 17) << clientAddr.toString() << "46631";
             games.append(sl);
         }
     }
--- a/QTfrontend/pageconnecting.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/pageconnecting.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -29,4 +29,9 @@
     QLabel * lblConnecting = new QLabel(this);
     lblConnecting->setText(tr("Connecting..."));
     pageLayout->addWidget(lblConnecting);
+
+    QPushButton * pbCancel = new QPushButton(this);
+    pbCancel->setText(tr("Cancel"));
+    pageLayout->addWidget(pbCancel);
+    connect(pbCancel, SIGNAL(clicked()), this, SIGNAL(cancelConnection()));
 }
--- a/QTfrontend/pages.h	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/pages.h	Sun Apr 17 13:33:46 2011 -0400
@@ -476,6 +476,9 @@
 
 public:
     PageConnecting(QWidget* parent = 0);
+
+signals:
+    void cancelConnection();
 };
 
 class PageScheme : public AbstractPage
--- a/QTfrontend/teamselect.cpp	Mon Apr 11 20:53:55 2011 +0000
+++ b/QTfrontend/teamselect.cpp	Sun Apr 17 13:33:46 2011 -0400
@@ -243,7 +243,6 @@
 
 void TeamSelWidget::resetPlayingTeams(const QList<HWTeam>& teamslist)
 {
-  QList<HWTeam>::iterator it;
   //for(it=curPlayingTeams.begin(); it!=curPlayingTeams.end(); it++) {
   //framePlaying->removeTeam(*it);
   //}
@@ -256,9 +255,8 @@
   frameDontPlaying->resetTeams();
   curDontPlayingTeams.clear();
 
-  for (QList<HWTeam>::ConstIterator it = teamslist.begin(); it != teamslist.end(); ++it ) {
-    addTeam(*it);
-  }
+  QListIterator<HWTeam> it(teamslist);
+  while(it.hasNext()) addTeam(it.next());
 }
 
 bool TeamSelWidget::isPlaying(HWTeam team) const
--- a/gameServer/Actions.hs	Mon Apr 11 20:53:55 2011 +0000
+++ b/gameServer/Actions.hs	Sun Apr 17 13:33:46 2011 -0400
@@ -17,6 +17,7 @@
 import Data.Unique
 import Control.Arrow
 import Control.Exception
+import OfficialServer.GameReplayStore
 -----------------------------
 import CoreTypes
 import Utils
@@ -60,6 +61,7 @@
     | AddNick2Bans B.ByteString B.ByteString UTCTime
     | AddIP2Bans B.ByteString B.ByteString UTCTime
     | CheckBanned
+    | SaveReplay
 
 
 type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action]
@@ -470,3 +472,10 @@
         throw RestartException
         else
         processAction $ ModifyServerInfo (\s -> s{restartPending=True})
+
+processAction SaveReplay = do
+    ri <- clientRoomA
+    rnc <- gets roomsClients
+    io $ do
+        r <- room'sM rnc id ri
+        saveReplay r
--- a/gameServer/CoreTypes.hs	Mon Apr 11 20:53:55 2011 +0000
+++ b/gameServer/CoreTypes.hs	Sun Apr 17 13:33:46 2011 -0400
@@ -44,6 +44,7 @@
 
 data HedgehogInfo =
     HedgehogInfo B.ByteString B.ByteString
+    deriving (Show, Read)
 
 data TeamInfo =
     TeamInfo
@@ -60,6 +61,7 @@
         hhnum :: Int,
         hedgehogs :: [HedgehogInfo]
     }
+    deriving (Show, Read)
 
 data RoomInfo =
     RoomInfo
--- a/gameServer/HWProtoInRoomState.hs	Mon Apr 11 20:53:55 2011 +0000
+++ b/gameServer/HWProtoInRoomState.hs	Sun Apr 17 13:33:46 2011 -0400
@@ -205,7 +205,8 @@
     chans <- roomClientsChans
 
     if isMaster cl && gameinprogress rm then
-        return $ ModifyRoom
+        return $ 
+            ModifyRoom
                 (\r -> r{
                     gameinprogress = False,
                     readyPlayers = 0,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gameServer/OfficialServer/GameReplayStore.hs	Sun Apr 17 13:33:46 2011 -0400
@@ -0,0 +1,19 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module OfficialServer.GameReplayStore where
+
+import CoreTypes
+import Data.Time
+import Control.Exception as E
+import qualified Data.Map as Map
+import Data.Sequence()
+import System.Log.Logger
+
+saveReplay :: RoomInfo -> IO ()
+saveReplay r = do
+    time <- getCurrentTime
+    let fileName = "replays/" ++ show time
+    let replayInfo = (teamsAtStart r, Map.toList $ mapParams r, Map.toList $ params r, roundMsgs r)
+    E.catch
+        (writeFile fileName (show replayInfo))
+        (\(e :: IOException) -> warningM "REPLAYS" $ "Couldn't write to " ++ fileName ++ ": " ++ show e)
+                   
\ No newline at end of file
--- a/hedgewars/ArgParsers.inc	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/ArgParsers.inc	Sun Apr 17 13:33:46 2011 -0400
@@ -16,12 +16,19 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *)
 
+procedure playReplayFileWithParameters(); forward;
+
 procedure internalSetGameTypeLandPreviewFromParameters();
 begin
-    val(ParamStr(2), ipcPort);
-    GameType:= gmtLandPreview;
-    if ParamStr(3) <> 'landpreview' then
-        GameType:= gmtSyntax
+    if ParamStr(3) = '--stats-only' then
+        playReplayFileWithParameters()
+    else
+        begin
+        val(ParamStr(2), ipcPort);
+        GameType:= gmtLandPreview;
+        if ParamStr(3) <> 'landpreview' then
+            GameType:= gmtSyntax
+        end
 end;
 
 procedure internalStartGameWithParameters();
@@ -210,10 +217,19 @@
                             paramIndex:= paramIndex + 13
                             end
                         else
-                            begin
-                            wrongParameter:= true;
-                            GameType:= gmtSyntax
-                            end
+                            if ParamStr(paramIndex) = '--stats-only'  then
+                                begin
+                                cOnlyStats:= true;
+                                isSoundEnabled:= false;
+                                isMusicEnabled:= false;
+                                cReducedQuality:= $FFFFFFFF xor rqLowRes; // HACK
+                                paramIndex:= paramIndex + 1
+                                end
+                            else
+                                begin
+                                wrongParameter:= true;
+                                GameType:= gmtSyntax
+                                end
     end
 end;
 
--- a/hedgewars/GSHandlers.inc	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/GSHandlers.inc	Sun Apr 17 13:33:46 2011 -0400
@@ -176,8 +176,8 @@
                 particle := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), cWaterLine, vgtDroplet);
                 if particle <> nil then
                     begin
-                    particle^.dX := particle^.dX - (Gear^.dX.QWordValue / 42949672960);
-                    particle^.dY := particle^.dY - (Gear^.dY.QWordValue / 21474836480)
+                    particle^.dX := particle^.dX - hwFloat2Float(Gear^.dX);
+                    particle^.dY := particle^.dY - hwFloat2Float(Gear^.dY)
                     end
                 end
             end;
@@ -380,7 +380,7 @@
     dec(Gear^.Timer);
     if Gear^.Timer = 1000 then // might need adjustments
         case Gear^.Kind of 
-            gtBomb: makeHogsWorry(Gear^.X, Gear^.Y, 50);
+            gtGrenade: 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);
@@ -404,7 +404,7 @@
     if Gear^.Timer = 0 then
     begin
         case Gear^.Kind of 
-            gtBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+            gtGrenade: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
             gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, Gear^.Hedgehog, EXPLAutoSound);
             gtClusterBomb: 
                 begin
@@ -1549,7 +1549,7 @@
         HHGear^.dY := HHGear^.dY * len;
         end;
 
-    haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) <> 0);
+    haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)]) <> 0);
 
     if not haveCollision then
         begin
@@ -1564,13 +1564,13 @@
             Gear^.Y:= RopePoints.ar[0].Y;
             end;
 
-        CheckCollisionWithLand(Gear);
+        CheckCollision(Gear);
         // if we haven't found any collision yet then check the otheer side too
         if (Gear^.State and gstCollision) = 0 then
             begin
             Gear^.dX.isNegative:= not Gear^.dX.isNegative;
             Gear^.dY.isNegative:= not Gear^.dY.isNegative;
-            CheckCollisionWithLand(Gear);
+            CheckCollision(Gear);
             Gear^.dX.isNegative:= not Gear^.dX.isNegative;
             Gear^.dY.isNegative:= not Gear^.dY.isNegative;
             end;
@@ -1678,7 +1678,7 @@
             end;
         end;
 
-    CheckCollisionWithLand(Gear);
+    CheckCollision(Gear);
 
     if (Gear^.State and gstCollision) <> 0 then
         if Gear^.Elasticity < _10 then
@@ -1930,7 +1930,7 @@
         ^.dY := _0;
     if hwAbs(Gear^.dX) < _0_001 then Gear^.dX := _0;
 
-    if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
+    if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
         if (cBarrelHealth div Gear^.Health) > 2 then
             AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
     else
@@ -1970,7 +1970,7 @@
         if (hwAbs(Gear^.dX) > _0_15) or ((hwAbs(Gear^.dY) > _0_15) and (hwAbs(Gear^.dX) > _0_02))
             then Gear^.doStep := @doStepRollingBarrel;
 
-        if ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
+        if (Gear^.Health > 0) and ((Gear^.Health * 100 div cBarrelHealth) < random(90)) and ((GameTicks and $FF) = 0) then
             if (cBarrelHealth div Gear^.Health) > 2 then
                 AddVisualGear(hwRound(Gear^.X) - 16 + Random(32), hwRound(Gear^.Y) - 2, vgtSmoke)
         else
--- a/hedgewars/HHHandlers.inc	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/HHHandlers.inc	Sun Apr 17 13:33:46 2011 -0400
@@ -90,14 +90,7 @@
         if i <= cMaxSlotAmmoIndex then ammoidx:= i
         else ammoidx:= -1
         end;
-        if ammoidx >= 0 then 
-            begin
-            CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
-            if (CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) then
-                ShowCrosshair:= (Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoCrossHair) = 0
-            else
-                ShowCrosshair:= (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoCrosshair) = 0;
-            end
+        if ammoidx >= 0 then CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
     end
 end;
 
@@ -211,7 +204,7 @@
             end;
 
              case CurAmmoType of
-                      amGrenade: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtBomb,         0, newDx, newDy, CurWeapon^.Timer);
+                      amGrenade: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade,         0, newDx, newDy, CurWeapon^.Timer);
                       amMolotov: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov,      0, newDx, newDy, 0);
                   amClusterBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb,  0, newDx, newDy, CurWeapon^.Timer);
                       amGasBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb,      0, newDx, newDy, CurWeapon^.Timer);
@@ -390,9 +383,6 @@
                 begin
                 if TagTurnTimeLeft = 0 then TagTurnTimeLeft:= TurnTimeLeft;
                 TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100;
-                if (CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) then
-                    ShowCrosshair:= (Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoCrossHair) = 0
-                else ShowCrosshair:= false;
                 end;
             if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) then State:= State or gstAttacked;
             if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) <> 0 then ApplyAmmoChanges(CurrentHedgehog^)
--- a/hedgewars/VGSHandlers.inc	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/VGSHandlers.inc	Sun Apr 17 13:33:46 2011 -0400
@@ -106,7 +106,7 @@
 
 // up-and-down-bounce magic
 s := (GameTicks + Gear^.Timer) mod 4096;
-t := 8 * AngleSin(s mod 2048).QWordValue / 4294967296;
+t := 8 * hwFloat2Float(AngleSin(s mod 2048));
 if (s < 2048) then t := -t;
 
 Gear^.Y := LAND_HEIGHT - 1184 + LongInt(Gear^.Timer mod 8) + t;
@@ -465,8 +465,8 @@
 
 if (Gear^.Hedgehog^.Gear <> nil) then
     begin
-    Gear^.X:= Gear^.Hedgehog^.Gear^.X.QWordValue/4294967296 + (Gear^.Tex^.w div 2  - Gear^.FrameTicks);
-    Gear^.Y:= Gear^.Hedgehog^.Gear^.Y.QWordValue/4294967296 - (16 + Gear^.Tex^.h);
+    Gear^.X:= hwFloat2Float(Gear^.Hedgehog^.Gear^.X) + (Gear^.Tex^.w div 2  - Gear^.FrameTicks);
+    Gear^.Y:= hwFloat2Float(Gear^.Hedgehog^.Gear^.Y) - (16 + Gear^.Tex^.h);
     end;
 
 if Gear^.Timer = 0 then
--- a/hedgewars/hwengine.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/hwengine.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -437,6 +437,7 @@
     WriteLn(' --set-other [language file] [full screen] [show FPS]');
     WriteLn(' --set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
     WriteLn(' --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
+    WriteLn(' --stats-only');
     WriteLn();
     WriteLn('Read documentation online at http://code.google.com/p/hedgewars/wiki/CommandLineOptions for more information');
     WriteLn();
--- a/hedgewars/uAI.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uAI.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -208,6 +208,9 @@
 BestRate:= RatePlace(Me);
 BaseRate:= Max(BestRate, 0);
 
+if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
+    AddAction(Actions, aia_Weapon, Longword(amNothing), 100 + random(200), 0, 0);
+
 while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do
     begin
     Pop(ticks, Actions, Me^);
--- a/hedgewars/uAIAmmoTests.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uAIAmmoTests.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -115,58 +115,60 @@
 implementation
 uses uAIMisc, uVariables, uUtils;
 
-function Metric(x1, y1, x2, y2: LongInt): LongInt;
+function Metric(x1, y1, x2, y2: LongInt): LongInt; inline;
 begin
 Metric:= abs(x1 - x2) + abs(y1 - y2)
 end;
 
 function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var Vx, Vy, r: hwFloat;
+var Vx, Vy, r, mX, mY: real;
     rTime: LongInt;
     Score, EX, EY: LongInt;
     valueResult: LongInt;
 
     function CheckTrace: LongInt;
-    var x, y, dX, dY: hwFloat;
+    var x, y, dX, dY: real;
         t: LongInt;
         value: LongInt;
     begin
-    x:= Me^.X;
-    y:= Me^.Y;
+    x:= mX;
+    y:= mY;
     dX:= Vx;
     dY:= -Vy;
     t:= rTime;
     repeat
       x:= x + dX;
       y:= y + dY;
-      dX:= dX + cWindSpeed;
-      dY:= dY + cGravity;
+      dX:= dX + cWindSpeedf;
+      dY:= dY + cGravityf;
       dec(t)
-    until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t <= 0);
-    EX:= hwRound(x);
-    EY:= hwRound(y);
+    until TestCollExcludingMe(Me, trunc(x), trunc(y), 5) or (t <= 0);
+    EX:= trunc(x);
+    EY:= trunc(y);
     value:= RateExplosion(Me, EX, EY, 101);
     if value = 0 then value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
     CheckTrace:= value;
     end;
 
 begin
+mX:= hwFloat2Float(Me^.X);
+mY:= hwFloat2Float(Me^.Y);
 ap.Time:= 0;
 rTime:= 350;
 ap.ExplR:= 0;
 valueResult:= BadTurn;
 repeat
   rTime:= rTime + 300 + Level * 50 + random(300);
-  Vx:= - cWindSpeed * rTime * _0_5 + (int2hwFloat(Targ.X + AIrndSign(2)) - Me^.X) / int2hwFloat(rTime);
-  Vy:= cGravity * rTime * _0_5 - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(rTime);
-  r:= Distance(Vx, Vy);
-  if not (r > _1) then
+  Vx:= - cWindSpeedf * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
+  Vy:= cGravityf * rTime * 0.5 - (Targ.Y - mY) / rTime;
+  r:= sqrt(sqr(Vx) + sqr(Vy));
+  if not (r > 1) then
      begin
      Score:= CheckTrace;
      if valueResult <= Score then
         begin
         ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
-        ap.Power:= hwRound(r * cMaxPower) - random((Level - 1) * 17 + 1);
+        ap.Power:= trunc(r * cMaxPower) - random((Level - 1) * 17 + 1);
         ap.ExplR:= 100;
         ap.ExplX:= EX;
         ap.ExplY:= EY;
--- a/hedgewars/uAmmos.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uAmmos.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -228,7 +228,6 @@
                 begin
                 PackAmmo(Ammo, Ammoz[AmmoType].Slot);
                 //SwitchNotHeldAmmo(Hedgehog);
-                ShowCrossHair:= false;
                 CurAmmoType:= amNothing
                 end
             end
@@ -295,10 +294,6 @@
         end;
     TryDo(slot <= cMaxSlotIndex, 'Ammo slot index overflow', true);
     CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
-    if (CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) then
-        ShowCrosshair:= (Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoCrossHair) = 0
-    else
-        ShowCrosshair:= (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoCrosshair) = 0;
     end
 end;
 
--- a/hedgewars/uConsole.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uConsole.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -53,7 +53,7 @@
 begin
 {$IFNDEF NOCONSOLE}
 AddFileLog('[Con] ' + s);
-Write(s);
+Write(stderr, s);
 done:= false;
 
 while not done do
@@ -76,7 +76,7 @@
 begin
 {$IFNDEF NOCONSOLE}
 WriteToConsole(s);
-WriteLn;
+WriteLn(stderr);
 inc(CurrLine);
 if CurrLine = cLinesCount then
     CurrLine:= 0;
--- a/hedgewars/uFloat.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uFloat.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -58,6 +58,7 @@
 
 // Returns an hwFloat that represents the value of integer parameter i
 function int2hwFloat (const i: LongInt) : hwFloat; inline;
+function hwFloat2Float (const i: hwFloat) : extended; inline;
 
 // The implemented operators
 
@@ -188,6 +189,12 @@
 int2hwFloat.Frac:= 0
 end;
 
+function hwFloat2Float (const i: hwFloat) : extended;
+begin
+hwFloat2Float:= i.QWordValue / $100000000;
+if i.isNegative then hwFloat2Float:=hwFloat2Float*-1;
+end;
+
 operator + (const z1, z2: hwFloat) z : hwFloat;
 begin
 if z1.isNegative = z2.isNegative then
--- a/hedgewars/uGame.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uGame.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -40,7 +40,11 @@
     end;
 if Lag > 100 then Lag:= 100
 else if (GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) then Lag:= 2500;
-if (GameType = gmtDemo) and isSpeed then Lag:= Lag * 10;
+
+if (GameType = gmtDemo) then 
+    if isSpeed then Lag:= Lag * 10
+    else
+        if cOnlyStats then Lag:= High(LongInt);
 
 i:= 1;
 while (GameState <> gsExit) and (i <= Lag) do
--- a/hedgewars/uGears.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uGears.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -228,7 +228,7 @@
     end;
 
 case Kind of
-     gtBomb,
+     gtGrenade,
      gtClusterBomb,
      gtGasBomb: begin
                 gear^.ImpactSound:= sndGrenadeImpact;
@@ -1242,7 +1242,7 @@
                 gtStructure: begin
 // Run the calcs only once we know we have a type that will need damage
                         if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
-                            dmg:= dmgBase - hwRound(Distance(Gear^.X - fX, Gear^.Y - fY));
+                            dmg:= dmgBase - max(hwRound(Distance(Gear^.X - fX, Gear^.Y - fY)),Gear^.Radius);
                         if dmg > 1 then
                             begin
                             dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
--- a/hedgewars/uGearsRender.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uGearsRender.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -258,9 +258,12 @@
 
     if (Gear^.State and gstHHDriven) <> 0 then
         begin
-        if ((Gear^.State and gstHHThinking) = 0) and
-        ShowCrosshair and
-        ((Gear^.State and gstAnimation) = 0) then
+        if ((Gear^.State and (gstHHThinking or gstAnimation)) = 0) and
+/// If current ammo is active, and current ammo has alt attack and uses a crosshair  (rope, basically, right now, with no crosshair for parachute/saucer
+           (((CurAmmoGear <> nil) and //((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) and
+             ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoCrossHair) = 0)) or
+/// If no current ammo is active, and the selected ammo uses a crosshair
+             ((CurAmmoGear = nil) and ((Ammoz[HH^.CurAmmoType].Ammo.Propz and ammoprop_NoCrosshair) = 0) and ((Gear^.State and gstAttacked) = 0))) then
             begin
     (* These calculations are a little complex for a few reasons:
     1: I need to draw the laser from weapon origin to nearest land
@@ -868,7 +871,7 @@
     startX, endX, startY, endY: LongInt;
 begin
     case Gear^.Kind of
-          gtBomb: DrawRotated(sprBomb, x, y, 0, Gear^.DirAngle);
+          gtGrenade: DrawRotated(sprBomb, x, y, 0, Gear^.DirAngle);
       gtSnowball: DrawRotated(sprSnowball, x, y, 0, Gear^.DirAngle);
        gtGasBomb: DrawRotated(sprCheese, x, y, 0, Gear^.DirAngle);
        gtMolotov: DrawRotated(sprMolotov, x, y, 0, Gear^.DirAngle);
--- a/hedgewars/uIO.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uIO.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -178,10 +178,12 @@
 
 // set RDNLY on file open
 filemode:= 0;
-
+{$I-}
 assign(f, fileName);
 reset(f, 1);
 
+tryDo(IOResult = 0, 'Error opening file ' + fileName, true);
+
 i:= 0; // avoid compiler hints
 buf[0]:= 0;
 repeat
@@ -199,6 +201,7 @@
 until i = 0;
 
 close(f)
+{$I+}
 end;
 
 procedure SendStat(sit: TStatInfoType; s: shortstring);
--- a/hedgewars/uSound.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uSound.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -19,33 +19,71 @@
 {$INCLUDE "options.inc"}
 
 unit uSound;
+(*
+ * This unit controls the sounds and music of the game.
+ * Doesn't really do anything if isSoundEnabled = false.
+ *
+ * There are three basic types of sound controls:
+ *    Music        - The background music of the game:
+ *                   * will only be played if isMusicEnabled = true
+ *                   * can be started, changed, paused and resumed
+ *    Sound        - Can be started and stopped
+ *    Looped Sound - Subtype of sound: plays in a loop using a
+ *                   "channel", of which the id is returned on start.
+ *                   The channel id can be used to stop a specific sound loop.
+ *)
 interface
 uses SDLh, uConsts, uTypes, sysutils;
 
-var MusicFN: shortstring;
+var MusicFN: shortstring; // music file name
 
 procedure initModule;
 procedure freeModule;
 
-procedure InitSound;
-procedure ReleaseSound;
-procedure SoundLoad;
+procedure InitSound; // Initiates sound-system if isSoundEnabled.
+procedure ReleaseSound; // Releases sound-system and used resources.
+procedure SoundLoad; // Preloads some sounds for performance reasons.
+
+
+// MUSIC
+
+// Obvious music commands for music track specified in MusicFN.
+procedure PlayMusic;
+procedure PauseMusic;
+procedure ResumeMusic;
+procedure ChangeMusic; // Replaces music track with current MusicFN and plays it.
+
+
+// SOUNDS
+
+// Plays the sound snd [from a given voicepack],
+// if keepPlaying is given and true,
+// 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; voicepack: PVoicepack);
 procedure PlaySound(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+
+// Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in.
+// Returns sound channel of the looped sound.
 function  LoopSound(snd: TSound): LongInt;
 function  LoopSound(snd: TSound; fadems: LongInt): LongInt;
-function  LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
+function  LoopSound(snd: TSound; voicepack: PVoicepack): LongInt; // WTF?
 function  LoopSound(snd: TSound; voicepack: PVoicepack; fadems: LongInt): LongInt;
-procedure PlayMusic;
-procedure PauseMusic;
-procedure ResumeMusic;
-procedure ChangeMusic;
+
+// Stops the normal/looped sound of the given type/in the given channel
+// [with a fade-out effect for fadems milliseconds].
 procedure StopSound(snd: TSound);
 procedure StopSound(chn: LongInt);
 procedure StopSound(chn, fadems: LongInt);
+
+
+// MISC
+
+// Modifies the sound volume of the game by voldelta and returns the new volume level.
 function  ChangeVolume(voldelta: LongInt): LongInt;
+
+// Returns a pointer to the voicepack with the given name.
 function  AskForVoicepack(name: shortstring): Pointer;
 
 
@@ -366,6 +404,7 @@
     if (MusicFN = '') or (not isMusicEnabled) then
         exit;
 
+    // get rid of current music
     if Mus <> nil then
         Mix_FreeMusic(Mus);
 
--- a/hedgewars/uStats.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uStats.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -66,16 +66,16 @@
 
 if Gear^.Health <= Gear^.Damage then
     begin
-    inc(CurrentHedgehog^.stats.StepKills);
+    inc(Attacker^.stats.StepKills);
     inc(Kills);
     inc(KillsTotal);
-    inc(CurrentHedgehog^.Team^.stats.Kills);
-    if (CurrentHedgehog^.Team^.TeamName =
+    inc(Attacker^.Team^.stats.Kills);
+    if (Attacker^.Team^.TeamName =
             Gear^.Hedgehog^.Team^.TeamName) then begin
-        inc(CurrentHedgehog^.Team^.stats.TeamKills);
-        inc(CurrentHedgehog^.Team^.stats.TeamDamage, Gear^.Damage);
+        inc(Attacker^.Team^.stats.TeamKills);
+        inc(Attacker^.Team^.stats.TeamDamage, Gear^.Damage);
     end;
-    if CurrentHedgehog^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan then inc(KillsClan);
+    if Attacker^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan then inc(KillsClan);
     end;
 
 inc(Gear^.Hedgehog^.stats.StepDamageRecv, Gear^.Damage);
@@ -184,6 +184,7 @@
     maxTurnSkipsName : shortstring;
     maxTeamDamage : Longword;
     maxTeamDamageName : shortstring;
+    winnersClan : PClan;
 begin
 msd:= 0; msdhh:= nil;
 msk:= 0; mskhh:= nil;
@@ -191,6 +192,7 @@
 maxTeamKills := 0;
 maxTurnSkips := 0;
 maxTeamDamage := 0;
+winnersClan:= nil;
 
 for t:= 0 to Pred(TeamsCount) do
     with TeamsArray[t]^ do
@@ -216,6 +218,7 @@
 
         { send player stats for winner teams }
         if Clan^.ClanHealth > 0 then begin
+            winnersClan:= Clan;
             SendStat(siPlayerKills, IntToStr(Clan^.Color) + ' ' +
                 IntToStr(stats.Kills) + ' ' + TeamName);
         end;
@@ -259,6 +262,16 @@
     SendStat(siMaxTeamDamage, IntToStr(maxTeamDamage) + ' ' + maxTeamDamageName);
 
 if KilledHHs > 0 then SendStat(siKilledHHs, IntToStr(KilledHHs));
+
+// now to console
+if winnersClan <> nil then 
+    begin
+    writeln('WINNERS');
+    for t:= 0 to winnersClan^.TeamsNumber - 1 do
+        writeln(winnersClan^.Teams[t]^.TeamName);
+    writeln;
+    end else
+    writeln('DRAW');
 end;
 
 procedure initModule;
--- a/hedgewars/uStore.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uStore.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -943,8 +943,11 @@
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
 {$ELSE}
-    SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
-    SDLTry(SDLPrimSurface <> nil, true);
+    if not cOnlyStats then
+        begin
+        SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
+        SDLTry(SDLPrimSurface <> nil, true);
+        end;
 {$ENDIF}
 
     AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')');
--- a/hedgewars/uTypes.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uTypes.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -86,7 +86,7 @@
             );
 
     // Gears that interact with other Gears and/or Land
-    TGearType = (gtBomb, gtHedgehog, gtShell, gtGrave, gtBee, // 4
+    TGearType = (gtGrenade, gtHedgehog, gtShell, gtGrave, gtBee, // 4
             gtShotgunShot, gtPickHammer, gtRope, gtMine, gtCase, // 9
             gtDEagleShot, gtDynamite, gtClusterBomb, gtCluster, gtShover, // 14
             gtFlame, gtFirePunch, gtATStartGame, gtATSmoothWindCh, // 18
--- a/hedgewars/uUtils.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uUtils.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -42,6 +42,7 @@
 function  DxDy2Angle(const _dY, _dX: hwFloat): GLfloat;
 function  DxDy2Angle32(const _dY, _dX: hwFloat): LongInt;
 function  DxDy2AttackAngle(const _dY, _dX: hwFloat): LongInt;
+function  DxDy2AttackAngle(const _dY, _dX: extended): LongInt;
 
 procedure SetLittle(var r: hwFloat);
 
@@ -182,6 +183,11 @@
 DxDy2AttackAngle:= trunc(arctan2(dY, dX) * MaxAngleDivPI)
 end;
 
+function DxDy2AttackAngle(const _dY, _dX: extended): LongInt; inline;
+begin
+DxDy2AttackAngle:= trunc(arctan2(_dY, _dX) * (cMaxAngle/pi))
+end;
+
 
 procedure SetLittle(var r: hwFloat);
 begin
@@ -338,23 +344,27 @@
     if (ParamStr(1) <> '') and (ParamStr(2) <> '') then
         if (ParamCount <> 3) and (ParamCount <> cDefaultParamNum) then
         begin
-            for i:= 0 to 7 do
+            i:= 0;
+            while(i < 7) do
             begin
                 assign(f, ExtractFileDir(ParamStr(2)) + '/' + cLogfileBase + inttostr(i) + '.log');
                 rewrite(f);
                 if IOResult = 0 then break;
+                inc(i)
             end;
-            if IOResult <> 0 then f:= stderr; // if everything fails, write to stderr
+            if i = 7 then f:= stderr; // if everything fails, write to stderr
         end
         else
         begin
-            for i:= 0 to 7 do
+            i:= 0;
+            while(i < 7) do
             begin
                 assign(f, ParamStr(1) + '/Logs/' + cLogfileBase + inttostr(i) + '.log');
                 rewrite(f);
                 if IOResult = 0 then break;
+                inc(i)
             end;
-            if IOResult <> 0 then f:= stderr; // if everything fails, write to stderr
+            if i = 7 then f:= stderr; // if everything fails, write to stderr
         end
     else
         f:= stderr;
--- a/hedgewars/uVariables.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uVariables.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -45,6 +45,7 @@
     cReadyDelay     : Longword    = 5000;
     cLogfileBase    : shortstring = 'debug';
     cStereoMode     : TStereoMode = smNone;
+    cOnlyStats      : boolean = False;
 //////////////////////////
 
     alsoShutdownFrontend: boolean = false;
@@ -123,7 +124,7 @@
     bBetweenTurns   : boolean;
     bWaterRising    : boolean;
 
-    ShowCrosshair   : boolean;
+    //ShowCrosshair   : boolean;  This variable is inconvenient to set.  Easier to decide when rendering
     CursorMovementX : LongInt;
     CursorMovementY : LongInt;
     cDrownSpeed     : hwFloat;
--- a/hedgewars/uVisualGears.pas	Mon Apr 11 20:53:55 2011 +0000
+++ b/hedgewars/uVisualGears.pas	Sun Apr 17 13:33:46 2011 -0400
@@ -183,8 +183,8 @@
     vgtExplPart2: begin
                 t:= random(1024);
                 sp:= 0.001 * (random(95) + 70);
-                dx:= AngleSin(t).QWordValue/4294967296 * sp;
-                dy:= AngleCos(t).QWordValue/4294967296 * sp;
+                dx:= hwFloat2Float(AngleSin(t)) * sp;
+                dy:= hwFloat2Float(AngleCos(t)) * sp;
                 if random(2) = 0 then dx := -dx;
                 if random(2) = 0 then dy := -dy;
                 Frame:= 7 - random(3);
@@ -193,8 +193,8 @@
         vgtFire: begin
                 t:= random(1024);
                 sp:= 0.001 * (random(85) + 95);
-                dx:= AngleSin(t).QWordValue/4294967296 * sp;
-                dy:= AngleCos(t).QWordValue/4294967296 * sp;
+                dx:= hwFloat2Float(AngleSin(t)) * sp;
+                dy:= hwFloat2Float(AngleCos(t)) * sp;
                 if random(2) = 0 then dx := -dx;
                 if random(2) = 0 then dy := -dy;
                 FrameTicks:= 650 + random(250);
@@ -203,8 +203,8 @@
          vgtEgg: begin
                 t:= random(1024);
                 sp:= 0.001 * (random(85) + 95);
-                dx:= AngleSin(t).QWordValue/4294967296 * sp;
-                dy:= AngleCos(t).QWordValue/4294967296 * sp;
+                dx:= hwFloat2Float(AngleSin(t)) * sp;
+                dy:= hwFloat2Float(AngleCos(t)) * sp;
                 if random(2) = 0 then dx := -dx;
                 if random(2) = 0 then dy := -dy;
                 FrameTicks:= 650 + random(250);
@@ -284,8 +284,8 @@
      vgtFeather: begin
                 t:= random(1024);
                 sp:= 0.001 * (random(85) + 95);
-                dx:= AngleSin(t).QWordValue/4294967296 * sp;
-                dy:= AngleCos(t).QWordValue/4294967296 * sp;
+                dx:= hwFloat2Float(AngleSin(t)) * sp;
+                dy:= hwFloat2Float(AngleCos(t)) * sp;
                 if random(2) = 0 then dx := -dx;
                 if random(2) = 0 then dy := -dy;
                 FrameTicks:= 650 + random(250);
@@ -309,8 +309,8 @@
                 gear^.Frame:= random(4);
                 t:= random(1024);
                 sp:= 0.001 * (random(85) + 47);
-                dx:= AngleSin(t).QWordValue/4294967296 * sp;
-                dy:= AngleCos(t).QWordValue/4294967296 * sp * -2;
+                dx:= hwFloat2Float(AngleSin(t)) * sp;
+                dy:= hwFloat2Float(AngleCos(t)) * sp * -2;
                 if random(2) = 0 then dx := -dx;
                 end;
       vgtNote: begin
Binary file share/hedgewars/Data/Fonts/DejaVuSans-Bold.ttf has changed
--- a/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Mon Apr 11 20:53:55 2011 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Sun Apr 17 13:33:46 2011 -0400
@@ -1,4 +1,5 @@
 loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
 
 local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer, amBaseballBat, amMortar, amCake, amSeduction, amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane, amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb, amFlamethrower, amSMine, amKamikaze }
 
@@ -15,12 +16,89 @@
 --                        T,G,S,L,R,R,P,J,P,S
 local utilities_values = {1,2,2,1,2,2,1,2,2,2}
 
+function randomAmmo()
+    local n = 3   --"points" to be allocated on weapons
+    
+    --pick random weapon and subtract cost
+    local r = GetRandom(table.maxn(weapons_values)) + 1
+    local picked_items = {}
+    table.insert(picked_items, weapons[r])
+    n = n - weapons_values[r]
+    
+    
+    --choose any weapons or utilities to use up remaining n
+    
+    while n > 0 do
+        local items = {}
+        local items_values = {}
+
+        for i, w in pairs(weapons_values) do
+            local used = false
+            if w <= n then
+                --check that this weapon hasn't been given already
+                for j, k in pairs(picked_items) do
+                    if weapons[i] == k then
+                        used = true
+                    end
+                end
+                if not used then
+                    table.insert(items_values, w)
+                    table.insert(items, weapons[i])
+                end
+            end
+        end
+
+        for i, w in pairs(utilities_values) do
+            local used = false
+            if w <= n then
+                --check that this weapon hasn't been given already
+                for j, k in pairs(picked_items) do
+                    if utilities[i] == k then
+                        used = true
+                    end
+                end
+                if not used then
+                    table.insert(items_values, w)
+                    table.insert(items, utilities[i])
+                end
+            end
+        end
+        
+        local r = GetRandom(table.maxn(items_values)) + 1
+        table.insert(picked_items, items[r])
+        n = n - items_values[r]
+    end
+    
+    return picked_items
+end
+
+function assignAmmo(hog)
+    local name = GetHogTeamName(hog)
+    local processed = getTeamValue(name, "processed")
+    if processed == nil or not processed then
+        local ammo = getTeamValue(name, "ammo")
+        if ammo == nil then
+            ammo = randomAmmo()
+            setTeamValue(name, "ammo", ammo)
+        end
+        for i, w in pairs(ammo) do
+            AddAmmo(hog, w)
+        end
+        setTeamValue(name, "processed", true)
+    end
+end
+
+function reset(hog)
+    setTeamValue(GetHogTeamName(hog), "processed", false)
+end
+
 function onGameInit()
     GameFlags = band(bor(GameFlags, gfResetWeps), bnot(gfPerHogAmmo))
-    Goals = loc("Each turn you get 1-3 random weapons|The stronger they are, the fewer you get")
+    Goals = loc("Each turn you get 1-3 random weapons")
 end
 
 function onGameStart()
+    trackTeams()
     if MapHasBorder() == false then
         for i, w in pairs(airweapons) do
             table.insert(weapons, w)
@@ -29,8 +107,6 @@
             table.insert(weapons_values, w)
         end
     end
-
-    --ShowMission(loc("Balanced Random Weapons"), loc("A game of luck"), loc("Each turn you'll get a weapon, and if it sucks you'll get some more!"), -amSkip, 0)
 end
 
 function onAmmoStoreInit()
@@ -56,57 +132,17 @@
 end
 
 function onNewTurn()
-    local n = 3   --"points" to be allocated on weapons
-    
-    --pick random weapon and subtract cost
-    local r = GetRandom(table.maxn(weapons_values)) + 1
-    AddAmmo(CurrentHedgehog, weapons[r])
-    local items_used = {}
-    items_used[1] = weapons[r]
-    n = n - weapons_values[r]
-    
-    
-    --choose any weapons or utilities to use up remaining n
-    
-    while n > 0 do
-        local items = {}
-        local items_values = {}
+    runOnGears(assignAmmo)
+    runOnGears(reset)
+    setTeamValue(GetHogTeamName(CurrentHedgehog), "ammo", nil)
+end
 
-        for i, w in pairs(weapons_values) do
-            local used = false
-            if w <= n then
-                --check that this weapon hasn't been given already
-                for j = 1, table.maxn(items_used) do
-                    if weapons[i] == items_used[j] then
-                        used = true
-                    end
-                end
-                if not used then
-                    table.insert(items_values, w)
-                    table.insert(items, weapons[i])
-                end
-            end
-        end
-
-        for i, w in pairs(utilities_values) do
-            local used = false
-            if w <= n then
-                --check that this weapon hasn't been given already
-                for j = 1, table.maxn(items_used) do
-                    if utilities[i] == items_used[j] then
-                        used = true
-                    end
-                end
-                if not used then
-                    table.insert(items_values, w)
-                    table.insert(items, utilities[i])
-                end
-            end
-        end
-        
-        local r = GetRandom(table.maxn(items_values)) + 1
-        AddAmmo(CurrentHedgehog, items[r])
-        table.insert(items_used, items[r])
-        n = n - items_values[r]
+function onGearAdd(gear)
+    if GetGearType(gear) == gtHedgehog then
+        trackGear(gear)
     end
 end
+
+function onGearDelete(gear)
+    trackDeletion(gear)
+end
--- a/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua	Mon Apr 11 20:53:55 2011 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua	Sun Apr 17 13:33:46 2011 -0400
@@ -1,32 +1,72 @@
+-- Random Weapons, example for gameplay scripts
+
+-- Load the library for localisation ("loc" function)
 loadfile(GetDataPath() .. "Scripts/Locale.lua")()
 
+-- Load the gear tracker
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+-- List of available weapons
 local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun,
             amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer,
             amBaseballBat, amTeleport, amMortar, amCake, amSeduction,
             amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane,
             amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb,
-            amFlamethrower, amSMine, amHammer, amSnowball, amTardis, amStructure }
+            amFlamethrower, amSMine, amHammer }
 
+-- List of weapons that attack from the air
 local airweapons = { amAirAttack, amMineStrike, amNapalm, amDrillStrike }
 
+-- Function that assigns the team their weapon
+function assignAmmo(hog)
+    -- Get name of the current team
+    local name = GetHogTeamName(hog)
+    -- Get whither the team has been processed
+    local processed = getTeamValue(name, "processed")
+    -- If it has not, process it
+    if processed == nil or not processed then
+        -- Get the ammo for this hog's team
+        local ammo = getTeamValue(name, "ammo")
+        -- If there is no ammo, get a random one from the list and store it
+        if ammo == nil then
+            ammo = weapons[GetRandom(table.maxn(weapons)) + 1]
+            setTeamValue(name, "ammo", ammo)
+        end
+        -- Add the ammo for the hog
+        AddAmmo(hog, ammo)
+        -- Mark as processed
+        setTeamValue(name, "processed", true)
+    end
+end
+
+-- Mark team as not processed
+function reset(hog)
+    setTeamValue(GetHogTeamName(hog), "processed", false)
+end
 
 function onGameInit()
+    -- Limit flags that can be set, but allow game schemes to be used
     GameFlags = band(bor(GameFlags, gfResetWeps), bnot(gfInfAttack + gfPerHogAmmo))
+    -- Set a custom game goal that will show together with the scheme ones
     Goals = loc("Each turn you get one random weapon")
 end
 
 function onGameStart()
+    -- Initialize the tracking of hogs and teams
+    trackTeams()
+    -- Add air weapons to the game if the border is not active
     if MapHasBorder() == false then
         for i, w in pairs(airweapons) do
             table.insert(weapons, w)
         end
     end
-    --ShowMission(loc("Random Weapons"), loc("A game of luck"), loc("There has been a mix-up with your gear and now you|have to utilize whatever is coming your way!"), -amSkip, 0)
 end
 
 function onAmmoStoreInit()
+    -- Allow skip at all times
     SetAmmo(amSkip, 9, 0, 0, 0)
 
+    -- Let utilities be available through crates
     SetAmmo(amParachute, 0, 1, 0, 1)
     SetAmmo(amGirder, 0, 1, 0, 2)
     SetAmmo(amSwitch, 0, 1, 0, 1)
@@ -40,15 +80,34 @@
     SetAmmo(amPortalGun, 0, 1, 0, 1)
     SetAmmo(amResurrector, 0, 1, 0, 1)
 
+    -- Allow weapons to be used
     for i, w in pairs(weapons) do
         SetAmmo(w, 0, 0, 0, 1)
     end
 
+    -- Allow air weapons to be used
     for i, w in pairs(airweapons) do
         SetAmmo(w, 0, 0, 0, 1)
     end
 end
 
 function onNewTurn()
-    AddAmmo(CurrentHedgehog, weapons[GetRandom(table.maxn(weapons)) + 1])
+    -- Give every team their weapons, so one can plan during anothers turn
+    runOnGears(assignAmmo)
+    -- Mark all teams as not processed
+    runOnGears(reset)
+    -- Set the current teams weapons to nil so they will get new after the turn has ended
+    setTeamValue(GetHogTeamName(CurrentHedgehog), "ammo", nil)
 end
+
+function onGearAdd(gear)
+    -- Catch hedgehogs for the tracker
+    if GetGearType(gear) == gtHedgehog then
+        trackGear(gear)
+    end
+end
+
+function onGearDelete(gear)
+    -- Remove hogs that are gone
+    trackDeletion(gear)
+end
--- a/share/hedgewars/Data/Scripts/Tracker.lua	Mon Apr 11 20:53:55 2011 +0000
+++ b/share/hedgewars/Data/Scripts/Tracker.lua	Sun Apr 17 13:33:46 2011 -0400
@@ -274,15 +274,3 @@
         end
     end
 end
-
-function numGears()
-    return table.maxn(gears)
-end
-
-function numTeams()
-    num = 0
-    for team, hogs in pairs(teams) do
-        num = num + 1
-    end
-    return num
-end