hedgewars/uWorld.pas
branchsdl2transition
changeset 11362 ed5a6478e710
parent 9798 f2b18754742f
parent 11317 62287d4044e7
child 11519 aab4767d9a50
--- a/hedgewars/uWorld.pas	Tue Nov 10 18:16:35 2015 +0100
+++ b/hedgewars/uWorld.pas	Tue Nov 10 20:43:13 2015 +0100
@@ -1,6 +1,6 @@
 (*
  * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -13,11 +13,10 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *)
 
 {$INCLUDE "options.inc"}
-{$IF GLunit = GL}{$DEFINE GLunit:=GL,GLext}{$ENDIF}
 
 unit uWorld;
 interface
@@ -40,6 +39,7 @@
 procedure animateWidget(widget: POnScreenWidget; fade, showWidget: boolean);
 procedure MoveCamera;
 procedure onFocusStateChanged;
+procedure updateCursorVisibility;
 
 implementation
 uses
@@ -52,7 +52,6 @@
     , uVisualGears
     , uChat
     , uLandTexture
-    , GLunit
     , uVariables
     , uUtils
     , uTextures
@@ -66,8 +65,7 @@
 {$ENDIF}
     ;
 
-var cWaveWidth, cWaveHeight: LongInt;
-    AMShiftTargetX, AMShiftTargetY, AMShiftX, AMShiftY, SlotsNum: LongInt;
+var AMShiftTargetX, AMShiftTargetY, AMShiftX, AMShiftY, SlotsNum: LongInt;
     AMAnimStartTime, AMState : LongInt;
     AMAnimState: Single;
     tmpSurface: PSDL_Surface;
@@ -79,7 +77,6 @@
     amSel: TAmmoType = amNothing;
     missionTex: PTexture;
     missionTimer: LongInt;
-    stereoDepth: GLfloat;
     isFirstFrame: boolean;
     AMAnimType: LongInt;
     recTexture: PTexture;
@@ -121,18 +118,22 @@
 function AddGoal(s: ansistring; gf: longword; si: TGoalStrId; i: LongInt): ansistring;
 var t: ansistring;
 begin
+{$IFNDEF PAS2C}
     if (GameFlags and gf) <> 0 then
         begin
         t:= inttostr(i);
         s:= s + FormatA(trgoal[si], t) + '|'
         end;
+{$ENDIF}
     AddGoal:= s;
 end;
 
 function AddGoal(s: ansistring; gf: longword; si: TGoalStrId): ansistring;
 begin
+{$IFNDEF PAS2C}
     if (GameFlags and gf) <> 0 then
         s:= s + trgoal[si] + '|';
+{$ENDIF}
     AddGoal:= s;
 end;
 
@@ -212,10 +213,10 @@
     end;
 
 // if the string has been set, show it for (default timeframe) seconds
-if g <> '' then
+if length(g) > 0 then
     ShowMission(trgoal[gidCaption], trgoal[gidSubCaption], g, 1, 0);
 
-cWaveWidth:= SpritesData[sprWater].Width;
+//cWaveWidth:= SpritesData[sprWater].Width;
 //cWaveHeight:= SpritesData[sprWater].Height;
 cWaveHeight:= 32;
 
@@ -225,7 +226,7 @@
 prevPoint.Y:= cScreenHeight div 2;
 //prevTargetPoint.X:= 0;
 //prevTargetPoint.Y:= 0;
-WorldDx:=  -(LAND_WIDTH div 2) + cScreenWidth div 2;
+WorldDx:=  -(LongInt(leftX + (playWidth div 2))); // -(LAND_WIDTH div 2);// + cScreenWidth div 2;
 WorldDy:=  -(LAND_HEIGHT - (playHeight div 2)) + (cScreenHeight div 2);
 
 //aligns it to the bottom of the screen, minus the border
@@ -401,14 +402,12 @@
 // for uStore texture resetting
 procedure ResetWorldTex;
 begin
-    FreeTexture(fpsTexture);
-    fpsTexture:= nil;
-    FreeTexture(timeTexture);
-    timeTexture:= nil;
-    FreeTexture(missionTex);
-    missionTex:= nil;
-    FreeTexture(recTexture);
-    recTexture:= nil;
+    FreeAndNilTexture(fpsTexture);
+    FreeAndNilTexture(timeTexture);
+    FreeAndNilTexture(missionTex);
+    FreeAndNilTexture(recTexture);
+    FreeAndNilTexture(AmmoMenuTex);
+    AmmoMenuInvalidated:= true;
 end;
 
 function GetAmmoMenuTexture(Ammo: PHHAmmo): PTexture;
@@ -419,6 +418,8 @@
     AMRect: TSDL_Rect;
 {$IFDEF USE_AM_NUMCOLUMN}tmpsurf: PSDL_Surface;{$ENDIF}
 begin
+    if cOnlyStats then exit(nil);
+
     SlotsNum:= 0;
     for i:= 0 to cMaxSlotIndex do
         if((i = 0) and (Ammo^[i,1].Count > 0)) or ((i <> 0) and (Ammo^[i,0].Count > 0)) then
@@ -441,14 +442,14 @@
     AmmoRect.w:= (BORDERSIZE*2) + (SlotsNumX * AMSlotSize) + (SlotsNumX-1);
     AmmoRect.h:= (BORDERSIZE*2) + (SlotsNumY * AMSlotSize) + (SlotsNumY-1);
     amSurface := SDL_CreateRGBSurface(SDL_SWSURFACE, AmmoRect.w, AmmoRect.h, 32, RMask, GMask, BMask, AMask);
-    
+
     AMRect.x:= BORDERSIZE;
     AMRect.y:= BORDERSIZE;
     AMRect.w:= AmmoRect.w - (BORDERSIZE*2);
     AMRect.h:= AmmoRect.h - (BORDERSIZE*2);
 
     SDL_FillRect(amSurface, @AMRect, SDL_MapRGB(amSurface^.format, 0,0,0));
-    
+
     x:= AMRect.x;
     y:= AMRect.y;
     for i:= 0 to cMaxSlotIndex do
@@ -482,25 +483,25 @@
                     AMFrame:= LongInt(Ammo^[i,t].AmmoType) - 1;
                     if STurns >= 0 then //weapon not usable yet, draw grayed out with turns remaining
                         begin
-                        DrawSpriteFrame2Surf(sprAMAmmosBW, amSurface, x + AMSlotPadding, 
+                        DrawSpriteFrame2Surf(sprAMAmmosBW, amSurface, x + AMSlotPadding,
                                                                  y + AMSlotPadding, AMFrame);
                         if STurns < 100 then
-                            DrawSpriteFrame2Surf(sprTurnsLeft, amSurface, 
-                                x + AMSlotSize-16, 
+                            DrawSpriteFrame2Surf(sprTurnsLeft, amSurface,
+                                x + AMSlotSize-16,
                                 y + AMSlotSize + 1 - 16, STurns);
                         end
                     else //draw colored version
                         begin
-                        DrawSpriteFrame2Surf(sprAMAmmos, amSurface, x + AMSlotPadding, 
+                        DrawSpriteFrame2Surf(sprAMAmmos, amSurface, x + AMSlotPadding,
                                                                y + AMSlotPadding, AMFrame);
                         end;
 {$IFDEF USE_LANDSCAPE_AMMOMENU}
-	    inc(y, AMSlotSize + 1); //the plus one is for the border
+        inc(y, AMSlotSize + 1); //the plus one is for the border
 {$ELSE}
-	    inc(x, AMSlotSize + 1);
+        inc(x, AMSlotSize + 1);
 {$ENDIF}
-	    end;
-	end;
+        end;
+    end;
 {$IFDEF USE_LANDSCAPE_AMMOMENU}
     inc(x, AMSlotSize + 1);
 {$ELSE}
@@ -509,7 +510,7 @@
     end;
 
 for i:= 1 to SlotsNumX -1 do
-DrawLine2Surf(amSurface, i * (AMSlotSize+1)+1, BORDERSIZE, i * (AMSlotSize+1)+1, AMRect.h + BORDERSIZE - AMSlotSize - 2,160,160,160);            
+DrawLine2Surf(amSurface, i * (AMSlotSize+1)+1, BORDERSIZE, i * (AMSlotSize+1)+1, AMRect.h + BORDERSIZE - AMSlotSize - 2,160,160,160);
 for i:= 1 to SlotsNumY -1 do
 DrawLine2Surf(amSurface, BORDERSIZE, i * (AMSlotSize+1)+1, AMRect.w + BORDERSIZE, i * (AMSlotSize+1)+1,160,160,160);
 
@@ -554,11 +555,11 @@
     exit
     end;
 
-//Init the menu 
-if(AmmoMenuInvalidated) then 
+//Init the menu
+if(AmmoMenuInvalidated) then
     begin
     AmmoMenuInvalidated:= false;
-    FreeTexture(AmmoMenuTex);
+    FreeAndNilTexture(AmmoMenuTex);
     AmmoMenuTex:= GetAmmoMenuTexture(Ammo);
 
 {$IFDEF USE_LANDSCAPE_AMMOMENU}
@@ -611,7 +612,7 @@
             begin
             AMShiftX:= Round(AMShiftTargetX * (1 - AMAnimState));
             AMShiftY:= Round(AMShiftTargetY * (1 - AMAnimState));
-            if (AMAnimType and AMTypeMaskAlpha) <> 0 then 
+            if (AMAnimType and AMTypeMaskAlpha) <> 0 then
                 Tint($FF, $ff, $ff, Round($ff * AMAnimState));
             end
         else
@@ -636,10 +637,10 @@
             begin
             AMShiftX:= Round(AMShiftTargetX * AMAnimState);
             AMShiftY:= Round(AMShiftTargetY * AMAnimState);
-            if (AMAnimType and AMTypeMaskAlpha) <> 0 then 
+            if (AMAnimType and AMTypeMaskAlpha) <> 0 then
                 Tint($FF, $ff, $ff, Round($ff * (1-AMAnimState)));
             end
-         else 
+         else
             begin
             AMShiftX:= AMShiftTargetX;
             AMShiftY:= AMShiftTargetY;
@@ -648,11 +649,11 @@
             AMState:= AMHidden;
             end;
     end;
-    
+
 DrawTexture(AmmoRect.x + AMShiftX, AmmoRect.y + AMShiftY, AmmoMenuTex);
 
-if ((AMState = AMHiding) or (AMState = AMShowingUp)) and ((AMAnimType and AMTypeMaskAlpha) <> 0 )then 
-    Tint($FF, $ff, $ff, $ff);
+if ((AMState = AMHiding) or (AMState = AMShowingUp)) and ((AMAnimType and AMTypeMaskAlpha) <> 0 )then
+    untint;
 
 Pos:= -1;
 Slot:= -1;
@@ -672,15 +673,15 @@
                     begin
                     if (CursorPoint.Y <= (cScreenHeight - AmmoRect.y) - ( g    * (AMSlotSize+1))) and
                        (CursorPoint.Y >  (cScreenHeight - AmmoRect.y) - ((g+1) * (AMSlotSize+1))) and
-                       (CursorPoint.X >  AmmoRect.x                   + ( c    * (AMSlotSize+1))) and 
+                       (CursorPoint.X >  AmmoRect.x                   + ( c    * (AMSlotSize+1))) and
                        (CursorPoint.X <= AmmoRect.x                   + ((c+1) * (AMSlotSize+1))) then
                         begin
                         Slot:= i;
                         Pos:= t;
                         STurns:= Ammoz[Ammo^[i, t].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber;
                         if (STurns < 0) and (AMShiftX = 0) and (AMShiftY = 0) then
-                            DrawSprite(sprAMSlot, 
-                                       AmmoRect.x + BORDERSIZE + (c * (AMSlotSize+1)) + AMSlotPadding, 
+                            DrawSprite(sprAMSlot,
+                                       AmmoRect.x + BORDERSIZE + (c * (AMSlotSize+1)) + AMSlotPadding,
                                        AmmoRect.y + BORDERSIZE + (g  * (AMSlotSize+1)) + AMSlotPadding -1, 0);
                         end;
                         inc(g);
@@ -702,15 +703,15 @@
                     begin
                     if (CursorPoint.Y <= (cScreenHeight - AmmoRect.y) - ( c    * (AMSlotSize+1))) and
                        (CursorPoint.Y >  (cScreenHeight - AmmoRect.y) - ((c+1) * (AMSlotSize+1))) and
-                       (CursorPoint.X >  AmmoRect.x                   + ( g    * (AMSlotSize+1))) and 
+                       (CursorPoint.X >  AmmoRect.x                   + ( g    * (AMSlotSize+1))) and
                        (CursorPoint.X <= AmmoRect.x                   + ((g+1) * (AMSlotSize+1))) then
                         begin
                         Slot:= i;
                         Pos:= t;
                         STurns:= Ammoz[Ammo^[i, t].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber;
                         if (STurns < 0) and (AMShiftX = 0) and (AMShiftY = 0) then
-                            DrawSprite(sprAMSlot, 
-                                       AmmoRect.x + BORDERSIZE + (g * (AMSlotSize+1)) + AMSlotPadding, 
+                            DrawSprite(sprAMSlot,
+                                       AmmoRect.x + BORDERSIZE + (g * (AMSlotSize+1)) + AMSlotPadding,
                                        AmmoRect.y + BORDERSIZE + (c  * (AMSlotSize+1)) + AMSlotPadding -1, 0);
                         end;
                         inc(g);
@@ -741,11 +742,11 @@
                 bShowAmmoMenu:= false;
                 SetWeapon(Ammo^[Slot, Pos].AmmoType);
                 bSelected:= false;
-                FreeWeaponTooltip;
+                FreeAndNilTexture(WeaponTooltipTex);
 {$IFDEF USE_TOUCH_INTERFACE}//show the aiming buttons + animation
                 if (Ammo^[Slot, Pos].Propz and ammoprop_NeedUpDown) <> 0 then
                     begin
-                    if not(arrowUp.show) then
+                    if (not arrowUp.show) then
                         begin
                         animateWidget(@arrowUp, true, true);
                         animateWidget(@arrowDown, true, true);
@@ -764,11 +765,11 @@
             end
         end
     else
-        FreeWeaponTooltip;
+        FreeAndNilTexture(WeaponTooltipTex);
 
     if (WeaponTooltipTex <> nil) and (AMShiftX = 0) and (AMShiftY = 0) then
 {$IFDEF USE_LANDSCAPE_AMMOMENU}
-        if not isPhone() then
+        if (not isPhone()) then
             ShowWeaponTooltip(-WeaponTooltipTex^.w div 2, AmmoRect.y - WeaponTooltipTex^.h - AMSlotSize);
 {$ELSE}
         ShowWeaponTooltip(AmmoRect.x - WeaponTooltipTex^.w - 3, Min(AmmoRect.y + 1, cScreenHeight - WeaponTooltipTex^.h - 40));
@@ -781,127 +782,6 @@
 {$ENDIF}
 end;
 
-procedure DrawWater(Alpha: byte; OffsetY: LongInt);
-var VertexBuffer: array [0..3] of TVertex2f;
-    r: TSDL_Rect;
-    lw, lh: GLfloat;
-begin
-if SuddenDeathDmg then
-    begin
-    SDWaterColorArray[0].a := Alpha;
-    SDWaterColorArray[1].a := Alpha;
-    SDWaterColorArray[2].a := Alpha;
-    SDWaterColorArray[3].a := Alpha
-    end
-else
-    begin
-    WaterColorArray[0].a := Alpha;
-    WaterColorArray[1].a := Alpha;
-    WaterColorArray[2].a := Alpha;
-    WaterColorArray[3].a := Alpha
-    end;
-
-lw:= cScreenWidth / cScaleFactor;
-lh:= trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 + 16;
-
-    // Water
-r.y:= OffsetY + WorldDy + cWaterLine;
-if WorldDy < trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - cWaterLine then
-    begin
-        if r.y < 0 then
-            r.y:= 0;
-
-        glDisable(GL_TEXTURE_2D);
-        VertexBuffer[0].X:= -lw;
-        VertexBuffer[0].Y:= r.y;
-        VertexBuffer[1].X:= lw;
-        VertexBuffer[1].Y:= r.y;
-        VertexBuffer[2].X:= lw;
-        VertexBuffer[2].Y:= lh;
-        VertexBuffer[3].X:= -lw;
-        VertexBuffer[3].Y:= lh;
-
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-        glEnableClientState(GL_COLOR_ARRAY);
-        if SuddenDeathDmg then
-            glColorPointer(4, GL_UNSIGNED_BYTE, 0, @SDWaterColorArray[0])
-        else
-            glColorPointer(4, GL_UNSIGNED_BYTE, 0, @WaterColorArray[0]);
-
-        glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
-
-        glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-
-        glDisableClientState(GL_COLOR_ARRAY);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        glColor4ub($FF, $FF, $FF, $FF); // must not be Tint() as color array seems to stay active and color reset is required
-        glEnable(GL_TEXTURE_2D);
-    end;
-end;
-
-procedure DrawWaves(Dir, dX, dY: LongInt; tnt: Byte);
-var VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
-    lw, waves, shift: GLfloat;
-    sprite: TSprite;
-begin
-if SuddenDeathDmg then
-    sprite:= sprSDWater
-else
-    sprite:= sprWater;
-
-cWaveWidth:= SpritesData[sprite].Width;
-
-lw:= cScreenWidth / cScaleFactor;
-waves:= lw * 2 / cWaveWidth;
-
-if SuddenDeathDmg then
-    Tint(LongInt(tnt) * SDWaterColorArray[2].r div 255 + 255 - tnt,
-         LongInt(tnt) * SDWaterColorArray[2].g div 255 + 255 - tnt,
-         LongInt(tnt) * SDWaterColorArray[2].b div 255 + 255 - tnt,
-         255
-    )
-else
-    Tint(LongInt(tnt) * WaterColorArray[2].r div 255 + 255 - tnt,
-         LongInt(tnt) * WaterColorArray[2].g div 255 + 255 - tnt,
-         LongInt(tnt) * WaterColorArray[2].b div 255 + 255 - tnt,
-         255
-    );
-
-glBindTexture(GL_TEXTURE_2D, SpritesData[sprite].Texture^.id);
-
-VertexBuffer[0].X:= -lw;
-VertexBuffer[0].Y:= cWaterLine + WorldDy + dY;
-VertexBuffer[1].X:= lw;
-VertexBuffer[1].Y:= VertexBuffer[0].Y;
-VertexBuffer[2].X:= lw;
-VertexBuffer[2].Y:= VertexBuffer[0].Y + SpritesData[sprite].Height;
-VertexBuffer[3].X:= -lw;
-VertexBuffer[3].Y:= VertexBuffer[2].Y;
-
-shift:= - lw / cWaveWidth;
-TextureBuffer[0].X:= shift + (( - WorldDx + LongInt(RealTicks shr 6) * Dir + dX) mod cWaveWidth) / (cWaveWidth - 1);
-TextureBuffer[0].Y:= 0;
-TextureBuffer[1].X:= TextureBuffer[0].X + waves;
-TextureBuffer[1].Y:= TextureBuffer[0].Y;
-TextureBuffer[2].X:= TextureBuffer[1].X;
-TextureBuffer[2].Y:= SpritesData[sprite].Texture^.ry;
-TextureBuffer[3].X:= TextureBuffer[0].X;
-TextureBuffer[3].Y:= TextureBuffer[2].Y;
-
-
-glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
-glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
-glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-
-untint;
-
-{for i:= -1 to cWaterSprCount do
-    DrawSprite(sprWater,
-        i * cWaveWidth + ((WorldDx + (RealTicks shr 6) * Dir + dX) mod cWaveWidth) - (cScreenWidth div 2),
-        cWaterLine + WorldDy + dY,
-        0)}
-end;
-
 procedure DrawRepeated(spr, sprL, sprR: TSprite; Shift, OffsetY: LongInt);
 var i, w, h, lw, lh, rw, rh, sw: LongInt;
 begin
@@ -975,180 +855,92 @@
     else
         ZoomValue:= zoom;
 
-    // Sky
-    glClear(GL_COLOR_BUFFER_BIT);
-    //glPushMatrix;
-    //glScalef(1.0, 1.0, 1.0);
-
     if (not isPaused) and (not isAFK) and (GameType <> gmtRecord) then
         MoveCamera;
 
     if cStereoMode = smNone then
         begin
-        glClear(GL_COLOR_BUFFER_BIT);
+        RenderClear();
         DrawWorldStereo(Lag, rmDefault)
-        end
 {$IFDEF USE_S3D_RENDERING}
-    else if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
-        begin
-        // create left fb
-        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel);
-        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
-        DrawWorldStereo(Lag, rmLeftEye);
-
-        // create right fb
-        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer);
-        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
-        DrawWorldStereo(0, rmRightEye);
-
-        // detatch drawing from fbs
-        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame);
-        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
-        SetScale(cDefaultZoomLevel);
-
-        // draw left frame
-        glBindTexture(GL_TEXTURE_2D, texl);
-        glBegin(GL_QUADS);
-            if cStereoMode = smHorizontal then
-                begin
-                glTexCoord2f(0.0, 0.0);
-                glVertex2d(cScreenWidth / -2, cScreenHeight);
-                glTexCoord2f(1.0, 0.0);
-                glVertex2d(0, cScreenHeight);
-                glTexCoord2f(1.0, 1.0);
-                glVertex2d(0, 0);
-                glTexCoord2f(0.0, 1.0);
-                glVertex2d(cScreenWidth / -2, 0);
-                end
-            else
-                begin
-                glTexCoord2f(0.0, 0.0);
-                glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
-                glTexCoord2f(1.0, 0.0);
-                glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
-                glTexCoord2f(1.0, 1.0);
-                glVertex2d(cScreenWidth / 2, 0);
-                glTexCoord2f(0.0, 1.0);
-                glVertex2d(cScreenWidth / -2, 0);
-                end;
-        glEnd();
-
-        // draw right frame
-        glBindTexture(GL_TEXTURE_2D, texr);
-        glBegin(GL_QUADS);
-            if cStereoMode = smHorizontal then
-                begin
-                glTexCoord2f(0.0, 0.0);
-                glVertex2d(0, cScreenHeight);
-                glTexCoord2f(1.0, 0.0);
-                glVertex2d(cScreenWidth / 2, cScreenHeight);
-                glTexCoord2f(1.0, 1.0);
-                glVertex2d(cScreenWidth / 2, 0);
-                glTexCoord2f(0.0, 1.0);
-                glVertex2d(0, 0);
-                end
-            else
-                begin
-                glTexCoord2f(0.0, 0.0);
-                glVertex2d(cScreenWidth / -2, cScreenHeight);
-                glTexCoord2f(1.0, 0.0);
-                glVertex2d(cScreenWidth / 2, cScreenHeight);
-                glTexCoord2f(1.0, 1.0);
-                glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
-                glTexCoord2f(0.0, 1.0);
-                glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
-                end;
-        glEnd();
-        SetScale(zoom);
         end
     else
         begin
-        // clear scene
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
-        // draw left eye in red channel only
-        if cStereoMode = smGreenRed then
-            glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
-        else if cStereoMode = smBlueRed then
-            glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
-        else if cStereoMode = smCyanRed then
-            glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
-        else
-            glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+        // draw frame for left eye
+        RenderClear(rmLeftEye);
         DrawWorldStereo(Lag, rmLeftEye);
-        // draw right eye in selected channel(s) only
-        if cStereoMode = smRedGreen then
-            glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
-        else if cStereoMode = smRedBlue then
-            glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
-        else if cStereoMode = smRedCyan then
-            glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
-        else
-            glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
-        DrawWorldStereo(Lag, rmRightEye);
-        end
+
+        // draw frame for right eye
+        RenderClear(rmRightEye);
+        DrawWorldStereo(0, rmRightEye);
 {$ENDIF}
+        end;
+
+FinishRender();
 end;
 
-procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
-begin
-{$IFNDEF USE_S3D_RENDERING}
-    rm:= rm; d:= d; // avoid hint
-    exit;
-{$ELSE}
-    d:= d / 5;
-    if rm = rmDefault then
-        exit
-    else if rm = rmLeftEye then
-        d:= -d;
-    stereoDepth:= stereoDepth + d;
-    glMatrixMode(GL_PROJECTION);
-    glTranslatef(d, 0, 0);
-    glMatrixMode(GL_MODELVIEW);
-{$ENDIF}
-end;
- 
-procedure ResetDepth(rm: TRenderMode);
+procedure RenderWorldEdge;
+var
+    //VertexBuffer: array [0..3] of TVertex2f;
+    tmp, w: LongInt;
+    rect: TSDL_Rect;
+    //c1, c2: LongWord; // couple of colours for edges
 begin
-{$IFNDEF USE_S3D_RENDERING}
-    rm:= rm; // avoid hint
-    exit;
-{$ELSE}
-    if rm = rmDefault then
-        exit;
-    glMatrixMode(GL_PROJECTION);
-    glTranslatef(-stereoDepth, 0, 0);
-    glMatrixMode(GL_MODELVIEW);
-    stereoDepth:= 0;
-{$ENDIF}
-end;
-
-
-procedure RenderWorldEdge(Lag: Longword);
-var
-    VertexBuffer: array [0..3] of TVertex2f;
-    c1, c2: LongWord; // couple of colours for edges
-begin
-if WorldEdge <> weNone then
+if (WorldEdge <> weNone) and (WorldEdge <> weSea) then
     begin
 (* I think for a bounded world, will fill the left and right areas with black or something. Also will probably want various border effects/animations based on border type.  Prob also, say, trigger a border animation timer on an impact. *)
 
+    rect.y:= ViewTopY;
+    rect.h:= ViewHeight;
+    tmp:= LongInt(leftX) + WorldDx;
+    w:= tmp - ViewLeftX;
+
+    if w > 0 then
+        begin
+        rect.w:= w;
+        rect.x:= ViewLeftX;
+        DrawRect(rect, $10, $10, $10, $80, true);
+        if WorldEdge = weBounce then
+            DrawLineOnScreen(tmp - 1, ViewTopY, tmp - 1, ViewBottomY, 2, $54, $54, $FF, $FF);
+        end;
+
+    tmp:= LongInt(rightX) + WorldDx;
+    w:= ViewRightX - tmp;
+
+    if w > 0 then
+        begin
+        rect.w:= w;
+        rect.x:= tmp;
+        DrawRect(rect, $10, $10, $10, $80, true);
+        if WorldEdge = weBounce then
+            DrawLineOnScreen(tmp - 1, ViewTopY, tmp - 1, ViewBottomY, 2, $54, $54, $FF, $FF);
+        end;
+
+    (*
+    WARNING: the following render code is outdated and does not work with
+             current Render.pas ! - don't just uncomment without fixing it first
+
     glDisable(GL_TEXTURE_2D);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glEnableClientState(GL_COLOR_ARRAY);
+    if (WorldEdge = weWrap) or (worldEdge = weBounce) then
+        glColor4ub($00, $00, $00, $40)
+    else
+        begin
+        glEnableClientState(GL_COLOR_ARRAY);
+        glColorPointer(4, GL_UNSIGNED_BYTE, 0, @WorldFade[0]);
+        end;
 
     glPushMatrix;
     glTranslatef(WorldDx, WorldDy, 0);
-    glColorPointer(4, GL_UNSIGNED_BYTE, 0, @WorldFade[0]);
 
     VertexBuffer[0].X:= leftX-20;
-    VertexBuffer[0].Y:= -3000;
+    VertexBuffer[0].Y:= -3500;
     VertexBuffer[1].X:= leftX-20;
     VertexBuffer[1].Y:= cWaterLine+cVisibleWater;
     VertexBuffer[2].X:= leftX+30;
     VertexBuffer[2].Y:= cWaterLine+cVisibleWater;
     VertexBuffer[3].X:= leftX+30;
-    VertexBuffer[3].Y:= -3000;
+    VertexBuffer[3].Y:= -3500;
 
     glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
     glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
@@ -1186,7 +978,7 @@
     glColor4ub($FF, $FF, $FF, $FF); // must not be Tint() as color array seems to stay active and color reset is required
     glEnable(GL_TEXTURE_2D);
 
-    // I'd still like to have things happen to the border when a wrap or bounce just occurred, based on a timer 
+    // I'd still like to have things happen to the border when a wrap or bounce just occurred, based on a timer
     if WorldEdge = weBounce then
         begin
         // could maybe alternate order of these on a bounce, or maybe drop the outer ones.
@@ -1227,6 +1019,7 @@
         end;
     if LeftImpactTimer > Lag then dec(LeftImpactTimer,Lag) else LeftImpactTimer:= 0;
     if RightImpactTimer > Lag then dec(RightImpactTimer,Lag) else RightImpactTimer:= 0
+    *)
     end;
 end;
 
@@ -1288,7 +1081,7 @@
             for i:= 0 to cMaxHHIndex do
                 begin
                 inc(h, Hedgehogs[i].HealthBarHealth);
-                if (h < TeamHealthBarHealth) and (Hedgehogs[i].HealthBarHealth > 0) then 
+                if (h < TeamHealthBarHealth) and (Hedgehogs[i].HealthBarHealth > 0) then
                     DrawTexture(15 + h * TeamHealthBarWidth div TeamHealthBarHealth, cScreenHeight + DrawHealthY + smallScreenOffset + 1, SpritesData[sprSlider].Texture);
                 end;
 
@@ -1312,34 +1105,86 @@
             r.w:= NameTagTex^.w - 4;
             r.h:= NameTagTex^.h - 4;
             DrawTextureFromRect(-NameTagTex^.w - 14, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, NameTagTex);
+
+            if OwnerTex <> nil then
+                begin
+                r.w:= OwnerTex^.w - 4;
+                r.h:= OwnerTex^.h - 4;
+                DrawTextureFromRect(-OwnerTex^.w - NameTagTex^.w - 16, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, OwnerTex)
+                end;
+
+            if (GameFlags and gfAISurvival) <> 0 then
+                begin
+                r.w:= AIKillsTex^.w - 4;
+                r.h:= AIKillsTex^.h - 4;
+                DrawTextureFromRect(TeamHealthBarWidth + 24, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, AIKillsTex);
+                end;
+
             // draw flag
             r.w:= 22;
             r.h:= 15;
             DrawTextureFromRect(-12, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, FlagTex);
+            end
+        // draw an arrow next to active team
+        else if (CurrentTeam = TeamsArray[t]) and (TurnTimeLeft > 0) then
+            begin
+            h:= -NameTagTex^.w - 24;
+            if OwnerTex <> nil then
+                h:= h - OwnerTex^.w - 4;
+            DrawSpriteRotatedF(sprFinger, h, cScreenHeight + DrawHealthY + smallScreenOffset + 2 + SpritesData[sprFinger].Width div 4, 0, 1, -90);
             end;
         end;
 if smallScreenOffset <> 0 then
     begin
     SetScale(cDefaultZoomLevel);
     if TeamsCount * 20 > Longword(cScreenHeight) div 5 then
-        Tint($FF,$FF,$FF,$FF);
+        untint;
     end;
 end;
 
 
+var preShiftWorldDx: LongInt;
+
+procedure ShiftWorld(Dir: LongInt); inline;
+begin
+    preShiftWorldDx:= WorldDx;
+    WorldDx:= WorldDx + LongInt(Dir * LongInt(playWidth));
+
+end;
+
+procedure UnshiftWorld(); inline;
+begin
+    WorldDx:= preShiftWorldDx;
+end;
+
 procedure DrawWorldStereo(Lag: LongInt; RM: TRenderMode);
 var i, t: LongInt;
     r: TSDL_Rect;
     tdx, tdy: Double;
     s: shortstring;
     offsetX, offsetY, screenBottom: LongInt;
-    VertexBuffer: array [0..3] of TVertex2f;
+    replicateToLeft, replicateToRight, tmp: boolean;
+    a: Byte;
 begin
+if WorldEdge <> weWrap then
+    begin
+    replicateToLeft := false;
+    replicateToRight:= false;
+    end
+else
+    begin
+    replicateToLeft := (LongInt(leftX)  + WorldDx > ViewLeftX);
+    replicateToRight:= (LongInt(rightX) + WorldDx < ViewRightX);
+    end;
+
+ScreenBottom:= (WorldDy - trunc(cScreenHeight/cScaleFactor) - (cScreenHeight div 2) + cWaterLine);
+
+// note: offsetY is negative!
+offsetY:= 10 *  Min(0, -145 - ScreenBottom); // TODO limit this in the other direction too
+
 if (cReducedQuality and rqNoBackground) = 0 then
     begin
         // Offsets relative to camera - spare them to wimpier cpus, no bg or flakes for them anyway
-        ScreenBottom:= (WorldDy - trunc(cScreenHeight/cScaleFactor) - (cScreenHeight div 2) + cWaterLine);
-        offsetY:= 10 * Min(0, -145 - ScreenBottom);
         SkyOffset:= offsetY div 35 + cWaveHeight;
         HorizontOffset:= SkyOffset;
         if ScreenBottom > SkyOffset then
@@ -1363,67 +1208,159 @@
 if (cReducedQuality and rq2DWater) = 0 then
     begin
         // Waves
-        DrawWater(255, SkyOffset); 
+        DrawWater(255, SkyOffset, 0);
         ChangeDepth(RM, -cStereo_Water_distant);
-        DrawWaves( 1,  0 - WorldDx div 32, - cWaveHeight + offsetY div 35, 64);
+        DrawWaves( 1,  0 - WorldDx div 32, offsetY div 35, -49, 64);
         ChangeDepth(RM, -cStereo_Water_distant);
-        DrawWaves( -1,  25 + WorldDx div 25, - cWaveHeight + offsetY div 38, 48);
+        DrawWaves( -1,  25 + WorldDx div 25, offsetY div 38, -37, 48);
         ChangeDepth(RM, -cStereo_Water_distant);
-        DrawWaves( 1,  75 - WorldDx div 19, - cWaveHeight + offsetY div 45, 32);
+        DrawWaves( 1,  75 - WorldDx div 19, offsetY div 45, -23, 32);
         ChangeDepth(RM, -cStereo_Water_distant);
-        DrawWaves(-1, 100 + WorldDx div 14, - cWaveHeight + offsetY div 70, 24);
+        DrawWaves(-1, 100 + WorldDx div 14, offsetY div 70, -7, 24);
     end
 else
-        DrawWaves(-1, 100, - (cWaveHeight + (cWaveHeight shr 1)), 0);
+    DrawWaves(-1, 100, - cWaveHeight div 2, - cWaveHeight div 2, 0);
+
+ChangeDepth(RM, cStereo_Land);
+DrawVisualGears(5);
+DrawLand(WorldDx, WorldDy);
+
+if replicateToLeft then
+    begin
+    ShiftWorld(-1);
+    DrawLand(WorldDx, WorldDy);
+    UnshiftWorld();
+    end;
+
+if replicateToRight then
+    begin
+    ShiftWorld(1);
+    DrawLand(WorldDx, WorldDy);
+    UnshiftWorld();
+    end;
+
+DrawWater(255, 0, 0);
 
-    changeDepth(RM, cStereo_Land);
-    DrawVisualGears(5);
-    DrawLand(WorldDx, WorldDy);
+(*
+// Attack bar
+    if CurrentTeam <> nil then
+        case AttackBar of
+        //1: begin
+        //r:= StuffPoz[sPowerBar];
+        //{$WARNINGS OFF}
+        //r.w:= (CurrentHedgehog^.Gear^.Power * 256) div cPowerDivisor;
+        //{$WARNINGS ON}
+        //DrawSpriteFromRect(r, cScreenWidth - 272, cScreenHeight - 48, 16, 0, Surface);
+        //end;
+        2: with CurrentHedgehog^ do
+                begin
+                tdx:= hwSign(Gear^.dX) * Sin(Gear^.Angle * Pi / cMaxAngle);
+                tdy:= - Cos(Gear^.Angle * Pi / cMaxAngle);
+                for i:= (Gear^.Power * 24) div cPowerDivisor downto 0 do
+                    DrawSprite(sprPower,
+                            hwRound(Gear^.X) + GetLaunchX(CurAmmoType, hwSign(Gear^.dX), Gear^.Angle) + LongInt(round(WorldDx + tdx * (24 + i * 2))) - 16,
+                            hwRound(Gear^.Y) + GetLaunchY(CurAmmoType, Gear^.Angle) + LongInt(round(WorldDy + tdy * (24 + i * 2))) - 16,
+                            i)
+                end
+        end;
+*)
 
-    DrawWater(255, 0);
+tmp:= bShowFinger;
+bShowFinger:= false;
+
+if replicateToLeft then
+    begin
+    ShiftWorld(-1);
+    DrawVisualGears(1);
+    DrawGears();
+    DrawVisualGears(6);
+    UnshiftWorld();
+    end;
+
+if replicateToRight then
+    begin
+    ShiftWorld(1);
+    DrawVisualGears(1);
+    DrawGears();
+    DrawVisualGears(6);
+    UnshiftWorld();
+    end;
+
+bShowFinger:= tmp;
 
 DrawVisualGears(1);
 DrawGears;
 DrawVisualGears(6);
 
+
 if SuddenDeathDmg then
-    DrawWater(SDWaterOpacity, 0)
+    DrawWater(SDWaterOpacity, 0, 0)
 else
-    DrawWater(WaterOpacity, 0);
+    DrawWater(WaterOpacity, 0, 0);
 
     // Waves
 ChangeDepth(RM, cStereo_Water_near);
-DrawWaves( 1, 25 - WorldDx div 9, - cWaveHeight, 12);
+DrawWaves( 1, 25 - WorldDx div 9, 0, 0, 12);
 
 if (cReducedQuality and rq2DWater) = 0 then
     begin
     //DrawWater(WaterOpacity, - offsetY div 40);
     ChangeDepth(RM, cStereo_Water_near);
-    DrawWaves(-1, 50 + WorldDx div 6, - cWaveHeight - offsetY div 40, 8);
+    DrawWaves(-1, 50 + WorldDx div 6, - offsetY div 40, 23, 8);
     if SuddenDeathDmg then
-        DrawWater(SDWaterOpacity, - offsetY div 20)
+        DrawWater(SDWaterOpacity, - offsetY div 20, 23)
     else
-        DrawWater(WaterOpacity, - offsetY div 20);
+        DrawWater(WaterOpacity, - offsetY div 20, 23);
     ChangeDepth(RM, cStereo_Water_near);
-    DrawWaves( 1, 75 - WorldDx div 4, - cWaveHeight - offsetY div 20, 2);
+    DrawWaves( 1, 75 - WorldDx div 4, - offsetY div 20, 37, 2);
         if SuddenDeathDmg then
-            DrawWater(SDWaterOpacity, - offsetY div 10)
+            DrawWater(SDWaterOpacity, - offsetY div 10, 47)
         else
-            DrawWater(WaterOpacity, - offsetY div 10);
+            DrawWater(WaterOpacity, - offsetY div 10, 47);
         ChangeDepth(RM, cStereo_Water_near);
-        DrawWaves( -1, 25 + WorldDx div 3, - cWaveHeight - offsetY div 10, 0);
+        DrawWaves( -1, 25 + WorldDx div 3, - offsetY div 10, 59, 0);
         end
     else
-        DrawWaves(-1, 50, - (cWaveHeight shr 1), 0);
+        DrawWaves(-1, 50, cWaveHeight div 2, cWaveHeight div 2, 0);
 
 // everything after this ChangeDepth will be drawn outside the screen
 // note: negative parallax gears should last very little for a smooth stereo effect
     ChangeDepth(RM, cStereo_Outside);
+
+    if replicateToLeft then
+        begin
+        ShiftWorld(-1);
+        DrawVisualGears(2);
+        UnshiftWorld();
+        end;
+
+    if replicateToRight then
+        begin
+        ShiftWorld(1);
+        DrawVisualGears(2);
+        UnshiftWorld();
+        end;
+
     DrawVisualGears(2);
 
 // everything after this ResetDepth will be drawn at screen level (depth = 0)
 // note: everything that needs to be readable should be on this level
     ResetDepth(RM);
+
+    if replicateToLeft then
+        begin
+        ShiftWorld(-1);
+        DrawVisualGears(3);
+        UnshiftWorld();
+        end;
+
+    if replicateToRight then
+        begin
+        ShiftWorld(1);
+        DrawVisualGears(3);
+        UnshiftWorld();
+        end;
+
     DrawVisualGears(3);
 
 {$WARNINGS OFF}
@@ -1440,7 +1377,7 @@
     end;
 {$WARNINGS ON}
 
-RenderWorldEdge(Lag);
+RenderWorldEdge();
 
 // this scale is used to keep the various widgets at the same dimension at all zoom levels
 SetScale(cDefaultZoomLevel);
@@ -1460,7 +1397,7 @@
             i:= Succ(Pred(ReadyTimeLeft) div 1000)
         else
             i:= Succ(Pred(TurnTimeLeft) div 1000);
-       
+
         if i>99 then
             t:= 112
         else if i>9 then
@@ -1545,14 +1482,14 @@
         AMAnimStartTime:= RealTicks - (AMAnimDuration - (RealTicks - AMAnimStartTime));
     AMState:= AMShowingUp;
     end;
-if not(bShowAmmoMenu) and ((AMstate = AMShowing) or (AMState = AMShowingUp)) then
+if (not bShowAmmoMenu) and ((AMstate = AMShowing) or (AMState = AMShowingUp)) then
     begin
     if (AMState = AMShowing) then
         AMAnimStartTime:= RealTicks
     else
         AMAnimStartTime:= RealTicks - (AMAnimDuration - (RealTicks - AMAnimStartTime));
     AMState:= AMHiding;
-    end; 
+    end;
 
 if bShowAmmoMenu or (AMState = AMHiding) then
     ShowAmmoMenu;
@@ -1564,6 +1501,7 @@
 // Chat
 DrawChat;
 
+
 // various captions
 if fastUntilLag then
     DrawTextureCentered(0, (cScreenHeight shr 1), SyncTexture);
@@ -1607,11 +1545,11 @@
         if t < 10 then
             s:= '0' + s;
         s:= inttostr(i div 60) + ':' + s;
-   
-    
+
+
         tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
         tmpSurface:= doSurfaceConversion(tmpSurface);
-        FreeTexture(timeTexture);
+        FreeAndNilTexture(timeTexture);
         timeTexture:= Surface2Tex(tmpSurface, false);
         SDL_FreeSurface(tmpSurface)
         end;
@@ -1629,7 +1567,7 @@
             s:= inttostr(FPS) + ' fps';
             tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
             tmpSurface:= doSurfaceConversion(tmpSurface);
-            FreeTexture(fpsTexture);
+            FreeAndNilTexture(fpsTexture);
             fpsTexture:= Surface2Tex(tmpSurface, false);
             SDL_FreeSurface(tmpSurface)
             end;
@@ -1644,7 +1582,7 @@
 
 if ScreenFade <> sfNone then
     begin
-    if not isFirstFrame then
+    if (not isFirstFrame) then
         case ScreenFade of
             sfToBlack, sfToWhite:     if ScreenFadeValue + Lag * ScreenFadeSpeed < sfMax then
                                           inc(ScreenFadeValue, Lag * ScreenFadeSpeed)
@@ -1657,27 +1595,16 @@
             end;
     if ScreenFade <> sfNone then
         begin
+        r.x:= ViewLeftX;
+        r.y:= ViewTopY;
+        r.w:= ViewWidth;
+        r.h:= ViewHeight;
+
         case ScreenFade of
-            sfToBlack, sfFromBlack: Tint(0, 0, 0, ScreenFadeValue * 255 div 1000);
-            sfToWhite, sfFromWhite: Tint($FF, $FF, $FF, ScreenFadeValue * 255 div 1000);
+            sfToBlack, sfFromBlack: DrawRect(r, 0, 0, 0, ScreenFadeValue * 255 div 1000, true);
+            sfToWhite, sfFromWhite: DrawRect(r, $FF, $FF, $FF, ScreenFadeValue * 255 div 1000, true);
             end;
 
-        VertexBuffer[0].X:= -cScreenWidth;
-        VertexBuffer[0].Y:= cScreenHeight;
-        VertexBuffer[1].X:= -cScreenWidth;
-        VertexBuffer[1].Y:= 0;
-        VertexBuffer[2].X:= cScreenWidth;
-        VertexBuffer[2].Y:= 0;
-        VertexBuffer[3].X:= cScreenWidth;
-        VertexBuffer[3].Y:= cScreenHeight;
-
-        glDisable(GL_TEXTURE_2D);
-
-        glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
-        glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-
-        glEnable(GL_TEXTURE_2D);
-        untint;
         if not isFirstFrame and ((ScreenFadeValue = 0) or (ScreenFadeValue = sfMax)) then
             ScreenFade:= sfNone
         end
@@ -1692,21 +1619,17 @@
         s:= 'rec';
         tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fntBig].Handle, Str2PChar(s), cWhiteColorChannels);
         tmpSurface:= doSurfaceConversion(tmpSurface);
-        FreeTexture(recTexture);
+        FreeAndNilTexture(recTexture);
         recTexture:= Surface2Tex(tmpSurface, false);
         SDL_FreeSurface(tmpSurface)
         end;
     DrawTexture( -(cScreenWidth shr 1) + 50, 20, recTexture);
 
+    //a:= Byte(Round(127*(1 + sin(RealTicks*0.007))));
+    a:= Byte(min(255, abs(-255 + ((RealTicks div 2) and 511))));
+
     // draw red circle
-    glDisable(GL_TEXTURE_2D); 
-    Tint($FF, $00, $00, Byte(Round(127*(1 + sin(SDL_GetTicks()*0.007)))));
-    glBegin(GL_POLYGON);
-    for i:= 0 to 20 do
-        glVertex2f(-(cScreenWidth shr 1) + 30 + sin(i*2*Pi/20)*10, 35 + cos(i*2*Pi/20)*10);
-    glEnd();
-    untint;
-    glEnable(GL_TEXTURE_2D);
+    DrawCircleFilled(-(cScreenWidth shr 1) + 30, 35, 10, $FF, $00, $00, a);
     end;
 {$ENDIF}
 
@@ -1736,31 +1659,51 @@
 
 
 // Cursor
-if isCursorVisible then
+if isCursorVisible and (not bShowAmmoMenu) then
     begin
-    if not bShowAmmoMenu then
-        begin
-        if not CurrentTeam^.ExtDriven then TargetCursorPoint:= CursorPoint;
-        with CurrentHedgehog^ do
-            if (Gear <> nil) and ((Gear^.State and gstHHChooseTarget) <> 0) then
+    if not CurrentTeam^.ExtDriven then TargetCursorPoint:= CursorPoint;
+    with CurrentHedgehog^ do
+        if (Gear <> nil) and ((Gear^.State and gstChooseTarget) <> 0) then
+            begin
+        if (CurAmmoType = amNapalm) or (CurAmmoType = amMineStrike) or (((GameFlags and gfMoreWind) <> 0) and ((CurAmmoType = amDrillStrike) or (CurAmmoType = amAirAttack))) then
+            DrawLine(-3000, topY-300, 7000, topY-300, 3.0, (Team^.Clan^.Color shr 16), (Team^.Clan^.Color shr 8) and $FF, Team^.Clan^.Color and $FF, $FF);
+        i:= GetCurAmmoEntry(CurrentHedgehog^)^.Pos;
+        with Ammoz[CurAmmoType] do
+            if PosCount > 1 then
                 begin
-            if (CurAmmoType = amNapalm) or (CurAmmoType = amMineStrike) then
-                DrawLine(-3000, topY-300, 7000, topY-300, 3.0, (Team^.Clan^.Color shr 16), (Team^.Clan^.Color shr 8) and $FF, Team^.Clan^.Color and $FF, $FF);
-            i:= GetCurAmmoEntry(CurrentHedgehog^)^.Pos;
-            with Ammoz[CurAmmoType] do
-                if PosCount > 1 then
-                    DrawSprite(PosSprite, TargetCursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - TargetCursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
+                if (CurAmmoType = amGirder) or (CurAmmoType = amTeleport) then
+                    begin
+                // pulsating transparency
+                    if ((GameTicks div 16) mod $80) >= $40 then
+                        Tint($FF, $FF, $FF, $C0 - (GameTicks div 16) mod $40)
+                    else
+                        Tint($FF, $FF, $FF, $80 + (GameTicks div 16) mod $40);
+                    end;
+                DrawSprite(PosSprite, TargetCursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - TargetCursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
+                Untint();
                 end;
-        DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
-        end
+            end;
+    //DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
+    DrawTextureF(SpritesData[sprArrow].Texture, cDefaultZoomLevel / cScaleFactor, TargetCursorPoint.X + round(SpritesData[sprArrow].Width / cScaleFactor), cScreenHeight + round(SpritesData[sprArrow].Height / cScaleFactor) - TargetCursorPoint.Y, (RealTicks shr 6) mod 8, 1, SpritesData[sprArrow].Width, SpritesData[sprArrow].Height);
     end;
-isFirstFrame:= false;
+
+// debug stuff
+if cViewLimitsDebug then
+    begin
+    r.x:= ViewLeftX;
+    r.y:= ViewTopY;
+    r.w:= ViewWidth;
+    r.h:= ViewHeight;
+    DrawRect(r, 255, 0, 0, 128, false);
+    end;
+
+isFirstFrame:= false
 end;
 
 var PrevSentPointTime: LongWord = 0;
 
 procedure MoveCamera;
-var EdgesDist, wdy, shs,z, amNumOffsetX, amNumOffsetY: LongInt;
+var EdgesDist, wdy, shs,z, amNumOffsetX, amNumOffsetY, dstX: LongInt;
     inbtwnTrgtAttks: Boolean;
 begin
 {$IFNDEF MOBILE}
@@ -1768,8 +1711,8 @@
     uCursor.updatePosition();
 {$ENDIF}
 z:= round(200/zoom);
-inbtwnTrgtAttks := (CurrentHedgehog <> nil) and ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0) and ((GameFlags and gfInfAttack) <> 0);
-if autoCameraOn and not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) and not inbtwnTrgtAttks then
+inbtwnTrgtAttks := ((GameFlags and gfInfAttack) <> 0) and (CurrentHedgehog <> nil) and ((CurrentHedgehog^.Gear = nil) or (CurrentHedgehog^.Gear <> FollowGear)) and ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0);
+if autoCameraOn and (not PlacingHogs) and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) and (not inbtwnTrgtAttks) then
     if ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then
         begin
         FollowGear:= nil;
@@ -1778,13 +1721,36 @@
         end
     else
         begin
-        CursorPoint.X:= (prevPoint.X * 7 + hwRound(FollowGear^.X) + hwSign(FollowGear^.dX) * z + WorldDx) div 8;
-        if isPhone() or (cScreenHeight < 600) or ((hwSign(FollowGear^.dY) * z) < 10)  then
+            dstX:= hwRound(FollowGear^.X) + hwSign(FollowGear^.dX) * z + WorldDx;
+
+            if (WorldEdge = weWrap) then
+                begin
+                    if dstX - prevPoint.X < (LongInt(leftX) - rightX) div 2 then
+                        CursorPoint.X:= (prevPoint.X * 7 + dstX - (leftX - rightX)) div 8
+                    else if dstX - prevPoint.X > (LongInt(rightX) - leftX) div 2 then
+                        CursorPoint.X:= (prevPoint.X * 7 + dstX - (rightX - leftX)) div 8
+                    else
+                        CursorPoint.X:= (prevPoint.X * 7 + dstX) div 8;
+                end
+            else // usual camera movement routine
+                begin
+                    CursorPoint.X:= (prevPoint.X * 7 + dstX) div 8;
+                end;
+
+        if isPhone() or (cScreenHeight < 600) or (hwFloat(FollowGear^.dY * z).Round < 10) then
             CursorPoint.Y:= (prevPoint.Y * 7 + cScreenHeight - (hwRound(FollowGear^.Y) + WorldDy)) div 8
         else
             CursorPoint.Y:= (prevPoint.Y * 7 + cScreenHeight - (hwRound(FollowGear^.Y) + hwSign(FollowGear^.dY) * z + WorldDy)) div 8;
         end;
 
+if (WorldEdge = weWrap) then
+    begin
+        if -WorldDx < leftX then
+            WorldDx:= WorldDx - LongInt(rightX) + leftX
+        else if -WorldDx > rightX then
+            WorldDx:= WorldDx + LongInt(rightX) - leftX;
+    end;
+
 wdy:= trunc(cScreenHeight / cScaleFactor) + cScreenHeight div 2 - cWaterLine - cVisibleWater;
 if WorldDy < wdy then
     WorldDy:= wdy;
@@ -1810,7 +1776,7 @@
     {$ENDIF}
 
 {$ENDIF}
-    if CursorPoint.X < AmmoRect.x + amNumOffsetX + 3 then//check left 
+    if CursorPoint.X < AmmoRect.x + amNumOffsetX + 3 then//check left
         CursorPoint.X:= AmmoRect.x + amNumOffsetX + 3;
     if CursorPoint.X > AmmoRect.x + AmmoRect.w - 3 then//check right
         CursorPoint.X:= AmmoRect.x + AmmoRect.w - 3;
@@ -1889,25 +1855,27 @@
 procedure ShowMission(caption, subcaption, text: ansistring; icon, time : LongInt);
 var r: TSDL_Rect;
 begin
+if cOnlyStats then exit;
+
 r.w:= 32;
 r.h:= 32;
 
 if time = 0 then
     time:= 5000;
 missionTimer:= time;
-FreeTexture(missionTex);
+FreeAndNilTexture(missionTex);
 
 if icon > -1 then
     begin
     r.x:= 0;
     r.y:= icon * 32;
-    missionTex:= RenderHelpWindow(caption, subcaption, text, '', 0, MissionIcons, @r)
+    missionTex:= RenderHelpWindow(caption, subcaption, text, ansistring(''), 0, MissionIcons, @r)
     end
 else
     begin
     r.x:= ((-icon - 1) shr 4) * 32;
     r.y:= ((-icon - 1) mod 16) * 32;
-    missionTex:= RenderHelpWindow(caption, subcaption, text, '', 0, SpritesData[sprAMAmmos].Surface, @r)
+    missionTex:= RenderHelpWindow(caption, subcaption, text, ansistring(''), 0, SpritesData[sprAMAmmos].Surface, @r)
     end;
 end;
 
@@ -1939,14 +1907,22 @@
 
 {$IFDEF USE_VIDEO_RECORDING}
 // do not change volume during prerecording as it will affect sound in video file
-if not flagPrerecording then
+if (not flagPrerecording) then
 {$ENDIF}
     begin
-    if not cHasFocus then DampenAudio()
+    if (not cHasFocus) then DampenAudio()
     else UndampenAudio();
     end;
 end;
 
+procedure updateCursorVisibility;
+begin
+    if isPaused or isAFK then
+        SDL_ShowCursor(1)
+    else
+        SDL_ShowCursor(ord(GameState = gsConfirm))
+end;
+
 procedure SetUtilityWidgetState(ammoType: TAmmoType);
 begin
 {$IFDEF USE_TOUCH_INTERFACE}
@@ -1954,11 +1930,11 @@
     ammoType:= CurrentHedgehog^.CurAmmoType;
 
 if(CurrentHedgehog <> nil)then
-    if (Ammoz[ammoType].Ammo.Propz and ammoprop_Timerable) <> 0 then
+    if ((Ammoz[ammoType].Ammo.Propz and ammoprop_Timerable) <> 0) and (ammoType <> amDrillStrike) then
         begin
         utilityWidget.sprite:= sprTimerButton;
         animateWidget(@utilityWidget, true, true);
-        end 
+        end
     else if (Ammoz[ammoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
         begin
         utilityWidget.sprite:= sprTargetButton;
@@ -1966,7 +1942,7 @@
         end
     else if ammoType = amSwitch then
         begin
-        utilityWidget.sprite:= sprTargetButton;
+        utilityWidget.sprite:= sprSwitchButton;
         animateWidget(@utilityWidget, true, true);
         end
     else if utilityWidget.show then
@@ -1982,7 +1958,7 @@
     begin
     show:= showWidget;
     if fade then fadeAnimStart:= RealTicks;
-    
+
     with moveAnim do
         begin
         animate:= true;
@@ -2020,10 +1996,8 @@
     missionTimer:= 0;
     missionTex:= nil;
     cOffsetY:= 0;
-    stereoDepth:= 0;
     AMState:= AMHidden;
     isFirstFrame:= true;
-    stereoDepth:= stereoDepth; // avoid hint
 
     FillChar(WorldFade, sizeof(WorldFade), 0);
     WorldFade[0].a:= 255;
@@ -2034,6 +2008,8 @@
     WorldEnd[2].a:= 255;
     WorldEnd[3].a:= 255;
 
+    AmmoMenuTex:= nil;
+    AmmoMenuInvalidated:= true
 end;
 
 procedure freeModule;