Initial checkin master
authorRalf Ertzinger <ralf@skytale.net>
Fri, 10 Jan 2014 21:40:56 +0000 (22:40 +0100)
committerRalf Ertzinger <ralf@skytale.net>
Fri, 10 Jan 2014 21:40:56 +0000 (22:40 +0100)
23 files changed:
COPYING [new file with mode: 0644]
README [new file with mode: 0644]
gs_analyze/README [new file with mode: 0644]
gs_analyze/gs_analyze2.pl [new file with mode: 0755]
gs_analyze/mapnames.txt [new file with mode: 0644]
server/README [new file with mode: 0644]
server/jff.template [new file with mode: 0644]
server/mapnames.txt [new file with mode: 0644]
server/ndc.template [new file with mode: 0644]
server/ndcstrict.template [new file with mode: 0644]
server/quakec5.pl [new file with mode: 0644]
stats/README [new file with mode: 0644]
stats/dailystats.pl [new file with mode: 0644]
stats/dailystats_wap3.pl [new file with mode: 0644]
stats/databasectrl.sh [new file with mode: 0644]
stats/foreverstats2.pl [new file with mode: 0644]
stats/foreverstats3.pl [new file with mode: 0644]
stats/foreverstats_wap.pl [new file with mode: 0644]
stats/foreverstatsstrict.template [new file with mode: 0644]
stats/makedb.pl [new file with mode: 0644]
stats/makerank.pl [new file with mode: 0644]
stats/playerstats.pl [new file with mode: 0644]
stats/stats.sql [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f9c5fe3
--- /dev/null
+++ b/README
@@ -0,0 +1,109 @@
+README - NDC Code
+=================
+
+Dies ist die README fuer die GPL-Release des NDC (Northcore Deathmatch
+Clan) Codes fuer Quakeserver-Administration und -Auswertung (oder
+ganz kurz: NDC Code).
+
+Die in diesem Paket gesammelten Werke sind ueber die Jahre aus
+eigenem Beduerfnis bei der Verwaltung unserer Quakeserver und
+der Homepage entstanden.
+Meisterwerke sind nach unserer Meinung nicht dabei, aber da es
+genug Leute gegeben hat, die Interesse an dem Code gezeigt
+haben: nun, hier ist er.
+Erwartet bitte keinen wunderschoenen und akurat durchkommentierten
+Code. Ich habe versucht, die groessten Knaller rauszufeilen
+(ich habe Perl und SQL gelernt, waehrend dieser Code entstand,
+und das sieht man), aber teilweise sind da noch Stellen
+drin, die ich selber nicht mehr verstehe.
+Der gesamte Code steht von der ersten bis zur letzten Zeile
+unter der GPL (GNU Public License), in voller Laenge und
+Schoenheit nachzulesen in der Datei COPYING.
+
+Was heisst das fuer Euch und uns?
+(Note: Dieser Absatz ist meine Interpretation der GPL. Er ist
+_keine_ Rechtsgrundlage. Gueltig ist der Wortlaut der GPL,
+zu entnehmen der Datei COPYING, oder bei der FSF)
+Fuer uns heisst es: was auch immer dieser Code bei Euch anrichten
+mag, es ist einzig und allein Euer Problem. Wir uebernehmen keinerlei
+Garantie fuer die Funktionalitaet, Sicherheit oder Brauchbarkeit
+des Codes fuer irgendwelche Zwecke.
+Fuer Euch heisst es: Macht damit, was ihr wollt. Veraendert ihn,
+erweitert ihn, benutzt, was Euch gefaellt, und werft den Rest weg.
+Dies alles unter einer Bedingung: der Code, der aus unserem oder
+mit Hilfe unseres Codes entsteht, muss wieder unter der GPL stehen.
+Man koennte sagen, GPL ist ansteckend. Und Heilmittel gibts keins :)
+Dass abgeleiteter Code wieder unter der GPL steht, impliziert 
+automatisch, daß er wieder frei verfügbar sein muss. Das heisst
+_nicht_, dass ihr damit kein Geld verdienen duerft. Ihr duerft
+Programme verfassen, und dafuer Geld verlangen. Aber ihr muesst
+(spaetestens auf Anfrage) den Code rausruecken.
+
+
+INHALT
+======
+
+Was verbirgt sich nun in den einzelnen Verzeichnissen? Eine kurze
+Auflistung:
+
+gs_analyze     Ein Perl-Script, dass die von Lithium (und anderen
+               MODs) erzeugten GS-Logfiles auswertet, und in eine
+               Form bringt, die die Datenbankscripte leichter ver-
+               arbeiten koennen.
+               Das Script erzeugt eine Gesamtstatistik, und
+               Statistiken fuer einzelne Maps.
+
+stats          Die Teile des Codes, die auf der Website im Vordergrund
+               (dailystats, foreverstats, playerstats) und im Hintergrund
+               (makedb, makerank) die Statistiken verwalten.
+
+server         Das quakec5-Skript, das den Echtzeit-Status eines
+               Quake2-Servers auswertet.
+
+
+VORAUSSETZUNGEN
+===============
+
+Was braucht man fuer all das hier? Von den technischen Voraussetzungen
+her:
+perl (mindestens 5.002)
+MySQL 3.22
+apache 1.3
+
+Es gibt keinen wirklichen Grund, warum das alles hier nicht auch mit
+IIS und Oracle laufen sollte, aber die obige Liste stellt die laufende
+Konfiguration dar, und ist als solche geprueft.
+
+Noch etwas: die Skripte sind zwar "aus dem Leben" gegriffen, aber
+natuerlich steht da auch etwas drin, was Euch nix angeht. Passworte,
+Serverpfade, so ein Zeug. Das ist in diesem Release entfernt.
+Das bringt es mit sich, dass moeglicherweise (oder eher: ziemlich
+sicher) dieser Sourcetree nicht aus der Tuete laufen wird. Wer also
+Angst vor dreckigen Fingern und anderer Leute Code hat, ist hiermit
+wohl auf dem falschen Dampfer. Aber solche Personen lesen fuer gewoehnlich
+auch keine READMEs :)
+
+
+VERSIONIERUNG
+=============
+
+Versionsnummern? Was ist das?
+Bei den fuer NDC erstellten Scripts war das nie ein grosses Thema.
+Neuere Versionen wurden einfach gnadenlos in den alten Code
+reingeschoben. Bei guter Laune des Autors wurde dem Dateinamen
+eine sich (eventuell sogar nachvollziehbar erhoehende) angehaengte
+Nummer verpasst. Diese Nummern haben sie hier auch.
+Aus diesem Chaos heraus deklarieren wir alle hier mitgelieferten
+Programme als Version NDC Code Release 1. Also bitte nicht wundern,
+wenn es eine foreverstats3.pl gibt, aber keine Spur der vorigen
+zu finden ist. Das ist dann eben so :)
+
+
+KONTAKT
+=======
+
+Bei Fragen, Anregungen, Bugfixes:
+http://www.ndc.sh/ndccode
+
+oder
+ndccode@ndc.sh
diff --git a/gs_analyze/README b/gs_analyze/README
new file mode 100644 (file)
index 0000000..2ca4212
--- /dev/null
@@ -0,0 +1,36 @@
+README - gs_analyze2.pl
+=======================
+
+Eines der Kernstuecke des Statistiksystems. Dieses Script
+laeuft bevorzugt auf dem Quake-Server selbst, wo es
+Logfiles im GS-Format liest, und in ein kuerzeres Logfile
+umwandelt, das von den Datenbankscripten weiterverarbeitet
+werden kann.
+
+Das Script liest seine Daten von STDIN. Die Ausgabe erfolgt
+zu einen in eine Datei (big.res), die die gesamte Statistik
+fuer das Logfile enthaelt.
+Zum anderen liest das Script, falls vorhanden, eine Datei namens
+mapnames.txt ein. Da GS-Logfiles aus nicht bekannten Gruenden
+nicht den BSP-Namen der gespielten Maps, sondern den vollen Namen
+(also nicht q2dm1 sondern "The Edge") enthalten, wird der Inhalt
+dieser Datei zur Uebersetzung genutzt.
+Fuer Maps, deren BSP-Namen das Script auf diese Weise ermitteln
+kann, werden separate Logdateien mit dem Namen des BSP (also
+q2dm1.res...) geschrieben.
+
+Jede .res-Datei enthaelt in einer Zeile Daten fuer je einen
+Spieler. Die einzelnen Felder sind durch ":" getrennt (nein,
+wir machen uns keine Gedanken um : in Spielernamen). Die einzelnen
+Felder:
+
+Name
+Kills
+Victims
+Suicides
+gespielte Maps
+gewonnene Maps
+Spielzeit (Sekunden)
+
+Die jeweils erste Zeile (ohne Spielernamen, beginnend mit einem :)
+enthaelt die jeweiligen Summen aller Felder.
diff --git a/gs_analyze/gs_analyze2.pl b/gs_analyze/gs_analyze2.pl
new file mode 100755 (executable)
index 0000000..69e61fe
--- /dev/null
@@ -0,0 +1,327 @@
+#!/usr/bin/perl -w
+
+# gs_analyze2.pl
+# NDC Code Release 1
+#
+# Reads a GS-compliant log file from STDIN, writes processed logs
+# to various files.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+@gslog=<STDIN>;
+
+# Enable this line for debugging
+
+# $debug = 1;
+
+# Read mapname-mapping from file
+
+open (MAPNAMES,"mapnames.txt") or die "Could not open mapnames.txt: $!\n";
+
+# Log file for skill calculation
+open (SKILLOG, ">skill.log") or die "Could not open skill.log: $!\n";
+
+while ($line=<MAPNAMES>) {
+
+  ($handle,$mapname) = split (":",$line);
+  chop($mapname);
+  $handle{$mapname} = $handle;
+}
+
+close (MAPNAMES); 
+
+while ($gslog_line = shift(@gslog)) {
+
+  ($killer,$victim,$action,$weapon,$fragdiff,$timestamp,$ping) = 
+  split("\t",$gslog_line);
+  unless (defined($action)) {
+    next;
+  }
+
+  if ($action eq "Kill") {
+    $pl_kills{"##global"}{$killer}++;
+    $pl_kills{$actual_map}{$killer}++;
+    $pl_victims{"##global"}{$victim}++;
+    $pl_victims{$actual_map}{$victim}++;
+    if (defined($pl_count_map{$killer})) {
+      $pl_maps_played{"##global"}{$killer}++;
+      $pl_maps_played{$actual_map}{$killer}++;
+      print "Map count for $killer increased to $pl_maps_played{\"##global\"}{$killer}\n" if $debug;
+      undef $pl_count_map{$killer};
+    }
+    if (defined($pl_count_map{$victim})) {
+      $pl_maps_played{"##global"}{$victim}++;
+      $pl_maps_played{$actual_map}{$victim}++;
+      print "Map count for $victim increased to $pl_maps_played{\"##global\"}{$victim}\n" if $debug;
+      undef $pl_count_map{$victim};
+    }
+    $sys_kills{"##global"}++;
+    $sys_kills{$actual_map}++;
+    $pl_kills_local{$killer}++;
+
+    # Print out skill log
+    print SKILLOG "K:$killer:$victim\n";
+  }
+
+  if ($action eq "Suicide") {
+    $pl_suicides{"##global"}{$killer}++;
+    $pl_suicides{$actual_map}{$killer}++;
+    if (defined($pl_count_map{$killer})) {
+      $pl_maps_played{"##global"}{$killer}++;
+      $pl_maps_played{$actual_map}{$killer}++;
+      print "Map count for $killer increased to $pl_maps_played{\"##global\"}{$killer}\n" if $debug;
+      undef $pl_count_map{$killer};
+    }
+    $sys_suicides{"##global"}++;
+    $sys_suicides{$actual_map}++;
+    $pl_kills_local{$killer}--;
+
+    # Print out skill log
+    print SKILLOG "S:$killer\n";
+  }
+
+  # Check if a new map has been started.
+  # $weapon holds the map name
+
+  if ($action eq "Map") {
+    chop ($weapon);
+    chop ($weapon);
+    $actual_map = $handle{$weapon};
+    unless (defined($actual_map)) {
+      $actual_map = "##undefined";
+    }
+    $sys_maps_played{"##global"}++;
+    $sys_maps_played{$actual_map}++;
+    print "Map started: $actual_map\n" if $debug;
+  }
+
+  # Check for a newly started game.
+
+  if ($action eq "GameStart") {
+    pl_disconnect_all();
+  }
+
+
+  # Check for the end of a map. Calculate map winner.
+  # Log out all players
+
+  if ($action eq "GameEnd") {
+    print "Map ends: $actual_map\n" if $debug;
+    $sys_connect_total{"##global"} += $timestamp;
+    $sys_connect_total{$actual_map} += $timestamp;
+    $pl_best_frags = 0;
+    undef $pl_best_nick;
+    if (defined(%pl_kills_local)) {
+      foreach $nick (keys %pl_kills_local) {
+        if ($pl_kills_local{$nick} > $pl_best_frags) {
+          $pl_best_frags = $pl_kills_local{$nick};
+          $pl_best_nick = $nick;
+        }
+      }
+      if (defined($pl_best_nick)) {
+        $pl_maps_won{"##global"}{$pl_best_nick}++;
+        $pl_maps_won{$actual_map}{$pl_best_nick}++;
+        print "$pl_best_nick wins $actual_map with $pl_best_frags\n" if $debug;
+      }
+    }
+    pl_disconnect_all();
+
+    # Print out skill log
+    if (defined($pl_best_nick)) {              # If no one won the map, why bother?
+      print SKILLOG "W:$pl_best_nick\n";
+    } 
+  }
+
+
+  # Check for a newly connecting player. Initialize all fields, if necessary.
+  # $weapon holds player name.
+
+  if ($action eq "PlayerConnect") {
+
+    pl_connect($weapon);
+
+  }
+
+
+  # If a player disconnects, log his online time.
+  # $weapon holds the player name.
+
+  if ($action eq "PlayerLeft") {
+
+    pl_disconnect($weapon);
+
+  }
+
+
+  # If a player renames himself, consider this a disconnect and immediate
+  # reconnect.
+  # $weapon holds the old name, $fragdiff the new one.
+  # Preserve frags in the local map! Important for winning caclulations
+  # WARNING! We might get into trouble here. If a player wins a map,
+  # and renames during the ending music, the "new" player will win the
+  # map (since he inherits the kills), but the map will not count as
+  # played (since he was neither fragged, nor fragged another player).
+  # PS: this is not theoretical ;)
+
+  if ($action eq "PlayerRename") {
+
+    $tmp = $pl_kills_local{$weapon};
+    print "$weapon renamed to $fragdiff, inheriting $tmp\n" if $debug;
+    # If the map counts for the "leaving" player, decrease
+    # his mapcount, and increase the count of the "connecting" player.
+    unless(defined($pl_count_map{$weapon})) {
+      $pl_maps_played{"##global"}{$weapon}--;
+      $pl_maps_played{$actual_map}{$weapon}--;
+      print "Map count for $weapon decreased to $pl_maps_played{\"##global\"}{$weapon}\n" if $debug;
+    }
+    pl_disconnect($weapon);
+    pl_connect($fragdiff);
+    unless(defined($pl_count_map{$weapon})) {
+      $pl_maps_played{"##global"}{$fragdiff}++;
+      $pl_maps_played{$actual_map}{$fragdiff}++;
+      print "Map count for $fragdiff increased to $pl_maps_played{\"##global\"}{$fragdiff}\n" if $debug;
+    }
+    $pl_kills_local{$fragdiff} = $tmp;
+  }
+
+}
+
+# Just to be sure....
+
+pl_disconnect_all();
+
+# Write out all results. Phew.
+
+foreach $mapkey (keys %pl_kills) {
+
+  if ($mapkey eq "##global") {
+    $filename = "big.res";
+  } else {
+    $filename = $mapkey . ".res";
+  }
+  
+
+  open(LOGFILE, ">$filename") or die "Could not open $filename: $!\n";
+
+  select LOGFILE;
+
+  # Print final results. First line holds overall system statistics.
+
+  print ":";
+  print "$sys_kills{$mapkey}:";
+  print ":";
+  print "$sys_suicides{$mapkey}:";
+  print "$sys_maps_played{$mapkey}:";
+  print ":";
+  print "$sys_connect_total{$mapkey}:";
+  print "\n";
+
+  foreach $nick (keys %{ $pl_kills{$mapkey} }) {
+
+    print "$nick:";
+    print "$pl_kills{$mapkey}{$nick}:";
+    print "$pl_victims{$mapkey}{$nick}:";
+    print "$pl_suicides{$mapkey}{$nick}:";
+    print "$pl_maps_played{$mapkey}{$nick}:";
+    print "$pl_maps_won{$mapkey}{$nick}:";
+    print "$pl_connect_total{$mapkey}{$nick}:";
+    print "\n";
+
+  }
+
+  select STDOUT;
+
+  close (LOGFILE);
+
+}
+
+
+###### - Subroutines
+
+sub pl_connect() {
+
+  $pl_name = shift;
+  return unless defined($pl_name);
+
+  # Reduce the player name to the first 15 characters. You want that.
+  # Believe me.
+
+  $pl_name = substr($pl_name, 0, 15);
+
+  print "Player connected: $pl_name\n" if $debug;
+
+  $pl_kills{"##global"}{$pl_name} = 0 unless defined($pl_kills{"##global"}{$pl_name});
+  $pl_kills{$actual_map}{$pl_name} = 0 unless defined($pl_kills{$actual_map}{$pl_name});
+
+  $pl_victims{"##global"}{$pl_name} = 0 unless defined($pl_victims{"##global"}{$pl_name});
+  $pl_victims{$actual_map}{$pl_name} = 0 unless defined($pl_victims{$actual_map}{$pl_name});
+
+  $pl_suicides{"##global"}{$pl_name} = 0 unless defined($pl_suicides{"##global"}{$pl_name});
+  $pl_suicides{$actual_map}{$pl_name} = 0 unless defined($pl_suicides{$actual_map}{$pl_name});
+
+  $pl_maps_played{"##global"}{$pl_name} = 0 unless defined($pl_maps_played{"##global"}{$pl_name});
+  $pl_maps_played{$actual_map}{$pl_name} = 0 unless defined($pl_maps_played{$actual_map}{$pl_name});
+
+  $pl_maps_won{"##global"}{$pl_name} = 0 unless defined($pl_maps_won{"##global"}{$pl_name});
+  $pl_maps_won{$actual_map}{$pl_name} = 0 unless defined($pl_maps_won{$actual_map}{$pl_name});
+
+
+
+  # If the player reconnects before a map change, don't count as
+  # a played map
+  # This flag is reset by pl_disconnect_all().
+
+  unless (defined($pl_connect{$pl_name})) {
+    $pl_count_map{$pl_name} = 1;
+  }
+
+  $pl_connect{$pl_name} = 1;
+  $pl_kills_local{$pl_name} = 0;
+  $pl_connect_start{"##global"}{$pl_name} = $timestamp;
+  $pl_connect_start{$actual_map}{$pl_name} = $timestamp;
+}
+
+# ----------------------
+
+sub pl_disconnect {
+
+  $pl_name = shift;
+  return unless defined($pl_name);
+
+  print "Player left: $pl_name with $pl_maps_played{\"##global\"}{$pl_name} maps played, $pl_maps_won{\"##global\"}{$pl_name} maps won\n" if $debug;
+
+  $pl_connect_total{"##global"}{$pl_name} += ($timestamp - $pl_connect_start{"##global"}{$pl_name});
+  $pl_connect_total{$actual_map}{$pl_name} += ($timestamp - $pl_connect_start{$actual_map}{$pl_name});
+  $pl_connect_start{"##global"}{$pl_name} = -1;
+  delete $pl_kills_local{$pl_name};
+}
+
+# ----------------------
+
+sub pl_disconnect_all {
+
+  foreach $name (keys %pl_connect) {
+
+    undef $pl_connect{$name};
+    undef $pl_count_map{$name};
+    if ($pl_connect_start{"##global"}{$name} >= 0) {
+      pl_disconnect($name);
+    }
+    undef %pl_kills_local;
+  }
+}
diff --git a/gs_analyze/mapnames.txt b/gs_analyze/mapnames.txt
new file mode 100644 (file)
index 0000000..b88b1c1
--- /dev/null
@@ -0,0 +1,11 @@
+q2dm1:The Edge
+q2dm2:Tokay's Towers
+q2dm3:The Frag Pipe
+q2dm4:Lost Hallways
+q2dm5:The Pits
+q2dm6:Lava Tomb
+q2dm7:The Slimy Place
+q2dm8:WareHouse
+match1:Reckless Abandon
+nexus2:Rusted \85 by Shadowdane
+trdm01a:Sepulchre -by Trebz-
diff --git a/server/README b/server/README
new file mode 100644 (file)
index 0000000..02746e7
--- /dev/null
@@ -0,0 +1,4 @@
+README quakec5.pl
+=================
+
+Ein Perl-Skript, das 
diff --git a/server/jff.template b/server/jff.template
new file mode 100644 (file)
index 0000000..a574012
--- /dev/null
@@ -0,0 +1,98 @@
+<STYLE type=text/css>
+               A:link
+               {
+                       COLOR: #000066; TEXT-DECORATION: none
+               }
+               A:visited
+               {
+                       COLOR: #000066; TEXT-DECORATION: none
+               }
+               A:active
+               {
+                       COLOR: #0033FF; TEXT-DECORATION: none
+               }
+               A:hover
+               {
+                       COLOR: #336699; CURSOR: hand; TEXT-DECORATION: none
+               }
+               A
+               {
+                       COLOR: #000000; TEXT-DECORATION: line-through
+               }
+               P
+               {
+                       COLOR: #336699
+               }
+               </STYLE>
+               <BODY background="../pic/gitter_w.gif" TOPMARGIN=2 LEFTMARGIN=2 MARGINWIDTH=2 MARGINHEIGHT=2
+                TEXT="000000" BGCOLOR="FFFFFF" LINK="0000FF" VLINK="0000FF">
+
+          <H1 align="center">Serverstatus</H1>
+          <center>
+          <font size="+1"><b>Letztes Update: <i><!--$server_date--></i></font></b><br><br>
+          <font size="-1">(-<a href="http://141.57.8.35:6666/cgi-bin/sstatus.pl?server=141.57.8.35&port=27910" target="_self">aktualisieren</a>-)</font><br>
+       <hr width="50%"><br>
+       <table border="0" align="center">
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Server&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left">&nbsp;<font color="#0000FF"><!--$server_hostname--></font>&nbsp;</td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Map&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_map--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Game Mod&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_gamename--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Game Dir&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_gamedir--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Features&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_features--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Fraglimit&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_fraglimit--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Timelimit&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_timelimit--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;DMFlags&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_dmflags--></td>
+         </tr>
+         <tr>
+            <td bgcolor="a0a0a0" align="left"><b>&nbsp;Version&nbsp;</td>
+            <td bgcolor="e0e0e0" align="left"><!--$server_version--></td>
+         </tr>
+         </table>
+         <br><hr width="50%"><center>
+<!--if clients-->
+         <b>Diese Spieler sind zurzeit auf dem Server:</b><br><br>
+         <table border="0" align="center">
+            <tr>
+              <th bgcolor="a0a0a0" align="left">&nbsp;Playername&nbsp;</th>
+              <th bgcolor="a0a0a0" align="left">&nbsp;Frags&nbsp;</th>
+              <th bgcolor="a0a0a0" align="left">&nbsp;Ping&nbsp;</th>
+            </tr>
+<!--loop clients-->
+           <tr>
+              <td bgcolor="a0a0a0" align="left"><!--$parser_clientname--></td>
+              <td bgcolor="e0e0e0" align="left"><!--$parser_clientfrags--></td>
+              <td bgcolor="e0e0e0" align="left"><!--$parser_clientping--></td>
+           </tr>
+<!--endloop clients-->
+         </table>
+<!--endif clients-->
+<!--if noclients-->
+         <b>Derzeit keine Spieler auf dem Server</b>
+<!--endif noclients-->
+          <br><hr width="50%"><br><br>
+          <font size="-1">(Script wurde erstellt mit freundlicher Hilfe von [NDC]Maria)<br>
+          - <a href="http://www.ndc.sh" target="NDCWin">www.ndc.sh</a> -</font>
+          
+</BODY></HTML>
diff --git a/server/mapnames.txt b/server/mapnames.txt
new file mode 100644 (file)
index 0000000..b88b1c1
--- /dev/null
@@ -0,0 +1,11 @@
+q2dm1:The Edge
+q2dm2:Tokay's Towers
+q2dm3:The Frag Pipe
+q2dm4:Lost Hallways
+q2dm5:The Pits
+q2dm6:Lava Tomb
+q2dm7:The Slimy Place
+q2dm8:WareHouse
+match1:Reckless Abandon
+nexus2:Rusted \85 by Shadowdane
+trdm01a:Sepulchre -by Trebz-
diff --git a/server/ndc.template b/server/ndc.template
new file mode 100644 (file)
index 0000000..6c82106
--- /dev/null
@@ -0,0 +1,166 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+
+<!--$parser_selfinfo-->
+
+<HTML>
+<HEAD>
+  <TITLE>NDC Serverstatus</TITLE>
+  <META NAME="Author" CONTENT="Andreas Ulbrich">
+  <META NAME="Author" CONTENT="Ralf Ertzinger">
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF">
+  <CENTER>
+    <img SRC="http://www.ndc.sh/graphics/aktuell_logo.jpg" WIDTH="300" HEIGHT="90" BORDER="0" ALT="[SERVER Status]">
+  </CENTER>
+  <P STYLE="margin-left=1cm">
+    <table BORDER="0">
+      <tr>
+        <td WIDTH="270" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>Serverstatus</b> <!--$server_date-->
+        </td>
+      </tr>
+    </TABLE><BR>
+    <table BORDER="0">
+      <tr>
+        <td>
+          Adresse:
+        </td>
+        <td>
+          <!--$server_address--> Port: <!--$server_port-->
+        </td>
+        <td ROWSPAN="10" VALIGN="BOTTOM">
+          <img src="<!--$map_thumbnail-->" WIDTH="160" HEIGHT="120" BORDER="0" ALT="Map Thumbnail">
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Server-Name:
+        </td>
+        <td>
+          <b><!--$server_hostname--></b>
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Systemlast:
+        </td>
+        <td>
+          <!--$server_load_color-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Server-Mod:
+        </td>
+        <td>
+          <!--$server_gamename-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Features:
+        </td>
+        <td>
+          <!--$server_features-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          dmflags:
+        </td>
+        <td>
+          <!--$server_dmflags-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Timelimit:
+        </td>
+        <td>
+          <!--$server_timelimit-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Fraglimit:
+        </td>
+        <td>
+          <!--$server_fraglimit-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Spieleranzahl:
+        </td>
+        <td>
+          <!--$server_actclients-->/<!--$server_maxclients-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Momentan gespielte Map:
+        </td>
+        <td>
+          <!--$server_map-->
+        </td>
+      </tr>
+    </TABLE>
+    <BR>
+<!--if clients-->
+    <b><!--$parser_sortmode--></b>
+    <table BORDER="0">
+      <tr>
+        <td WIDTH="50" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>Rank</b>
+        </td>
+        <td WIDTH="170" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>
+            <a href="<!--$parser_selfsortname-->">Name</a>
+          </b>
+        </td>
+        <td WIDTH="130" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>
+            <a href="<!--$parser_selfsortfrags-->">Frags</a>
+          </b>
+        </td>
+        <td WIDTH="130" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>
+            <a href="<!--$parser_selfsortping-->">Ping</a>
+          </b>
+        </td>
+      </tr>
+<!--loop clients-->
+      <tr>
+        <td ALIGN="CENTER" BGCOLOR="#EEEEEE">
+          <!--$parser_clientrank-->
+        </td>
+        <td ALIGN="CENTER" BGCOLOR="#CCCCCC">
+          <!--$parser_clientlink_color-->
+        </td>
+        <td ALIGN="CENTER" BGCOLOR="#EEEEEE">
+          <!--$parser_clientfrags-->
+        </td>
+        <td ALIGN="CENTER" BGCOLOR="#EEEEEE">
+          <!--$parser_clientping-->
+        </td>
+      </tr>
+<!--endloop clients-->
+    </table>
+<!--endif clients-->
+<!--if noclients-->
+    <table BORDER="0">
+      <tr>
+        <td WIDTH="350" ALIGN="CENTER" BGCOLOR="#FFFFCC">
+          <b>Zur Zeit sind keine Spieler auf dem Server</b>
+        </td>
+      </tr>
+    </table>
+<!--endif noclients-->
+  <P align="right">
+    <FONT SIZE="-2">
+      Skripting by ADDIX<BR>
+      <A href="http://www.addix.de" target="_top">www.addix.de</A>
+    </FONT>
+</BODY>
+</HTML>
diff --git a/server/ndcstrict.template b/server/ndcstrict.template
new file mode 100644 (file)
index 0000000..f93f443
--- /dev/null
@@ -0,0 +1,163 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+
+<HTML>
+
+<HEAD>
+  <TITLE>NDC Serverstatus</TITLE>
+  <META NAME="Author" CONTENT="Andreas Ulbrich">
+  <META NAME="Author" CONTENT="Ralf Ertzinger">
+  <link rel="stylesheet" href="http://www.ndc.sh/css/ndcstrict.css" media="screen">
+</HEAD>
+
+
+<BODY>
+  <p class="image">
+    <img SRC="http://www.ndc.sh/graphics/aktuell_logo.jpg" WIDTH="300" HEIGHT="90" ALT="[SERVER Status]">
+  </p>
+  <div class="serverstatus">
+    <p>
+      <b>Serverstatus</b> <!--$server_date-->
+    </p>
+  </div>
+  <p>
+    <table BORDER="0">
+      <tr>
+        <td>
+          Adresse:
+        </td>
+        <td>
+          <!--$server_address--> Port: <!--$server_port-->
+        </td>
+        <td ROWSPAN="10" VALIGN="BOTTOM">
+          <img src="<!--$map_thumbnail-->" WIDTH="160" HEIGHT="120" ALT="Map Thumbnail">
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Server-Name:
+        </td>
+        <td>
+          <b><!--$server_hostname--></b>
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Systemlast:
+        </td>
+        <td>
+          <!--$server_load-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Server-Mod:
+        </td>
+        <td>
+          <!--$server_gamename-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Features:
+        </td>
+        <td>
+          <!--$server_features-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          dmflags:
+        </td>
+        <td>
+          <!--$server_dmflags-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Timelimit:
+        </td>
+        <td>
+          <!--$server_timelimit-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Fraglimit:
+        </td>
+        <td>
+          <!--$server_fraglimit-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Spieleranzahl:
+        </td>
+        <td>
+          <!--$server_actclients-->/<!--$server_maxclients-->
+        </td>
+      </tr>
+      <tr>
+        <td>
+          Momentan gespielte Map:
+        </td>
+        <td>
+          <!--$server_map-->
+        </td>
+      </tr>
+    </TABLE>
+<!--if clients-->
+    <p>
+      <b><!--$parser_sortmode--></b>
+    </p>
+    <table class="player">
+      <tr class="playerheader">
+        <td class="rankheader">
+          <b>Rank</b>
+        </td>
+        <td class="nameheader">
+          <b>
+            <a href="<!--$parser_selfsortname-->">Name</a>
+          </b>
+        </td>
+        <td class="fragheader">
+          <b>
+            <a href="<!--$parser_selfsortfrags-->">Frags</a>
+          </b>
+        </td>
+        <td class="pingheader">
+          <b>
+            <a href="<!--$parser_selfsortping-->">Ping</a>
+          </b>
+        </td>
+      </tr>
+<!--loop clients-->
+      <tr>
+        <td class="rankbody">
+          <!--$parser_clientrank-->
+        </td>
+        <td>
+          <!--$parser_clientlink-->
+        </td>
+        <td>
+          <!--$parser_clientfrags-->
+        </td>
+        <td>
+          <!--$parser_clientping-->
+        </td>
+      </tr>
+<!--endloop clients-->
+    </table>
+<!--endif clients-->
+<!--if noclients-->
+    <div class="serverstatus">
+      <p>
+        <b>Zur Zeit sind keine Spieler auf dem Server</b>
+      </p>
+    </div>
+<!--endif noclients-->
+  <p class="credits">
+    Skripting by ADDIX<BR>
+    <A href="http://www.addix.de">www.addix.de</A>
+  </p>
+</BODY>
+</HTML>
diff --git a/server/quakec5.pl b/server/quakec5.pl
new file mode 100644 (file)
index 0000000..ab3f6bc
--- /dev/null
@@ -0,0 +1,444 @@
+#!/usr/bin/perl 
+
+# quakec5.pl
+# NDC Code Release 1
+#
+# Connects to a Quake2 server, queries current map, players, mod
+# and various other stuff, and builds a web page from that.
+# Templates are supported.
+# CGI-Parameters:
+#      server:         IP or FQDN of server. Defaults to 194.64.167.5
+#      port:           Port. Defaults to 27910
+#      template:       Template file. Defaults to ndc
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use Socket;
+use Sys::Hostname;
+use DBI;
+use CGI;
+
+# Define some variables
+my %eingabe;
+my %variables;
+my %mapnames;
+my $mappath = "/maparchiv"; # Path to map thumbnails
+my $template_path = "."; # Path to templates.
+my $mapnamefile = "mapnames.txt";
+my $scriptpath = "http://www.ndc.sh/cgi-bin/quake/quakec5.pl"; # The script itself when called by HTTP
+my $quakeresponse;
+my $template;
+my $template_file;
+my $CGIquery;
+
+# Info about the script
+$variables{parser_selfinfo} =  "<!--\nThis is the [NDC] serverinfo script, Release 5.\n" .
+                               "Featuring support for Quake2, HTML templatefiles and SQL-Queries.\n" .
+                               "Parsing-Engine: Lilith, Version 1.1.\n" .
+                               "Output is HTML 4.01 strict compliant.\n\n" .
+                               "Original Release by [NDC]Maria.\n" .
+                               "Quake connection code by [NDC]Maria and [NDC]Sundancer.\n" .
+                               "Lilith by [NDC]Sundancer.\n" .
+                               "Source code is available. Contact ndccode\@ndc.sh or see http://www.ndc.sh/ndccode.\n" .
+                               "//-->";
+
+### Var def ###
+$CGIquery = new CGI;
+$variables{server_address} = ($CGIquery->param("server")?$CGIquery->param("server"):"194.64.167.5");
+$variables{server_port} = ($CGIquery->param("port")?$CGIquery->param("port"):"27910");
+$sort = ($CGIquery->param("sort")?$CGIquery->param("sort"):0);
+$template = ($CGIquery->param("template")?$CGIquery->param("template"):"ndc");
+
+# Load map names
+if (-e $mapnamefile) {
+  open(MAPNAMES,$mapnamefile);
+  while ($line=<MAPNAMES>) {
+    ($maphandle,$mapn) = split(":",$line);
+    chomp($mapn);
+    $mapname{$maphandle} = $mapn;
+  }
+  close(MAPNAMES);
+}
+
+$quakeresponse = QueryQuakeServer("status");
+
+### Ausgabeformatierung ###
+## Abtrennen der ersten Zeile mit den Systeminformationen ###
+@ausg = split (/\n/,$quakeresponse);
+
+## Zuweisen der Ausgabevariablen zu $variable{wasausgegebenwerdensoll} ##
+@config = split (/\\/,$ausg[1]);
+for ( $i = 1; $i < $#config; $i= $i + 2) {
+       $var = $config[$i];
+       $variables{"server_${var}"} = $config[$i + 1];  
+}
+
+## Zaehlen der Onlinespieler ##
+$anzplayer = scalar(@ausg) - 2;
+$variables{server_actclients} = $anzplayer;
+
+#### Umfomartieren der Spielernamen
+foreach $i (2..($#ausg)) 
+{
+       
+       @playerdata = ($ausg[$i] =~ /^(\d+)\s(\d+)\s"(.+)"$/);
+       $name = $playerdata[2];
+       $pings{$name} = $playerdata[1]; 
+       $frags{$name} = $playerdata[0];
+       $nicks{$name} = $name;
+       $nicks{$name} =~ s/&/&amp;/g;
+       $nicks{$name} =~ s/</&lt;/g;
+       $nicks{$name} =~ s/>/&gt;/g;
+       $nicks{$name} =~ s/"/&quot;/g;
+}
+
+
+## Mapnamen auf vollen Namen erweitern (wenn möglich)
+if (defined($mapname{$variables{server_mapname}})) {
+       $variables{server_map} = $mapname{$variables{server_mapname}} . " (". $variables{server_mapname} . ")";
+} else {
+       $variables{server_map} = $variables{server_mapname};
+}
+
+#### Ermittlung der Load falls moeglich #####
+$load = "N/A";
+
+$variables{server_load} = $load;
+$variables{server_load_color} = "<FONT color=\"#000000\">" . $load. "</FONT>";
+if ($load <= 0.7) {
+  $variables{server_load_color} = "<FONT color=\"#00CC00\">$load</FONT>";
+}
+if (($load > 0.7) && ($load < 1)) {
+  $variables{server_load_color} = "<FONT color=\"#CCCC00\">$load</FONT>";
+}
+if ($load >= 1) {
+  $variables{server_load_color} = "<FONT color=\"#CC0000\">$load</FONT>";
+}
+
+
+###### Sortieren #####
+
+# By default, sort by frags.
+@sortkey = sort { $frags{$b} <=> $frags{$a} } (keys %frags);
+$sortname = "Frags";
+
+if ($sort eq "0") {
+       @sortkey = sort { $frags{$b} <=> $frags{$a} } (keys %frags);
+       $sortname = "Frags";
+}
+
+if ($sort eq "1") {
+       @sortkey = sort { $pings{$a} <=> $pings{$b} } (keys %pings);
+       $sortname = "Pings";
+}
+
+if ($sort eq "2") {
+       @sortkey = sort { $nicks{$a} cmp $nicks{$b} } (keys %nicks);
+       $sortname = "Nick";
+}
+
+$variables{parser_sortmode} = "Sortiert nach $sortname";
+#### Ermittlung und formatierung des Datums #####
+$date_command = "/bin/date";
+$date = `$date_command +"%T Uhr \&nbsp\; %d.%m.%Y"`;
+chop($date);
+$variables{server_date} = $date;
+
+#### Bild von Map? #####
+
+if (-e "$mappath/$variables{server_mapname}/$variables{server_mapname}_1_thumb.jpg") {
+       $variables{map_thumbnail} = "http://www.ndc.sh/maparchiv/$variables{server_mapname}/$variables{server_mapname}_1_thumb.jpg";
+} else {
+       $variables{map_thumbnail} = "http://www.ndc.sh/maparchiv/blank.gif";
+}
+
+## Variables for different sorting
+$variables{parser_selfsortname} = $scriptpath . "?server=" . $variables{server_address} . "&amp;port=" . $variables{server_port} . "&amp;sort=2";
+$variables{parser_selfsortfrags} = $scriptpath . "?server=" . $variables{server_address} . "&amp;port=" . $variables{server_port} . "&amp;sort=0";
+$variables{parser_selfsortping} = $scriptpath . "?server=" . $variables{server_address} . "&amp;port=" . $variables{server_port} . "&amp;sort=1";
+
+
+## Ausgabe ##
+
+# Define variables used by if and loop statements
+$in_if_clients = 0;
+$in_if_noclients = 0;
+$in_loop_players = 0;
+
+# Check template file
+if ($eingabe{template} =~ /\W/) {
+       # template file contains illegal characters
+       $template_file = $template_path . "/ndc.template";
+} else {
+       $template_file = $template_path . "/" . $eingabe{template} . ".template";
+}
+
+if ( ! -e $template_file ) {
+       $template_file = $template_path . "/ndc.template";
+}
+
+# Start by printing content type
+print "Content-Type: text/html\n\n";
+
+open (TEMPLATE, $template_file) or die "Could not open template file: $!\n";
+@main_source=<TEMPLATE>;
+close(TEMPLATE);
+parse(@main_source);
+##### Subroutines ######
+
+
+sub cantconnect {
+
+# Start by printing content type
+print "Content-Type: text/html\n\n";
+print "<HTML><BODY>Can\'t connect to $server:$port\n<BR>$!\n</BODY></HTML>";
+exit;
+}
+
+sub dmflag {
+@dmflags_name = ("Health" , "Powerups" , "Weapon Stay" , "Falling Damage" , "Instant Powerups" , "Same Map" , "Teams by Skin" , "Teams by Model" , "Friendly Fire" , "Spawn Farthest" , "Force Respawn" , "Armor" , "Allow Exit" , "Infinite Ammo" , "Quad Drop" , "Fixed FOV");
+@dmflags_neg = (1 , 2 , 0 , 8 , 0 , 0 , 0 , 0 , 256 , 0 , 0 , 2048 , 0 , 0 , 0 , 0);
+
+
+print "<P>\&nbsp\;<P><UL><a name=\"dmflags\"><b>DMFLAGS f\&uuml\;r DUMMIES<\/b><\/a><BR>\n";
+print "<TABLE BORDER = \"0\">\n";
+print "<TR><td WIDTH=\"150\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Flag<\/B><\/td>\n";
+print "<td WIDTH=\"60\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>On<\/B><\/td>\n";
+print "<td WIDTH=\"60\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Off<\/b><\/td><\/TR>\n";
+foreach $i (0..($#dmflags_name)) {
+  if ( (($text{dmflags} & (2**$i)) ^ $dmflags_neg[$i]) == (2**$i)) {
+    print "<TR><TD ALIGN=\"LEFT\" BGCOLOR=\"\#CCCCCC\">$dmflags_name[$i]<\/TD>\n";
+    print "<TD ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><img src=\"http\:\/\/www.ndc.sh\/graphics\/haken.gif\"><\/TD>\n";
+    print "<TD ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">\&nbsp\;<\/TD><\/TR>\n";
+  } else {
+    print "<TR><TD ALIGN=\"LEFT\" BGCOLOR=\"\#CCCCCC\">$dmflags_name[$i]<\/TD>\n";
+    print "<TD ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">\&nbsp\;<\/TD>\n";
+    print "<TD ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><img src=\"http\:\/\/www.ndc.sh\/graphics\/haken.gif\"><\/TD><\/TR>\n";
+  }
+}
+
+print "<\/TABLE><\/UL>\n";
+
+}
+
+
+sub GetDBURL {
+
+# Takes a player name from subroutine call, returns a URL if player is in
+# database, undef else.
+
+  $pl_sql_nick = shift;
+  $pl_sql_nick_old = $pl_sql_nick;
+
+  $pl_sql_nick =~ s/(\\)/\\$1/g;
+  $pl_sql_nick =~ s/(')/\\$1/g;
+
+  # SQL-Variables
+
+  $sql_database = "stats";
+  $sql_db_table = "PlayerStats";
+  $sql_datasource = "DBI:mysql:$sql_database";
+  $sql_username = "";
+  $sql_password = "";
+  $sql_db_handle = DBI->connect($sql_datasource, $sql_username, $sql_password) or return undef;
+
+  $sql_query = $sql_db_handle->prepare("SELECT nick FROM $sql_db_table WHERE nick='$pl_sql_nick'");
+  $sql_query->execute;
+  $sql_result = $sql_query->fetchrow_hashref;
+  $sql_query->finish;
+
+  if (defined($sql_result)) {
+    $returnvalue = "\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/playerstats.pl\?nick\=" . make_compatible($pl_sql_nick_old) . "\"";
+  } else {
+    $returnvalue = undef;
+  }
+
+  $sql_db_handle->disconnect;
+  return $returnvalue;
+}
+
+sub parse {
+# This routine takes an array as input, and parses it line by line,
+# echoing results to the screen.
+# BEWARE:
+# Switches like if and loop are GLOBAL!
+
+my $template_line;
+my $if_variable;
+my $loop_variable;
+my @parser_comment;
+my $comment;
+my $fullcomment;
+my $replacement;
+my @looparray;
+my $clients;
+my $i;
+my $dbURL;
+
+LOOP: while ($template_line = shift) {
+       # Catch special requests
+       if ($template_line =~ /^\s*\<!--if [\w_]+--\>/) {
+               ($if_variable) = $template_line =~ /\<!--if ([\w_]+)--\>/;
+               if ($if_variable eq "clients") {
+                       $in_if_clients = 1;
+               }
+               if ($if_variable eq "noclients") {
+                       $in_if_noclients = 1;
+               }
+               next LOOP;
+       }
+       if ($template_line =~ /^\s*\<!--endif [\w_]+--\>/) {
+               ($if_variable) = ($template_line =~ /\<!--endif ([\w_]+)--\>/);
+               if ($if_variable eq "clients") {
+                       $in_if_clients = 0;
+               }
+               if ($if_variable eq "noclients") {
+                       $in_if_noclients = 0;
+               }
+               next LOOP;
+       }
+
+       if ($template_line =~ /^\s*\<!--loop [\w_]+--\>/) {
+               ($loop_variable) = ($template_line =~ /\<!--loop ([\w_]+)--\>/);
+               if ($if_variable eq "clients") {
+                       $in_loop_clients = 1;
+               }
+               next LOOP;
+       }
+
+       if ($template_line =~ /^\s*\<!--endloop [\w_]+--\>/) {
+               ($loop_variable) = ($template_line =~ /\<!--endloop ([\w_]+)--\>/);
+               if ($if_variable eq "clients") {
+                       $in_loop_clients = 0;
+                       # Now, loop through all clients and parse
+                       # the saved loop once for each.
+                       $i = 0;
+                       foreach $clients ( @sortkey) {
+                               $dbURL = GetDBURL($clients);
+                               $variables{parser_clientrank} = ++$i;
+                               $variables{parser_clientname} = $nicks{$clients};
+                               if (defined($dbURL)) {
+                                       $variables{parser_clientlink} = "<a href=$dbURL>" . $nicks{$clients} . "</a>";
+                                       $variables{parser_clientlink_color} = "<a href=$dbURL><font color=\"#000000\">" . $nicks{$clients} . "</font></a>";
+                               } else {
+                                       $variables{parser_clientlink} =  $nicks{$clients};
+                                       $variables{parser_clientlink_color} =  $nicks{$clients};
+                               }
+                               $variables{parser_clientping} = $pings{$clients};
+                               $variables{parser_clientfrags} = $frags{$clients};
+                               parse(@looparray);
+                       }
+
+               }
+               next LOOP;
+       }
+
+       # Check if we are to ignore these lines
+       if (($in_if_clients == 1) && ($variables{server_actclients} == 0)) {
+               next LOOP;
+       }
+       if (($in_if_noclients == 1) && ($variables{server_actclients} != 0)) {
+               next LOOP;
+       }
+
+       # If we are in loop mode, copy lines into an array for
+       # later parsing
+       if ($in_loop_clients == 1) {
+               push @looparray, $template_line;
+               next LOOP;
+       }
+
+       @parser_comment = ($template_line =~ /\<!--\$([\w_]+)--\>/g);
+       foreach $comment ( @parser_comment) {
+               if (defined($variables{$comment})) {
+                       $fullcomment = "\\<!--\\\$" . $comment . "--\\>";
+                       $replacement = $variables{$comment};
+                       $template_line =~ s/$fullcomment/$replacement/g;
+               }
+       }
+       print $template_line;
+}
+} # end of sub
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+  $input =~ s/\x1c/%1C/g;
+
+  return $input;
+}
+
+sub QueryQuakeServer {
+
+# Takes a command from caller. Executes the command on the server defined by the
+# global variables $variables{server_address} and $variables{server_port}
+# Returns a literal containing the server's response.
+
+my ($count, $hisiaddr, $host, $iaddr,$paddr, $port ,$proto, $hispaddr, $command, $query, $response);
+
+$command = shift;
+
+$iaddr = gethostbyname(hostname());
+$proto = getprotobyname('udp');
+$paddr =sockaddr_in(0 ,$iaddr);
+
+
+### Netzwerk und auslesen der Daten ###
+
+socket (SOCKET, PF_INET, SOCK_DGRAM, $proto) or &cantconnect;
+bind(SOCKET, $paddr) or die "bind: $!";
+$| = 1;
+
+
+$hisiaddr = inet_aton($variables{server_address}) or &cantconnect;
+$hispaddr = sockaddr_in($variables{server_port}, $hisiaddr);
+$query = "\xff\xff\xff\xff$command\x00";
+defined(send(SOCKET, $query, 0, $hispaddr)) or &cantconnect;
+
+## Timeout nach 5 sec ##
+$rin = "";
+vec($rin, fileno(SOCKET), 1) = 1;
+while (($response eq "" ) && select($rout = $rin, undef ,undef ,5.0))
+{
+       ($hispaddr = recv(SOCKET, $response, 1000, 0)) || &cantconnect; 
+}
+
+if ($response eq "")
+{
+       &cantconnect;
+}
+
+close(SOCKET);
+
+return $response;
+
+}
diff --git a/stats/README b/stats/README
new file mode 100644 (file)
index 0000000..a34ef05
--- /dev/null
@@ -0,0 +1,66 @@
+README - stats
+==============
+
+Diese Skripte bilden das Herzstueck des Statistiksystems.
+Sie _sind_ das Statistiksystem.
+foreverstats   - Die ewigen Statistiken
+               Version 2, die aktuell laeuft
+               Version 3, die neue (schoenerbesserbunter), mit
+               Suchfunktion in der Datenbank und Template-
+               Unterstuetzung (wer hat da "PHP" gerufen?)
+               WAP-Version.
+dailystats     - Die Tagesstatistiken
+               HTML und WAP.
+playerstats    - Statistiken fuer einzelne Spieler.
+               Von den dailystats und foreverstats
+               gelinkt.
+
+makedb         Macht aus gs_analyze-Ausgaben SQL
+makerank       Berechnet die Raenge in der ewigen Bestenliste
+databasectrl   Ein Shellscript, das makedb und makerank aufruft.
+
+Der Lauf der Daten vom Quake-Server zur Webseite laeuft
+ueber verschiedene Stufen.
+
+Die vom Server erzeugten Logs werden von gs_analyze in
+ein Zwischenformat gewandelt, und dann per FTP-Upload
+auf den Webserver geschoben.
+Hier kommt ein Synchronisationsproblem ans Licht. Der
+Quakeserver rotiert (in unserem Fall) taeglich um 6
+seine Stats, und wertet sie danach mit gs_analyze aus.
+Dann kommen die Zwischenlogs auf den Webserver. 
+Nun weiss der Webserver leider nicht, wann es beim Quake-
+server 6 Uhr ist. Da wir uns Konstukte wie rsh gerne ersparen
+wollten, haben wir einen anderen Weg gewählt.
+Der Quakeserver uebertraegt neben dem Logfile noch eine Datei
+namens first.run. Diese enthaelt nur eine 1. Jedesmal wenn
+entweder foreverstat oder dailystats aufgerufen wird, wird
+der Inhalt dieser Datei ueberprueft. Ist er 1, so wird
+databasectrl.sh aufgerufen, das wiederum das Logfile in die
+Datenbank ueberfuerht. Dann wird der Inhalt von first.run
+auf 0 gesetzt. Solange, bis ein neues Logfile vom Quakeserver
+kommt.
+
+In allen Skripten, die auf die Datenbanken zugreifen, gibt es
+Variablen, die den Benutzernamen und das Passwort setzen, mit
+denen auf die Datenbank zugegriffen wird. Im Moment sind diese
+beiden Felder leer.
+Der Name der Datenbank wird mit "stats" angenommen.
+Die Datei "stats.sql" enthaelt die SQL-Aufrufe, die die von den
+Skripten benoetigten Tables erstellen.
+
+In allen Skripten, die auf die Datenbanken zugreifen, gibt es
+
+In allen Skripten, die auf die Datenbanken zugreifen, gibt es
+Variablen, die den Benutzernamen und das Passwort setzen, mit
+denen auf die Datenbank zugegriffen wird. Im Moment sind diese
+beiden Felder leer.
+Der Name der Datenbank wird mit "stats" angenommen.
+Die Datei "stats.sql" enthaelt die SQL-Aufrufe, die die von den
+Skripten benoetigten Tables erstellen.
+Variablen, die den Benutzernamen und das Passwort setzen, mit
+denen auf die Datenbank zugegriffen wird. Im Moment sind diese
+beiden Felder leer.
+Der Name der Datenbank wird mit "stats" angenommen.
+Die Datei "stats.sql" enthaelt die SQL-Aufrufe, die die von den
+Skripten benoetigten Tables erstellen.
diff --git a/stats/dailystats.pl b/stats/dailystats.pl
new file mode 100644 (file)
index 0000000..b98b521
--- /dev/null
@@ -0,0 +1,278 @@
+#!/usr/bin/perl 
+
+# dailystats.pl
+# NDC Code Release 1
+#
+# Connects to the database holding the stats, and builds the web page
+# for the previous day.
+# CGI-Parameters:
+#      start:          First entry displayed
+#      limit:          Number of entries. Defaults to 20.
+#      sort:           Sort mode.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use DBI;
+use CGI;
+
+my $CGIquery;
+
+### Var def ###
+$CGIquery = new CGI;
+$sort = ($CGIquery->param("sort")?$CGIquery->param("sort"):0);
+$limit = ($CGIquery->param("limit")?$CGIquery->param("limit"):20);
+$back = ($CGIquery->param("back")?$CGIquery->param("back"):0);
+$sort = ($back==1?0:($CGIquery->param("sort")?$CGIquery->param("sort"):0));
+
+# Rebuild database, if necessary
+open (FIRST, "< first.run") || die "Can't open first.run\n";
+while (<FIRST>) {
+       if ($_ == 1) {
+               close (FIRST);
+               open (FIRST, "> first.run") || die "Can't open first.run\n";
+               print FIRST "0\n";
+               close (FIRST);
+               {$update = `databasectrl.sh`}
+       }
+}
+close (FIRST);
+
+$database = "stats";
+$data_source = "DBI:mysql:$database";
+$username = "";
+$password = "";
+$dbh = DBI->connect( $data_source, $username, $password) or die "Can't connect to $data_source\n"; #: $dbh->errstr\n";
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats WHERE mapsplayed > 0");
+$query->execute;
+$rows = $query->rows;
+$query->finish;
+
+$query = $dbh->prepare("SELECT nick ,skill, kills, victims, suicides, mapsplayed, mapswon, time, fph FROM PlayerStats WHERE mapsplayed > 0 ORDER by skill DESC LIMIT $start,$limit");
+$query->execute;
+
+while ($row_hash = $query->fetchrow_hashref) {
+       $name = $row_hash->{nick};
+       $nick{$name} = $name;
+       $skill{$name} = $row_hash->{skill};
+       $kills{$name} = $row_hash->{kills};
+       $victims{$name} = $row_hash->{victims};
+       $suicides{$name} = $row_hash->{suicides};
+       $maps{$name} = $row_hash->{mapsplayed};
+       $wonmaps{$name} = $row_hash->{mapswon};
+       $time{$name} = $row_hash->{time};
+       $fph{$name} = $row_hash->{fph};
+}
+$query->finish;
+$dbh->disconnect;
+
+
+
+
+
+print "Content-Type: text/html\n\n\n";
+
+
+###### Sortieren #####
+
+# By default, sort by rank
+
+if ($sort eq "0") {
+  @sortkey = sort { $skill{$b} <=> $skill{$a} } (keys %nick);
+  $sortname = "Skill";
+  $darstellung = "<IMG SRC=\"\/graphics\/formel.gif\" ALT=\"Formel\">";
+}
+
+
+
+if ($sort eq "1") {
+  @sortkey = sort { $nick{$a} cmp $nick{$b} } (keys %nick);
+  $sortname = "Nick";
+  $darstellung = "";
+}
+
+if ($sort eq "2") {
+  @sortkey = sort { $maps{$b} <=> $maps{$a} } (keys %maps);
+  $sortname = "gespielten Maps";
+  $darstellung = "";
+}
+
+if ($sort eq "3") {
+  @sortkey = sort { $kills{$b} <=> $kills{$a} } (keys %kills);
+  $sortname = "Kills";
+  $darstellung = "";
+}
+
+if ($sort eq "4") {
+  @sortkey = sort { $victims{$b} <=> $victims{$a} } (keys %victims);
+  $sortname = "Victims";
+  $darstellung = "";
+}
+
+if ($sort eq "5") {
+  @sortkey = sort { $suicides{$b} <=> $suicides{$a} } (keys %suicides);
+  $sortname = "Suicides";
+  $darstellung = "";
+}
+
+if ($sort eq "6") {
+  @sortkey = sort { $fph{$b} <=> $fph{$a} } (keys %fph);
+  $sortname = "FPH";
+  $darstellung = "\= Kills \/ \(Sec \/ 3600 \)";
+}
+
+if ($sort eq "7") {
+  @sortkey = sort { $time{$b} <=> $time{$a} } (keys %nick);
+  $sortname = "Zeit";
+  $darstellung = "";
+}
+
+if ($sort eq "8") {
+  @sortkey = sort { $wonmaps{$b} <=> $wonmaps{$a} } (keys %nick);
+  $sortname = "gewonnenen Maps";
+  $darstellung = "";
+}
+## Ausgabe ##
+### Header ###
+print '<HTML><HEAD><TITLE>Cardassia - Hall of Fame</TITLE>';
+print '<META NAME="Andreas Ulbrich \+ Ralf Ertzinger">';
+print '</HEAD><BODY BGCOLOR="#FFFFFF">';
+print "\n<CENTER><img SRC=\"http\:\/\/www.ndc.sh\/graphics\/dailystatic_logo.jpg\" WIDTH=\"500\" HEIGHT=\"90\" BORDER=\"0\"ALT=\"\[SERVER Daily Static\]\"><\/CENTER>\n";
+
+print "<CENTER><b>Anzahl der Spieler: $rows<\/B><BR>\n";
+if ($back == 0) {
+       print "<b><a href =\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=0\&limit\=$rows\&back\=1\">Alle Spieler anzeigen<\/A><\/B><\/CENTER><\/BR>\n";
+}
+else {
+       print "<b><a href =\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=0\&limit\=20\&back\=0\">Die ersten 20 anzeigen<\/A><\/B><\/CENTER><\/BR>\n";
+}
+
+
+##### Sortiert nach sortkey ########
+
+print "<P>\&nbsp\;<P><UL><b>Sortiert nach $sortname $darstellung<\/b>\n";
+print "<table BORDER=\"0\">\n";
+print "<tr>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Rang<\/b><\/td>
+\n";
+print "<td WIDTH=\"120\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=1\&limit=$limit\&back=$back\">Name<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=0\&limit=$limit\&back=$back\">Skill<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=6\&limit=$limit\&back=$back\">FPH<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=2\&limit=$limit\&back=$back\">Maps gespielt<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=8\&limit=$limit\&back=$back\">Maps gewonnen<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=3\&limit=$limit\&back=$back\">Kills<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=4\&limit=$limit\&back=$back\">Victims<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=5\&limit=$limit\&back=$back\">Suicides<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort\=7\&limit=$limit\&back=$back\">Zeit (Min)<\/a><\/b><\/td>\n";
+print "<\/tr>\n";
+
+$count = $start;
+foreach $name (@sortkey)
+{
+       
+       $count ++;
+       print "<tr>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"+0\">$count<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#CCCCCC\"><font size =\"+0\">";
+       print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/playerstats.pl\?nick\=";
+       print make_compatible($nick{$name});
+       print "\">";
+       print "<font color=\"#000000\">";
+       print make_html($nick{$name});
+       print "<\/font>";
+       print "<\/a><\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$skill{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$fph{$name}<\/font><\/td>\n";
+
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$maps{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$wonmaps{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$kills{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$victims{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$suicides{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$time{$name}<\/font><\/td>\n";
+       print "<\/tr>\n";
+}
+
+print "<\/TABLE><\/UL><P>\n";
+
+if ($back == 0) {
+  print "<CENTER><TABLE BORDER=\"0\">\n";
+  print "<tr>\n";
+  print "<td WIDTH=\"200\" ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">";
+  if ($start != 0) {
+    $start_prev = $start - $limit;
+    if ($start_prev < 0) {$start_prev = 0;}
+    print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort=$sort&start=$start_prev&limit=$limit&back=0\">";
+    print "Zur&uuml;ck";
+    print "<\/a>\n";
+  } else {
+    print "Zur&uuml;ck";
+  }
+  print "<\/td>\n";
+  print "<td WIDTH=\"200\" ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">";
+  if ($start + $limit < $rows) {
+    $start_next = $start + $limit;
+    print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/dailystats.pl\?sort=$sort&start=$start_next&limit=$limit&back=0\">";
+    print "Weiter";
+    print "<\/a>\n";
+  } else {
+    print "Weiter";
+  }
+  print "<\/td>\n";
+  print "<\/tr>\n";
+  print "<\/TABLE><\/CENTER>\n";
+}
+
+print "<P><FONT SIZE=\"-2\"><DIV ALIGN=right>Skripting by NDC Code<BR><A href=\"http://www.ndc.sh\" target=\"_top\">www.ndc.sh</A></DIV></FONT><BR>\n";
+print '</BODY></HTML>';
+
+
+############### Subroutines ###########
+
+sub make_html {
+
+  $input = shift;
+#  $input =~ s/&/und/g;
+  $input =~ s/</&lt\;/g;
+  $input =~ s/>/&gt\;/g;
+  $input =~ s/"/&quot\;/g;
+  $input =~ s/\x1c/&middot;/g;
+#  $input =~ s/\|/pipe/g;
+  return $input;
+}
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+  $input =~ s/\x1c/%1C/g;
+
+  return $input;
+}
diff --git a/stats/dailystats_wap3.pl b/stats/dailystats_wap3.pl
new file mode 100644 (file)
index 0000000..d7f0193
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/perl 
+
+# dailystats_wap3.pl
+# NDC Code Release 1
+#
+# Connects to the server holding the stats, and builds a web page
+# of yesterdays players
+# CGI-Parameters:
+#       start:          First entry displayed
+#       limit:          Number of entries. Defaults to 10.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#use strict;
+require 5.002;
+use DBI;
+use CGI;
+
+my $CGIquery;
+
+### Var def ###
+$CGIquery = new CGI;
+$start = ($CGIquery->param("start")?$CGIquery->param("start"):0);
+$limit = ($CGIquery->param("limit")?$CGIquery->param("limit"):10);
+
+# Rebuild database, if necessary
+
+$database = "stats";
+$data_source = "DBI:mysql:$database";
+$username = "";
+$password = "";
+$dbh = DBI->connect( $data_source, $username, $password) or die "Can't connect to $data_source\n"; #: $dbh->errstr\n";
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats WHERE mapsplayed > 0");
+$query->execute;
+$rows = $query->rows;
+$query->finish;
+
+$query = $dbh->prepare("SELECT nick ,skill FROM PlayerStats WHERE mapsplayed > 0 ORDER by skill DESC LIMIT $start,$limit");
+$query->execute;
+
+while ($row_hash = $query->fetchrow_hashref) {
+       $name = $row_hash->{nick};
+       $nick{$name} = $name;
+       $skill{$name} = $row_hash->{skill};
+}
+$query->finish;
+$dbh->disconnect;
+
+# Sort
+@sortkey = sort { $skill{$b} <=> $skill{$a} } (keys %nick);
+
+print "Content-Type: text/vnd.wap.wml\n\n";
+
+## Ausgabe ##
+### Header ###
+print '<?xml version="1.0"?>' . "\n"; 
+print '<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">' . "\n\n"; 
+
+print "<wml>\n";
+print "<card id=\"card1\" title=\"Gestern\">\n";
+
+if (($start + 10) < $rows) {
+  $start_next=$start + 10;
+  print "<do type=\"accept\" label=\"Weiter\">\n";
+  print "<go href=\"\/cgi-bin\/quake\/dailystats_wap.pl\?start=$start_next\"\/>\n";
+  print "<\/do>\n";
+}
+
+print "<p>\n";
+
+print "<small>\n";
+print "<table columns=\"3\">\n";
+print "<tr><td>P.<\/td><td>Name<\/td><td>Skill<\/td><\/tr>\n";
+
+$count = $start;
+foreach $name (@sortkey)
+{
+       $count ++;
+       print "<tr>\n";
+       print "<td>$count<\/td>\n";
+       print "<td>";
+       print make_html($nick{$name});
+       print "<\/td>\n";
+       print "<td>$skill{$name}<\/td>\n";
+       print "<\/tr>\n";
+}
+
+print "<\/table></small>\n";
+print "<\/p>\n";
+print "</card>\n";
+print '</wml>';
+
+
+############### Subroutines ###########
+
+sub make_html {
+
+  $input = shift;
+#  $input =~ s/&/und/g;
+  $input =~ s/</&lt\;/g;
+  $input =~ s/>/&gt\;/g;
+  $input =~ s/"/&quot\;/g;
+#  $input =~ s/\|/pipe/g;
+  return $input;
+}
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+
+  return $input;
+}
diff --git a/stats/databasectrl.sh b/stats/databasectrl.sh
new file mode 100644 (file)
index 0000000..1735974
--- /dev/null
@@ -0,0 +1,2 @@
+cat big.res | makedb.pl
+makerank.pl
diff --git a/stats/foreverstats2.pl b/stats/foreverstats2.pl
new file mode 100644 (file)
index 0000000..780476f
--- /dev/null
@@ -0,0 +1,290 @@
+#!/usr/bin/perl 
+
+# foreverstats2.pl
+# NDC Code Release 1
+#
+# Connects to the database holding the statistic data and builds
+# a web page from it.
+# This is old code. The HTML is inlined in it. Hard to read,
+# almost impossible to maintain.
+# CGI-Parameters:
+#       start:          First entry displayed
+#       limit:          Number of entries. Defaults to 20.
+#       sort:           Sort mode.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use DBI;
+use CGI;
+
+my $CGIquery;
+
+### Var def ###
+$CGIquery = new CGI;
+$sort = ($CGIquery->param("sort")?$CGIquery->param("sort"):'0');
+$limit = ($CGIquery->param("limit")?$CGIquery->param("limit"):'20');
+$start = ($CGIquery->param("start")?$CGIquery->param("start"):'0');
+$back = ($CGIquery->param("back")?$CGIquery->param("back"):'0');
+
+# Rebuild database, if necessary
+open (FIRST, "< first.run") || die "Can't open first.run\n";
+while (<FIRST>) {
+       if ($_ == 1) {
+               close (FIRST);
+               open (FIRST, "> first.run") || die "Can't open first.run\n";
+               print FIRST "0\n";
+               close (FIRST);
+               {$update = `databasectrl.sh`}
+       }
+}
+close (FIRST);
+
+$database = "stats";
+$data_source = "DBI:mysql:$database";
+$username = "";
+$password = "";
+$dbh = DBI->connect( $data_source, $username, $password) or die "Can't connect to $data_source\n"; #: $dbh->errstr\n";
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats WHERE fe_skill > 0");
+$query->execute;
+$rows = $query->rows;
+$query->finish;
+
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats");
+$query->execute;
+$rowsall = $query->rows;
+$query->finish;
+
+
+
+$query = $dbh->prepare("SELECT nick ,fe_skill, fe_kills, fe_victims, fe_suicides, fe_mapsplayed, fe_mapswon, fe_time, fe_fph, date_format(LastSeen, '%d.%m.%Y') as date_europe FROM PlayerStats WHERE fe_skill > 0 ORDER by fe_skill DESC LIMIT $start,$limit");
+$query->execute;
+
+while ($row_hash = $query->fetchrow_hashref) {
+       $name = $row_hash->{nick};
+       $nick{$name} = $name;
+       $skill{$name} = $row_hash->{fe_skill};
+       $kills{$name} = $row_hash->{fe_kills};
+       $victims{$name} = $row_hash->{fe_victims};
+       $suicides{$name} = $row_hash->{fe_suicides};
+       $maps{$name} = $row_hash->{fe_mapsplayed};
+       $wonmaps{$name} = $row_hash->{fe_mapswon};
+       $time{$name} = $row_hash->{fe_time};
+       $fph{$name} = $row_hash->{fe_fph};
+       $lastseen{$name} = $row_hash->{date_europe};
+       unless(defined($lastseen{$name})) { $lastseen{$name} = '--.--.--'; }
+}
+$query->finish;
+$dbh->disconnect;
+
+
+
+print "Content-Type: text/html\n\n\n";
+
+
+###### Sortieren #####
+
+# By default, sort by rank
+
+if ($sort eq "0") {
+  @sortkey = sort { $skill{$b} <=> $skill{$a} } (keys %nick);
+  $sortname = "Skill";
+  $darstellung = "\= Kills \/ \( 1 \+ Victims \+ Suicides \) \* \( 1 \+ \( Maps-won \/ Maps-played \)";
+}
+
+
+
+if ($sort eq "1") {
+  @sortkey = sort { $nick{$a} cmp $nick{$b} } (keys %nick);
+  $sortname = "Nick";
+  $darstellung = "";
+}
+
+if ($sort eq "2") {
+  @sortkey = sort { $maps{$b} <=> $maps{$a} } (keys %maps);
+  $sortname = "gespielten Maps";
+  $darstellung = "";
+}
+
+if ($sort eq "3") {
+  @sortkey = sort { $kills{$b} <=> $kills{$a} } (keys %kills);
+  $sortname = "Kills";
+  $darstellung = "";
+}
+
+if ($sort eq "4") {
+  @sortkey = sort { $victims{$b} <=> $victims{$a} } (keys %victims);
+  $sortname = "Victims";
+  $darstellung = "";
+}
+
+if ($sort eq "5") {
+  @sortkey = sort { $suicides{$b} <=> $suicides{$a} } (keys %suicides);
+  $sortname = "Suicides";
+  $darstellung = "";
+}
+
+if ($sort eq "6") {
+  @sortkey = sort { $fph{$b} <=> $fph{$a} } (keys %fph);
+  $sortname = "FPH";
+  $darstellung = "\= Kills \/ \(Sec \/ 3600 \)";
+}
+
+if ($sort eq "7") {
+  @sortkey = sort { $time{$b} <=> $time{$a} } (keys %nick);
+  $sortname = "Zeit";
+  $darstellung = "";
+}
+
+if ($sort eq "8") {
+  @sortkey = sort { $wonmaps{$b} <=> $wonmaps{$a} } (keys %nick);
+  $sortname = "gewonnenen Maps";
+  $darstellung = "";
+}
+## Ausgabe ##
+### Header ###
+print '<HTML><HEAD><TITLE>Cardassia - Hall of Fame</TITLE>';
+print '<META NAME="Andreas Ulbrich \+ Ralf Ertzinger">';
+print '</HEAD><BODY BGCOLOR="#FFFFFF">';
+print "\n<CENTER><img SRC=\"http\:\/\/www.ndc.sh\/graphics\/halloffame_logo.jpg\" WIDTH=\"500\" HEIGHT=\"90\" BORDER=\"0\"ALT=\"\[SERVER Hall of Fame\]\"><\/CENTER>\n";
+
+print "<CENTER><b>Erfasste Spieler gesamt: $rowsall <BR>Anzahl der Spieler mit mehr als 10 Maps: $rows<\/B><BR>\n";
+if ($back == 0) {
+       print "<b><a href =\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=0\&limit\=$rows\&back\=1\">$rows Spieler anzeigen<\/A><\/B><\/CENTER><\/BR>\n";
+}
+else {
+       print "<b><a href =\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=0\&limit\=20\&back\=0\">Die ersten 20 anzeigen<\/A><\/B><\/CENTER><\/BR>\n";
+}
+
+
+##### Sortiert nach sortkey ########
+
+print "<P>\&nbsp\;<P><UL><b>Sortiert nach $sortname $darstellung<\/b>\n";
+print "<table BORDER=\"0\">\n";
+print "<tr>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Rang<\/b><\/td>
+\n";
+print "<td WIDTH=\"120\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=1\&limit=$limit\&back=$back\">Name<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=0\&limit=$limit\&back=$back\">Skill<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=6\&limit=$limit\&back=$back\">FPH<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=2\&limit=$limit\&back=$back\">Maps gespielt<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=8\&limit=$limit\&back=$back\">Maps gewonnen<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=3\&limit=$limit\&back=$back\">Kills<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=4\&limit=$limit\&back=$back\">Victims<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=5\&limit=$limit\&back=$back\">Suicides<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"50\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b><a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort\=7\&limit=$limit\&back=$back\">Zeit (Min)<\/a><\/b><\/td>\n";
+print "<td WIDTH=\"100\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Zuletzt gespielt<\/b><\/td>\n";
+print "<\/tr>\n";
+
+$count = $start;
+foreach $name (@sortkey)
+{
+       
+       $count ++;
+       print "<tr>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"+0\">$count<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#CCCCCC\"><font size =\"+0\">";
+       print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/playerstats.pl\?nick\=";
+       print make_compatible($nick{$name});
+       print "\">";
+       print "<font color\=\"#000000\">";
+       print make_html($nick{$name});
+       print "<\/font>";
+       print "<\/a><\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$skill{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$fph{$name}<\/font><\/td>\n";
+
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$maps{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$wonmaps{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$kills{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$victims{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$suicides{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$time{$name}<\/font><\/td>\n";
+       print "<td ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\"><font size =\"-1\">$lastseen{$name}<\/font><\/td>\n";
+       print "<\/tr>\n";
+}
+
+print "<\/TABLE><\/UL><P>\n";
+
+if ($back == 0) {
+  print "<CENTER><TABLE BORDER=\"0\">\n";
+  print "<tr>\n";
+  print "<td WIDTH=\"200\" ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">";
+  if ($start != 0) {
+    $start_prev = $start - $limit;
+    if ($start_prev < 0) {$start_prev = 0;}
+    print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort=$sort&start=$start_prev&limit=$limit&back=0\">";
+    print "Zur&uuml;ck";
+    print "<\/a>\n";
+  } else {
+    print "Zur&uuml;ck";
+  }
+  print "<\/td>\n";
+  print "<td WIDTH=\"200\" ALIGN=\"CENTER\" BGCOLOR=\"\#EEEEEE\">";
+  if ($start + $limit < $rows) {
+    $start_next = $start + $limit;
+    print "<a href=\"http\:\/\/www.ndc.sh\/cgi-bin\/quake\/foreverstats2.pl\?sort=$sort&start=$start_next&limit=$limit&back=0\">";
+    print "Weiter";
+    print "<\/a>\n";
+  } else {
+    print "Weiter";
+  }
+  print "<\/td>\n";
+  print "<\/tr>\n";
+  print "<\/TABLE><\/CENTER>\n";
+}
+
+print "<P><FONT SIZE=\"-2\"><DIV ALIGN=right>Skripting by NDC Code<BR><A href=\"http://www.ndc.sh\" target=\"_top\">www.ndc.sh</A></DIV></FONT><BR>\n";
+print '</BODY></HTML>';
+
+
+############### Subroutines ###########
+
+sub make_html {
+
+  $input = shift;
+#  $input =~ s/&/und/g;
+  $input =~ s/</&lt\;/g;
+  $input =~ s/>/&gt\;/g;
+  $input =~ s/"/&quot\;/g;
+  $input =~ s/\x1c/&middot;/g;
+#  $input =~ s/\|/pipe/g;
+  return $input;
+}
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+  $input =~ s/\x1c/%1C/g;
+
+  return $input;
+}
diff --git a/stats/foreverstats3.pl b/stats/foreverstats3.pl
new file mode 100644 (file)
index 0000000..17cef4c
--- /dev/null
@@ -0,0 +1,240 @@
+#!/usr/bin/perl -w
+
+# foreverstats3.pl
+# NDC Code Release 1
+#
+# Connects to the database holding the statistic data. Builds a
+# web page based on a template file.
+# This script has limited functionality compared to foreverstats2,
+# bus has _much_ cleaner code.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+use strict;
+use CGI;
+use CGI::Debug (report => 'everything', on => 'warnings');
+use DBI;
+
+# Define some variables
+my $template_path = "templates";
+my $scriptpath = "http://www.ndc.sh/cgi-bin/quake/foreverstats3.pl";
+my $template_file;
+my @main_source;
+my %variables;
+my @playerdata;
+
+my $CGI_query;
+
+# Info about the script
+$variables{parser_selfinfo} =  "<!--\nThis is the [NDC] foreverstats script, Release 3.0.\n" .
+                               "Featuring support for selectable viewlimits and player highlighting.\n" .
+                               "Parsing-Engine: Lilith, Version 1.1.\n" .
+                               "Output is HTML 4.01 strict compliant.\n\n".
+                               "Original Release by [NDC]Maria.\n" .
+                               "Rewrite by [NDC]Sundancer.\n" .
+                               "Lilith by [NDC]Sundancer.\n" .
+                               "Source code is available. Contact ndccode\@ndc.sh or see http://www.ndc.sh/ndccode.\n" .
+                               "//-->";
+$variables{scriptpath} = $ENV{REQUEST_URI};
+
+sub parse {
+
+       # This is Lilith. Takes an array on input, and parses it line by line,
+       # printing the result to STDOUT.
+
+       # Variables
+       my $template_line;
+       my @parser_comment;
+       my @looparray;
+       my $comment;
+       my $fullcomment;
+       my $replacement;
+       my $loop_variable;
+       my $in_loop_players = 0;
+
+       LOOP: while ($template_line = shift) {
+
+               if ($template_line =~ /^\s*\<!--loop [\w_]+--\>/) {
+                       ($loop_variable) = ($template_line =~ /<!--loop ([\w_]+)--\>/);
+                       if ($loop_variable eq "players") {
+                               $in_loop_players = 1;
+                       }
+                       next LOOP;
+               }
+
+               if ($template_line =~ /^\s*\<!--endloop [\w_]+--\>/) {
+                       ($loop_variable) = ($template_line =~ /<!--endloop ([\w_]+)--\>/);
+                       if ($loop_variable eq "players") {
+                               $in_loop_players = 0;
+
+                               # Unroll the loop.
+                               for (my $i=0;$i<scalar(@playerdata);$i++) {
+                                       $variables{'parser_playerrank'} = $i+1;
+                                       $variables{'parser_playername'} = make_compatible(@{$playerdata[$i]}->[0]);
+                                       $variables{'parser_playerskill'} = @{$playerdata[$i]}->[1];
+                                       $variables{'parser_playerfph'} = @{$playerdata[$i]}->[2];
+                                       $variables{'parser_playermapsplayed'} = @{$playerdata[$i]}->[3];
+                                       $variables{'parser_playermapswon'} = @{$playerdata[$i]}->[4];
+                                       $variables{'parser_playerkills'} = @{$playerdata[$i]}->[5];
+                                       $variables{'parser_playervictims'} = @{$playerdata[$i]}->[6];
+                                       $variables{'parser_playersuicides'} = @{$playerdata[$i]}->[7];
+                                       $variables{'parser_playertime'} = @{$playerdata[$i]}->[8];
+                                       $variables{'parser_playerlastseen'} = @{$playerdata[$i]}->[9];
+                                       parse(@looparray);
+                               }
+                       }
+                       next LOOP;
+               }
+
+               # If we are in loopmode, copy lines into an array for later parsing.
+               if ($in_loop_players == 1) {
+                       push @looparray, $template_line;
+                       next LOOP;
+               }
+
+               @parser_comment = ($template_line =~ /\<!--\$([\w_]+)--\>/g);
+               foreach $comment ( @parser_comment) {
+                       if(defined($variables{$comment})) {
+                               $fullcomment = "\\<!--\\\$" . $comment . "--\\>";
+                               $replacement = $variables{$comment};
+                               $template_line =~ s/$fullcomment/$replacement/g;
+                       }
+               }
+               print $template_line;
+       }
+}
+               
+sub main {
+
+       # Main routine.
+
+       my $template;
+
+       $CGI_query = new CGI;
+       $template = ($CGI_query->param('template')?$CGI_query->param('template'):'/foreverstatsstrict.template');
+       $template_file = $template_path;
+       if ($template =~ /\W/) {
+               # template file name contains illegal characters
+               $template_file .= "/forerverstatsstrict.template";
+       } else {
+               $template_file .= $template . ".template";
+       }
+
+       if ( ! -e $template_file) {
+               $template_file = $template_path . "/foreverstatsstrict.template";
+       }
+
+       # Read the contents of the templatefile
+       open(TEMPLATE, $template_file) or die "Could not open template file: $!\n";
+       @main_source = <TEMPLATE>;
+       close(TEMPLATE);
+       GetPlayerData();
+       print "Content-Type: text/html\n\n";
+       parse(@main_source);
+}
+
+sub buildsqlquery {
+
+       # Evaluates the parameters and constructs a SQL-query.
+
+       my $operator;
+       my $field;
+       my $value;
+       my $sql_query;
+
+       my %operatormapping = ( 'mehrgleich' => '>=',
+                               'wenigergleich' => '<=',
+                               'gleich' => '=',
+                               'mehr' => '>',
+                               'weniger' => '<' );
+
+       my %fieldmapping = (    'Mapsplayed' => 'fe_MapsPlayed',
+                               'Mapswon' => 'fe_MapsWon',
+                               'Kills' => 'fe_Kills',
+                               'Victims' => 'fe_Victims',
+                               'Suicides' => 'fe_Suicides' );
+
+       $operator = ($CGI_query->param('sel_operator')?$CGI_query->param('sel_operator'):'mehrgleich');
+       $field = ($CGI_query->param('sel_field')?$CGI_query->param('sel_field'):'50');
+       $value = ($CGI_query->param('sel_number')?$CGI_query->param('sel_number'):'mehrgleich');
+
+       if(defined($operatormapping{$operator})) {
+               $operator = $operatormapping{$operator};
+       } else {
+               $operator = $operatormapping{'mehrgleich'};
+       }
+
+       if(defined($fieldmapping{$field})) {
+               $field = $fieldmapping{$field};
+       } else {
+               $field = $fieldmapping{'Mapsplayed'};
+       }
+
+       unless($value=~/\d+/) {
+               $value = 50;
+       }
+
+       # Build the Query. Hiho.
+       $sql_query = 'SELECT nick, fe_skill, fe_fph, fe_mapsplayed, fe_mapswon, fe_kills, fe_victims, fe_suicides, fe_time, date_format(LastSeen, \'%d.%m.%Y\') as date_europe FROM PlayerStats WHERE (' . $field . $operator . $value . ') ORDER BY fe_skill DESC LIMIT 20';
+
+       return $sql_query;
+}
+
+sub GetPlayerData {
+
+       # Get the players from the database.
+
+       my $sql_handle;
+       my $sql_query;
+       my $sql_querystring;
+       my @row;
+       my $i=0;
+
+       my $sql_user = "";
+       my $sql_pass = "";
+
+       $sql_handle = DBI->connect("DBI:mysql:NDC",$sql_user,$sql_pass) or die;
+       $sql_querystring = buildsqlquery();
+       $sql_query = $sql_handle->prepare($sql_querystring);
+       $sql_query->execute or die;
+
+       while (@row = $sql_query->fetchrow_array) {
+               $playerdata[$i++] = [ @row ];
+       }
+       $sql_query->finish;
+       $sql_handle->disconnect;
+}
+
+sub make_compatible {
+
+       # Takes a string. Converts all suspicious characters into HTML.
+       
+       my $input;
+
+       $input = shift;
+       $input =~ s/&/&amp;/g;
+       $input =~ s/\x1c/&middot;/g;
+       $input =~ s/</&lt;/g;
+       $input =~ s/>/&gt;/g;
+       $input =~ s/"/&quot;/g;
+       return $input;
+}
+
+
+# This is the main program.
+
+main();
diff --git a/stats/foreverstats_wap.pl b/stats/foreverstats_wap.pl
new file mode 100644 (file)
index 0000000..e5222df
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/perl 
+
+# foreverstats_wap.pl
+# NDC Code Release 1
+#
+# Connects to the database holding the stats, and builds a WAP-Page
+# from it.
+# CGI-Parameters:
+#       start:          First entry displayed
+#       limit:          Number of entries. Defaults to 10.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use DBI;
+use CGI;
+
+my $CGIquery;
+
+### Var def ###
+$CGIquery = new CGI;
+$start = ($CGIquery->param("start")?$CGIquery->param("start"):0);
+$limit = ($CGIquery->param("limit")?$CGIquery->param("limit"):10);
+
+# Rebuild database, if necessary
+
+$database = "stats";
+$data_source = "DBI:mysql:$database";
+$username = "";
+$password = "";
+$dbh = DBI->connect( $data_source, $username, $password) or die "Can't connect to $data_source\n"; #: $dbh->errstr\n";
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats WHERE fe_skill > 0");
+$query->execute;
+$rows = $query->rows;
+$query->finish;
+
+$query = $dbh->prepare("SELECT nick ,skill FROM PlayerStats WHERE fe_skill > 0 ORDER by fe_skill DESC LIMIT $start,$limit");
+$query->execute;
+
+while ($row_hash = $query->fetchrow_hashref) {
+       $name = $row_hash->{nick};
+       $nick{$name} = $name;
+       $skill{$name} = $row_hash->{skill};
+}
+$query->finish;
+$dbh->disconnect;
+
+# Sort
+@sortkey = sort { $skill{$b} <=> $skill{$a} } (keys %nick);
+
+print "Content-Type: text/vnd.wap.wml\n\n\n";
+
+
+
+## Ausgabe ##
+### Header ###
+print '<?xml version="1.0"?>' . "\n"; 
+print '<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">' . "\n"; 
+
+print "<wml>\n";
+print "<card id=\"card1\" title=\"Ewige Stats\">\n";
+if ($start!=0) {
+  $start_prev=$start - 10;
+  if ($start_prev<0) {$start_prev=0;}
+  print "<do type=\"accept\" label=\"Zur&#252;ck\">\n";
+  print "<go href=\"\/cgi-bin\/quake\/foreverstats_wap.pl\?start=$start_prev\"\/>\n";
+  print "<\/do>\n";
+}
+
+if (($start + 10) < $rows) {
+  $start_next=$start + 10;
+  print "<do type=\"accept\" label=\"Weiter\">\n";
+  print "<go href=\"\/cgi-bin\/quake\/foreverstats_wap.pl\?start=$start_next\"\/>\n";
+  print "<\/do>\n";
+}
+
+print "<do type=\"accept\" label=\"Gestern\">\n";
+print "<go href=\"\/cgi-bin\/quake\/dailystats_wap.pl\"\/>\n";
+print "<\/do>\n";
+
+print "<do type=\"accept\" label=\"Navigation\">\n";
+print "<go href=\"\/nav.wml\"\/>\n";
+print "<\/do>\n";
+
+print "<do type=\"accept\" label=\"Hauptseite\">\n";
+print "<go href=\"\/\"\/>\n";
+print "<\/do>\n";
+
+print "<p>\n";
+
+print "<small>\n";
+print "<table columns=\"3\">\n";
+print "<tr><td>P.<\/td><td>Name<\/td><td>Skill<\/td><\/tr>\n";
+
+$count = $start;
+foreach $name (@sortkey)
+{
+       $count ++;
+       print "<tr>\n";
+       print "<td>$count<\/td>\n";
+       print "<td>";
+       print make_html($nick{$name});
+       print "<\/td>\n";
+       print "<td>$skill{$name}<\/td>\n";
+       print "<\/tr>\n";
+}
+
+print "<\/table></small>\n";
+print "<\/p>\n";
+print "<\/card>\n";
+print "<\/wml>";
+
+
+############### Subroutines ###########
+
+sub make_html {
+
+  $input = shift;
+#  $input =~ s/&/und/g;
+  $input =~ s/</&lt\;/g;
+  $input =~ s/>/&gt\;/g;
+  $input =~ s/"/&quot\;/g;
+#  $input =~ s/\|/pipe/g;
+  return $input;
+}
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+
+  return $input;
+}
diff --git a/stats/foreverstatsstrict.template b/stats/foreverstatsstrict.template
new file mode 100644 (file)
index 0000000..e85e08f
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+
+<!--$parser_selfinfo-->
+
+<HTML>
+
+<HEAD>
+  <TITLE>NDC Foreverstats</TITLE>
+  <META NAME="Author" CONTENT="Andreas Ulbrich">
+  <META NAME="Author" CONTENT="Ralf Ertzinger">
+  
+<link rel="stylesheet" href="/css/ndcstrict.css" media="screen" type="text/css">
+<style type="text/css">
+<!--
+.globalinfo {  font-weight: bold; text-align: center}
+.tableheader {  background-color: #FFFFCC; text-align: center}
+.namecolumn {  font-size: smaller; background-color: #CCCCCC; width: 120px; text-align: center}
+.othercolumn {  font-size: smaller; background-color: #EEEEEE; width: 50px; text-align: center}
+.sortedby {  text-align: left; font-weight: bold}
+-->
+</style></HEAD>
+
+
+<BODY>
+  
+<p class="image"> <img SRC="/graphics/halloffame_logo.jpg" WIDTH="500" HEIGHT="90" ALT="[Hall of Fame]"> 
+</p>
+<p class="globalinfo">Erfasste Spieler gesamt:<br>
+  Anzahl der Spieler mit mehr als xx Maps:</p>
+<form method="post" action="<!--$scriptpath-->">
+  <p class="globalinfo">
+  Zeige Spieler mit 
+  <select name="sel_operator">
+    <option value="mehrgleich" selected>&gt;=</option>
+    <option value="gleich">=</option>
+    <option value="wenigergleich">&lt;=</option>
+    <option value="mehr">&gt;</option>
+    <option value="weniger">&lt;</option>
+  </select>
+  <input type="text" name="sel_number" maxlength="20" value="50">
+  <select name="sel_field">
+    <option value="Mapsplayed" selected>gespielten Maps</option>
+    <option value="Mapswon">gewonnenen Maps</option>
+    <option value="Kills">Kills</option>
+    <option value="Victims">Victims</option>
+    <option value="Suicides">Suicides</option>
+  </select>
+  <input type="submit" name="Submit" value="Go go go">
+  </p>
+</form>
+<p class="globalinfo">&nbsp;</p>
+<p class="sortedby">Sortiert nach Skill = Kills / ( 1 + Victims + Suicides ) * 
+  ( 1 + ( Maps-won / Maps-played )</p>
+<table border="0">
+  <tr class="tableheader"> 
+    <td>Rang</td>
+    <td>Name</td>
+    <td>Skill</td>
+    <td>FPH</td>
+    <td>Maps gespielt</td>
+    <td>Maps gewonnen</td>
+    <td>Kills</td>
+    <td>Victims</td>
+    <td>Suicides</td>
+    <td>Zeit (Min)</td>
+    <td>Zuletzt gespielt</td>
+  </tr>
+<!--loop players-->
+  <tr>
+    <td class="othercolumn"><!--$parser_playerrank--></td>
+    <td class="namecolumn"><!--$parser_playername--></td>
+    <td class="othercolumn"><!--$parser_playerskill--></td>
+    <td class="othercolumn"><!--$parser_playerfph--></td>
+    <td class="othercolumn"><!--$parser_playermapsplayed--></td>
+    <td class="othercolumn"><!--$parser_playermapswon--></td>
+    <td class="othercolumn"><!--$parser_playerkills--></td>
+    <td class="othercolumn"><!--$parser_playervictims--></td>
+    <td class="othercolumn"><!--$parser_playersuicides--></td>
+    <td class="othercolumn"><!--$parser_playertime--></td>
+    <td class="othercolumn"><!--$parser_playerlastseen--></td>
+  </tr>
+<!--endloop players-->
+</table>
+<p class="globalinfo">&nbsp;</p>
+<p class="credits">
+    Skripting by NDC Code<BR>
+    <A href="http://www.ndc.sh">www.ndc.sh</A>
+  </p>
+</BODY>
+</HTML>
diff --git a/stats/makedb.pl b/stats/makedb.pl
new file mode 100644 (file)
index 0000000..560bd67
--- /dev/null
@@ -0,0 +1,171 @@
+#!/bin/perl -w
+
+# makedb.pl
+# NDC Code Release 1
+#
+# Read preprocessed GS-Logs from STDIN, and flush them into a SQL-Database
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+use DBI;
+
+# Define SQL-Variables
+
+$sql_database = "stats";
+$sql_db_table = "PlayerStats";
+$sql_datasource = "DBI:mysql:$sql_database";
+$sql_username = "";
+$sql_password = "";
+$sql_db_handle = DBI->connect($sql_datasource, $sql_username, $sql_password) or die "Could not connect to database.\n";
+
+# Load player data
+
+@gslog = <STDIN>;
+
+# Load a list of players who are _not_ updated.
+if ( -r "noupdate") {
+       open(NOUPDATE,"noupdate") or die "Could not open noupdate: $!\n";
+       @noupdate = <NOUPDATE>;
+       close(NOUPDATE);
+       chomp(@noupdate);
+       print "List of players not being updated by specific request:\n";
+       print join("\n", @noupdate);
+       print "\n";
+       %noupdate = ();
+       foreach $nick (@noupdate) { $noupdate{$nick} = 1 }
+}
+
+# First, delete all players who didn't play within the last 100 days
+
+print "Deleting players...\n";
+
+$sql_query = $sql_db_handle->prepare("DELETE from $sql_db_table WHERE TO_DAYS(NOW()) - TO_DAYS(LastSeen) > 100");
+$sql_query->execute or die "Could not delete datasets.";
+$sql_query->finish;
+
+# Flush data from previous day (in fact, flush only 'mapsplayed'. The
+# DailyStats.pl script will ignore these datasets for table generation.
+
+print "Flushing datasets...\n";
+
+$sql_query = $sql_db_handle->prepare("UPDATE $sql_db_table SET MapsPlayed=0, fe_rank=0");
+$sql_query->execute or die "Could not flush database.\n";
+$sql_query->finish;
+
+# Process data
+
+print "Processing...\n";
+
+LOOP: while ($gslog_line = shift(@gslog)) {
+
+  ($pl_nick,$pl_kills,$pl_victims,$pl_suicides,$pl_maps_played,$pl_maps_won,$pl_time) = split(":",$gslog_line);
+
+  # Check if the player is on the "noupdate" list. Skip it then.
+  if (defined($noupdate{$pl_nick})) {
+       print "Skipping $pl_nick due to noupdate.";
+       shift @gslog;
+       next LOOP;
+  }
+
+  if (($pl_nick ne "") & ($pl_time > 60) & ($pl_maps_played != 0)) {
+
+    # Check if there is already a dataset for this player.
+    # If not, init all values, and create an entry.
+
+    $sql_query = $sql_db_handle->prepare("SELECT nick FROM $sql_db_table WHERE nick=?");
+    $sql_query->execute($pl_nick);
+    $sql_result = $sql_query->fetchrow_hashref;
+    $sql_query->finish;
+
+    unless (defined($sql_result)) {
+      $sql_query = $sql_db_handle->prepare("INSERT INTO $sql_db_table (Nick, Email, Picture, Homepage, Skill, Skill_top, Kills, Victims, Suicides, MapsPlayed, MapsWon, Time, FPH, fe_Skill, fe_Kills, fe_Victims, fe_Suicides, fe_MapsPlayed, fe_MapsWon, fe_Time, fe_FPH, LastSeen) VALUES (?, '', 'empty.jpg', '', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', NOW())");
+      $sql_query->execute($pl_nick) or die "Could not insert dataset for $pl_nick\n";
+      $sql_query->finish;
+    }
+
+    # Load the dataset
+
+    $sql_query = $sql_db_handle->prepare("SELECT Skill, Skill_top, Kills, Victims, Suicides, MapsPlayed, MapsWon, Time, FPH, fe_Skill, fe_Kills, fe_Victims, fe_Suicides, fe_MapsPlayed, fe_MapsWon, fe_Time, fe_FPH FROM $sql_db_table WHERE nick=?");
+    $sql_query->execute($pl_nick);
+    $sql_result = $sql_query->fetchrow_hashref;
+
+    $pl_sql_skill = $sql_result->{Skill};
+    $pl_sql_skill_top = $sql_result->{Skill_top};
+    $pl_sql_kills = $sql_result->{Kills};
+    $pl_sql_victims = $sql_result->{Victims};
+    $pl_sql_suicides = $sql_result->{Suicides};
+    $pl_sql_mapsplayed = $sql_result->{MapsPlayed};
+    $pl_sql_mapswon = $sql_result->{MapsWon};
+    $pl_sql_time = $sql_result->{"Time"};
+    $pl_sql_fph = $sql_result->{FPH};
+    $pl_sql_fe_skill = $sql_result->{fe_Skill};
+    $pl_sql_fe_kills = $sql_result->{fe_Kills};
+    $pl_sql_fe_victims = $sql_result->{fe_Victims};
+    $pl_sql_fe_suicides = $sql_result->{fe_Suicides};
+    $pl_sql_fe_mapsplayed = $sql_result->{fe_MapsPlayed};
+    $pl_sql_fe_mapswon = $sql_result->{fe_MapsWon};
+    $pl_sql_fe_time = $sql_result->{fe_Time};
+    $pl_sql_fe_fph = $sql_result->{fe_FPH};
+
+    $sql_query->finish; 
+
+    $pl_skill = ($pl_kills / ($pl_victims + $pl_suicides + 1)) * (1 + ($pl_maps_won / $pl_maps_played));
+    $pl_fph = ($pl_kills * 3600) / $pl_time; 
+    $pl_time = $pl_time / 60;
+
+    # Flush the data into the fields
+
+    $pl_sql_skill = $pl_skill;
+    $pl_sql_kills = $pl_kills;
+    $pl_sql_victims = $pl_victims;
+    $pl_sql_suicides = $pl_suicides;
+    $pl_sql_mapsplayed = $pl_maps_played;
+    $pl_sql_mapswon = $pl_maps_won;
+    $pl_sql_time = $pl_time;
+    $pl_sql_fph = $pl_fph;
+
+    $pl_sql_fe_kills += $pl_kills;
+    $pl_sql_fe_victims += $pl_victims;
+    $pl_sql_fe_suicides += $pl_suicides;
+    $pl_sql_fe_mapsplayed += $pl_maps_played;
+    $pl_sql_fe_mapswon += $pl_maps_won;
+    $pl_sql_fe_time += $pl_time;
+    $pl_sql_fe_fph = ($pl_sql_fe_kills * 60) / $pl_sql_fe_time;
+    $pl_sql_fe_skill = ($pl_sql_fe_kills / ($pl_sql_fe_victims + $pl_sql_fe_suicides + 1)) * (1 + ($pl_sql_fe_mapswon / $pl_sql_fe_mapsplayed));
+    if ($pl_sql_fe_mapsplayed < 10) {
+      $pl_sql_fe_skill = 0;
+    }
+    if ($pl_sql_fe_skill > $pl_sql_skill_top) {
+      $pl_sql_skill_top = $pl_sql_fe_skill;
+    }
+
+    $sql_query = $sql_db_handle->prepare("UPDATE $sql_db_table SET Skill='$pl_sql_skill', Skill_top='$pl_sql_skill_top', Kills='$pl_sql_kills', Victims='$pl_sql_victims', Suicides='$pl_sql_suicides', MapsPlayed='$pl_sql_mapsplayed', MapsWon='$pl_sql_mapswon', Time='$pl_sql_time', FPH='$pl_sql_fph', fe_Skill='$pl_sql_fe_skill', fe_kills='$pl_sql_fe_kills', fe_Victims='$pl_sql_fe_victims', fe_Suicides='$pl_sql_fe_suicides', fe_MapsPlayed='$pl_sql_fe_mapsplayed', fe_MapsWon='$pl_sql_fe_mapswon', fe_Time='$pl_sql_fe_time', fe_FPH='$pl_sql_fe_fph', LastSeen=NOW() WHERE nick=?");
+    $sql_query->execute($pl_nick) or die "Could not update entry: $pl_nick\n";
+    $sql_query->finish;
+  }
+
+  shift @gslog;
+
+}
+
+$sql_db_handle->disconnect;
+
+print "Finished.\n";
+
+exit(0);
+
diff --git a/stats/makerank.pl b/stats/makerank.pl
new file mode 100644 (file)
index 0000000..b2a8d2c
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/perl 
+
+# makerank.pl
+# NDC Code Release 1
+#
+# Updates the rank field in the stats database.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use DBI;
+
+### Var def ###
+
+$database = "stats";
+$data_source = "DBI:mysql:$database";
+$username = "";
+$password = "";
+$dbh = DBI->connect( $data_source, $username, $password) or die "Can't connect to $data_source\n"; #: $dbh->errstr\n";
+
+
+$query = $dbh->prepare("SELECT nick FROM PlayerStats WHERE fe_skill > 0 ORDER by fe_skill DESC");
+$query->execute;
+
+$rank = 1;
+
+while ($row_hash = $query->fetchrow_hashref) {
+       $name = $row_hash->{nick};
+       $nick{$name} = $name;
+       $rank{$name} = $rank++;
+}
+
+$query->finish;
+
+foreach $name (%nick) {
+
+  $sql_query_string = "UPDATE PlayerStats SET fe_rank=? WHERE nick=?";
+  $sql_query=$dbh->prepare($sql_query_string);
+  $sql_query->execute($rank{$name},$nick{$name});
+  $sql_query->finish;
+}
+
+$dbh->disconnect;
+
diff --git a/stats/playerstats.pl b/stats/playerstats.pl
new file mode 100644 (file)
index 0000000..47af3fb
--- /dev/null
@@ -0,0 +1,299 @@
+#!/usr/bin/perl 
+
+# playerstats.pl
+# NDC Code Release 1
+# CGI-Parameters:
+#      nick:   Player name
+#
+# Displays a web page showing the stats for one player, displaying
+# a picture, mail address and web page.
+#
+#   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#use strict;
+require 5.002;
+use DBI;
+use CGI;
+
+my $CGIquery;
+
+### Var def ###
+$CGIquery = new CGI;
+$picturepath = 'http://www.ndc.sh/graphics/playerdb/';
+$nick = $CGIquery->param("nick");
+
+# Define SQL-Variables
+
+$sql_database = "stats";
+$sql_datasource = "DBI:mysql:$sql_database";
+$sql_username = "";
+$sql_password = "";
+$sql_db_handle = DBI->connect($sql_datasource, $sql_username, $sql_password) or die "Could not connect to database.\n";
+
+
+print "Content-Type: text/html\n\n\n";
+
+# Retrieve player data from SQL
+
+$sql_query_string = "SELECT nick, email, picture, homepage, kills, victims, suicides, mapsplayed, mapswon, FPH, skill, time, skill_top, fe_skill, fe_kills, fe_victims, fe_suicides, fe_mapsplayed, fe_mapswon, fe_fph, fe_time, fe_rank, date_format(LastSeen, '%d.%m.%Y') as date_europe FROM PlayerStats WHERE nick=?";
+$sql_query = $sql_db_handle->prepare($sql_query_string);
+$sql_query->execute($nick);
+
+$sql_row = $sql_query->fetchrow_hashref;
+
+$pl_name = $sql_row->{nick};
+$pl_email = $sql_row->{email};
+$pl_picture = $picturepath . $sql_row->{picture};
+$pl_homepage = $sql_row->{homepage};
+$pl_kills = $sql_row->{kills};
+$pl_victims = $sql_row->{victims};
+$pl_suicides = $sql_row->{suicides};
+$pl_fph = $sql_row->{FPH};
+$pl_skill = $sql_row->{skill};
+$pl_time = $sql_row->{time};
+$pl_maps_played = $sql_row->{mapsplayed};
+$pl_maps_won = $sql_row->{mapswon};
+$pl_fe_kills = $sql_row->{fe_kills};
+$pl_fe_victims = $sql_row->{fe_victims};
+$pl_fe_suicides = $sql_row->{fe_suicides};
+$pl_fe_maps_played= $sql_row->{fe_mapsplayed};
+$pl_fe_maps_won = $sql_row->{fe_mapswon};
+$pl_fe_skill = $sql_row->{fe_skill};
+$pl_fe_fph = $sql_row->{fe_fph};
+$pl_fe_time = $sql_row->{fe_time};
+$pl_skill_top = $sql_row->{skill_top};
+$pl_fe_rank = $sql_row->{fe_rank};
+$pl_lastseen = $sql_row->{date_europe};
+
+$sql_query->finish;
+
+$sql_db_handle->disconnect;
+
+## Ausgabe ##
+### Header ###
+print '<HTML><HEAD><TITLE>NDC Spielerdaten</TITLE>';
+print '<META NAME="Andreas Ulbrich">';
+print '</HEAD><BODY BGCOLOR="#FFFFFF">';
+print "\n<CENTER><img SRC=\"http:\/\/www.ndc.sh\/graphics\/aktuell_logo.jpg\" WIDTH=\"300\" HEIGHT=\"90\" BORDER=\"0\"ALT=\"\[SERVER Status\]\"><\/CENTER>\n";
+print "\&nbsp\;<P>\n";
+if (defined($eingabe{showquery})) {
+  print "<pre>\n";
+  print "SQL-Query:\n";
+  print "$sql_query_string\n";
+  print "</pre>";
+}
+print "<UL><table BORDER=\"0\">\n";
+print "<tr>\n";
+print "<td WIDTH=\"270\" ALIGN=\"CENTER\" BGCOLOR=\"\#FFFFCC\"><b>Spielerdaten<\/b><\/td>\n";
+print "<\/TABLE><\/UL>\n";
+
+if (defined($pl_name)) {
+  print "<UL><table BORDER=\"0\">\n";
+  print "<tr>\n";
+  print "<td ROWSPAN=\"10\" VALIGN=\"TOP\"><img src \=\"$pl_picture\" WIDTH=\"186\" HEIGHT=\"300\" BORDER=\"0\"><\/td>";
+  print "<td WIDTH=\"120\" BGCOLOR=\"\#CCCCCC\">Nickname:<\/td>";
+  print "<td WIDTH=\"200\" BGCOLOR=\"\#EEEEEE\"><b>" . make_html($pl_name) . "<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">email:<\/td>";
+  if ($pl_email ne "") {
+    print "<td BGCOLOR=\"#EEEEEE\"><b><a href=\"mailto:$pl_email\">$pl_email<\/a><\/b><\/td>\n";
+  } else {
+    print "<td BGCOLOR=\"#EEEEEE\"><b>-<\/b><\/td>\n";
+  }
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Homepage:<\/td>";
+  if ($pl_homepage ne "") {
+    print "<td BGCOLOR=\"#EEEEEE\"><b><a href=\"$pl_homepage\" TARGET=\"xxyyzz\">$pl_homepage<\/a><\/b><\/td>\n";
+  } else {
+    print "<td BGCOLOR=\"#EEEEEE\"><b>-<\/b><\/td>\n";
+  }
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Kills:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_fe_kills<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Victims:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_fe_victims<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Suicides:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_fe_suicides<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Skill:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_fe_skill<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">H&ouml;chster Skill:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_skill_top<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Rang:<\/td>";
+  if ($pl_fe_rank != 0) {
+    print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_fe_rank<\/b><\/td>\n";
+  } else {
+    print "<td BGCOLOR=\"#EEEEEE\"><b>-<\/b><\/td>\n";
+  }
+  print "<\/tr>\n";
+
+  print "<tr>\n";
+  print "<td BGCOLOR=\"#CCCCCC\">Zuletzt gespielt:<\/td>";
+  print "<td BGCOLOR=\"#EEEEEE\"><b>$pl_lastseen<\/b><\/td>\n";
+  print "<\/tr>\n";
+
+  print "<\/TABLE><\/UL>\n";
+
+  print "<P>&nbsp;<P>\n";
+  print "<UL><b>Gestern<\/b><br>\n";
+  print "<TABLE border=\"0\">\n";
+  print "<tr>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"100\">Map<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Skill<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">FPH<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Maps gespielt<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Maps gewonnen<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Kills<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Victims<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Suicides<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Zeit (Min)<\/td>\n";
+  print "<\/tr>\n";
+
+  if ($pl_maps_played > 0) {
+
+    print "<tr>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#CCCCCC\">Total<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_skill<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fph<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_maps_played<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_maps_won<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_kills<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_victims<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_suicides<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_time<\/td>\n";
+    print "<\/tr>\n";
+
+  } else {
+
+    print "<tr>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#CCCCCC\">Total<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">-<\/td>\n";
+    print "<\/tr>\n";
+
+  }
+
+  print "<\/TABLE><\/UL>\n";
+
+
+  print "<P>&nbsp;<P>\n";
+  print "<UL><b>Gesamt<\/b><br>\n";
+  print "<TABLE border=\"0\">\n";
+  print "<tr>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"100\">Map<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Skill<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">FPH<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Maps gespielt<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Maps gewonnen<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Kills<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Victims<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Suicides<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#FFFFCC\" WIDTH=\"50\">Zeit (Min)<\/td>\n";
+  print "<\/tr>\n";
+
+
+  print "<tr>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#CCCCCC\">Total<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_skill<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_fph<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_maps_played<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_maps_won<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_kills<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_victims<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_suicides<\/td>\n";
+  print "<td ALIGN=\"CENTER\" BGCOLOR=\"#EEEEEE\">$pl_fe_time<\/td>\n";
+  print "<\/tr>\n";
+
+  print "<\/TABLE><\/UL>\n";
+
+  print "<P>&nbsp;<P>\n";
+  print "<UL>Suche bei <a href=\"http\:\/\/www.theclq.com\/asp\/find.asp\?name=";
+  print make_compatible($pl_name);
+  print "\" TARGET=\"_blank\">The CLQ<\/a><\/ul>\n";
+  
+
+} else {
+
+  print "<ul>Es wurde kein Spieler dieses Namens in der Datenbank gefunden.</ul>\n";
+
+}
+  
+print "<P><FONT SIZE=\"-2\"><DIV ALIGN=right>Skripting by NDC Code<BR><A href=\"http://www.ndc.sh\" target=\"_top\">www.ndc.sh</A></DIV></FONT><BR>\n";
+
+print '</BODY></HTML>';
+
+
+####### Subroutines #####
+
+sub make_html {
+
+  $input = shift;
+#  $input =~ s/&/und/g;
+  $input =~ s/</&lt\;/g;
+  $input =~ s/>/&gt\;/g;
+  $input =~ s/"/&quot\;/g;
+  $input =~ s/\x1c/&middot;/g;
+#  $input =~ s/\|/pipe/g;
+  return $input;
+}
+
+sub make_compatible {
+
+  $input = shift;
+  $input =~ s/%/%25/g;
+  $input =~ s/\+/%2B/g;
+  $input =~ s/ /+/g;
+  $input =~ s/,/%2C/g;
+  $input =~ s/</%3C/g;
+  $input =~ s/>/%3E/g;
+  $input =~ s/#/%23/g;
+  $input =~ s/\[/%5B/g;
+  $input =~ s/\]/%5D/g;
+  $input =~ s/\//%2F/g;
+  $input =~ s/\|/%7C/g;
+  $input =~ s/\?/%3F/g;
+  $input =~ s/\x1c/%1C/g;
+
+  return $input;
+}
+
diff --git a/stats/stats.sql b/stats/stats.sql
new file mode 100644 (file)
index 0000000..c45892e
--- /dev/null
@@ -0,0 +1,29 @@
+# --------------------------------------------------------
+#
+# Table structure for table 'PlayerStats'
+# CREATE TABLE PlayerStats (
+   Nick varchar(30) NOT NULL,
+   Email varchar(60),
+   Picture varchar(50) NOT NULL,
+   Homepage varchar(100),
+   Skill float(10,3) DEFAULT '0.000' NOT NULL,
+   Skill_top float(10,3) DEFAULT '0.000' NOT NULL,
+   Kills int(11) DEFAULT '0' NOT NULL,
+   Victims int(11) DEFAULT '0' NOT NULL,
+   Suicides int(11) DEFAULT '0' NOT NULL,
+   MapsPlayed int(11) DEFAULT '0' NOT NULL,
+   MapsWon int(11) DEFAULT '0' NOT NULL,
+   Time int(11) DEFAULT '0' NOT NULL,
+   FPH float(10,2) DEFAULT '0.00' NOT NULL,
+   fe_Skill float(10,3) DEFAULT '0.000' NOT NULL,
+   fe_Kills int(11) DEFAULT '0' NOT NULL,
+   fe_Victims int(11) DEFAULT '0' NOT NULL,
+   fe_Suicides int(11) DEFAULT '0' NOT NULL,
+   fe_MapsPlayed int(11) DEFAULT '0' NOT NULL,
+   fe_MapsWon int(11) DEFAULT '0' NOT NULL,
+   fe_Time int(11) DEFAULT '0' NOT NULL,
+   fe_FPH float(10,2) DEFAULT '0.00' NOT NULL,
+   fe_rank int(11) DEFAULT '0' NOT NULL,
+   LastSeen date DEFAULT '0000-00-00' NOT NULL,
+   PRIMARY KEY (Nick)
+);