/[james]/t2matchlog/t2matchlog
ViewVC logotype

Contents of /t2matchlog/t2matchlog

Parent Directory Parent Directory | Revision Log Revision Log


Revision 47 - (show annotations) (download)
Thu Jan 22 23:53:16 2004 UTC (20 years, 3 months ago) by james
File size: 24287 byte(s)
Bug fixes and configurable html extension.

1 #!/bin/perl -W
2
3 use strict;
4 use GD;
5
6 die "Usage: perl $0 logfile outputdir" unless @ARGV == 2;
7 open LOG, $ARGV[0] or die "Failed to open $ARGV[0]: $!";
8 my $outdir = $ARGV[1];
9 mkdir $outdir or die "Failed to create output directory $outdir: $!";
10 my $dir = $0;
11 $dir =~ s#(^|/)[^/]+$#$1#;
12 (system "cp ${dir}t2matchlog.css $outdir/") == 0 or die "Failed to copy stylesheet: $!";
13
14 $/ = "\r\n";
15 $| = 1;
16
17 my $near0 = 70;
18 my $near1 = 200;
19 my $thumbsize = 400;
20 my $html_extension = '';
21
22 # from damageTypes.cs
23 my @DamageTypeText;
24 $DamageTypeText[0] = 'default';
25 $DamageTypeText[1] = 'blaster';
26 $DamageTypeText[2] = 'plasma';
27 $DamageTypeText[3] = 'chaingun';
28 $DamageTypeText[4] = 'disc';
29 $DamageTypeText[5] = 'grenade';
30 $DamageTypeText[6] = 'laser';
31 $DamageTypeText[7] = 'ELF';
32 $DamageTypeText[8] = 'mortar';
33 $DamageTypeText[9] = 'missile';
34 $DamageTypeText[10] = 'shocklance';
35 $DamageTypeText[11] = 'mine';
36 $DamageTypeText[12] = 'explosion';
37 $DamageTypeText[13] = 'impact';
38 $DamageTypeText[14] = 'ground';
39 $DamageTypeText[15] = 'turret';
40 $DamageTypeText[16] = 'plasma turret';
41 $DamageTypeText[17] = 'AA turret';
42 $DamageTypeText[18] = 'ELF turret';
43 $DamageTypeText[19] = 'mortar turret';
44 $DamageTypeText[20] = 'missile turret';
45 $DamageTypeText[21] = 'clamp turret';
46 $DamageTypeText[22] = 'spike turret';
47 $DamageTypeText[23] = 'sentry turret';
48 $DamageTypeText[24] = 'out of bounds';
49 $DamageTypeText[25] = 'lava';
50 $DamageTypeText[26] = 'shrike blaster';
51 $DamageTypeText[27] = 'belly turret';
52 $DamageTypeText[28] = 'bomber bomb';
53 $DamageTypeText[29] = 'tank chaingun';
54 $DamageTypeText[30] = 'tank mortar';
55 $DamageTypeText[31] = 'satchel charge';
56 $DamageTypeText[32] = 'MPB missile';
57 $DamageTypeText[33] = 'lighting';
58 $DamageTypeText[35] = 'ForceField';
59 $DamageTypeText[36] = 'Crash';
60 $DamageTypeText[98] = 'nexus camping';
61 $DamageTypeText[99] = 'suicide';
62
63 my $icon_player = load_image("${dir}icons/com_player_grey_24x.png");
64 my %icon;
65 $icon{'flag'} = load_image("${dir}icons/com_icon_flag_outside.png");
66 $icon{'gen'} = load_image("${dir}icons/com_icon_generator.png");
67 $icon{'turret'} = load_image("${dir}icons/com_icon_turretbase.png");
68 $icon{'inv'} = load_image("${dir}icons/com_icon_inventory.png");
69 $icon{'sensor'} = load_image("${dir}icons/com_icon_sensor.png");
70 $icon{'vpad'} = load_image("${dir}icons/com_icon_vehicle_inventory.png");
71 $icon{'solar'} = load_image("${dir}icons/com_icon_solar_gen.png");
72
73 my %colour = ('S' => 0xffff00, 'A' => 0xff8000, 'KK' => 0x00ff00, 'K' => 0xff0000,
74 'KS' => 0xff0000,
75 'L' => 0xff8000, 'F+' => 0x00ffff, 'F-' => 0xff00ff, 'P' => 0xff8000,
76 'V' => 0xffff00, 'W' => 0xff0000, 'G' => 0x0080ff, 'J' => 0x00ff80,
77 'GG' => 0x0080ff, 'JJ' => 0x00ff80,
78 'C' => 0x00ff00, 'R' => 0x00ff00);
79 my $colour_me = 0xffffff;
80 my %desc = ('S' => 'spawned on team $team_name[$p1]',
81 'A' => '$p1 armour',
82 'KK' => 'killed $enemy using $DamageTypeText[$p2]',
83 'K' => 'killed by $DamageTypeText[$p2] $enemy',
84 'KS' => 'killed himself using $DamageTypeText[$p2]',
85 'L' => 'left the game',
86 'F+' => '${melink}took the $team_name[$p1] flag',
87 'F-' => '${melink}dropped the $team_name[$p1] flag',
88 'P' => '$p1',
89 'V' => 'vehicle created',
90 'W' => 'vehicle destroyed',
91 'G' => 'entered " . vehicle_link($p1) . " as ${seat{$p2}}',
92 'J' => 'ejected from vehicle',
93 'GG' => '<a href=\'" . safe_name($p1) . $html_extension . "#t$time\'>$p1</a> entered as ${seat{$p2}}',
94 'JJ' => '<a href=\'" . safe_name($p1) . $html_extension . "#t$time\'>$p1</a> ejected',
95 'C' => '<strong>${melink}captured the $team_name[$p1] flag!</strong>',
96 'R' => '${melink}returned the $team_name[$p1] flag',);
97 my @teamcol = (0xffffff, 0x0000ff, 0xff00ff);
98 my %seat = ('' => 'a passenger', 'p' => 'pilot', 'w' => 'gunner');
99 my %veh_name = ('bomberflyer' => 'Bomber',
100 'hapcflyer' => 'Havoc',
101 'mobilebasevehicle' => 'MPB',
102 'scoutflyer' => 'Shrike',
103 'assaultvehicle' => 'Tank',
104 'scoutvehicle' => 'Wildcat');
105
106 my ($mission, $mission_type, $mission_name, $mission_type_name, $x0, $y0, $width, $height);
107 my (@landmarks, @waypoints);
108
109 print "reading data";
110 read_header();
111
112 my @events = ();
113 my @coords = ();
114 my %score = ();
115 my %kills = ();
116 my %deaths = ();
117 my %grabs = ();
118 my %caps = ();
119 my %returns = ();
120 my %player = ();
121 my %vehicle = ();
122 my %team = ();
123 my $end_time;
124 my (@final_score, @team_name);
125 my %flag = ();
126 my @flag_coords = ();
127
128 read_data();
129 print ".\n";
130
131 my $imall = create_image();
132
133 my $player;
134 foreach $player (keys %player) {
135 print "$player";
136 write_player_report($player);
137 print ".\n";
138 }
139 my $vehicle;
140 foreach $vehicle (keys %vehicle) {
141 my ($team, $name) = split / /, $vehicle, 2;
142 print "$team_name[$team] $veh_name{$name}s";
143 write_vehicle_report($name, $team);
144 print ".\n";
145 }
146 my $team;
147 foreach $team (keys %flag) {
148 print "$team_name[$team] flag";
149 write_flag_report($team);
150 print ".\n";
151 }
152 write_summary_report();
153
154 exit;
155
156 ####################################################################################################
157
158 sub read_header {
159 $mission = <LOG>; chomp $mission;
160 $mission_type = <LOG>; chomp $mission_type;
161 $mission_name = <LOG>; chomp $mission_name;
162 $mission_type_name = <LOG>; chomp $mission_type_name;
163 my $area = <LOG>; chomp $area; ($x0, $y0, $width, $height) = split / /, $area;
164
165 while (($_ = <LOG>) ne $/) {
166 chomp;
167 my ($team, $type, $block, $name, $x, $y, $z, $desc) = split / /, $_, 8;
168 $x -= $x0; $y = $height - $y + $y0;
169 if ($type eq 'StaticShape' and $block eq 'GeneratorLarge') {
170 push @landmarks, "$z gen $team $x $y";
171 } elsif ($type eq 'Turret' and $block eq 'TurretBaseLarge') {
172 push @landmarks, "$z turret $team $x $y";
173 } elsif ($type eq 'StaticShape' and $block eq 'ExteriorFlagStand') {
174 push @landmarks, "$z flag $team $x $y";
175 } elsif ($type eq 'StaticShape' and $block eq 'StationVehicle') {
176 push @landmarks, "$z vpad $team $x $y";
177 } elsif ($type eq 'StaticShape' and $block eq 'StationInventory') {
178 push @landmarks, "$z inv $team $x $y";
179 } elsif ($type eq 'StaticShape' and $block eq 'SensorLargePulse') {
180 push @landmarks, "$z sensor $team $x $y";
181 } elsif ($type eq 'StaticShape' and $block eq 'SolarPanel') {
182 push @landmarks, "$z solar $team $x $y";
183 } elsif ($type eq 'WayPoint' and $block eq 'WayPointMarker') {
184 push @waypoints, "$team $x $y $z $desc";
185 }
186 }
187
188 # sort by height for nicer plotting
189 @landmarks = sort { my ($az, $ra) = split / /, $a, 2; my ($bz, $rb) = split / /, $b, 2;
190 return $az <=> $bz; } @landmarks;
191 }
192
193 ####################################################################################################
194
195 sub read_data {
196 my $time = 0;
197 my %name = ();
198 my @flag_carrier;
199 my %player_veh;
200 my %player_flag;
201
202 while (<LOG>) {
203 chomp;
204 if ($_ eq '') {
205 $time++;
206 next;
207 }
208
209 my ($cmd, $params) = split / /, $_, 2;
210
211 if ($cmd eq 'S') { # player spawned
212 my ($id, $team, $name) = split / /, $params, 3;
213 $name{$id} = $name;
214 push @events, [$time, 'S', $name, $team];
215 $player{$name} = 1;
216 $team{$name} = $team;
217 $player_veh{$name} = 0;
218
219 } elsif ($cmd eq 'K') { # player killed
220 my ($victim, $killer, $weapon) = split / /, $params;
221 next unless exists $name{$victim};
222 $deaths{$name{$victim}}++;
223 $kills{$name{$killer}}++ if exists $name{$killer};
224 push @events, [$time, 'K', $name{$victim}, $name{$killer}, $weapon];
225 push @events, [$time, 'KK', $name{$killer}, $name{$victim}, $weapon]
226 if exists $name{$killer} and $killer != $victim;
227 if (exists $name{$killer} and $player_veh{$name{$killer}}) {
228 push @events, [$time, 'KK', $name{$player_veh{$name{$killer}}},
229 $name{$victim}, $weapon];
230 }
231 delete $player_flag{$name{$victim}};
232 # if (defined $player_veh{$name}) TODO
233 # delete $name{$victim};
234
235 } elsif ($cmd eq 'L') { # player left
236 my ($id, $score) = split / /, $params;
237 next unless exists $name{$id};
238 push @events, [$time, 'L', $name{$id}];
239 $score{$name{$id}} += $score;
240 delete $name{$id};
241
242 } elsif ($cmd eq 'A') { # armour changed
243 my ($id, $armour) = split / /, $params;
244 push @events, [$time, 'A', $name{$id}, $armour];
245
246 } elsif ($cmd eq 'I') { # inventory changed
247 my ($id, $item, $count) = split / /, $params;
248 if ($item =~ m/(Pack|SatchelCharge|Deployable)$/ and $count == 1) {
249 $item =~ s/(Pack|Deployable)$/ pack/;
250 push @events, [$time, 'P', $name{$id}, $item];
251 }
252
253 } elsif ($cmd eq 'D') { # player damaged
254 my ($victim, $attacker, $weapon) = split / /, $params;
255
256 } elsif ($cmd eq 'V') { # new vehicle
257 my ($id, $team, $name) = split / /, $params, 3;
258 $name = lc $name;
259 $vehicle{"$team $name"}++;
260 $name{$id} = "$team $name " . $vehicle{"$team $name"};
261 $team{$name{$id}} = $team;
262 push @events, [$time, 'V', $name{$id}];
263
264 } elsif ($cmd eq 'W') { # vehicle destroyed
265 my $id = $params;
266 push @events, [$time, 'W', $name{$id}];
267 #delete $name{$id};
268
269 } elsif ($cmd eq 'Z') { # final score
270 my ($team, $score, $team_name) = split / /, $params, 3;
271 $final_score[$team] = $score;
272 $team_name[$team] = $team_name;
273
274 } elsif ($cmd eq 'F') { # flag position
275 my ($team, @data) = split / /, $params;
276 my $carrier;
277 $flag{$team} = 1;
278 $team{"$team flag"} = $team;
279 $flag_carrier[$team] = 0 unless defined $flag_carrier[$team];
280 if (@data == 3) {
281 my ($x, $y, $z) = @data;
282 $x -= $x0; $y = $height - $y + $y0;
283 ${$coords[$time]}{"$team flag"} = "$x $y $z";
284 $carrier = 0;
285 } else {
286 $carrier = $name{$data[0]};
287 }
288 if ($carrier ne $flag_carrier[$team]) {
289 if ($flag_carrier[$team]) {
290 push @events, [$time, 'F-', $flag_carrier[$team], $team];
291 delete $player_flag{$flag_carrier[$team]};
292 }
293 if ($carrier) {
294 push @events, [$time, 'F+', $carrier, $team];
295 $grabs{$carrier}++;
296 $player_flag{$carrier} = $team;
297 }
298 $flag_carrier[$team] = $carrier;
299 }
300
301 } elsif ($cmd eq 'C') { # flag captured (CTF)
302 my ($team, $id) = split / /, $params;
303 push @events, [$time, 'C', $name{$id}, $team];
304 $flag_carrier[$team] = 0;
305 $caps{$name{$id}}++;
306
307 } elsif ($cmd eq 'R') { # flag returned (CTF)
308 my ($team, $id) = split / /, $params;
309 push @events, [$time, 'R', exists $name{$id} ? $name{$id} : '', $team];
310 $returns{$name{$id}}++ if exists $name{$id};
311
312 } else { # player / vehicle position
313 my $id = $cmd;
314 next unless exists $name{$id};
315 my $name = $name{$id};
316 my ($x, $y, $z, $vehicle, $seat) = split / /, $params;
317 $x -= $x0; $y = $height - $y + $y0;
318 ${$coords[$time]}{$name} = "$x $y $z";
319 next unless defined $player{$name};
320 if ($player_veh{$name} != $vehicle) {
321 if ($player_veh{$name}) {
322 push @events, [$time, 'J', $name];
323 push @events, [$time, 'JJ',
324 $name{$player_veh{$name}}, $name];
325 }
326 if ($vehicle != 0) {
327 push @events, [$time, 'G', $name,
328 $name{$vehicle}, $seat];
329 push @events, [$time, 'GG', $name{$vehicle},
330 $name, $seat];
331 }
332 $player_veh{$name} = $vehicle;
333 }
334 if (exists $player_flag{$name}) {
335 ${$coords[$time]}{$player_flag{$name} . " flag"} = "$x $y $z";
336 }
337 }
338 }
339 $end_time = $time + 1;
340 }
341
342 ####################################################################################################
343
344 sub write_player_report {
345 my $player = shift;
346
347 my $score = exists $score{$player} ? $score{$player} : 0;
348 my $deaths = exists $deaths{$player} ? $deaths{$player} : 0;
349 my $kills = exists $kills{$player} ? $kills{$player} : 0;
350 my $sname = safe_name($player);
351 my $html = create_html($player);
352
353 $html .= <<END;
354 <p>Total score $score, deaths $deaths, kills $kills. <a href="./">Match summary.</a></p>
355 END
356
357 # find spawn / death times
358 my @spawn = map $$_[0], (grep {$$_[2] eq $player and $$_[1] eq 'S'} @events);
359 my @death = map $$_[0], (grep {$$_[2] eq $player and
360 ($$_[1] eq 'K' or $$_[1] eq 'L')} @events);
361 push @spawn, $end_time;
362
363 for (my $life = 0; $life != @spawn - 1; $life++) {
364 my $nicetime = nice_time($spawn[$life]);
365 my $nicedtime = nice_time($death[$life]);
366 my $life1 = $life + 1;
367 $html .= <<END;
368 <div><h2 id="life$life1">Life $life1 ($nicetime - $nicedtime)</h2>
369 <div><a href="${sname}_$life1.png"><img src="s${sname}_$life1.png"
370 alt="" title="Map of life $life1"></a></div>
371 END
372 $html .= player_life($player, "${sname}_$life1.png",
373 $spawn[$life], $spawn[$life1] - 1);
374 $html .= '</div>';
375 }
376
377 save_html(safe_name($player) . $html_extension, $html);
378 }
379
380 ####################################################################################################
381
382 sub player_life {
383 my $player = shift;
384 my $imname = shift;
385 my $time0 = shift;
386 my $time1 = shift;
387
388 my $im = create_image();
389 plot_route($im, $player, $time0, $time1);
390
391 my @evs = grep {$$_[2] eq $player and $time0 <= $$_[0] and $$_[0] <= $time1} @events;
392 my $html = write_events($player, \@evs, $im);
393
394 save_image($im, $imname);
395 undef $im;
396
397 return $html;
398 }
399
400 ####################################################################################################
401
402 sub write_events {
403 my $player = shift;
404 my $evs = shift;
405 my $im = shift;
406
407 my $prev_time = -1;
408 my $html = "<table>\n";
409
410 my $event;
411 foreach $event (@$evs) {
412 my ($time, $ev, $me, $p1, $p2) = @$event;
413
414 my $nicetime = nice_time($time);
415 if ($time == $prev_time) {
416 $html .= '<tr><td></td>';
417 } else {
418 $html .= "<tr id='t$time'><td class='time'>$nicetime</td>";
419 }
420
421 my $melink = '';
422 my $enemy = '';
423 $ev = 'KS' if ($ev eq 'K' and defined $p1 and $p1 eq $player);
424 if (defined $me and $me ne $player) {
425 my $sname_me = safe_name($me);
426 $melink = "<a href='$sname_me$html_extension#t$time'>$me</a> ";
427 }
428 if (defined $p1) {
429 my $sname_en = safe_name($p1);
430 $enemy = "<a href='$sname_en$html_extension#t$time'>$p1</a>";
431 }
432 my $desc = eval '"' . $desc{$ev} . '"';
433 my $hexcol = sprintf "%.6lx", $colour{$ev};
434 $html .= "<td style='color: #$hexcol'>$desc</td></tr>\n";
435
436 if (exists ${$coords[$time]}{$player}) {
437 my ($x, $y, $z) = split / /, ${$coords[$time]}{$player};
438 square($im, $x, $y, 8, $colour{$ev});
439 } elsif (exists ${$coords[$time - 1]}{$player}) {
440 my ($x, $y, $z) = split / /, ${$coords[$time - 1]}{$player};
441 square($im, $x, $y, 8, $colour{$ev});
442 }
443 $prev_time = $time;
444 }
445
446 $html .= "</table>\n";
447
448 return $html;
449 }
450
451 ####################################################################################################
452
453 sub plot_route {
454 my $image = shift;
455 my $name = shift;
456 my $t0 = shift;
457 my $t1 = shift;
458 my %near = ();
459 for (my $t = $t0; $t != $t1; $t++) {
460 my $s = ($t % 10) == 0 ? 2 : 1;
461 if (exists ${$coords[$t]}{$name}) {
462 my ($x0, $y0, $z0) = split / /, ${$coords[$t]}{$name};
463 my $near;
464 foreach $near (keys %near) {
465 if (exists ${$coords[$t]}{$near}) {
466 my ($xn, $yn, $zn) = split / /, ${$coords[$t]}{$near};
467 delete $near{$near} if $near1 < distance($x0, $y0, $z0,
468 $xn, $yn, $zn);
469 } else {
470 delete $near{$near};
471 }
472 }
473 foreach $near (keys %player) {
474 next if $near eq $name;
475 next if exists $near{$near};
476 if (exists ${$coords[$t]}{$near}) {
477 my ($xn, $yn, $zn) = split / /, ${$coords[$t]}{$near};
478 if (distance($x0, $y0, $z0, $xn, $yn, $zn) < $near0) {
479 $near{$near} = 1;
480 line($image, $x0, $y0, $xn, $yn, 0x444444);
481 text($image, $xn, $yn, $near);
482 }
483 }
484 }
485 foreach $near (keys %near) {
486 my ($xn0, $yn0, $zn0) = split / /, ${$coords[$t]}{$near};
487 my $colour = $team{$name} == $team{$near} ? 0x00ff00 : 0xff0000;
488 line($image, $x0, $y0, $xn0, $yn0, 0x444444) if $s == 2;
489 if (exists ${$coords[$t + 1]}{$near}) {
490 my ($xn1, $yn1, $zn1) = split / /,
491 ${$coords[$t + 1]}{$near};
492 line($image, $xn0, $yn0, $xn1, $yn1, $colour);
493 }
494 square($image, $xn0, $yn0, $s, $colour);
495 }
496 if (exists ${$coords[$t + 1]}{$name}) {
497 my ($x1, $y1, $z1) = split / /, ${$coords[$t + 1]}{$name};
498 line($image, $x0, $y0, $x1, $y1, $colour_me);
499 line($imall, $x0, $y0, $x1, $y1, $teamcol[$team{$name}]);
500 }
501 square($image, $x0, $y0, $s, $colour_me);
502 text($image, $x0, $y0, nice_time($t)) if $s == 2;
503 }
504 }
505 }
506
507 ####################################################################################################
508
509 sub write_vehicle_report {
510 my $name = shift;
511 my $team = shift;
512
513 my $sname = safe_name($name);
514 my $html = create_html($team_name[$team] . ' ' . $veh_name{$name} . 's');
515 $html .= '<p><a href="./">Match summary.</a></p>';
516
517 my $run;
518 for ($run = 1; $run != $vehicle{"$team $name"} + 1; $run++) {
519 my @ev = grep {$$_[2] eq "$team $name $run"} @events;
520 my $time0 = ${$ev[0]}[0];
521 my $time1 = ${$ev[-1]}[1] eq 'W' ? ${$ev[-1]}[0] : $end_time;
522 my $nicetime = nice_time($time0);
523 my $nicedtime = nice_time($time1);
524
525 $html .= <<END;
526 <div><h2 id="life$run">$veh_name{$name} $run ($nicetime - $nicedtime)</h2>
527 <div><a href="${team}_${sname}_$run.png"><img src="s${team}_${sname}_$run.png"
528 alt="" title="Map of $veh_name{$name} $run"></a></div>
529 END
530 $html .= player_life("$team $name $run", "${team}_${sname}_$run.png",
531 $time0, $time1);
532 $html .= '</div>';
533 }
534
535 save_html("${team}_$sname$html_extension", $html);
536 }
537
538 ####################################################################################################
539
540 sub vehicle_link {
541 my $s = shift;
542 my ($team, $name, $run) = split / /, $s;
543 return "<a href='${team}_$name$html_extension#life$run'>$team_name[$team] $veh_name{$name} $run</a>";
544 }
545
546 ####################################################################################################
547
548 sub write_flag_report {
549 my $team = shift;
550
551 my $html = create_html($team_name[$team] . ' flag');
552
553 my @grab;
554 my @return;
555
556 my @fevs = grep {($$_[1] eq 'F+' or $$_[1] eq 'F-' or $$_[1] eq 'C' or $$_[1] eq 'R') and
557 $$_[3] == $team} @events;
558 my $event;
559 my $at_stand = 1;
560 foreach $event (@fevs) {
561 if ($at_stand and $$event[1] eq 'F+') {
562 push @grab, $$event[0];
563 $at_stand = 0;
564 } elsif (!$at_stand and ($$event[1] eq 'C' or $$event[1] eq 'R')) {
565 push @return, $$event[0];
566 $at_stand = 1;
567 }
568 }
569 push @return, $end_time;
570
571 for (my $grab = 0; $grab != @grab; $grab++) {
572 my $nicetime = nice_time($grab[$grab]);
573 my $nicedtime = nice_time($return[$grab]);
574 my $grab1 = $grab + 1;
575 $html .= <<END;
576 <div><h2 id="grab$grab1">Grab $grab1 ($nicetime - $nicedtime)</h2>
577 <div><a href="${team}_flag_$grab1.png"><img src="s${team}_flag_$grab1.png"
578 alt="" title="Map of ${team_name[$team]} flag grab $grab1"></a></div>
579 END
580
581 my $im = create_image();
582 plot_route($im, "$team flag", $grab[$grab], $return[$grab] - 1);
583
584 my @fevs;
585 my $carrier = '';
586 foreach $event (grep {$grab[$grab] <= $$_[0] and $$_[0] <= $return[$grab]} @events) {
587 if ($$event[1] eq 'F+' and $$event[3] == $team) {
588 $carrier = $$event[2];
589 } elsif (($$event[1] eq 'F-' or $$event[1] eq 'C' or $$event[1] eq 'R')
590 and $$event[3] == $team) {
591 $carrier = '';
592 } elsif ($$event[1] eq 'K' and $$event[2] eq $carrier) {
593 ;
594 } else {
595 next;
596 }
597 push @fevs, $event;
598 }
599 $html .= write_events("$team flag", \@fevs, $im);
600 $html .= '</div>';
601
602 save_image($im, "${team}_flag_$grab1.png");
603 undef $im;
604 }
605
606 save_html("${team}_flag$html_extension", $html);
607 }
608
609 ####################################################################################################
610
611 sub write_summary_report {
612 my $html = create_html("Match Summary");
613 my $name;
614 my $nicetime = nice_time($end_time);
615 my $i;
616
617 $html .= <<END;
618 <div><a href="Overview.png"><img src="sOverview.png"
619 alt="" title="Overview map"></a></div>
620 <p>Playing time $nicetime</p>
621 <table><tr><th>Final scores</th></tr>
622 END
623 for ($i = 1; $i != @team_name; $i++) {
624 $html .= "<tr><td>${team_name[$i]}</td><td>${final_score[$i]}</td></tr>\n";
625 }
626 $html .= "</table>\n";
627
628 my $team;
629 foreach $team (keys %flag) {
630 $html .= "<p><a href=\"${team}_flag$html_extension\">${team_name[$team]} flag</a></p>\n";
631 }
632
633 $html .= <<END;
634 <h2>Players and Vehicles</h2>
635 <table>
636 <tr><th>Player</th><th>Team</th><th>Score</th><th>Deaths</th><th>Kills</th><th>Grabs</th><th>Caps</th><th>Returns</th></tr>
637 END
638
639 sub lookup {
640 my $hash = shift;
641 my $name = shift;
642 my $max = 0; grep { $max = $_ if $max < $_ } values %$hash;
643 my $n = exists $$hash{$name} ? $$hash{$name} : 0;
644 return $n == $max ? "<td><strong class=\"max\">$n</strong></td>" : "<td>$n</td>";
645 }
646
647 foreach $name (sort keys %player) {
648 my $sname = safe_name($name);
649 $html .= "<tr><td><a href=\"$sname$html_extension\">$name</a></td>" .
650 "<td>$team_name[$team{$name}]</td>" .
651 lookup(\%score, $name) .
652 lookup(\%deaths, $name) .
653 lookup(\%kills, $name) .
654 lookup(\%grabs, $name) .
655 lookup(\%caps, $name) .
656 lookup(\%returns, $name) .
657 "</tr>\n";
658 }
659
660 $html .= "</table>\n";
661
662 if (keys %vehicle) {
663 $html .= "<table><tr><th>Vehicles</th><th>Total used</th></tr>\n";
664 foreach my $vehicle (sort keys %vehicle) {
665 my ($team, $name) = split / /, $vehicle, 2;
666 my $sname = safe_name($name);
667 $html .= <<END;
668 <tr><td><a href="${team}_$sname$html_extension">$team_name[$team] $veh_name{$name}s</a></td><td>${vehicle{"$team $name"}}</td></tr>
669 END
670 }
671 $html .= "</table>\n";
672 }
673
674 save_html("index$html_extension", $html);
675 save_image($imall, 'Overview.png');
676 undef $imall;
677 }
678
679 ####################################################################################################
680
681 sub create_image {
682 my $image = GD::Image->newTrueColor($width, $height);
683 my ($lm, $g);
684 foreach $lm (@landmarks) {
685 my ($z, $type, $team, $x, $y) = split / /, $lm;
686 icon($image, $icon{$type}, $x, $y);
687 }
688 foreach $g (@waypoints) {
689 my ($team, $x, $y, $z, $desc) = split / /, $g, 5;
690 text($image, $x, $y, $desc);
691 }
692 return $image;
693 }
694
695 sub save_image {
696 my $image = shift;
697 my $file = shift;
698 my $png = $image->png;
699 open PNG, ">$outdir/$file" or die "failed to open $outdir/$file: $!";
700 binmode PNG;
701 print PNG $png;
702 close PNG;
703
704 my $max = $width < $height ? $height : $width;
705 my $thumb = GD::Image->newTrueColor($thumbsize * $width / $max,
706 $thumbsize * $height / $max);
707 $thumb->copyResampled($image, 0, 0, 0, 0, $thumbsize * $width / $max,
708 $thumbsize * $height / $max, $width, $height);
709 $png = $thumb->png;
710 open PNG, ">$outdir/s$file" or die "failed to open $outdir/s$file: $!";
711 binmode PNG;
712 print PNG $png;
713 close PNG;
714 }
715
716 sub square {
717 my $image = shift;
718 return unless defined $image;
719 my $x = shift;
720 my $y = shift;
721 my $s = shift;
722 my $colour = shift;
723 $image->filledRectangle($x - $s, $y - $s, $x + $s, $y + $s, $colour);
724 }
725
726 sub line {
727 my $image = shift;
728 return unless defined $image;
729 my $x0 = shift;
730 my $y0 = shift;
731 my $x1 = shift;
732 my $y1 = shift;
733 my $colour = shift;
734 $image->line($x0, $y0, $x1, $y1, $colour);
735 }
736
737 sub load_image {
738 my $file = shift;
739 open PNG, $file or die "failed to open $file: $!";
740 my $im = GD::Image->newFromPng(\*PNG) or die "PNG load of $file failed";
741 close PNG;
742 $im->transparent(0);
743 return $im;
744 }
745
746 sub icon {
747 my $image = shift;
748 my $icon = shift;
749 my $x = shift;
750 my $y = shift;
751 $image->setBrush($icon);
752 $image->setPixel($x, $y, gdBrushed);
753 }
754
755 sub text {
756 my $image = shift;
757 my $x = shift;
758 my $y = shift;
759 my $text = shift;
760 $image->string(gdSmallFont, $x, $y, $text, 0xffffff);
761 }
762
763 ####################################################################################################
764
765 sub create_html {
766 my $title = shift;
767 my $html = <<END;
768 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
769 "http://www.w3.org/TR/html4/strict.dtd">
770 <html>
771 <head>
772 <link rel="stylesheet" type="text/css" href="t2matchlog.css">
773 <title>$title ($mission_name / $mission_type_name)</title>
774 </head>
775
776 <body>
777 <h1>$title <em class="mission">($mission_name / $mission_type_name)</em></h1>
778
779 END
780 return $html;
781 }
782
783 sub save_html {
784 my $file = shift;
785 my $html = shift;
786 $html .= "</body></html>\n";
787 open HTML, ">$outdir/$file" or die "failed to open $outdir/$file: $!";
788 print HTML $html;
789 close HTML;
790 }
791
792 ####################################################################################################
793
794 sub safe_name {
795 my $s = shift;
796 $s =~ tr/a-zA-Z0-9/_/cs;
797 return $s;
798 }
799
800 sub nice_time {
801 my $time = shift;
802 my $secs = $time % 60;
803 return int($time / 60) . ':' . (($secs < 10) ? "0$secs" : $secs);
804 }
805
806 sub distance {
807 return sqrt (($_[0] - $_[3]) ** 2 + ($_[1] - $_[4]) ** 2 + ($_[2] - $_[5]) ** 2);
808 }
809
810 ####################################################################################################
811

  ViewVC Help
Powered by ViewVC 1.1.26