First pass at cleaver.
authornemo
Sun, 14 Oct 2012 13:35:15 -0400
changeset 7754 e81dc9bef8b8
parent 7753 dda33caa609d
child 7755 b8958e64e68d
First pass at cleaver.
QTfrontend/hwconsts.h
hedgewars/GSHandlers.inc
hedgewars/uAmmos.pas
hedgewars/uCollisions.pas
hedgewars/uGears.pas
hedgewars/uGearsHedgehog.pas
hedgewars/uGearsList.pas
hedgewars/uGearsUtils.pas
hedgewars/uScript.pas
hedgewars/uStore.pas
hedgewars/uTypes.pas
hedgewars/uVariables.pas
share/hedgewars/Data/Graphics/AmmoMenu/Ammos.png
share/hedgewars/Data/Graphics/AmmoMenu/Ammos_bw.png
share/hedgewars/Data/Graphics/Hats/Reserved/chef.png
share/hedgewars/Data/Graphics/Hedgehog/amCleaver.png
share/hedgewars/Data/Graphics/cleaver.png
share/hedgewars/Data/Graphics/cleaver.svg
share/hedgewars/Data/Graphics/star.png
share/hedgewars/Data/Locale/en.txt
--- a/QTfrontend/hwconsts.h	Sun Oct 14 00:22:33 2012 +0400
+++ b/QTfrontend/hwconsts.h	Sun Oct 14 13:35:15 2012 -0400
@@ -63,40 +63,40 @@
 
 #define HEDGEHOGS_PER_TEAM           8
 
-#define AMMOLINE_DEFAULT_QT     "93919294221991210322351110012010000002111101010111110111"
-#define AMMOLINE_DEFAULT_PROB   "04050405416006555465544647765766666661555101011154110111"
+#define AMMOLINE_DEFAULT_QT     "93919294221991210322351110012010000002111101010111110101"
+#define AMMOLINE_DEFAULT_PROB   "04050405416006555465544647765766666661555101011154110101"
 #define AMMOLINE_DEFAULT_DELAY  "00000000000002055000000400070040000000002200000006000000"
 #define AMMOLINE_DEFAULT_CRATE  "13111103121111111231141111111111111112111111011111110101"
 
-#define AMMOLINE_CRAZY_QT       "99999999999999999929999999999999992999999999099999920999"
-#define AMMOLINE_CRAZY_PROB     "11111101111111111111111111111111111111111111011111110111"
+#define AMMOLINE_CRAZY_QT       "99999999999999999929999999999999992999999999099999920909"
+#define AMMOLINE_CRAZY_PROB     "11111101111111111111111111111111111111111111011111110101"
 #define AMMOLINE_CRAZY_DELAY    "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE    "13111103121111111231141111111111111112111101011111110111"
+#define AMMOLINE_CRAZY_CRATE    "13111103121111111231141111111111111112111101011111110101"
 
 #define AMMOLINE_PROMODE_QT     "90900090000000000000090000000000000000000000000000000001"
 #define AMMOLINE_PROMODE_PROB   "00000000000000000000000000000000000000000000000000000000"
 #define AMMOLINE_PROMODE_DELAY  "00000000000002055000000400070040000000002000000000000009"
-#define AMMOLINE_PROMODE_CRATE  "11111111111111111111111111111111111111111001011111110111"
+#define AMMOLINE_PROMODE_CRATE  "11111111111111111111111111111111111111111001011111110101"
 
 #define AMMOLINE_SHOPPA_QT      "00000099000000000000000000000000000000000000000000000000"
 #define AMMOLINE_SHOPPA_PROB    "44444100442444022101121212224220000000020004000100110000"
 #define AMMOLINE_SHOPPA_DELAY   "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE   "11111111111111111111111111111111111111111011011111110011"
+#define AMMOLINE_SHOPPA_CRATE   "11111111111111111111111111111111111111111011011111110001"
 
 #define AMMOLINE_CLEAN_QT       "10100090000100000110000000000000000000000000000010000000"
-#define AMMOLINE_CLEAN_PROB     "04050405416006555465544647765766666661555101011154110111"
+#define AMMOLINE_CLEAN_PROB     "04050405416006555465544647765766666661555101011154110101"
 #define AMMOLINE_CLEAN_DELAY    "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CLEAN_CRATE    "13111103121111111231141111111111111112111111011111110111"
+#define AMMOLINE_CLEAN_CRATE    "13111103121111111231141111111111111112111111011111110101"
 
 #define AMMOLINE_MINES_QT       "00000099000900000003000000000000000000000000000000000000"
 #define AMMOLINE_MINES_PROB     "00000000000000000000000000000000000000000000000000000000"
 #define AMMOLINE_MINES_DELAY    "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_MINES_CRATE    "11111111111111111111111111111111111111111111011111110111"
+#define AMMOLINE_MINES_CRATE    "11111111111111111111111111111111111111111111011111110101"
 
 #define AMMOLINE_PORTALS_QT     "90000090020000000021000000000000001100000900000000000000"
-#define AMMOLINE_PORTALS_PROB   "04050405416006555465544647765766666661555101011154110110"
+#define AMMOLINE_PORTALS_PROB   "04050405416006555465544647765766666661555101011154110100"
 #define AMMOLINE_PORTALS_DELAY  "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_PORTALS_CRATE  "13111103121111111231141111111111111112111111011111110111"
+#define AMMOLINE_PORTALS_CRATE  "13111103121111111231141111111111111112111111011111110101"
 
 //Different seasons; assigned to season (int)
 #define SEASON_NONE 0
--- a/hedgewars/GSHandlers.inc	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/GSHandlers.inc	Sun Oct 14 13:35:15 2012 -0400
@@ -1414,30 +1414,26 @@
             end;
         CalcRotationDirAngle(Gear);
         AllInactive := false
-    end
-    else
-        if ((GameTicks and $3F) = 25) then
-            doStepFallingGear(Gear);
+        end
+    else if (GameTicks and $3F) = 25 then
+        doStepFallingGear(Gear);
     if (Gear^.Health = 0) then
         begin
-            if not Gear^.dY.isNegative and (Gear^.dY > _0_2) and (TestCollisionYwithGear(Gear, 1) <> 0) then
-                inc(Gear^.Damage, hwRound(Gear^.dY * _70))
-                
-            else if not Gear^.dX.isNegative and (Gear^.dX > _0_2) and TestCollisionXwithGear(Gear, 1) then
-                inc(Gear^.Damage, hwRound(Gear^.dX * _70))
-                
-            else if Gear^.dY.isNegative and (Gear^.dY < -_0_2) and (TestCollisionYwithGear(Gear, -1) <> 0) then
-                inc(Gear^.Damage, hwRound(Gear^.dY * -_70))
-                
-            else if Gear^.dX.isNegative and (Gear^.dX < -_0_2) and TestCollisionXwithGear(Gear, -1) then
-                inc(Gear^.Damage, hwRound(Gear^.dX * -_70));
+        if not Gear^.dY.isNegative and (Gear^.dY > _0_2) and (TestCollisionYwithGear(Gear, 1) <> 0) then
+            inc(Gear^.Damage, hwRound(Gear^.dY * _70))
+        else if not Gear^.dX.isNegative and (Gear^.dX > _0_2) and TestCollisionXwithGear(Gear, 1) then
+            inc(Gear^.Damage, hwRound(Gear^.dX * _70))
+        else if Gear^.dY.isNegative and (Gear^.dY < -_0_2) and (TestCollisionYwithGear(Gear, -1) <> 0) then
+            inc(Gear^.Damage, hwRound(Gear^.dY * -_70))
+        else if Gear^.dX.isNegative and (Gear^.dX < -_0_2) and TestCollisionXwithGear(Gear, -1) then
+            inc(Gear^.Damage, hwRound(Gear^.dX * -_70));
         
         if ((GameTicks and $FF) = 0) and (Gear^.Damage > random(30)) then
-                begin
-                vg:= AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
-                if vg <> nil then
-                    vg^.Scale:= 0.5
-                end;
+            begin
+            vg:= AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
+            if vg <> nil then
+                vg^.Scale:= 0.5
+            end;
 
         if (Gear^.Damage > 35) then
             begin
@@ -4687,7 +4683,7 @@
                 // only make hat-less hedgehogs look like zombies, preserve existing hats
 
                 if resgear^.Hedgehog^.Hat = 'NoHat' then
-                    LoadHedgehogHat(resgear, 'Reserved/Zombie');
+                    LoadHedgehogHat(resgear^.Hedgehog^, 'Reserved/Zombie');
                 end;
 
         hh^.Gear^.dY := _0;
@@ -5245,6 +5241,59 @@
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
+procedure doStepKnife(Gear: PGear);
+var ox, oy: LongInt;
+    la: hwFloat;
+begin
+    // Gear is shrunk so it can actually escape the hog without carving into the terrain
+    if (Gear^.Radius = 6) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 16;
+    if (Gear^.State and gstMoving <> 0) and (Gear^.State and gstCollision = 0) then
+        begin
+        DeleteCI(Gear);
+        // used for damage and impact calc. needs balancing I think
+        Gear^.Health:= hwRound(hwSqr((hwAbs(Gear^.dY)+hwAbs(Gear^.dX))*_4));
+        doStepFallingGear(Gear);
+        AllInactive := false;
+        CalcRotationDirAngle(Gear)
+        end
+    else if Gear^.CollisionIndex = -1 then
+        begin
+        ox:= 0; oy:= 0;
+        if      TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1
+        else if TestCollisionXwithGear(Gear, 1)       then ox:=  1
+        else if TestCollisionXwithGear(Gear, -1)      then ox:= -1
+        else if TestCollisionYwithGear(Gear, 1) <> 0  then oy:=  1;
+        if Gear^.Health > 0 then
+            PlaySound(sndRopeAttach);
+        la:= _0;
+        if (ox <> 0) or (oy <> 0) then
+            la:= CalcSlopeNearGear(Gear, ox, oy);
+        if la = _0 then
+            begin
+            // debug for when we couldn't get an angle
+            //AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeWhite);
+            Gear^.DirAngle:= DxDy2Angle(Gear^.dX, Gear^.dY)*hwSign(Gear^.dX) + (random(20)-10)
+            end
+        else Gear^.DirAngle:= hwFloat2Float(la)*90; // sheepluva's comment claims 45deg = 0.5 - yet orientation doesn't seem consistent?
+        Gear^.dX:= _0;
+        Gear^.dY:= _0;
+        Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
+        Gear^.Radius:= 20;
+        if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
+        Gear^.Radius:= 16;
+        Gear^.Health:= 0;
+        AddGearCI(Gear)
+        end
+    else if GameTicks and $3F = 0 then
+        begin
+        if  (TestCollisionYwithGear(Gear, -1) = 0)
+        and not TestCollisionXwithGear(Gear, 1)
+        and not TestCollisionXwithGear(Gear, -1)
+        and (TestCollisionYwithGear(Gear, 1) = 0) then Gear^.State:= Gear^.State and (not gstCollision) or gstMoving;
+        end
+end;
+(*
+ This didn't end up getting used, but, who knows, might be reasonable for javellin or something
 // Make the knife initial angle based on the hog attack angle, or is that too hard?
 procedure doStepKnife(Gear: PGear);
 var t, 
@@ -5374,3 +5423,4 @@
             end
         end;
 end;
+*)
--- a/hedgewars/uAmmos.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uAmmos.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -20,7 +20,7 @@
 
 unit uAmmos;
 interface
-uses uConsts, uTypes;
+uses uConsts, uTypes, uStore;
 
 procedure initModule;
 procedure freeModule;
@@ -277,6 +277,7 @@
                 begin
                 PackAmmo(Ammo, Ammoz[AmmoType].Slot);
                 //SwitchNotHeldAmmo(Hedgehog);
+                if CurAmmoType = amKnife then LoadHedgehogHat(Hedgehog, Hedgehog.Hat);
                 CurAmmoType:= amNothing
                 end
             end
@@ -347,6 +348,7 @@
         end;
     TryDo(slot <= cMaxSlotIndex, 'Ammo slot index overflow', true);
     CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
+    if CurAmmoType = amKnife then LoadHedgehogHat(Hedgehog, 'Reserved/chef')
     end
 end;
 
--- a/hedgewars/uCollisions.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uCollisions.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -56,6 +56,7 @@
 
 // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45° = _0_5)
 function  CalcSlopeBelowGear(Gear: PGear): hwFloat;
+function  CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
 function  CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean;
 
 implementation
@@ -139,8 +140,8 @@
 begin
 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
 if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
-    ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.X) - Gear^.Radius) or
-     (hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.X) + Gear^.Radius)) then
+    ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.X) - Gear^.Radius) or
+     (hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.X) + Gear^.Radius)) then
     Gear^.CollisionMask:= $FFFF;
 
 x:= hwRound(Gear^.X);
@@ -169,8 +170,8 @@
 begin
 // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
 if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
-    ((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.Y) - Gear^.Radius) or
-     (hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.Y) + Gear^.Radius)) then
+    ((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.Y) - Gear^.Radius) or
+     (hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.Y) + Gear^.Radius)) then
     Gear^.CollisionMask:= $FFFF;
 
 y:= hwRound(Gear^.Y);
@@ -238,7 +239,7 @@
         with cinfos[i] do
             if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
             and ((mx > x) xor (Dir > 0)) then
-                if ((cGear^.Kind in [gtHedgehog, gtMine]) and ((Gear^.State and gstNotKickable) = 0)) or
+                if ((cGear^.Kind in [gtHedgehog, gtMine, gtKnife]) and ((Gear^.State and gstNotKickable) = 0)) or
                 // only apply X kick if the barrel is knocked over
                 ((cGear^.Kind = gtExplosives) and ((cGear^.State and gsttmpflag) <> 0)) then
                     begin
@@ -247,6 +248,7 @@
                         dX:= Gear^.dX;
                         dY:= Gear^.dY * _0_5;
                         State:= State or gstMoving;
+                        if Kind = gtKnife then State:= State and not gstCollision;
                         Active:= true
                         end;
                     DeleteCI(cGear);
@@ -298,7 +300,7 @@
         with cinfos[i] do
             if (Gear <> cGear) and (sqr(mx - x) + sqr(my - y) <= sqr(Radius + Gear^.Radius + 2))
             and ((my > y) xor (Dir > 0)) then
-                if (cGear^.Kind in [gtHedgehog, gtMine, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
+                if (cGear^.Kind in [gtHedgehog, gtMine, gtKnife, gtExplosives]) and ((Gear^.State and gstNotKickable) = 0) then
                     begin
                     with cGear^ do
                         begin
@@ -306,6 +308,7 @@
                             dX:= Gear^.dX * _0_5;
                         dY:= Gear^.dY;
                         State:= State or gstMoving;
+                        if Kind = gtKnife then State:= State and not gstCollision;
                         Active:= true
                         end;
                     DeleteCI(cGear);
@@ -576,6 +579,99 @@
 CalcSlopeTangent:= true;
 end;
 
+function CalcSlopeNearGear(Gear: PGear; dirX, dirY: LongInt): hwFloat;
+var dx, dy: hwFloat;
+    collX, collY, i, y, x, gx, gy, sdx, sdy: LongInt;
+    isColl, bSucc: Boolean;
+begin
+
+if dirY <> 0 then 
+    begin
+    y:= hwRound(Gear^.Y) + Gear^.Radius * dirY;
+    gx:= hwRound(Gear^.X);
+    collX := gx;
+    isColl:= false;
+
+    if (y and LAND_HEIGHT_MASK) = 0 then
+        begin
+        x:= hwRound(Gear^.X) - Gear^.Radius + 1;
+        i:= x + Gear^.Radius * 2 - 2;
+        repeat
+        if (x and LAND_WIDTH_MASK) = 0 then
+            if Land[y, x] <> 0 then
+                if not isColl or (abs(x-gx) < abs(collX-gx)) then
+                    begin
+                    isColl:= true;
+                    collX := x;
+                    end;
+        inc(x)
+        until (x > i);
+        end;
+    end
+else
+    begin
+    x:= hwRound(Gear^.X) + Gear^.Radius * dirX;
+    gy:= hwRound(Gear^.Y);
+    collY := gy;
+    isColl:= false;
+
+    if (x and LAND_WIDTH_MASK) = 0 then
+        begin
+        y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
+        i:= y + Gear^.Radius * 2 - 2;
+        repeat
+        if (y and LAND_HEIGHT_MASK) = 0 then
+            if Land[y, x] <> 0 then
+                if not isColl or (abs(y-gy) < abs(collY-gy)) then
+                    begin
+                    isColl:= true;
+                    collY := y;
+                    end;
+        inc(y)
+        until (y > i);
+        end;
+    end;
+
+if isColl then
+    begin
+    // save original dx/dy
+    dx := Gear^.dX;
+    dy := Gear^.dY;
+
+    if dirY <> 0 then
+        begin
+        Gear^.dX.QWordValue:= 0;
+        Gear^.dX.isNegative:= (collX >= gx);
+        Gear^.dY:= _1*dirY
+        end
+    else
+        begin
+        Gear^.dY.QWordValue:= 0;
+        Gear^.dY.isNegative:= (collY >= gy);
+        Gear^.dX:= _1*dirX
+        end;
+
+    sdx:= 0;
+    sdy:= 0;
+    if dirY <> 0 then
+         bSucc := CalcSlopeTangent(Gear, collX, y, sdx, sdy, 0)
+    else bSucc := CalcSlopeTangent(Gear, x, collY, sdx, sdy, 0);
+
+    // restore original dx/dy
+    Gear^.dX := dx;
+    Gear^.dY := dy;
+
+    if bSucc and ((sdx <> 0) or (sdy <> 0)) then
+        begin
+        dx := int2hwFloat(sdy) / (abs(sdx) + abs(sdy));
+        dx.isNegative := (sdx * sdy) < 0;
+        exit (dx);
+        end
+    end;
+
+CalcSlopeNearGear := _0;
+end;
+
 function CalcSlopeBelowGear(Gear: PGear): hwFloat;
 var dx, dy: hwFloat;
     collX, i, y, x, gx, sdx, sdy: LongInt;
--- a/hedgewars/uGears.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uGears.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -730,7 +730,7 @@
 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
 var t: PGearArray;
     Gear: PGear;
-    i, tmpDmg: LongInt;
+    i, j, tmpDmg: LongInt;
     VGear: PVisualGear;
 begin
 t:= CheckGearsCollision(Ammo);
@@ -769,6 +769,7 @@
             gtHedgehog,
             gtMine,
             gtSMine,
+            gtKnife,
             gtTarget,
             gtCase,
             gtExplosives,
@@ -780,7 +781,28 @@
                 exit;
                 end;
             if (not Gear^.Invulnerable) then
+                begin
+                if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
+                    for j:= 1 to max(1,min(3,tmpDmg div 5)) do
+                        begin
+                        VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
+                        if VGear <> nil then
+                            with VGear^ do
+                                begin
+                                Tint:= $FFCC00FF;
+                                Angle:= random(360);
+                                dx:= 0.0005 * (random(100));
+                                dy:= 0.0005 * (random(100));
+                                if random(2) = 0 then
+                                    dx := -dx;
+                                if random(2) = 0 then
+                                    dy := -dy;
+                                FrameTicks:= 600+random(200);
+                                State:= ord(sprStar)
+                                end
+                        end;
                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
+                end
             else
                 Gear^.State:= Gear^.State or gstWinner;
             if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then 
@@ -790,35 +812,39 @@
                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
                 end;
 
-            DeleteCI(Gear);
             if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then
                 begin
                 Gear^.dX:= Ammo^.dX * Power * _0_005;
                 Gear^.dY:= Ammo^.dY * Power * _0_005
                 end
-            else
+            else if (Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog) then
                 begin
                 Gear^.dX:= Ammo^.dX * Power * _0_01;
                 Gear^.dY:= Ammo^.dY * Power * _0_01
                 end;
 
-            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
+            if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
                 begin
-                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^.Active:= true;
+                DeleteCI(Gear);
+                Gear^.State:= Gear^.State or gstMoving;
+                if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and not gstCollision;
+                // 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))
+                    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;
+                    end
                 end;
 
+
             if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then
                 FollowGear:= Gear
             end;
--- a/hedgewars/uGearsHedgehog.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uGearsHedgehog.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -42,6 +42,7 @@
 function ChangeAmmo(HHGear: PGear): boolean;
 var slot, i: Longword;
     ammoidx: LongInt;
+    prevAmmo: TAmmoType;
 begin
 ChangeAmmo:= false;
 slot:= HHGear^.MsgParam;
@@ -49,6 +50,7 @@
 with HHGear^.Hedgehog^ do
     begin
     HHGear^.Message:= HHGear^.Message and (not gmSlot);
+    prevAmmo:= CurAmmoType;
     ammoidx:= 0;
     if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0)
     or ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0))
@@ -95,6 +97,13 @@
         end;
         if ammoidx >= 0 then
             CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
+    if (prevAmmo <> CurAmmoType) then
+        begin
+        if CurAmmoType = amKnife then
+            LoadHedgehogHat(HHGear^.Hedgehog^, 'Reserved/chef')
+        else if prevAmmo = amKnife then
+            LoadHedgehogHat(HHGear^.Hedgehog^, Hat);
+        end
     end
 end;
 
@@ -262,7 +271,11 @@
                          amRope: newGear:= AddGear(hwRound(lx), hwRound(ly), gtRope, 0, xx, yy, 0);
                          amMine: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, SignAs(_0_02, dX), _0, 3000);
                         amSMine: newGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
-                        amKnife: newGear:= AddGear(hwRound(lx), hwRound(ly), gtKnife,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
+                        amKnife: begin 
+                                 newGear:= AddGear(hwRound(lx), hwRound(ly), gtKnife,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
+                                 newGear^.State:= newGear^.State or gstMoving; 
+                                 newGear^.Radius:= 6 // temporarily shrink so it doesn't instantly embed in the ground
+                                 end;
                        amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
                       amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
                     amPortalGun: begin
--- a/hedgewars/uGearsList.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uGearsList.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -251,9 +251,8 @@
                 gear^.Timer:= 500;
                 end;
        gtKnife: begin
-                gear^.Density:= _0_5;
-                gear^.Radius:= 1;
-                gear^.CollisionMask:= $FF00;
+                gear^.Density:= _4;
+                gear^.Radius:= 16
                 end;
         gtCase: begin
                 gear^.ImpactSound:= sndGraveImpact;
--- a/hedgewars/uGearsUtils.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uGearsUtils.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -105,6 +105,7 @@
                 gtCase,
                 gtTarget,
                 gtFlame,
+                gtKnife,
                 gtExplosives,
                 gtStructure: begin
 // Run the calcs only once we know we have a type that will need damage
@@ -130,6 +131,7 @@
                                 Gear^.dY:= Gear^.dY + SignAs(_0_005 * dmg + cHHKick, tdY)/(Gear^.Density/_3);
 
                                 Gear^.State:= (Gear^.State or gstMoving) and (not gstLoser);
+                                if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and not gstCollision;
                                 if not Gear^.Invulnerable then
                                     Gear^.State:= (Gear^.State or gstMoving) and (not gstWinner);
                                 Gear^.Active:= true;
--- a/hedgewars/uScript.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uScript.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -1669,7 +1669,7 @@
         if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
             hat:= lua_tostring(L, 2);
             gear^.Hedgehog^.Hat:= hat;
-            LoadHedgehogHat(gear, hat);
+            LoadHedgehogHat(gear^.Hedgehog^, hat);
         end;
     lc_sethoghat:= 0;
 end;
--- a/hedgewars/uStore.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uStore.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -40,7 +40,7 @@
 // like LoadDataImage but uses altFile as fallback-filename if file cannot be loaded
 function  LoadDataImageAltFile(const path: TPathType; const filename, altFile: shortstring; imageFlags: LongInt): PSDL_Surface;
 
-procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring);
+procedure LoadHedgehogHat(var HH: THedgehog; newHat: shortstring);
 procedure SetupOpenGL;
 procedure SetScale(f: GLfloat);
 function  RenderHelpWindow(caption, subcaption, description, extra: ansistring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
@@ -244,9 +244,9 @@
                     if Hat <> 'NoHat' then
                         begin
                         if (Length(Hat) > 39) and (Copy(Hat,1,8) = 'Reserved') and (Copy(Hat,9,32) = PlayerHash) then
-                            LoadHedgehogHat(Gear, 'Reserved/' + Copy(Hat,9,Length(Hat)-8))
+                            LoadHedgehogHat(Hedgehogs[i], 'Reserved/' + Copy(Hat,9,Length(Hat)-8))
                         else
-                            LoadHedgehogHat(Gear, Hat);
+                            LoadHedgehogHat(Hedgehogs[i], Hat);
                         end
                     end;
         end;
@@ -640,19 +640,20 @@
     LoadDataImageAltFile:= tmpsurf;
 end;
 
-procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring);
+procedure LoadHedgehogHat(var HH: THedgehog; newHat: shortstring);
 var texsurf: PSDL_Surface;
 begin
     texsurf:= LoadDataImage(ptHats, newHat, ifNone);
-
+AddFileLog('Hat => '+newHat);
     // only do something if the hat could be loaded
     if texsurf <> nil then
         begin
+AddFileLog('Got Hat');
         // free the mem of any previously assigned texture
-        FreeTexture(HHGear^.Hedgehog^.HatTex);
+        FreeTexture(HH.HatTex);
 
         // assign new hat to hedgehog
-        HHGear^.Hedgehog^.HatTex:= Surface2Tex(texsurf, true);
+        HH.HatTex:= Surface2Tex(texsurf, true);
 
         // cleanup: free temporary surface mem
         SDL_FreeSurface(texsurf)
--- a/hedgewars/uTypes.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uTypes.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -86,7 +86,7 @@
             sprHandResurrector, sprCross, sprAirDrill, sprNapalmBomb,
             sprBulletHit, sprSnowball, sprHandSnowball, sprSnow,
             sprSDFlake, sprSDWater, sprSDCloud, sprSDSplash, sprSDDroplet, sprTardis,
-            sprSlider, sprBotlevels, sprHandKnife, sprKnife
+            sprSlider, sprBotlevels, sprHandKnife, sprKnife, sprStar
             );
 
     // Gears that interact with other Gears and/or Land
--- a/hedgewars/uVariables.pas	Sun Oct 14 00:22:33 2012 +0400
+++ b/hedgewars/uVariables.pas	Sun Oct 14 13:35:15 2012 -0400
@@ -662,10 +662,16 @@
             Width: 3; Height: 17; imageWidth: 3; imageHeight: 17; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprSlider
             (FileName:  'botlevels'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
             Width: 22; Height: 15; imageWidth: 22; imageHeight: 15; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprBotlevels
-            (FileName:  'amKnife'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
-            Width:  64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandKnife
-            (FileName:  'knife'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
-            Width: 29; Height: 14; imageWidth: 64; imageHeight: 64; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprKnife
+         (*   (FileName:  'amKnife'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:  64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandKnife*)
+            (FileName:  'amCleaver'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:  64; Height: 64; imageWidth: 64; imageHeight: 64; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: false),// sprHandKnife
+            (*(FileName:  'knife'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width: 29; Height: 14; imageWidth: 64; imageHeight: 64; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprKnife*)
+            (FileName:  'cleaver'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width: 64; Height: 64; imageWidth: 64; imageHeight: 128; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprKnife
+            (FileName:  'star'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width: 12; Height: 12; imageWidth: 12; imageHeight: 12; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprStar
             );
 
 const
@@ -2334,7 +2340,7 @@
             Ammo: (Propz: ammoprop_Power or
                           ammoprop_NeedUpDown; //FIXME: enable multishoot at altuse, until then removed ammoprop_AltUse
                 Count: 1;
-                NumPerTurn: 3;
+                NumPerTurn: 1;
                 Timer: 0;
                 Pos: 0;
                 AmmoType: amKnife;
Binary file share/hedgewars/Data/Graphics/AmmoMenu/Ammos.png has changed
Binary file share/hedgewars/Data/Graphics/AmmoMenu/Ammos_bw.png has changed
Binary file share/hedgewars/Data/Graphics/Hats/Reserved/chef.png has changed
Binary file share/hedgewars/Data/Graphics/Hedgehog/amCleaver.png has changed
Binary file share/hedgewars/Data/Graphics/cleaver.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Graphics/cleaver.svg	Sun Oct 14 13:35:15 2012 -0400
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   width="450"
+   height="470"
+   sodipodi:docname="cleaver.svg">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6">
+    <linearGradient
+       id="linearGradient3767">
+      <stop
+         style="stop-color:#6a6a6a;stop-opacity:1;"
+         offset="0"
+         id="stop3769" />
+      <stop
+         style="stop-color:#dbdbdb;stop-opacity:1;"
+         offset="1"
+         id="stop3771" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3767"
+       id="linearGradient3856"
+       gradientUnits="userSpaceOnUse"
+       x1="183.86975"
+       y1="213.57822"
+       x2="323.47919"
+       y2="103.38492" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3767"
+       id="linearGradient3882"
+       gradientUnits="userSpaceOnUse"
+       x1="183.86975"
+       y1="213.57822"
+       x2="326.20184"
+       y2="120.35856"
+       gradientTransform="matrix(1.0972003,0,0,0.76264827,-18.838734,68.569149)" />
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1242"
+     inkscape:window-height="868"
+     id="namedview4"
+     showgrid="false"
+     inkscape:zoom="1.0042553"
+     inkscape:cx="205.71997"
+     inkscape:cy="192.5461"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <path
+     sodipodi:nodetypes="cccccssssss"
+     inkscape:connector-curvature="0"
+     style="fill:url(#linearGradient3882);fill-opacity:1;stroke:#222222;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 225.90551,108.67968 C 182.87572,133.43708 155.21472,164.45472 132.53094,196.82022 195.69872,221.91543 199.95162,252.4674 204.03008,290.30913 255.29581,289.41319 296.87745,280.50855 329.72809,249.74578 324.96182,204.42109 289.52086,128.98334 225.90551,108.67968 z M 225.59692,129.27118 C 228.29612,129.16913 230.95971,129.51441 233.3459,130.39132 240.98173,133.19744 242.87403,140.27073 237.56326,146.16861 232.25249,152.06649 221.74644,154.57543 214.1106,151.76931 206.47477,148.96319 204.61676,141.8899 209.92753,135.99202 213.57868,131.93723 219.65867,129.49572 225.59692,129.27118 z"
+     id="path2987"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     inkscape:connector-curvature="0"
+     style="fill:#cfcfcf;fill-opacity:1;stroke:#222222;stroke-width:5;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 225.97408,109.10867 205.09299,122.71718 C 210.13058,125.22056 214.88743,127.7568 219.39088,130.31983 224.01197,128.93641 229.11177,128.83531 233.3459,130.39132 239.7278,132.73663 242.08226,138.06415 239.58622,143.18952 290.70676,179.79427 298.47819,221.3 311.00711,262.82996 316.92444,259.29111 323.72772,254.63048 329.28235,249.57895 322.93255,198.81501 291.29561,132.47714 225.97408,109.10867 z"
+     id="path3759"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     transform="matrix(1.090887,0.40089412,-0.66619266,0.73984055,45.886101,-17.883965)"
+     d="M 233.7647,95.061127 A 12.67399,14.434267 0 1 1 208.41672,95.061127 12.67399,14.434267 0 1 1 233.7647,95.061127 z"
+     sodipodi:ry="14.434267"
+     sodipodi:rx="12.67399"
+     sodipodi:cy="95.061127"
+     sodipodi:cx="221.09071"
+     id="path3779"
+     style="fill:none;stroke:none"
+     sodipodi:type="arc"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     style="fill:#c6ba88;fill-opacity:1;stroke:#222222;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 203.34878,290.82382 C 202.57349,309.63771 200.72506,324.14058 187.80748,338.35174 188.46168,347.80203 193.86915,347.27331 198.72527,347.90208 234.16583,334.60641 229.03629,309.93407 231.57515,289.00247 z"
+     id="path3761"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="ccccc"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     style="fill:#c8ac1d;fill-opacity:1;stroke:#222222;stroke-width:3.28770398999999980;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 203.44706,291.39151 203.1569,297.94586 230.81974,297.29852 231.10991,289.04487 z"
+     id="path3809"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="ccccc"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 200.17035,335.78701 C 201.22805,337.23038 202.66678,337.76213 204.2423,337.96662"
+     id="path3817"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 210.76291,320.56732 C 213.14437,322.15978 215.38854,322.14589 217.58341,321.55533"
+     id="path3817-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc"
+     inkscape:export-filename="/tmp/path3817-7.png"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="M 206.01411,328.26521 C 207.84525,329.83412 210.01071,330.27207 212.29617,330.30402"
+     id="path3817-7"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc"
+     inkscape:export-xdpi="21.549999"
+     inkscape:export-ydpi="21.549999" />
+</svg>
Binary file share/hedgewars/Data/Graphics/star.png has changed
--- a/share/hedgewars/Data/Locale/en.txt	Sun Oct 14 00:22:33 2012 +0400
+++ b/share/hedgewars/Data/Locale/en.txt	Sun Oct 14 13:35:15 2012 -0400
@@ -57,7 +57,7 @@
 00:54=Structure
 00:55=Land Spray
 00:56=Freezer
-00:57=Knife
+00:57=Cleaver
 
 01:00=Let's fight!
 01:01=Round draw