Merge
authorMedo <smaxein@googlemail.com>
Mon, 11 Jun 2012 00:06:22 +0200
changeset 7221 8d04e85ca204
parent 7182 076aba32abd3 (current diff)
parent 7218 9ecd5bc9810b (diff)
child 7224 5143861c83bd
Merge
QTfrontend/game.cpp
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
--- a/QTfrontend/game.cpp	Mon Jun 11 00:02:17 2012 +0200
+++ b/QTfrontend/game.cpp	Mon Jun 11 00:06:22 2012 +0200
@@ -97,7 +97,7 @@
             HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammdelay %1").arg(ammostr.mid(2 * cAmmoNumber, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber)));
-            if(!gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore"));
+            if(gamecfg->schemeData(15).toBool() || !gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore"));
             HWProto::addStringListToBuffer(buf,
                                            team.teamGameConfig(gamecfg->getInitHealth()));
             ;
--- a/hedgewars/GSHandlers.inc	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/GSHandlers.inc	Mon Jun 11 00:06:22 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 ////////////////////////////////////
@@ -1025,7 +1025,9 @@
         else
             AmmoShove(Gear, Gear^.Timer, 20);
         CheckGearDrowning(Gear);
-        dec(i) until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
+        dec(i) 
+    until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
+
     if Gear^.Damage > 0 then
         begin
         DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 82 - i, 1);
@@ -2077,6 +2079,7 @@
     exBoom: boolean;
     dX, dY: HWFloat;
     hog: PHedgehog;
+    sparkles: PVisualGear;
 begin
     k := Gear^.Kind;
     exBoom := false;
@@ -2108,6 +2111,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
@@ -3422,7 +3440,7 @@
         PlaySound(sndGun);
         end;
 
-    if (Gear^.Timer = 0) or (HHGear^.Damage <> 0) then
+    if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
         begin
         DeleteGear(Gear);
         AfterAttack
--- a/hedgewars/SDLh.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/SDLh.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -270,6 +270,19 @@
     AShift = 0;
 {$ENDIF}
 
+    KMOD_NONE   = $0000;
+    KMOD_LSHIFT = $0001;
+    KMOD_RSHIFT = $0002;
+    KMOD_LCTRL  = $0040;
+    KMOD_RCTRL  = $0080;
+    KMOD_LALT   = $0400;
+    KMOD_RALT   = $0800;
+    KMOD_LMETA  = $0400;
+    KMOD_RMETA  = $0800;
+    KMOD_NUM    = $1000;
+    KMOD_CAPS   = $2000;
+    KMOD_MODE   = $4000;
+
     {* SDL_mixer *}
     MIX_MAX_VOLUME = 128;
     MIX_INIT_FLAC  = $00000001;
--- a/hedgewars/VGSHandlers.inc	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/VGSHandlers.inc	Mon Jun 11 00:06:22 2012 +0200
@@ -90,10 +90,16 @@
             if round(X) > cRightScreenBorder then
                 X:= X - cScreenSpace;
             // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards?
-            if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then
-                Y:= Y - (1024 + 300) // TODO - configure in theme (jellies for example could use limited range)
-            else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then
-                Y:= Y - (1024 + 25);
+        if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then
+            begin
+            X:= cLeftScreenBorder + random(cScreenSpace);
+            Y:= Y - (1024 + 250 + random(50)) // TODO - configure in theme (jellies for example could use limited range)
+            end
+        else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then
+            begin
+            X:= cLeftScreenBorder + random(cScreenSpace);
+            Y:= Y - (1024 + random(25))
+            end;
         Timer:= 0;
         tdX:= 0;
         tdY:= 0
--- a/hedgewars/uAI.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uAI.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -111,7 +111,7 @@
 procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean);
 var BotLevel: Byte;
     ap: TAttackParams;
-    Score, i: LongInt;
+    Score, i, dAngle: LongInt;
     a, aa: TAmmoType;
 begin
 BotLevel:= Me^.Hedgehog^.BotLevel;
@@ -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);
@@ -151,29 +153,45 @@
                     
                     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
+                        dAngle:= LongInt(Me^.Angle) - Abs(ap.Angle);
+                        if dAngle > 0 then
                             begin
                             AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0);
-                            AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0)
+                            AddAction(BestActions, aia_Up, aim_release, dAngle, 0, 0)
                             end
-                        else if ap.Angle < 0 then
+                        else if dAngle < 0 then
                             begin
                             AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
-                            AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0)
+                            AddAction(BestActions, aia_Down, aim_release, -dAngle, 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
+                        
+                    if (Ammoz[a].Ammo.Propz and ammoprop_OscAim) <> 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;
+                        AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0);
+                        AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
+                                                
+                        AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0);
+                        AddAction(BestActions, aia_Down, aim_release, 32, 0, 0);
+                        
+                        AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0);
+                        AddAction(BestActions, aia_attack, aim_push, 1, 0, 0);
+                        AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
+                        end else
+                        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
@@ -181,8 +199,8 @@
         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;
 
@@ -216,81 +234,86 @@
 BestRate:= RatePlace(Me);
 BaseRate:= Max(BestRate, 0);
 
+// switch to 'skip' if we can't move because of mouse cursor being shown
 if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
     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
+if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0)) 
+    and (GameFlags and gfArtillery = 0) then
     begin
-    Pop(ticks, Actions, Me^);
+    tmp:= random(2) + 1;
+    Push(0, Actions, Me^, tmp);
+    Push(0, Actions, Me^, tmp xor 3);
+    
+    while (Stack.Count > 0) and (not StopThinking) do
+        begin
+        Pop(ticks, Actions, Me^);
 
-    AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
-    if (Me^.Message and gmLeft) <> 0 then
-        AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
-    else
-        AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
-    
-    steps:= 0;
+        AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
+        if (Me^.Message and gmLeft) <> 0 then
+            AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
+        else
+            AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
+        
+        steps:= 0;
 
-    while (not StopThinking) do
-        begin
-{$HINTS OFF}
-        CanGo:= HHGo(Me, @AltMe, GoInfo);
-{$HINTS ON}
-        inc(ticks, GoInfo.Ticks);
-        if ticks > maxticks then
-            break;
+        while (not StopThinking) do
+            begin
+    {$HINTS OFF}
+            CanGo:= HHGo(Me, @AltMe, GoInfo);
+    {$HINTS ON}
+            inc(ticks, GoInfo.Ticks);
+            if ticks > maxticks then
+                break;
 
-        if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
-            if Push(ticks, Actions, AltMe, Me^.Message) then
-                with Stack.States[Pred(Stack.Count)] do
-                    begin
-                    if Me^.dX.isNegative then
-                        AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
-                    else
-                        AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
+            if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
+                if Push(ticks, Actions, AltMe, Me^.Message) then
+                    with Stack.States[Pred(Stack.Count)] do
+                        begin
+                        if Me^.dX.isNegative then
+                            AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
+                        else
+                            AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
+                            
+                        AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
+                        AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
                         
-                    AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
-                    AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
-                    
-                    if Me^.dX.isNegative then
-                        AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
-                    else
-                        AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
-                    end;
-        if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
-            if Push(ticks, Actions, AltMe, Me^.Message) then
-                with Stack.States[Pred(Stack.Count)] do
-                    AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
+                        if Me^.dX.isNegative then
+                            AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
+                        else
+                            AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
+                        end;
+            if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
+                if Push(ticks, Actions, AltMe, Me^.Message) then
+                    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);
-         Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
-         Rate:= RatePlace(Me);
-         if Rate > BestRate then
-            begin
-            BestActions:= Actions;
-            BestActions.isWalkingToABetterPlace:= true;
-            BestRate:= Rate;
-            Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
-            end
-        else if Rate < BestRate then
-            break;
-        if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then
-            TestAmmos(Actions, Me, true);
-        if GoInfo.FallPix >= FallPixForBranching then
-            Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
-        end {while};
+            // 'not CanGO' means we can't go straight, possible jumps are checked above
+            if not CanGo then
+                break;
+            
+             inc(steps);
+             Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
+             Rate:= RatePlace(Me);
+             if Rate > BestRate then
+                begin
+                BestActions:= Actions;
+                BestActions.isWalkingToABetterPlace:= true;
+                BestRate:= Rate;
+                Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
+                end
+            else if Rate < BestRate then
+                break;
+            if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then
+                TestAmmos(Actions, Me, true);
+            if GoInfo.FallPix >= FallPixForBranching then
+                Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
+            end {while};
 
-    if BestRate > BaseRate then
-        exit
+        if BestRate > BaseRate then
+            exit
         end {while}
+    end {if}
 end;
 
 function Think(Me: Pointer): ptrint;
@@ -412,6 +435,8 @@
 AddFileLog('Thread started');
 end;
 
+//var scoreShown: boolean = false;
+
 procedure ProcessBot;
 const cStopThinkTime = 40;
 begin
@@ -428,16 +453,27 @@
                     StopMessages(Gear^.Message);
                     TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true);
                     end;
+                    
                 if Gear^.Message <> 0 then
                     exit;
+                    
+                //scoreShown:= false;   
                 StartThink(Gear);
                 StartTicks:= GameTicks
                 
-                end else
-                    ProcessAction(BestActions, Gear)
+            end else
+                begin
+                (*
+                if not scoreShown then
+                    begin
+                    if BestActions.Score > 0 then ParseCommand('/say Expected score = ' + inttostr(BestActions.Score div 1024), true);
+                    scoreShown:= true
+                    end;*)
+                ProcessAction(BestActions, Gear)
+                end
         else if ((GameTicks - StartTicks) > cMaxAIThinkTime)
-        or (TurnTimeLeft <= cStopThinkTime) then
-            StopThinking:= true
+            or (TurnTimeLeft <= cStopThinkTime) then
+                StopThinking:= true
 end;
 
 procedure initModule;
--- a/hedgewars/uAIActions.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uAIActions.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -43,6 +43,7 @@
     aia_Skip       = $8008;
     aia_Wait       = $8009;
     aia_Put        = $800A;
+    aia_waitAngle  = $800B;
     
     aim_push       = $8000;
     aim_release    = $8001;
@@ -70,7 +71,7 @@
 var PrevX: LongInt = 0;
     timedelta: Longword = 0;
 
-const ActionIdToStr: array[0..7] of string[16] = (
+const ActionIdToStr: array[0..8] of string[16] = (
 {aia_none}           '',
 {aia_Left}           'left',
 {aia_Right}          'right',
@@ -78,7 +79,8 @@
 {aia_attack}         'attack',
 {aia_Up}             'up',
 {aia_Down}           'down',
-{aia_Switch}         'switch'
+{aia_Switch}         'switch',
+{aia_waitAngle}      'waitAngle'
                      );
 
 {$IFDEF TRACEAIACTIONS}
@@ -150,6 +152,7 @@
 begin
 repeat
 if Actions.Pos >= Actions.Count then exit;
+
 with Actions.actions[Actions.Pos] do
     begin
     if Time > GameTicks then
@@ -160,74 +163,77 @@
     if (Action and ai_specmask) <> 0 then
         case Action of
             aia_Weapon: 
-            SetWeapon(TAmmoType(Param));
+                SetWeapon(TAmmoType(Param));
             
             aia_WaitXL: 
-            if hwRound(Me^.X) = Param then
-                begin
-                Action:= aia_LookLeft;
-                Time:= GameTicks;
-                exit
-                end
-                else if hwRound(Me^.X) < Param then
+                if hwRound(Me^.X) = Param then
                     begin
-                    //OutError('AI: WaitXL assert (' + IntToStr(hwRound(Me^.X)) + ' < ' + IntToStr(Param) + ')', false);
-                    FreeActionsList;
+                    Action:= aia_LookLeft;
+                    Time:= GameTicks;
+                    exit
+                    end
+                    else if hwRound(Me^.X) < Param then
+                        begin
+                        //OutError('AI: WaitXL assert (' + IntToStr(hwRound(Me^.X)) + ' < ' + IntToStr(Param) + ')', false);
+                        FreeActionsList;
+                        exit
+                        end
+                    else
+                        begin 
+                        CheckHang(Me);
+                        exit
+                        end;
+                            
+            aia_WaitXR: 
+                if hwRound(Me^.X) = Param then
+                    begin
+                    Action:= aia_LookRight;
+                    Time:= GameTicks;
+                    exit
+                    end
+                    else if hwRound(Me^.X) > Param then
+                        begin
+                        //OutError('AI: WaitXR assert (' + IntToStr(hwRound(Me^.X)) + ' > ' + IntToStr(Param) + ')', false);
+                        FreeActionsList;
+                        exit
+                        end
+                    else
+                        begin 
+                        CheckHang(Me);
+                        exit
+                        end;
+            aia_LookLeft:
+                if not Me^.dX.isNegative then
+                    begin
+                    ParseCommand('+left', true);
                     exit
                     end
                 else
-                    begin 
-                    CheckHang(Me);
-                    exit
-                    end;
-                            
-            aia_WaitXR: 
-            if hwRound(Me^.X) = Param then
-                begin
-                Action:= aia_LookRight;
-                Time:= GameTicks;
-                exit
-                end
-                else if hwRound(Me^.X) > Param then
+                    ParseCommand('-left', true);
+            aia_LookRight:
+                if Me^.dX.isNegative then
                     begin
-                    //OutError('AI: WaitXR assert (' + IntToStr(hwRound(Me^.X)) + ' > ' + IntToStr(Param) + ')', false);
-                    FreeActionsList;
+                    ParseCommand('+right', true);
                     exit
                     end
-                else
-                    begin 
-                    CheckHang(Me);
-                    exit
-                    end;
-            aia_LookLeft:
-            if not Me^.dX.isNegative then
-                begin
-                ParseCommand('+left', true);
-                exit
-                end
-            else
-                ParseCommand('-left', true);
-            aia_LookRight:
-            if Me^.dX.isNegative then
-                begin
-                ParseCommand('+right', true);
-                exit
-                end
-            else ParseCommand('-right', true);
+                else ParseCommand('-right', true);
             aia_AwareExpl:
-            AwareOfExplosion(X, Y, Param);
+                AwareOfExplosion(X, Y, Param);
             
             aia_HJump:
-            ParseCommand('hjump', true);
+                ParseCommand('hjump', true);
             
             aia_LJump:
-            ParseCommand('ljump', true);
+                ParseCommand('ljump', true);
             
             aia_Skip:
-            ParseCommand('skip', true);
+                ParseCommand('skip', true);
             
             aia_Put:
-            doPut(X, Y, true);
+                doPut(X, Y, true);
+                
+            aia_waitAngle:
+                if Me^.Angle <> Abs(Param) then exit;
             end
         else
             begin
--- a/hedgewars/uAIAmmoTests.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Mon Jun 11 00:06:22 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;
 
@@ -41,6 +43,7 @@
 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestDesertEagle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestSniperRifle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
@@ -68,9 +71,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
@@ -95,7 +98,7 @@
             (proc: nil;              flags: 0), // amExtraTime
             (proc: nil;              flags: 0), // amLaserSight
             (proc: nil;              flags: 0), // amVampiric
-            (proc: nil;              flags: 0), // amSniperRifle
+            (proc: @TestSniperRifle; flags: 0), // amSniperRifle
             (proc: nil;              flags: 0), // amJetpack
             (proc: @TestMolotov;     flags: 0), // amMolotov
             (proc: nil;              flags: 0), // amBirdy
@@ -105,7 +108,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
@@ -600,7 +603,56 @@
     TestDesertEagle:= BadTurn;
     exit(BadTurn);
     end;
-t:= 0.5 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y));
+t:= 2 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y));
+Vx:= (Targ.X - x) * t;
+Vy:= (Targ.Y - y) * t;
+ap.Angle:= DxDy2AttackAnglef(Vx, -Vy);
+d:= 0;
+
+repeat
+    x:= x + vX;
+    y:= y + vY;
+    if ((trunc(x) and LAND_WIDTH_MASK) = 0)and((trunc(y) and LAND_HEIGHT_MASK) = 0)
+    and (Land[trunc(y), trunc(x)] <> 0) then
+        inc(d);
+until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 5)
+    or (x < 0)
+    or (y < 0)
+    or (trunc(x) > LAND_WIDTH)
+    or (trunc(y) > LAND_HEIGHT)
+    or (d > 50);
+
+if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 5 then
+    begin
+    fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00125 * 20, vY * 0.00125 * 20);
+    if fallDmg < 0 then
+        valueResult:= 204800
+    else valueResult:= Max(0, (4 - d div 50) * trunc((7+fallDmg)*dmgMod) * 1024)
+    end
+else
+    valueResult:= BadTurn;
+TestDesertEagle:= valueResult
+end;
+
+
+function TestSniperRifle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, x, y, t, dmg, dmgMod: real;
+    d: Longword;
+    fallDmg, valueResult: LongInt;
+begin
+dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
+Level:= Level; // avoid compiler hint
+ap.ExplR:= 0;
+ap.Time:= 0;
+ap.Power:= 1;
+x:= hwFloat2Float(Me^.X);
+y:= hwFloat2Float(Me^.Y);
+if Abs(trunc(x) - Targ.X) + Abs(trunc(y) - Targ.Y) < 40 then
+    exit(BadTurn);
+
+dmg:= sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y));
+t:= 1.5 / dmg;
+dmg:= dmg * 0.025; // div 40
 Vx:= (Targ.X - x) * t;
 Vy:= (Targ.Y - y) * t;
 ap.Angle:= DxDy2AttackAnglef(Vx, -Vy);
@@ -617,153 +669,172 @@
     or (y < 0)
     or (trunc(x) > LAND_WIDTH)
     or (trunc(y) > LAND_HEIGHT)
-    or (d > 200);
+    or (d > 23);
 
-if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 3 then
+if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4 then
     begin
-    fallDmg:= TraceShoveFall(Me, Targ.X, Targ.Y, vX * 0.005 * 20, vY * 0.005 * 20);
+    fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg);
     if fallDmg < 0 then
-        valueResult:= 204800
-    else valueResult:= Max(0, (4 - d div 50) * trunc((7+fallDmg)*dmgMod) * 1024)
+        TestSniperRifle:= BadTurn
+    else 
+        TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024)
     end
 else
-    valueResult:= BadTurn;
-TestDesertEagle:= valueResult
+    TestSniperRifle:= BadTurn
 end;
 
+
 function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var valueResult: LongInt;
-    x, y: real;
+var valueResult, a, v1, v2: LongInt;
+    x, y: LongInt;
+    dx, dy: real;
 begin
-Level:= Level; // avoid compiler hint
-TestBaseballBat:= BadTurn;
-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
-    exit(BadTurn);
+    Level:= Level; // avoid compiler hint
+    ap.ExplR:= 0;
+    ap.Time:= 0;
+    ap.Power:= 1;
+    x:= hwRound(Me^.X);
+    y:= hwRound(Me^.Y);
+
+    a:= 0;
+    valueResult:= 0;
+
+    while a <= cMaxAngle div 2 do
+        begin
+        dx:= sin(a / cMaxAngle * pi) * 0.5;
+        dy:= cos(a / cMaxAngle * pi) * 0.5;
 
-ap.Time:= 0;
-ap.Power:= 1;
-if (Targ.X) - trunc(x) >= 0 then
-    ap.Angle:=   cMaxAngle div 4
-else
-    ap.Angle:= - cMaxAngle div 4;
+        v1:= RateShove(Me, x - 10, y
+                , 33, 30, 115
+                , -dx, -dy, afTrackFall);
+        v2:= RateShove(Me, x + 10, y
+                , 33, 30, 115
+                , dx, -dy, afTrackFall);
+        if (v1 > valueResult) or (v2 > valueResult) then
+            if (v2 > v1) 
+                or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
+                begin
+                ap.Angle:= a;
+                valueResult:= v2
+                end
+            else 
+                begin
+                ap.Angle:= -a;
+                valueResult:= v1
+                end;
 
-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
-    inc(valueResult);
-TestBaseballBat:= valueResult;
+        a:= a + 15 + random(cMaxAngle div 16)
+        end;
+   
+    if valueResult <= 0 then
+        valueResult:= BadTurn;
+
+    TestBaseballBat:= valueResult;
 end;
 
 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var val1, val2, i, t: LongInt;
-    x, y: real;
+var valueResult, v1, v2, i: LongInt;
+    x, y: LongInt;
 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
-    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.45, -0.9,  1) >= 0) then
-        val1:= Succ(BadTurn)
-    else
-        val1:= BadTurn;
-    exit(val1);
-    end;
-    }
-// and this is actual try to attack
-val1:= 0;
-for i:= 0 to 4 do
-    begin
-    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;
+    Level:= Level; // avoid compiler hint
+    ap.ExplR:= 0;
+    ap.Time:= 0;
+    ap.Power:= 1;
+    x:= hwRound(Me^.X);
+    y:= hwRound(Me^.Y);
+
+    v1:= 0;
+    for i:= 0 to 8 do
+        begin
+        v1:= v1 + RateShove(Me, x - 10, y - 10 * i
+                , 18, 30, 40
+                , -0.45, -0.9, afTrackFall or afSetSkip);
+        end;
+    v1:= v1 + RateShove(Me, x - 10, y - 90
+            , 18, 30, 40
+            , -0.45, -0.9, afTrackFall);
+
 
-val2:= 0;
-for i:= 0 to 4 do
-    begin
-    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;
-if (val1 > val2) and (val1 > 0) then 
-    TestFirePunch:= val1
-else if (val2 > val1) and (val2 > 0) then
-    begin
-    ap.Angle:= -hwSign(Me^.dX);
-    TestFirePunch:= val2
-    end
-else TestFirePunch:= BadTurn;
+    // now try opposite direction
+    v2:= 0;
+    for i:= 0 to 8 do
+        begin
+        v2:= v2 + RateShove(Me, x + 10, y - 10 * i
+                , 18, 30, 40
+                , 0.45, -0.9, afTrackFall or afSetSkip);
+        end;
+    v2:= v2 + RateShove(Me, x + 10, y - 90
+            , 18, 30, 40
+            , 0.45, -0.9, afTrackFall);
+
+    if (v2 > v1) 
+        or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
+        begin
+        ap.Angle:= 1;
+        valueResult:= v2
+        end
+    else 
+        begin
+        ap.Angle:= -1;
+        valueResult:= v1
+        end;
+    
+    if valueResult <= 0 then
+        valueResult:= BadTurn;
+
+    TestFirePunch:= valueResult;
 end;
 
-// TODO: TestWhip, TestFirepunch and TestBaseballBat could be called only once at each position 
-// (now they're called for each possible target in each position)
+
 function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 var valueResult, v1, v2: LongInt;
-    x, y: real;
+    x, y: LongInt;
 begin
-Level:= Level; // avoid compiler hint
-ap.ExplR:= 0;
-ap.Time:= 0;
-ap.Power:= 1;
-x:= hwFloat2Float(Me^.X);
-y:= hwFloat2Float(Me^.Y);
+    Level:= Level; // avoid compiler hint
+    ap.ExplR:= 0;
+    ap.Time:= 0;
+    ap.Power:= 1;
+    x:= hwRound(Me^.X);
+    y:= hwRound(Me^.Y);
 
-if(abs(Targ.X - x) > 50) or (abs(Targ.Y - y) > 30) then // we're way too far from our target
-    exit(BadTurn);
+    // check left direction
+    {first RateShove checks farthermost of two whip's AmmoShove attacks 
+    to encourage distant attacks (damaged hog is excluded from view of second 
+    RateShove call)}
+    v1:= RateShove(Me, x - 15, y
+            , 30, 30, 25
+            , -1, -0.8, afTrackFall or afSetSkip);
+    v1:= v1 +
+        RateShove(Me, x, y
+            , 30, 30, 25
+            , -1, -0.8, afTrackFall);
+    // now try opposite direction
+    v2:= RateShove(Me, x + 15, y
+            , 30, 30, 25
+            , 1, -0.8, afTrackFall or afSetSkip);
+    v2:= v2 +
+        RateShove(Me, x, y
+            , 30, 30, 25
+            , 1, -0.8, afTrackFall);
+
+    if (v2 > v1) 
+        or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
+        begin
+        ap.Angle:= 1;
+        valueResult:= v2
+        end
+    else 
+        begin
+        ap.Angle:= -1;
+        valueResult:= v1
+        end;
     
-// 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 valueResult <= 0 then
+        valueResult:= BadTurn
+    else
+        inc(valueResult);
 
-if (v2 > v1) 
-    or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
-    begin
-    ap.Angle:= 1;
-    valueResult:= v2
-    end
-else 
-    begin
-    ap.Angle:= -1;
-    valueResult:= v1
-    end;
-   
-if valueResult <= 0 then
-    valueResult:= BadTurn
-else
-    inc(valueResult);
-
-TestWhip:= valueResult;
+    TestWhip:= valueResult;
 end;
 
 function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
@@ -775,10 +846,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;
--- a/hedgewars/uAIMisc.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uAIMisc.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -59,8 +59,9 @@
 
 function  RatePlace(Gear: PGear): LongInt;
 function  TestColl(x, y, r: LongInt): boolean; inline;
+function  TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
 function  TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
-function  TraceShoveFall(Me: PGear; x, y, dX, dY: Real): LongInt;
+function  TraceShoveFall(x, y, dX, dY: Real): LongInt;
 
 function  RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
 function  RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
@@ -80,7 +81,7 @@
         end;
 
 implementation
-uses uCollisions, uVariables, uUtils, uDebug;
+uses uCollisions, uVariables, uUtils, uDebug, uLandTexture;
 
 const KillScore = 200;
 
@@ -236,6 +237,28 @@
     TestCollExcludingMe:= TestColl(x, y, r)
 end;
 
+function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
+var b: boolean;
+begin
+    b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and $FF00 <> 0);
+    if b then
+        exit(true);
+    
+    b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and $FF00 <> 0);
+    if b then
+        exit(true);
+    
+    b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and $FF00 <> 0);
+    if b then
+        exit(true);
+    
+    b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and $FF00 <> 0);
+    if b then
+        exit(true);
+    
+    TestCollExcludingObjects:= false;
+end;
+
 function TestColl(x, y, r: LongInt): boolean; inline;
 var b: boolean;
 begin
@@ -311,16 +334,25 @@
     end;
 end;
 
-function TraceShoveFall(Me: PGear; x, y, dX, dY: Real): LongInt;
-var dmg: LongInt;
+function TraceShoveFall(x, y, dX, dY: Real): LongInt;
+var dmg, v: LongInt;
 begin
+v:= random($FFFFFFFF);
     while true do
     begin
         x:= x + dX;
         y:= y + dY;
         dY:= dY + cGravityf;
+(*
+        if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then 
+            begin
+            LandPixels[trunc(y), trunc(x)]:= v;
+            UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true);
+            end;
+*)
+
         // consider adding dX/dY calc here for fall damage
-        if TestCollExcludingMe(Me, trunc(x), trunc(y), cHHRadius) then
+        if TestCollExcludingObjects(trunc(x), trunc(y), cHHRadius) then
         begin
             if 0.4 < dY then
             begin
@@ -398,8 +430,8 @@
     dX, dY, dmgMod: real;
 begin
 fallDmg:= 0;
-dX:= gdX * 0.005 * kick;
-dY:= gdY * 0.005 * kick;
+dX:= gdX * 0.01 * kick;
+dY:= gdY * 0.01 * kick;
 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
 rate:= 0;
 for i:= 0 to Pred(Targets.Count) do
@@ -410,15 +442,13 @@
         begin
         dmg:= 0;
         if abs(Point.x - x) + abs(Point.y - y) < r then
-            begin
             dmg:= r - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)));
-            dmg:= trunc(dmg * dmgMod);
-            end;
+
         if dmg > 0 then
             begin
             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 (Flags and afTrackFall <> 0) and (Score > 0) then 
+                fallDmg:= trunc(TraceShoveFall(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
--- a/hedgewars/uCommandHandlers.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uCommandHandlers.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -436,7 +436,7 @@
         end
     else
         TryDo(checksum = lastTurnChecksum, 'Desync detected', true);
-    AddFileLog('Doing SwitchHedgehog: time '+inttostr(GameTicks));
+    AddFileLog('Next turn: time '+inttostr(GameTicks));
 end;
 
 procedure chTimer(var s: shortstring);
@@ -763,7 +763,8 @@
 
 procedure chGameFlags(var s: shortstring);
 begin
-GameFlags:= StrToInt(s)
+GameFlags:= StrToInt(s);
+if GameFlags and gfSharedAmmo <> 0 then GameFlags:= GameFlags and not gfPerHogAmmo
 end;
 
 procedure chHedgehogTurnTime(var s: shortstring);
--- a/hedgewars/uConsts.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uConsts.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -147,6 +147,7 @@
     cBlowTorchC    = 6;
 
     cKeyMaxIndex = 1023;
+    cKbdMaxIndex = 65536;//need more room for the modifier keys
 
     cHHFileName = 'Hedgehog';
     cCHFileName = 'Crosshair';
@@ -259,6 +260,8 @@
     ammoprop_Effect       = $00002000;
     ammoprop_SetBounce    = $00004000;
     ammoprop_NeedUpDown   = $00008000;//Used by TouchInterface to show or hide up/down widgets 
+    ammoprop_OscAim       = $00010000;
+    ammoprop_NoMoveAfter  = $00020000;
     ammoprop_NoRoundEnd   = $10000000;
 
     AMMO_INFINITE = 100;
--- a/hedgewars/uGears.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uGears.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -363,11 +363,11 @@
 
                 FreeActionsList; // could send -left, -right and similar commands, so should be called before /nextturn
 
+                ParseCommand('/nextturn', true);
                 SwitchHedgehog;
 
                 AfterSwitchHedgehog;
-                bBetweenTurns:= false;
-                ParseCommand('/nextturn', true)
+                bBetweenTurns:= false
                 end;
             step:= Low(step)
             end;
@@ -826,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);
@@ -859,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 Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uGearsHedgehog.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -707,12 +707,10 @@
     if (Gear^.Message and gmLeft  )<>0 then
         Gear^.dX:= -cLittle else
     if (Gear^.Message and gmRight )<>0 then
-        Gear^.dX:=  cLittle else exit;
+        Gear^.dX:=  cLittle 
+        else exit;
 
-    if (Gear^.Message and (gmLeft or gmRight)) <> 0 then
-        begin
-        StepSoundTimer:= cHHStepTicks;
-        end;
+    StepSoundTimer:= cHHStepTicks;
    
     GHStepTicks:= cHHStepTicks;
     if PrevdX <> hwSign(Gear^.dX) then
@@ -837,6 +835,7 @@
     if (CurrentHedgehog^.Gear = Gear)
         and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then 
         begin
+        // TODO: why so aggressive at setting FollowGear when falling?
         FollowGear:= Gear;
         end;
     if isUnderwater then
--- a/hedgewars/uGearsList.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uGearsList.pas	Mon Jun 11 00:06:22 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 Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uGearsRender.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -989,7 +989,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
@@ -1011,6 +1013,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 Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uGearsUtils.pas	Mon Jun 11 00:06:22 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;
@@ -481,13 +483,13 @@
     RecountTeamHealth(tempTeam);
 end;
 
-function CountNonZeroz(x, y, r, c: LongInt): LongInt;
+function CountNonZeroz(x, y, r, c: LongInt; mask: LongWord): LongInt;
 var i: LongInt;
     count: LongInt = 0;
 begin
     if (y and LAND_HEIGHT_MASK) = 0 then
         for i:= max(x - r, 0) to min(x + r, LAND_WIDTH - 4) do
-            if Land[y, i] <> 0 then
+            if Land[y, i] and mask <> 0 then
             begin
                 inc(count);
                 if count = c then
@@ -529,9 +531,10 @@
     ar2: array[0..1023] of TPoint;
     cnt, cnt2: Longword;
     delta: LongInt;
-    reallySkip, tryAgain: boolean;
+    ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
 begin
-reallySkip:= false; // try not skipping proximity at first
+ignoreNearObjects:= false; // try not skipping proximity at first
+ignoreOverlap:= false; // this not only skips proximity, but allows overlapping objects (barrels, mines, hogs, crates).  Saving it for a 3rd pass.  With this active, winning AI Survival goes back to virtual impossibility
 tryAgain:= true;
 while tryAgain do
     begin
@@ -547,23 +550,27 @@
                 begin
                 repeat
                     inc(y, 2);
-                until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) = 0);
+                until (y >= cWaterLine) or
+                        (not ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or 
+                        (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) = 0));
 
                 sy:= y;
 
                 repeat
                     inc(y);
-                until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) <> 0);
+                until (y >= cWaterLine) or
+                        (not ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or 
+                        (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) <> 0)); 
 
                 if (y - sy > Gear^.Radius * 2)
                     and (((Gear^.Kind = gtExplosives)
                     and (y < cWaterLine)
-                    and (reallySkip or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60))
-                    and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1) > Gear^.Radius))
+                    and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60))
+                    and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1, $FFFF) > Gear^.Radius))
                 or
                     ((Gear^.Kind <> gtExplosives)
                     and (y < cWaterLine)
-                    and (reallySkip or NoGearsToAvoid(x, y - Gear^.Radius, 110, 110))
+                    and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 110, 110))
                     )) then
                     begin
                     ar[cnt].X:= x;
@@ -588,10 +595,12 @@
 
         dec(Delta, 60)
     until (cnt2 > 0) or (Delta < 70);
-    if (cnt2 = 0) and skipProximity and (not reallySkip) then
+    // if either of these has not been tried, do another pass
+    if (cnt2 = 0) and skipProximity and (not ignoreOverlap) then
         tryAgain:= true
     else tryAgain:= false;
-    reallySkip:= true;
+    if ignoreNearObjects then ignoreOverlap:= true;
+    ignoreNearObjects:= true;
     end;
 
 if cnt2 > 0 then
--- a/hedgewars/uInputHandler.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uInputHandler.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -25,7 +25,9 @@
 procedure initModule;
 procedure freeModule;
 
-function  KeyNameToCode(name: shortstring): word;
+function  KeyNameToCode(name: shortstring; Modifier: shortstring = ''): LongInt;
+procedure MaskModifier(var code: LongInt; modifier: LongWord);
+procedure MaskModifier(Modifier: shortstring; var code: LongInt);
 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
 procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
 procedure ProcessKey(code: LongInt; KeyDown: boolean);
@@ -45,37 +47,79 @@
 implementation
 uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug;
 
-var tkbd: array[0..cKeyMaxIndex] of boolean;
+const
+    LSHIFT = $0200;
+    RSHIFT = $0400;
+    LALT   = $0800;
+    RALT   = $1000;
+    LCTRL  = $2000;
+    RCTRL  = $4000; 
+
+var tkbd: array[0..cKbdMaxIndex] of boolean;
     quitKeyCode: Byte;
     KeyNames: array [0..cKeyMaxIndex] of string[15];
     CurrentBinds: TBinds;
 
-function KeyNameToCode(name: shortstring): word;
-var code: Word;
+function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
+var code: LongInt;
 begin
     name:= LowerCase(name);
     code:= cKeyMaxIndex;
     while (code > 0) and (KeyNames[code] <> name) do dec(code);
+
+    MaskModifier(Modifier, code);
     KeyNameToCode:= code;
 end;
 
+procedure MaskModifier(var code: LongInt; Modifier: LongWord);
+begin
+    if(Modifier and KMOD_LSHIFT) <> 0 then code:= code or LSHIFT; 
+    if(Modifier and KMOD_RSHIFT) <> 0 then code:= code or LSHIFT; 
+    if(Modifier and KMOD_LALT) <> 0 then code:= code or LALT; 
+    if(Modifier and KMOD_RALT) <> 0 then code:= code or LALT; 
+    if(Modifier and KMOD_LCTRL) <> 0 then code:= code or LCTRL; 
+    if(Modifier and KMOD_RCTRL) <> 0 then code:= code or LCTRL; 
+end;
+
+procedure MaskModifier(Modifier: shortstring; var code: LongInt);
+var mod_ : shortstring;
+    ModifierCount, i: LongInt;
+begin
+if Modifier = '' then exit;
+ModifierCount:= 0;
+
+for i:= 1 to Length(Modifier) do
+    if(Modifier[i] = ':') then inc(ModifierCount);
+
+SplitByChar(Modifier, mod_, ':');//remove the first mod: part
+Modifier:= mod_;
+for i:= 0 to ModifierCount do
+    begin 
+    mod_:= '';
+    SplitByChar(Modifier, mod_, ':');
+    if (Modifier = 'lshift')                    then code:= code or LSHIFT;
+    if (Modifier = 'rshift')                    then code:= code or RSHIFT;
+    if (Modifier = 'lalt')                      then code:= code or LALT;
+    if (Modifier = 'ralt')                      then code:= code or RALT;
+    if (Modifier = 'lctrl') or (mod_ = 'lmeta') then code:= code or LCTRL;
+    if (Modifier = 'rctrl') or (mod_ = 'rmeta') then code:= code or RCTRL;
+    Modifier:= mod_;
+    end;
+end;
+
 procedure ProcessKey(code: LongInt; KeyDown: boolean);
 var
     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);
 
-
-
 // ctrl/cmd + q to close engine and frontend
 if(KeyDown and (code = quitKeyCode)) then
     begin
@@ -109,8 +153,11 @@
 end;
 
 procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
+var code: LongInt;
 begin
-    ProcessKey(event.keysym.sym, event.type_ = SDL_KEYDOWN);
+    code:= event.keysym.sym;
+    //MaskModifier(code, event.keysym.modifier);
+    ProcessKey(code, event.type_ = SDL_KEYDOWN);
 end;
 
 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
@@ -132,7 +179,7 @@
 procedure ResetKbd;
 var t: LongInt;
 begin
-for t:= 0 to cKeyMaxIndex do
+for t:= 0 to cKbdMaxIndex do
     if tkbd[t] then
         ProcessKey(t, False);
 end;
@@ -239,11 +286,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 cKbdMaxIndex do
+    if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
+        ProcessKey(t, False);
+
     CurrentBinds:= binds;
 {$ENDIF}
 end;
--- a/hedgewars/uLand.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uLand.pas	Mon Jun 11 00:06:22 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);
--- a/hedgewars/uLandGraphics.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uLandGraphics.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -463,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;
 
@@ -515,7 +515,7 @@
     end;
 
 
-UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT)
+UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false)
 end;
 
 //
@@ -665,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;
@@ -753,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;
@@ -955,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;
--- a/hedgewars/uLandTexture.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uLandTexture.pas	Mon Jun 11 00:06:22 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^.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^.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;
 
--- a/hedgewars/uStore.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uStore.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -1118,7 +1118,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 Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uTeams.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -248,8 +248,6 @@
     FollowGear:= Gear
     end;
 
-ResetKbd;
-
 if (GameFlags and gfDisableWind) = 0 then
     begin
     cWindSpeed:= rndSign(GetRandomf * 2 * cMaxWindSpeed);
@@ -554,22 +552,33 @@
 end;
 
 procedure chBind(var id: shortstring);
-var s: shortstring;
+var KeyName, Modifier, tmp: shortstring;
     b: LongInt;
 begin
-s:= '';
+KeyName:= '';
+Modifier:= '';
+
 if CurrentTeam = nil then
     exit;
-SplitBySpace(id, s);
-if s[1]='"' then
-    Delete(s, 1, 1);
-if s[byte(s[0])]='"' then
-    Delete(s, byte(s[0]), 1);
-b:= KeyNameToCode(id);
+
+if(Pos('mod:', id) <> 0)then
+    begin
+    tmp:= '';
+    SplitBySpace(id, tmp);
+    Modifier:= id;
+    id:= tmp;
+    end;
+
+SplitBySpace(id, KeyName);
+if KeyName[1]='"' then
+    Delete(KeyName, 1, 1);
+if KeyName[byte(KeyName[0])]='"' then
+    Delete(KeyName, byte(KeyName[0]), 1);
+b:= KeyNameToCode(id, Modifier);
 if b = 0 then
     OutError(errmsgUnknownVariable + ' "' + id + '"', false)
 else
-    CurrentTeam^.Binds[b]:= s
+    CurrentTeam^.Binds[b]:= KeyName;
 end;
 
 procedure chTeamGone(var s:shortstring);
--- a/hedgewars/uTouch.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uTouch.pas	Mon Jun 11 00:06:22 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/uTypes.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uTypes.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -308,7 +308,7 @@
         TeamDamage : Longword;
         end;
 
-    TBinds = array[0..cKeyMaxIndex] of shortstring;
+    TBinds = array[0..cKbdMaxIndex] of shortstring;
     TKeyboardState = array[0..cKeyMaxIndex] of Byte;
 
     PVoicepack = ^TVoicepack;
--- a/hedgewars/uUtils.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uUtils.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -24,6 +24,7 @@
 uses uTypes, uFloat, GLunit;
 
 procedure SplitBySpace(var a, b: shortstring);
+procedure SplitByChar(var a, b: shortstring; c: char);
 procedure SplitByChar(var a, b: ansistring; c: char);
 
 {$IFNDEF PAS2C}
@@ -83,11 +84,16 @@
 {$ENDIF}
 var CharArray: array[byte] of Char;
 
+procedure SplitBySpace(var a,b: shortstring);
+begin
+SplitByChar(a,b,' ');
+end;
+
 // should this include "strtolower()" for the split string?
-procedure SplitBySpace(var a, b: shortstring);
+procedure SplitByChar(var a, b: shortstring; c : char);
 var i, t: LongInt;
 begin
-i:= Pos(' ', a);
+i:= Pos(c, a);
 if i > 0 then
     begin
     for t:= 1 to Pred(i) do
--- a/hedgewars/uVariables.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uVariables.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -1828,7 +1828,9 @@
             NameTex: nil;
             Probability: 20;
             NumberInCase: 2;
-            Ammo: (Propz: ammoprop_NeedUpDown;
+            Ammo: (Propz: ammoprop_NeedUpDown or 
+                    ammoprop_OscAim or
+                    ammoprop_NoMoveAfter;
                 Count: 2;
                 NumPerTurn: 1;
                 Timer: 0;
--- a/hedgewars/uWorld.pas	Mon Jun 11 00:02:17 2012 +0200
+++ b/hedgewars/uWorld.pas	Mon Jun 11 00:06:22 2012 +0200
@@ -1512,9 +1512,6 @@
             DrawTexture((cScreenWidth shr 1) - 60 - offsetY, offsetX, fpsTexture);
         end;
 
-    if CountTicks >= 1000 then
-        CountTicks:= 0;
-
     // lag warning (?)
     inc(SoundTimerTicks, Lag);
 end;
@@ -1606,7 +1603,10 @@
 {$ENDIF}
 z:= round(200/zoom);
 if not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) then
-    if (not autoCameraOn) or ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then
+    if (not autoCameraOn) then
+        FollowGear:= nil
+    else        
+    if ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then
         begin
         FollowGear:= nil;
         prevPoint:= CursorPoint;
@@ -1656,7 +1656,7 @@
     EdgesDist:= cGearScrEdgesDist;
 
 // this generates the border around the screen that moves the camera when cursor is near it
-if isCursorVisible or (FollowGear <> nil) then
+if isCursorVisible or ((FollowGear <> nil) and autoCameraOn) then
     begin
     if CursorPoint.X < - cScreenWidth div 2 + EdgesDist then
         begin
--- a/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp	Mon Jun 11 00:02:17 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp	Mon Jun 11 00:06:22 2012 +0200
@@ -638,16 +638,12 @@
     return Android_JNI_FileClose(ctx, true);
 }
 
-/*******************************************************************************
-             Functions called by the hwengine into Java
-*******************************************************************************/
-
-extern "C" float Android_JNI_getDensity(){
+extern "C" int Android_JNI_getDensity(){
     jmethodID mid;
-    jfloat density;
+    jint density;
     //SDLActivity.getDensity()
-    mid = mEnv->GetStaticMethodID(mActivityClass, "getDensity", "()F");
-        if(!mid) return 1.5f;
+    mid = mEnv->GetStaticMethodID(mActivityClass, "getDensity", "()I");
+        if(!mid) return 160;
     density = mEnv->CallStaticFloatMethod(mActivityClass, mid);
     return density;
 
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Mon Jun 11 00:02:17 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Mon Jun 11 00:06:22 2012 +0200
@@ -403,9 +403,9 @@
 		}
 	}
 	
-	public static float getDensity(){
+	public static int getDensity(){
 		DisplayMetrics dm = SDLActivity.getContext().getResources().getDisplayMetrics();
-		return dm.density;
+		return dm.densityDpi;
 	}
 }
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Mon Jun 11 00:02:17 2012 +0200
+++ b/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Mon Jun 11 00:06:22 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