- Many AI improvements
authorunc0rr
Fri, 23 Jun 2006 20:02:41 +0000
changeset 70 82d93eeecebe
parent 69 d8a526934b9f
child 71 5f56c6979496
- Many AI improvements - New 'spray objects' on generated land - Many small fixes
hedgewars/CCHandlers.inc
hedgewars/Data/Themes/avematan/theme.cfg
hedgewars/Data/Themes/bubbles/theme.cfg
hedgewars/Data/Themes/ethereal/theme.cfg
hedgewars/Data/Themes/norsk/theme.cfg
hedgewars/Data/Themes/tibet/theme.cfg
hedgewars/Data/Themes/wood/leaf1.png
hedgewars/Data/Themes/wood/leaf2.png
hedgewars/Data/Themes/wood/theme.cfg
hedgewars/Data/Themes/xtheme/theme.cfg
hedgewars/GSHandlers.inc
hedgewars/HHHandlers.inc
hedgewars/SDLh.pas
hedgewars/hwengine.dpr
hedgewars/uAI.pas
hedgewars/uAIActions.pas
hedgewars/uAIAmmoTests.pas
hedgewars/uAIMisc.pas
hedgewars/uCollisions.pas
hedgewars/uConsts.pas
hedgewars/uGears.pas
hedgewars/uIO.pas
hedgewars/uLand.pas
hedgewars/uLandObjects.pas
hedgewars/uMisc.pas
hedgewars/uSound.pas
hedgewars/uStore.pas
hedgewars/uTeams.pas
hedgewars/uWorld.pas
--- a/hedgewars/CCHandlers.inc	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/CCHandlers.inc	Fri Jun 23 20:02:41 2006 +0000
@@ -269,7 +269,7 @@
         begin
         Ammo[CurSlot, CurAmmo].Timer:= 1000 * (byte(s[1]) - 48);
         with CurrentTeam^ do
-             ApplyAmmoChanges(@Hedgehogs[CurrHedgehog]);
+             ApplyAmmoChanges(Hedgehogs[CurrHedgehog]);
         if not CurrentTeam.ExtDriven then SendIPC(s);
         end
 end;
@@ -302,7 +302,7 @@
                 end;
           TargetPoint.X:= NoPointX;
           end;
-     ApplyAmmoChanges(@Hedgehogs[CurrHedgehog])
+     ApplyAmmoChanges(Hedgehogs[CurrHedgehog])
      end
 end;
 
--- a/hedgewars/Data/Themes/avematan/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/avematan/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -8,3 +8,4 @@
 248 112 220 5 22 18 1 0 0 205 112
 sqrt
 264 249 2 191 7 25 3 25 183 82 66 68 54 81 131 117 2 146 55
+0
--- a/hedgewars/Data/Themes/bubbles/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/bubbles/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -2,3 +2,4 @@
 1
 round
 167 242 90 242 10 1 3 0 0 97 97 63 61 95 115 100 190 67 26
+0
--- a/hedgewars/Data/Themes/ethereal/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/ethereal/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -1,2 +1,3 @@
 32896
 0
+0
--- a/hedgewars/Data/Themes/norsk/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/norsk/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -1,2 +1,3 @@
 32896
 0
+0
--- a/hedgewars/Data/Themes/tibet/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/tibet/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -10,3 +10,4 @@
 153 111 2 83 14 12 2 9 9 140 57 25 65 96 40
 ta1
 125 139 58 130 16 8 1 5 7 119 100
+0
Binary file hedgewars/Data/Themes/wood/leaf1.png has changed
Binary file hedgewars/Data/Themes/wood/leaf2.png has changed
--- a/hedgewars/Data/Themes/wood/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/wood/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -2,3 +2,8 @@
 1
 tree
 105 225 41 224 22 1 1 0 0 105 203
+2
+leaf1
+5
+leaf2
+5
--- a/hedgewars/Data/Themes/xtheme/theme.cfg	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/Data/Themes/xtheme/theme.cfg	Fri Jun 23 20:02:41 2006 +0000
@@ -2,3 +2,4 @@
 1
 plant1
 128 128 35 127 29 1 2 12 7 63 108 75 26 49 52
+0
--- a/hedgewars/GSHandlers.inc	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/GSHandlers.inc	Fri Jun 23 20:02:41 2006 +0000
@@ -317,7 +317,7 @@
 var i, ei: integer;
     HHGear: PGear;
 begin
-Allinactive:= false;
+AllInactive:= false;
 dec(Gear.Timer);
 if (Gear.Timer = 0)or((Gear.Message and gm_Destroy) <> 0) then
    begin
@@ -384,8 +384,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepRopeWork(Gear: PGear);
-const pidiv2: real = pi/2;
-      flCheck: boolean = false;
+const flCheck: boolean = false;
 var HHGear: PGear;
     len, cs, cc, tx, ty: real;
     lx, ly: integer;
@@ -399,7 +398,7 @@
            end;
       DeleteGear(Gear);
       OnUsedAmmo(PHedgehog(Gear.Hedgehog)^.Ammo);
-      ApplyAmmoChanges(PHedgehog(Gear.Hedgehog))
+      ApplyAmmoChanges(PHedgehog(Gear.Hedgehog)^)
     end;
 
 begin
@@ -429,8 +428,8 @@
          begin
          tx:= cc*len;
          ty:= cs*len;
-         lx:= round(Gear.X + tx) + sign(HHGear.dX);
-         ly:= round(Gear.Y + ty) + sign(HHGear.dY);
+         lx:= round(Gear.X + tx) + Sign(HHGear.dX);
+         ly:= round(Gear.Y + ty) + Sign(HHGear.dY);
          if ((ly and $FFFFFC00) = 0) and ((lx and $FFFFF800) = 0)and (Land[ly, lx] <> 0) then
            begin
            with RopePoints.ar[RopePoints.Count] do
--- a/hedgewars/HHHandlers.inc	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/HHHandlers.inc	Fri Jun 23 20:02:41 2006 +0000
@@ -124,10 +124,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepHedgehogDriven(Gear: PGear);
 const StepTicks: LongWord = 0;
-      cStepTicks = 38;
 var t: PGear;
 begin
-if isinMultiShoot and (Gear.Damage = 0) then
+if isInMultiShoot and (Gear.Damage = 0) then
    begin
    exit
    end;
@@ -142,7 +141,7 @@
       Gear.State:= Gear.State and not gstHHJumping;
    exit
    end;
-if ((Gear.State and gstFalling) <> 0) or (StepTicks = cStepTicks)
+if ((Gear.State and gstFalling) <> 0) or (StepTicks = cHHStepTicks)
    or (CurAmmoGear <> nil) then // we're moving
    begin
    // check for case with ammo
@@ -251,7 +250,7 @@
    if (Gear.Message and gm_Left  )<>0 then Gear.dX:= -1.0 else
    if (Gear.Message and gm_Right )<>0 then Gear.dX:=  1.0 else exit;
    PHedgehog(Gear.Hedgehog).visStepPos:= (PHedgehog(Gear.Hedgehog).visStepPos + 1) and 7;
-   StepTicks:= cStepTicks;
+   StepTicks:= cHHStepTicks;
    if TestCollisionXwithGear(Gear, Sign(Gear.dX)) then
       begin
       if not (TestCollisionXwithXYShift(Gear, 0, -6, Sign(Gear.dX))
--- a/hedgewars/SDLh.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/SDLh.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -84,8 +84,8 @@
                  end;
 
      TPoint = record
-              x: Integer;
-              y: Integer;
+              X: Integer;
+              Y: Integer;
               end;
 
      PSDL_PixelFormat = ^TSDL_PixelFormat;
--- a/hedgewars/hwengine.dpr	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/hwengine.dpr	Fri Jun 23 20:02:41 2006 +0000
@@ -68,7 +68,6 @@
 
 ////////////////////////////////
 procedure DoTimer(Lag: integer);  // - обработка таймера
-const cCons: boolean = false;
 var s: string;
 begin
 case GameState of
--- a/hedgewars/uAI.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uAI.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -65,7 +65,10 @@
 for i:= 0 to Pred(Targets.Count) do
     if Targets.ar[i].Score >= 0 then
        begin
-       a:= Low(TAmmoType);
+       if (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].AttacksNum > 0)
+          then with CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog] do
+                    a:= Ammo[CurSlot, CurAmmo].AmmoType
+          else a:= Low(TAmmoType);
        aa:= a;
        repeat
         if Assigned(AmmoTests[a]) then
@@ -89,47 +92,54 @@
                  AddAction(BestActions, aia_Down, aim_push, 500);
                  AddAction(BestActions, aia_Down, aim_release, -Angle)
                  end;
-              AddAction(BestActions, aia_attack, aim_push, 300);
+              AddAction(BestActions, aia_attack, aim_push, 800);
               AddAction(BestActions, aia_attack, aim_release, Power);
               end
            end;
         if a = High(TAmmoType) then a:= Low(TAmmoType)
                                else inc(a)
-       until isInMultiShoot or (a = aa) or (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].AttacksNum > 0)
+       until (a = aa) or (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].AttacksNum > 0)
        end
 end;
 
 procedure Walk(Me: PGear);
 var Actions: TActions;
     BackMe: TGear;
-    Dir, t, avoidt, steps: integer;
+    Dir, steps, maxsteps: integer;
+    BestRate, Rate: integer;
 begin
 Actions.Score:= 0;
 Actions.Count:= 0;
 Actions.Pos:= 0;
+BestActions.Count:= 0;
+if (Me.State and gstAttacked) = 0 then maxsteps:= (TurnTimeLeft - 4000) div cHHStepTicks
+                                  else maxsteps:= 3000;
 BackMe:= Me^;
 if (Me.State and gstAttacked) = 0 then TestAmmos(Actions, Me);
-avoidt:= CheckBonuses(Me);
+BestRate:= RatePlace(Me);
 for Dir:= aia_Left to aia_Right do
     begin
     Me.Message:= Dir;
     steps:= 0;
-    while HHGo(Me) do
+    while HHGo(Me) and (steps < maxsteps) do
        begin
        inc(steps);
        Actions.Count:= 0;
-       AddAction(Actions, Dir, aim_push, 50);
+       AddAction(Actions, Dir, aim_push, 250);
        AddAction(Actions, aia_WaitX, round(Me.X), 0);
        AddAction(Actions, Dir, aim_release, 0);
-       t:= CheckBonuses(Me);
-       if t < avoidt then break
-       else if (t > 0) or (t > avoidt) then
-            begin
-            BestActions:= Actions;
-            exit
-            end;
+       Rate:= RatePlace(Me);
+       if Rate > BestRate then
+          begin
+          BestActions:= Actions;
+          BestRate:= Rate;
+          Me.State:= Me.State or gstAttacked // we have better place, go to it and don't use ammo
+          end
+       else if Rate < BestRate then
+               if BestRate > 0 then exit
+                               else break;
        if ((Me.State and gstAttacked) = 0)
-       and ((steps mod 4) = 0) then TestAmmos(Actions, Me);
+           and ((steps mod 4) = 0) then TestAmmos(Actions, Me);
        if StopThinking then exit;
        end;
     Me^:= BackMe
@@ -140,27 +150,29 @@
 var BackMe: TGear;
     StartTicks: Longword;
 begin
-{$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF}
 StartTicks:= GameTicks;
-ThinkingHH:= Me;
-FillTargets;
-FillBonuses;
 BestActions.Score:= Low(integer);
 if Targets.Count > 0 then
    begin
    BackMe:= Me^;
    Walk(@BackMe);
    end;
-if StartTicks > GameTicks - 1000 then SDL_Delay(500);
-Me.State:= Me.State and not gstHHThinking;
-{$IFDEF DEBUGFILE}AddFileLog('Exit Think Thread');{$ENDIF}
+if ((Me.State and gstAttacked) = 0)
+    and (StartTicks > GameTicks - 1000) then SDL_Delay(1000);
+    
+if BestActions.Count > 0 then Me.State:= Me.State and not gstHHThinking;
 ThinkThread:= nil
 end;
 
 procedure StartThink(Me: PGear);
 begin
+if ((Me.State and gstAttacking) <> 0) or isInMultiShoot then exit;
 Me.State:= Me.State or gstHHThinking;
 StopThinking:= false;
+ThinkingHH:= Me;
+FillTargets;
+FillBonuses((Me.State and gstAttacked) <> 0);
+{$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF}
 ThinkThread:= SDL_CreateThread(@Think, Me)
 end;
 
--- a/hedgewars/uAIActions.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uAIActions.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -6,10 +6,9 @@
       aia_Left       = 1;
       aia_Right      = 2;
       aia_Timer      = 3;
-      aia_Slot       = 4;
-      aia_attack     = 5;
-      aia_Up         = 6;
-      aia_Down       = 7;
+      aia_attack     = 4;
+      aia_Up         = 5;
+      aia_Down       = 6;
 
       aia_Weapon     = $80000000;
       aia_WaitX      = $80000001;
@@ -37,12 +36,11 @@
 implementation
 uses uMisc, uTeams, uConsts, uConsole;
 
-const ActionIdToStr: array[0..7] of string[16] = (
+const ActionIdToStr: array[0..6] of string[16] = (
 {aia_none}           '',
 {aia_Left}           'left',
 {aia_Right}          'right',
 {aia_Timer}          'timer',
-{aia_slot}           'slot',
 {aia_attack}         'attack',
 {aia_Up}             'up',
 {aia_Down}           'down'
@@ -65,7 +63,7 @@
 begin
 with CurrentTeam^ do
      with Hedgehogs[CurrHedgehog] do
-          while Ammo[CurSlot, CurAmmo].AmmoType <> TAmmotype(weap) do
+          while Ammo[CurSlot, CurAmmo].AmmoType <> TAmmoType(weap) do
                 ParseCommand('/slot ' + chr(49 + Ammoz[TAmmoType(weap)].Slot));
 end;
 
--- a/hedgewars/uAIAmmoTests.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uAIAmmoTests.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -4,6 +4,7 @@
 
 function TestBazooka(Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
 function TestGrenade(Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
+function TestShotgun(Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
 
 type TAmmoTestProc = function (Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
 const AmmoTests: array[TAmmoType] of TAmmoTestProc =
@@ -11,7 +12,7 @@
 {amGrenade}       TestGrenade,
 {amBazooka}       TestBazooka,
 {amUFO}           nil,
-{amShotgun}       nil,
+{amShotgun}       TestShotgun,
 {amPickHammer}    nil,
 {amSkip}          nil,
 {amRope}          nil,
@@ -22,6 +23,7 @@
 
 implementation
 uses uMisc, uAIMisc;
+const BadTurn = Low(integer);
 
 function Metric(x1, y1, x2, y2: integer): integer;
 begin
@@ -49,13 +51,14 @@
       dY:= dY + cGravity;
       dec(t)
     until TestColl(round(x), round(y), 5) or (t <= 0);
-    Result:= RateExplosion(Me, round(x), round(y), 101) - Metric(Targ.X, Targ.Y, round(x), round(y)) div 16
+    Result:= RateExplosion(Me, round(x), round(y), 101);
+    if Result = 0 then Result:= - Metric(Targ.X, Targ.Y, round(x), round(y)) div 64
     end;
 
 begin
 Time:= 0;
 rTime:= 10;
-Result:= Low(integer);
+Result:= BadTurn;
 repeat
   rTime:= rTime + 100 + random*250;
   Vx:= - cWindSpeed * rTime / 2 + (Targ.X - Me.X) / rTime;
@@ -76,7 +79,7 @@
 end;
 
 function TestGrenade(Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
-const tDelta = 10;
+const tDelta = 24;
 var Vx, Vy, r: real;
     Score: integer;
     TestTime: Longword;
@@ -100,7 +103,7 @@
     end;
 
 begin
-Result:= Low(integer);
+Result:= BadTurn;
 TestTime:= 0;
 repeat
   inc(TestTime, 1000);
@@ -110,7 +113,7 @@
   if r <= 1 then
      begin
      Score:= CheckTrace;
-     if Result <= Score then
+     if Result < Score then
         begin
         r:= sqrt(r);
         Angle:= DxDy2AttackAngle(Vx, Vy);
@@ -122,4 +125,32 @@
 until (TestTime = 5000)
 end;
 
+function TestShotgun(Me: PGear; Targ: TPoint; out Time: Longword; out Angle, Power: integer): integer;
+var Vx, Vy, x, y: real;
+begin
+if Metric(round(Me.X), round(Me.Y), Targ.X, Targ.Y) < 80 then
+   begin
+   Result:= BadTurn;
+   exit
+   end;
+Time:= 0;
+Power:= 1;
+Vx:= (Targ.X - Me.X)/1024;
+Vy:= (Targ.Y - Me.Y)/1024;
+x:= Me.X;
+y:= Me.Y;
+Angle:= DxDy2AttackAngle(Vx, -Vy);
+repeat
+  x:= x + vX;
+  y:= y + vY;
+  if TestColl(round(x), round(y), 2) then
+     begin
+     Result:= RateExplosion(Me, round(x), round(y), 25) * 2;
+     if Result = 0 then Result:= - Metric(Targ.X, Targ.Y, round(x), round(y)) div 64;
+     exit
+     end
+until (abs(Targ.X - x) + abs(Targ.Y - y) < 4) or (x < 0) or (y < 0) or (x > 2048) or (y > 1024);
+Result:= BadTurn
+end;
+
 end.
--- a/hedgewars/uAIMisc.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uAIMisc.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -12,8 +12,8 @@
                 end;
 
 procedure FillTargets;
-procedure FillBonuses;
-function CheckBonuses(Gear: PGear): integer;
+procedure FillBonuses(isAfterAttack: boolean);
+function RatePlace(Gear: PGear): integer;
 function DxDy2AttackAngle(const _dY, _dX: Extended): integer;
 function TestColl(x, y, r: integer): boolean;
 function RateExplosion(Me: PGear; x, y, r: integer): integer;
@@ -29,7 +29,7 @@
       
 type TBonus = record
               X, Y: integer;
-              Radius: Longword;
+              Radius: integer;
               Score: integer;
               end;
 var bonuses: record
@@ -62,8 +62,9 @@
       end
 end;
 
-procedure FillBonuses;
+procedure FillBonuses(isAfterAttack: boolean);
 var Gear: PGear;
+    MyColor: Longword;
 
     procedure AddBonus(x, y: integer; r: Longword; s: integer);
     begin
@@ -77,27 +78,36 @@
 
 begin
 bonuses.Count:= 0;
+MyColor:= PHedgehog(ThinkingHH.Hedgehog).Team.Color;
 Gear:= GearsList;
 while Gear <> nil do
       begin
       case Gear.Kind of
-           gtCase: AddBonus(round(Gear.X), round(Gear.Y), 32, 25);
-           gtMine: AddBonus(round(Gear.X), round(Gear.Y), 45, -50);
-           gtAmmo_Bomb: AddBonus(round(Gear.X), round(Gear.Y), 50, -100);
-           gtHedgehog: if Gear.Damage >= Gear.Health then AddBonus(round(Gear.X), round(Gear.Y), 50, -25);
+           gtCase: AddBonus(round(Gear.X), round(Gear.Y), 33, 25);
+           gtMine: AddBonus(round(Gear.X), round(Gear.Y), 46, -50);
+           gtDynamite: AddBonus(round(Gear.X), round(Gear.Y), 150, -75);
+           gtHedgehog: begin
+                       if Gear.Damage >= Gear.Health then AddBonus(round(Gear.X), round(Gear.Y), 50, -25);
+                       if isAfterAttack
+                          and (ThinkingHH.Hedgehog <> Gear.Hedgehog)
+                          and (MyColor = PHedgehog(Gear.Hedgehog).Team.Color) then AddBonus(round(Gear.X), round(Gear.Y), 100, -1);
+                       end;
            end;
       Gear:= Gear.NextGear
       end
 end;
 
-function CheckBonuses(Gear: PGear): integer;
-var i: integer;
+function RatePlace(Gear: PGear): integer;
+var i, r: integer;
 begin
 Result:= 0;
 for i:= 0 to Pred(bonuses.Count) do
     with bonuses.ar[i] do
-         if sqrt(sqr(Gear.X - X) + sqr(Gear.Y - y)) <= Radius then
-            inc(Result, Score) 
+         begin
+         r:= round(sqrt(sqr(Gear.X - X) + sqr(Gear.Y - y)));
+         if r < Radius then
+            inc(Result, Score * (Radius - r))
+         end;
 end;
 
 function DxDy2AttackAngle(const _dY, _dX: Extended): integer;
@@ -151,6 +161,7 @@
                             else dec(Result, dmg * 3)
             end;
          end;
+Result:= Result * 1024
 end;
 
 function HHGo(Gear: PGear): boolean;
--- a/hedgewars/uCollisions.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uCollisions.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -37,10 +37,7 @@
 {$INCLUDE options.inc}
 const cMaxGearArrayInd = 255;
 
-type TDirection = record
-                  dX, dY: integer
-                  end;
-     PGearArray = ^TGearArray;
+type PGearArray = ^TGearArray;
      TGearArray = record
                   ar: array[0..cMaxGearArrayInd] of PGear;
                   Count: Longword
--- a/hedgewars/uConsts.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uConsts.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -71,7 +71,6 @@
 
 resourcestring
       errmsgCreateSurface   = 'Error creating SDL surface';
-      errmsgNoDesc          = 'Unknown error';
       errmsgTransparentSet  = 'Error setting transparent color';
       errmsgUnknownCommand  = 'Unknown command';
       errmsgUnknownVariable = 'Unknown variable';
@@ -103,11 +102,12 @@
       cMaxHHs          = 20;
       cMaxSpawnPoints  = 1024;
       cHHSurfaceWidth     = 512;
-      cHHSurfaceHeigth    = 256;
+     // cHHSurfaceHeigth    = 256;
 
       cMaxEdgePoints = 16384;
 
       cHHRadius = 9;
+      cHHStepTicks = 38;
 
       cKeyMaxIndex = 322;
 
@@ -166,11 +166,8 @@
       posCaseAmmo    = $00000001;
       posCaseHealth  = $00000002;
 
-      cToggleConsoleKey     = 39;
-
       NoPointX = Low(Integer); // константа для TargetPoint, показывает, что цель не указана
 
-      cLandFileName = 'Land.bmp';
       cHHFileName   = 'Hedgehog.png';
       cCHFileName   = 'Crosshair.png';
       cThemeCFGFilename = 'theme.cfg';
@@ -351,16 +348,6 @@
                                     Slot: 3;
                                     TimeAfterTurn: 5000));
 
-
-
-
-      Resolutions: array[0..3] of String = (
-                                           '640 480',
-                                           '800 600',
-                                           '1024 768',
-                                           '1280 1024'
-                                           );
-
 implementation
 
 end.
--- a/hedgewars/uGears.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uGears.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -74,7 +74,7 @@
 
 var CurAmmoGear: PGear = nil;
     GearsList: PGear = nil;
-    
+
 implementation
 uses uWorld, uMisc, uStore, uConsole, uSound, uTeams, uRandom, uCollisions, uLand, uIO, uLandGraphics;
 var RopePoints: record
@@ -93,6 +93,7 @@
 function  CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: integer): PGear; forward;
 procedure SpawnBoxOfSmth; forward;
 procedure AfterAttack; forward;
+procedure FindPlace(Gear: PGear; withFall: boolean; Left, Right: integer); forward;
 
 {$INCLUDE GSHandlers.inc}
 {$INCLUDE HHHandlers.inc}
@@ -145,7 +146,7 @@
     gtHedgehog: begin
                 Result.Radius:= cHHRadius;
                 Result.Elasticity:= 0.002;
-                Result.Friction:= 0.9985;
+                Result.Friction:= 0.999;
                 Result.Angle:= cMaxAngle div 2;
                 end;
 gtAmmo_Grenade: begin
@@ -515,18 +516,13 @@
 end;
 
 procedure AddMiscGears;
-var i, x, y: integer;
+var i: integer;
 begin
 for i:= 0 to cCloudsNumber do AddGear( - cScreenWidth + i * ((cScreenWidth * 2 + 2304) div cCloudsNumber), -128, gtCloud, random(4), (0.5-random)*0.01);
 AddGear(0, 0, gtActionTimer, gtsStartGame, 0, 0, 2000).Health:= 3;
 if (GameFlags and gfForts) = 0 then
-   begin
    for i:= 0 to 3 do
-       begin
-       GetHHPoint(x, y);
-       AddGear(X, Y + 9, gtMine, 0);
-       end;
-   end;
+       FindPlace(AddGear(0, 0, gtMine, 0), false, 0, 2048);
 end;
 
 procedure doMakeExplosion(X, Y, Radius: integer; Mask: LongWord);
@@ -553,8 +549,8 @@
                           if (Mask and EXPLNoDamage) = 0 then inc(Gear.Damage, dmg);
                           if ((Mask and EXPLDoNotTouchHH) = 0) or (Gear.Kind <> gtHedgehog) then
                              begin
-                             Gear.dX:= Gear.dX + dmg / 200 * sign(Gear.X - X);
-                             Gear.dY:= Gear.dY + dmg / 200 * sign(Gear.Y - Y);
+                             Gear.dX:= Gear.dX + dmg / 200 * Sign(Gear.X - X);
+                             Gear.dY:= Gear.dY + dmg / 200 * Sign(Gear.Y - Y);
                              Gear.Active:= true;
                              FollowGear:= Gear
                              end;
@@ -603,18 +599,12 @@
 
 procedure AssignHHCoords;
 var Gear: PGear;
-    pX, pY: integer;
 begin
 Gear:= GearsList;
 while Gear <> nil do
       begin
       if Gear.Kind = gtHedgehog then
-         begin
-         GetHHPoint(pX, pY);
-         {$IFDEF DEBUGFILE}AddFileLog('HH at ('+inttostr(pX)+','+inttostr(pY)+')');{$ENDIF}
-         Gear.X:= pX;
-         Gear.Y:= pY
-         end;
+         FindPlace(Gear, false, 0, 2048);
       Gear:= Gear.NextGear
       end
 end;
@@ -670,38 +660,76 @@
 end;
 
 procedure SpawnBoxOfSmth;
-var i, x, y, k: integer;
-    b: boolean;
 begin
-if (CountGears(gtCase) > 1) or (getrandom(3) <> 0) then exit;
-k:= 7;
+if (CountGears(gtCase) > 2) or (getrandom(3) <> 0) then exit;
+FollowGear:= AddGear(0, 0, gtCase, 0);
+FollowGear.Health:= 25;
+FollowGear.Pos:= posCaseHealth;
+FindPlace(FollowGear, true, 0, 2048)
+end;
+
+procedure FindPlace(Gear: PGear; withFall: boolean; Left, Right: integer);
+
+    function CountNonZeroz(x, y, r: integer): integer;
+    var i: integer;
+    begin
+    Result:= 0;
+    if (y and $FFFFFC00) <> 0 then exit;
+    for i:= max(x - r, 0) to min(x + r, 2043) do
+        if Land[y, i] <> 0 then inc(Result)
+    end;
+
+var fx, x: integer;
+    y, sy: integer;
+    ar: array[0..512] of TPoint;
+    cnt, delta: Longword;
+begin
+fx:= Left + integer(GetRandom(Right - Left));
+x:= fx;
+delta:= 130;
 repeat
-  x:= getrandom(2000) + 24;
-  b:= false;
-  y:= -1;
-  while (y < 1023) and not b do
+  repeat
+     inc(x, Gear.Radius);
+     if x > Right then x:= Left + (x mod (Right - left));
+     cnt:= 0;
+     y:= -Gear.Radius * 2;
+     while y < 1023 do
         begin
-        inc(y);
-        i:= x - 13;
-        while (i <= x + 13) and not b do // 13 is gtCase Radius-1
-              begin
-              if Land[y, i] <> 0 then
-                 begin
-                 b:= true;
-                 end;
-              inc(i)
-              end;
+        repeat
+          inc(y, 2);
+        until (y > 1023) or (CountNonZeroz(x, y, Gear.Radius - 1) = 0);
+        sy:= y;
+        repeat
+          inc(y);
+        until (y > 1023) or (CountNonZeroz(x, y, Gear.Radius - 1) <> 0);
+        if (y - sy > Gear.Radius * 2)
+        and (y < 1023)
+        and (CheckGearsNear(x, y - Gear.Radius, [gtHedgehog, gtMine, gtCase], 110, 110) = nil) then
+           begin
+           ar[cnt].X:= x;
+           if withFall then ar[cnt].Y:= sy + Gear.Radius
+                       else ar[cnt].Y:= y - Gear.Radius;
+           inc(cnt)
+           end;
+        inc(y, 80)
         end;
-  if b then
-     b:= CheckGearsNear(x, y, [gtMine, gtHedgehog, gtCase], 70, 70) = nil;
-  dec(k)
-until (k = 0) or b;
-if b then
-   begin
-   FollowGear:= AddGear(x, -30, gtCase, 0);
-   FollowGear.Health:= 25;
-   FollowGear.Pos:= posCaseHealth
-   end;
+     if cnt > 0 then
+        with ar[GetRandom(cnt)] do
+          begin
+          Gear.X:= x;
+          Gear.Y:= y;
+         {$IFDEF DEBUGFILE}
+         AddFileLog('Assigned Gear ' + inttostr(integer(Gear)) +
+                    ' coordinates (' + inttostr(x) +
+                    ',' + inttostr(y) + ')');
+         {$ENDIF}
+          exit
+          end
+  until (x - Gear.Radius < fx) and (x + Gear.Radius > fx);
+dec(Delta, 20)
+until (Delta < 70);
+OutError('Couldn''t find place for Gear ' + inttostr(integer(Gear)), false);
+DeleteGear(Gear)
 end;
 
 initialization
--- a/hedgewars/uIO.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uIO.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -44,7 +44,6 @@
 procedure InitIPC;
 procedure CloseIPC;
 procedure NetGetNextCmd;
-procedure LoadFortPoints(Fort: shortstring; isRight: boolean; Count: Longword);
 
 implementation
 uses uConsole, uConsts, uWorld, uMisc, uRandom, uLand;
@@ -166,8 +165,11 @@
       end;
          
 if cmdcurpos <= cmdendpos then
-   if GameTicks > extcmd[cmdcurpos].Time then
-      outerror('oops, queue error. in buffer: '+extcmd[cmdcurpos].cmd+' ('+inttostr(GameTicks)+' > '+inttostr(extcmd[cmdcurpos].Time)+')', true);
+   TryDo(GameTicks <= extcmd[cmdcurpos].Time,
+         'oops, queue error. in buffer: ' + extcmd[cmdcurpos].cmd +
+         ' (' + inttostr(GameTicks) + ' > ' +
+         inttostr(extcmd[cmdcurpos].Time) + ')',
+         true);
 
 tmpflag:= true;
 while (cmdcurpos <= cmdendpos)and(GameTicks = extcmd[cmdcurpos].Time) do
@@ -208,44 +210,4 @@
 isInLag:= (cmdcurpos > cmdendpos) and tmpflag
 end;
 
-procedure LoadFortPoints(Fort: shortstring; isRight: boolean; Count: Longword);
-const cMAXFORTPOINTS = 20;
-var f: textfile;
-    i, t: integer;
-    cnt: Longword;
-    ar: array[0..Pred(cMAXFORTPOINTS)] of TPoint;
-    p: TPoint;
-begin
-if isRight then Fort:= Pathz[ptForts] + '/' + Fort + 'R.txt'
-           else Fort:= Pathz[ptForts] + '/' + Fort + 'L.txt';
-WriteToConsole(msgLoading + Fort + ' ');
-{$I-}
-AssignFile(f, Fort);
-Reset(f);
-cnt:= 0;
-while not (eof(f) or (cnt = cMAXFORTPOINTS)) do
-      begin
-      Readln(f, ar[cnt].x, ar[cnt].y);
-      if isRight then inc(ar[cnt].x, 1024);
-      inc(cnt);
-      end;
-Closefile(f);
-{$I+}
-TryDo(IOResult = 0, msgFailed, true);
-WriteLnToConsole(msgOK);
-TryDo(Count < cnt, 'Fort doesn''t contain needed amount of spawn points', true);
-for i:= 0 to Pred(cnt) do
-    begin
-    t:= GetRandom(cnt);
-    if i <> t then
-       begin
-       p:= ar[i];
-       ar[i]:= ar[t];
-       ar[t]:= p
-       end
-    end;
-for i:= 0 to Pred(Count) do
-    AddHHPoint(ar[i].x, ar[i].y);
-end;
-
 end.
--- a/hedgewars/uLand.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uLand.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -1,6 +1,6 @@
 (*
  * Hedgewars, a worms-like game
- * Copyright (c) 2005 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2005, 2006 Andrey Korotaev <unC0Rr@gmail.com>
  *
  * Distributed under the terms of the BSD-modified licence:
  *
@@ -33,16 +33,13 @@
 
 unit uLand;
 interface
-uses SDLh;
+uses SDLh, uGears;
 {$include options.inc}
 type TLandArray = packed array[0..1023, 0..2047] of LongWord;
 
 var  Land: TLandArray;
      LandSurface: PSDL_Surface;
 
-procedure AddHHPoint(_x, _y: integer);
-procedure GetHHPoint(out _x, _y: integer);
-procedure RandomizeHHPoints;
 procedure GenMap;
 
 implementation
@@ -53,11 +50,6 @@
               ar: array[0..Pred(cMaxEdgePoints)] of TPoint;
               end;
 
-var HHPoints: record
-              First, Last: word;
-              ar: array[1..Pred(cMaxSpawnPoints)] of TPoint
-              end;
-
 procedure LogLandDigest;
 var ctx: TSHA1Context;
     dig: TSHA1Digest;
@@ -333,56 +325,6 @@
     end;
 end;
 
-procedure AddHHPoints;
-var x, y, t: integer;
-
-    function CountNonZeroz(x, y: integer): integer;
-    var i: integer;
-    begin
-    Result:= 0;
-    if (y and $FFFFFC00) <> 0 then exit;
-    for i:= max(x - 5, 0) to min(x + 5, 2043) do
-        if Land[y, i] <> 0 then inc(Result)
-    end;
-
-begin
-x:= 40;
-while x < 2010 do
-    begin
-    y:= -24;
-    while y < 1023 do
-          begin
-          repeat
-          inc(y, 2);
-          until (y > 1023) or (CountNonZeroz(x, y) = 0);
-          t:= 0;
-          repeat
-          inc(y, 2);
-          inc(t, 2)
-          until (y > 1023) or (CountNonZeroz(x, y) <> 0);
-          if (t > 22) and (y < 1023) then AddHHPoint(x, y - 12);
-          inc(y, 80)
-          end;
-    inc(x, 100)
-    end;
-
-if HHPoints.Last < cMaxHHs then
-   begin
-   AddHHPoint(300, 800);
-   AddHHPoint(400, 800);
-   AddHHPoint(500, 800);
-   AddHHPoint(600, 800);
-   AddHHPoint(700, 800);
-   AddHHPoint(800, 800);
-   AddHHPoint(900, 800);
-   AddHHPoint(1000, 800);
-   AddHHPoint(1100, 800);
-   AddHHPoint(1200, 800);
-   AddHHPoint(1300, 800);
-   AddHHPoint(1400, 800);
-   end;
-end;
-
 procedure PointWave(var Template: TEdgeTemplate; var pa: TPixAr);
 const MAXPASSES = 32;
 var ar: array[0..MAXPASSES, 0..5] of real;
@@ -538,14 +480,11 @@
 SDL_FillRect(LandSurface, nil, 0);
 AddProgress;
 
-AddObjects(LandSurface);
+SDL_SetColorKey(tmpsurf, SDL_SRCCOLORKEY, 0);
+AddObjects(tmpsurf, LandSurface);
+SDL_FreeSurface(tmpsurf);
 
-SDL_SetColorKey(tmpsurf, SDL_SRCCOLORKEY, 0);
-SDL_UpperBlit(tmpsurf, nil, LandSurface, nil);
-SDL_FreeSurface(tmpsurf);
-AddProgress;
-AddHHPoints;
-RandomizeHHPoints;
+AddProgress
 end;
 
 procedure MakeFortsMap;
@@ -561,13 +500,11 @@
 tmpsurf:= LoadImage(Pathz[ptForts] + '/' + p.FortName + 'L.png', false);
 BlitImageAndGenerateCollisionInfo(0, 0, tmpsurf, LandSurface);
 SDL_FreeSurface(tmpsurf);
-LoadFortPoints(p.FortName, false, TeamSize(p));
 p:= p.Next;
 TryDo(p <> nil, 'Only one team on map!', true);
 tmpsurf:= LoadImage(Pathz[ptForts] + '/' + p.FortName + 'R.png', false);
 BlitImageAndGenerateCollisionInfo(1024, 0, tmpsurf, LandSurface);
 SDL_FreeSurface(tmpsurf);
-LoadFortPoints(p.FortName, true, TeamSize(p));
 p:= p.Next;
 TryDo(p = nil, 'More than 2 teams on map in forts mode!', true);
 end;
@@ -613,9 +550,6 @@
      end;
 if SDL_MustLock(LandSurface) then
    SDL_UnlockSurface(LandSurface);
-
-AddHHPoints;
-RandomizeHHPoints;
 end;
 
 procedure GenMap;
@@ -628,55 +562,6 @@
 {$IFDEF DEBUGFILE}LogLandDigest{$ENDIF}
 end;
 
-procedure AddHHPoint(_x, _y: integer);
-begin
-with HHPoints do
-     begin
-     inc(Last);
-     TryDo(Last < cMaxSpawnPoints, 'HHs coords queue overflow', true);
-     with ar[Last] do
-          begin
-          x:= _x;
-          y:= _y
-          end
-     end
-end;
-
-procedure GetHHPoint(out _x, _y: integer);
-begin
-with HHPoints do
-     begin
-     TryDo(First <= Last, 'HHs coords queue underflow ' + inttostr(First), true);
-     with ar[First] do
-          begin
-          _x:= x;
-          _y:= y
-          end;
-     inc(First)
-     end
-end;
-
-procedure RandomizeHHPoints;
-var i, t: integer;
-    p: TPoint;
-begin
-with HHPoints do
-     begin
-     for i:= First to Last do
-         begin
-         t:= GetRandom(Last - First + 1) + First;
-         if i <> t then
-            begin
-            p:= ar[i];
-            ar[i]:= ar[t];
-            ar[t]:= p
-            end
-         end
-     end
-end;
-
 initialization
 
-HHPoints.First:= 1
-
 end.
--- a/hedgewars/uLandObjects.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uLandObjects.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -36,24 +36,38 @@
 uses SDLh;
 {$include options.inc}
 
-procedure AddObjects(Surface: PSDL_Surface);
+procedure AddObjects(InSurface, Surface: PSDL_Surface);
 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY: Longword; Image, Surface: PSDL_Surface);
 
 implementation
 uses uLand, uStore, uConsts, uMisc, uConsole, uRandom;
 const MaxRects = 256;
       MAXOBJECTRECTS = 16;
-type  PRectArray = ^TRectsArray;
-      TRectsArray = array[0..MaxRects] of TSDL_rect;
+      MAXTHEMEOBJECTS = 32;
 
-type TThemeObject = record
+type PRectArray = ^TRectsArray;
+     TRectsArray = array[0..MaxRects] of TSDL_Rect;
+     TThemeObject = record
                     Surf: PSDL_Surface;
                     inland: TSDL_Rect;
-                    outland: array[1..MAXOBJECTRECTS] of TSDL_Rect;
+                    outland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
                     rectcnt: Longword;
                     Width, Height: Longword;
                     Maxcnt: Longword;
                     end;
+     TThemeObjects = record
+                     Count: integer;
+                     objs: array[0..Pred(MAXTHEMEOBJECTS)] of TThemeObject;
+                     end;
+     TSprayObject = record
+                    Surf: PSDL_Surface;
+                    Width, Height: Longword;
+                    Maxcnt: Longword;
+                    end;
+     TSprayObjects = record
+                     Count: integer;
+                     objs: array[0..Pred(MAXTHEMEOBJECTS)] of TSprayObject
+                     end;
 
 var Rects: PRectArray;
     RectCount: Longword;
@@ -81,7 +95,7 @@
             begin
             i:= Longword(@Land[cpY + y, cpX]);
             for x:= 0 to Pred(Image.w) do
-                if PWord(p + x * 2)^ <> 0 then PLongWord(i + x * 4)^:= $FFFFFF;
+                if PWord(p + x * 2)^ <> 0 then PLongWord(i + x * 4)^:= COLOR_LAND;
             inc(p, Image.pitch);
             end;
      3: for y:= 0 to Pred(Image.h) do
@@ -90,14 +104,14 @@
             for x:= 0 to Pred(Image.w) do
                 if  (PByte(p + x * 3 + 0)^ <> 0)
                  or (PByte(p + x * 3 + 1)^ <> 0)
-                 or (PByte(p + x * 3 + 2)^ <> 0) then PLongWord(i + x * 4)^:= $FFFFFF;
+                 or (PByte(p + x * 3 + 2)^ <> 0) then PLongWord(i + x * 4)^:= COLOR_LAND;
             inc(p, Image.pitch);
             end;
      4: for y:= 0 to Pred(Image.h) do
             begin
             i:= Longword(@Land[cpY + y, cpX]);
             for x:= 0 to Pred(Image.w) do
-                if PLongword(p + x * 4)^ <> 0 then PLongWord(i + x * 4)^:= $FFFFFF;
+                if PLongword(p + x * 4)^ <> 0 then PLongWord(i + x * 4)^:= COLOR_LAND;
             inc(p, Image.pitch);
             end;
      end;
@@ -247,7 +261,7 @@
         Result:= false
 end;
 
-function TryPut(var Obj: TThemeObject; Surface: PSDL_Surface): boolean;
+function TryPut(var Obj: TThemeObject; Surface: PSDL_Surface): boolean; overload;
 const MaxPointsIndex = 2047;
 var x, y: Longword;
     ar: array[0..MaxPointsIndex] of TPoint;
@@ -291,25 +305,76 @@
      end
 end;
 
-procedure AddThemeObjects(Surface: PSDL_Surface; MaxCount: Longword);
-const MAXTHEMEOBJECTS = 32;
-var f: textfile;
-    s: string;
-    ThemeObjects: array[1..MAXTHEMEOBJECTS] of TThemeObject;
-    i, ii, t, n: Longword;
-    b: boolean;
+function TryPut(var Obj: TSprayObject; Surface: PSDL_Surface): boolean; overload;
+const MaxPointsIndex = 8095;
+var x, y: Longword;
+    ar: array[0..MaxPointsIndex] of TPoint;
+    cnt, i: Longword;
+    r: TSDL_Rect;
+begin
+cnt:= 0;
+with Obj do
+     begin
+     if Maxcnt = 0 then
+        begin
+        Result:= false;
+        exit
+        end;
+     x:= 0;
+     r.x:= 0;
+     r.y:= 0;
+     r.w:= Width;
+     r.h:= Height + 16;
+     repeat
+         y:= 8;
+         repeat
+             if CheckLand(r, x, y - 8, $FFFFFF)
+                and not CheckIntersect(x, y, Width, Height) then
+                begin
+                ar[cnt].x:= x;
+                ar[cnt].y:= y;
+                inc(cnt);
+                if cnt > MaxPointsIndex then // buffer is full, do not check the rest land
+                   begin
+                   y:= 5000;
+                   x:= 5000;
+                   end
+                end;
+             inc(y, 12);
+         until y > 1023 - Height - 8;
+         inc(x, getrandom(12) + 12)
+     until x > 2047 - Width;
+     Result:= cnt <> 0;
+     if Result then
+        begin
+        i:= getrandom(cnt);
+        r.x:= ar[i].X;
+        r.y:= ar[i].Y;
+        r.w:= Width;
+        r.h:= Height;
+        SDL_UpperBlit(Obj.Surf, nil, Surface, @r);
+        AddRect(ar[i].x - 32, ar[i].y - 32, Width + 64, Height + 64);
+        dec(Maxcnt)
+        end else Maxcnt:= 0
+     end
+end;
+
+procedure ReadThemeInfo(var ThemeObjects: TThemeObjects; var SprayObjects: TSprayObjects);
+var s: string;
+    f: textfile;
+    i, ii: integer;
 begin
 s:= Pathz[ptThemeCurrent] + '/' + cThemeCFGFilename;
-WriteLnToConsole('Adding objects...');
+WriteLnToConsole('Reading objects info...');
 AssignFile(f, s);
 {$I-}
 Reset(f);
 Readln(f, s); // skip color
-Readln(f, n);
-for i:= 1 to n do
+Readln(f, ThemeObjects.Count);
+for i:= 0 to Pred(ThemeObjects.Count) do
     begin
     Readln(f, s); // filename
-    with ThemeObjects[i] do
+    with ThemeObjects.objs[i] do
          begin
          Surf:= LoadImage(Pathz[ptThemeCurrent] + '/' + s + '.png', false);
          Read(f, Width, Height);
@@ -317,37 +382,84 @@
          Read(f, rectcnt);
          for ii:= 1 to rectcnt do
              with outland[ii] do Read(f, x, y, w, h);
-         Maxcnt:= 2;
+         Maxcnt:= 3;
          ReadLn(f)
          end;
     end;
+
+Readln(f, SprayObjects.Count);
+for i:= 0 to Pred(SprayObjects.Count) do
+    begin
+    Readln(f, s); // filename
+    with SprayObjects.objs[i] do
+         begin
+         Surf:= LoadImage(Pathz[ptThemeCurrent] + '/' + s + '.png', false);
+         Width:= Surf.w;
+         Height:= Surf.h;
+         ReadLn(f, Maxcnt)
+         end;
+    end;
 Closefile(f);
 {$I+}
-TryDo(IOResult = 0, 'Bad data or cannot access file ' + cThemeCFGFilename, true);
+TryDo(IOResult = 0, 'Bad data or cannot access file ' + cThemeCFGFilename, true)
+end;
 
-// loaded objects, try to put on land
-if n = 0 then exit;
+procedure AddThemeObjects(Surface: PSDL_Surface; var ThemeObjects: TThemeObjects; MaxCount: integer);
+var i, ii, t: integer;
+    b: boolean;
+begin
+if ThemeObjects.Count = 0 then exit;
+WriteLnToConsole('Adding theme objects...');
 i:= 1;
 repeat
-    t:= getrandom(n) + 1;
+    t:= getrandom(ThemeObjects.Count);
     ii:= t;
     repeat
       inc(ii);
-      if ii > n then ii:= 1;
-      b:= TryPut(ThemeObjects[ii], Surface)
+      if ii = ThemeObjects.Count then ii:= 0;
+      b:= TryPut(ThemeObjects.objs[ii], Surface)
     until b or (ii = t);
-inc(i)
-until (i > MaxCount) or not b
+    inc(i)
+until (i > MaxCount) or not b;
 end;
 
-procedure AddObjects(Surface: PSDL_Surface);
+procedure AddSprayObjects(Surface: PSDL_Surface; var SprayObjects: TSprayObjects; MaxCount: Longword);
+var i: Longword;
+    ii, t: integer;
+    b: boolean;
+begin
+if SprayObjects.Count = 0 then exit;
+WriteLnToConsole('Adding spray objects...');
+i:= 1;
+repeat
+    t:= getrandom(SprayObjects.Count);
+    ii:= t;
+    repeat
+      inc(ii);
+      if ii = SprayObjects.Count then ii:= 0;
+      b:= TryPut(SprayObjects.objs[ii], Surface)
+    until b or (ii = t);
+    inc(i)
+until (i > MaxCount) or not b;
+end;
+
+procedure AddObjects(InSurface, Surface: PSDL_Surface);
+var ThemeObjects: TThemeObjects;
+    SprayObjects: TSprayObjects;
 begin
 InitRects;
+AddGirder(256, Surface);
 AddGirder(512, Surface);
+AddGirder(768, Surface);
 AddGirder(1024, Surface);
-AddGirder(1300, Surface);
+AddGirder(1280, Surface);
 AddGirder(1536, Surface);
-AddThemeObjects(Surface, 8);
+AddGirder(1792, Surface);
+ReadThemeInfo(ThemeObjects, SprayObjects);
+AddThemeObjects(Surface, ThemeObjects, 8);
+AddProgress;
+SDL_UpperBlit(InSurface, nil, Surface, nil);
+AddSprayObjects(Surface, SprayObjects, 10);
 FreeRects
 end;
 
--- a/hedgewars/uMisc.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uMisc.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -64,7 +64,6 @@
 
     cSkyColor     : Cardinal = 0;
     cWaterColor   : Cardinal = $005ACE;
-    cMapBackColor : Cardinal = $FFFFFF;
     cWhiteColor   : Cardinal = $FFFFFF;
     cConsoleSplitterColor : Cardinal = $FF0000;
     cColorNearBlack       : Cardinal = 16;
@@ -149,7 +148,7 @@
 
 procedure TryDo(Assert: boolean; Msg: string; isFatal: boolean);
 begin
-if not Assert then OutError(msg, isFatal)
+if not Assert then OutError(Msg, isFatal)
 end;
 
 procedure SDLTry(Assert: boolean; isFatal: boolean);
--- a/hedgewars/uSound.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uSound.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -77,7 +77,7 @@
 if not isSoundEnabled then exit;
 for i:= Low(TSound) to High(TSound) do
     begin
-    s:= Pathz[ptSounds] + '/' + Soundz[i].FileName;
+    s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
     WriteToConsole(msgLoading + s + ' ');
     Soundz[i].id:= Mix_LoadWAV_RW(SDL_RWFromFile(PChar(s), 'rb'), 1);
     TryDo(Soundz[i].id <> nil, msgFailed, true);
--- a/hedgewars/uStore.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uStore.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -150,7 +150,7 @@
     begin
     r.x:= 0;
     r.y:= 272;
-    drY:= cSCreenHeight - 4;
+    drY:= cScreenHeight - 4;
     Team:= TeamsList;
     while Team<>nil do
       begin
@@ -319,7 +319,7 @@
 
 AddProgress;
 WriteNames(fnt16);
-MakeCrosshairs;
+MakeCrossHairs;
 LoadGraves;
 
 GetSkyColor;
--- a/hedgewars/uTeams.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uTeams.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -73,7 +73,7 @@
     TeamsList: PTeam = nil;
 
 function AddTeam: PTeam;
-procedure ApplyAmmoChanges(Hedgehog: PHedgehog);
+procedure ApplyAmmoChanges(var Hedgehog: THedgehog);
 procedure SwitchHedgehog;
 procedure InitTeams;
 procedure OnUsedAmmo(Ammo: PHHAmmo);
@@ -129,7 +129,7 @@
 cWindSpeed:= (GetRandom * 2 - 1) * cMaxWindSpeed;
 AddGear(0, 0, gtActionTimer, gtsSmoothWindCh).Tag:= round(72 * cWindSpeed / cMaxWindSpeed);
 {$IFDEF DEBUGFILE}AddFileLog('Wind = '+FloatToStr(cWindSpeed));{$ENDIF}
-ApplyAmmoChanges(@CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog]);
+ApplyAmmoChanges(CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog]);
 TurnTimeLeft:= cHedgehogTurnTime
 end;
 
@@ -219,10 +219,10 @@
 RecountAllTeamsHealth
 end;
 
-procedure ApplyAmmoChanges(Hedgehog: PHedgehog);
+procedure ApplyAmmoChanges(var Hedgehog: THedgehog);
 var s: shortstring;
 begin
-with Hedgehog^ do
+with Hedgehog do
      begin
      if Ammo[CurSlot, CurAmmo].Count = 0 then
         begin
@@ -259,12 +259,12 @@
       b:= false;
       ami:= 0;
       while (not b) and (ami < cMaxSlotAmmoIndex) do
-          if (Ammo[slot, ami].Count = 0)
-             and (Ammo[slot, ami + 1].Count > 0) then b:= true
+          if (Ammo[Slot, ami].Count = 0)
+             and (Ammo[Slot, ami + 1].Count > 0) then b:= true
                                                  else inc(ami);
       if b then // есть пустое место
          begin
-         Ammo[slot, ami]:= Ammo[slot, ami + 1]
+         Ammo[Slot, ami]:= Ammo[Slot, ami + 1]
          end
     until not b;
 end;
--- a/hedgewars/uWorld.pas	Tue Jun 20 21:22:15 2006 +0000
+++ b/hedgewars/uWorld.pas	Fri Jun 23 20:02:41 2006 +0000
@@ -318,8 +318,8 @@
       exit
       end
       else begin
-      CursorPoint.x:= (CursorPoint.x + (round(FollowGear.X + Sign(FollowGear.dX) * 100) + WorldDx)) div 2;
-      CursorPoint.y:= (CursorPoint.y + (round(FollowGear.Y) + WorldDy)) div 2
+      CursorPoint.x:= (CursorPoint.x * 3 + (round(FollowGear.X + Sign(FollowGear.dX) * 100) + WorldDx)) div 4;
+      CursorPoint.y:= (CursorPoint.y * 3 + (round(FollowGear.Y) + WorldDy)) div 4
       end;
 
 if ((CursorPoint.X = prevPoint.X)and(CursorPoint.Y = prevpoint.Y)) then exit;
@@ -360,8 +360,8 @@
          end;
    end else
    begin
-      WorldDx:= WorldDx - CursorPoint.X + (cScreenWidth  shr 1);
-      WorldDy:= WorldDy - CursorPoint.Y + (cScreenHeight shr 1);
+      WorldDx:= WorldDx - CursorPoint.X + prevPoint.X;
+      WorldDy:= WorldDy - CursorPoint.Y + prevPoint.Y;
       CursorPoint.X:= (cScreenWidth  shr 1);
       CursorPoint.Y:= (cScreenHeight shr 1);
    end;