Initial checkin
[ndccode.git] / gs_analyze / gs_analyze2.pl
1 #!/usr/bin/perl -w
2
3 # gs_analyze2.pl
4 # NDC Code Release 1
5 #
6 # Reads a GS-compliant log file from STDIN, writes processed logs
7 # to various files.
8 #
9 #   Copyright (C) 2001 Andreas Ulbrich, Ralf Ertzinger (ndccode@ndc.sh)
10 #
11 #   This program is free software; you can redistribute it and/or modify
12 #   it under the terms of the GNU General Public License as published by
13 #   the Free Software Foundation; either version 2 of the License, or
14 #   (at your option) any later version.
15 #
16 #   This program is distributed in the hope that it will be useful,
17 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 #   GNU General Public License for more details.
20 #
21 #   You should have received a copy of the GNU General Public License
22 #   along with this program; if not, write to the Free Software
23 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25 @gslog=<STDIN>;
26
27 # Enable this line for debugging
28
29 # $debug = 1;
30
31 # Read mapname-mapping from file
32
33 open (MAPNAMES,"mapnames.txt") or die "Could not open mapnames.txt: $!\n";
34
35 # Log file for skill calculation
36 open (SKILLOG, ">skill.log") or die "Could not open skill.log: $!\n";
37
38 while ($line=<MAPNAMES>) {
39
40   ($handle,$mapname) = split (":",$line);
41   chop($mapname);
42   $handle{$mapname} = $handle;
43 }
44
45 close (MAPNAMES); 
46
47 while ($gslog_line = shift(@gslog)) {
48
49   ($killer,$victim,$action,$weapon,$fragdiff,$timestamp,$ping) = 
50   split("\t",$gslog_line);
51  
52   unless (defined($action)) {
53     next;
54   }
55
56   if ($action eq "Kill") {
57     $pl_kills{"##global"}{$killer}++;
58     $pl_kills{$actual_map}{$killer}++;
59     $pl_victims{"##global"}{$victim}++;
60     $pl_victims{$actual_map}{$victim}++;
61     if (defined($pl_count_map{$killer})) {
62       $pl_maps_played{"##global"}{$killer}++;
63       $pl_maps_played{$actual_map}{$killer}++;
64       print "Map count for $killer increased to $pl_maps_played{\"##global\"}{$killer}\n" if $debug;
65       undef $pl_count_map{$killer};
66     }
67     if (defined($pl_count_map{$victim})) {
68       $pl_maps_played{"##global"}{$victim}++;
69       $pl_maps_played{$actual_map}{$victim}++;
70       print "Map count for $victim increased to $pl_maps_played{\"##global\"}{$victim}\n" if $debug;
71       undef $pl_count_map{$victim};
72     }
73     $sys_kills{"##global"}++;
74     $sys_kills{$actual_map}++;
75     $pl_kills_local{$killer}++;
76
77     # Print out skill log
78     print SKILLOG "K:$killer:$victim\n";
79   }
80
81   if ($action eq "Suicide") {
82     $pl_suicides{"##global"}{$killer}++;
83     $pl_suicides{$actual_map}{$killer}++;
84     if (defined($pl_count_map{$killer})) {
85       $pl_maps_played{"##global"}{$killer}++;
86       $pl_maps_played{$actual_map}{$killer}++;
87       print "Map count for $killer increased to $pl_maps_played{\"##global\"}{$killer}\n" if $debug;
88       undef $pl_count_map{$killer};
89     }
90     $sys_suicides{"##global"}++;
91     $sys_suicides{$actual_map}++;
92     $pl_kills_local{$killer}--;
93
94     # Print out skill log
95     print SKILLOG "S:$killer\n";
96   }
97
98   # Check if a new map has been started.
99   # $weapon holds the map name
100
101   if ($action eq "Map") {
102     chop ($weapon);
103     chop ($weapon);
104     $actual_map = $handle{$weapon};
105     unless (defined($actual_map)) {
106       $actual_map = "##undefined";
107     }
108     $sys_maps_played{"##global"}++;
109     $sys_maps_played{$actual_map}++;
110     print "Map started: $actual_map\n" if $debug;
111   }
112
113   # Check for a newly started game.
114
115   if ($action eq "GameStart") {
116     pl_disconnect_all();
117   }
118
119
120   # Check for the end of a map. Calculate map winner.
121   # Log out all players
122
123   if ($action eq "GameEnd") {
124     print "Map ends: $actual_map\n" if $debug;
125     $sys_connect_total{"##global"} += $timestamp;
126     $sys_connect_total{$actual_map} += $timestamp;
127     $pl_best_frags = 0;
128     undef $pl_best_nick;
129     if (defined(%pl_kills_local)) {
130       foreach $nick (keys %pl_kills_local) {
131         if ($pl_kills_local{$nick} > $pl_best_frags) {
132           $pl_best_frags = $pl_kills_local{$nick};
133           $pl_best_nick = $nick;
134         }
135       }
136       if (defined($pl_best_nick)) {
137         $pl_maps_won{"##global"}{$pl_best_nick}++;
138         $pl_maps_won{$actual_map}{$pl_best_nick}++;
139         print "$pl_best_nick wins $actual_map with $pl_best_frags\n" if $debug;
140       }
141     }
142     pl_disconnect_all();
143
144     # Print out skill log
145     if (defined($pl_best_nick)) {               # If no one won the map, why bother?
146       print SKILLOG "W:$pl_best_nick\n";
147     } 
148   }
149
150
151   # Check for a newly connecting player. Initialize all fields, if necessary.
152   # $weapon holds player name.
153
154   if ($action eq "PlayerConnect") {
155
156     pl_connect($weapon);
157
158   }
159
160
161   # If a player disconnects, log his online time.
162   # $weapon holds the player name.
163
164   if ($action eq "PlayerLeft") {
165
166     pl_disconnect($weapon);
167
168   }
169
170
171   # If a player renames himself, consider this a disconnect and immediate
172   # reconnect.
173   # $weapon holds the old name, $fragdiff the new one.
174   # Preserve frags in the local map! Important for winning caclulations
175   # WARNING! We might get into trouble here. If a player wins a map,
176   # and renames during the ending music, the "new" player will win the
177   # map (since he inherits the kills), but the map will not count as
178   # played (since he was neither fragged, nor fragged another player).
179   # PS: this is not theoretical ;)
180
181   if ($action eq "PlayerRename") {
182
183     $tmp = $pl_kills_local{$weapon};
184     print "$weapon renamed to $fragdiff, inheriting $tmp\n" if $debug;
185     # If the map counts for the "leaving" player, decrease
186     # his mapcount, and increase the count of the "connecting" player.
187     unless(defined($pl_count_map{$weapon})) {
188       $pl_maps_played{"##global"}{$weapon}--;
189       $pl_maps_played{$actual_map}{$weapon}--;
190       print "Map count for $weapon decreased to $pl_maps_played{\"##global\"}{$weapon}\n" if $debug;
191     }
192     pl_disconnect($weapon);
193     pl_connect($fragdiff);
194     unless(defined($pl_count_map{$weapon})) {
195       $pl_maps_played{"##global"}{$fragdiff}++;
196       $pl_maps_played{$actual_map}{$fragdiff}++;
197       print "Map count for $fragdiff increased to $pl_maps_played{\"##global\"}{$fragdiff}\n" if $debug;
198     }
199     $pl_kills_local{$fragdiff} = $tmp;
200   }
201
202 }
203
204 # Just to be sure....
205
206 pl_disconnect_all();
207
208 # Write out all results. Phew.
209
210 foreach $mapkey (keys %pl_kills) {
211
212   if ($mapkey eq "##global") {
213     $filename = "big.res";
214   } else {
215     $filename = $mapkey . ".res";
216   }
217   
218
219   open(LOGFILE, ">$filename") or die "Could not open $filename: $!\n";
220
221   select LOGFILE;
222
223   # Print final results. First line holds overall system statistics.
224
225   print ":";
226   print "$sys_kills{$mapkey}:";
227   print ":";
228   print "$sys_suicides{$mapkey}:";
229   print "$sys_maps_played{$mapkey}:";
230   print ":";
231   print "$sys_connect_total{$mapkey}:";
232   print "\n";
233
234   foreach $nick (keys %{ $pl_kills{$mapkey} }) {
235
236     print "$nick:";
237     print "$pl_kills{$mapkey}{$nick}:";
238     print "$pl_victims{$mapkey}{$nick}:";
239     print "$pl_suicides{$mapkey}{$nick}:";
240     print "$pl_maps_played{$mapkey}{$nick}:";
241     print "$pl_maps_won{$mapkey}{$nick}:";
242     print "$pl_connect_total{$mapkey}{$nick}:";
243     print "\n";
244
245   }
246
247   select STDOUT;
248
249   close (LOGFILE);
250
251 }
252
253
254 ###### - Subroutines
255
256 sub pl_connect() {
257
258   $pl_name = shift;
259   return unless defined($pl_name);
260
261   # Reduce the player name to the first 15 characters. You want that.
262   # Believe me.
263
264   $pl_name = substr($pl_name, 0, 15);
265
266   print "Player connected: $pl_name\n" if $debug;
267
268   $pl_kills{"##global"}{$pl_name} = 0 unless defined($pl_kills{"##global"}{$pl_name});
269   $pl_kills{$actual_map}{$pl_name} = 0 unless defined($pl_kills{$actual_map}{$pl_name});
270
271   $pl_victims{"##global"}{$pl_name} = 0 unless defined($pl_victims{"##global"}{$pl_name});
272   $pl_victims{$actual_map}{$pl_name} = 0 unless defined($pl_victims{$actual_map}{$pl_name});
273
274   $pl_suicides{"##global"}{$pl_name} = 0 unless defined($pl_suicides{"##global"}{$pl_name});
275   $pl_suicides{$actual_map}{$pl_name} = 0 unless defined($pl_suicides{$actual_map}{$pl_name});
276
277   $pl_maps_played{"##global"}{$pl_name} = 0 unless defined($pl_maps_played{"##global"}{$pl_name});
278   $pl_maps_played{$actual_map}{$pl_name} = 0 unless defined($pl_maps_played{$actual_map}{$pl_name});
279
280   $pl_maps_won{"##global"}{$pl_name} = 0 unless defined($pl_maps_won{"##global"}{$pl_name});
281   $pl_maps_won{$actual_map}{$pl_name} = 0 unless defined($pl_maps_won{$actual_map}{$pl_name});
282
283
284
285   # If the player reconnects before a map change, don't count as
286   # a played map
287   # This flag is reset by pl_disconnect_all().
288
289   unless (defined($pl_connect{$pl_name})) {
290     $pl_count_map{$pl_name} = 1;
291   }
292
293   $pl_connect{$pl_name} = 1;
294   $pl_kills_local{$pl_name} = 0;
295   $pl_connect_start{"##global"}{$pl_name} = $timestamp;
296   $pl_connect_start{$actual_map}{$pl_name} = $timestamp;
297 }
298
299 # ----------------------
300
301 sub pl_disconnect {
302
303   $pl_name = shift;
304   return unless defined($pl_name);
305
306   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;
307
308   $pl_connect_total{"##global"}{$pl_name} += ($timestamp - $pl_connect_start{"##global"}{$pl_name});
309   $pl_connect_total{$actual_map}{$pl_name} += ($timestamp - $pl_connect_start{$actual_map}{$pl_name});
310   $pl_connect_start{"##global"}{$pl_name} = -1;
311   delete $pl_kills_local{$pl_name};
312 }
313
314 # ----------------------
315
316 sub pl_disconnect_all {
317
318   foreach $name (keys %pl_connect) {
319
320     undef $pl_connect{$name};
321     undef $pl_count_map{$name};
322     if ($pl_connect_start{"##global"}{$name} >= 0) {
323       pl_disconnect($name);
324     }
325     undef %pl_kills_local;
326   }
327 }