unit yatc_score;
{YATC - Unit Global
Autor : Tobias Mark aka Colenzo (tobiasmark@gmx.de)

Global verwendte Definitionen
                   
Version
0.1 - 12.9 : - erste version speichern und laden
0.2 - 18.9 : - anti debug_cheating der highscore eingebaut

Hinweis : Die Datensätze werd ein der anzeige und speicherung nach modi getrennt
intern allerdings in einer liste gehandelt, das ist absichtlich um den Code
intressanter für mich zu machen ;)
}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Grids, yatc_global,JclSecurity, JvSimpleXml;

type Thighscore = class (Tobject)    //Datenzsatzm, name bleibt in Stringliste
                     mode : Rgamemode;
                     punkte : integer;
                     feld : string;
                     script : string;
                     date : string;
                   end;
                   
type
  Tscore_form = class(TForm)
    esay_panel: TPanel;
    medium_panel: TPanel;
    hard_panel: TPanel;
    menu_panel: TPanel;
    ok_button: TButton;
    esay_table: TStringGrid;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    tabel_head: TPanel;
    head_table: TStringGrid;
    medium_table: TStringGrid;
    hard_table: TStringGrid;
    clear_button: TButton;
    procedure ok_buttonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure clear_buttonClick(Sender: TObject);
  private
    data_list : Tstringlist;   //liste der Einträge
    lastname : string; //letzer vewendeter name;
    procedure sort_trunc_list; //Sortiert liste und schneidet auf 5 einträge ab
    procedure add_entry(mode : Rgamemode;punkte : integer;feld,script,name,date : string);//fügt eintrag hinzu
    procedure update_list;//aktualisiert anzeige
  public
    cheat : boolean;   //Überprüfung ob eine der Debug möglichkeiten genutzt wurde
    procedure add(mode : Rgamemode;punkte,feldx,feldy : integer;script : string); overload;//erstellt neuen eintrag, fragt nach name
    procedure add(mode : Rgamemode;punkte,feldx,feldy : integer;script : string;name : string); overload; //zur vorgabe eine standard namens
  end;

var
  score_form: Tscore_form;

implementation

{$R *.dfm}

function sort_list(List: TStringList; Index1, Index2: Integer): Integer;
//Callback funktion zum Sortieren der Liste

begin
  if Thighscore(list.objects[index1]).punkte = Thighscore(list.objects[index2]).punkte
  then result := 0
  else
    if Thighscore(list.objects[index1]).punkte < Thighscore(list.objects[index2]).punkte
    then result := 1
    else result := -1;
end;

procedure Tscore_form.ok_buttonClick(Sender: TObject);

begin
  score_form.Visible := false;   //Schließen
end;

procedure Tscore_form.FormCreate(Sender: TObject);

var table_selection : Tgridrect; //hilfsvar um das selektions fenster aus dem sichtbaren bereich zu schieben
    node1,node2 : TJvSimpleXMLElem;  //help zum durchhangel durch Struktur
    i : integer;      //zähler
    j : Rgamemode; //zähler
    name,feld,script,date : string;  //geladenen daten
    punkte : integer;
    xml_file : TJvSimpleXml;   //XML System

begin
  cheat := false;
  data_list := tstringlist.create;  //init
  lastname := '';
  with head_table do
  begin      //einstellen der spalten überschrift
    cells[1,0] := 'Name';
    cells[2,0] := 'Punkte';
    cells[3,0] := 'Feld';
    cells[4,0] := 'Modus';
    cells[5,0] := 'Datum';
    table_selection.Left := 1;
    table_selection.Right := 1;
    table_selection.Top := 1;
    table_selection.Bottom := 1;
    selection := table_selection;
    colwidths[0] := 20;
    colwidths[1] := 120;
    colwidths[2] := 50;
    colwidths[3] := 50;
    colwidths[4] := 90;
    colwidths[5] := 500;
  end;
  table_selection.Left := 6;
  table_selection.Right := 6;
  table_selection.Top := 0;
  table_selection.Bottom := 0;
  with esay_table do
  begin   // Einstellen der 3 Tabellen
    selection := table_selection;
    colwidths[0] := 20;
    colwidths[1] := 120;
    colwidths[2] := 50;
    colwidths[3] := 50;
    colwidths[4] := 90;
    colwidths[5] := 500;
  end;
  with medium_table do
  begin
    selection := table_selection;
    colwidths[0] := 20;
    colwidths[1] := 120;
    colwidths[2] := 50;
    colwidths[3] := 50;
    colwidths[4] := 90;
    colwidths[5] := 500;
  end;
  with hard_table do
  begin
    selection := table_selection;
    colwidths[0] := 20;
    colwidths[1] := 120;
    colwidths[2] := 50;
    colwidths[3] := 50;
    colwidths[4] := 90;
    colwidths[5] := 500;
  end;
  //********* Laden der Highscore daten
  xml_file  := Tjvsimplexml.create(self); //Xml dokument erstellen
  xml_file.options := [sxoAutoCreate]; //autocreate für notfälle um fehler zu vermeiden bei zugriff auf nicht existierendes
  try
    xml_file.LoadFromFile(highscore_file);    //laden aus datei
    node1 := xml_file.Root;
    if xml_file.Root.Name = 'Highscore' then //richtig datei?
    begin
      for j := desay to dhard do //über alle 3 Hauptzweigen
      begin
        case j of       //Hauptzweig hohlen
          desay : node1 :=xml_file.root.items.itemnamed['esay'];
          dmedium : node1 :=xml_file.root.items.itemnamed['medium'];
          dhard : node1 :=xml_file.root.items.itemnamed['hard'];
        end;
        if node1.Items.Count > 0 then //falls leere datei dann nicht
        for i := 0 to node1.Items.Count -1 do
        begin      //über alle einträge
          node2 := node1.Items[i];     //Daten holen
          punkte := strtoint(node2.items.itemnamed['punkte'].value);
          feld := node2.items.itemnamed['feld'].value;
          script := node2.items.itemnamed['script'].value;
          name := node2.items.itemnamed['name'].value;
          date := node2.Items.ItemNamed['date'].Value;
          add_entry(j,punkte,feld,script,name,date);   //der liste hinzufügen
        end;
      end;
      update_list;   //anzeige aktualisieren
    end;
  except
    Showmessage('Fehler beim Laden der Highscore Daten!');
  end;  
  xml_file.free;   //xml dokument freigeben
end;

procedure Tscore_form.add_entry(mode : Rgamemode;punkte : integer;feld,script,name,date : string);
//Fügt eintrag hinzu

var help : Thighscore;

begin
  help := Thighscore.Create;     //datensatz erstellen
  help.mode := mode;
  help.punkte := punkte;
  help.feld := feld;
  help.script := script;
  help.date := date;
  data_list.addobject(name,help);   //zu liste hinzufügen
end;

procedure Tscore_form.sort_trunc_list;
//Sortiert und Kürzt

var i : byte;
    esay,medium,hard : byte;
    nothing : boolean;

begin
  data_list.customsort(@sort_list);//Sortieren mit Callback funktion
  repeat     //Wiederholen solange bis kein Eintrag mehr gelöscht wurde
    esay := 0;   //init
    medium := 0;
    hard := 0;
    nothing := true;
    if data_list.Count > 0 then //Zur sicherheit falls keien einträge
    for i := 0 to data_list.count -1 do //schleife durch liste
    begin
      case Thighscore(data_list.objects[i]).mode of
        desay : begin          //Kürzen auf 5 pro Modus
                  inc(esay);
                  if esay > 5 then //ab dem 5ten item alle löschen
                  begin
                    data_list.delete(i); //löschen
                    nothing := false;    //etwas gelöscht
                    break;        //in die nächste runde gehen
                  end;
                end;
        dmedium :begin
                  inc(medium);
                  if medium > 5 then
                  begin
                    data_list.delete(i);
                    nothing := false;
                    break;
                  end;
                end;
        dhard : begin
                  inc(hard);
                  if hard > 5 then
                  begin
                    data_list.delete(i);
                    nothing := false;
                    break;
                  end;
                end;
      end;
    end;
  until nothing = true;
end;

procedure Tscore_form.update_list;
//Aktuallisiert die Anzeige

var i : byte;     //for zähler
    table : Tstringgrid;  //verwendete tabelle
    esay,hard,medium : byte;     //zähler für einträge
    pos : byte; //verwendte positon

begin
  esay := 0; //init
  hard := 0;
  medium := 0;
  pos := 0;
  if data_list.Count > 0 then //Zur sicherheit falls keien einträge
  for i := 0 to data_list.count -1 do //schleife durch liste
  begin
    table := esay_table; //um ganz sicher zu gehen
    case Thighscore(data_list.objects[i]).mode of //auswahl der spezielle Tabelle
      desay : begin
                table := esay_table;
                pos := esay;
                inc(esay);
              end;
      dmedium : begin
                  table := medium_table;
                  pos := medium;
                  inc(medium);
                end;
      dhard :  begin
                 table := hard_table;
                 pos := hard;
                 inc(hard);
               end;
    end;
    //daten eintragen
    table.cells[1,pos] := data_list.strings[i];
    table.cells[2,pos] := inttostr(Thighscore(data_list.objects[i]).punkte);
    table.Cells[3,pos] := Thighscore(data_list.objects[i]).feld;
    table.Cells[4,pos] := Thighscore(data_list.objects[i]).script;
    table.Cells[5,pos] := Thighscore(data_list.objects[i]).date;
  end;
end;

procedure Tscore_form.add(mode : Rgamemode;punkte,feldx,feldy : integer;script : string);

var name : string;

begin
  //**** Name ermitteln
  if length(lastname) > 0 then
    name := lastname   //lastname holen wenn schon vorhanden
  else begin
    name := GetInteractiveUserName;  //angemeldten Namen holen als Standard (nur NT-Systeme+)
    delete(name,1,pos('\',name));  //Computername entfernen
  end;
  add(mode,punkte,feldx,feldy,script,name);
end;

procedure Tscore_form.add(mode : Rgamemode;punkte,feldx,feldy : integer;script : string;name : string);
//fügt eintrag hinzu mit frage nach name

var feld : string;  //hilfsvariablen
    use : boolean;   //speicher ja nein?
    i : byte; //zähler
    minpoints : integer; //punkte die überschritten werden müßen
    entrycount : byte;

begin
  if cheat = false then //keine debug möglichkeite genutzt?
  begin
    //****Nötige Punktzahl?
    minpoints := maxint;  //varialben grenze = maximal punktzahl
    entrycount := 0;
    if data_list.Count > 0 then //Zur sicherheit falls keien einträge
    for i := 0 to data_list.count -1 do //schleife durch liste
    begin
      if Thighscore(data_list.objects[i]).mode = mode then
      begin        //nur aktuellen modus beachten
        if Thighscore(data_list.objects[i]).punkte < minpoints then minpoints := Thighscore(data_list.objects[i]).punkte; //minimale punkte finden
        inc(entrycount);
      end;
    end;
    if ((punkte > minpoints) or (entrycount < 5) and (cheat = false)) and (punkte > 0) then
    begin  //nur wenn minium überschritten, oder noch nicht 5 einträge sind
      use := InputQuery('Highscore', 'Bitte Namen Angeben', Name);
      //**** Eintrag vornehmen
      if use = true then
      begin
        lastname := name; //Name für nächst verwendung speichern
        feld := inttostr(feldx)+'x'+inttostr(feldy);  //feld in string schreiben
        add_entry(mode,punkte,feld,script,name,datetostr(date)+' '+timetostr(time));     //hinzufügen
        sort_trunc_list;   //sortieren
        update_list;  //anzeigen
      end;
      visible := true;    //Formular Zeigen
    end;
  end
  else Showmessage('Keine Highscore im Debug Modus!');
  cheat := false;
end;

procedure Tscore_form.FormDestroy(Sender: TObject);

var node : TJvSimpleXMLElem; //help
    esay,medium,hard : TJvSimpleXMLElem;  //hauptzweige
    xml_file : TJvSimpleXml;
    i : integer;

begin
   //***Speichern  Highscore in XML Datei
  xml_file  := Tjvsimplexml.create(self);  //erstellen XML daten
  xml_file.options := [];
  xml_file.Root.Name := 'Highscore';            //erzeuge Datei Kopf
  node := xml_file.Root.Items.Add('Description','YATC '+version+' Highscore File');
  esay := xml_file.Root.Items.Add('esay','');  //erzeuge 3 Hauptzweige
  medium := xml_file.Root.Items.Add('medium','');
  hard := xml_file.Root.Items.Add('hard','');
  if data_list.Count > 0 then //Zur sicherheit falls keien einträge
  for i := 0 to data_list.count -1 do //schleife durch liste
  begin
    case Thighscore(data_list.Objects[i]).mode of //je nach modus hauptzweig wählen &eintrag erstellen
      desay : node := esay.items.add('entry','');
      dmedium : node := medium.items.add('entry','');
      dhard : node := hard.items.add('entry','');
    end;
    node.items.add('name',data_list.Strings[i]);  //Daten schreiben
    node.items.add('feld',Thighscore(data_list.Objects[i]).feld);
    node.items.add('script',Thighscore(data_list.Objects[i]).script);
    node.items.add('punkte',Thighscore(data_list.Objects[i]).punkte);
    node.items.add('date',Thighscore(data_list.Objects[i]).date);
  end;
  xml_file.SaveToFile(highscore_file);    //Speichern in datei

  xml_file.free;      // xml objekt freigeben
  data_list.Free;   //liste freigeben
end;

procedure Tscore_form.clear_buttonClick(Sender: TObject);

var i,j : integer;
    m : Rgamemode;
    table : Tstringgrid;

begin
  if MessageDlg('Highscore Löschen?',mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  begin
    data_list.Clear;  //Daten Löschen
    //*****Tabellen Löschen (anzeige)
    for m := desay to dhard do  //schelife durch modi
    begin
      table := esay_table; //zur sicherheit
      case m of
        desay : table := esay_table;   //tabelle wählen
        dmedium : table := medium_table;
        dhard : table := hard_table;
      end;
      for i := 1 to 5 do
        for j := 0 to 4 do
          table.cells[i,j] := '';//Löschen der Zellen
  end;
  end;
end;

end.
