
{
 Nomenklatura:
  object: istniejący, naniesiony objekt
  item:   objekt z listy możliwych rzeczy
}

unit MainForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ImgList, ComCtrls, ToolWin, Grids, ValEdit, ExtCtrls, IniFIles,
  Menus, StdCtrls, Math;

type
  TMainFrm = class(TForm)
    ToolBar1: TToolBar;
    NewFileBtn: TToolButton;
    ImageList1: TImageList;
    SaveFileBtn: TToolButton;
    ObjSelectRd: TToolButton;
    ObjAddRd: TToolButton;
    ObjDelRd: TToolButton;
    ToolButton7: TToolButton;
    Splitter1: TSplitter;
    Panel1: TPanel;
    ItemPreview: TImage;
    ItemSelector: TTreeView;
    Splitter2: TSplitter;
    RefreshBtn: TToolButton;
    ToolButton9: TToolButton;
    ObjectProperties: TStringGrid;
    ScrollBox1: TScrollBox;
    DrawBox: TImage;
    InfoBar: TStatusBar;
    MainMenu1: TMainMenu;
    Plik1: TMenuItem;
    Edycja1: TMenuItem;
    Widok1: TMenuItem;
    Nowy1: TMenuItem;
    Otwrz1: TMenuItem;
    Zapisz1: TMenuItem;
    Zapiszjako1: TMenuItem;
    N1: TMenuItem;
    DoGameEditora1: TMenuItem;
    N2: TMenuItem;
    Zakocz1: TMenuItem;
    Dziaanie1: TMenuItem;
    Wybr1: TMenuItem;
    Dodawanie1: TMenuItem;
    Usuwanie1: TMenuItem;
    N3: TMenuItem;
    Cofnij1: TMenuItem;
    Ponw1: TMenuItem;
    Odswie1: TMenuItem;
    Powikszenie1: TMenuItem;
    Zwiksz1: TMenuItem;
    Zmniejsz1: TMenuItem;
    Ustaw1: TMenuItem;
    FileOpen: TOpenDialog;
    FileSave: TSaveDialog;
    OpenFileBtn: TToolButton;
    Eksportujdoplikugry1: TMenuItem;
    PropPopup: TPopupMenu;
    Nowawaciwo1: TMenuItem;
    Usuzaznwaciwo1: TMenuItem;
    procedure RefreshBtnClick(Sender: TObject);
    procedure ItemSelectorChange(Sender: TObject; Node: TTreeNode);
    procedure ObjectPropertiesSetEditText(Sender: TObject; ACol,
      ARow: Integer; const Value: String);
    procedure DrawBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure RefreshObjectInfo;
    procedure UpdateMap;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Ustaw1Click(Sender: TObject);
    procedure Odswie1Click(Sender: TObject);
    procedure Zwiksz1Click(Sender: TObject);
    procedure Zmniejsz1Click(Sender: TObject);
    procedure OpenFileBtnClick(Sender: TObject);
    procedure UpdateSize;
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure ShowPleaseWait(text:string; cl:TColor);
    procedure HidePleaseWait;
    procedure Eksportujdoplikugry1Click(Sender: TObject);
    procedure Nowawaciwo1Click(Sender: TObject);
    procedure Usuzaznwaciwo1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrm: TMainFrm;
  tf:TIniFile;
  TotalObjects:word=0;
  SelectedObject:word;
  PxPerMetre:real=1;
  ClickTolerance:byte;
  Map:TCanvas;
  VzX:real=500;
  VzY:real=500;
  PWText:string;

implementation

uses ZoneViewForm, OutputForm;

procedure TMainFrm.ShowPleaseWait(text:string; cl:TColor);
begin
 InfoBar.Color := cl;
 InfoBar.Panels[2].Text := 'Proszę zaczekaj...';
 InfoBar.Panels[3].Bevel := pbRaised;
 InfoBar.Panels[3].Text := text;
 PWText := text;
 Application.ProcessMessages;
end;

procedure TMainFrm.HidePleaseWait;
begin
 InfoBar.Panels[2].Text := 'Zaznaczony objekt:';
 InfoBar.Panels[3].Bevel := pbLowered;
 if InfoBar.Panels[3].Text=PWText then
  InfoBar.Panels[3].Text := '---';
 InfoBar.Color := clBtnFace;
end;

function MetresToPx(Metre:real):Integer; overload;
var ts: LongWord;
begin
 Result := Round(Metre * PxPerMetre);
end;

function PxToMetres(Pixels:Integer):real; overload;
begin
 Result := (Pixels / PxPerMetre);
end;

function PxToMetres(Pixels:Integer; VZ:real):real; overload;
begin
 Result := (Pixels / PxPerMetre) + (VZ - PxToMetres(500));
end;
{
function PxToRoundMetres(Pixels:Integer):Integer;
begin
 Result := Round(Pixels / PxPerMetre);
end;
 }
function MetresToPx(Metre:real; VZ:real):Integer; overload;
var ts: LongWord;
begin
 Result := Round((Metre-(VZ-PxToMetres(500))) * PxPerMetre);
end;

function CompareWithTolerance(param1, param2, tolerance: real):bool;
var dif:real;
begin
 dif := param1-param2;
 if dif<0 then dif := -dif;
 if (dif<=tolerance) then Result := true else Result := false;
end;

procedure WriteProperty(name, value:string); overload;
begin
 tf.WriteString('obj_'+IntToStr(SelectedObject), name, value);
end;

procedure WriteProperty(name, value:string; ObjectId:word); overload;
begin
 tf.WriteString('obj_'+IntToStr(ObjectId), name, value);
end;


function ReadProperty(name:string; default:string=''):string; overload;
begin
 Result := tf.ReadString('obj_'+IntToStr(SelectedObject), name, default);
end;

function ReadProperty(name:string; default:string; const ObjectId:word):string; overload;
begin
 Result := tf.ReadString('obj_'+IntToStr(ObjectId), name, default);
end;

procedure Circle(Canvas:TCanvas; X, Y, R:integer);
begin
 Canvas.Ellipse(X-R, Y-R, X+R, Y+R);
end;

{$R *.dfm}

procedure TMainFrm.RefreshObjectInfo;
var i:word; f:TIniFile; oname:string; s:TStringList;
begin
 oname := tf.ReadString('obj_'+IntToStr(SelectedObject), 'type', 'null');
 if (oname='null') then begin
  ObjectProperties.Enabled := false;
  exit;
 end;
 ObjectProperties.Enabled := true;
 f := TIniFile.Create('.\data\items_dat\'+oname+'.ini');
 InfoBar.Panels.Items[3].Text := f.ReadString('Info', 'IName', 'Brak wpisu nazwy!');
 f.Free;
 if FileExists('.\data\items_img\'+oname+'.bmp') then
  ItemPreview.Picture.LoadFromFile('.\data\items_img\'+oname+'.bmp')
 else
  ItemPreview.Picture.LoadFromFile('.\data\items_img\noimg.bmp');
 s := TStringList.Create;
 tf.ReadSection('obj_'+IntToStr(SelectedObject), s);
 if s.Count < 1 then begin
  s.Free;
  exit;
 end;
 for i := 1 to ObjectProperties.RowCount-1 do ObjectProperties.Rows[i].Clear;
 ObjectProperties.RowCount := s.Count+1;
 for i := 0 to s.Count-1 do begin
  ObjectProperties.Cells[0,i+1] := s[i];
  ObjectProperties.Cells[1,i+1] :=
   tf.ReadString('obj_'+IntToStr(SelectedObject), s[i], '');
 end;
 s.Free;
end;

procedure TMainFrm.UpdateSize;
var mr,x1,y1,x2,y2:integer;
begin
 InfoBar.Panels.Items[1].Text := FloatToStrF(PxPerMetre, ffGeneral,5,2)+' px/m';
 {DrawBox.Width := MetresToPx(1000);
 DrawBox.Height := MetresToPx(1000);
 DrawBox.Picture.Bitmap.Width := DrawBox.Width;
 DrawBox.Picture.Bitmap.Height := DrawBox.Height;}

 if PxPerMetre=1 then begin
  VzX := 500;
  VzY := 500;
 end;
 mr := Round((PxToMetres(1000)/10)/2);
 x1 := Round(VzX/10)-mr;
 y1 := Round(VzY/10)-mr;
 x2 := Round(VzX/10)+mr;
 y2 := Round(VzY/10)+mr;
 with ViewZoneFrm.ZoneView.Canvas do begin
  Pen.Color := clWhite;
  Brush.Color := clWhite;
  Rectangle(ClientRect);
  Pen.Color := clMaroon;
  Brush.Color := clRed;
  Rectangle(x1,y1,x2,y2);
 end;
end;

procedure TMainFrm.UpdateMap;
var f:TIniFile;
    c,fc:TColor; oname,t:string;
    i:word;
    b,bg:TPicture;
    ScaleClass:string;
    size:real;
    MapRange:real;
    mr:integer;
begin
 ShowPleaseWait('Odswieżanie mapy', clRed);
 bg := TPicture.Create;
 bg.LoadFromFile(tf.ReadString('Info', 'MapFile', '.\defmap.bmp'));
 DrawBox.Canvas.StretchDraw(DrawBox.ClientRect, bg.Graphic);
 bg.Free;
 b := TPicture.Create;
 for i := 1 to tf.ReadInteger('Info', 'ObjectsCount', 1) do begin
  oname := ReadProperty('type', 'null', i);
  if ReadProperty('type', 'null', i)='null' then continue;
  f := TIniFile.Create('.\data\items_dat\'+oname+'.ini');
  t := f.ReadString('Info', 'ItemType', '');
  size := StrToFloat(f.ReadString('Info', 'ItemSize', '1'));
  {if PxPerMetre>9 then b.LoadFromFile('.\data\map_img\'+oname+'.bmp') else begin}
   if t='build' then c := clYellow else
   if t='bot' then c := clBlue else
   if t='alien' then c := clLime else
   if t='portable' then c := clRed else
   if t='decor' then c := clFuchsia else continue;
{  end;}
  DrawBox.Canvas.Pen.Color := c;
  Circle(DrawBox.Canvas,
   MetresToPx(StrToFloat(ReadProperty('_pos_x','0',i)),VzX),
   MetresToPx(StrToFloat(ReadProperty('_pos_y','0',i)),VzY),
   MetresToPx(size));
 end;
 b.Free;
 HidePleaseWait;
end;

procedure TMainFrm.RefreshBtnClick(Sender: TObject);

begin
 UpdateMap;
end;

procedure TMainFrm.ItemSelectorChange(Sender: TObject; Node: TTreeNode);
var f:TIniFile; oname,pname:string; s:TStrings; i:byte;
begin
 f := TIniFile.Create('.\data\names.ini');
 oname := f.ReadString('ONames', Node.Text, 'nothing');
 f.Free;
 if FileExists('.\data\items_img\'+oname+'.bmp') then
  ItemPreview.Picture.LoadFromFile('.\data\items_img\'+oname+'.bmp')
 else
  ItemPreview.Picture.LoadFromFile('.\data\items_img\noimg.bmp');
 f := TIniFile.Create('.\data\items_dat\'+oname+'.ini');
 i := 0;
 while (f.ValueExists('ParamNames', 'param'+IntToStr(i))) do begin
  pname := f.ReadString('ParamNames', 'param'+IntToStr(i), '');
  ObjectProperties.Cells[0,i] := pname;
  ObjectProperties.Cells[1,i] :=
   tf.ReadString('obj_'+IntToStr(SelectedObject), pname, '');
  Inc(i);
 end;
 f.Free;
end;

procedure TMainFrm.ObjectPropertiesSetEditText(Sender: TObject; ACol,
  ARow: Integer; const Value: String);
begin
 tf.WriteString('obj_'+IntToStr(SelectedObject),
     ObjectProperties.Cells[0, ARow], ObjectProperties.Cells[1, ARow]);
 if (ObjectProperties.Cells[0, ARow]='_pos_x') or
    (ObjectProperties.Cells[0, ARow]='_pos_y') then
  tf.WriteString('obj_'+IntToStr(SelectedObject), 'pos',
       tf.ReadString('obj_'+IntToStr(SelectedObject), '_pos_x', '0')+';'+
       tf.ReadString('obj_'+IntToStr(SelectedObject), '_pos_x', '0'));

end;

procedure TMainFrm.DrawBoxMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var oname, pname:string;
 i:word; f:TIniFile; s:TStringList; dist:real;
 mindist:real; mdistobj:word; // najmniejsza długość, najmniejszej długości index
begin
 {x := x+VisibleZoneX;
 y := y+VisibleZoneY;}
 // Jesli dodawanie itemu:
 ShowPleaseWait('Odczyt / zapis objektu', clLime);
 if ObjAddRd.Down then begin
  // Pozyskaj nazwę wewnętrzną
  f := TIniFile.Create('.\data\names.ini');
  oname := f.ReadString('ONames', ItemSelector.Selected.Text, 'nothing');
  f.Free;

  f := TIniFile.Create('.\data\items_dat\'+oname+'.ini');
  Inc(TotalObjects);
  SelectedObject := TotalObjects;
  tf.WriteInteger('Info', 'ObjectsCount', TotalObjects);

  // DODAWANIE PARAMETRÓW "UNIWERSALNYCH" ///////////////////////////////////
  WriteProperty('type', oname);
  WriteProperty('pos',
   FloatToStrF(PxToMetres(X), ffFixed,5,2)+';'+
   FloatToStrF(PxToMetres(Y), ffFixed,5,2));
  WriteProperty('_pos_x', FloatToStrF(PxToMetres(X,VzX), ffGeneral,5,2));
  WriteProperty('_pos_y', FloatToStrF(PxToMetres(Y,VzY), ffGeneral,5,2));
  //////////////////////////////////////////////////////////////////////////
  tf.WriteInteger('Info', 'ObjectsCount', TotalObjects); // I zaktualizuj ilosc
  // Przepisywanie parametrów
  s := TStringList.Create;
  f.ReadSection('Params', s);
  if s.Count>0 then
   for i := 0 to s.Count-1 do WriteProperty(s[i], f.ReadString('Params', s[i], ''));
  s.Free;
  f.Free;
  RefreshObjectInfo;
  RefreshBtnClick(Sender);
 end;

 // Jesli zaznaczenie lub usunięcie ...
 if ObjSelectRd.Down or ObjDelRd.Down then begin
  // ... trzeba najpierw sprawdzic co to
  mindist := 10000;
  for i := 1 to tf.ReadInteger('Info', 'ObjectsCount', 1) do begin
   // Jesli usunięty lub nie ma, pomiń
   if tf.ReadString('obj_'+IntToStr(i), 'type', 'null')='null' then continue;
   // Porównaj (Pitagoras twierdzi, że jak się pierdzi, to śmierdzi)
   dist := Sqrt(Power(StrToFloat(ReadProperty('_pos_x','0',i))-PxToMetres(X,VzX),2)+
    Power(StrToFloat(ReadProperty('_pos_y','0',i))-PxToMetres(Y,VzY),2));
   if dist<mindist then begin
    mindist := dist;
    mdistobj := i;
   end;
   SelectedObject := mdistobj;
   RefreshObjectInfo;
  end;
 end;
 if ObjDelRd.Down then begin
  tf.WriteString('obj_'+IntToStr(SelectedObject), 'type', 'null');
  UpdateMap;
 end;
 HidePleaseWait;
end;

procedure TMainFrm.FormCreate(Sender: TObject);
begin
 ItemSelector.LoadFromFile('.\data\list.txt');
 tf := TIniFile.Create('.\example.ini');
 TotalObjects := tf.ReadInteger('Info', 'ObjectsCount', 0);
 {Map := TCanvas.Create;
 Map.Unlock;}
 ObjectProperties.Cells[0,0] := 'Nazwa';
 ObjectProperties.Cells[1,0] := 'Wartość';
end;

procedure TMainFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 tf.Free;
end;

procedure TMainFrm.Ustaw1Click(Sender: TObject);
var s:string;
begin
 s := FloatToStrF(PxPerMetre, ffGeneral,5,2);
 try
  if InputQuery('Ustawianie powiększenia', 'Wprowadź powiększenie (px/m):', s)
   then PxPerMetre := StrToFloat(s);
 except
  MessageBox(0, 'Błędna wartosc powiększenia.', 'Błąd!', MB_ICONERROR);
 end;
 UpdateSize;
 UpdateMap;
end;

procedure TMainFrm.Odswie1Click(Sender: TObject);
begin
 UpdateMap;
end;

procedure TMainFrm.Zwiksz1Click(Sender: TObject);
begin
 ViewZoneFrm.SpeedButton5.Click;
end;

procedure TMainFrm.Zmniejsz1Click(Sender: TObject);
begin
 ViewZoneFrm.SpeedButton6.Click;
end;

procedure TMainFrm.OpenFileBtnClick(Sender: TObject);
begin
 if FileOpen.Execute then begin
  CopyFile(PChar(FileOpen.FileName), '.\tmp\edt00.ini', false);
  tf.Create('.\tmp\edt00.ini');
 end;
end;

procedure TMainFrm.FormKeyPress(Sender: TObject; var Key: Char);
begin    {
 if Ord(Key)=VK_LEFT then Dec(VisibleZoneX);
 if Ord(Key)=VK_RIGHT then Inc(VisibleZoneX);
 if Ord(Key)=VK_Up then Dec(VisibleZoneY);
 if Ord(Key)=Vk_Down then Inc(VisibleZoneY);}
end;

procedure TMainFrm.Eksportujdoplikugry1Click(Sender: TObject);
var i,j:word; sl:TStringList; s:string;
begin
 OutputFrm.CodeMemo.Lines.Clear;
 for i := 1 to TotalObjects do begin
  s := 'CreateObject ';
  sl := TStringList.Create;
  tf.ReadSection('obj_'+IntToStr(i), sl);
  for j := 0 to sl.Count-1 do s := s+sl[j]+'='+tf.ReadString('obj_'+IntToStr(i), sl[j],'')+' ';
  OutputFrm.CodeMemo.Lines.Add(s);
  OutputFrm.Show;
 end;
end;

procedure TMainFrm.Nowawaciwo1Click(Sender: TObject);
begin
 ObjectProperties.RowCount := ObjectProperties.RowCount+1;
end;

procedure TMainFrm.Usuzaznwaciwo1Click(Sender: TObject);
var i:byte;
begin
 for i := ObjectProperties.Row to ObjectProperties.RowCount-1 do
  ObjectProperties.Rows[i] := ObjectProperties.Rows[i+1];
 ObjectProperties.RowCount := ObjectProperties.RowCount-1;
end;

end.

