Author Topic: stats with rank  (Read 1140 times)

0 Members and 1 Guest are viewing this topic.

Offline Zabijaka

  • Soldier
  • **
  • Posts: 201
  • Soldat Fan, Hitman Fan
stats with rank
« on: August 27, 2009, 06:29:08 am »
Hello, I got problem with script for stats. Script use CurryWurst MySSQL funkcions.
Compile pass but if I type !stats I see out of range error in onplayerspeek :/
PLZ help me :)
Code: [Select]
const
  _FOLDER_DATABASE = '';
  _NAME_DATABASE = 'stats.txt';
  Players = 14;

var
  database : array of string;
  Exception: string;
  Kills,Deaths: array [1..Players] of Word;

procedure OnErrorOccur(const ERROR_MSG: string);
begin
  Exception:= ERROR_MSG;
end;

function IXSplit(const SOURCE: string; Delimiter: string): array of string;
var
  i, x, d: integer;
  s, b: string;
begin
  d:= length(Delimiter);
  i:= 1;
  SetArrayLength(Result, 0);
  while (i <= length(SOURCE)) do
  begin
    s:= Copy(SOURCE, i, d);
    if (s = Delimiter) then
    begin
      SetArrayLength(Result, x + 1);
      Result[x]:= b;
      Inc(i, d);
      Inc(x, 1);
      b:= '';
    end else
    begin       
      b:= b + Copy(s, 1, 1);
      Inc(i, 1);
    end;
  end;
  if (b <> '') then
  begin
    SetArrayLength(Result, x + 1);
    Result[x]:= b;
  end;
end;

function ReadFromFile(File: string): string;
begin
  Result:= ReadFile(File);
  Result:= Copy(Result, 0, length(Result) - 2);
end;

function DoesFileExist(Name: string): boolean;
begin
  if (GetSystem() = 'windows') then
  begin
    if (FileExists(Name)) then
    begin
      result:= true;
    end;
  end else
  begin
    if ((FileExists(Name)) or (ReadFromFile(Name) <> '')) then
    begin
      result:= true;
    end;
  end;
end;

procedure _LoadDatabase();
begin
  if (DoesFileExist(_FOLDER_DATABASE + _NAME_DATABASE)) then
  begin
    database:= IXSplit(ReadFromFile(_FOLDER_DATABASE + _NAME_DATABASE), #13#10);
  end else
  begin
    WriteFile(_FOLDER_DATABASE + _NAME_DATABASE, '');
  end;
end;
 
procedure _SnapDatabase();
var
  i: integer;
  b: string;
begin
  for i:= 0 to GetArrayLength(database) - 1 do
  begin
    if (b <> '') then
    begin
      b:= b + #13#10 + database[i];
    end else
    begin
      b:= database[i];
    end;
  end;
  WriteFile(_FOLDER_DATABASE + _NAME_DATABASE, b);
end;

function _RowExists(RowID: integer): boolean;
begin
  result:= ArrayHigh(database) >= RowID;
end;

function _getColumnInfo(RowID, ColumnID: integer): integer;
var
  ch, x, tabs: integer;
  b: string;
begin
  tabs:= -1;
  b:= database[RowID];
  while (tabs <> ColumnID) do
  begin
    x:= StrPos(#9, b);
    if ((x = 0) and (tabs <> ColumnID)) then
    begin
      exit;
    end;
    Inc(tabs, 1);
    if (tabs = ColumnID) then
    begin
      result:= ch + 1;
      break;
    end else
    begin
      ch:= ch + x;
      Delete(b, 1, x);
    end;
  end;
end;

function GetTypeOF(Value: variant): string;
begin
  case VarType(Value) of
    3  : result:= IntToStr(Value);
    5  : result:= FloatToStr(Value);
    11 : result:= iif(Value, 'true', 'false');
    256: result:= Value;
    else result:= 'unknown Type';
  end;
end;

procedure _CreateRow(Columns: array of variant);
var
  i, x: integer;
begin
  SetArrayLength(database, GetArrayLength(database) + 1);
  x:= GetArrayLength(database) - 1;
  for i:= 0 to GetArrayLength(Columns) - 1 do
  begin
    database[x]:= database[x] + GetTypeOF(Columns[i]) + #9;
  end;
  _SnapDatabase();
end;

function _DeleteRow(RowID: integer): boolean;
var
  HIndex: integer;
begin
  if (_RowExists(RowID)) then
  begin
    HIndex:= GetArrayLength(database) - 1;
    if (RowID <> HIndex) then
    begin
      database[RowID]:= database[HIndex];
    end;
    SetArrayLength(database, iif(HIndex > 0, HIndex - 1, 0));
    _SnapDatabase();
    result:= true;
  end else
  begin
    OnErrorOccur('RowID ' + IntToStr(RowID) + ' does not exist');
  end;
end;

function _UpdateColumn(RowID, ColumnID: integer; Increase: extended): boolean;
var
  data, Sum: string;
  pos: integer;
begin
  if (_RowExists(RowID)) then
  begin
    pos:= _getColumnInfo(RowID, ColumnID);
    if (pos > 0) then
    begin
      data:= GetPiece(database[RowID], #9, ColumnID);
      if (RegExpMatch('^-?(\d+|\d+.?\d+)$', data)) then
      begin
        Sum:= FloatToStr(StrToFloat(data) + Increase);
        Delete(database[RowID], pos, length(data));
        Insert(Sum, database[RowID], pos);
        result:= true;
      end else
      begin
        OnErrorOccur('Column "' + IntToStr(ColumnID) + '" represents no numeric value');
      end;
    end else
    begin
      OnErrorOccur('ColumnID ' + IntToStr(ColumnID) + ' does not exist');
    end;
  end else
  begin
    OnErrorOccur('RowID ' + IntToStr(RowID) + ' does not exist');
  end;
end;

function _SetColumn(RowID, ColumnID: integer; Value: variant): boolean;
var
  pos: integer;
  data: string;
begin
  if (_RowExists(RowID)) then
  begin
    pos:= _getColumnInfo(RowID, ColumnID);
    if (pos > 0) then
    begin
      data:= GetPiece(database[RowID], #9, ColumnID);
      Delete(database[RowID], pos, length(data));
      Insert(GetTypeOF(Value), database[RowID], pos);
      result:= true;
    end else
    begin
      OnErrorOccur('ColumnID ' + IntToStr(ColumnID) + ' does not exist');
    end;
  end else
  begin
    OnErrorOccur('RowID ' + IntToStr(RowID) + ' does not exist');
  end;
end;

function _AppendColumn(RowID: integer; Value: variant): boolean;
begin
  if (_RowExists(RowID)) then
  begin
    database[RowID]:= database[RowID] + GetTypeOF(Value) + #9;
    result:= true;
  end else
  begin
    OnErrorOccur('RowID ' + IntToStr(RowID) + ' does not exist');
  end;
end;

procedure ActivateServer();
begin
  _LoadDatabase();
end;

Procedure Sortowanie; //sort by points
var
i,j,licznik,licznik2:integer;
temp:String;
begin;
licznik:=1;
licznik2:=1;
repeat
if Database[licznik]<>'' then
  begin;
  inc(licznik,1);
  inc(licznik2,1);
  end;
until Database[licznik]='';
licznik2:=licznik2-2;
for j:=1 to licznik2 do
  begin;
    for i:=1 to licznik2 do
      begin;
        if StrToFloat(GetPiece(Database[i], #9, 1))<StrToFloat(GetPiece(Database[i+1], #9, 1)) then
          begin
            temp:=Database[i];
            Database[i]:=Database[i+1];
            Database[i+1]:=temp;
          end;
      end;
  end;
end;

function GetRowByPlayer(Name:String):longword;
var
i:Integer;
Found:Boolean;
begin
Found:=False;
For i:=1 to GetArrayLength(Database) do begin
if Name=GetPiece(Database[i], #9, 0) then begin Found:=True; Result:=i; Break; end;
end;
If Not Found then begin
_CreateRow([Name,'0','0','1']);
Result:=GetRowByPlayer(Name);
end;
end;

procedure SaveAllStats;
var
i:byte;
row:Longword;
Killss,Deathss:Word;
begin
for i:=1 to Players do begin
If GetPlayerStat(I,'active')=True then begin
row:=GetRowByPlayer(IdToName(i));
Killss:=StrToInt(GetPiece(Database[Row], #9, 2));
Deathss:=StrToInt(GetPiece(Database[Row], #9, 3));
_SetColumn(Row, 2 , IntToStr(Killss+Kills[I]));
_SetColumn(Row, 3 , IntToStr(Deathss+Deaths[I]));
_SetColumn(Row, 1 , FloatToStr(Killss/Deathss*Killss));
Kills[I]:=0;
Deaths[I]:=0;
end;
end;
_SnapDatabase();
end;

procedure SaveStats(i:Byte);
var
row:Longword;
Killss,Deathss:Integer;
begin
row:=GetRowByPlayer(IdToName(i));
Killss:=StrToInt(GetPiece(Database[Row], #9, 2));
Deathss:=StrToInt(GetPiece(Database[Row], #9, 3));
_SetColumn(Row, 2 , IntToStr(Killss+Kills[I]));
_SetColumn(Row, 3 , IntToStr(Deathss+Deaths[I]));
_SetColumn(Row, 1 , FloatToStr(Killss/Deathss*Killss));
Kills[I]:=0;
Deaths[I]:=0;
end;

procedure OnPlayerKill(Killer, Victim: byte; Weapon: string);
begin
If Killer<>Victim and GetPlayerStat(Killer,'Team')<>GetPlayerStat(Victim,'Team') then begin
Kills[Killer]:=Kills[Killer]+1;
Deaths[Victim]:=Deaths[Victim]+1;
end;
end;

procedure OnMapChange(NewMap: String);
begin
SaveAllStats;
Sortowanie;
end;

procedure OnLeaveGame(ID, Team: byte; Kicked: boolean);
begin
SaveStats(Id);
end;

Procedure ShowStats(Id:Byte);
var
Row:Longword;
begin
Row:=GetRowByPlayer(IdToName(Id));
WriteConsole(Id, 'Rank '+ IntToStr(Row)+ ' of '+ IntToStr(GetArrayLength(Database)), $FFFFFFFF);
WriteConsole(Id, 'Points '+ GetPiece(Database[Row], #9, 1), $FFFFFFFF);
WriteConsole(Id, 'Kills '+ GetPiece(Database[Row], #9, 2), $FFFFFFFF);
WriteConsole(Id, 'Deaths '+ GetPiece(Database[Row], #9, 3), $FFFFFFFF);
WriteConsole(Id, 'K/D ratio '+ FloatToStr(StrToFloat(GetPiece(Database[Row], #9, 3))/StrToFloat(GetPiece(Database[Row], #9, 3))), $FFFFFFFF);
end;

procedure OnPlayerSpeak(ID: Byte; Text: string);
begin
if text='!stats' then ShowStats(ID);
end;
« Last Edit: August 27, 2009, 06:36:07 am by Zabijaka »

Offline rayanaga

  • Soldier
  • **
  • Posts: 143
  • ~Fur flying~
    • Kryonex
Re: stats with rank
« Reply #1 on: August 27, 2009, 11:22:29 am »
Filling the first entry with a non-used playername seemed to make it work fine. For example:

Quote
43#@%^ 0 0 1
Raya 0 0 1

Just a quick and easy fix I guess. I'll look into the script part a little later.
[kY] Kryonex - Your local zombie fanatics.
http://www.kryonex.com/

Offline CurryWurst

  • Camper
  • ***
  • Posts: 265
    • Soldat Global Account System
Re: stats with rank
« Reply #2 on: August 27, 2009, 12:46:07 pm »
Filling the first entry with a non-used playername seemed to make it work fine. For example:

Quote
43#@%^ 0 0 1
Raya 0 0 1

Just a quick and easy fix I guess. I'll look into the script part a little later.

Yay, that's the point. Because he iterates through the database starting from 1, actually it should be 0.

By adding a second row you trick the GetRowByPlayer function and avoid that problem :P

Code: (pascal) [Select]
function GetRowByPlayer(Name:String):longword;
var
i:Integer;
Found:Boolean;
begin
Found:=False;
For i:=0 to GetArrayLength(Database) do begin  // for i:= 0
if Name=GetPiece(Database[i], #9, 0) then begin Found:=True; Result:=i; Break; end;
end;
If Not Found then begin
_CreateRow([Name,'0','0','1']);
Result:=GetRowByPlayer(Name);
end;
end;

Besides, I would recommend to switch to MySSQL 2.0. It is much more reliable as well as faster and also contains functions such as GetRowByPlayer by default. I already wrote an update for MySSQL 2.0, which has not been released yet. PM me if you want to switch to the latest version, so I can send you the update.
« Last Edit: August 27, 2009, 12:56:59 pm by CurryWurst »
Soldat Global Account System: #soldat.sgas @ quakenet

Offline rayanaga

  • Soldier
  • **
  • Posts: 143
  • ~Fur flying~
    • Kryonex
Re: stats with rank
« Reply #3 on: August 27, 2009, 10:17:21 pm »
Filling the first entry with a non-used playername seemed to make it work fine. For example:

Quote
43#@%^ 0 0 1
Raya 0 0 1

Just a quick and easy fix I guess. I'll look into the script part a little later.

Yay, that's the point. Because he iterates through the database starting from 1, actually it should be 0.

By adding a second row you trick the GetRowByPlayer function and avoid that problem :P

Code: (pascal) [Select]
function GetRowByPlayer(Name:String):longword;
var
i:Integer;
Found:Boolean;
begin
Found:=False;
For i:=0 to GetArrayLength(Database) do begin  // for i:= 0
if Name=GetPiece(Database[i], #9, 0) then begin Found:=True; Result:=i; Break; end;
end;
If Not Found then begin
_CreateRow([Name,'0','0','1']);
Result:=GetRowByPlayer(Name);
end;
end;

Besides, I would recommend to switch to MySSQL 2.0. It is much more reliable as well as faster and also contains functions such as GetRowByPlayer by default. I already wrote an update for MySSQL 2.0, which has not been released yet. PM me if you want to switch to the latest version, so I can send you the update.

Hey! Thanks for clearing me up on that lol.
[kY] Kryonex - Your local zombie fanatics.
http://www.kryonex.com/

Offline CurryWurst

  • Camper
  • ***
  • Posts: 265
    • Soldat Global Account System
Re: stats with rank
« Reply #4 on: August 27, 2009, 11:16:46 pm »
Btw, just a random note: Instead of searching if an accounts exist, after calling _CreateRow, you could simply store the result of it to the result of GetRowByPlayer, because _CreateRow will always return the index of the latest created row and there's no need to check the result of _CreateRow, because it won't fail, unless your server can't allocate new memory.

Soldat Global Account System: #soldat.sgas @ quakenet

Offline Zabijaka

  • Soldier
  • **
  • Posts: 201
  • Soldat Fan, Hitman Fan
Re: stats with rank
« Reply #5 on: August 28, 2009, 11:52:48 am »
Ok, now stats work xD
Script added to My MilitartShop server ;]

Offline Zabijaka

  • Soldier
  • **
  • Posts: 201
  • Soldat Fan, Hitman Fan
Re: stats with rank
« Reply #6 on: August 28, 2009, 03:31:13 pm »
I have problem with sort method, My sort method is too slow. When database will be large My server will crash xD

Sombody have any idea?

Edit:
Ok, Fixed

Soon I wiil add all script on forum :)
« Last Edit: August 29, 2009, 01:00:48 pm by Zabijaka »