unit Unit1;

interface
      
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GLScene, GLObjects, GLCoordinates, GLWin32Viewer,
  GLCrossPlatform, GLCadencer,  jpeg,
  GLNavigator, Math, ExtCtrls, StdCtrls, ComCtrls,
  GLBitmapFont, GLWindowsFont,
  GLGameMenu, GLHUDObjects, GLConsole, GLGui, GLWindows,
  typinfo, ScktComp, GLGeomObjects,UMyUtils, GLBaseClasses;
  
type THeight=(Down,Up);     //todo 1:Zeitanzeige

type TInhaltSorte=(
  empty,Arrow,Goal,YSNP,Green,GreenTrap,                             //0..8
  WallTrap,Speed,BadSpeed,GreenSpeed,Turner,UpDownPorter,UpPorter,   //9..15
  DownPorter,Explosion,RainbowTrap,Pusher,BlackExplosion,Lightning   //16..20
  );

type TPanelConfig=record  
  ID:Cardinal;
  TopDivH,LeftDivW,HeightDivH,WidthDivW:Real;
  Text:String;
  FontColor,BackGroundColor:TColor;
  FontSizeDivH:Real;
  Seconds:Real;
  DontShowIfWon:Boolean;
  SpeedAtEnd:Boolean;
end;

type PPanelConfig=^TPanelConfig;

type TInhalt=record
  Sorte:Integer;
  Daten:Pointer;
end;       

type TPlayer=record
  X,Y,Z:Real;
  LastX,LastZ:Real;
  LastTimeStart,LastTimeEnd:Cardinal;
  Ceilwalk:Boolean;
  jumping:Boolean;
  jumptime:Real;
  Speed:Real;
  Dead:Boolean;
  OutOfMaze:Boolean;
end;

type TRoomtype=record
  MaterialName:array[THeight] of string; 
  ID:Cardinal;
  Roomfrequenzy:Real;
  Explode:array[THeight] of Boolean;
  ExplodeOtherPlayer:array[THeight] of Boolean;
  PortTo:array[THeight] of Boolean;
  TurnToGoal:array[THeight] of Boolean;
  WinAtArrival:Boolean;
  YSNP:array[THeight] of Boolean;
  GreenWallsAround:Boolean;
  ChangeAtArrivalTo:array[THeight] of Integer;//-1=nicht ändern, 0=Feld leeren
  ChangeWallsAtArrival:Boolean;
  ChangeSpeedAtArrival:Real;
  ChangeSpeedRandom:array[THeight] of Boolean;
  TurnPlayer:Boolean;
  PortPlayerToCenter:Boolean;
  PushPlayer:array[THeight] of Boolean;
  TurnRandom:array[THeight] of Boolean;    
  InkOthers:array[THeight] of Boolean;    
  ChangeOtherPlayerSpeed:Boolean;
  Contaminate:Boolean;
  OPTanzGegner:Boolean;
  Passierbar:Boolean;
  NotAtSpawn:Boolean;
  WallCageTrap:Boolean;
  NotNextToSelf:Boolean;
  SPInvisible:Boolean; //todo 1: raus
end;

type PRoomtype=^TRoomtype;

type PGLCube=^TGLCube;

type TRichtung=(px,nx,pz,nz);

type TWallset=set of TRichtung;
type PWallset=^TWallset;

type TRaum=record
  created:Boolean;
  Walls,UpWalls,DownWalls:TWallset;
  Inhalt:TInhalt;
end;

type PRaum=^TRaum;

const mapsize=500;
type TMap=array[-mapsize..mapsize,-mapsize..mapsize] of TRaum;

type TMuhNPC=record  //todo 2:nach Inhalt.Daten
  Body:TGLCube;
  MoveX,MoveY,MoveZ:Real;
end;


type
  TForm1 = class(TForm)
    Scene1: TGLScene;
    GLSceneViewer1: TGLSceneViewer;
    Panel1: TPanel;
    Timer1: TTimer;
    GLUserInterface1: TGLUserInterface;
    GLNavigator1: TGLNavigator;
    Panel2: TPanel;
    Panel3: TPanel;
    Panel4: TPanel;
    Panel5: TPanel;
    Panel6: TPanel;
    Panel8: TPanel;
    Panel9: TPanel;
    Panel11: TPanel;
    Panel13: TPanel;
    RichEdit1: TRichEdit;
    MenuFont: TGLWindowsBitmapFont;
    PlayerGoalDistFont: TGLWindowsBitmapFont;
    Memo1: TMemo;
    Walls: TGLDummyCube;
    OtherPlayers: TGLDummyCube;
    GLCamera1: TGLCamera;
    Planes: TGLDummyCube;
    Pushers: TGLDummyCube;
    UpDownPorters: TGLDummyCube;
    GreenSpeeds: TGLDummyCube;
    Explosions: TGLDummyCube;
    BadSpeeds: TGLDummyCube;
    Turners: TGLDummyCube;
    Grounds: TGLDummyCube;
    Speeds: TGLDummyCube;
    Arrows: TGLDummyCube;
    YSNPs: TGLDummyCube;
    Ceilings: TGLDummyCube;
    Blackexplosions: TGLDummyCube;
    Lightnings: TGLDummyCube;
    Menu: TGLDummyCube;
    MPJoinMenu: TGLGameMenu;
    MPHostMenu: TGLGameMenu;
    MPMenu: TGLGameMenu;
    VideoMenu: TGLGameMenu;
    SettingsMenu: TGLGameMenu;
    MainMenu: TGLGameMenu;
    HUDTexts: TGLDummyCube;
    GLHUDText1: TGLHUDText;
    PlayerGoalDists: TGLDummyCube;
    GLHUDText2: TGLHUDText;
    MuhNPCs: TGLDummyCube;
    ThrustBar: TProgressBar;
    PlayerLight: TGLLightSource;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    function NewWall(x,z:Integer; width,depth:Real):TGLCube;
    function NewUpWall(x,z:Integer; width,depth:Real):TGLCube;
    function NewDownWall(x,z:Integer; width,depth:Real):TGLCube;
    function NewMuhNPCBody(x,z:Integer):TGLCube;
    procedure startJump(ID:Integer);
    procedure activateWall(dir,x,z:Integer; activate:Boolean);
    procedure activateUpWall(dir,x,z:Integer; activate:Boolean);
    procedure activateDownWall(dir,x,z:Integer; activate:Boolean);
    procedure activateGreen(x,z:Integer; activate:Boolean);
    procedure Reload;
    procedure ReloadWallShaders;
    procedure ReloadTexQual;
    procedure CreateMap;
    procedure ReloadRoom(X,Z:Integer);
    procedure SpreadContamination(X,Z:Integer);
    procedure Explode(X,Z:Integer);
    function NewPlane(x,z:Integer; Height:THeight;
      Sorte:Integer):TGLPlane;
    function NewPlayer(ID:Integer):TGLCylinder;
    procedure Creategoal;
    procedure FormResize(Sender: TObject);
    procedure RearrangePanels;
    procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure Respawn;
    procedure GLSceneViewer1MouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure WinGame(ID: Cardinal);
    procedure LoseGame;
    procedure ChangeSpeedTo(NewSpeed:Real);
    procedure MultiplySpeedBy(Factor:Real);
    procedure ChangeSpeedBy(DeltaSpeed:Real);
    procedure ThrustBarMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure GLSceneViewer1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);   
    procedure ShowPanel(ID:Cardinal);
  private
  end;

function GetRT(X,Z:Integer):PRoomtype;
function GetPC(X,Z:Integer):PPanelConfig;

const                
  PlayerDepth:array[Boolean] of Real=(1.6,0.3);
  PlayerHeight:array[Boolean] of Real=(0.3,1.6);
  RaumRange=8;
  Exploradius=4;
  Spawnradius=4;
  SpawnradiusNoSorte=7;
  SpawnradiusNoWalls=3;
  ViewFullscreen:Boolean=false;
  colortest=false;
  Debug=true;
  showMapCreateTime=false;

  Richtungen:array[TRichtung] of TRichtung=(px,nx,pz,nz);
var
  StartSpeed:Real=15;

  start:Cardinal; 

  GameEnded:Boolean=false;
  
  Camera:TGLCamera;
  PlayerGoalDistPanels:array of TGLHUDText;

  jumppressed:Boolean;

  log:TextFile;
  npl:TGLCylinder;
  Roomtypes:array of TRoomType;
  PanelConfigs:array of TPanelConfig;

  Players:array of TPlayer;
  MyID:Cardinal;

  MinGoalDist:Integer=22;
  MaxGoalDist:Integer=26;
  ShaderWidth:Integer=6;
  GoalProtectionRadius:Integer=2;
  inMenu:Boolean;
  Panel11Seconds,Panel13Seconds,RE1Seconds:Real;
  Form1: TForm1;
  Map:TMap;

  PosX,PosZ:Integer;

  playerarr:array of TGLCylinder;

  RoomInvisible,PlaneInvisible:array[-RaumRange..RaumRange,-RaumRange..RaumRange]
  of Boolean;

  Wallarr,DownWallArr,UpWallArr:
  array[0..1,-RaumRange..RaumRange+1,-RaumRange..RaumRange+1] of TGLCube;
  PlayerList:TList;

  MuhNPCArr:array[-RaumRange..RaumRange,-RaumRange..RaumRange] of
  TMuhNPC;

  PlaneArr:
  array of array[THeight,-RaumRange..RaumRange,-RaumRange..RaumRange] of
  TGLPlane;

  lasttime:Cardinal=0;

  PGoal:PRaum;
  GoalPos:TPoint;

  Lost,Won:Boolean;

  ThrustDrag:Boolean;  

  SW:TMyStopWatch;




implementation

uses UNetwork, UMaterials, UCadencer, UMoveToRoom,UCreateRaum,UColorByID,
  UCheckmaze, UMessageThread, ShellAPI, UIni, IniFiles, UMainMenu, System.UITypes;

{$R *.dfm}


function GetRT(X,Z:Integer):PRoomtype;
begin
  Result:=@Roomtypes[Map[X,Z].Inhalt.Sorte];
end;


function GetPC(X,Z:Integer):PPanelConfig;  
begin
  Result:=@PanelConfigs[Map[X,Z].Inhalt.Sorte];
end;


               
procedure TForm1.ChangeSpeedBy(DeltaSpeed:Real);
begin                                          
  Players[MyID].Speed:=Players[MyID].Speed+DeltaSpeed*ThrustBar.Position/1000;
end;

procedure TForm1.ChangeSpeedTo(NewSpeed:Real);
begin                                       
  Players[MyID].Speed:=NewSpeed*ThrustBar.Position/1000;
end;

procedure TForm1.MultiplySpeedBy(Factor:Real);
begin
  Players[MyID].Speed:=Players[MyID].Speed*Factor;
end;


procedure TForm1.WinGame(ID: Cardinal);
begin
  if Won then Exit;
  GameEnded:=true;
  if ID=MyID then begin
    Panel8.Font.Color:=RGB(25,150,25);
    Panel8.Color:=RGB(38,38,38);
    Panel8.Visible:=true;
    Panel8.Caption:='You win!';
    Panel9.Font.Color:=RGB(25,150,25);
    Panel9.Color:=RGB(38,38,38);
    Panel9.Visible:=true;
    Panel9.Caption:='Made by EBY aka Eror';
    ChangeSpeedBy(30);
    Won:=true;
    Beep;
  end else begin
    Panel8.Font.Color:=RGB(150,25,25);
    Panel8.Color:=RGB(38,38,38);
    Panel8.Visible:=true;
    Panel8.Caption:='Player '+IntToStr(ID)+' won the game!';
    LoseGame;
  end;
end;

procedure TForm1.LoseGame;
begin
  Form3.SendPosition;
  if Lost then Exit;
  Players[MyID].Dead:=true;
  Form3.SendKill(MyID);
  Panel9.Font.Color:=RGB(150,25,25);
  Panel9.Color:=RGB(38,38,38);
  Panel9.Visible:=true;
  Panel9.Caption:='You Lose...';
  Lost:=true;

  
  Beep;
end;





procedure TForm1.RearrangePanels;
var C2:Integer;
begin
  MenuFont.Font.Size:=Round(OrigSizes[13]*self.Height);
  PlayerGoalDistFont.Font.Size:=Round(OrigSizes[14]*self.Height);

  for C2:=0 to High(PlayerGoalDistPanels) do
  PlayerGoalDistPanels[C2].Position.SetPoint
  (0.01*self.Width,Form1.PlayerGoalDistFont.Font.Size*(C2+0.5),0);

  Panel8.SetBounds(
  Round(self.Width*OrigSizes[5]),
  Round(self.Height*OrigSizes[7]),
  Round(self.Width*OrigSizes[6]),
  Round(self.Height*OrigSizes[8]));
  Panel9.SetBounds(
  Round(self.Width*OrigSizes[9]),
  Round(self.Height*OrigSizes[11]),
  Round(self.Width*OrigSizes[10]),
  Round(self.Height*OrigSizes[12]));
  MainMenu.Position.X:=self.Width*OrigSizes[15];
  MainMenu.Position.Y:=self.Height*OrigSizes[16];

  GLHUDText1.Position.X:=Round(self.Width*OrigSizes[21]);
  GLHUDText1.Position.Y:=Round(self.Height*OrigSizes[22]);

  GLHUDText2.Position.X:=Round(self.Width*OrigSizes[23]);
  GLHUDText2.Position.Y:=Round(self.Height*OrigSizes[24]);

  Panel13.SetBounds(
  Round(self.Width*OrigSizes[25]), 
  Round(self.Height*OrigSizes[27]),
  Round(self.Width*OrigSizes[26]),
  Round(self.Height*OrigSizes[28]));
  Panel8.Font.Size:=Round(self.Width*OrigSizes[29]);
  Panel9.Font.Size:=Round(self.Width*OrigSizes[30]);
  Panel11.Font.Size:=Round(self.Width*OrigSizes[32]);
  MenuFont.Font.Size:=Round(self.Width*OrigSizes[33]);
  Panel13.Font.Size:=Round(self.Width*OrigSizes[34]);


  RichEdit1.SetBounds(
  Round(OrigSizes[35]*self.Width),
  Round(OrigSizes[37]*self.Height),
  Round(OrigSizes[36]*self.Width),
  Round(OrigSizes[38]*self.Height));
  RichEdit1.Font.SIZE:=Round(OrigSizes[39]*self.Height);   
  SettingsMenu.Position.X:=self.Width*OrigSizes[40];
  SettingsMenu.Position.Y:=self.Height*OrigSizes[41]; 
  VideoMenu.Position.X:=self.Width*OrigSizes[42];
  VideoMenu.Position.Y:=self.Height*OrigSizes[43];
  MPMenu.Position.X:=self.Width*OrigSizes[46];
  MPMenu.Position.Y:=self.Height*OrigSizes[47];
  MPHostMenu.Position.X:=self.Width*OrigSizes[48];
  MPHostMenu.Position.Y:=self.Height*OrigSizes[49];
  MPJoinMenu.Position.X:=self.Width*OrigSizes[50];
  MPJoinMenu.Position.Y:=self.Height*OrigSizes[51];
  
  ThrustBar.Top:=Round(self.Height*OrigSizes[52]);
  ThrustBar.Left:=Round(self.Width*OrigSizes[53]);
  ThrustBar.Height:=Round(self.Height*OrigSizes[54]);
  ThrustBar.Width:=Round(self.Width*OrigSizes[55]);
end;
                          
procedure TForm1.ReloadRoom(X,Z:Integer);
var C1,C2:Integer;
begin
  if (X<PosX-RaumRange)
  or (X>PosX+RaumRange)
  or (Z<PosZ-RaumRange)
  or (Z>PosZ+RaumRange) then
  Exit;

  if not Map[X,Z].created then CreateRaum(X,Z);

  if RoomInvisible[X-PosX,Z-PosZ] then begin
    Wallarr[0,X-posX,Z-PosZ].Visible:=false;
    Wallarr[1,X-posX,Z-PosZ].Visible:=false;
    UpWallarr[0,X-posX,Z-PosZ].Visible:=false;
    UpWallarr[1,X-posX,Z-PosZ].Visible:=false;
    DownWallarr[0,X-posX,Z-PosZ].Visible:=false;
    DownWallarr[1,X-posX,Z-PosZ].Visible:=false;

    for C1:=0 to High(Roomtypes) do begin
      PlaneArr[C1,Down,X-posX,Z-PosZ].Visible:=false;
      PlaneArr[C1,Up,X-posX,Z-PosZ].Visible:=false;
    end;
    MuhNPCArr[X-posX,Z-posZ].Body.Visible:=false;

    Exit;
  end;


  if Map[X-1,Z].Inhalt.Sorte<>Integer(Green) then begin
    activateWall(0,X-posX,Z-posZ,nx in Map[X,Z].Walls);
    activateUpWall(0,X-posX,Z-posZ,nx in Map[X,Z].UpWalls);
    activateDownWall(0,X-posX,Z-posZ,nx in Map[X,Z].DownWalls);
  end;
  if Map[X+1,Z].Inhalt.Sorte<>Integer(Green) then begin
    activateWall(0,X+1-posX,Z-posZ,px in Map[X,Z].Walls);
    activateUpWall(0,X+1-posX,Z-posZ,px in Map[X,Z].UpWalls);
    activateDownWall(0,X+1-posX,Z-posZ,px in Map[X,Z].DownWalls);
  end;
  if Map[X,Z-1].Inhalt.Sorte<>Integer(Green) then begin
    activateWall(1,X-posX,Z-posZ,nz in Map[X,Z].Walls);
    activateUpWall(1,X-posX,Z-posZ,nz in Map[X,Z].UpWalls);
    activateDownWall(1,X-posX,Z-posZ,nz in Map[X,Z].DownWalls);
  end;
  if Map[X,Z+1].Inhalt.Sorte<>Integer(Green) then begin
    activateWall(1,X-posX,Z-posZ+1,pz in Map[X,Z].Walls);
    activateUpWall(1,X-posX,Z-posZ+1,pz in Map[X,Z].UpWalls);
    activateDownWall(1,X-posX,Z-posZ+1,pz in Map[X,Z].DownWalls);
  end;
            
    
  activateGreen(X-PosX,Z-posZ,Map[X,Z].Inhalt.Sorte=Integer(Green));

  if PlaneInvisible[X-PosX,Z-PosZ] then begin
    for C1:=0 to High(Roomtypes) do begin
      PlaneArr[C1,Down,X-posX,Z-PosZ].Visible:=false;
      PlaneArr[C1,Up,X-posX,Z-PosZ].Visible:=false;
    end;
    MuhNPCArr[X-posX,Z-posZ].Body.Visible:=false;

    Exit;
  end;

  for C1:=0 to High(Roomtypes) do begin
    PlaneArr[C1,Down,X-PosX,Z-PosZ].Visible:=Map[X,Z].Inhalt.Sorte=C1;
    if Map[X,Z].Inhalt.Sorte=C1 then begin
      for C2:=C1+1 to High(Roomtypes) do
      if PlaneArr[C1,Down,X-PosX,Z-PosZ]<>PlaneArr[C2,Down,X-PosX,Z-PosZ]
      then PlaneArr[C2,Down,X-PosX,Z-PosZ].Visible:=false;
      Break;
    end;
  end;

  for C1:=0 to High(Roomtypes) do begin
    PlaneArr[C1,Up,X-PosX,Z-PosZ].Visible:=Map[X,Z].Inhalt.Sorte=C1;
    if Map[X,Z].Inhalt.Sorte=C1 then begin
      for C2:=C1+1 to High(Roomtypes) do
      if PlaneArr[C1,Up,X-PosX,Z-PosZ]<>PlaneArr[C2,Up,X-PosX,Z-PosZ]
      then PlaneArr[C2,Up,X-PosX,Z-PosZ].Visible:=false;
      Break;
    end;
  end;

  if (GetRT(X,Z).SPInvisible)
  and not Form3.ClientSocket.Active
  and not Form3.ServerSocket.Active then begin
    for C1:=1 to High(Roomtypes) do begin
      PlaneArr[C1,Down,X-PosX,Z-PosZ].Visible:=false;
      PlaneArr[C1,Up,X-PosX,Z-PosZ].Visible:=false;
    end;                                     
    MuhNPCArr[X-posX,Z-posZ].Body.Visible:=false;
    
    PlaneArr[0,Down,X-PosX,Z-PosZ].Visible:=true;
    PlaneArr[0,Up,X-PosX,Z-PosZ].Visible:=true;
    Exit;
  end;


  if GetRT(X,Z).TurnRandom[Up] then
  if Assigned(Map[X,Z].Inhalt.Daten) then
  case TRichtung(Map[X,Z].Inhalt.Daten^) of
    pz:Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=0;
    nx:Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=90;
    nz:Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=180;
    px:Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=270;
  end;
  if GetRT(X,Z).TurnRandom[Down] then
  if Assigned(Map[X,Z].Inhalt.Daten) then
  case TRichtung(Map[X,Z].Inhalt.Daten^) of
    pz:Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=180;
    nx:Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=90;
    nz:Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=0;  
    px:Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=270;
  end;

  if GetRT(X,Z).TurnToGoal[Up] then
  if Abs(GoalPos.X-X)>Abs(GoalPos.Y-Z) then begin
    if GoalPos.X-X>0 then
    Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=-90//px
    else
    Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=90//nx
  end else begin
    if GoalPos.Y-Z>0 then
    Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=0//pz
    else
    Planearr[Map[X,Z].Inhalt.Sorte,Up,x-PosX,z-posZ].RollAngle:=180//nz
  end;

  if GetRT(X,Z).TurnToGoal[Down] then
  if Abs(GoalPos.X-X)>Abs(GoalPos.Y-Z) then begin
    if GoalPos.X-X>0 then
    Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=-90//px
    else
    Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=90//nx
  end else begin
    if GoalPos.Y-Z>0 then
    Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=180//pz
    else
    Planearr[Map[X,Z].Inhalt.Sorte,Down,x-PosX,z-posZ].RollAngle:=0//nu
  end;

  MuhNPCArr[X-posX,Z-posZ].Body.Visible:=GetRT(X,Z).OPTanzGegner;
end;

procedure TForm1.Reload;
var C1,C3,C2:Integer;
begin
  CameraDirection:=Ceil(Camera.Direction.X)+2*Ceil(Camera.Direction.Z);

  for C1:=-RaumRange to RaumRange do
  for C2:=-RaumRange to RaumRange do begin
    RoomInvisible[C1,C2]:=false;
    PlaneInvisible[C1,C2]:=false;
  end;

  if GetRT(PosX,PosZ).GreenWallsAround then  
  for C1:=-RaumRange to RaumRange do
  for C2:=-RaumRange to RaumRange do begin
    RoomInvisible[C1,C2]:=true;
    PlaneInvisible[C1,C2]:=true;
  end;

  if not Players[MyID].OutOfMaze then begin
    for C2:=1 to RaumRange do
    if (nx in Map[C2+PosX,PosZ].Walls)
    or (GetRT(C2+PosX,PosZ).GreenWallsAround) then begin
      PlaneInvisible[C2,0]:=true;
      for C1:=C2+1 to RaumRange do
      RoomInvisible[C1,0]:=true;
      Break;
    end;            
    for C2:=1 to RaumRange do
    if (nz in Map[PosX,C2+PosZ].Walls)
    or (GetRT(PosX,C2+PosZ).GreenWallsAround) then begin
      PlaneInvisible[0,C2]:=true;
      for C1:=C2+1 to RaumRange do
      RoomInvisible[0,C1]:=true;
      Break;
    end;     
    for C2:=-1 downto -RaumRange do
    if (pz in Map[PosX,C2+PosZ].Walls)
    or (GetRT(PosX,C2+PosZ).GreenWallsAround) then begin 
      PlaneInvisible[0,C2]:=true;
      for C1:=C2-1 downto -RaumRange do
      RoomInvisible[0,C1]:=true;
      Break;
    end;
    for C2:=-1 downto -RaumRange do
    if (px in Map[C2+PosX,PosZ].Walls)
    or (GetRT(C2+PosX,PosZ).GreenWallsAround) then begin
      PlaneInvisible[C2,0]:=true;
      for C1:=C2-1 downto -RaumRange do
      RoomInvisible[C1,0]:=true;
      Break;
    end;

    if (((px in Map[PosX,PosZ].Walls)
    or (GetRT(PosX+1,PosZ).GreenWallsAround))
    and ((pz in Map[PosX,PosZ].Walls)
    or (GetRT(PosX,PosZ+1).GreenWallsAround)))
    or (CameraDirection=0) then
    for C1:=1 to RaumRange do
    for C2:=1 to RaumRange do begin
      RoomInvisible[C1,C2]:=true;
    end;

    if (((px in Map[PosX,PosZ].Walls)
    or (GetRT(PosX+1,PosZ).GreenWallsAround))
    and ((nz in Map[PosX,PosZ].Walls)
    or (GetRT(PosX,PosZ-1).GreenWallsAround)))
    or (CameraDirection=2) then
    for C1:=1 to RaumRange do
    for C2:=-1 downto -RaumRange do begin
      RoomInvisible[C1,C2]:=true;
    end;

    if (((nx in Map[PosX,PosZ].Walls)
    or (GetRT(PosX-1,PosZ).GreenWallsAround))
    and ((nz in Map[PosX,PosZ].Walls)
    or (GetRT(PosX,PosZ-1).GreenWallsAround)))
    or (CameraDirection=3) then
    for C1:=-1 downto -RaumRange do
    for C2:=-1 downto -RaumRange do begin
      RoomInvisible[C1,C2]:=true;
    end;

    if (((nx in Map[PosX,PosZ].Walls)
    or (GetRT(PosX-1,PosZ).GreenWallsAround))
    and ((pz in Map[PosX,PosZ].Walls)
    or (GetRT(PosX,PosZ+1).GreenWallsAround)))
    or (CameraDirection=1) then
    for C1:=-1 downto -RaumRange do
    for C2:=1 to RaumRange do begin
      RoomInvisible[C1,C2]:=true;
    end;

    for C1:=-1 to 1 do begin
      RoomInvisible[C1,0]:=false;
      RoomInvisible[0,C1]:=false;
    end;
    PlaneInvisible[0,0]:=false;
  end;

  for C1:=PosX-RaumRange to PosX+RaumRange do
  for C3:=PosZ-RaumRange to PosZ+RaumRange do
  ReloadRoom(C1,C3);

  ReloadWallShaders;
  ReloadTexQual;
end;

procedure TForm1.ReloadWallShaders;
var C1,C3:Integer;
begin
  for C1:=-RaumRange to RaumRange+1 do
  for C3:=-RaumRange to RaumRange+1 do
  if (C1<-ShaderWidth+1)
  or (C3<-ShaderWidth+1)
  or (C1>ShaderWidth)
  or (C3>ShaderWidth) then begin
    if Wallarr[0,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[0,C1,C3].Material.LibMaterialName:='WallFar';
    if Wallarr[1,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[1,C1,C3].Material.LibMaterialName:='WallFar';
    if UpWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallFar';
    if UpWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallFar';
    if DownWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallFar';
    if DownWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallFar';
  end;
end;

procedure TForm1.ReloadTexQual;
var C1,C3:Integer;
const HiResRad=3; LowResRad=6;
begin
  for C1:=-RaumRange to RaumRange+1 do
  for C3:=-RaumRange to RaumRange+1 do
  if sqrt(sqr(C1)+sqr(C3))>LowResRad then begin
    if Wallarr[0,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[0,C1,C3].Material.LibMaterialName:='WallVeryLowRes';
    if Wallarr[1,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[1,C1,C3].Material.LibMaterialName:='WallVeryLowRes';
    if UpWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallVeryLowRes';
    if UpWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallVeryLowRes';
    if DownWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallVeryLowRes';
    if DownWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallVeryLowRes';
  end else
  if sqrt(sqr(C1)+sqr(C3))>HiResRad then begin
    if Wallarr[0,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[0,C1,C3].Material.LibMaterialName:='WallLowRes';
    if Wallarr[1,C1,C3].Material.LibMaterialName='Wall'
    then Wallarr[1,C1,C3].Material.LibMaterialName:='WallLowRes';
    if UpWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallLowRes';
    if UpWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then UpWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallLowRes';
    if DownWallarr[0,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[0,C1,C3].Material.LibMaterialName:='HalfWallLowRes';
    if DownWallarr[1,C1,C3].Material.LibMaterialName='HalfWall'
    then DownWallarr[1,C1,C3].Material.LibMaterialName:='HalfWallLowRes';
  end;
end;


procedure TForm1.Timer1Timer(Sender: TObject);
begin
  GLHUDText2.Visible:=inMenu;
  if VideoMenu.Visible then begin
    VideoMenu.Items[2]:='Shading Distance: '+IntToStr(ShaderWidth);
  end;
  if MPHostMenu.Visible then begin
    MPHostMenu.Items[0]:='Port: '+IntToStr(MPPort);
  end;
  if MPJoinMenu.Visible then begin
    MPJoinMenu.Items[0]:='Server-IP: '+MPServerAddress;
    MPJoinMenu.Items[1]:='Port: '+IntToStr(MPPort);
  end;


  GLSceneViewer1MouseMove(
  Sender,[],Form1.ScreenToClient(Mouse.CursorPos).X,
  Form1.ScreenToClient(Mouse.CursorPos).Y);

  CalcFPS(TTimer(Sender).Interval/1000);
  if Panel1.Visible then
  Panel1.Caption:=floatToStr(Round(100*FPS)/100);
  Self.Caption:='Randomaze  FPS: '+floatToStr(Round(100*FPS)/100);

  if Panel11.Visible then begin
    Panel11Seconds:=Panel11Seconds-TTimer(Sender).Interval/1000;
    if Panel11Seconds<0.01 then begin //Float Comparison
      Panel11Seconds:=0;
      Panel11.Visible:=false;
    end;
  end;
  //todo 1:panel11 position in panelconfig, RichEdit1 in origsizes
  if RichEdit1.Visible then begin
    RE1Seconds:=RE1Seconds-TTimer(Sender).Interval/1000;
    if RE1Seconds<0.01 then begin //Float Comparison
      RE1Seconds:=0;
      RichEdit1.Visible:=false;
    end;
  end;

  if Panel13.Visible then begin
    Panel13Seconds:=Panel13Seconds-TTimer(Sender).Interval/1000;
    if Panel13Seconds<0.01 then begin //Float Comparison
      Panel13Seconds:=0;
      Panel13.Visible:=false;
    end;
  end;


  if Panel2.Visible then
  Panel2.Caption:=
  FloatToStr(Round(100*GLCamera1.Position.X)/100)+','
  +FloatToStr(Round(100*GLCamera1.Position.Y)/100)+','
  +FloatToStr(Round(100*GLCamera1.Position.Z)/100);       
  if Panel3.Visible then
  Panel3.Caption:=BoolToStr(players[MyId].CeilWalk,true);     
  if Panel4.Visible then
  Panel4.Caption:=BoolToStr(won,true)+','+BoolToStr(lost,true);

  if Panel6.Visible then
  Panel6.Caption:=IntToStr(PosX)+','+IntToStr(PosZ);
   
  if Players[MyID].Speed<=0.01 then
  if IDRecieved then begin   
    Panel8.Font.Color:=RGB(150,25,25);
    Panel8.Color:=RGB(38,38,38);
    Panel8.Visible:=true;
    Panel8.Caption:='Anticamper:';
    LoseGame;
  end;
end;

function TForm1.NewWall(x,z:Integer; width,depth:Real):TGLCube;
begin
  Result:=TGLCube(Walls.AddNewChild(TGLCube));
  Result.Position.X:=x;
  Result.Position.Y:=1;
  Result.Position.Z:=z;
  Result.CubeWidth:=width;
  Result.CubeHeight:=6;
  Result.CubeDepth:=depth;
  Result.Material.MaterialLibrary:=Form2.GLMaterialLibrary1;
  Result.Material.LibMaterialName:='Wall';
end;

function TForm1.NewMuhNPCBody(X,Z:Integer):TGLCube;
begin
  Result:=TGLCube(MuhNPCs.AddNewChild(TGLCube)); 
  Result.Position.X:=20*X;
  Result.Position.Y:=0;
  Result.Position.Z:=20*Z;
  Result.CubeWidth:=2;
  Result.CubeHeight:=2;
  Result.CubeDepth:=2;
  Result.Material.MaterialLibrary:=Form2.GLMaterialLibrary1;
  Result.Material.LibMaterialName:='Muh';
end;

function TForm1.NewUpWall(x,z:Integer; width,depth:Real):TGLCube;
begin
  Result:=TGLCube(Walls.AddNewChild(TGLCube));
  Result.Position.X:=x;
  Result.Position.Y:=2.5;
  Result.Position.Z:=z;
  Result.CubeWidth:=width;
  Result.CubeHeight:=3;
  Result.CubeDepth:=depth;
  Result.Material.MaterialLibrary:=Form2.GLMaterialLibrary1;
  Result.Material.LibMaterialName:='HalfWall';
end;

function TForm1.NewDownWall(x,z:Integer; width,depth:Real):TGLCube;
begin
  Result:=TGLCube(Walls.AddNewChild(TGLCube));
  Result.Position.X:=x;
  Result.Position.Y:=-0.5;
  Result.Position.Z:=z;
  Result.CubeWidth:=width;
  Result.CubeHeight:=3;
  Result.CubeDepth:=depth;
  Result.Material.MaterialLibrary:=Form2.GLMaterialLibrary1;
  Result.Material.LibMaterialName:='HalfWall';
end;

procedure TForm1.SpreadContamination(X,Z:Integer);
var C1,C2:Integer; R1:Real; Pos:TPoint;
begin
  for C1:=X-1 to X+1 do
  for C2:=Z-1 to Z+1 do begin
    R1:=Random;
    if R1<0.3 then begin
      Map[C1,C2].Inhalt.Sorte:=Map[X,Z].Inhalt.Sorte;
      if GetRT(C1,C2).TurnRandom[Down]
      or GetRT(C1,C2).TurnRandom[Up]
      then Map[C1,C2].Inhalt.Daten:=@Richtungen[
      TRichtung(Random(Integer(High(TRichtung))+1))]
    end else if R1<0.5 then
    Map[C1,C2].Inhalt.Sorte:=0;
    
    if R1<0.5 then
    if Form3.ServerSocket.Active then begin
      Pos.X:=C1;
      Pos.Y:=C2;
      Form3.SendRaum(Pos);
    end;
  end;
end;



procedure TForm1.ShowPanel(ID:Cardinal);
begin
  Panel11.Top:=Round(PanelConfigs[ID].TopDivH*Self.Height);
  Panel11.Left:=Round(PanelConfigs[ID].LeftDivW*Self.Width);
  Panel11.Width:=Round(PanelConfigs[ID].WidthDivW*Self.Width);
  Panel11.Height:=Round(PanelConfigs[ID].HeightDivH*Self.Height);
  
  Panel11.Caption:=PanelConfigs[ID].Text;

  if PanelConfigs[ID].SpeedAtEnd then
  Panel11.Caption:=Panel11.Caption+' '+
  Floattostr(Round(100*Players[MyID].Speed)/100);

  Panel11.Font.Color:=PanelConfigs[ID].FontColor;
  Panel11.Color:=PanelConfigs[ID].BackGroundColor;
  Panel11.Font.SIZE:=Round(PanelConfigs[ID].FontSizeDivH*Self.Height);
  Panel11Seconds:=PanelConfigs[ID].Seconds;
  Panel11.Visible:=true;
end;

procedure TForm1.Explode(X,Z:Integer);
var C1,C2:Integer;
begin
  if (X=PosX) and (Z=PosZ) then
  Form1.ShowPanel(14);//todo 1:testen

  if GetRT(X,Z).Explode[Up]
  or GetRT(X,Z).Explode[Down] then 
  Map[X,Z].Inhalt.Sorte:=0;
  for C1:=X-Exploradius to X+Exploradius do
  for C2:=Z-Exploradius to Z+Exploradius do
  if (C1<MapSize)
  and (C1>-MapSize)
  and (C2<MapSize)
  and (C2>-MapSize) then begin
    if not Map[C1,C2].created then CreateRaum(C1,C2);
    if sqrt(sqr(X-C1)+sqr(Z-C2))<Exploradius then begin
      Map[C1,C2].Walls:=[];
      Map[C1+1,C2].Walls:=Map[C1+1,C2].Walls-[nx];
      Map[C1,C2+1].Walls:=Map[C1,C2+1].Walls-[nz];
      Map[C1,C2-1].Walls:=Map[C1,C2-1].Walls-[pz];
      Map[C1-1,C2].Walls:=Map[C1-1,C2].Walls-[px];
      Map[C1,C2].UpWalls:=[];
      Map[C1+1,C2].UpWalls:=Map[C1+1,C2].UpWalls-[nx];
      Map[C1,C2+1].UpWalls:=Map[C1,C2+1].UpWalls-[nz];
      Map[C1,C2-1].UpWalls:=Map[C1,C2-1].UpWalls-[pz];
      Map[C1-1,C2].UpWalls:=Map[C1-1,C2].UpWalls-[px];
      Map[C1,C2].DownWalls:=[];
      Map[C1+1,C2].DownWalls:=Map[C1+1,C2].DownWalls-[nx];
      Map[C1,C2+1].DownWalls:=Map[C1,C2+1].DownWalls-[nz];
      Map[C1,C2-1].DownWalls:=Map[C1,C2-1].DownWalls-[pz];
      Map[C1-1,C2].DownWalls:=Map[C1-1,C2].DownWalls-[px];
      if not Won then begin
        if (Map[C1,C2].Inhalt.Sorte=Integer(GreenTrap))
        then begin
          Map[C1,C2].Inhalt.Sorte:=Integer(Green);
        end;
        if (Map[C1+1,C2].Inhalt.Sorte=Integer(GreenTrap))
        then begin
          Map[C1+1,C2].Inhalt.Sorte:=Integer(Green);
        end;
        if (Map[C1,C2+1].Inhalt.Sorte=Integer(GreenTrap))
        then begin
          Map[C1,C2+1].Inhalt.Sorte:=Integer(Green);
        end;
        if (Map[C1-1,C2].Inhalt.Sorte=Integer(GreenTrap))
        then begin
          Map[C1-1,C2].Inhalt.Sorte:=Integer(Green);
        end;
        if (Map[C1,C2-1].Inhalt.Sorte=Integer(GreenTrap))
        then begin
          Map[C1,C2-1].Inhalt.Sorte:=Integer(Green);
          Form3.SendRaumSorte(C1,C2-1);
        end;
      end;
      if (Map[C1,C2].Inhalt.Sorte=Integer(Explosion))
      then Explode(C1,C2);
      if (Map[C1+1,C2].Inhalt.Sorte=Integer(Explosion))
      then Explode(C1+1,C2);
      if (Map[C1,C2+1].Inhalt.Sorte=Integer(Explosion))
      then Explode(C1,C2);
      if (Map[C1-1,C2].Inhalt.Sorte=Integer(Explosion))
      then Explode(C1-1,C2);
      if (Map[C1,C2-1].Inhalt.Sorte=Integer(Explosion))
      then Explode(C1,C2-1);
    end;
  end;
end;

function TForm1.NewPlayer(ID:Integer):TGLCylinder;
var R,G,B:Real;
begin                                     
  Result:=TGLCylinder(OtherPlayers.AddNewChild(TGLCylinder));
  Result.Slices:=50;
  Result.Height:=PlayerDepth[false]+PlayerHeight[false];
  Result.Position.Y:=-2+(PlayerDepth[false]+PlayerHeight[false])/2;
  Result.TopRadius:=1;
  Result.BottomRadius:=1;
  Result.Up.SetVector(0,1,0);    
  RedbyID(ID,R);
  GreenbyID(ID,G);
  BluebyID(ID,B);
  Result.Material.FrontProperties.Ambient.SetColor(R,G,B);
  Result.Material.FrontProperties.Diffuse.SetColor(R,G,B);
  Result.Material.FrontProperties.Emission.SetColor(R,G,B);
  Result.Material.BackProperties.Ambient.SetColor(R,G,B);
  Result.Material.BackProperties.Diffuse.SetColor(R,G,B);
  Result.Material.BackProperties.Emission.SetColor(R,G,B);
end;

function TForm1.NewPlane(x,z:Integer; Height:THeight;
  Sorte:Integer):TGLPlane;
const HiResRad=1.5; LowResRad=3;
begin
  Result:=TGLPlane(Planes.AddNewChild(TGLPlane));
  Result.Position.X:=x*20;
  if Height=Down then
  Result.Position.Y:=-2
  else Result.Position.Y:=4;
  Result.Position.Z:=z*20;
  Result.Width:=20;
  Result.Height:=20;  
  if Height=Down then
  Result.PitchAngle:=90
  else 
  Result.PitchAngle:=-90;
  Result.Material.MaterialLibrary:=Form2.GLMaterialLibrary1;
  Result.Material.LibMaterialName:=Roomtypes[Sorte].MaterialName[Height];
  if sqrt(sqr(x)+sqr(z))>LowResRad then begin
    if (Roomtypes[Sorte].MaterialName[Height]='Grass') then
    Result.Material.LibMaterialName:='GrassVeryLowRes';
    if (Roomtypes[Sorte].MaterialName[Height]='Ceiling') then
    Result.Material.LibMaterialName:='CeilingVeryLowRes';
  end else if sqrt(sqr(x)+sqr(z))>HiResRad then begin
    if (Roomtypes[Sorte].MaterialName[Height]='Grass') then
    Result.Material.LibMaterialName:='GrassLowRes';
    if (Roomtypes[Sorte].MaterialName[Height]='Ceiling') then
    Result.Material.LibMaterialName:='CeilingLowRes';
  end;
end;

procedure TForm1.activateWall(dir,x,z:Integer; activate:Boolean);
begin
  Wallarr[dir,x,z].Visible:=activate;
end;

procedure TForm1.activateUpWall(dir,x,z:Integer; activate:Boolean);
begin
  UpWallarr[dir,x,z].Visible:=activate;
end;

procedure TForm1.activateDownWall(dir,x,z:Integer; activate:Boolean);
begin
  DownWallarr[dir,x,z].Visible:=activate;
end;

procedure TForm1.activateGreen(X,Z:Integer; activate:Boolean);
begin
  if activate then begin
    if nx in Map[x+PosX,z+PosZ].UpWalls then begin
      DownWallarr[0,X,Z].Material.LibMaterialName:='HalfGreenWall';
      UpWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X,Z].Visible:=true;
      UpWallarr[0,X,Z].Visible:=true;
      Wallarr[0,X,Z].Visible:=false;
    end else if nx in Map[x+PosX,z+PosZ].DownWalls then begin
      DownWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X,Z].Material.LibMaterialName:='HalfGreenWall';
      Wallarr[0,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X,Z].Visible:=true;
      UpWallarr[0,X,Z].Visible:=true;
      Wallarr[0,X,Z].Visible:=false;
    end else if not (nx in Map[x+PosX,z+PosZ].Walls) then begin
      DownWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X,Z].Material.LibMaterialName:='GreenWall';
      DownWallarr[0,X,Z].Visible:=false;
      UpWallarr[0,X,Z].Visible:=false;
      Wallarr[0,X,Z].Visible:=true;
    end else begin                                 
      DownWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X,Z].Visible:=false;
      UpWallarr[0,X,Z].Visible:=false;
      Wallarr[0,X,Z].Visible:=true;
    end;

    if px in Map[x+PosX,z+PosZ].UpWalls then begin
      DownWallarr[0,X+1,Z].Material.LibMaterialName:='HalfGreenWall';
      UpWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X+1,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X+1,Z].Visible:=true;
      UpWallarr[0,X+1,Z].Visible:=true;
      Wallarr[0,X+1,Z].Visible:=false;
    end else if px in Map[x+PosX,z+PosZ].DownWalls then begin
      DownWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X+1,Z].Material.LibMaterialName:='HalfGreenWall';
      Wallarr[0,X+1,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X+1,Z].Visible:=true;
      UpWallarr[0,X+1,Z].Visible:=true;
      Wallarr[0,X+1,Z].Visible:=false;
    end else if not (px in Map[x+PosX,z+PosZ].Walls) then begin
      DownWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X+1,Z].Material.LibMaterialName:='GreenWall';
      DownWallarr[0,X+1,Z].Visible:=false;
      UpWallarr[0,X+1,Z].Visible:=false;
      Wallarr[0,X+1,Z].Visible:=true;
    end else begin                                 
      DownWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X+1,Z].Material.LibMaterialName:='Wall';
      DownWallarr[0,X+1,Z].Visible:=false;
      UpWallarr[0,X+1,Z].Visible:=false;
      Wallarr[0,X+1,Z].Visible:=true;
    end;

    if nz in Map[x+PosX,z+PosZ].UpWalls then begin
      DownWallarr[1,X,Z].Material.LibMaterialName:='HalfGreenWall';
      UpWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z].Visible:=true;
      UpWallarr[1,X,Z].Visible:=true;
      Wallarr[1,X,Z].Visible:=false;
    end else if nz in Map[x+PosX,z+PosZ].DownWalls then begin
      DownWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z].Material.LibMaterialName:='HalfGreenWall';
      Wallarr[1,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z].Visible:=true;
      UpWallarr[1,X,Z].Visible:=true;
      Wallarr[1,X,Z].Visible:=false;
    end else if not (nz in Map[x+PosX,z+PosZ].Walls) then begin
      DownWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z].Material.LibMaterialName:='GreenWall';
      DownWallarr[1,X,Z].Visible:=false;
      UpWallarr[1,X,Z].Visible:=false;
      Wallarr[1,X,Z].Visible:=true;
    end else begin                                 
      DownWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z].Visible:=false;
      UpWallarr[1,X,Z].Visible:=false;
      Wallarr[1,X,Z].Visible:=true;
    end;

    
    if pz in Map[X+PosX,Z+PosZ].UpWalls then begin
      DownWallarr[1,X,Z+1].Material.LibMaterialName:='HalfGreenWall';
      UpWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z+1].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z+1].Visible:=true;
      UpWallarr[1,X,Z+1].Visible:=true;
      Wallarr[1,X,Z+1].Visible:=false;
    end else if pz in Map[x+PosX,z+PosZ].DownWalls then begin
      DownWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z+1].Material.LibMaterialName:='HalfGreenWall';
      Wallarr[1,X,Z+1].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z+1].Visible:=true;
      UpWallarr[1,X,Z+1].Visible:=true;
      Wallarr[1,X,Z+1].Visible:=false;
    end else if not (pz in Map[x+PosX,z+PosZ].Walls) then begin
      DownWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z+1].Material.LibMaterialName:='GreenWall';
      DownWallarr[1,X,Z+1].Visible:=false;
      UpWallarr[1,X,Z+1].Visible:=false;
      Wallarr[1,X,Z+1].Visible:=true;
    end else begin
      DownWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z+1].Material.LibMaterialName:='Wall';
      DownWallarr[1,X,Z+1].Visible:=false;
      UpWallarr[1,X,Z+1].Visible:=false;
      Wallarr[1,X,Z+1].Visible:=true;
    end;

  end else begin 
    if (Map[X+PosX-1,Z+PosZ].Inhalt.Sorte<>Integer(Green)) then begin
      DownWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X,Z].Material.LibMaterialName:='Wall';
    end;
    if (Map[X+PosX+1,Z+PosZ].Inhalt.Sorte<>Integer(Green)) then begin
      DownWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[0,X+1,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[0,X+1,Z].Material.LibMaterialName:='Wall';
    end;
    if (Map[X+PosX,Z+PosZ].Inhalt.Sorte<>Integer(Green)) then begin
      DownWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X+1,Z].Material.LibMaterialName:='Wall';
    end;
    if (Map[X+PosX,Z+PosZ+1].Inhalt.Sorte<>Integer(Green)) then begin
      DownWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      UpWallarr[1,X,Z+1].Material.LibMaterialName:='HalfWall';
      Wallarr[1,X,Z+1].Material.LibMaterialName:='Wall';
    end;
  end;
end;

procedure TForm1.Creategoal;
var C1,C2,C3,C4:Integer;
begin
  Lost:=false;
  Won:=false;
  if PGoal<>nil then begin
    PGoal.Inhalt.Sorte:=0;
    PGoal:=nil;
  end;
  Panel8.Visible:=false;
  C1:=GoalPos.x;
  C3:=GoalPos.y;
//  Map[C1,C3].created:=true;
  Map[C1,C3].Inhalt.Daten:=nil;

  for C4:=C1-GoalProtectionRadius to C1+GoalProtectionRadius do
  for C2:=C3-GoalProtectionRadius to C3+GoalProtectionRadius do begin
    if sqrt(sqr(C1-C4)+sqr(C3-C2))<GoalProtectionRadius then begin
      if not Map[C4,C2].created then CreateRaum(C4,C2);
      if not Map[C4-1,C2].created then CreateRaum(C4,C2);
      if not Map[C4,C2+1].created then CreateRaum(C4,C2);
      if not Map[C4,C2-1].created then CreateRaum(C4,C2);
      if not Map[C4+1,C2].created then CreateRaum(C4,C2);
      if not GetRT(C4,C2).Passierbar then
      Map[C4,C2].Inhalt.Sorte:=0;
      Map[C4,C2].Walls:=[];
      Map[C4+1,C2].Walls:=Map[C4+1,C2].Walls-[nx];
      Map[C4,C2+1].Walls:=Map[C4,C2+1].Walls-[nz];
      Map[C4,C2-1].Walls:=Map[C4,C2-1].Walls-[pz];
      Map[C4-1,C2].Walls:=Map[C4-1,C2].Walls-[px];
      Map[C4,C2].UpWalls:=[];
      Map[C4+1,C2].UpWalls:=Map[C4+1,C2].UpWalls-[nx];
      Map[C4,C2+1].UpWalls:=Map[C4,C2+1].UpWalls-[nz];
      Map[C4,C2-1].UpWalls:=Map[C4,C2-1].UpWalls-[pz];
      Map[C4-1,C2].UpWalls:=Map[C4-1,C2].UpWalls-[px];
      Map[C4,C2].DownWalls:=[];
      Map[C4+1,C2].DownWalls:=Map[C4+1,C2].DownWalls-[nx];
      Map[C4,C2+1].DownWalls:=Map[C4,C2+1].DownWalls-[nz];
      Map[C4,C2-1].DownWalls:=Map[C4,C2-1].DownWalls-[pz];
      Map[C4-1,C2].DownWalls:=Map[C4-1,C2].DownWalls-[px];
    end;
  end; 
  Map[C1,C3].Inhalt.Sorte:=Integer(Goal);

  PGoal:=@Map[C1,C3]; //todo 1: hier müssten "Daten" gefüllt werden

  if GetRT(C1,C3).TurnRandom[Up]
  or GetRT(C1,C3).TurnRandom[Down] then
  Map[C1,C3].Inhalt.Daten:=@Richtungen[
  TRichtung(Random(Integer(High(TRichtung))+1))];

  ReloadRoom(C1,C3);
end;

procedure TForm1.FormCreate(Sender: TObject);
var C1,C3,C4:integer;         
  Repcount:Cardinal;
begin
  
  Memo1.Align:=alClient;
  Memo1.Width:=Form1.Width;
  Memo1.Lines.Clear;
  Memo1.Lines.Add('');
  Memo1.Lines.Add('');
  Memo1.Lines.Add('');
  Memo1.Lines.Add('This is not a Bug and the Game has not stopped running.');
  Memo1.Lines.Add('Please go to the next Room to remove this Message.');
  Memo1.Lines.Add('This works at a proability of 20%.');
  Memo1.Lines.Add('If you can see the Cursor you might be in a Menu.');
  Memo1.Visible:=false;

  ThrustBar.Position:=ThrustBar.Max;

  LastPos:=ThrustBar.Position;

  GLHUDText2.ModulateColor.SetColor(162,162,162);
  GLHUDText2.Text:=GetCurrentVersion;

  Randomize;
  FrameCount:=0;
  Camera:=GLCamera1;
  Form2:=TForm2.Create(Self);
  Form3:=TForm3.Create(Self);
  Form4:=TForm4.Create(Self);

  if colortest then
  for C1:=0 to 20 do begin
    npl:=NewPlayer(C1);
    npl.Position.SetPoint(C1*3-30,2,0);
  end;
  
  MyID:=0;
  if MyID>=Cardinal(Length(Players)) then setlength(Players,MyID+1);
  if MyID>=Cardinal(Length(playerarr)) then begin
    Setlength(playerarr,MyID+1);
    for C3:=0 to High(playerarr) do
    if not assigned(playerarr[C3]) then playerarr[C3]:=Form1.NewPlayer(C3);
  end;
  Players[MyID].Dead:=false;
  Players[MyID].jumping:=false;

  Players[MyID].X:=GLCamera1.Position.X;
  Players[MyID].Y:=GLCamera1.Position.Y;
  Players[MyID].Z:=GLCamera1.Position.Z;
  Players[MyID].CeilWalk:=false; 
  ChangeSpeedTo(StartSpeed);          

  ini:=TMyIni.Create(ExtractFilePath(ParamStr(0))+'Settings.ini');
  ROOMini:=TMyIni.Create(ExtractFilePath(ParamStr(0))+'Roomtypes.ini');
  ROOMini.ReadFloatDefault:=0;
  PanelIni:=TMyIni.Create(ExtractFilePath(ParamStr(0))+'PanelConfigs.ini');

  if not ini.SectionExists('Difficulty') then begin
    RewriteDifficulty;
  end else ReadDifficulty;
              
  if not ini.SectionExists('Multiplayer') then begin
    RewriteMPSet;
  end else ReadMPSet;

  if (not ini.SectionExists('Roomtypelist'))
  or (not FileExists(ExtractFilePath(ParamStr(0))+'Roomtypes.ini')) then
  RewriteRoomtypes;

  ReadRoomtypes;

  if not FileExists(ExtractFilePath(ParamStr(0))+'PanelConfigs.ini')
  then
  RewritePanelConfigs;

  ReadPanelConfigs;

  Setlength(PlaneArr,Length(Roomtypes));

  maxJumpHeight:=4-PlayerHeight[false];
  Form2.loadTextures;
  Form1.Icon.LoadFromFile('Wall.ico');
  MainMenu.Visible:=true;
  SettingsMenu.Visible:=false;
  VideoMenu.Visible:=false;
  MPMenu.Visible:=false;
  MPHostMenu.Visible:=false;
  MPJoinMenu.Visible:=false;
  inMenu:=true;
  if not inMenu then
  GLUserInterface1.MouseLookActivate
  else GLUserInterface1.MouseLookDeactivate;

  
  GLHUDText1.ModulateColor.SetColor(0/255,168/255,255/255);
  GLHUDText1.Visible:=true;
  ChangeSpeedTo(StartSpeed);
  GLHUDText1.Text:=
  'Speed: '+Floattostr(Round(100*Players[MyID].Speed)/100)+' m/s';
  Panel13.Left:=Round(Self.Width*0.05);
  Panel13.Width:=Round(Self.Width*0.9);
  Panel13.Top:=Round(Self.Height*0.1);
  Panel13.Height:=Round(Self.Height*0.8);
  Panel13.Font.Size:=300;
  
  PosX:=0;
  PosZ:=0;
  for C1:=-RaumRange to RaumRange+1 do
  for C3:=-RaumRange to RaumRange+1 do begin
    Wallarr[0,C1,C3]:=NewWall(20*C1-10,20*C3,1,20);
    Wallarr[1,C1,C3]:=NewWall(20*C1,20*C3-10,20,1);
    UpWallarr[0,C1,C3]:=NewUpWall(20*C1-10,20*C3,1,20);
    UpWallarr[1,C1,C3]:=NewUpWall(20*C1,20*C3-10,20,1);
    DownWallarr[0,C1,C3]:=NewDownWall(20*C1-10,20*C3,1,20);
    DownWallarr[1,C1,C3]:=NewDownWall(20*C1,20*C3-10,20,1);
  end;

  for C1:=-RaumRange to RaumRange do
  for C3:=-RaumRange to RaumRange do begin
    PlaneArr[0,Down,C1,C3]:=NewPlane(C1,C3,Down,0);
    PlaneArr[0,Up,C1,C3]:=NewPlane(C1,C3,Up,0);
  end;

  for C4:=1 to High(Roomtypes) do
  for C1:=-RaumRange to RaumRange do
  for C3:=-RaumRange to RaumRange do begin
    if Roomtypes[C4].MaterialName[Down]=Roomtypes[0].MaterialName[Down]
    then PlaneArr[C4,Down,C1,C3]:=PlaneArr[0,Down,C1,C3]
    else PlaneArr[C4,Down,C1,C3]:=NewPlane(C1,C3,Down,C4);
    if Roomtypes[C4].MaterialName[Up]=Roomtypes[0].MaterialName[Up]
    then PlaneArr[C4,Up,C1,C3]:=PlaneArr[0,Up,C1,C3]
    else PlaneArr[C4,Up,C1,C3]:=NewPlane(C1,C3,Up,C4);
  end;

  for C1:=-RaumRange to RaumRange do
  for C3:=-RaumRange to RaumRange do begin
    MuhNPCarr[C1,C3].Body:=NewMuhNPCBody(C1,C3);
    MuhNPCarr[C1,C3].MoveX:=(Random-0.5)*3;
    MuhNPCarr[C1,C3].MoveY:=(Random-0.5)*3;
    MuhNPCarr[C1,C3].MoveZ:=(Random-0.5)*3;
  end;

  GLSceneViewer1.FieldOfView:=150;

  GLSceneViewer1.Buffer.BackgroundColor:=RGB(66,66,66);

  Panel11.Left:=Panel9.Left;
  Panel11.Top:=Panel9.Top;
  RichEdit1.Left:=Panel9.Left;
  RichEdit1.Top:=Panel9.Top;

  if not ini.SectionExists('Proportions') then RewriteOrigSizes
  else ReadOrigSizes;

                 
  start:=GetTickCount;
  Repcount:=0;
  repeat
    Inc(Repcount);
    CreateMap;
    InitValidate;
    Validate(0,0,Down);
    if Application.Terminated then Exit;
    if GetTickCount>start+20000 then
    if MessageDlg(
    'The game is taking very a long time to create a winable map. '+#13+#10+
    'Try using "reini.bat" to reset the settings. Continue trying?',
    mtWarning, [mbYes, mbNo], 0) =mrNo then begin
      Application.Terminate;
      Break;
    end else start:=High(Cardinal)-20000;
  until valid[0,0,Down];
  if showMapCreateTime then
  MessageOut(
  'Map generated:'+#13+#10
  +IntToStr(GetTickCount-start)+' ms,'+#13+#10
  +IntToStr(Repcount)+' tries,'+#13+#10
  +FloatToStr((GetTickCount-start)/repcount)+' ms/try',
  'Map generated') else InformationDump:=Repcount;
    
  if Application.Terminated then Exit;
  Reload;


  SW:=TMyStopWatch.Create;
end;

procedure TForm1.CreateMap;
var C1,C3,C4,C5:Integer;
begin
  for C1:=-mapsize to mapsize do
  for C3:=-mapsize to mapsize do
  Map[C1,C3].created:=false;

  repeat
    GoalPos.x:=RandomRange(-MaxGoalDist-1,MaxGoalDist+1);
    GoalPos.y:=RandomRange(-MaxGoalDist-1,MaxGoalDist+1);
    

    if Application.Terminated then Exit;
    if GetTickCount>start+20000 then
    if MessageDlg(
    'The game is taking very a long time to create a winable map. '+#13+#10+
    'Try using "reini.bat" to reset the settings. Continue trying?',
    mtWarning, [mbYes, mbNo], 0) =mrNo then begin
      Application.Terminate;
      Break;
    end else start:=High(Cardinal)-20000;
  until (sqrt(sqr(GoalPos.X)+sqr(GoalPos.Y))>=MinGoalDist)
  and (sqrt(sqr(GoalPos.X)+sqr(GoalPos.Y))<=MaxGoalDist);

  PGoal:=nil;
  Creategoal;
  
  for C4:=-SpawnradiusNoWalls to SpawnradiusNoWalls do
  for C5:=-SpawnradiusNoWalls to SpawnradiusNoWalls do begin
    if sqrt(sqr(PosX-C4)+sqr(PosZ-C5))<SpawnradiusNoWalls then begin
      if not Map[C4,C5].created then CreateRaum(C4,C5);
      if not Map[C4-1,C5].created then CreateRaum(C4,C5);
      if not Map[C4,C5+1].created then CreateRaum(C4,C5);
      if not Map[C4,C5-1].created then CreateRaum(C4,C5);
      if not Map[C4+1,C5].created then CreateRaum(C4,C5);
      if not GetRT(C4,C5).Passierbar then
      Map[C4,C5].Inhalt.Sorte:=0;
      Map[C4,C5].Walls:=[];
      Map[C4+1,C5].Walls:=Map[C4+1,C5].Walls-[nx];
      Map[C4,C5+1].Walls:=Map[C4,C5+1].Walls-[nz];
      Map[C4,C5-1].Walls:=Map[C4,C5-1].Walls-[pz];
      Map[C4-1,C5].Walls:=Map[C4-1,C5].Walls-[px];
      Map[C4,C5].UpWalls:=[];
      Map[C4+1,C5].UpWalls:=Map[C4+1,C5].UpWalls-[nx];
      Map[C4,C5+1].UpWalls:=Map[C4,C5+1].UpWalls-[nz];
      Map[C4,C5-1].UpWalls:=Map[C4,C5-1].UpWalls-[pz];
      Map[C4-1,C5].UpWalls:=Map[C4-1,C5].UpWalls-[px];
      Map[C4,C5].DownWalls:=[];
      Map[C4+1,C5].DownWalls:=Map[C4+1,C5].DownWalls-[nx];
      Map[C4,C5+1].DownWalls:=Map[C4,C5+1].DownWalls-[nz];
      Map[C4,C5-1].DownWalls:=Map[C4,C5-1].DownWalls-[pz];
      Map[C4-1,C5].DownWalls:=Map[C4-1,C5].DownWalls-[px];
    end;
  end;

  for C4:=-SpawnradiusNoSorte to SpawnradiusNoSorte do
  for C5:=-SpawnradiusNoSorte to SpawnradiusNoSorte do
  if sqrt(sqr(PosX-C4)+sqr(PosZ-C5))<SpawnradiusNoSorte then begin
    if not Map[C4,C5].created then CreateRaum(C4,C5);
    if GetRT(C4,C5).NotAtSpawn then
    Map[C4,C5].Inhalt.Sorte:=0;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var C1,C2,C3:integer;
begin
  if assigned(LastFrameCounts) then
  FreeAndNil(LastFrameCounts);
  Freeandnil(ini);
  Freeandnil(ROOMini);
  Timer1.Enabled:=false;
  for C1:=-RaumRange to RaumRange do
  for C2:=-RaumRange to RaumRange do begin
    FreeAndNil(PlaneArr[0,Down,C1,C2]);
    FreeAndNil(PlaneArr[0,Up,C1,C2]);
  end;
  for C1:=-RaumRange to RaumRange do
  for C2:=-RaumRange to RaumRange do
  for C3:=0 to High(Roomtypes) do begin
    if Roomtypes[C3].MaterialName[Down]<>'Grass' then
    if Assigned(PlaneArr[C3,Down,C1,C2]) then
    FreeAndNil(PlaneArr[C3,Down,C1,C2]);
    if Roomtypes[C3].MaterialName[Up]<>'Ceiling' then
    if Assigned(PlaneArr[C3,Up,C1,C2]) then
    FreeAndNil(PlaneArr[C3,Up,C1,C2]);
  end;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
var vis:Boolean; C2:Char;
begin
  if Debug then
  if Key='v' then begin
    vis:=not Panel1.Visible;
    Panel1.Visible:=vis;
    Panel2.Visible:=vis;
    Panel3.Visible:=vis;
    Panel4.Visible:=vis;
    Panel5.Visible:=vis;
    Panel6.Visible:=vis;
  end;
  if Key='b' then begin
    Close;
  end;
  if Key='m' then begin  
    if self.Left=OrigSizes[0] then begin  
      Self.BorderStyle:=bsnone;
      Self.Left:=0;
      Self.Top:=0;
      Self.Width:=Screen.Width;
      Self.Height:=Screen.Height;
    end else begin
      Self.BorderStyle:=TFormBorderStyle(Round(OrigSizes[4]));
      Self.SetBounds(
      Round(OrigSizes[0]),
      Round(OrigSizes[1]),
      Round(OrigSizes[2]),
      Round(OrigSizes[3]));
    end;
  end;
  if Key='n' then begin
    ShellExecute(Handle, 'open','restart.bat',
    PChar(extractFileName(application.ExeName)), nil, SW_SHOWNORMAL);
    Close;        //parameter dateiname
  end;
  if (Key='p') or (Key=Char(27)) then begin
    inMenu:=not MainMenu.Visible;
    MainMenu.Visible:=inMenu;
    SettingsMenu.Visible:=false;
    VideoMenu.Visible:=false;
    MPMenu.Visible:=false;
    MPHostMenu.Visible:=false;
    MPJoinMenu.Visible:=false;
    if not inMenu then begin
      if players[MyId].CeilWalk then
      GLCamera1.Up.SetVector(0,-1,0)
      else
      GLCamera1.Up.SetVector(0,1,0);
      GLUserInterface1.MouseLookActivate;
    end else GLUserInterface1.MouseLookDeactivate;
  end;
  if Key='-' then begin
    inMenu:=not SettingsMenu.Visible;
    MainMenu.Visible:=false;
    SettingsMenu.Visible:=inMenu;
    VideoMenu.Visible:=false;
    MPMenu.Visible:=false;   
    MPHostMenu.Visible:=false;
    MPJoinMenu.Visible:=false;
    if not inMenu then begin
      if players[MyId].CeilWalk then
      GLCamera1.Up.SetVector(0,-1,0)
      else
      GLCamera1.Up.SetVector(0,1,0);
      GLUserInterface1.MouseLookActivate;
    end else GLUserInterface1.MouseLookDeactivate;
  end;
  if Key='w' then if inMenu then begin
    MainMenu.SelectPrev;
    SettingsMenu.SelectPrev;
    VideoMenu.SelectPrev;
    MPMenu.SelectPrev;
    MPHostMenu.SelectPrev;
    MPJoinMenu.SelectPrev;
  end;
  if Key='r' then begin
    if (MessageDlg('Do you really want to respawn?', mtConfirmation,
    [mbYes, mbNo], 0) = mrYes) then begin
      Respawn;
      while inMenu do begin
        C2:='p';
        FormKeyPress(Sender,C2);
      end;
    end;
  end;
  if Key='s' then if inMenu then begin
    MainMenu.SelectNext;
    SettingsMenu.SelectNext;
    VideoMenu.SelectNext;
    MPMenu.SelectNext;
    MPHostMenu.SelectNext;
    MPJoinMenu.SelectNext;
  end;
  if Key=Char(32) then begin       
    if not inMenu then begin
      StartJump(MyID);
      Form3.SendJump(MyID);
    end else GLSceneViewer1MouseDown(Sender,TMouseButton(3),[],
    Mouse.CursorPos.X,Mouse.CursorPos.Y);
    jumppressed:=true;
  end;
  Panel5.Caption:=IntToStr(Ord(Key))+'='+Key;
end;

procedure TForm1.StartJump(ID:Integer);
begin
  if jumppressed then Exit;
  if Lost then Exit;
  if players[ID].jumping then Exit;
  players[ID].jumptime:=0.00001;
  players[ID].jumping:=true;
end;
                      
procedure TForm1.FormResize(Sender: TObject);
begin
  RearrangePanels;
  Camera.SetFieldOfView(160,GLSceneviewer1.Width);
end;

procedure TForm1.GLSceneViewer1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  if not inMenu then Exit;
  
  if MainMenu.Visible then
  MenuSelect2(MainMenu,X,Y);

  if SettingsMenu.Visible then
  MenuSelect2(SettingsMenu,X,Y);

  if VideoMenu.Visible then
  MenuSelect2(VideoMenu,X,Y);

  if MPMenu.Visible then
  MenuSelect2(MPMenu,X,Y);

  if MPHostMenu.Visible then
  MenuSelect2(MPHostMenu,X,Y);

  if MPJoinMenu.Visible then
  MenuSelect2(MPJoinMenu,X,Y);
  
  if ThrustDrag then
  ThrustBarMouseDown(Sender,TMousebutton(mbLeft),Shift,X,Y);
end;

procedure TForm1.Respawn;
var C3:Integer;
begin
  if GameEnded then begin
    MessageOut('Game has already ended. Try "N" instead.','Respawn impossible');
    Exit;
  end;
  Lost:=false;
  Panel8.Visible:=false;
  Panel9.Visible:=false;
  ThrustBar.Position:=ThrustBar.Max;

  if Form3.ClientSocket.Active then begin
    Form3.RequestNewID(Form3.ClientSocket.Socket);
  end else begin   
    Players[MyID].Dead:=true;

    MyID:=High(Players)+1;
    Setlength(Players,MyID+1);
    Setlength(playerarr,MyID+1);
    for C3:=0 to High(playerarr) do
    if not assigned(playerarr[C3]) then playerarr[C3]:=Form1.NewPlayer(C3);

    Players[MyID].Dead:=false;


    ChangeSpeedTo(StartSpeed);

    Form1.GLHUDText1.Text:=
    'Speed: '+Floattostr(Round(100*Players[MyID].Speed)/100)+' m/s';
    Form1.GLCamera1.Up.SetVector(0,1,0);
    Form1.GLCamera1.Position.X:=0;
    Form1.GLCamera1.Position.Z:=0;
    Form1.GLNavigator1.VirtualUp.SetPoint(0,1,0);
    PosX:=0;
    PosZ:=0;
    Players[MyID].jumping:=false;
    Players[MyID].X:=0;
    Players[MyID].Y:=0;
    Players[MyID].Z:=0;
    Players[MyID].jumptime:=0.00001;
    Players[MyID].LastX:=0;
    Players[MyID].LastZ:=0;
    Players[MyID].Ceilwalk:=false;
    Form3.SendCeilWalk;
    Reload;
  end;
end;

procedure TForm1.GLSceneViewer1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin                          
  if not inMenu then Exit;
  MouseDownMenu(Sender,Button,Shift,X,Y);
end;

procedure TForm1.ThrustBarMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var m,b:real;
begin                       
  if not inMenu then Exit;
  ThrustDrag:=true;
  m:=-(ThrustBar.Max-ThrustBar.Min)/ThrustBar.Height;
  b:=ThrustBar.Max-m*ThrustBar.Top;
  ThrustBar.Position:=
  Round(m*ScreenToClient(Mouse.CursorPos).Y+b);
  if Round(m*Mouse.CursorPos.Y+b)>ThrustBar.Max then
  ThrustBar.Position:=ThrustBar.Max
  else if Round(m*Mouse.CursorPos.Y+b)<5 then  
  ThrustBar.Position:=5;
  Form4.UpdateSpeed;
end;

procedure TForm1.GLSceneViewer1MouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin                
  if not inMenu then Exit;
  ThrustDrag:=false;
end;

end.
