#!/usr/bin/perl -w
use strict;
$|=1;
use EVEcommon;
use Data::Dumper;
use Carp;
my $datadir = @ARGV ? shift @ARGV : "cache";
$datadir =~ s,(/*$),/,;
die "bad datadir $datadir" unless -d $datadir;
# prereq attributes
my @prereqs = (
[1,182,277,],
[2,183,278,],
[3,184,279,],
[4,1285,1286,],
[5,1289,1287,],
[6,1290,1288,],);
&load_units();
&load_graphics();
&load_metagroups();
&load_marketgroups();
&load_variations();
&load_attributes();
&load_categories();
&load_groups();
&load_types();
&load_typeattributes();
&load_typeeffects();
&load_certs();
&load_certrels();
&load_certrecs();
&load_certcats();
&load_certclasses();
### CERTS
open(CF, ">", "eve-certificates.xml") or die $!;
print CF '',"\n",'',"\n";
my @ccs = &certcats();
for my $ccat (sort {$a->{categoryName} cmp $b->{categoryName}} @ccs) {
printf CF ' %s',
$ccat->{categoryName},
$ccat->{categoryID},
&render_descr($ccat->{description}),
"\n";
my %ccc = ();
my @certs = &certs_by_catid($ccat->{categoryID});
for my $c (@certs) {
my $cid = $c->{certificateID};
my $grade = $c->{grade};
my $class = $c->{classID};
die "cert without class" unless $class;
$ccc{$class} ||= {};
#printf "DEB: ccc{$class}{$grade}\n";
die "dupe ccc{$class}{$grade}" if $ccc{$class}{$grade};
$ccc{$class}{$grade} = $c;
}
for my $classid (sort {$a <=> $b} keys %ccc) {
my $cclass = &certclass_by_id($classid);
die "no class for $classid" unless $cclass;
die "classid mismatch" unless $cclass->{classID} == $classid;
printf CF ' %s',
$cclass->{className},
$cclass->{classID},
&render_descr($cclass->{description}),
"\n";
for my $grade (sort {$a <=> $b} keys %{$ccc{$classid}}) {
my $cert = $ccc{$classid}{$grade};
die "missing ccc{$classid}{$grade}" unless $cert;
printf CF ' %s',
&level_to_grade($grade),
$cert->{certificateID},
&render_descr($cert->{description}),
"\n";
my @rec = &certrecs_by_certid($cert->{certificateID});
for my $r (@rec) {
printf CF ' %s',
$r->{recommendationID},
$r->{recommendationLevel},
&type_by_id($r->{shipTypeID})->{typeName},
"\n";
}
my @rel = &certrels_by_certid($cert->{certificateID});
for my $r (@rel) {
my $rid = $r->{relationshipID};
my $ptid = ($r->{parentTypeID} > 0) ? $r->{parentTypeID} : 0;
my $pid = ($r->{parentID} > 0) ? $r->{parentID} : 0;
die "both type and id for rid $rid" if $ptid && $pid;
my ($type, $name, $level,);
if ($pid) {
$type = "cert";
my $cert = &cert_by_id($pid);
$name = &certclass_by_id($cert->{classID})->{className};
$level = &level_to_grade($cert->{grade});
} elsif ($ptid) {
$type = "type";
$name = &type_by_id($ptid)->{typeName};
$level = $r->{parentLevel};
} else {
die "never here";
}
printf CF ' %s',
$r->{relationshipID},
$type, $name, $level,
"\n";
}
printf CF " \n";
}
printf CF " \n";
}
printf CF " \n";
}
print CF "\n";
close CF or die $!;
#### START ITEMS
my $tree = {
group => { marketGroupID => 0, marketGroupName => 'Ship Items', },
subs => [],
items => [],
};
my %groups = ( NULL => $tree );
#| 9 | NULL | Ship Equipment |
#| 11 | NULL | Ammunition & Charges |
#| 24 | NULL | Implants & Boosters |
#| 157 | NULL | Drones |
#| 477 | NULL | Starbase Structures |
#| 955 | NULL | Ship Modifications |
#for (9, 11, 24, 157, 477, 955,) {
# my $mg = &marketgroup_by_id($_);
for ( "Ship Equipment",
"Ammunition & Charges",
"Implants & Boosters",
"Drones",
"Starbase Structures",
"Ship Modifications",
) {
my $mg = &marketgroup_by_name($_);
my $mgid = $mg->{marketGroupID};
die "no mgid for $_" unless $mgid;
die "dupe $_" if $groups{$mgid};
my $grp = { group => $mg, subs => [], items => [], };
push @{$tree->{subs}}, $grp;
$groups{$mgid} = $grp;
}
my $ac = 1;
while ($ac) {
$ac = 0;
for (&marketgroup_ids()) {
next if $groups{$_};
my $mg = &marketgroup_by_id($_);
my $pid = $mg->{parentGroupID};
next unless $pid && $groups{$pid};
my $grp = { group => $mg, subs => [], items => [], };
push @{$groups{$pid}->{subs}}, $grp;
$groups{$_} = $grp;
$ac++;
}
printf "TREELOOP: %i added\n", $ac;
}
my %chargegroups =();
for (&groups_by_category("Charge")) {
my $gid = $_->{groupID};
die "dupe gid $gid" if $chargegroups{$gid};
# my $g = &group_by_id($_);
#next unless $g->{published};
$chargegroups{$gid} = $_;
}
my %types = ();
for (&type_ids()) {
die "dupe tid $_" if $types{$_};
my $t = &type_by_id($_);
next unless $t->{published};
$types{$_} = $t;
my $g = $t->{groupID};
if ($g && $chargegroups{$g} && (!defined $t->{marketGroupID} || !$t->{marketGroupID})) {
printf "CHARGE-NO-MARKETGROUP: %i '%s'\n",
$_, $t->{typeName};
}
}
printf "LOADED %i types\n", scalar keys %types;
my %typegroup = ();
# PASS 1 - assign by marketgroupID
$ac = 0;
my $dc = 0;
for (keys %types) {
my $t = $types{$_};
my $mgid = $t->{marketGroupID};
next unless $mgid;
delete $types{$_};
$dc++;
next unless $groups{$mgid};
die "wtf BP $_" if $t->{typeName} =~ /Blueprint/;
push @{$groups{$mgid}->{items}}, $t;
die "unexpeced tg $_" if $typegroup{$_};
$typegroup{$_} = $groups{$mgid};
$ac++;
}
printf "PASS1 (marketgroups) %i added, %i deleted, %i left\n", $ac, $dc-$ac, scalar keys %types;
# PASS 2 - assign by variation
($ac, $dc,) = (0,0,);
for (keys %typegroup) {
my $tid = $_;
my $grp = $typegroup{$_};
die "unexpeced type $_" if $types{$_};
for (&variations_by_id($tid)) {
my $vid = $_;
next if $typegroup{$vid};
unless ($types{$vid}) {
$types{$vid} = &type_by_id($vid);
die "missing vid $vid" unless $types{$vid};
# warn "summoned variation $vid for $tid";
$dc++;
}
my $t = delete $types{$vid};
die "wtf BP $vid for $tid" if $t->{typeName} =~ /Blueprint/;
push @{$grp->{items}}, $t;
$typegroup{$vid} = $grp;
$ac++;
}
}
printf "PASS2 (variations) %i added, %i summoned, %i left\n", $ac, $dc, scalar keys %types;
# PASS 3 - assign by having a slot id
($ac, $dc,) = (0,0,);
for (keys %types) {
my $tid = $_;
my $ta = &typeattributes($tid,1);
next unless $ta->{331};
die "unexpeced tg $tid" if $typegroup{$tid};
die "high slot ".$ta->{331} if $ta->{331} > 10;
my $mgid = 617 + $ta->{331};
die "bad mgid $mgid" unless $groups{$mgid};
my $t = delete $types{$tid};
die "wtf BP $tid" if $t->{typeName} =~ /Blueprint/;
my $grp = $groups{$mgid};
push @{$grp->{items}}, $t;
$typegroup{$tid} = $grp;
$ac++;
}
printf "PASS3 (implantslot) %i added, %i left\n", $ac, scalar keys %types;
# PASS 4 - assign by being in the same group as a known item
my %structgroups = ();
my @ss = (
$groups{11}, # Charges
$groups{477}, # Structures
);
while (@ss) {
my $grp = shift @ss;
my $mgid = $grp->{group}->{marketGroupID};
for my $t (@{$grp->{items}}) {
my $tid = $t->{typeID};
my $gid = $t->{groupID};
if ($structgroups{$gid}) {
warn "redefined gid $gid from mgid ".
$structgroups{$gid}." to $mgid"
unless $structgroups{$gid} == $mgid;
}
$structgroups{$gid} = $mgid;
# unless (&variations_by_id($tid)) {
# printf "NOVAR: %5i '%s'\n", $tid, $t->{typeName};
# }
}
push @ss, @{$grp->{subs}};
}
#printf "have %i struct groups\n", scalar keys %structgroups;
($ac, $dc,) = (0,0,);
for (keys %types) {
my $tid = $_;
my $t = $types{$tid};
my $gid = $t->{groupID};
die "missing gid for $tid" unless $gid;
next unless $structgroups{$gid};
die "wtf BP $tid" if $t->{typeName} =~ /Blueprint/;
my $mgid = $structgroups{$gid};
die "bad mgid $mgid" unless $groups{$mgid};
delete $types{$tid};
my $grp = $groups{$mgid};
push @{$grp->{items}}, $t;
$typegroup{$tid} = $grp;
$ac++;
printf "PASS4 added: %i '%s'\n",
$t->{typeID}, $t->{typeName};
# unless (&variations_by_id($tid)) {
# printf "NOVAR: %5i '%s'\n", $tid, $t->{typeName};
# }
}
printf "PASS4 (market group groups) %i added, %i left\n", $ac, scalar keys %types;
printf "ASSIGNED %i ITEMS\n", scalar keys %typegroup;
#for (keys %typegroup) {
# my $tid = $_;
# my $t = &type_by_id($tid);
# printf "TYPE: %s\n", $t->{typeName};
#}
open(SF, ">", "eve-items2.xml") or die $!;
print SF '',"\n";
&render_group($tree);
close SF or die $!;
sub render_group ($$) {
my ($tree, $depth,) = @_;
$depth ||= 0;
if ($depth < 2) {
printf "%s%04i %s (%i items)\n",
" "x$depth,
$tree->{group}->{marketGroupID},
$tree->{group}->{marketGroupName},
scalar @{$tree->{items}};
}
printf SF "%s\n", " "x$depth;
printf SF "%s %s\n", " "x$depth,
&render_descr($tree->{group}->{marketGroupName});
if (@{$tree->{subs}}) {
printf SF "%s \n", " "x$depth;
for (sort {$a->{group}->{marketGroupName} cmp $b->{group}->{marketGroupName}} @{$tree->{subs}}) {
&render_group($_, $depth+1);
}
printf SF "%s \n", " "x$depth;
}
if (@{$tree->{items}}) {
printf SF "%s \n", " "x$depth;
for (sort {$a->{typeName} cmp $b->{typeName}} @{$tree->{items}}) {
&render_item($_, $depth+1);
}
printf SF "%s \n", " "x$depth;
}
printf SF "%s\n", " "x$depth;
}
sub render_item ($$) {
my ($type, $depth,) = @_;
$depth ||= 0;
my $tid = $type->{typeID};
my $ta = &typeattributes($tid);
my %a = %$ta;
# printf SF "%s>>>> %s\n", " "x$depth, $type->{typeName};
# return;
my $mg = &metagroup_by_typeid($tid);
my $dmg = "Tech I";
if ($mg) {
if ($mg->{metaGroupID} == 1) {
$dmg = 'Named';
} else {
$dmg = $mg->{metaGroupName};
}
} elsif (defined $ta->{422}) {
my $tl = $ta->{422};
$mg = {
1 => "Tech I",
2 => "Tech II",
3 => "Tech III",
}->{$tl};
if ($mg) {
$dmg = $mg;
} else {
warn "bad tl:$tl for tid:$tid";
}
}
# die "cant decide on metaGroup for $tid" unless $dmg;
my $icon = &get_icon_by_type($type);
printf SF '%s- %s',
" "x$depth,
$type->{typeID},
&render_descr($type->{typeName}),
&render_descr($type->{description}),
$icon,
$dmg,
"\n";
printf SF "%s \n", " "x$depth;
for (@prereqs) {
my ($ai, $as, $al,) = @$_;
my $s = defined $a{$as} ? delete $a{$as} : 0;
my $l = defined $a{$al} ? delete $a{$al} : 0;
if ($tid == 30651) {
printf "DEB(%i): s(%i => %i), l(%i => %i)\n",
$tid, $as, $s, $al, $l;
}
next unless $s && $l;
printf SF '%s %s',
" "x$depth,
&type_by_id($s)->{typeName},
$l, "\n";
}
printf SF "%s \n", " "x$depth;
printf SF "%s \n", " "x$depth;
printf SF '%s %s', " "x$depth,
&render_attrval($type->{basePrice}, {}), "\n";
printf SF '%s %s', " "x$depth,
&render_attrval($type->{mass}, {}), "\n";
printf SF '%s %s', " "x$depth,
&render_attrval($type->{volume}, {}), "\n";
printf SF '%s %s', " "x$depth,
&render_attrval($type->{capacity}, {}), "\n";
my $eff = &typeeffects($tid, 1);
if (defined $eff->{11}) {
die "multislot" if defined $eff->{12} || defined $eff->{13};
printf SF '%s %s', " "x$depth, "\n";
}
if (defined $eff->{12}) {
die "multislot" if defined $eff->{11} || defined $eff->{13};
printf SF '%s %s', " "x$depth, "\n";
}
if (defined $eff->{13}) {
die "multislot" if defined $eff->{11} || defined $eff->{12};
printf SF '%s %s', " "x$depth, "\n";
}
for my $aid (sort {&attribute_by_id($a)->{attributeName} cmp &attribute_by_id($b)->{attributeName}} keys %a) {
my $v = delete $a{$aid};
if ($aid == 107) {
warn "BR69169: pre-QR explosion radius";
next;
}
my $a = &attribute_by_id($aid);
my $n = $a->{displayName} || $a->{attributeName};
# next if !$v && $n =~ /^(CPU Load|Damage|Powerload)$/;
my $dv = &render_attrval($v, $a);
# next unless $s && $l;
printf SF '%s %s', " "x$depth, $n, $dv, "\n";
}
printf SF "%s \n", " "x$depth;
for my $aid (sort {$a <=> $b} keys %a) {
my $attr = &attribute_by_id($aid);
printf "TypeAttributes(%i): %s %s\n", $aid,
$attr->{attributeName},
$ta->{$aid};
}
printf SF "%s
\n", " "x$depth;
}
#print Dumper($tree);
#exit 23;
###
open(SF, ">", "eve-ships2.xml") or die $!;
print SF '',"\n",
'',"\n";
my %ships = ();
my @shg = &groups_by_category("Ship");
for my $group (@shg) {
# printf "Group(%i): %s\n", $group->{groupID}, $group->{groupName};
my @st = &types_by_group($group->{groupID});
for my $type (@st) {
# printf "Type(%i): %s\n", $type->{typeID}, $type->{typeName};
next unless $type->{published};
my $ta = &typeattributes($type->{typeID});
die "dupe type: ".$type->{typeName} if $ships{$type->{typeName}};
$ships{$type->{typeName}} = [$group, $type, $ta,];
}
}
for (sort keys %ships) {
my ($group, $type, $ta,) = @{$ships{$_}};
# printf "Type(%i): %s\n", $type->{typeID}, $type->{typeName};
my %a = %$ta;
my $race = "UNKNOWN";
if (!defined $type->{marketGroupID} || !$type->{marketGroupID}) {
$race = 'Faction';
} else {
$race = &marketgroup_by_id($type->{marketGroupID})->{marketGroupName};
}
# checky-checky
&get_icon_by_type($type);
printf SF ' %s',
$type->{typeID},
$type->{typeName},
&render_descr($type->{description}),
$race,
$group->{groupName},
"\n";
print SF " \n";
for (@prereqs) {
my ($ai, $as, $al,) = @$_;
my $s = defined $a{$as} ? delete $a{$as} : 0;
my $l = defined $a{$al} ? delete $a{$al} : 0;
next unless $s && $l;
printf SF ' %s',
&type_by_id($s)->{typeName},
$l, "\n";
}
print SF " \n";
print SF " \n";
printf SF ' %s',
&render_attrval($type->{basePrice}, {}), "\n";
printf SF ' %s',
&render_attrval($type->{mass}, {}), "\n";
printf SF ' %s',
&render_attrval($type->{volume}, {}), "\n";
printf SF ' %s',
&render_attrval($type->{capacity}, {}), "\n";
for my $aid (sort {&attribute_by_id($a)->{attributeName} cmp &attribute_by_id($b)->{attributeName}} keys %a) {
my $v = delete $a{$aid};
my $a = &attribute_by_id($aid);
my $n = $a->{displayName} || $a->{attributeName};
next if !$v && $n =~ /^(CPU Load|Damage|Powerload)$/;
my $dv = &render_attrval($v, $a);
# next unless $s && $l;
printf SF ' %s', $n, $dv, "\n";
}
print SF " \n";
for my $aid (sort {$a <=> $b} keys %a) {
my $attr = &attribute_by_id($aid);
printf "TypeAttributes(%i): %s %s\n", $aid,
$attr->{attributeName},
$ta->{$aid};
}
print SF " \n";
# last;
}
print SF "\n";
close SF or die $!;
#exit 42;
###
open(SF, ">", "eve-implants2.xml") or die $!;
print SF '',"\n",
'',"\n";
my %implants = ();
my @ig = &groups_by_category("Implant");
for my $group (@ig) {
printf "Group(%i): %s\n", $group->{groupID}, $group->{groupName};
my @st = &types_by_group($group->{groupID});
for my $type (@st) {
# printf "Type(%i): %s\n", $type->{typeID}, $type->{typeName};
my $ta = &typeattributes($type->{typeID});
# next unless scalar %$ta;
if (defined $ta->{331}) {
my $slot = $ta->{331};
$implants{$slot} ||= [];
push @{$implants{$slot}}, [$type, $ta,];
next;
};
next if $group->{groupName} eq "Booster";
printf "NoSlot(typeID:%i): %s\n", $type->{typeID}, $type->{typeName};
# for my $aid (sort {$a <=> $b} keys %$ta) {
# my $attr = &attribute_by_id($aid);
# printf "TypeAttributes(%i): %s %s\n", $aid,
# $attr->{attributeName},
# $ta->{$aid};
# }
}
# exit 5;
}
my @slotmap = (
[ 1, "Perception", 178, ],
[ 2, "Memory", 177, ],
[ 3, "Willpower", 179, ],
[ 4, "Intelligence", 176, ],
[ 5, "Charisma", 175, ],
[ 6, "Misc", -1, ],
[ 7, "Misc", -1, ],
[ 8, "Misc", -1, ],
[ 9, "Misc", -1, ],
[10, "Misc", -1, ],
);
for (@slotmap) {
my ($slot, $attr, $pba,) = @$_;
printf "SLOT(%s): %i plants\n", $slot, scalar @{$implants{$slot}};
printf SF ' %s', $slot, $attr, "\n";
for (sort {$a->[0]->{typeName} cmp $b->[0]->{typeName}} @{$implants{$slot}}) {
my ($type, $ta, ) = @$_;
# printf "Type(%i): %s\n", $type->{typeID}, $type->{typeName};
my %a = %$ta;
my $bonus = $a{$pba} ? delete $a{$pba} : 0;
die "no pba" if $pba > 0 && !$bonus;
for (175..179) {
delete $a{$_} if defined $a{$_} && !$a{$_};
}
my $sl = delete $a{331};
die "wrong slot $sl != $slot" unless $sl == $slot;
my $tl = defined $a{422} ? delete $a{422} : 0;
printf SF ' %s',
$tl == 2 ? "true" : "false",
$bonus, $type->{typeID},
&graphic_by_id($type->{graphicID})->{icon},
$type->{typeName},
&render_descr($type->{description}),
"\n";
print SF " \n";
for (@prereqs) {
my ($ai, $as, $al,) = @$_;
my $s = defined $a{$as} ? delete $a{$as} : 0;
my $l = defined $a{$al} ? delete $a{$al} : 0;
next unless $s && $l;
printf SF ' %s',
&type_by_id($s)->{typeName},
$l, "\n";
}
print SF " \n";
if (scalar %a) {
print SF " \n";
for my $a (sort {$a <=> $b} keys %a) {
my $v = delete $a{$a};
# next unless $s && $l;
printf SF ' %s',
&attribute_by_id($a)->{attributeName},
$v, "\n";
}
print SF " \n";
}
for my $aid (sort {$a <=> $b} keys %a) {
my $attr = &attribute_by_id($aid);
printf "TypeAttributes(%i): %s %s\n", $aid,
$attr->{attributeName},
$ta->{$aid};
}
print SF " \n";
# last;
}
print SF " \n";
}
print SF "\n";
close SF or die $!;
#exit 42;
###
open(SF, ">", "eve-skills2.xml") or die $!;
print SF '',"\n",'',"\n";
my %rbp = ();
my @sg = &groups_by_category("Skill");
for my $group (sort {$a->{groupName} cmp $b->{groupName}} @sg) {
next if $group->{groupName} eq "Fake Skills";
printf "SkillGroup(%i): %s\n", $group->{groupID}, $group->{groupName};
printf SF ' %s', $group->{groupName}, $group->{groupID}, "\n";
my @st = &types_by_group($group->{groupID});
for my $type (sort {$a->{typeName} cmp $b->{typeName}} @st) {
# printf "SkillType(%i): %s\n", $type->{typeID}, $type->{typeName};
my $ta = &typeattributes($type->{typeID});
next unless scalar %$ta;
# for my $aid (sort {$a <=> $b} keys %$ta) {
# my $attr = &attribute_by_id($aid);
# printf "TypeAttributes(%i): %s %s\n", $aid,
# $attr->{attributeName},
# $ta->{$aid};
# }
my $descr = &render_descr($type->{description});
die "missing a180" unless $ta->{180};
die "missing a181" unless $ta->{181};
die "missing rank" unless $ta->{275};
die "missing price" unless defined $type->{basePrice};
if ($type->{typeName} =~ /^((?:Amarr|Caldari|Gallente|Minmatar)\w*) (.+)$/) {
my $bp = $type->{basePrice};
die "redefining rbp for ".$type->{typeName} if $rbp{$2}{$1};
$rbp{$2}{$1} = $bp;
} elsif ($type->{typeName} =~ /(Amarr|Caldari|Gallente|Minmatar)/i) {
die "racial mismatch: ".$type->{typeName};
}
my $have_prereq = 0;
for (@prereqs) {
my ($ai, $as, $al,) = @$_;
die "sl$ai without s$ai" if !$ta->{$as} && $ta->{$al};
$have_prereq++ if $ta->{$al};
if ($ta->{$as} && !$ta->{$al}) {
my $pl = defined $ta->{$al} ? $ta->{$al} : "undef";
my $pn = &type_by_id($ta->{$as})->{typeName};
my $n = $type->{typeName};
warn "false($pl) prereq($ai) '$pn' for '$n'";
}
}
my $rank = int($ta->{275}+0.5);
warn "rank for ".$type->{typeName}." changed from ".$ta->{275}." to $rank"
unless $ta->{275} == $rank;
printf SF ' {published} ? "" : 'p="false" ',
$type->{typeName}, $type->{typeID},
$descr,
&attribute_by_id($ta->{180})->{attributeName},
&attribute_by_id($ta->{181})->{attributeName},
$rank,
$type->{basePrice},
$ta->{1047} ? 'false' : 'true';
unless ($have_prereq) {
print SF "/>\n";
next;
}
print SF ">\n";
for (@prereqs) {
my ($ai, $as, $al,) = @$_;
if ($ta->{$al}) {
printf SF ' %s',
&type_by_id($ta->{$as})->{typeName},
$ta->{$al},
"\n";
}
}
print SF " \n";
}
print SF " \n";
# exit 5;
}
print SF "\n";
close SF or die $!;
for my $s (sort keys %rbp) {
my $bp = undef;
for my $r (sort keys %{$rbp{$s}}) {
my $rbp = $rbp{$s}{$r};
$bp = $rbp unless defined $bp;
warn "BP mismatch for '$r $s'" unless $rbp == $bp;
}
}
exit 0;
##
sub get_icon_by_type ($) {
my $type = shift;
my $tid = $type->{typeID};
die "no typeID in $type" unless $tid;
my $iconfile = $tid;
my $icon = sprintf "/icons/64_64/%s.png", $iconfile;
if (-e ".".$iconfile) {
my $big = sprintf "/icons/256_256/%s.png", $iconfile;
warn "MISSING: BIG $big" unless -e ".".$big;
} elsif ($type->{graphicID}) {
my $graphic = &graphic_by_id($type->{graphicID});
my $ic = $graphic->{icon};
if ($ic) {
$iconfile = "icon".$ic;
}
$icon = sprintf "/icons/64_64/%s.png", $iconfile;
if ($type->{published}) {
warn "MISSING: ICON $icon" unless -e ".".$icon;
}
} else {
warn "MISSING: ALL $tid";
}
return $iconfile;
}
sub render_attrval ($$) {
my ($v, $a,) = @_;
my $form = "%s %s";
my $u = $a->{unitID} ? &unit_by_id($a->{unitID}) : {};
my $du = $u->{displayName} || $u->{unitName} || "";
my $dv = $v;
# clobber milliseconds
if ((($a->{unitID}||0) == 101) ||
($du eq "ms" && $dv =~ /000$/)) {
$du = "sec";
$dv /= 1000;
}
# BR 71720
if ($du eq "sec" &&
$dv > 5000) {
my $n = "attributeID:".$a->{attributeID}." ".
($a->{displayName} || $a->{attributeName});
if ($a->{attributeName} =~ /^(boosterDuration|missileLaunchDuration|warpScrambleDuration|cloakingTargetingDelay)$/) {
warn "BR71720: fixing $dv sec '$n'";
$dv /= 1000;
} else {
# warn "IGNORING BR71720 CANDIDATE: $dv sec '$n'";
}
}
my $d = 0;
if (($u->{unitName}||"") eq "Inverse Absolute Percent") {
$dv = (1.0-$dv)*-100;
} elsif (($u->{unitName}||"") eq "Modifier Percent") {
$dv = ($dv-1.0)*100;
} elsif (($u->{unitName}||"") eq "Absolute Percent") {
$dv = $dv*100;
#$d=1;
} elsif (($u->{unitName}||"") eq "Inversed Modifier Percent") {
$dv = (1.0-$dv)*100;
} elsif (($u->{unitName}||"") eq "typeID") {
my $g = &type_by_id($v);
$dv = &render_descr($g->{typeName});
$du = "";
} elsif (($u->{unitName}||"") eq "groupID") {
my $g = &group_by_id($v);
$dv = &render_descr($g->{groupName});
$du = "";
} elsif (($u->{unitName}||"") eq "Sizeclass") {
$dv = {
1 => 'Small',
2 => 'Medium',
3 => 'Large',
4 => 'Extra Large',
}->{$v};
die "bad SizeClass $v" unless $dv;
$du = "";
}
if ($dv !~ /^0\.\d+$/ &&
$dv =~ /\.(\d+)$/ &&
int($dv) != $dv) {
if (length($1) > 5) {
$dv = sprintf "%.3f", $dv;
} else {
$dv = sprintf "%f", $dv;
}
$dv =~ s/0+$//;
$dv =~ s/\.$//;
} else {
if ($du eq 'sec' && $dv =~ /\./) {
warn "DEB: secnomatch '$dv'";
}
}
while ($dv =~ s/^(\d+)(\d\d\d)(\D|$)/$1,$2$3/) { ; }
warn "FIX: $v -> $dv\n" if $d;
return $du ? sprintf $form, $dv, $du : $dv;
}
sub render_descr ($) {
my ($d,) = @_;
$d =~ s/\s+$//g;
#$d =~ s/[\r\n]+/\n/g;
$d =~ s/&/\&/g;
$d =~ s/\r\n/\n/g;
$d =~ s/\n/\
\
/g;
$d =~ s/"/\"/g;
$d =~ s/\</g;
$d =~ s/>/\>/g;
# $d =~ s/\n/\
/g;
die "bad descr($1): '$d'\n" if $d =~ /(["<])/;
return $d;
}
###
my %certrel_by_id;
sub certrel_by_id ($) {
my ($cid,) = @_;
die "bad cid '$cid'" unless $cid =~ /^\d+$/;
&load_certrels() unless %certrel_by_id;
die "dont have cid $cid" unless $certrel_by_id{$cid};
return $certrel_by_id{$cid};
}
my %certrels;
sub certrels_by_certid ($) {
my $cid = shift;
die "bad classid '$cid'" unless $cid =~ /^\d+$/;
return @{$certrels{$cid}} if defined $certrels{$cid};
&load_certrels() unless %certrel_by_id;
my @cl = ();
for (keys %certrel_by_id) {
my $c = $certrel_by_id{$_};
next unless $c->{childID} == $cid;
push @cl, $c;
}
$certrels{$cid} = \@cl;
return @{$certrels{$cid}};
}
sub load_certrels {
return if %certrel_by_id;
# die "inconsistent" if %types_by_id || %types_by_name;
my $data = &loadfile("config.BulkData.certificaterelationships");
for my $row (@$data) {
my $rid = $row->{relationshipID};
die "missing rid" unless defined $rid;
die "trying to redefine certrel $rid" if $certrel_by_id{$rid};
$certrel_by_id{$rid} = $row;
}
}
my %certrec_by_id;
sub certrec_by_id ($) {
my ($cid,) = @_;
die "bad cid '$cid'" unless $cid =~ /^\d+$/;
&load_certrecs() unless %certrec_by_id;
die "dont have cid $cid" unless $certrec_by_id{$cid};
return $certrec_by_id{$cid};
}
my %certrecs;
sub certrecs_by_certid ($) {
my $cid = shift;
die "bad classid '$cid'" unless $cid =~ /^\d+$/;
return @{$certrecs{$cid}} if defined $certrecs{$cid};
&load_certrecs() unless %certrec_by_id;
my @cl = ();
for (keys %certrec_by_id) {
my $c = $certrec_by_id{$_};
next unless $c->{certificateID} == $cid;
push @cl, $c;
}
$certrecs{$cid} = \@cl;
return @{$certrecs{$cid}};
}
sub load_certrecs {
return if %certrec_by_id;
# die "inconsistent" if %types_by_id || %types_by_name;
my $data = &loadfile("certificateMgr.GetAllShipCertificateRecommendations");
for my $row (@$data) {
my $cid = $row->{recommendationID};
die "missing cid" unless defined $cid;
die "trying to redefine certrec $cid" if $certrec_by_id{$cid};
$certrec_by_id{$cid} = $row;
}
}
my %cert_by_id;
sub cert_by_id ($) {
my ($cid,) = @_;
die "bad cid '$cid'" unless $cid =~ /^\d+$/;
&load_certs() unless %cert_by_id;
die "dont have cid $cid" unless $cert_by_id{$cid};
return $cert_by_id{$cid};
}
my %certcats;
sub certs_by_catid ($) {
my $cid = shift;
die "bad classid '$cid'" unless $cid =~ /^\d+$/;
return @{$certcats{$cid}} if defined $certcats{$cid};
&load_certs() unless %cert_by_id;
my @cl = ();
for (keys %cert_by_id) {
my $c = $cert_by_id{$_};
next unless $c->{categoryID} == $cid;
push @cl, $c;
}
$certcats{$cid} = \@cl;
return @{$certcats{$cid}};
}
sub load_certs {
return if %cert_by_id;
my $data = &loadfile("config.BulkData.certificates");
for my $row (@$data) {
my $cid = $row->{certificateID};
die "missing cid" unless defined $cid;
die "trying to redefine cert $cid" if $cert_by_id{$cid};
$cert_by_id{$cid} = $row;
}
}
my %certclass_by_id;
sub certclass_by_id ($) {
my ($cid,) = @_;
die "bad cid '$cid'" unless $cid =~ /^\d+$/;
&load_certclasses() unless %certclass_by_id;
die "dont have cid $cid" unless $certclass_by_id{$cid};
return $certclass_by_id{$cid};
}
sub load_certclasses {
return if %certclass_by_id;
my $data = &loadfile("certificateMgr.GetCertificateClasses");
for my $row (@$data) {
my $cid = $row->{classID};
die "missing cid" unless defined $cid;
die "trying to redefine cclass $cid" if $certclass_by_id{$cid};
$certclass_by_id{$cid} = $row;
}
}
my %certcat_by_id;
sub certcats {
&load_certcats() unless %certcat_by_id;
return values %certcat_by_id;
}
sub load_certcats {
return if %certcat_by_id;
my $data = &loadfile("certificateMgr.GetCertificateCategories");
for my $row (@$data) {
my $cid = $row->{categoryID};
die "missing cid" unless defined $cid;
die "trying to redefine ccat $cid" if $certcat_by_id{$cid};
$certcat_by_id{$cid} = $row;
}
}
#
sub level_to_grade ($) {
my $grade = shift;
die "bad grade $grade" unless $grade =~ /^\d$/;
my $g = { 1 => "Basic",
2 => "Standard",
3 => "Improved",
4 => "Advanced",
5 => "Elite",
}->{$grade};
die "unknown grade $grade" unless $g;
return $g;
}
# typeattribs
my %typeattributes;
sub typeattributes ($$) {
my ($tid,$quiet,) = @_;
&load_typeattributes() unless %typeattributes;
unless ($typeattributes{$tid}) {
warn "dont have attribs for type $tid" unless $quiet;
return {};
}
return $typeattributes{$tid};
}
sub load_typeattributes {
return if %typeattributes;
my $data = &loadfile("config.BulkData.dgmtypeattribs");
for (@$data) {
my $t = $_->{typeID} || die "missing typeID";
my $a = $_->{attributeID} || die "missing attributeID";
my $v = $_->{value};
$typeattributes{$t} ||= {};
die "trying to redefine attributeID:$a for typeID:$t" if
defined $typeattributes{$t}{$a};
$typeattributes{$t}{$a} = $v;
}
}
# typeeffects
my %typeeffects;
sub typeeffects ($$) {
my ($tid,$quiet,) = @_;
&load_typeeffects() unless %typeeffects;
unless ($typeeffects{$tid}) {
warn "dont have effects for type $tid" unless $quiet;
return {};
}
return $typeeffects{$tid};
}
sub load_typeeffects {
return if %typeeffects;
my $data = &loadfile("config.BulkData.dgmtypeeffects");
for my $row (@$data) {
my $t = $row->{typeID} || die "missing typeID";
my $a = $row->{effectID} || die "missing effectID";
my $v = $row->{isDefault};
$typeeffects{$t} ||= {};
die "trying to redefine effectID:$a for typeID:$t" if
defined $typeeffects{$t}{$a};
$typeeffects{$t}{$a} = $v;
}
}
# types
my %types_by_id;
sub type_by_id ($) {
my ($cid,) = @_;
die "bad type '$cid'" unless $cid =~ /^\d+$/;
&load_types() unless %types_by_id;
die "dont have type $cid" unless $types_by_id{$cid};
return $types_by_id{$cid};
}
sub type_ids {
&load_types() unless %types_by_id;
return keys %types_by_id;
}
my %types_by_name;
sub type_by_name ($) {
my ($cname,) = @_;
&load_types() unless %types_by_name;
die "dont have type $cname" unless $types_by_name{$cname};
return $types_by_name{$cname};
}
my %grouptypes;
sub types_by_group ($) {
my ($gid,) = @_;
unless ($gid =~ /^\d+$/) {
printf "Resolving group '%s' ...", $gid;
my $c = &group_by_name($gid);
$gid = $c->{groupID};
printf " %i\n", $gid;
}
return @{$grouptypes{$gid}} if defined $grouptypes{$gid};
my @types = ();
for (keys %types_by_id) {
next unless $types_by_id{$_}->{groupID} == $gid;
push @types, $types_by_id{$_};
}
$grouptypes{$gid} = \@types;
return @{$grouptypes{$gid}};
}
sub load_types {
return if %types_by_id && %types_by_name;
die "inconsistent" if %types_by_id || %types_by_name;
my $data = &loadfile("config.BulkData.types");
for my $row (@$data) {
my $cid = $row->{typeID};
die "missing cid" unless defined $cid;
die "trying to redefine type $cid" if $types_by_id{$cid};
$types_by_id{$cid} = $row;
my $cname = $row->{typeName};
if ($types_by_name{$cname}) {
warn "trying to redefine type $cname";
next;
}
$types_by_name{$cname} = $row;
}
}
# metatypes
my %variations_by_id;
sub variations_by_id ($) {
my ($id,) = @_;
&load_variations() unless %variations_by_id;
return () unless $variations_by_id{$id};
# die "dont have variation $id" unless $variations_by_id{$id};
return keys %{$variations_by_id{$id}};
}
my %metagroup_by_typeid;
sub metagroup_by_typeid ($) {
my ($id,) = @_;
&load_variations() unless %metagroup_by_typeid;
my $mid = $metagroup_by_typeid{$id};
return undef unless $mid;
return &metagroup_by_id($mid);
# die "dont have variation $id" unless $variations_by_id{$id};
}
sub load_variations {
return if %variations_by_id;
my $data = &loadfile("config.BulkData.invmetatypes");
for my $row (@$data) {
my $tid = $row->{typeID};
die "missing tid" unless defined $tid;
my $pid = $row->{parentTypeID};
die "missing pid" unless defined $pid;
$variations_by_id{$tid} ||= {};
$variations_by_id{$tid}{$pid}++;
$variations_by_id{$pid} ||= {};
$variations_by_id{$pid}{$tid}++;
$metagroup_by_typeid{$tid} = $row->{metaGroupID};
}
}
# group
my %groups_by_id;
sub group_by_id ($) {
my ($cid,) = @_;
&load_groups() unless %groups_by_id;
die "dont have group $cid" unless $groups_by_id{$cid};
return $groups_by_id{$cid};
}
my %groups_by_name;
sub group_by_name ($) {
my ($cname,) = @_;
&load_groups() unless %groups_by_name;
die "dont have group $cname" unless $groups_by_name{$cname};
return $groups_by_name{$cname};
}
my %catgroups;
sub groups_by_category ($) {
my ($cid,) = @_;
unless ($cid =~ /^\d+$/) {
printf "Resolving category '%s' ...", $cid;
my $c = &category_by_name($cid);
$cid = $c->{categoryID};
printf " %i\n", $cid;
}
return @{$catgroups{$cid}} if defined $catgroups{$cid};
my @groups = ();
for (keys %groups_by_id) {
next unless $groups_by_id{$_}->{categoryID} == $cid;
push @groups, $groups_by_id{$_};
}
$catgroups{$cid} = \@groups;
return @{$catgroups{$cid}};
}
sub load_groups {
return if %groups_by_id && %groups_by_name;
die "inconsistent" if %groups_by_id || %groups_by_name;
my $data = &loadfile("config.BulkData.groups");
for my $row (@$data) {
my $cid = $row->{groupID};
die "missing cid" unless defined $cid;
die "trying to redefine group $cid" if $groups_by_id{$cid};
$groups_by_id{$cid} = $row;
my $cname = $row->{groupName};
die "trying to redefine group $cname" if $groups_by_name{$cname};
$groups_by_name{$cname} = $row;
}
}
# attributes
my %attributes_by_id;
sub attribute_by_id ($) {
my ($cid,) = @_;
&load_attributes() unless %attributes_by_id;
die "dont have attribute $cid" unless $attributes_by_id{$cid};
return $attributes_by_id{$cid};
}
my %attributes_by_name;
sub attribute_by_name ($) {
my ($cname,) = @_;
&load_attributes() unless %attributes_by_name;
die "dont have attribute $cname" unless $attributes_by_name{$cname};
return $attributes_by_name{$cname};
}
sub load_attributes {
return if %attributes_by_id && %attributes_by_name;
die "inconsistent" if %attributes_by_id || %attributes_by_name;
my $data = &loadfile("config.BulkData.dgmattribs");
for my $row (@$data) {
my $cid = $row->{attributeID};
die "missing cid" unless defined $cid;
die "trying to redefine attribute $cid" if $attributes_by_id{$cid};
$attributes_by_id{$cid} = $row;
my $cname = $row->{attributeName};
warn "trying to redefine attribute $cname" if $attributes_by_name{$cname};
$attributes_by_name{$cname} = $row;
}
}
# marketgroups
my (%marketgroups_by_id, %marketgroups_by_name,);
sub marketgroup_by_id ($) {
my ($cid,) = @_;
&load_marketgroups() unless %marketgroups_by_id;
confess "dont have marketgroup $cid" unless $marketgroups_by_id{$cid};
return $marketgroups_by_id{$cid};
}
sub marketgroup_by_name ($) {
my ($cname,) = @_;
&load_marketgroups() unless %marketgroups_by_name;
die "dont have marketgroup $cname" unless $marketgroups_by_name{$cname};
return $marketgroups_by_name{$cname};
}
sub marketgroup_ids {
&load_marketgroups() unless %marketgroups_by_id;
return keys %marketgroups_by_id;
}
sub load_marketgroups {
return if %marketgroups_by_id;
die "inconsistent: name without id" if %marketgroups_by_name;
my $data = &loadfile("market.GetMarketGroups");
my @header = @{$data->{header}};
my $d = $data;
$d = $d->{'machostring (id:40)'} || $d->{'items'};
die "no marketgroups" unless $d && ref $d eq 'HASH';
for (keys %$d) {
for (@{$d->{$_}}) {
my @row = @$_;
die "col count mismatch" unless scalar(@header) == scalar(@row);
my %row=();
for (0..$#row) {
my $k = $header[$_];
my $v = $row[$_];
die "trying to redefine key $k" if $row{$k};
$row{$k} = $v;
}
my $cid = $row{marketGroupID};
die "missing cid" unless defined $cid;
die "trying to redefine marketgroup $cid" if $marketgroups_by_id{$cid};
$marketgroups_by_id{$cid} = \%row;
my $cname = $row{marketGroupName};
die "missing cname" unless defined $cname;
next if $marketgroups_by_name{$cname};
warn "WARN: trying to redefine marketgroup $cname" if $marketgroups_by_name{$cname};
$marketgroups_by_name{$cname} = \%row;
}
}
# print Dumper( \%marketgroups_by_id );
}
# graphics
my %graphics_by_id;
sub graphic_by_id ($) {
my ($cid,) = @_;
&load_graphics() unless %graphics_by_id;
die "dont have graphic $cid" unless $graphics_by_id{$cid};
return $graphics_by_id{$cid};
}
sub load_graphics {
return if %graphics_by_id;
my $data = &loadfile("config.BulkData.graphics");
for my $row (@$data) {
my $cid = $row->{graphicID};
die "missing cid" unless defined $cid;
die "trying to redefine graphic $cid" if $graphics_by_id{$cid};
$graphics_by_id{$cid} = $row;
}
}
# categories
my %categories_by_id;
sub category_by_id ($) {
my ($cid,) = @_;
&load_categories() unless %categories_by_id;
die "dont have category $cid" unless $categories_by_id{$cid};
return $categories_by_id{$cid};
}
my %categories_by_name;
sub category_by_name ($) {
my ($cname,) = @_;
&load_categories() unless %categories_by_name;
die "dont have category $cname" unless $categories_by_name{$cname};
return $categories_by_name{$cname};
}
sub load_categories {
return if %categories_by_id && %categories_by_name;
die "inconsistent" if %categories_by_id || %categories_by_name;
my $data = &loadfile("config.BulkData.categories");
for my $row (@$data) {
my $cid = $row->{categoryID};
die "missing cid" unless defined $cid;
die "trying to redefine category $cid" if $categories_by_id{$cid};
$categories_by_id{$cid} = $row;
my $cname = $row->{categoryName};
die "trying to redefine category $cname" if $categories_by_name{$cname};
$categories_by_name{$cname} = $row;
}
}
### metagroups
my %metagroups_by_id;
sub metagroup_by_id ($) {
my ($id,) = @_;
&load_metagroups() unless %metagroups_by_id;
die "dont have metagroup $id" unless $metagroups_by_id{$id};
return $metagroups_by_id{$id};
}
sub load_metagroups {
return if %metagroups_by_id;
my $data = &loadfile("config.BulkData.metagroups");
for my $row (@$data) {
my $cid = $row->{metaGroupID};
die "missing cid" unless defined $cid;
die "trying to redefine metagroup $cid" if $metagroups_by_id{$cid};
$metagroups_by_id{$cid} = $row;
}
}
### units
my %units_by_id;
sub unit_by_id ($) {
my ($uid,) = @_;
&load_units() unless %units_by_id;
die "dont have unit $uid" unless $units_by_id{$uid};
return $units_by_id{$uid};
}
sub load_units {
return if %units_by_id;
my $data = &loadfile("config.BulkData.units");
die "no data" unless $data;
die "data not array: $data" unless ref $data eq 'ARRAY';
for my $row (@$data){
my $cid = $row->{unitID};
die "missing cid" unless defined $cid;
die "trying to redefine unit $cid" if $units_by_id{$cid};
$units_by_id{$cid} = $row;
}
}
###
sub loadfile ($) {
my ($fn,) = @_;
printf "FILE: %s ... ", $fn;
for my $efn ($fn, "$fn.dump", "$datadir/$fn", "$datadir/$fn.dump") {
next unless -e $efn;
printf "%s ... ", $efn;
my $cd = do $efn or die "cant do '$efn': '$!'";
die "undef cd" unless defined $cd;
die "no cd" unless $cd;
printf "%s ... ", $cd;
my $data = $cd;
if (ref $data eq 'ARRAY' && ref $data->[0] eq 'ARRAY') {
my @header = @{$data->[0]};
my $d = [];
for (@{$data->[1]}) {
my @row = @$_;
die "col count mismatch" unless scalar(@header) == scalar(@row);
my %row=();
for (0..$#row) {
my $k = $header[$_];
my $v = $row[$_];
die "trying to redefine key $k" if $row{$k};
$row{$k} = $v;
}
push @$d, \%row;
}
$data = $d;
} elsif (ref $data eq 'HASH') {
die "no data" unless $data->{data};
$data = $data->{data};
}
printf "%s ... done\n", $data;
return $data;
}
die "not found";
}
sub slurpfile ($) {
my ($fn,) = @_;
open IF, $fn or die "cant open '$fn': $!";
undef $/;
my $data = ;
close IF or die "cant close '$fn': $!";
return $data;
}