unit GameMap;

interface
uses SysUtils, DGLEngine_header, OpenGL, Variables, Classes, GameUtils, Windows;

type
TGameObject = record
Texture : Cardinal;
Angle : integer;
Model, Depth : Cardinal;
Col : TSingleRect;
end;
TMapHeader = record
CellsX_count,CellsY_count, bg_type : byte;
SurfaceCount, ObjCount, SObjCount, AirObjCount : cardinal;
CRC : string [5];
end;

var
m_Header  : TMapHeader;
CurCellX, CurCellY : integer;
Mouse3D : TGLVectord3;
m_GObjects : array of TGameObject;

procedure LoadMap(Name : string);
procedure FreeMap;
procedure DrawMapSurface;
procedure DrawGroundObj;
procedure DrawAirObj;
procedure ReadSpecialObj;

implementation
uses GameScenes, GameObjects;

type


TGameAirObject = record
Texture : Cardinal;
Angle, Z : integer;
Alpha : byte;
X, Y, Model, Width, Height, Depth : Cardinal;
end;

TGObjInfo = record
Obj_type,Texture : Cardinal;
Model : integer;
end;

TSurface = record
Gr_type,X,Y,A1,A2,A3,A4,A5,A6,A7,A8 : byte;
end;

TObject = record
Obj_type,Angle : Cardinal;
X,Y,Width,Height,Depth : byte;
end;

TAirObject = record
Obj_type,Angle : Cardinal;
ZLevel : integer;
X,Y,Width,Height,Depth,Alpha : byte;
end;

TSpecial_Obj = record
Sobj_type, X, Y : byte;
Param : string[20];
end;

var
m_Surface : array of TSurface;
m_Objects : array of TObject;
m_Specs   : array of TSpecial_Obj;
m_AirObj  : array of TAirObject;

tex_mainbg : cardinal;
GObj,AirObj, Surface_textures : array of TGObjInfo;

m_GAirObjects : array of TGameAirObject;

procedure DrawMapSurface;
 procedure FindCell;
 var i,j : integer;
 begin
  CurCellX:=-1;
  CurCellY:=-1;
   for i:=0 to m_Header.CellsX_count-1 do
     for j:=0 to m_Header.CellsY_count-1 do
      if  PointInRect(mouse3D[0],mouse3D[1],i,j,1,1) then
      begin
         CurCellX:=i;
         CurCellY:=j;
         Exit;
      end;
 end;
 function GetSurfaceTex(stype : byte):Cardinal;
var i : integer;
begin
result:=0;
for i:=0 to length(Surface_textures)-1 do
 if Surface_textures[i].Obj_type=stype then
  begin
  result:=Surface_textures[i].Texture;
  Exit;
  end;
end;
var i : integer;
begin
 //Первый слой
  SetTexture(tex_mainbg);
  glBegin(GL_QUADS);
    glNormal3f( 0.0, 0.0, 1.0);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(0.0, 0.0,0.0);
    glTexCoord2f(m_Header.CellsX_count div 2, 0.0);
    glVertex3f(m_Header.CellsX_count, 0.0,  0.0);
    glTexCoord2f(m_Header.CellsX_count div 2, m_Header.CellsY_count div 2);
    glVertex3f(m_Header.CellsX_count,  m_Header.CellsY_count,  0.0);
    glTexCoord2f(0.0, m_Header.CellsY_count div 2);
    glVertex3f(0.0,  m_Header.CellsY_count,  0.0);
  glEnd();
 //
  mouse3D := GetOpenGLPos(GetMousePos.X, GetMousePos.Y);
  FindCell;
 //Второй слой
 GlEnable(GL_BLEND);
 glEnable(GL_ALPHA_TEST);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 if m_Header.SurfaceCount<>0 then
 for i:=0 to m_Header.SurfaceCount-1 do
  begin
  glPushMatrix();
   SetTexture(GetSurfaceTex(m_Surface[i].Gr_type));
   glTranslatef(m_Surface[i].X+0.5,m_Surface[i].Y+0.5,0.015);
   glBegin(GL_QUADS);
   glNormal3f( 0.0, 0.0, 1.0);

   glcolor4ub(255,255,255,m_Surface[i].A1);
   glTexCoord2f(0.0, 1.0);
   glVertex2f(-0.5, -0.5);
   glcolor4ub(255,255,255,m_Surface[i].A2);
   glTexCoord2f(0.5, 1.0);
   glVertex2f(0.0, -0.5);
   glcolor4ub(255,255,255,255);
   glTexCoord2f(0.5, 0.5);
   glVertex2f(0.0, 0.0);
   glcolor4ub(255,255,255,m_Surface[i].A4);
   glTexCoord2f(0.0, 0.5);
   glVertex2f(-0.5, 0.0);

   glcolor4ub(255,255,255,m_Surface[i].A2);
   glTexCoord2f(0.5, 1.0);
   glVertex2f(0.0, -0.5);
   glcolor4ub(255,255,255,m_Surface[i].A3);
   glTexCoord2f(1.0, 1.0);
   glVertex2f(0.5, -0.5);
   glcolor4ub(255,255,255,m_Surface[i].A5);
   glTexCoord2f(1.0, 0.5);
   glVertex2f(0.5, 0.0);
   glcolor4ub(255,255,255,255);
   glTexCoord2f(0.5, 0.5);
   glVertex2f(0.0, 0.0);

   glcolor4ub(255,255,255,m_Surface[i].A4);
   glTexCoord2f(0.0, 0.5);
   glVertex2f(-0.5, 0.0);
   glcolor4ub(255,255,255,255);
   glTexCoord2f(0.5, 0.5);
   glVertex2f(0.0, 0.0);
   glcolor4ub(255,255,255,m_Surface[i].A7);
   glTexCoord2f(0.5, 0.0);
   glVertex2f(0.0, 0.5);
   glcolor4ub(255,255,255,m_Surface[i].A6);
   glTexCoord2f(0.0, 0.0);
   glVertex2f(-0.5, 0.5);

   glcolor4ub(255,255,255,255);
   glTexCoord2f(0.5, 0.5);
   glVertex2f(0.0, 0.0);
   glcolor4ub(255,255,255,m_Surface[i].A5);
   glTexCoord2f(1.0, 0.5);
   glVertex2f(0.5, 0.0);
   glcolor4ub(255,255,255,m_Surface[i].A8);
   glTexCoord2f(1.0, 0.0);
   glVertex2f(0.5, 0.5);
   glcolor4ub(255,255,255,m_Surface[i].A7);
   glTexCoord2f(0.5, 0.0);
   glVertex2f(0.0, 0.5);

   glcolor4ub(255,255,255,255);
   glEnd;
  glPopMatrix();
  end;
  GlDisable(GL_BLEND);
  glDisable(GL_ALPHA_TEST);
end;

procedure DrawGroundObj;
var i : integer;
begin
   //Объекты
 if length(m_GObjects)<>0 then
  for i:=0 to length(m_GObjects)-1 do
  begin
  glPushMatrix;
  glTranslatef(m_GObjects[i].Col.X+0.5*m_GObjects[i].Col.Width,
  m_GObjects[i].Col.Y+0.5*m_GObjects[i].Col.Height,0.49*m_GObjects[i].Depth);
  glScaleF(0.5,0.5,0.5);
  glScalef(m_GObjects[i].Col.Width,m_GObjects[i].Col.Height,m_GObjects[i].Depth);
  RotateZ(m_GObjects[i].Angle);
  SetTexture(m_GObjects[i].Texture);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
//    SetLight(30,-30,30);
    DrawModel(m_GObjects[i].Model,0,false);
   glDisable(GL_LIGHTING);
  glPopMatrix;
  end;
end;

procedure DrawAirObj;
var i : integer;
begin
  //Воздушные Объекты
 if length(m_GAirObjects)<>0 then
  for i:=0 to length(m_GAirObjects)-1 do
  begin
   glPushMatrix;
     if m_GAirObjects[i].Alpha<>255 then
     begin
     glEnable(GL_BLEND);
     glEnable(GL_ALPHA_TEST);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glColor4ub(255,255,255,m_GAirObjects[i].Alpha);
     end;
   glTranslatef(m_GAirObjects[i].X+0.5*m_GAirObjects[i].Width,m_GAirObjects[i].Y+0.5*m_GAirObjects[i].Height,m_GAirObjects[i].Z*0.25+0.49*m_GAirObjects[i].Depth);
   glScaleF(0.5,0.5,0.5);
   glScalef(m_GAirObjects[i].Width,m_GAirObjects[i].Height,m_GAirObjects[i].Depth);
   RotateZ(m_GAirObjects[i].Angle);
   SetTexture(m_GAirObjects[i].Texture);
   DrawModel(m_GAirObjects[i].Model,0,false);
   glColor4ub(255,255,255,255);
   glDisable(GL_ALPHA_TEST);
   glDisable(GL_BLEND);
  glPopMatrix;
  end;
end;

procedure FreeMap;
var i : integer;
begin
FreeTexture(tex_mainbg);
for i:=0 to length(Surface_textures)-1 do
 FreeTexture(Surface_textures[i].Texture);
for i:=0 to length(GObj)-1 do
 begin
 FreeTexture(GObj[i].Texture);
 FreeModel(GObj[i].Model);
 end;

for i:=0 to length(AirObj)-1 do
 begin
 FreeTexture(AirObj[i].Texture);
 FreeModel(AirObj[i].Model);
 end;

end;

procedure ReadSpecialObj;
var i : integer;
begin
for i:=0 to length(m_Specs)-1 do
case m_Specs[i].Sobj_type of
1:begin
if Player[0].Active=false then
begin
  Player[0].Active:=true;
  Player[0].X:=m_Specs[i].X;
  Player[0].Y:=m_Specs[i].Y;
end;
 end;
2:CreateMonster(m_Specs[i].X,m_Specs[i].Y);
end;//case

AddStringToConsole('Scripts compilation - done');
AddStringToConsole('Map loaded!');
end;

procedure BuildMap;
 type
 TtexandModel = record
 Model : integer;
 Tex : Cardinal;
 end;
 function getdraw(typ : cardinal) : TtexandModel;
 var i : integer;
 begin
  for i:=0 to length(GObj)-1 do
   if typ=GObj[i].Obj_type then
    begin
     result.Model:=GObj[i].Model;
     result.Tex:=GObj[i].Texture;
     Exit;
    end;
 end;
 function getdrawa(typ : cardinal) : TtexandModel;
 var i : integer;
 begin
  for i:=0 to length(AirObj)-1 do
   if typ=AirObj[i].Obj_type then
    begin
     result.Model:=AirObj[i].Model;
     result.Tex:=AirObj[i].Texture;
     Exit;
    end;
 end;
var i : integer;
begin
SetLength(m_GObjects,length(m_Objects));
 for i:=0 to length(m_Objects)-1 do
  begin
   m_GObjects[i].Texture:=getdraw(m_Objects[i].Obj_type).Tex;
   m_GObjects[i].Model:=getdraw(m_Objects[i].Obj_type).Model;
   m_GObjects[i].Angle:=m_Objects[i].Angle;
   m_GObjects[i].Depth:=m_Objects[i].Depth;
   m_GObjects[i].Col:=boundsS(m_Objects[i].X,m_Objects[i].Y,m_Objects[i].Width,m_Objects[i].Height);
  end;

SetLength(m_GAirObjects,length(m_AirObj));
 for i:=0 to length(m_AirObj)-1 do
  begin
   m_GAirObjects[i].Texture:=getdrawa(m_AirObj[i].Obj_type).Tex;
   m_GAirObjects[i].Model:=getdrawa(m_AirObj[i].Obj_type).Model;
   m_GAirObjects[i].Angle:=m_AirObj[i].Angle;
   m_GAirObjects[i].Z:=m_AirObj[i].ZLevel;
   m_GAirObjects[i].Alpha:=m_AirObj[i].Alpha;
   m_GAirObjects[i].X:=m_AirObj[i].X;
   m_GAirObjects[i].Y:=m_AirObj[i].Y;
   m_GAirObjects[i].Width:=m_AirObj[i].Width;
   m_GAirObjects[i].height:=m_AirObj[i].Height;
   m_GAirObjects[i].Depth:=m_AirObj[i].Depth;
  end;

 AddStringToConsole('Map build - done');

 ReadSpecialObj;
end;

procedure MapLoadTextures(bg : byte; objects,airobjects : array of Cardinal; Surf : array of byte; TexDetail : byte);
var S : TstringList; i : integer;
begin
try
S:=TstringList.Create;
S.LoadFromFile('Basic_surface.txt');
 LoadTextureFromPackage('..\Data\Textures.dpc',S.Strings[bg]+'.jpg',tex_mainbg,TexDetail);
S.LoadFromFile('Surface.txt');
if length(Surf)<>0 then
begin
 SetLength(Surface_textures,length(Surf));
  for i:=0 to length(Surf)-1 do
   begin
    Surface_textures[i].Obj_type:=Surf[i];
    LoadTextureFromPackage('..\Data\Textures.dpc',S.Strings[Surf[i]]+'.bmp',Surface_textures[i].Texture,TexDetail);
   end;
end else SetLength(Surface_textures,0);
S.LoadFromStream(LoadFromPackage('..\Data\Objects.dpc','Info_ground.txt'));
if length(objects)<>0 then
begin
  SetLength(GObj,length(objects));
   for i:=0 to length(objects)-1 do
    begin
     GObj[i].Obj_type:=objects[i];
     LoadTextureFromPackage('..\Data\Objects.dpc',S.Strings[objects[i]*2+1],GObj[i].Texture,TexDetail);
     ExtractFromPackage('..\Data\Objects.dpc',S.Strings[objects[i]*2],'Temp.dmd');
     GObj[i].Model:=LoadModel('Temp.dmd',2);
     DeleteFile('Temp.dmd');
    end;
end else SetLength(GObj,0);

S.LoadFromStream(LoadFromPackage('..\Data\Objects.dpc','Info_air.txt'));
if length(airobjects)<>0 then
begin
  SetLength(AirObj,length(airobjects));
   for i:=0 to length(airobjects)-1 do
    begin
     AirObj[i].Obj_type:=objects[i];
     LoadTextureFromPackage('..\Data\Objects.dpc',S.Strings[objects[i]*2+1],AirObj[i].Texture,TexDetail);
     ExtractFromPackage('..\Data\Objects.dpc',S.Strings[airobjects[i]*2],'Temp.dmd');
     AirObj[i].Model:=LoadModel('Temp.dmd',2);
     DeleteFile('Temp.dmd');
    end;
end else SetLength(AirObj,0);
S.Free;
AddStringToConsole('Loading map graphics - done');
BuildMap;
except
 AddStringToConsole('Some errors were arised while loading map graphics!');
 InitType:=MENU_START;
 StartScene(gsInit);
end;
end;

procedure BuildLoadLists;
 function DataExistsInArray(Data : Cardinal; ar : array of Cardinal):boolean;
 var i : integer;
 begin
 if length(ar)<>0 then
 for i:=0 to length(ar)-1 do
  if ar[i]=data then
   begin
   result:=true;
   Exit;
   end;
  result:=false;
 end;
 function DataExistsInArrayB(Data : Cardinal; ar : array of byte):boolean;
 var i : integer;
 begin
 if length(ar)<>0 then
 for i:=0 to length(ar)-1 do
  if ar[i]=data then
   begin
   result:=true;
   Exit;
   end;
  result:=false;
 end;
var Obj,AObj : array of Cardinal; Surf : array of byte;
i : integer;
begin
SetLength(Obj,0); SetLength(AObj,0); SetLength(Surf,0);
if length(m_Objects)<>0 then
  for i:=0 to length(m_Objects)-1 do
   if not DataExistsInArray(m_Objects[i].Obj_type,Obj) then
    begin
     SetLength(Obj,Length(Obj)+1);
     Obj[Length(Obj)-1]:=m_Objects[i].Obj_type;
    end;
if length(m_AirObj)<>0 then
  for i:=0 to length(m_AirObj)-1 do
   if not DataExistsInArray(m_AirObj[i].Obj_type,AObj) then
    begin
     SetLength(AObj,Length(AObj)+1);
     AObj[Length(AObj)-1]:=m_AirObj[i].Obj_type;
    end;
if length(m_Surface)<>0 then
  for i:=0 to length(m_Surface)-1 do
   if not DataExistsInArrayB(m_Surface[i].Gr_type,Surf) then
    begin
     SetLength(Surf,Length(Surf)+1);
     Surf[Length(Surf)-1]:=m_Surface[i].Gr_type;
    end;
AddStringToConsole('Building map graphics load lists - done');
 MapLoadTextures(m_Header.bg_type,Obj,AObj,Surf,TexDetail);
 SetLength(Obj,0);
 SetLength(AObj,0);
 SetLength(Surf,0);
end;

procedure LoadMap(Name : string);
var F : file;
begin
 if fileexists(name) then
 begin
 AddStringToConsole('Loading map: "'+Name+'"...');
 AssignFile(F,Name);
 Reset(F,1);
 AddStringToConsole('Map file opened...');
 BlockRead(F, m_Header, sizeof(TMapHeader));
 if m_Header.CRC[2]<>'1' then
  begin
  AddStringtoConsole('Incorrect map version!');
  CloseFile(F);
  InitType:=MENU_START;
  StartScene(gsInit);
  Exit;
  end;
 SetLength(m_Surface,m_Header.SurfaceCount);
 SetLength(m_Objects,m_Header.ObjCount);
 SetLength(m_Specs,m_Header.SObjCount);
 SetLength(m_AirObj,m_Header.AirObjCount);

 BlockRead(F, m_Surface[0], m_Header.SurfaceCount*sizeof(TSurface));
 BlockRead(F, m_Objects[0], m_Header.ObjCount*sizeof(TObject));
 BlockRead(F, m_Specs[0], m_Header.SObjCount*sizeof(TSpecial_Obj));
 BlockRead(F, m_AirObj[0], m_Header.AirObjCount*sizeof(TAirObject));

 CloseFile(F);
 AddStringToConsole('Reading map data - done');
 BuildLoadLists;
 end else
 begin
 AddStringToConsole('Map "'+Name+'" not found!');
 InitType:=MENU_START;
 StartScene(gsInit);
 end;
end;

end.
