game => 'StarCraft II LotV',
major => 2,
},
+ index => 'bw',
+ 1 => 'bw',
+ 2 => 'lotv',
);
-$Request ||= 'bw';
-$Request = 'lotv' if $Request eq '2';
-my %scver = %{ $scvers{$Request} }
- or Abort("Requested version $Request not available", '404 unknown');
+my $requestver = $scvers{$Request ||= 'index'}
+ or Html(), Abort("Requested version <q>$Request</q> not available", '404 request not found');
-my $datafile = "sc-units-$Request.inc.pl";
+if (ref $requestver ne 'HASH') {
+ $header{Location} = "/sc/$requestver";
+ Abort("Canonical URL for $Request is at $requestver", '302 subpage alias');
+}
+
+my %scver = %{$requestver};
+my $datafile = "sc-units-$Request";
Html({
title => "$scver{title} unit cheat sheet",
- version => '1.2',
+ version => '1.4',
description => [
"Reference of $scver{game} unit properties,"
. " comparing various statistics of all the units in $scver{name}"
],
stylesheet => [qw( light dark )],
raw => '<link rel="stylesheet" type="text/css" media="all" href="/sc.css?1.2">',
- data => [$datafile],
+ data => ["$datafile.inc.pl"],
});
say "<h1>$scver{game} units</h1>\n";
-my $units = do $datafile;
-Abort("Cannot open unit data", 501, $_) for $@ || $! || ();
+my $units = Data($datafile);
my $patch = shift @{$units}
or Abort("Cannot open unit data: metadata not found", 501);
if $attack->{type} eq 'implosive';
if (my @bonus = sort grep { !/^-/ } keys %{ $attack->{bonus} }) {
$out .= sprintf('<span class="%s" title="%s">≥</span>',
- (map {
+ (
$_ eq 'light' ? 'unit-s' :
$_ eq 'armored' ? 'unit-l' :
$_ eq 'organic' ? 'unit-o' :
$_ eq 'massive' ? 'unit-h' :
$_ eq 'shields' ? 'unit-shield' :
+ $_ eq 'structure' ? 'unit-x' :
'',
- } join '_', @bonus),
- join(', ', map {(
+ ),
+ (
sprintf('+%s vs %s',
showrangeint(
$attack->{bonus}->{$_},
- $attack->{bonus}->{$_} + $attack->{bonus}->{"-$_"} * 3,
+ ($upattack->{bonus} // $attack->{bonus})->{$_}
+ + ($upattack->{bonus} // $attack->{bonus})->{"-$_"} * 3,
),
$_,
),
- )} @bonus),
- );
+ ),
+ ) for @bonus;
}
$out .= '<span class="unit-pdd" title="projectile">•</span>'
if $attack->{type} eq 'projectile';
my $specials = $row->{special} or return '';
return join ' ', map {
sprintf '<span%s title="%s">%s</span>',
- $_->{duration} < 0 && ' class="magic-perma"',
join('',
- $_->{name},
+ $_->{duration} < 0 && ' class="magic-perma"',
+ $_->{detect} && ' class="unit-detect"',
+ ),
+ join('',
+ $_->{name} // $_->{alt},
$_->{desc} ? ": $_->{desc}" : '',
(map { $_ && " ($_)" } join ', ',
#TODO: apply upgrades
$_->{transform},
) :
!defined $_->{build} ? '<td>' : sprintf('<td class="val time"%s>%s%.0f',
- defined $_->{warp} && qq(title="$_->{build} without warpgate"),
+ defined $_->{warp} && sprintf(' title="%.0f without warpgate"', $_->{build}),
!!$_->{base} && sprintf(
'<span class="unit-composed" title="%s">+</span>',
'from '.join('+', @{ $_->{base} }),
$_->{attr}->{jump}
&& qq'<span class="unit unit-jump" title="$_->{attr}->{jump}">↕</span>',
'<td class="unit-magic">' . showmagic($_),
- !$_->{attack}->[1] ? () : (
- '<tr><th class="cat" colspan="2"><td colspan=10>', showattack($_, 1), '<td colspan=3>'
- ),
- !$_->{attack}->[2] ? () : (
- '<tr><th class="cat" colspan="2"><td colspan=10>', showattack($_, 2), '<td colspan=3>'
- ),
+ (map {(
+ '<tr class="sub"><th class="cat"><td><td colspan=10>',
+ showattack($row, $_),
+ '<td colspan=3>',
+ )} 1 .. $#{ $_->{attack} }),
"\n"
);
}
if ($get{order} eq 'name') {
@rows = sort {$a->{name} cmp $b->{name}} @rows;
}
- elsif ($get{order} eq 'hp') {
- $_->{order} = (
- $_->{hp}*1.01 + $_->{armor} + $_->{shield} + $_->{size}/1024,
- ) for @rows;
- }
elsif ($get{order} eq 'cost') {
$_->{order} = (
$_->{gas}*1.5 + $_->{min} + $_->{pop}/8 + $_->{build}/256/8
+ $_->{hp}/512 + $_->{min}/8192
) for @rows;
}
+ elsif ($get{order} eq 'hp') {
+ $_->{order} = (
+ $_->{hp}*1.01 + $_->{armor} + $_->{shield} + $_->{size}/1024,
+ ) for @rows;
+ }
elsif ($get{order} eq 'attack') {
- $_->{order} = $_->{hp} / 1024 + $_->{shield} / 1008 + max(
+ $_->{order} = $_->{hp} / 16384 + max(
map {
($_->{dps} ? $_->{dps}->[-1] :
($_->{damage} + $_->{upgrade} * 3)