Merge
authorWolfgang Steffens <WolfgangSteff@gmail.com>
Tue, 05 Jun 2012 22:17:06 +0200
changeset 7186 013deb83086b
parent 7138 f8248bcba8f1 (current diff)
parent 7185 92a045156255 (diff)
child 7188 580cd247511e
Merge
hedgewars/hwengine.pas
hedgewars/uGearsRender.pas
hedgewars/uLandTexture.pas
hedgewars/uStore.pas
hedgewars/uTextures.pas
hedgewars/uWorld.pas
--- a/QTfrontend/drawmapscene.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/drawmapscene.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -271,7 +271,8 @@
 
             quint8 penWidth = flags & 0x3f;
             m_pen.setWidth(deserializePenWidth(penWidth));
-            if(flags & 0x40)
+            params.erasing = flags & 0x40;
+            if(params.erasing)
                 m_pen.setBrush(m_eraser);
             else
                 m_pen.setBrush(m_brush);
--- a/QTfrontend/gameuiconfig.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/gameuiconfig.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -67,7 +67,7 @@
     Form->ui.pageOptions->CBFrontendEffects->setChecked(frontendEffects);
     Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool());
     Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool());
-    Form->ui.pageOptions->CBEnableMusic->setChecked(value(" audio/music", true).toBool());
+    Form->ui.pageOptions->CBEnableMusic->setChecked(value("audio/music", true).toBool());
     Form->ui.pageOptions->CBEnableFrontendMusic->setChecked(value("frontend/music", true).toBool());
     Form->ui.pageOptions->volumeBox->setValue(value("audio/volume", 100).toUInt());
 
--- a/QTfrontend/team.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/team.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -54,6 +54,7 @@
     m_rounds = 0;
     m_wins = 0;
     m_campaignProgress = 0;
+    m_color = 0;
 }
 
 HWTeam::HWTeam(const QStringList& strLst) :
@@ -82,6 +83,7 @@
     m_rounds = 0;
     m_wins = 0;
     m_campaignProgress = 0;
+    m_color = 0;
 }
 
 HWTeam::HWTeam() :
@@ -112,6 +114,7 @@
     m_rounds = 0;
     m_wins = 0;
     m_campaignProgress = 0;
+    m_color = 0;
 }
 
 HWTeam::HWTeam(const HWTeam & other) :
@@ -157,6 +160,7 @@
         m_campaignProgress = other.m_campaignProgress;
         m_rounds = other.m_rounds;
         m_wins = other.m_wins;
+        m_color = other.m_color;
     }
 
     return *this;
--- a/QTfrontend/ui/page/pageoptions.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/page/pageoptions.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -181,7 +181,7 @@
     {
         IconedGroupBox* groupMisc = new IconedGroupBox(this);
         //groupMisc->setContentTopPadding(0);
-        groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+        groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
         groupMisc->setIcon(QIcon(":/res/miscicon.png"));
         //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
         groupMisc->setTitle(QGroupBox::tr("Misc"));
@@ -229,30 +229,22 @@
         editNetNick->setText(QLineEdit::tr("anonymous"));
         MiscLayout->addWidget(editNetNick, 1, 1);
 
-        // Label and field for password
-        labelNetPassword = new QLabel(groupMisc);
-        labelNetPassword->setText(QLabel::tr("Password"));
-        MiscLayout->addWidget(labelNetPassword, 2, 0);
+        // checkbox and field for password
+        CBSavePassword = new QCheckBox(groupMisc);
+        CBSavePassword->setText(QCheckBox::tr("Save password"));
+        MiscLayout->addWidget(CBSavePassword, 2, 0);
 
         editNetPassword = new QLineEdit(groupMisc);
         editNetPassword->setEchoMode(QLineEdit::Password);
         MiscLayout->addWidget(editNetPassword, 2, 1);
 
-        CBSavePassword = new QCheckBox(groupMisc);
-        CBSavePassword->setText(QCheckBox::tr("Save password"));
-        MiscLayout->addWidget(CBSavePassword, 3, 0, 1, 2);
-
-        CBAltDamage = new QCheckBox(groupMisc);
-        CBAltDamage->setText(QCheckBox::tr("Alternative damage show"));
-        MiscLayout->addWidget(CBAltDamage, 4, 0, 1, 2);
-
         CBNameWithDate = new QCheckBox(groupMisc);
         CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name"));
         MiscLayout->addWidget(CBNameWithDate, 5, 0, 1, 2);
 
         BtnAssociateFiles = new QPushButton(groupMisc);
         BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions"));
-        BtnAssociateFiles->setEnabled(!custom_data && !custom_config);
+        BtnAssociateFiles->setVisible(!custom_data && !custom_config);
         MiscLayout->addWidget(BtnAssociateFiles, 6, 0, 1, 2);
 
 #ifdef __APPLE__
@@ -309,7 +301,7 @@
 
         CBFullscreen = new QCheckBox(AGGroupBox);
         CBFullscreen->setText(QCheckBox::tr("Fullscreen"));
-        GBAlayout->addWidget(CBFullscreen);
+        GBAreslayout->addWidget(CBFullscreen);
 
         QLabel * quality = new QLabel(AGGroupBox);
         quality->setText(QLabel::tr("Quality"));
@@ -349,36 +341,6 @@
         GBAstereolayout->addWidget(CBStereoMode);
         GBAlayout->addLayout(GBAstereolayout);
 
-        hr = new QFrame(AGGroupBox);
-        hr->setFrameStyle(QFrame::HLine);
-        hr->setLineWidth(3);
-        hr->setFixedHeight(10);
-        GBAlayout->addWidget(hr);
-
-        QHBoxLayout * GBAvollayout = new QHBoxLayout(0);
-        QLabel * vol = new QLabel(AGGroupBox);
-        vol->setText(QLabel::tr("Initial sound volume"));
-        GBAvollayout->addWidget(vol);
-        GBAlayout->addLayout(GBAvollayout);
-        volumeBox = new QSpinBox(AGGroupBox);
-        volumeBox->setRange(0, 100);
-        volumeBox->setSingleStep(5);
-        GBAvollayout->addWidget(volumeBox);
-
-        CBEnableSound = new QCheckBox(AGGroupBox);
-        CBEnableSound->setText(QCheckBox::tr("Enable sound"));
-        GBAlayout->addWidget(CBEnableSound);
-
-        CBEnableMusic = new QCheckBox(AGGroupBox);
-        CBEnableMusic->setText(QCheckBox::tr("Enable music"));
-        GBAlayout->addWidget(CBEnableMusic);
-
-        hr = new QFrame(AGGroupBox);
-        hr->setFrameStyle(QFrame::HLine);
-        hr->setLineWidth(3);
-        hr->setFixedHeight(10);
-        GBAlayout->addWidget(hr);
-
         QHBoxLayout * GBAfpslayout = new QHBoxLayout(0);
         QLabel * maxfps = new QLabel(AGGroupBox);
         maxfps->setText(QLabel::tr("FPS limit"));
@@ -389,7 +351,43 @@
 
         CBShowFPS = new QCheckBox(AGGroupBox);
         CBShowFPS->setText(QCheckBox::tr("Show FPS"));
-        GBAlayout->addWidget(CBShowFPS);
+        GBAfpslayout->addWidget(CBShowFPS);
+
+        hr = new QFrame(AGGroupBox);
+        hr->setFrameStyle(QFrame::HLine);
+        hr->setLineWidth(3);
+        hr->setFixedHeight(10);
+        GBAlayout->addWidget(hr);
+
+        QGridLayout * GBAvollayout = new QGridLayout();
+        QLabel * vol = new QLabel(AGGroupBox);
+        vol->setText(QLabel::tr("Initial sound volume"));
+        GBAvollayout->addWidget(vol, 0, 0, 1, 2);
+        GBAlayout->addLayout(GBAvollayout);
+        volumeBox = new QSpinBox(AGGroupBox);
+        volumeBox->setRange(0, 100);
+        volumeBox->setSingleStep(5);
+        GBAvollayout->addWidget(volumeBox, 0, 2);
+
+        CBEnableSound = new QCheckBox(AGGroupBox);
+        CBEnableSound->setText(QCheckBox::tr("Enable sound"));
+        GBAvollayout->addWidget(CBEnableSound, 1, 0, 1, 1);
+
+        CBEnableMusic = new QCheckBox(AGGroupBox);
+        CBEnableMusic->setText(QCheckBox::tr("Enable music"));
+        GBAvollayout->addWidget(CBEnableMusic, 1, 1, 1, 2);
+
+        GBAvollayout->setSizeConstraint(QLayout::SetMinimumSize);
+
+        hr = new QFrame(AGGroupBox);
+        hr->setFrameStyle(QFrame::HLine);
+        hr->setLineWidth(3);
+        hr->setFixedHeight(10);
+        GBAlayout->addWidget(hr);
+
+        CBAltDamage = new QCheckBox(AGGroupBox);
+        CBAltDamage->setText(QCheckBox::tr("Alternative damage show"));
+        GBAlayout->addWidget(CBAltDamage);
 
         gbTBLayout->addWidget(AGGroupBox, 0, 1, 3, 1);
     }
--- a/QTfrontend/ui/page/pageoptions.h	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/page/pageoptions.h	Tue Jun 05 22:17:06 2012 +0200
@@ -65,7 +65,6 @@
 
         FPSEdit *fpsedit;
         QLabel *labelNN;
-        QLabel *labelNetPassword;
         QSpinBox * volumeBox;
         QLineEdit *editNetNick;
         QLineEdit *editNetPassword;
--- a/QTfrontend/ui/widget/igbox.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/widget/igbox.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -29,7 +29,7 @@
 // Has issues with border-radius on children
 //    setAttribute(Qt::WA_PaintOnScreen, true);
     titleLeftPadding = 49;
-    contentTopPadding = 15;
+    contentTopPadding = 5;
 }
 
 void IconedGroupBox::setIcon(const QIcon & icon)
@@ -45,7 +45,7 @@
                           "subcontrol-origin: margin;"
                           "subcontrol-position: top left;"
                           "padding-left: %2px;"
-                          "padding-top: %1px;"
+                          "padding-top: 15px;"
                           "text-align: left;"
                           "}"
                       ).arg(contentTopPadding).arg(titleLeftPadding)
--- a/QTfrontend/ui/widget/teamselect.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/widget/teamselect.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -169,8 +169,8 @@
         // return if max playing teams reached
         if(framePlaying->isFullTeams()) return;
         // dont playing team => playing
+        itDontPlay->setColor(framePlaying->getNextColor());
         team=*itDontPlay; // for net team info saving in framePlaying (we have only name with netID from network)
-        itDontPlay->setColor(framePlaying->getNextColor());
         curPlayingTeams.push_back(*itDontPlay);
         if(!m_acceptOuter) emit teamWillPlay(*itDontPlay);
         m_curNotPlayingTeams.erase(itDontPlay);
@@ -295,6 +295,6 @@
 
 void TeamSelWidget::pre_changeTeamStatus(HWTeam team)
 {
-    team.setColor(framePlaying->getNextColor());
+    //team.setColor(framePlaying->getNextColor());
     emit acceptRequested(team);
 }
--- a/QTfrontend/ui/widget/teamselhelper.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/widget/teamselhelper.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -20,6 +20,7 @@
 #include <QPixmap>
 #include <QPainter>
 #include <QStyleFactory>
+#include <QDebug>
 
 #include <algorithm>
 
@@ -33,7 +34,7 @@
     emit teamActivated(text());
 }
 
-TeamShowWidget::TeamShowWidget(HWTeam team, bool isPlaying, FrameTeams * parent) :
+TeamShowWidget::TeamShowWidget(const HWTeam & team, bool isPlaying, FrameTeams * parent) :
     QWidget(parent), mainLayout(this), m_team(team), m_isPlaying(isPlaying), phhoger(0),
     colorWidget(0)
 {
@@ -73,9 +74,8 @@
         colorWidget->setMaximumWidth(26);
         colorWidget->setMinimumHeight(26);
         colorWidget->setMaximumHeight(26);
-        //colorWidget->setGeometry(0, 0, 26, 26);
+        colorWidget->setColor(team.color());
         connect(colorWidget, SIGNAL(colorChanged(int)), this, SLOT(onColorChanged(int)));
-        colorWidget->setColor(m_parentFrameTeams->getNextColor());
         mainLayout.addWidget(colorWidget);
 
         phhoger = new CHedgehogerWidget(QImage(":/res/hh25x25.png"), QImage(":/res/hh25x25grey.png"), this);
--- a/QTfrontend/ui/widget/teamselhelper.h	Mon May 28 10:38:27 2012 +0200
+++ b/QTfrontend/ui/widget/teamselhelper.h	Tue Jun 05 22:17:06 2012 +0200
@@ -58,7 +58,7 @@
         void onColorChanged(int color);
 
     public:
-        TeamShowWidget(HWTeam team, bool isPlaying, FrameTeams * parent);
+        TeamShowWidget(const HWTeam &team, bool isPlaying, FrameTeams * parent);
         void setPlaying(bool isPlaying);
         void setHHNum(unsigned int num);
         void setInteractivity(bool interactive);
--- a/hedgewars/ArgParsers.inc	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/ArgParsers.inc	Tue Jun 05 22:17:06 2012 +0200
@@ -24,7 +24,7 @@
         playReplayFileWithParameters()
     else
         begin
-        val(ParamStr(2), ipcPort);
+        ipcPort:= StrToInt(ParamStr(2));
         GameType:= gmtLandPreview;
         if ParamStr(3) <> 'landpreview' then
             GameType:= gmtSyntax
@@ -35,22 +35,21 @@
 var tmp: LongInt;
 begin
     UserPathPrefix:= ParamStr(1);
-    val(ParamStr(2), cScreenWidth);
-    val(ParamStr(3), cScreenHeight);
-    val(ParamStr(4), cBits);
-    val(ParamStr(5), ipcPort);
+    cScreenWidth:= StrToInt(ParamStr(2));
+    cScreenHeight:= StrToInt(ParamStr(3));
+    cBits:= StrToInt(ParamStr(4));
+    ipcPort:= StrToInt(ParamStr(5));
     cFullScreen:= ParamStr(6) = '1';
     SetSound(ParamStr(7) = '1');
     SetMusic(ParamStr(8) = '1');
-    val(ParamStr(9), tmp);
-    SetVolume(tmp);
-    val(ParamStr(10), cTimerInterval);
+    SetVolume(StrToInt(ParamStr(9)));
+    cTimerInterval:= StrToInt(ParamStr(10));
     PathPrefix:= ParamStr(11);
     cShowFPS:= ParamStr(12) = '1';
     cAltDamage:= ParamStr(13) = '1';
     UserNick:= DecodeBase64(ParamStr(14));
-    val(ParamStr(15), cReducedQuality);
-    val(ParamStr(16), tmp);
+    cReducedQuality:= StrToInt(ParamStr(15));
+    tmp:= StrToInt(ParamStr(16));
     GrayScale:= false;
     if (tmp > 9) and (tmp < 16) then 
         begin
@@ -72,11 +71,11 @@
 end;
 
 procedure setVideoWithParameters(screenWidthParam: string; screenHeightParam: string; bitsParam: string);
-var screenWidthAsInt, screenHeightAsInt, bitsStrAsInt: LongInt;
+var screenWidthAsInt, screenHeightAsInt, bitsStrAsInt, c: LongInt;
 begin
-    val(screenWidthParam, screenWidthAsInt);
-    val(screenHeightParam, screenHeightAsInt);
-    val(bitsParam, bitsStrAsInt);
+    val(screenWidthParam, screenWidthAsInt, c);
+    val(screenHeightParam, screenHeightAsInt, c);
+    val(bitsParam, bitsStrAsInt, c);
     setVideo(screenWidthAsInt,screenHeightAsInt,bitsStrAsInt)
 end;
 
@@ -108,10 +107,10 @@
 end;
 
 procedure setAudioWithParameters(initialVolumeParam: string; musicEnabledParam: string; soundEnabledParam: string);
-var initialVolumeAsInt: LongInt;
+var initialVolumeAsInt, c: LongInt;
     musicEnabled, soundEnabled: boolean;
 begin
-    val(initialVolumeParam, initialVolumeAsInt);
+    val(initialVolumeParam, initialVolumeAsInt, c);
     musicEnabled:= musicEnabledParam = '1';
     soundEnabled:= soundEnabledParam = '1';
     setAudio(initialVolumeAsInt,musicEnabled, soundEnabled)
@@ -139,7 +138,7 @@
                                       languageFileParam:string; fullScreenParam:string; showFPSParam:string;
                                       altDamageParam:string; timeItervalParam:string; reducedQualityParam: string);
 var showFPS, altDamage, reducedQuality: boolean;
-    timeIterval: LongInt;
+    timeIterval, c: LongInt;
 begin
     setMultimediaOptionsWithParameters(screenWidthParam,screenHeightParam, bitsParam,
                                        initialVolumeParam,musicEnabledParam,soundEnabledParam,
@@ -148,7 +147,7 @@
     setShowFPS(showFPS);
 
     altDamage:= altDamageParam = '1';
-    val(timeItervalParam, timeIterval);
+    val(timeItervalParam, timeIterval, c);
     reducedQuality:= reducedQualityParam = '1';
     setAltDamageTimerValueAndQuality(altDamage,timeIterval,reducedQuality);
 end;
--- a/hedgewars/GSHandlers.inc	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/GSHandlers.inc	Tue Jun 05 22:17:06 2012 +0200
@@ -702,14 +702,14 @@
             //Land[py, px+1]:= lfBasic;
             
             if allpx then
-                UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w))
+                UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w), true)
             else
                 begin
                 UpdateLandTexture(
                     max(0, min(LAND_WIDTH, xx)),
                     min(LAND_WIDTH - xx, Pred(s^.w)),
                     max(0, min(LAND_WIDTH, yy)),
-                    min(LAND_HEIGHT - yy, Pred(s^.h))
+                    min(LAND_HEIGHT - yy, Pred(s^.h)), false // could this be true without unnecessarily creating blanks?
                 );
                 end;
 ////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
@@ -2077,6 +2077,7 @@
     exBoom: boolean;
     dX, dY: HWFloat;
     hog: PHedgehog;
+    sparkles: PVisualGear;
 begin
     k := Gear^.Kind;
     exBoom := false;
@@ -2108,6 +2109,21 @@
         Gear^.Damage := 0;
         if Gear^.Health <= 0 then
             exBoom := true;
+        end
+    else
+        begin 
+        if Gear^.Timer = 0 then
+        begin
+(* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up
+   voices. Reinforcements voices is heard for active team, not team-to-be.  Either that or change crate spawn from end of turn to start, although that
+   has its own complexities. *)
+        sparkles:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust, 1);
+        if sparkles <> nil then
+            begin
+            sparkles^.Tint:= $FAB22CFF
+            end
+        end;
+        if (GameTicks and $1 = 0) and (Gear^.Timer < 255) then inc(Gear^.Timer)
         end;
 
     if (Gear^.Damage > 0) or exBoom then
--- a/hedgewars/LuaPas.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/LuaPas.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -1,4 +1,5 @@
 {$HINTS OFF}
+{$INCLUDE "options.inc"}
 
 unit LuaPas;
 
@@ -23,8 +24,7 @@
     lua_State = record end;
     Plua_State = ^lua_State;
 
-const
-    LuaLibName = cLuaLibrary;
+{$DEFINE LuaLibName:= cLuaLibrary}
 
 
 (*****************************************************************************)
@@ -81,8 +81,8 @@
 ** CHANGE them if you want to improve this functionality (e.g., by using
 ** GNU readline and history facilities).
 *)
-function  lua_readline(L : Plua_State;
-var b : PChar; p : PChar): Boolean;
+{function  lua_readline(L : Plua_State;
+var b : PChar; p : PChar): Boolean;}
 
 procedure lua_saveline(L : Plua_State; idx : LongInt);
 
@@ -119,7 +119,7 @@
     LUA_AUTHORS     = 'R. Ierusalimschy, L. H. de Figueiredo & W. Celes';
 
     (* mark for precompiled code (`<esc>Lua') *)
-    LUA_SIGNATURE = #27 + 'Lua';
+    //LUA_SIGNATURE = #27'Lua';
 
     (* option for multiple returns in `lua_pcall' and `lua_call' *)
     LUA_MULTRET = -1;
@@ -799,7 +799,7 @@
 (*****************************************************************************)
 (*                            luaconfig.h                                    *)
 (*****************************************************************************)
-
+{
 function  lua_readline(L : Plua_State;
 var
     b : PChar; p : PChar): Boolean;
@@ -811,7 +811,7 @@
     b := PChar(s);                   //   and return it
     lua_readline := (b[0] <> #4);          // test for ctrl-D
 end;
-
+}
 procedure lua_saveline(L : Plua_State; idx : LongInt);
 begin
 end;
@@ -1041,7 +1041,7 @@
         lua_ref := luaL_ref(L, LUA_REGISTRYINDEX)
     else
         begin
-        lua_pushstring(L, 'unlocked references are obsolete');
+        lua_pushstring(L, _P'unlocked references are obsolete');
         lua_error(L);
         lua_ref := 0;
         end;
--- a/hedgewars/SDLh.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/SDLh.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -968,6 +968,10 @@
 function SDL_getenv(const text: PChar): PChar; cdecl; external SDLLibName;
 {$ENDIF}
 
+{$IFDEF ANDROID}
+function Android_JNI_getDensity(): Single; cdecl; external SDLLibName;
+{$ENDIF}
+
 {* Compatibility between SDL-1.2 and SDL-1.3 *}
 procedure SDL_WarpMouse(x, y: Word); {$IFDEF SDL13}inline{$ELSE}cdecl; external SDLLibName{$ENDIF};
 function  SDL_GetKeyState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName {$IFDEF SDL13} name 'SDL_GetKeyboardState'{$ENDIF};
--- a/hedgewars/hwengine.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/hwengine.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -104,7 +104,11 @@
     if flagMakeCapture then
         begin
         flagMakeCapture:= false;
+        {$IFDEF PAS2C}
+        s:= 'hw';
+        {$ELSE}
         s:= 'hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks);
+        {$ENDIF}
 
         playSound(sndShutter);
         
@@ -267,10 +271,10 @@
     cBits:= 32;
     cTimerInterval:= 8;
     cShowFPS:= {$IFDEF DEBUGFILE}true{$ELSE}false{$ENDIF};
-    val(gameArgs[0], ipcPort);
-    val(gameArgs[1], cScreenWidth);
-    val(gameArgs[2], cScreenHeight);
-    val(gameArgs[3], cReducedQuality);
+    ipcPort:= StrToInt(gameArgs[0]);
+    cScreenWidth:= StrToInt(gameArgs[1]);
+    cScreenHeight:= StrToInt(gameArgs[2]);
+    cReducedQuality:= StrToInt(gameArgs[3]);
     cLocaleFName:= gameArgs[4];
     // cFullScreen functionality is platform dependent, ifdef it if you need to modify it
     cFullScreen:= false;
@@ -493,26 +497,26 @@
 procedure DisplayUsage;
 var i: LongInt;
 begin
-    WriteLn('Wrong argument format: correct configurations is');
-    WriteLn();
-    WriteLn('  hwengine <path to user hedgewars folder> <path to global data folder> <path to replay file> [options]');
-    WriteLn();
-    WriteLn('where [options] must be specified either as:');
-    WriteLn(' --set-video [screen width] [screen height] [color dept]');
-    WriteLn(' --set-audio [volume] [enable music] [enable sounds]');
-    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();
-    Write('PARSED COMMAND: ');
+    WriteLn(stdout, 'Wrong argument format: correct configurations is');
+    WriteLn(stdout, '');
+    WriteLn(stdout, '  hwengine <path to user hedgewars folder> <path to global data folder> <path to replay file> [options]');
+    WriteLn(stdout, '');
+    WriteLn(stdout, 'where [options] must be specified either as:');
+    WriteLn(stdout, ' --set-video [screen width] [screen height] [color dept]');
+    WriteLn(stdout, ' --set-audio [volume] [enable music] [enable sounds]');
+    WriteLn(stdout, ' --set-other [language file] [full screen] [show FPS]');
+    WriteLn(stdout, ' --set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
+    WriteLn(stdout, ' --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(stdout, ' --stats-only');
+    WriteLn(stdout, '');
+    WriteLn(stdout, 'Read documentation online at http://code.google.com/p/hedgewars/wiki/CommandLineOptions for more information');
+    WriteLn(stdout, '');
+    Write(stdout, 'PARSED COMMAND: ');
     
     for i:=0 to ParamCount do
-        Write(ParamStr(i) + ' ');
+        Write(stdout, ParamStr(i) + ' ');
         
-    WriteLn();
+    WriteLn(stdout, '');
 end;
 
 ////////////////////
@@ -549,6 +553,6 @@
     else Game();
 
     // return 1 when engine is not called correctly
-    ExitCode:= LongInt(GameType = gmtSyntax);
+    halt(LongInt(GameType = gmtSyntax));
 {$ENDIF}
 end.
--- a/hedgewars/pas2c.h	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/pas2c.h	Tue Jun 05 22:17:06 2012 +0200
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <stddef.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <wchar.h>
@@ -28,6 +29,7 @@
     } string15;
 
 typedef string255 shortstring;
+typedef string255 ansistring;
     
 typedef uint8_t Byte;
 typedef int8_t ShortInt;
@@ -56,17 +58,6 @@
 typedef int PtrInt;
 typedef wchar_t widechar;
 
-#ifdef __GNUG__
-#define NULL __null
-#else   /* G++ */
-/* shield NULL definition for non-gnu parsers */
-#ifndef __cplusplus
-#define NULL ((void *)0)
-#else
-#define NULL 0
-#endif  /* __cplusplus */
-#endif  /* G++ */
-
 #define new(a) __new((void **)&a, sizeof(*(a)))
 void __new(void ** p, int size);
 #define dispose(a) __dispose(a, sizeof(*(a)))
@@ -81,10 +72,12 @@
 string255 _strconcat(string255 a, string255 b);
 string255 _strappend(string255 s, char c);
 string255 _strprepend(char c, string255 s);
+string255 _chrconcat(char a, char b);
 bool _strcompare(string255 a, string255 b);
 bool _strcomparec(string255 a, char b);
 bool _strncompare(string255 a, string255 b);
 char * _pchar(string255 s);
+string255 pchar2str(char * s);
 
 int Length(string255 a);
 string255 copy(string255 a, int s, int l);
@@ -100,6 +93,7 @@
 typedef int TextFile;
 extern int FileMode;
 extern int IOResult;
+extern int stdout;
 extern int stderr;
 
 #define assign(a, b) assign_(&(a), b)
@@ -112,7 +106,8 @@
 void BlockWrite_(int f, void * p, int size);
 void close(int f);
 
-void write(string255 s);
+void write(int f, string255 s);
+void writeLn(int f, string255 s);
 
 bool DirectoryExists(string255 dir);
 bool FileExists(string255 filename);
@@ -140,8 +135,8 @@
 string255 ParamStr(int n);
 int ParamCount();
 
-#define val(a, b) _val(a, (LongInt*)&(b))
-void _val(string255 str, LongInt * a);
+#define val(a, b, c) _val(a, (LongInt*)&(b), (LongInt*)&(c))
+void _val(string255 str, LongInt * a, LongInt * c);
 
 extern double pi;
 
--- a/hedgewars/pas2cSystem.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/pas2cSystem.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -43,7 +43,6 @@
     PInteger = ^Integer;
     
     Handle = integer;
-    stderr = Handle;
 
     png_structp = pointer;
     png_size_t = integer;
@@ -68,6 +67,7 @@
     Length, StrToInt : function : integer;
     SetLength, val : procedure;
     _pchar : function : PChar;
+    pchar2str : function : string;
     memcpy : procedure;
 
     assign, rewrite, reset, flush, BlockWrite, BlockRead, close : procedure;
@@ -78,6 +78,7 @@
     FileExists, DirectoryExists, eof : function : boolean;
     ExtractFileName : function : string;
     exitcode : integer;
+    stdout, stderr : Handle;
     
     ParamCount : function : integer;
     ParamStr : function : string;
@@ -133,7 +134,7 @@
     
     Assigned : function : boolean;
     
-    _strconcat, _strappend, _strprepend : function : string;
+    _strconcat, _strappend, _strprepend, _chrconcat : function : string;
     _strcompare, _strncompare, _strcomparec : function : boolean;
 
     png_structp, png_set_write_fn, png_get_io_ptr,
--- a/hedgewars/uAI.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uAI.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -129,8 +129,10 @@
         ThreadSwitch();
 {$ENDIF}       
         repeat
-        if (CanUseAmmo[a]) and
-            ((not isMoved) or ((AmmoTests[a].flags and amtest_OnTurn) = 0)) then
+        if (CanUseAmmo[a]) 
+            and ((not isMoved) or ((AmmoTests[a].flags and amtest_OnTurn) = 0)) 
+            and ((i = 0) or ((AmmoTests[a].flags and amtest_NoTarget) = 0)) 
+            then
             begin
 {$HINTS OFF}
             Score:= AmmoTests[a].proc(Me, Targets.ar[i].Point, BotLevel, ap);
@@ -142,47 +144,47 @@
                     inc(BestActions.Score, Score);
                     BestActions.isWalkingToABetterPlace:= false;
 
-                if (ap.Angle > 0) then
-                    AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
-            else if (ap.Angle < 0) then
-                AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
+                    AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
 
-                AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
-                
-                if (ap.Time <> 0) then
-                    AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
-                if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
-                    begin
-                    ap.Angle:= LongInt(Me^.Angle) - Abs(ap.Angle);
-                    if ap.Angle > 0 then
+                    if (ap.Angle > 0) then
+                        AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
+                    else if (ap.Angle < 0) then
+                        AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
+                    
+                    if (ap.Time <> 0) then
+                        AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
+                    if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
                         begin
-                        AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0);
-                        AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0)
-                        end
-                    else if ap.Angle < 0 then
+                        ap.Angle:= LongInt(Me^.Angle) - Abs(ap.Angle);
+                        if ap.Angle > 0 then
+                            begin
+                            AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0);
+                            AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0)
+                            end
+                        else if ap.Angle < 0 then
+                            begin
+                            AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
+                            AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0)
+                            end
+                        end;
+                    if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
                         begin
-                        AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
-                        AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0)
-                        end
-                    end;
-                if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
-                    begin
-                    AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
-                    end;
-                if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
-                    begin
-                    AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0);
-                    AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
-                    end;
-                if ap.ExplR > 0 then
-                    AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY);
-                end
+                        AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
+                        end;
+                    if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
+                        begin
+                        AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0);
+                        AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
+                        end;
+                    if ap.ExplR > 0 then
+                        AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY);
+                    end
             end;
         if a = High(TAmmoType) then
             a:= Low(TAmmoType)
         else inc(a)
-        until (a = aa) or (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon
-        StopThinking
+        until (a = aa) or (CurrentHedgehog^.MultiShootAttacks > 0) {shooting same weapon}
+            or StopThinking
         end
 end;
 
@@ -205,10 +207,6 @@
 
 BotLevel:= Me^.Hedgehog^.BotLevel;
 
-tmp:= random(2) + 1;
-Push(0, Actions, Me^, tmp);
-Push(0, Actions, Me^, tmp xor 3);
-
 if (Me^.State and gstAttacked) = 0 then
     maxticks:= Max(0, TurnTimeLeft - 5000 - LongWord(4000 * BotLevel))
 else
@@ -221,8 +219,12 @@
 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);
+    AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0);
 
+tmp:= random(2) + 1;
+Push(0, Actions, Me^, tmp);
+Push(0, Actions, Me^, tmp xor 3);
+    
 while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do
     begin
     Pop(ticks, Actions, Me^);
@@ -266,9 +268,11 @@
                 with Stack.States[Pred(Stack.Count)] do
                     AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
 
+        // 'not CanGO' means we can't go straight, possible jumps are checked above
         if not CanGo then
             break;
-        inc(steps);
+        
+         inc(steps);
          Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
          Rate:= RatePlace(Me);
          if Rate > BestRate then
@@ -284,11 +288,11 @@
             TestAmmos(Actions, Me, true);
         if GoInfo.FallPix >= FallPixForBranching then
             Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
-        end;
+        end {while};
 
     if BestRate > BaseRate then
         exit
-        end
+        end {while}
 end;
 
 function Think(Me: Pointer): ptrint;
--- a/hedgewars/uAIActions.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uAIActions.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -176,7 +176,8 @@
                     exit
                     end
                 else
-                    begin CheckHang(Me);
+                    begin 
+                    CheckHang(Me);
                     exit
                     end;
                             
@@ -194,7 +195,8 @@
                     exit
                     end
                 else
-                    begin CheckHang(Me);
+                    begin 
+                    CheckHang(Me);
                     exit
                     end;
             aia_LookLeft:
--- a/hedgewars/uAIAmmoTests.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -21,7 +21,9 @@
 unit uAIAmmoTests;
 interface
 uses SDLh, uConsts, uFloat, uTypes;
-const amtest_OnTurn = $00000001;
+const 
+    amtest_OnTurn   = $00000001; // from one position
+    amtest_NoTarget = $00000002; // each pos, but no targetting
 
 var windSpeed: real;
 
@@ -68,9 +70,9 @@
             (proc: nil;              flags: 0), // amMine
             (proc: @TestDesertEagle; flags: 0), // amDEagle
             (proc: nil;              flags: 0), // amDynamite
-            (proc: @TestFirePunch;   flags: 0), // amFirePunch
-            (proc: @TestWhip;        flags: 0), // amWhip
-            (proc: @TestBaseballBat; flags: 0), // amBaseballBat
+            (proc: @TestFirePunch;   flags: amtest_NoTarget), // amFirePunch
+            (proc: @TestWhip;        flags: amtest_NoTarget), // amWhip
+            (proc: @TestBaseballBat; flags: amtest_NoTarget), // amBaseballBat
             (proc: nil;              flags: 0), // amParachute
             (proc: @TestAirAttack;   flags: amtest_OnTurn), // amAirAttack
             (proc: nil;              flags: 0), // amMineStrike
@@ -105,7 +107,7 @@
             (proc: @TestShotgun;     flags: 0), // amSineGun
             (proc: nil;              flags: 0), // amFlamethrower
             (proc: @TestGrenade;     flags: 0), // amSMine
-            (proc: @TestHammer;      flags: 0), // amHammer
+            (proc: @TestHammer;      flags: amtest_NoTarget), // amHammer
             (proc: nil;              flags: 0), // amResurrector
             (proc: nil;              flags: 0), // amDrillStrike
             (proc: nil;              flags: 0), // amSnowball
@@ -163,7 +165,7 @@
         EX:= trunc(x);
         EY:= trunc(y);
         if Me^.Hedgehog^.BotLevel = 1 then
-            value:= RateExplosion(Me, EX, EY, 101, 3)
+            value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
         else value:= RateExplosion(Me, EX, EY, 101);
         if value = 0 then
             value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
@@ -220,7 +222,7 @@
         EX:= trunc(x);
         EY:= trunc(y);
 
-        value:= RateShove(Me, trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, 1);
+        value:= RateShove(Me, trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
         if value = 0 then
             value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
 
@@ -323,7 +325,7 @@
     EY:= trunc(y);
     if t < 50 then 
         if Me^.Hedgehog^.BotLevel = 1 then
-            Score:= RateExplosion(Me, EX, EY, 101, 3)
+            Score:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
         else Score:= RateExplosion(Me, EX, EY, 101)
     else 
         Score:= BadTurn;
@@ -364,7 +366,7 @@
         Vx:= ((Targ.X+10) - meX) / (TestTime + tDelta)
     else
         Vx:= ((Targ.X-10) - meX) / (TestTime + tDelta);
-    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-150) - meY) / (TestTime + tDelta);
+    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-50) - meY) / (TestTime + tDelta);
     r:= sqr(Vx)+sqr(Vy);
     if not (r > 1) then
         begin
@@ -388,7 +390,7 @@
      if valueResult < Score then
         begin
         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
-        ap.Power:= trunc(sqrt(r) * cMaxPower * 0.9) + AIrndSign(random(Level) * 15);
+        ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
         ap.Time:= TestTime;
         ap.ExplR:= 90;
         ap.ExplX:= EX;
@@ -416,7 +418,7 @@
 repeat
     inc(TestTime, 1000);
     Vx:= (Targ.X - meX) / (TestTime + tDelta);
-    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-200) - meY) / (TestTime + tDelta);
+    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-50) - meY) / (TestTime + tDelta);
     r:= sqr(Vx)+sqr(Vy);
     if not (r > 1) then
         begin
@@ -424,30 +426,31 @@
         y:= meY;
         dY:= -Vy;
         t:= TestTime;
-    repeat
-        x:= x + Vx;
-        y:= y + dY;
-        dY:= dY + cGravityf;
-        dec(t)
-    until TestCollExcludingMe(Me, trunc(x), trunc(y), 5) or (t = 0);
-    EX:= trunc(x);
-    EY:= trunc(y);
-    if t < 50 then 
-        Score:= RateExplosion(Me, EX, EY, 381)
-    else 
-        Score:= BadTurn;
+        repeat
+            x:= x + Vx;
+            y:= y + dY;
+            dY:= dY + cGravityf;
+            dec(t)
+        until TestCollExcludingMe(Me, trunc(x), trunc(y), 7) or (t = 0);
         
-    if valueResult < Score then
-        begin
-        ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
-        ap.Power:= trunc(sqrt(r) * cMaxPower * 0.9) + AIrndSign(random(Level) * 15);
-        ap.Time:= TestTime;
-        ap.ExplR:= 300;
-        ap.ExplX:= EX;
-        ap.ExplY:= EY;
-        valueResult:= Score
-        end;
-    end
+        EX:= trunc(x);
+        EY:= trunc(y);
+        if t < 50 then 
+            Score:= RateExplosion(Me, EX, EY, 200) + RateExplosion(Me, EX, EY + 120, 200)
+        else 
+            Score:= BadTurn;
+            
+        if valueResult < Score then
+            begin
+            ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
+            ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
+            ap.Time:= TestTime;
+            ap.ExplR:= 300;
+            ap.ExplX:= EX;
+            ap.ExplY:= EY;
+            valueResult:= Score
+            end;
+        end
 until (TestTime = 4000);
 TestWatermelon:= valueResult
 end;
@@ -457,15 +460,15 @@
     var A, B, D, T: real;
         C: LongInt;
     begin
-        A:= sqr(cGravityf) * 0.25;
+        A:= sqr(cGravityf);
         B:= - cGravityf * (TY - MY) - 1;
         C:= sqr(TY - MY) + sqr(TX - MX);
-        D:= sqr(B) - (A * C * 4);
+        D:= sqr(B) - A * C;
         if D >= 0 then
             begin
-            D:= ( - B + sqrt(D)) * 0.5 / A;
+            D:= sqrt(D) - B;
             if D >= 0 then
-                T:= sqrt(D)
+                T:= sqrt(D * 2 / A)
             else
                 T:= 0;
             Solve:= trunc(T)
@@ -639,7 +642,7 @@
 ap.ExplR:= 0;
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
-if (Level > 2) or (Abs(trunc(x) - Targ.X) + Abs(trunc(y) - Targ.Y) > 25) then
+if (Level > 2) then
     exit(BadTurn);
 
 ap.Time:= 0;
@@ -649,7 +652,7 @@
 else
     ap.Angle:= - cMaxAngle div 4;
 
-valueResult:= RateShove(Me, trunc(x) + LongWord(10*hwSignf(Targ.X - x)), trunc(y), 15, 30, 115, hwSign(Me^.dX)*0.353, -0.353, 1);
+valueResult:= RateShove(Me, trunc(x) + LongWord(10*hwSignf(Targ.X - x)), trunc(y), 15, 30, 115, hwSign(Me^.dX)*0.353, -0.353, afTrackFall);
 if valueResult <= 0 then
     valueResult:= BadTurn
 else
@@ -658,34 +661,36 @@
 end;
 
 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var val1: LongInt;
+var val1, val2, i, t: LongInt;
     x, y: real;
 begin
 Level:= Level; // avoid compiler hint
+TestFirePunch:= BadTurn;
 ap.ExplR:= 0;
 ap.Time:= 0;
 ap.Power:= 1;
 ap.Angle:= hwSign(Me^.dX);
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
+{
+// this block is for digging with firepunch when blocked close to walls (notice TestColl check)
 if (Abs(trunc(x) - Targ.X) > 25)
-or (Abs(trunc(y) - 50 - Targ.Y) > 50) then
+    or (Abs(trunc(y) + 50 - Targ.Y) > 50) then
     begin
-// TODO - find out WTH this works.
     if TestColl(trunc(x), trunc(y) - 16, 6) and 
        (RateShove(Me, trunc(x) + LongWord(10 * hwSign(Me^.dX)), 
-                      trunc(y) - 40, 30, 30, 40, hwSign(Me^.dX)*0.45, -0.9,  1) = 0) then
+                      trunc(y) - 40, 30, 30, 40, hwSign(Me^.dX)*0.45, -0.9,  1) >= 0) then
         val1:= Succ(BadTurn)
     else
         val1:= BadTurn;
     exit(val1);
     end;
-(*
-For some silly reason, having this enabled w/ the AI 
+    }
+// and this is actual try to attack
 val1:= 0;
 for i:= 0 to 4 do
     begin
-    t:= RateShove(Me, trunc(x) + 10 * hwSign(Targ.X - x), trunc(y) - 20 * i - 5, 10, 30, 40, hwSign(Me^.dX)*0.45, -0.9, 1);
+    t:= RateShove(Me, trunc(x) + 10 * hwSignf(Targ.X - x), trunc(y) - 20 * i - 5, 10, 30, 40, hwSign(Me^.dX)*0.45, -0.9, afTrackFall);
     if (val1 < 0) or (t < 0) then val1:= BadTurn
     else if t > 0 then val1:= t;
     end;
@@ -693,7 +698,7 @@
 val2:= 0;
 for i:= 0 to 4 do
     begin
-    t:= RateShove(Me, trunc(x) + 10 * hwSign(Targ.X - x), trunc(y) - 20 * i - 5, 10, 30, 40, -hwSign(Me^.dX)*0.45, -0.9, 1);
+    t:= RateShove(Me, trunc(x) + 10 * hwSignf(Targ.X - x), trunc(y) - 20 * i - 5, 10, 30, 40, -hwSign(Me^.dX)*0.45, -0.9, afTrackFall);
     if (val2 < 0) or (t < 0) then val2:= BadTurn
     else if t > 0 then val2:= t;
     end;
@@ -704,35 +709,53 @@
     ap.Angle:= -hwSign(Me^.dX);
     TestFirePunch:= val2
     end
-else TestFirePunch:= BadTurn;*)
+else TestFirePunch:= BadTurn;
 end;
 
+
 function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var i, valueResult: LongInt;
+var valueResult, v1, v2: LongInt;
     x, y: real;
 begin
 Level:= Level; // avoid compiler hint
 ap.ExplR:= 0;
 ap.Time:= 0;
 ap.Power:= 1;
-ap.Angle:= 0;
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
-if (Abs(trunc(x) - Targ.X) > 25)
-or (Abs(trunc(y) - 50 - Targ.Y) > 50) then
+
+// check left direction
+{first RateShove checks fartherest of two whip's AmmoShove attacks 
+to encourage distant attacks (damaged hog is excluded from view of second 
+RateShove call)}
+v1:= RateShove(Me, trunc(x) - 15, trunc(y)
+        , 30, 30, 40
+        , -1, -0.8, afTrackFall or afSetSkip);
+v1:= v1 +
+    RateShove(Me, trunc(x), trunc(y)
+        , 30, 30, 40
+        , -1, -0.8, afTrackFall);
+// now try opposite direction
+v2:= RateShove(Me, trunc(x) + 15, trunc(y)
+        , 30, 30, 40
+        , 1, -0.8, afTrackFall or afSetSkip);
+v2:= v2 +
+    RateShove(Me, trunc(x), trunc(y)
+        , 30, 30, 40
+        , 1, -0.8, afTrackFall);
+
+if (v2 > v1) 
+    or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
     begin
-    if TestColl(trunc(x), trunc(y) - 16, 6)
-    and (RateShove(Me, trunc(x) + LongWord(10 * hwSign(Me^.dX)), trunc(y) - 40, 30, 30, 40, hwSign(Me^.dX), -0.8,  1) = 0) then
-        valueResult:= Succ(BadTurn)
-    else
-        valueResult:= BadTurn;
-    exit(valueResult);
+    ap.Angle:= 1;
+    valueResult:= v2
+    end
+else 
+    begin
+    ap.Angle:= -1;
+    valueResult:= v1
     end;
-
-valueResult:= 0;
-for i:= 0 to 4 do
-    valueResult:= valueResult + RateShove(Me, trunc(x) + LongWord(10 * hwSignf(Targ.X - x)),
-                                    trunc(y) - LongWord(20 * i) - 5, 10, 30, 40, hwSign(Me^.dX), -0.8, 1);
+   
 if valueResult <= 0 then
     valueResult:= BadTurn
 else
@@ -750,10 +773,7 @@
 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);
+rate:= RateHammer(Me);
 if rate = 0 then
     rate:= BadTurn;
 TestHammer:= rate;
@@ -772,6 +792,7 @@
 if (Level > 3) then
     exit(BadTurn);
 
+ap.Angle:= 0;
 ap.AttackPutX:= Targ.X;
 ap.AttackPutY:= Targ.Y;
 
--- a/hedgewars/uAIMisc.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uAIMisc.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -24,9 +24,15 @@
 
 const MAXBONUS = 1024;
 
+      afTrackFall  = $00000001;
+      afErasesLand = $00000002;
+      afSetSkip    = $00000004;
+
+
 type TTarget = record
     Point: TPoint;
     Score: LongInt;
+    skip: boolean;
     end;
 TTargets = record
     Count: Longword;
@@ -100,6 +106,7 @@
                     begin
                     with Targets.ar[Targets.Count], Hedgehogs[i] do
                         begin
+                        skip:= false;
                         Point.X:= hwRound(Gear^.X);
                         Point.Y:= hwRound(Gear^.Y);
                         if Clan <> CurrentTeam^.Clan then
@@ -122,12 +129,14 @@
 
 procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
 begin
-bonuses.ar[bonuses.Count].x:= x;
-bonuses.ar[bonuses.Count].y:= y;
-bonuses.ar[bonuses.Count].Radius:= r;
-bonuses.ar[bonuses.Count].Score:= s;
-inc(bonuses.Count);
-TryDo(bonuses.Count <= MAXBONUS, 'Bonuses overflow', true)
+if(bonuses.Count < MAXBONUS) then
+    begin
+    bonuses.ar[bonuses.Count].x:= x;
+    bonuses.ar[bonuses.Count].y:= y;
+    bonuses.ar[bonuses.Count].Radius:= r;
+    bonuses.ar[bonuses.Count].Score:= s;
+    inc(bonuses.Count);
+    end;
 end;
 
 procedure FillBonuses(isAfterAttack: boolean);
@@ -155,7 +164,7 @@
                     
             gtExplosives:
             if isAfterAttack then
-                AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 75, -60+Gear^.Health);
+                AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 75, -60 + Gear^.Health);
                 
             gtSMine:
                 AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 50, -30);
@@ -203,7 +212,7 @@
         r:= Radius;
         if abs(gX-X)+abs(gY-Y) < Radius then
             r:= trunc(sqrt(sqr(gX - X)+sqr(gY - Y)));
-        if r < 15 then
+        if r < 20 then
                 inc(rate, Score * Radius)
         else if r < Radius then
                 inc(rate, Score * (Radius - r))
@@ -327,7 +336,6 @@
     end;
 end;
 
-// Flags are not defined yet but 1 for checking drowning and 2 for assuming land erasure.
 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
 begin
     RateExplosion:= RateExplosion(Me, x, y, r, 0);
@@ -349,7 +357,7 @@
     end;
 // rate explosion
 dmgBase:= r + cHHRadius div 2;
-if (Flags and 2 <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r
+if (Flags and afErasesLand <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r
 else erasure:= 0;
 for i:= 0 to Targets.Count do
     with Targets.ar[i] do
@@ -360,7 +368,7 @@
 
         if dmg > 0 then
             begin
-            if Flags and 1 <> 0 then
+            if Flags and afTrackFall <> 0 then
                 begin
                 dX:= 0.005 * dmg + 0.01;
                 dY:= dX;
@@ -396,6 +404,9 @@
 rate:= 0;
 for i:= 0 to Pred(Targets.Count) do
     with Targets.ar[i] do
+      if skip then 
+        if (Flags and afSetSkip = 0) then skip:= false else {still skip}
+      else  
         begin
         dmg:= 0;
         if abs(Point.x - x) + abs(Point.y - y) < r then
@@ -405,8 +416,9 @@
             end;
         if dmg > 0 then
             begin
-            if (Flags and 1 <> 0) then 
-                fallDmg:= trunc(TraceShoveFall(Me, Point.x, Point.y-2, dX, dY) * dmgMod);
+            if (Flags and afSetSkip <> 0) then skip:= true;
+            if (Flags and afTrackFall <> 0) then 
+                fallDmg:= trunc(TraceShoveFall(Me, Point.x, Point.y - 2, dX, dY) * dmgMod);
             if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
                 if Score > 0 then
                     inc(rate, KillScore + Score div 10)   // Add a bit of a bonus for bigger hog drownings
@@ -602,114 +614,124 @@
 GoInfo.Ticks:= 0;
 GoInfo.FallPix:= 0;
 GoInfo.JumpType:= jmpNone;
+
 repeat
-pX:= hwRound(Gear^.X);
-pY:= hwRound(Gear^.Y);
-if pY + cHHRadius >= cWaterLine then
-    exit(false);
-if (Gear^.State and gstMoving) <> 0 then
-    begin
-    inc(GoInfo.Ticks);
-    Gear^.dY:= Gear^.dY + cGravity;
-    if Gear^.dY > _0_4 then
+    pX:= hwRound(Gear^.X);
+    pY:= hwRound(Gear^.Y);
+    if pY + cHHRadius >= cWaterLine then
+        exit(false);
+        
+    // hog is falling    
+    if (Gear^.State and gstMoving) <> 0 then
         begin
-        Goinfo.FallPix:= 0;
-        HHJump(AltGear, jmpLJump, GoInfo); // try ljump instead of fall with damage
-        exit(false)
-        end;
-    Gear^.Y:= Gear^.Y + Gear^.dY;
-    if hwRound(Gear^.Y) > pY then
-        inc(GoInfo.FallPix);
-    if TestCollisionYwithGear(Gear, 1) <> 0 then
-        begin
-        inc(GoInfo.Ticks, 410);
-        Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping);
-        Gear^.dY:= _0;
-        HHJump(AltGear, jmpLJump, GoInfo); // try ljump instead of fall
-        HHGo:= true;
-        exit(false)
+        inc(GoInfo.Ticks);
+        Gear^.dY:= Gear^.dY + cGravity;
+        if Gear^.dY > _0_4 then
+            begin
+            Goinfo.FallPix:= 0;
+            // try ljump instead of fall with damage
+            HHJump(AltGear, jmpLJump, GoInfo); 
+            exit(false)
+            end;
+        Gear^.Y:= Gear^.Y + Gear^.dY;
+        if hwRound(Gear^.Y) > pY then
+            inc(GoInfo.FallPix);
+        if TestCollisionYwithGear(Gear, 1) <> 0 then
+            begin
+            inc(GoInfo.Ticks, 410);
+            Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping);
+            Gear^.dY:= _0;
+            // try ljump instead of fall
+            HHJump(AltGear, jmpLJump, GoInfo);
+            exit(true)
+            end;
+        continue
         end;
-    continue
-    end;
-    if (Gear^.Message and gmLeft  )<>0 then
-        Gear^.dX:= -cLittle
-    else
-        if (Gear^.Message and gmRight )<>0 then
-            Gear^.dX:=  cLittle
+        
+        // usual walk
+        if (Gear^.Message and gmLeft) <> 0 then
+            Gear^.dX:= -cLittle
         else
-            exit(false);
-    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
-        begin
-        if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
+            if (Gear^.Message and gmRight) <> 0 then
+                Gear^.dX:=  cLittle
+            else
+                exit(false);
+                
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
+            Gear^.Y:= Gear^.Y - _1;
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
+            Gear^.Y:= Gear^.Y - _1;
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
             Gear^.Y:= Gear^.Y - _1;
-            
-        if not (TestCollisionXwithXYShift(Gear, _0, -5, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
             Gear^.Y:= Gear^.Y - _1;
-            
-        if not (TestCollisionXwithXYShift(Gear, _0, -4, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
+            Gear^.Y:= Gear^.Y - _1;
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+            begin
             Gear^.Y:= Gear^.Y - _1;
-            
-        if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-            
-        if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
+            if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+                Gear^.Y:= Gear^.Y + _6
+            end else Gear^.Y:= Gear^.Y + _5 else
+            end else Gear^.Y:= Gear^.Y + _4 else
+            end else Gear^.Y:= Gear^.Y + _3 else
+            end else Gear^.Y:= Gear^.Y + _2 else
+            end else Gear^.Y:= Gear^.Y + _1
+            end;
+
+        if not TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+        begin
+            Gear^.X:= Gear^.X + int2hwFloat(hwSign(Gear^.dX));
+            inc(GoInfo.Ticks, cHHStepTicks)
         end;
 
-    if not TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
-    begin
-        Gear^.X:= Gear^.X + int2hwFloat(hwSign(Gear^.dX));
-        inc(GoInfo.Ticks, cHHStepTicks)
-    end;
+        // too scared to reformat this part
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
+            
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
+            
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
 
-    // too scared to reformat this part
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
-        
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
-        
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
 
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
 
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
-
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y + _1;
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y + _1;
 
-    if TestCollisionYwithGear(Gear, 1) = 0 then
-        begin
-        Gear^.Y:= Gear^.Y - _6;
-        Gear^.dY:= _0;
-        Gear^.State:= Gear^.State or gstMoving
+        if TestCollisionYwithGear(Gear, 1) = 0 then
+            begin
+            Gear^.Y:= Gear^.Y - _6;
+            Gear^.dY:= _0;
+            Gear^.State:= Gear^.State or gstMoving
+            end
+        end
+        end
         end
-    end
-    end
-    end
-    end
-    end
-    end;
-if (pX <> hwRound(Gear^.X)) and ((Gear^.State and gstMoving) = 0) then
-    exit(true)
+        end
+        end
+        end;
+        // we have moved for 1 px
+        if (pX <> hwRound(Gear^.X)) and ((Gear^.State and gstMoving) = 0) then
+            exit(true)
 until (pX = hwRound(Gear^.X)) and (pY = hwRound(Gear^.Y)) and ((Gear^.State and gstMoving) = 0);
+
 HHJump(AltGear, jmpHJump, GoInfo);
 end;
 
--- a/hedgewars/uCommandHandlers.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uCommandHandlers.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -86,11 +86,11 @@
 end;
 
 procedure chCheckProto(var s: shortstring);
-var i: LongInt;
+var i, c: LongInt;
 begin
     if isDeveloperMode then
         begin
-        val(s, i);
+        val(s, i, c);
         TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
         TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
         end
@@ -683,104 +683,102 @@
 
 procedure chMapGen(var s: shortstring);
 begin
-val(s, cMapGen)
+cMapGen:= StrToInt(s)
 end;
 
 procedure chTemplateFilter(var s: shortstring);
 begin
-val(s, cTemplateFilter)
+cTemplateFilter:= StrToInt(s)
 end;
 
 procedure chInactDelay(var s: shortstring);
 begin
-val(s, cInactDelay)
+cInactDelay:= StrToInt(s)
 end;
 
 procedure chReadyDelay(var s: shortstring);
 begin
-val(s, cReadyDelay)
+cReadyDelay:= StrToInt(s)
 end;
 
 procedure chCaseFactor(var s: shortstring);
 begin
-val(s, cCaseFactor)
+cCaseFactor:= StrToInt(s)
 end;
 
 procedure chHealthCaseProb(var s: shortstring);
 begin
-val(s, cHealthCaseProb)
+cHealthCaseProb:= StrToInt(s)
 end;
 
 procedure chHealthCaseAmount(var s: shortstring);
 begin
-val(s, cHealthCaseAmount)
+cHealthCaseAmount:= StrToInt(s)
 end;
 
 procedure chSuddenDTurns(var s: shortstring);
 begin
-val(s, cSuddenDTurns)
+cSuddenDTurns:= StrToInt(s)
 end;
 
 procedure chWaterRise(var s: shortstring);
 begin
-val(s, cWaterRise)
+cWaterRise:= StrToInt(s)
 end;
 
 procedure chHealthDecrease(var s: shortstring);
 begin
-val(s, cHealthDecrease)
+cHealthDecrease:= StrToInt(s)
 end;
 
 procedure chDamagePercent(var s: shortstring);
 begin
-val(s, cDamagePercent)
+cDamagePercent:= StrToInt(s)
 end;
 
 procedure chRopePercent(var s: shortstring);
 begin
-val(s, cRopePercent)
+cRopePercent:= StrToInt(s)
 end;
 
 procedure chGetAwayTime(var s: shortstring);
 begin
-val(s, cGetAwayTime)
+cGetAwayTime:= StrToInt(s)
 end;
 
 procedure chMineDudPercent(var s: shortstring);
 begin
-val(s, cMineDudPercent)
+cMineDudPercent:= StrToInt(s)
 end;
 
 procedure chLandMines(var s: shortstring);
 begin
-val(s, cLandMines)
+cLandMines:= StrToInt(s)
 end;
 
 procedure chExplosives(var s: shortstring);
 begin
-val(s, cExplosives)
+cExplosives:= StrToInt(s)
 end;
 
 procedure chGameFlags(var s: shortstring);
 begin
-val(s, GameFlags)
+GameFlags:= StrToInt(s)
 end;
 
 procedure chHedgehogTurnTime(var s: shortstring);
 begin
-val(s, cHedgehogTurnTime)
+cHedgehogTurnTime:= StrToInt(s)
 end;
 
 procedure chMinesTime(var s: shortstring);
 begin
-val(s, cMinesTime)
+cMinesTime:= StrToInt(s)
 end;
 
 procedure chFastUntilLag(var s: shortstring);
-var i: LongInt;
 begin
-val(s, i);
-fastUntilLag:= i <> 0
+fastUntilLag:= StrToInt(s) <> 0
 end;
 
 procedure initModule;
--- a/hedgewars/uConsole.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uConsole.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -49,8 +49,10 @@
 end;
 
 procedure WriteToConsole(s: shortstring);
+{$IFNDEF NOCONSOLE}
 var Len: LongInt;
     done: boolean;
+{$ENDIF}
 begin
 {$IFNDEF NOCONSOLE}
 AddFileLog('[Con] ' + s);
@@ -83,7 +85,7 @@
 {$IFNDEF NOCONSOLE}
 WriteToConsole(s);
 {$IFNDEF ANDROID}
-WriteLn(stderr);
+WriteLn(stderr, '');
 inc(CurrLine);
 if CurrLine = cLinesCount then
     CurrLine:= 0;
--- a/hedgewars/uDebug.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uDebug.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -47,9 +47,13 @@
 end;
 
 procedure SDLTry(Assert: boolean; isFatal: boolean);
+var s: shortstring;
 begin
 if not Assert then
-    OutError(SDL_GetError, isFatal)
+    begin
+    s:= SDL_GetError();
+    OutError(s, isFatal)
+    end
 end;
 
 end.
--- a/hedgewars/uGears.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uGears.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -779,6 +779,7 @@
             Gear^.Active:= true;
             Gear^.State:= Gear^.State or gstMoving;
 
+            // move the gear upwards a bit to throw it over tiny obstacles at start
             if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
                 begin
                 if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
@@ -825,7 +826,7 @@
                                 if PlacingHogs then
                                     Unplaced:= true
                                 else
-                                    FindPlace(Gear, false, t, t + LAND_WIDTH div 2);// could make Gear == nil;
+                                    FindPlace(Gear, false, t, t + LAND_WIDTH div 2, true);// could make Gear == nil;
                                 if Gear <> nil then
                                     begin
                                     Gear^.Pos:= GetRandom(49);
@@ -858,7 +859,7 @@
         if PlacingHogs then
             ar[i]^.Unplaced:= true
         else
-            FindPlace(ar[i]^.Gear, false, 0, LAND_WIDTH);
+            FindPlace(ar[i]^.Gear, false, 0, LAND_WIDTH, true);
         if ar[i]^.Gear <> nil then
             begin
             ar[i]^.Gear^.dX.isNegative:= hwRound(ar[i]^.Gear^.X) > LAND_WIDTH div 2;
--- a/hedgewars/uGearsHedgehog.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uGearsHedgehog.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -723,26 +723,32 @@
     DeleteCI(Gear); // must be after exit!! (see previous line)
 
     Gear^.Hedgehog^.visStepPos:= (Gear^.Hedgehog^.visStepPos + 1) and 7;
-    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+        begin
+        Gear^.Y:= Gear^.Y - _1;
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+        begin
+        Gear^.Y:= Gear^.Y - _1;
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+        begin
+        Gear^.Y:= Gear^.Y - _1;
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
         begin
-        if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -5, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -4, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
-        if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
-        or (TestCollisionYwithGear(Gear, -1) <> 0)) then
-            Gear^.Y:= Gear^.Y - _1;
+        Gear^.Y:= Gear^.Y - _1;
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+        begin
+        Gear^.Y:= Gear^.Y - _1;
+    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then if (TestCollisionYwithGear(Gear, -1) = 0) then
+        begin
+        Gear^.Y:= Gear^.Y - _1;
+        if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
+            Gear^.Y:= Gear^.Y + _6
+        end else Gear^.Y:= Gear^.Y + _5 else
+        end else Gear^.Y:= Gear^.Y + _4 else
+        end else Gear^.Y:= Gear^.Y + _3 else
+        end else Gear^.Y:= Gear^.Y + _2 else
+        end else Gear^.Y:= Gear^.Y + _1
         end;
 
     if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
--- a/hedgewars/uGearsList.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uGearsList.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -246,7 +246,8 @@
                 gear^.ImpactSound:= sndGraveImpact;
                 gear^.nImpactSounds:= 1;
                 gear^.Radius:= 16;
-                gear^.Elasticity:= _0_3
+                gear^.Elasticity:= _0_3;
+                gear^.Timer:= 0
                 end;
   gtExplosives: begin
                 gear^.ImpactSound:= sndGrenadeImpact;
@@ -545,7 +546,8 @@
         inc(KilledHHs);
         RecountTeamHealth(team);
         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Effects[heResurrectable] <> 0)  and
-        (Gear^.Hedgehog^.Effects[heResurrectable] = 0) then
+        //(Gear^.Hedgehog^.Effects[heResurrectable] = 0) then
+        (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan) then
             with CurrentHedgehog^ do 
                 begin
                 inc(Team^.stats.AIKills);
--- a/hedgewars/uGearsRender.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uGearsRender.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -319,8 +319,8 @@
                 // reached edge of land. assume infinite beam. Extend it way out past camera
                 if ((ty and LAND_HEIGHT_MASK) <> 0) or ((tx and LAND_WIDTH_MASK) <> 0) then
                     begin
-                    tx:= round(lx + ax * (LAND_WIDTH div 4));
-                    ty:= round(ly + ay * (LAND_WIDTH div 4));
+                    tx:= round(lx + ax * (LAND_WIDTH div 2));
+                    ty:= round(ly + ay * (LAND_WIDTH div 2));
                     end;
 
                 //if (abs(lx-tx)>8) or (abs(ly-ty)>8) then
@@ -987,7 +987,9 @@
                            DrawSpriteRotated(sprSMineOn, x, y, 0, Gear^.DirAngle)
                        else DrawSpriteRotated(sprMineDead, x, y, 0, Gear^.DirAngle);
                        
-            gtCase: if ((Gear^.Pos and posCaseAmmo) <> 0) then
+            gtCase: begin
+                    if Gear^.Timer < 255 then Tint($FF, $FF, $FF, Gear^.Timer);
+                    if ((Gear^.Pos and posCaseAmmo) <> 0) then
                         begin
                         i:= (GameTicks shr 6) mod 64;
                         if i > 18 then
@@ -1009,6 +1011,8 @@
                         i:= i mod 12;
                         DrawSprite(sprUtility, x - 24, y - 24, i);
                         end;
+                    if Gear^.Timer < 255 then Tint($FF, $FF, $FF, $FF);
+                    end;
       gtExplosives: begin
                     if ((Gear^.State and gstDrowning) <> 0) then
                         DrawSprite(sprExplosivesRoll, x - 24, y - 24, 0)
--- a/hedgewars/uGearsUtils.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uGearsUtils.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -452,7 +452,8 @@
     gear^.Damage := 0;
     gear^.Health := gear^.Hedgehog^.InitialHealth;
     gear^.Hedgehog^.Effects[hePoisoned] := 0;
-    if CurrentHedgehog^.Effects[heResurrectable] = 0 then
+    if (CurrentHedgehog^.Effects[heResurrectable] = 0) or ((CurrentHedgehog^.Effects[heResurrectable] <> 0)
+          and (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan)) then
         with CurrentHedgehog^ do 
             begin
             inc(Team^.stats.AIKills);
@@ -474,6 +475,7 @@
     if gear <> nil then
         begin
         AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion);
+        PlaySound(sndWarp);
         RenderHealth(gear^.Hedgehog^);
         ScriptCall('onGearResurrect', gear^.uid);
         gear^.State := gstWait;
--- a/hedgewars/uInputHandler.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uInputHandler.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -45,7 +45,7 @@
 implementation
 uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug;
 
-var tkbd: TKeyboardState;
+var tkbd: array[0..cKeyMaxIndex] of boolean;
     quitKeyCode: Byte;
     KeyNames: array [0..cKeyMaxIndex] of string[15];
     CurrentBinds: TBinds;
@@ -64,35 +64,40 @@
     Trusted: boolean;
     s      : string;
 begin
+
+if not(tkbd[code] xor KeyDown) then exit;
+tkbd[code]:= KeyDown;
+
+
 hideAmmoMenu:= false;
 Trusted:= (CurrentTeam <> nil)
           and (not CurrentTeam^.ExtDriven)
           and (CurrentHedgehog^.BotLevel = 0);
 
-tkbd[code]:= ord(KeyDown);
+
 
 // ctrl/cmd + q to close engine and frontend
 if(KeyDown and (code = quitKeyCode)) then
     begin
 {$IFDEF DARWIN}
-    if ((tkbd[KeyNameToCode('left_meta')] = 1) or (tkbd[KeyNameToCode('right_meta')] = 1)) then
+    if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
 {$ELSE}
-    if ((tkbd[KeyNameToCode('left_ctrl')] = 1) or (tkbd[KeyNameToCode('right_ctrl')] = 1)) then
+    if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
 {$ENDIF}
         ParseCommand('halt', true);    
     end;
 
 if CurrentBinds[code][0] <> #0 then
     begin
-    if (code > 3) and (KeyDown) and not ((CurrentBinds[code] = 'put') or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true;
+    if (code > 3) and KeyDown and not ((CurrentBinds[code] = 'put') or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true;
 
-    if (KeyDown) then
+    if KeyDown then
         begin
         ParseCommand(CurrentBinds[code], Trusted);
         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
             ParseCommand('gencmd R', true)
         end
-    else if (CurrentBinds[code][1] = '+') and not KeyDown then
+    else if (CurrentBinds[code][1] = '+') then
         begin
         s:= CurrentBinds[code];
         s[1]:= '-';
@@ -101,7 +106,6 @@
             ParseCommand('gencmd R', true)
         end;
     end
-
 end;
 
 procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
@@ -129,7 +133,7 @@
 var t: LongInt;
 begin
 for t:= 0 to cKeyMaxIndex do
-    if(tkbd[t] <> 0) then
+    if tkbd[t] then
         ProcessKey(t, False);
 end;
 
@@ -235,11 +239,19 @@
 end;
 
 procedure SetBinds(var binds: TBinds);
+{$IFNDEF MOBILE}
+var
+    t: LongInt;
+{$ENDIF}
 begin
 {$IFDEF MOBILE}
     binds:= binds; // avoid hint
     CurrentBinds:= DefaultBinds;
 {$ELSE}
+for t:= 0 to cKeyMaxIndex do
+    if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
+        ProcessKey(t, False);
+
     CurrentBinds:= binds;
 {$ENDIF}
 end;
@@ -251,10 +263,10 @@
 
 procedure FreezeEnterKey;
 begin
-    tkbd[3]:= 1;
-    tkbd[13]:= 1;
-    tkbd[27]:= 1;
-    tkbd[271]:= 1;
+    tkbd[3]:= True;
+    tkbd[13]:= True;
+    tkbd[27]:= True;
+    tkbd[271]:= True;
 end;
 
 var Controller: array [0..5] of PSDL_Joystick;
@@ -279,7 +291,7 @@
     begin
     for j:= 0 to pred(ControllerNumControllers) do
         begin
-        WriteLnToConsole('Using game controller: ' + SDL_JoystickName(j));
+        WriteLnToConsole('Using game controller: ' + shortstring(SDL_JoystickName(j)));
         Controller[j]:= SDL_JoystickOpen(j);
         if Controller[j] = nil then
             WriteLnToConsole('* Failed to open game controller!')
--- a/hedgewars/uLand.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uLand.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -674,7 +674,7 @@
                 end
     end;
 
-UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT);
+UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false);
 end;
 
 procedure GenPreview(out Preview: TPreview);
@@ -750,9 +750,9 @@
 
 procedure freeModule;
 begin
-    Land:= nil;
-    LandPixels:= nil;
-    LandDirty:= nil;
+    SetLength(Land, 0, 0);
+    SetLength(LandPixels, 0, 0);
+    SetLength(LandDirty, 0, 0);
 end;
 
 end.
--- a/hedgewars/uLandGraphics.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uLandGraphics.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -39,6 +39,7 @@
 procedure ChangeRoundInLand(X, Y, Radius: LongInt; doSet: boolean);
 function  LandBackPixel(x, y: LongInt): LongWord;
 procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword);
+procedure DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword);
 
 function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; indestructible: boolean): boolean;
 
@@ -462,7 +463,7 @@
 dx:= Min(X + Radius + 1, LAND_WIDTH) - tx;
 ty:= Max(Y - Radius - 1, 0);
 dy:= Min(Y + Radius + 1, LAND_HEIGHT) - ty;
-UpdateLandTexture(tx, dx, ty, dy);
+UpdateLandTexture(tx, dx, ty, dy, false);
 DrawExplosion:= cnt
 end;
 
@@ -514,7 +515,7 @@
     end;
 
 
-UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT)
+UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false)
 end;
 
 //
@@ -664,7 +665,7 @@
 ddx:= Min(stX + HalfWidth * 2 + 4 + abs(hwRound(dX * ticks)), LAND_WIDTH) - tx;
 ddy:= Min(stY + HalfWidth * 2 + 4 + abs(hwRound(dY * ticks)), LAND_HEIGHT) - ty;
 
-UpdateLandTexture(tx, ddx, ty, ddy)
+UpdateLandTexture(tx, ddx, ty, ddy, false)
 end;
 
 function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; indestructible: boolean): boolean;
@@ -752,7 +753,7 @@
 w:= Min(cpX + Image^.w, LAND_WIDTH) - x;
 y:= Max(cpY, topY);
 h:= Min(cpY + Image^.h, LAND_HEIGHT) - y;
-UpdateLandTexture(x, w, y, h)
+UpdateLandTexture(x, w, y, h, true)
 end;
 
 function Despeckle(X, Y: LongInt): boolean;
@@ -954,7 +955,7 @@
                                 end;
                     end;
                 if updateBlock then
-                    UpdateLandTexture(tx, 32, ty, 32);
+                    UpdateLandTexture(tx, 32, ty, 32, false);
                 LandDirty[y, x]:= 2;
                 end;
             end;
@@ -1056,4 +1057,104 @@
     end
 end;
 
+procedure DrawDots(x, y, xx, yy: Longint; Color: Longword); inline;
+begin
+    if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) then Land[y + yy, x + xx]:= Color;
+    if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) then Land[y - yy, x + xx]:= Color;
+    if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) then Land[y + yy, x - xx]:= Color;
+    if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) then Land[y - yy, x - xx]:= Color;
+    if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) then Land[y + xx, x + yy]:= Color;
+    if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) then Land[y - xx, x + yy]:= Color;
+    if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) then Land[y + xx, x - yy]:= Color;
+    if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) then Land[y - xx, x - yy]:= Color;
+end;
+
+procedure DrawLines(X1, Y1, X2, Y2, XX, YY: LongInt; color: Longword);
+var
+  eX, eY, dX, dY: LongInt;
+  i, sX, sY, x, y, d: LongInt;
+  f: boolean;
+begin
+    eX:= 0;
+    eY:= 0;
+    dX:= X2 - X1;
+    dY:= Y2 - Y1;
+
+    if (dX > 0) then
+        sX:= 1
+    else
+        if (dX < 0) then
+            begin
+            sX:= -1;
+            dX:= -dX
+            end
+        else
+            sX:= dX;
+
+    if (dY > 0) then
+        sY:= 1
+    else
+        if (dY < 0) then
+            begin
+            sY:= -1;
+            dY:= -dY
+            end
+        else
+            sY:= dY;
+
+    if (dX > dY) then
+        d:= dX
+    else
+        d:= dY;
+
+    x:= X1;
+    y:= Y1;
+
+    for i:= 0 to d do
+        begin
+        inc(eX, dX);
+        inc(eY, dY);
+
+        f:= eX > d;
+        if f then
+            begin
+            dec(eX, d);
+            inc(x, sX);
+            DrawDots(x, y, xx, yy, color)
+            end;
+        if (eY > d) then
+            begin
+            dec(eY, d);
+            inc(y, sY);
+            f:= true;
+            DrawDots(x, y, xx, yy, color)
+            end;
+
+        if not f then
+            DrawDots(x, y, xx, yy, color)
+        end
+end;
+
+procedure DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword);
+var dx, dy, d: LongInt;
+begin
+    dx:= 0;
+    dy:= Radius;
+    d:= 3 - 2 * Radius;
+    while (dx < dy) do
+        begin
+        DrawLines(x1, y1, x2, y2, dx, dy, color);
+        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
+        DrawLines(x1, y1, x2, y2, dx, dy, color);
+end;
+
 end.
--- a/hedgewars/uLandPainted.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uLandPainted.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -43,78 +43,6 @@
 
 var pointsListHead, pointsListLast: PPointEntry;
 
-procedure DrawLineOnLand(X1, Y1, X2, Y2, radius: LongInt; color: Longword);
-var  eX, eY, dX, dY: LongInt;
-    i, sX, sY, x, y, d: LongInt;
-    b: boolean;
-    len: LongWord;
-begin
-    len:= 0;
-    if (X1 = X2) and (Y1 = Y2) then
-        begin
-        exit
-        end;
-    eX:= 0;
-    eY:= 0;
-    dX:= X2 - X1;
-    dY:= Y2 - Y1;
-
-    if (dX > 0) then
-        sX:= 1
-    else
-        if (dX < 0) then
-            begin
-            sX:= -1;
-            dX:= -dX
-            end
-        else
-            sX:= dX;
-
-    if (dY > 0) then
-        sY:= 1
-    else
-        if (dY < 0) then
-            begin
-            sY:= -1;
-            dY:= -dY
-            end
-        else
-            sY:= dY;
-
-        if (dX > dY) then
-            d:= dX
-        else
-            d:= dY;
-
-        x:= X1;
-        y:= Y1;
-
-        for i:= 0 to d do
-            begin
-            inc(eX, dX);
-            inc(eY, dY);
-            b:= false;
-            if (eX > d) then
-                begin
-                dec(eX, d);
-                inc(x, sX);
-                b:= true
-                end;
-            if (eY > d) then
-                begin
-                dec(eY, d);
-                inc(y, sY);
-                b:= true
-                end;
-            if b then
-                begin
-                inc(len);
-                if (len mod 4) = 0 then
-                    FillRoundInLand(X, Y, radius, color)
-                end
-        end
-end;
-
 procedure chDraw(var s: shortstring);
 var rec: PointRec;
     prec: ^PointRec;
@@ -173,7 +101,8 @@
             else
             begin
             AddFileLog('[DRAW] Line to: ('+inttostr(pe^.point.X)+','+inttostr(pe^.point.Y)+'), radius = '+inttostr(radius));
-            DrawLineOnLand(prevPoint.X, prevPoint.Y, pe^.point.X, pe^.point.Y, radius, color);
+            DrawThickLine(prevPoint.X, prevPoint.Y, pe^.point.X, pe^.point.Y, radius, color);
+            FillRoundInLand(pe^.point.X, pe^.point.Y, radius, color)
             end;
 
         prevPoint:= pe^.point;
--- a/hedgewars/uLandTexture.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uLandTexture.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -24,17 +24,17 @@
 
 procedure initModule;
 procedure freeModule;
-procedure UpdateLandTexture(X, Width, Y, Height: LongInt);
+procedure UpdateLandTexture(X, Width, Y, Height: LongInt; landAdded: boolean);
 procedure DrawLand(dX, dY: LongInt);
 procedure ResetLand;
 
 implementation
 uses uConsts, GLunit, uTypes, uVariables, uTextures, uDebug, uRender;
 
-const TEXSIZE = 512;
+const TEXSIZE = 128;
 
 type TLandRecord = record
-            shouldUpdate: boolean;
+            shouldUpdate, landAdded: boolean;
             tex: PTexture;
             end;
 
@@ -62,7 +62,7 @@
 Pixels2:= @tmpPixels
 end;
 
-procedure UpdateLandTexture(X, Width, Y, Height: LongInt);
+procedure UpdateLandTexture(X, Width, Y, Height: LongInt; landAdded: boolean);
 var tx, ty: Longword;
 begin
     if (Width <= 0) or (Height <= 0) then
@@ -75,16 +75,24 @@
     if (cReducedQuality and rqBlurryLand) = 0 then
         for ty:= Y div TEXSIZE to (Y + Height - 1) div TEXSIZE do
             for tx:= X div TEXSIZE to (X + Width - 1) div TEXSIZE do
-                LandTextures[tx, ty].shouldUpdate:= true
+                begin
+                LandTextures[tx, ty].shouldUpdate:= true;
+                LandTextures[tx, ty].landAdded:= landAdded
+                end
     else
         for ty:= (Y div TEXSIZE) div 2 to ((Y + Height - 1) div TEXSIZE) div 2 do
             for tx:= (X div TEXSIZE) div 2 to ((X + Width - 1) div TEXSIZE) div 2 do
+                begin
                 LandTextures[tx, ty].shouldUpdate:= true;
+                LandTextures[tx, ty].landAdded:= landAdded
+                end
 end;
 
 procedure RealLandTexUpdate;
-var x, y: LongWord;
+var x, y, ty, tx, lx, ly : LongWord;
+    isEmpty: boolean;
 begin
+(*
 if LandTextures[0, 0].tex = nil then
     for x:= 0 to LANDTEXARW -1 do
         for y:= 0 to LANDTEXARH - 1 do
@@ -95,14 +103,67 @@
                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, tpHigh);
                 end
 else
+*)
     for x:= 0 to LANDTEXARW -1 do
         for y:= 0 to LANDTEXARH - 1 do
             with LandTextures[x, y] do
                 if shouldUpdate then
                     begin
                     shouldUpdate:= false;
-                    glBindTexture(GL_TEXTURE_2D, tex^.atlas^.id);
-                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXSIZE, TEXSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, Pixels(x,y));
+                    isEmpty:= not landAdded;
+                    landAdded:= false;
+                    ty:= 0;
+                    tx:= 1;
+                    ly:= y * TEXSIZE;
+                    lx:= x * TEXSIZE;
+                    // first check edges
+                    while isEmpty and (ty < TEXSIZE) do
+                        begin
+                        isEmpty:= LandPixels[ly + ty, lx] and AMask = 0;
+                        if isEmpty then isEmpty:= LandPixels[ly + ty, lx + TEXSIZE-1] and AMask = 0;
+                        inc(ty)
+                        end;
+                    while isEmpty and (tx < TEXSIZE-1) do
+                        begin
+                        isEmpty:= LandPixels[ly, lx + tx] and AMask = 0;
+                        if isEmpty then isEmpty:= LandPixels[ly + TEXSIZE-1, lx + tx] and AMask = 0;
+                        inc(tx)
+                        end;
+                    // then search every other remaining. does this sort of stuff defeat compiler opts?
+                    ty:= 2;
+                    while isEmpty and (ty < TEXSIZE-1) do
+                        begin
+                        tx:= 2;
+                        while isEmpty and (tx < TEXSIZE-1) do
+                            begin
+                            isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0;
+                            inc(tx,2)
+                            end;
+                        inc(ty,2);
+                        end;
+                    // and repeat
+                    ty:= 1;
+                    while isEmpty and (ty < TEXSIZE-1) do
+                        begin
+                        tx:= 1;
+                        while isEmpty and (tx < TEXSIZE-1) do
+                            begin
+                            isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0;
+                            inc(tx,2)
+                            end;
+                        inc(ty,2);
+                        end;
+                    if not isEmpty then
+                        begin
+                        if tex = nil then tex:= NewTexture(TEXSIZE, TEXSIZE, Pixels(x, y));
+                        glBindTexture(GL_TEXTURE_2D, tex^.atlas^.id);
+                        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXSIZE, TEXSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, Pixels(x,y));
+                        end
+                    else if tex <> nil then
+                        begin
+                        FreeTexture(tex);
+                        tex:= nil
+                        end;
                     end
 end;
 
@@ -114,10 +175,11 @@
 for x:= 0 to LANDTEXARW -1 do
     for y:= 0 to LANDTEXARH - 1 do
         with LandTextures[x, y] do
-            if (cReducedQuality and rqBlurryLand) = 0 then
-                DrawTexture(dX + x * TEXSIZE, dY + y * TEXSIZE, tex)
-            else
-                DrawTexture(dX + x * TEXSIZE * 2, dY + y * TEXSIZE * 2, tex, 2.0)
+            if tex <> nil then
+                if (cReducedQuality and rqBlurryLand) = 0 then
+                    DrawTexture(dX + x * TEXSIZE, dY + y * TEXSIZE, tex)
+                else
+                    DrawTexture(dX + x * TEXSIZE * 2, dY + y * TEXSIZE * 2, tex, 2.0)
 
 end;
 
@@ -144,8 +206,11 @@
         for y:= 0 to LANDTEXARH - 1 do
             with LandTextures[x, y] do
                 begin
-                FreeTexture(tex);
-                tex:= nil;
+                if tex <> nil then
+                    begin
+                    FreeTexture(tex);
+                    tex:= nil
+                    end
                 end;
 end;
 
@@ -155,6 +220,6 @@
     if LandBackSurface <> nil then
         SDL_FreeSurface(LandBackSurface);
     LandBackSurface:= nil;
-    LandTextures:= nil;
+    SetLength(LandTextures, 0, 0);
 end;
 end.
--- a/hedgewars/uScript.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uScript.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -1162,6 +1162,25 @@
     lc_getstate:= 1
 end;
 
+function lc_gettag(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if lua_gettop(L) <> 1 then
+        begin
+        LuaError('Lua: Wrong number of parameters passed to GetX!');
+        lua_pushnil(L); // return value on stack (nil)
+        end
+    else
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            lua_pushinteger(L, gear^.Tag)
+        else
+            lua_pushnil(L);
+        end;
+    lc_gettag:= 1
+end;
+
 function lc_settag(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
@@ -2207,6 +2226,7 @@
 lua_register(luaState, _P'GetFollowGear', @lc_getfollowgear);
 lua_register(luaState, _P'SetState', @lc_setstate);
 lua_register(luaState, _P'GetState', @lc_getstate);
+lua_register(luaState, _P'GetTag', @lc_gettag);
 lua_register(luaState, _P'SetTag', @lc_settag);
 lua_register(luaState, _P'SetTimer', @lc_settimer);
 lua_register(luaState, _P'GetTimer', @lc_gettimer);
--- a/hedgewars/uSound.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uSound.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -263,7 +263,7 @@
             if not FileExists(s) then
                 s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
+            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
             if voicepack^.chunks[snd] = nil then
                 WriteLnToConsole(msgFailed)
             else
@@ -279,7 +279,7 @@
             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);
+            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
             SDLTry(defVoicepack^.chunks[snd] <> nil, true);
             WriteLnToConsole(msgOK);
             end;
@@ -363,7 +363,7 @@
             if not FileExists(s) then
                 s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
+            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
             if voicepack^.chunks[snd] = nil then
                 WriteLnToConsole(msgFailed)
             else
@@ -379,7 +379,7 @@
             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);
+            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
             SDLTry(defVoicepack^.chunks[snd] <> nil, true);
             WriteLnToConsole(msgOK);
             end;
--- a/hedgewars/uStats.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uStats.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -185,10 +185,10 @@
 begin
 if time > 4000 then
     begin
-    writeln('FLIGHT');
-    writeln(Gear^.Hedgehog^.Team^.TeamName);
-    writeln(time);
-    writeln;
+    writeln(stdout, 'FLIGHT');
+    writeln(stdout, Gear^.Hedgehog^.Team^.TeamName);
+    writeln(stdout, inttostr(time));
+    writeln(stdout, '');
     end
 end;
 
@@ -293,14 +293,14 @@
 // now to console
 if winnersClan <> nil then 
     begin
-    writeln('WINNERS');
+    writeln(stdout, 'WINNERS');
     for t:= 0 to winnersClan^.TeamsNumber - 1 do
-        writeln(winnersClan^.Teams[t]^.TeamName);
+        writeln(stdout, winnersClan^.Teams[t]^.TeamName);
     end
 else
-    writeln('DRAW');
+    writeln(stdout, 'DRAW');
 
-writeln;
+writeln(stdout, '');
 end;
 
 procedure initModule;
--- a/hedgewars/uStore.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uStore.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -961,7 +961,7 @@
 if caption = '' then
     caption:= '???';
 if subcaption = '' then
-    subcaption:= ' ';
+    subcaption:= _S' ';
 
 font:= CheckCJKFont(caption,fnt16);
 font:= CheckCJKFont(subcaption,font);
@@ -1045,9 +1045,9 @@
         r:= WriteInRect(tmpsurf, cFontBorder + 2, r.y + r.h, $ff707070, font, tmpline);
 
         // render highlighted caption (if there is a ':')
-        tmpline2:= '';
+        tmpline2:= _S'';
         SplitByChar(tmpline, tmpline2, ':');
-        if tmpline2 <> '' then
+        if tmpline2 <> _S'' then
             WriteInRect(tmpsurf, cFontBorder + 2, r2.y + r2.h, $ffc7c7c7, font, tmpline + ':');
         end
     end;
@@ -1090,7 +1090,7 @@
 r.h:= 32;
 
 // default (no extra text)
-extra:= '';
+extra:= _S'';
 extracolor:= 0;
 
 if (CurrentTeam <> nil) and (Ammoz[atype].SkipTurns >= CurrentTeam^.Clan^.TurnNumber) then // weapon or utility is not yet available
@@ -1105,7 +1105,7 @@
     end
 else
     begin
-    extra:= '';
+    extra:= _S'';
     extracolor:= 0;
     end;
 
@@ -1146,7 +1146,7 @@
 {$ENDIF}
         begin
         // set window title
-        {$IFNDEF SDL13}SDL_WM_SetCaption('Hedgewars', nil);{$ENDIF}
+        {$IFNDEF SDL13}SDL_WM_SetCaption(_P'Hedgewars', nil);{$ENDIF}
         WriteToConsole('Init SDL_image... ');
         SDLTry(IMG_Init(IMG_INIT_PNG) <> 0, true);
         WriteLnToConsole(msgOK);
@@ -1250,7 +1250,7 @@
         ReloadLines;
         StoreLoad(true);
         // redraw all land
-        UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT);
+        UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false);
         end;
 end;
 
--- a/hedgewars/uTeams.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uTeams.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -248,8 +248,6 @@
     FollowGear:= Gear
     end;
 
-ResetKbd;
-
 if (GameFlags and gfDisableWind) = 0 then
     begin
     cWindSpeed:= rndSign(GetRandomf * 2 * cMaxWindSpeed);
@@ -482,6 +480,7 @@
 procedure chAddHH(var id: shortstring);
 var s: shortstring;
     Gear: PGear;
+    c: LongInt;
 begin
 s:= '';
 if (not isDeveloperMode) or (CurrentTeam = nil) then
@@ -490,10 +489,10 @@
     begin
     SplitBySpace(id, s);
     CurrentHedgehog:= @Hedgehogs[HedgehogsNumber];
-    val(id, CurrentHedgehog^.BotLevel);
+    val(id, CurrentHedgehog^.BotLevel, c);
     Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
     SplitBySpace(s, id);
-    val(s, Gear^.Health);
+    val(s, Gear^.Health, c);
     TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
     Gear^.Hedgehog^.Team:= CurrentTeam;
     if (GameFlags and gfSharedAmmo) <> 0 then
@@ -514,6 +513,7 @@
 
 procedure chAddTeam(var s: shortstring);
 var Color: Longword;
+    c: LongInt;
     ts, cs: shortstring;
 begin
 cs:= '';
@@ -522,7 +522,7 @@
     begin
     SplitBySpace(s, cs);
     SplitBySpace(cs, ts);
-    val(cs, Color);
+    val(cs, Color, c);
     TryDo(Color <> 0, 'Error: black team color', true);
 
     // color is always little endian so the mask must be constant also in big endian archs
@@ -539,15 +539,15 @@
 
 procedure chSetHHCoords(var x: shortstring);
 var y: shortstring;
-    t: Longint;
+    t, c: Longint;
 begin
 y:= '';
 if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then
     exit;
 SplitBySpace(x, y);
-val(x, t);
+val(x, t, c);
 CurrentHedgehog^.Gear^.X:= int2hwFloat(t);
-val(y, t);
+val(y, t, c);
 CurrentHedgehog^.Gear^.Y:= int2hwFloat(t)
 end;
 
--- a/hedgewars/uTextures.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uTextures.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -212,7 +212,7 @@
     Surface2Tex^.atlas^.w:=tw;
     Surface2Tex^.atlas^.h:=th;
 
-    GetMem(tmpp, tw * th * surf^.format^.BytesPerPixel);
+    tmpp:= GetMem(tw * th * surf^.format^.BytesPerPixel);
 
     fromP4:= Surf^.pixels;
     toP4:= tmpp;
--- a/hedgewars/uTouch.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uTouch.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -62,8 +62,11 @@
 const
     clickTime = 200;
     nilFingerId = High(TSDL_FingerId);
+    baseRectSize = 96;
 
 var
+    rectSize, halfRectSize: LongInt;
+
     pointerCount : Longword;
     fingers: array of TTouch_Data;
     moveCursor : boolean;
@@ -551,8 +554,10 @@
     x := 0;//avoid compiler hint
     y := 0;
     convertToFingerCoord(x, y, CrosshairX, CrosshairY);
-  isOnCrosshair:= sqrt(sqr(finger.x-x) + sqr(finger.y-y)) < 50;
-//    isOnCrosshair:= isOnRect(x-24, y-24, 48, 48, finger);
+    isOnCrosshair:= isOnRect((x-HalfRectSize), (y-HalfRectSize), RectSize, RectSize, finger);
+    printFinger(finger);
+    WriteLnToConsole(inttostr(finger.x) + '   ' + inttostr(x));
+    WriteLnToConsole(inttostr(x) + '  ' + inttostr(y) + '   ' + inttostr(round(Android_JNI_getDensity() * 10)));
 end;
 
 function isOnCurrentHog(finger: TTouch_Data): boolean;
@@ -562,7 +567,7 @@
     x := 0;
     y := 0;
     convertToFingerCoord(x,y, hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y));
-    isOnCurrentHog := sqrt(sqr(finger.X-x) + sqr(finger.Y-y)) < 50;
+    isOnCurrentHog:= isOnRect((x-HalfRectSize), (y-HalfRectSize), RectSize, RectSize, finger);
 end;
 
 procedure convertToFingerCoord(var x,y : LongInt; oldX, oldY: LongInt);
@@ -627,12 +632,22 @@
 var
     index: Longword;
     //uRenderCoordScaleX, uRenderCoordScaleY: Longword;
+    density: Single;
 begin
     buttonsDown:= 0;
 
     setLength(fingers, 4);
     for index := 0 to High(fingers) do 
         fingers[index].id := nilFingerId;
+
+{$IFDEF ANDROID}
+    density:= Android_JNI_getDensity();
+{$ELSE}
+    density:= 1.0;
+{$ENDIF}
+
+    rectSize:= round(baseRectSize * density);
+    halfRectSize:= rectSize shl 1;
 end;
 
 begin
--- a/hedgewars/uUtils.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uUtils.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -39,6 +39,7 @@
 function  Max(a, b: LongInt): LongInt; inline;
 
 function  IntToStr(n: LongInt): shortstring;
+function  StrToInt(s: shortstring): LongInt;
 function  FloatToStr(n: hwFloat): shortstring;
 
 function  DxDy2Angle(const _dY, _dX: hwFloat): GLfloat;
@@ -65,6 +66,11 @@
 function  GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt;
 function  GetLaunchY(at: TAmmoType; angle: LongInt): LongInt;
 
+{$IFNDEF PAS2C}
+procedure Write(var f: textfile; s: shortstring);
+procedure WriteLn(var f: textfile; s: shortstring);
+{$ENDIF}
+
 procedure initModule(isGame: boolean);
 procedure freeModule;
 
@@ -158,6 +164,12 @@
 str(n, IntToStr)
 end;
 
+function  StrToInt(s: shortstring): LongInt;
+var c: LongInt;
+begin
+val(s, StrToInt, c)
+end;
+
 function FloatToStr(n: hwFloat): shortstring;
 begin
 FloatToStr:= cstr(n) + '_' + inttostr(Lo(n.QWordValue))
@@ -285,7 +297,7 @@
 begin
 s:= s;
 {$IFDEF DEBUGFILE}
-writeln(f, GameTicks, ': ', s);
+writeln(f, inttostr(GameTicks)  + ': ' + s);
 flush(f)
 {$ENDIF}
 end;
@@ -359,6 +371,18 @@
 CheckNoTeamOrHH:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil);
 end;
 
+{$IFNDEF PAS2C}
+procedure Write(var f: textfile; s: shortstring);
+begin
+system.write(f, s)
+end;
+
+procedure WriteLn(var f: textfile; s: shortstring);
+begin
+system.writeln(f, s)
+end;
+{$ENDIF}
+
 procedure initModule(isGame: boolean);
 {$IFDEF DEBUGFILE}
 var logfileBase: shortstring;
@@ -403,7 +427,7 @@
 recordFileName:= '';
 
 {$IFDEF DEBUGFILE}
-    writeln(f, 'halt at ', GameTicks, ' ticks. TurnTimeLeft = ', TurnTimeLeft);
+    writeln(f, 'halt at ' + inttostr(GameTicks) + ' ticks. TurnTimeLeft = ' + inttostr(TurnTimeLeft));
     flush(f);
     close(f);
 {$ENDIF}
--- a/hedgewars/uVisualGears.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uVisualGears.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -184,15 +184,15 @@
                     FrameTicks:= random(vobFrameTicks);
                     Frame:= random(vobFramesCount);
                     end;
-                Angle:= random * 360;
+                Angle:= random(360);
                 dx:= 0.0000038654705 * random(10000);
                 dy:= 0.000003506096 * random(7000);
                 if random(2) = 0 then
                     dx := -dx;
                 if SuddenDeathDmg then
-                    dAngle:= (random(2) * 2 - 1) * (1 + random) * vobSDVelocity / 1000
+                    dAngle:= (random(2) * 2 - 1) * (vobSDVelocity + random(vobSDVelocity)) / 1000
                 else
-                    dAngle:= (random(2) * 2 - 1) * (1 + random) * vobVelocity / 1000
+                    dAngle:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) / 1000
                 end;
     vgtCloud:
                 begin
--- a/hedgewars/uWorld.pas	Mon May 28 10:38:27 2012 +0200
+++ b/hedgewars/uWorld.pas	Tue Jun 05 22:17:06 2012 +0200
@@ -213,8 +213,13 @@
 procedure InitTouchInterface;
 begin
 {$IFDEF USE_TOUCH_INTERFACE}
+
 //positioning of the buttons
+{$IFDEF ANDROID}
+buttonScale:= Android_JNI_getDensity()/cDefaultZoomLevel;
+{$ELSE}
 buttonScale:= 1.5/cDefaultZoomLevel;
+{$ENDIF}
 
 
 with JumpWidget do
--- a/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp	Mon May 28 10:38:27 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp	Tue Jun 05 22:17:06 2012 +0200
@@ -638,6 +638,17 @@
     return Android_JNI_FileClose(ctx, true);
 }
 
+extern "C" int Android_JNI_getDensity(){
+    jmethodID mid;
+    jint density;
+    //SDLActivity.getDensity()
+    mid = mEnv->GetStaticMethodID(mActivityClass, "getDensity", "()I");
+        if(!mid) return 160;
+    density = mEnv->CallStaticFloatMethod(mActivityClass, mid);
+    return density;
+
+}
+
 #endif /* __ANDROID__ */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Mon May 28 10:38:27 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Tue Jun 05 22:17:06 2012 +0200
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -401,6 +402,11 @@
 			mAudioTrack = null;
 		}
 	}
+	
+	public static int getDensity(){
+		DisplayMetrics dm = SDLActivity.getContext().getResources().getDisplayMetrics();
+		return dm.densityDpi;
+	}
 }
 
 /**
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -111,11 +111,11 @@
 -- Note that there are 1000 ticks within one second.
 -- You shouldn't try to calculate too complicated
 -- code here as this might slow down your game.
-function onGameTick()
+function onGameTick20()
 	-- If time's up, set the game to be lost.
 	-- We actually check the time to be "1 ms" as it
 	-- will be at "0 ms" right at the start of the game.
-	if TurnTimeLeft == 1 and score < score_goal then
+	if TurnTimeLeft < 40 and TurnTimeLeft > 0 and score < score_goal then
 		game_lost = true
 		-- ... and show a short message.
 		ShowMission(loc("Bazooka Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0)
@@ -133,7 +133,7 @@
 			EndGame()
 		else
 			-- ... or just lower the timer by 1.
-			end_timer = end_timer - 1
+			end_timer = end_timer - 20
 			-- Reset the time left to stop the timer
 			TurnTimeLeft = time_goal
 		end
@@ -150,8 +150,8 @@
 -- This function is called when a new gear is added.
 -- We don't need it for this training, so we can
 -- keep it empty.
-function onGearAdd(gear)
-end
+-- function onGearAdd(gear)
+-- end
 
 -- This function is called before a gear is destroyed.
 -- We use it to count the number of targets destroyed.
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -63,9 +63,9 @@
 
 end
 
-function onGameTick()
+function onGameTick20()
 
-	if TurnTimeLeft == 1 and scored < 12 and game_lost == false then
+	if TurnTimeLeft < 40 and TurnTimeLeft > 0 and scored < 12 and game_lost == false then
 		game_lost = true
 		ShowMission(loc("Cluster Bomb Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0)
 		SetHealth(player, 0)
@@ -76,7 +76,7 @@
 		if end_timer == 0 then
 			EndGame()
 		else
-			end_timer = end_timer - 1
+			end_timer = end_timer - 20
 			TurnTimeLeft = time_goal
 		end
 	end
@@ -87,8 +87,8 @@
 	ParseCommand("setweap " .. string.char(amClusterBomb))
 end
 
-function onGearAdd(gear)
-end
+--function onGearAdd(gear)
+--end
 
 function onGearDamage(gear, damage)
 
@@ -120,4 +120,4 @@
 end
 
 function onGearDelete(gear)
-end
\ No newline at end of file
+end
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -114,11 +114,11 @@
 -- Note that there are 1000 ticks within one second.
 -- You shouldn't try to calculate too complicated
 -- code here as this might slow down your game.
-function onGameTick()
+function onGameTick20()
 	-- If time's up, set the game to be lost.
 	-- We actually check the time to be "1 ms" as it
 	-- will be at "0 ms" right at the start of the game.
-	if TurnTimeLeft == 1 and score < score_goal then
+	if TurnTimeLeft < 40 and TurnTimeLeft > 0 and score < score_goal then
 		game_lost = true
 		-- ... and show a short message.
 		ShowMission(loc("Grenade Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0)
@@ -145,7 +145,7 @@
 			end
 		else
 			-- ... or just lower the timer by 1.
-			end_timer = end_timer - 1
+			end_timer = end_timer - 20
 			-- Reset the time left to stop the timer
 			TurnTimeLeft = time_goal
 		end
@@ -162,8 +162,8 @@
 -- This function is called when a new gear is added.
 -- We don't need it for this training, so we can
 -- keep it empty.
-function onGearAdd(gear)
-end
+-- function onGearAdd(gear)
+-- end
 
 -- This function is called before a gear is destroyed.
 -- We use it to count the number of targets destroyed.
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -128,8 +128,8 @@
 	ParseCommand( "setweap " .. string.char( amRope ) ) -- Set the default weapon to Rope
 end
 
-function onGameTick()
-	if TurnTimeLeft == 1 then -- Round starts at 0, so we check if the round is finished by using 1
+function onGameTick20()
+	if TurnTimeLeft < 40 and TurnTimeLeft > 0 then -- Round starts at 0, so we check if the round is finished by using 1
 		GameLost = true -- You lost the game
 		Info( "Aiming Practice", "You did not make it in time, try again!", -amSkip )
 		SetHealth( Player, 0 ) -- Kill the player so he can't keep moving!
@@ -151,7 +151,7 @@
 
 			WaitTime = -1
 		else
-			WaitTime = WaitTime - 1
+			WaitTime = WaitTime - 20
 		end
 	end
 
@@ -161,7 +161,7 @@
 			FollowTime = 1500
 			FollowGear( Player )
 		else
-			FollowTime = FollowTime - 1
+			FollowTime = FollowTime - 20
 		end
 	end
 
@@ -172,7 +172,7 @@
 		end
 	end
 
-	GetTime = GetTime + 1
+	GetTime = GetTime + 20
 
 	CheckPosition( Player, 70 ) -- Run the CheckPosition function to check if the player is close to a target
 end
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -111,11 +111,11 @@
 -- Note that there are 1000 ticks within one second.
 -- You shouldn't try to calculate too complicated
 -- code here as this might slow down your game.
-function onGameTick()
+function onGameTick20()
 	-- If time's up, set the game to be lost.
 	-- We actually check the time to be "1 ms" as it
 	-- will be at "0 ms" right at the start of the game.
-	if TurnTimeLeft == 1 and score < score_goal then
+	if TurnTimeLeft < 40 and TurnTimeLeft > 20 and score < score_goal then
 		game_lost = true
 		-- ... and show a short message.
 		ShowMission(loc("Shotgun Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0)
@@ -133,7 +133,7 @@
 			EndGame()
 		else
 			-- ... or just lower the timer by 1.
-			end_timer = end_timer - 1
+			end_timer = end_timer - 20
 			-- Reset the time left to stop the timer
 			TurnTimeLeft = time_goal
 		end
@@ -150,8 +150,8 @@
 -- This function is called when a new gear is added.
 -- We don't need it for this training, so we can
 -- keep it empty.
-function onGearAdd(gear)
-end
+-- function onGearAdd(gear)
+-- end
 
 -- This function is called before a gear is destroyed.
 -- We use it to count the number of targets destroyed.
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -112,7 +112,7 @@
 -- Note that there are 1000 ticks within one second.
 -- You shouldn't try to calculate too complicated
 -- code here as this might slow down your game.
-function onGameTick()
+function onGameTick20()
 	if game_lost then
 		return
 	end
@@ -127,7 +127,7 @@
 	-- If time's up, set the game to be lost.
 	-- We actually check the time to be "1 ms" as it
 	-- will be at "0 ms" right at the start of the game.
-	if TurnTimeLeft == 1 and score < score_goal then
+	if TurnTimeLeft < 40 and TurnTimeLeft > 0 and score < score_goal then
 		game_lost = true
 		-- ... and show a short message.
 		ShowMission(loc("Sniper Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0)
@@ -145,7 +145,7 @@
 			EndGame()
 		else
 			-- ... or just lower the timer by 1.
-			end_timer = end_timer - 1
+			end_timer = end_timer - 20
 			-- Reset the time left to stop the timer
 			TurnTimeLeft = time_goal
 		end
@@ -162,8 +162,8 @@
 -- This function is called when a new gear is added.
 -- We don't need it for this training, so we can
 -- keep it empty.
-function onGearAdd(gear)
-end
+-- function onGearAdd(gear)
+-- end
 
 -- This function is called before a gear is destroyed.
 -- We use it to count the number of targets destroyed.
--- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -180,7 +180,7 @@
 end
 
 
-function onGameTick()
+function onGameTick20()
 
 	if (CurrentHedgehog ~= nil) then
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -107,7 +107,6 @@
 --------
 
 local cGear = nil
-local gTimer = 0
 
 local bestClan = nil
 local bestTime = nil
@@ -116,7 +115,6 @@
 local gameOver = false
 local racerActive = false
 local trackTime = 0
-local wpCheckCounter = 0
 
 local wpCirc = {}
 local wpX = {}
@@ -536,6 +534,7 @@
 			loc("NOT ENOUGH WAYPOINTS"),
 			loc("Place more waypoints using the 'Air Attack' weapon."), 2, 4000)
 			AddAmmo(CurrentHedgehog, amAirAttack, 4000)
+            ParseCommand("setweap " .. string.char(amAirAttack))
 		end
 	end
 
@@ -552,28 +551,32 @@
 
 end
 
-function onGameTick()
+function onGameTick20()
 
 	-- airstrike detected, convert this into a potential waypoint spot
 	if cGear ~= nil then
-		x,y = GetGearTarget(cGear)
+		x,y = GetGearPosition(cGear)
+        if x > -9000 then
+            x,y = GetGearTarget(cGear)
 
-		DeleteGear(cGear)
 
-		if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
-			AddCaption(loc("Please place the way-point in the open, within the map boundaries."))
-			PlaySound(sndDenied)
-		elseif (y > WaterLine-50) then
-			AddCaption(loc("Please place the way-point further from the waterline."))
-			PlaySound(sndDenied)
-		else
-			PlaceWayPoint(x, y)
-			if wpCount == wpLimit then
-				AddCaption(loc("Race complexity limit reached."))
-				DisableTumbler()
-			end
-		end
-
+            if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
+                AddCaption(loc("Please place the way-point in the open, within the map boundaries."))
+                PlaySound(sndDenied)
+            elseif (y > WaterLine-50) then
+                AddCaption(loc("Please place the way-point further from the waterline."))
+                PlaySound(sndDenied)
+            else
+                PlaceWayPoint(x, y)
+                if wpCount == wpLimit then
+                    AddCaption(loc("Race complexity limit reached."))
+                    DisableTumbler()
+                end
+            end
+        else
+            DeleteGear(cGear)
+        end
+        SetGearPosition(cGear, -10000, 0)
 	end
 
 
@@ -613,19 +616,19 @@
 		if (racerActive == true) and (gameBegun == true) then
 
 			--ghost
-			gTimer = gTimer + 1
-			if gTimer == 40 then
-				gTimer = 0
+			if GameTime%40 == 0 then
 				HandleGhost()
 			end
 
-			trackTime = trackTime + 1
+			trackTime = trackTime + 20
 
-			wpCheckCounter = wpCheckCounter + 1
-			if (wpCheckCounter == 100) then
-
-				wpCheckCounter = 0
-				AddCaption(trackTime/1000,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+			if GameTime%100 == 0 then
+                
+                if trackTime%1000 == 0 then
+                    AddCaption((trackTime/1000)..'.0',GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+                else
+                    AddCaption(trackTime/1000,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+                end
 
 				if (CheckWaypoints() == true) then
 					AdjustScores()
@@ -640,7 +643,7 @@
 
 
 		-- if the player has expended his tunbling time, stop him tumbling
-		if TurnTimeLeft <= 1 then
+		if TurnTimeLeft <= 20 then
 			DisableTumbler()
 		end
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -235,7 +235,6 @@
 -- some console stuff
 local shellID = 0
 local explosivesID = 0
-local luaGameTicks = 0
 
 -- gaudyRacer
 local boosterOn = false
@@ -351,7 +350,6 @@
 local rCircX = {}
 local rCircY = {}
 local rAlpha = 255
-local rPingTimer = 0
 local radShotsLeft = 0
 
 local vCircActive = {}
@@ -1159,7 +1157,6 @@
 
 
 	--WriteLnToConsole("Start of GameTick")
-	luaGameTicks = luaGameTicks + 1 -- GameTime
 
 	HandleCircles()
 
@@ -2132,9 +2129,7 @@
 
 	if rAlpha ~= 255 then
 
-		rPingTimer = rPingTimer + 1
-		if rPingTimer == 100 then
-			rPingTimer = 0
+		if GameTime%100 == 0 then
 
 			rAlpha = rAlpha + 5
 			if rAlpha >= 255 then
--- a/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -217,17 +217,17 @@
 	switchStage = 0
 end
 
-function onGameTick()
+function onGameTick20()
 
 	if (CurrentHedgehog ~= nil) then
 
 		currName = GetHogName(CurrentHedgehog)
 
-		if (currName ~= lastName) and (switchStage > 100) then
+		if (currName ~= lastName) and (switchStage > 5) then
 			AddCaption(loc("Switched to ") .. currName .. "!")
 		end
 
-		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) and (switchStage < 100) then
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) and (switchStage < 5) then
 
 			AddCaption(loc("Prepare yourself") .. ", " .. currName .. "!")
 
@@ -246,12 +246,12 @@
 				elseif switchStage == 3 then
 					SetGearMessage(CurrentHedgehog,gmAttack)
 				elseif switchStage == 4 then
-					switchStage = 110
+					switchStage = 6
 					AddAmmo(CurrentHedgehog, amSwitch, 0)
 				end
 
 			else
-				switchStage = 110
+				switchStage = 6
 			end
 
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Mon May 28 10:38:27 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Tue Jun 05 22:17:06 2012 +0200
@@ -598,7 +598,7 @@
 	roundN = roundN + 1
 	if roundN < 2 then
 		TurnTimeLeft = -1
-		SetInputMask(band(0xFFFFFFFF, bnot(gmAnimate+gmAttack+gmDown+gmHJump+gmLeft+gmLJump+gmPrecise+gmRight+gmSlot+gmSwitch+gmTimer+gmUp+gmWeapon)))
+		SetInputMask(0)
 		allowCrate = false
 		HandleStartingStage() -- new
 	end
@@ -670,7 +670,7 @@
 				then
 					SetInputMask(0xFFFFFFFF)
 				elseif ropeG == nil then
-					SetInputMask(band(0xFFFFFFFF, bnot(gmAttack)))
+					SetInputMask(bnot(gmAttack))
 				end
 			end
 
--- a/tools/pas2c.hs	Mon May 28 10:38:27 2012 +0200
+++ b/tools/pas2c.hs	Tue Jun 05 22:17:06 2012 +0200
@@ -39,10 +39,11 @@
         uniqCounter :: Int,
         toMangle :: Set.Set String,
         currentUnit :: String,
+        currentFunctionResult :: String,
         namespaces :: Map.Map String Records
     }
     
-emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty ""
+emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty "" ""
 
 getUniq :: State RenderState Int
 getUniq = do
@@ -334,7 +335,7 @@
 resolveType (DeriveType (InitFloat _)) = return BTFloat
 resolveType (DeriveType (InitString _)) = return BTString
 resolveType (DeriveType (InitBinOp {})) = return BTInt
-resolveType (DeriveType (InitPrefixOp {})) = return BTInt
+resolveType (DeriveType (InitPrefixOp _ e)) = initExpr2C e >> gets lastType
 resolveType (DeriveType (BuiltInFunction{})) = return BTInt
 resolveType (DeriveType (InitReference (Identifier{}))) = return BTBool -- TODO: derive from actual type
 resolveType (DeriveType _) = return BTUnknown
@@ -381,13 +382,19 @@
     t <- type2C returnType
     t'<- gets lastType
     n <- id2C IOInsert $ setBaseType (BTFunction (numberOfDeclarations params) t') name
-    (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st}) $ do
+    
+    let isVoid = case returnType of
+            VoidType -> True
+            _ -> False
+            
+    (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st
+            , currentFunctionResult = if isVoid then [] else render res}) $ do
         p <- functionParams2C params
         ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase)
         return (p, ph)
-    let phrasesBlock = case returnType of
-            VoidType -> ph
-            _ -> t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi
+        
+    let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi
+    
     return [ 
         t empty <+> n <> parens p
         $+$
@@ -615,7 +622,19 @@
         (BTFunction {}, (Reference r')) -> do
             e <- ref2C r'
             return $ r <+> text "=" <+> e <> semi
-        (BTArray (Range _) _ _, _) -> phrase2C $ 
+        (BTString, _) -> do
+            e <- expr2C expr
+            lt <- gets lastType
+            case lt of
+                -- assume pointer to char for simplicity
+                BTPointerTo _ -> do
+                    e <- expr2C $ Reference $ FunCall [Reference $ RefExpression expr] (SimpleReference (Identifier "pchar2str" BTUnknown))
+                    return $ r <+> text "=" <+> e <> semi
+                BTString -> do
+                    e <- expr2C expr
+                    return $ r <+> text "=" <+> e <> semi
+                _ -> error $ "Assignment to string from " ++ show lt
+        (BTArray _ _ _, _) -> phrase2C $ 
             ProcCall (FunCall
                 [
                 Reference $ Address ref
@@ -671,7 +690,12 @@
     return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi
 phrase2C NOP = return $ text ";"
 
-phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "exit" BTUnknown))) = return $ text "return" <> semi
+phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "exit" BTUnknown))) = do
+    f <- gets currentFunctionResult
+    if null f then
+        return $ text "return" <> semi
+        else
+        return $ text "return" <+> text f <> semi
 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "break" BTUnknown))) = return $ text "break" <> semi
 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "continue" BTUnknown))) = return $ text "continue" <> semi
 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "exit" BTUnknown))) = liftM (\e -> text "return" <+> e <> semi) $ expr2C e
@@ -695,6 +719,7 @@
         ("+", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strconcat" (BTFunction 2 BTString))
         ("+", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strappend" (BTFunction 2 BTString))
         ("+", BTChar, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strprepend" (BTFunction 2 BTString))
+        ("+", BTChar, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_chrconcat" (BTFunction 2 BTString))
         ("==", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcomparec" (BTFunction 2 BTBool))
         ("==", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcompare" (BTFunction 2 BTBool))
         ("!=", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strncompare" (BTFunction 2 BTBool))
@@ -878,9 +903,11 @@
     r <- ref2C ref
     return $ text "&" <> parens r
 ref2C (TypeCast t'@(Identifier i _) expr) = do
-    case map toLower i of
-        "pchar" -> ref2C $ FunCall [expr] (SimpleReference (Identifier "_pchar" $ BTPointerTo BTChar))
-        a -> do
+    lt <- expr2C expr >> gets lastType
+    case (map toLower i, lt) of
+        ("pchar", BTString) -> ref2C $ FunCall [expr] (SimpleReference (Identifier "_pchar" $ BTPointerTo BTChar))
+        ("shortstring", BTPointerTo _) -> ref2C $ FunCall [expr] (SimpleReference (Identifier "pchar2str" $ BTString))
+        (a, _) -> do
             e <- expr2C expr
             t <- id2C IOLookup t'    
             return . parens $ parens t <> e