MegaGlest/source/tools/convert_faction_xml2html/convert_faction_xml2html.pl

2708 lines
92 KiB
Perl
Executable File

#!/usr/bin/perl -w
# script to create HTML-pages and diagrams from the glest-factions techtree
# 20110120, bugs & feedback to olaus@rupp.de
# Copyright 2011 olaus
# Copyright 2012-2016 olaus & MegaGlest Team
# license: GPLv3 or newer
our $version = "0.8.1 beta";
# This tool requires jquery and the jquery dataTables plugin (run setupDeps.sh which uses curl to try to download these into the media folder).
# These are NOT required to run the script but are used to display the resulting html.
# general comments for running:
# - developed on ubuntu linux 10.04 and with modules from ubuntu (install with "apt-get install libgraphviz-perl libconfig-inifiles-perl libxml-xpath-perl perlmagick")
# - on non-ubuntu systems install "graphviz" using your package manager and try to also find the right perl modules with it.
# - if the package manager doesn't work install the needed perl modules using "cpan" on the command line: (untested):
# cpan> install XML::XPath;
# cpan> install GraphViz;
# cpan> install Config::IniFiles;
#
# - adjust the paths in the .ini-file to your system and run with f.e. "convert_faction_xml2html.pl mg.ini"
# - won't work on windows without adjustments (search for "system", at least ... ) and i guess some of the modules used aren't easily available for active-state-perl (graphviz also runs on windows).
# general comments for changing the code:
# - as far as possible i used "pidgin-perl" and tried to avoid complicated functions and data-structures. so hopefully anybody with bare programming skills can adopt this code to his needs
# - it runs with "use strict" and -w without any warnings. this makes coding a bit more complicated but saves lots of time in the long run, get used to it ;)
# - watch out for singular & plural in the variable-names, $harvested_resources{} ne $harvested_resource
# - if you need to read some new stuff from the XML-files, google the xpath-documentation. check if it's single- or multi-valued. use xpath.pl to check the location.
# - if you want to rewrite this in your favorite language i recommend your local xpath-module, then you can reuse the xpath-locations from this script
# - uses jquery.com and datatables.net for table sorting and searching. i recommend the firefox add-onswebdeveloper and firebug if touching these
# TODO:
# - requirement page per faction with all buildings and producing units and the units they produce (footnotes for requirements) (collect in $production{ $u } and $production_units{ $u }
# DONE:
# 0.8
# - bugfix: missing requirements in building & units diagrams
# - included all needed files in media-directory
# - reworker directory-structure in generated html-directory (best to delete the old one before upgrading!)
# - changed mg.ini and style.css to mg-webdesign (doesn't work with the wide tables because tiles are just made for narrow content in the middle)
# 0.7
# - big all and everything-table
# 0.6:
# - add png images rendered by g3d_viewer (by softcoder, thanks)
# 0.5:
# - allow relative & absolut path at the same time (relative can't start with / )
# - show what levels (f.e. elite after x kills) add to sight, armor, ...
# - show what available upgrades add to stats in each unit
# 0.4:
# - show updates available for each unit
# - fix paths with spaces
# 0.3
# - @all_html_pages with with page-title, sort by faction, special pages (keys & armor/attack)
# - fixed morph cost of thor/thortotem
# - pass http://validator.w3.org
# - images path per unit for romans (5 times guard.bmp with different content)
# - <NOBR> in cost
# - included levels
# maybe someday ...
# - compare units like http://www.imaging-resource.com/IMCOMP/COMPS01.HTM
# - support GAE skills (patrol, guard)
# - units commands in seperate table
# - links to XML-files
# - print -> &log
# - generate some descriptive text for each unit, like "this is the unit with the most hitpoints/damage to air units/armor/movement speed/... of the tech faction"
# - diff feature (CGI?) to show what changed in units if moving f.e. from vanila glest 3.2 to MG 3.4
# - make overview tables sortable (javascript?)
# - overview tables without border but different colors in odd/even rows
# - list of units this one is strong/weak against (via armor- and attack-types)
# - top-lists over all factions (units with most hit points, damage, ...)
# - calculate a "bang for the buck" for 10 units including all cost for upgrades, buildings, ...
# - multilanguage (use more icons, lng-files but unit names aren't multilanguage anyway)
# - import bitmap-icons in SVG (doesn't work with perls graphviz-module, would need to parse and change SVG)
# - map symbology below diagram
# - single pages for units with animated gif, link to XML, mini-diagram of techtree just for this unit
# - convert bmp-icons to png
# - create PDF-handbook of all units
# usefull for converting HTML-colors: http://www.yafla.com/yaflaColor/ColorRGBHSL.aspx
# strange stuff in the techtrees:
# - persian magician splash radius 0?
# - tech upgrades piercing/blade weapon don't work for battle machine?
# - f.e. battle machine with "hold" will only attack land units
# - workers are able to help a technician build an aerodrome faster. is that wanted?
####################################################################
our $cfg;
my $cfg_file;
if ( $cfg_file = shift @ARGV ) {
if ( ! -e $cfg_file ) {
die "cfg_file not existing: $cfg_file\n";
}
}
else {
$cfg_file ="megapack.ini";
}
if ( ! -e $cfg_file ) {
die "\nusage: $0 [megapack.ini]\n\n";
}
$cfg = new Config::IniFiles( -file => "./$cfg_file", -allowcontinue => 1 );
use strict;
use XML::XPath;
use XML::XPath::XMLParser;
use GraphViz;
use Config::IniFiles;
use FindBin;
use File::Spec;
use Cwd;
use File::Glob ':glob';
#use Image::Resize;
use Image::Magick;
BEGIN {
$ENV{APP_ROOT} = Cwd::realpath(File::Spec->rel2abs($FindBin::Bin)) ;
}
our $use_relative_paths = $cfg->val( 'all', 'relative_paths');
our $generate_g3d_images = $cfg->val( 'all', 'generate_g3d_images');
our $debug = $cfg->val( 'all', 'debug');
our $glest_version = $cfg->val( 'all', 'version');
our $factions_path=$cfg->val( 'files' , 'factions_path');
$factions_path = "$ENV{APP_ROOT}/$factions_path" if ( $use_relative_paths && $factions_path !~ /^\//);
our $g3dviewer_path=$cfg->val( 'files' , 'g3dviewer_path');
$g3dviewer_path = "$ENV{APP_ROOT}/$g3dviewer_path" if ( $use_relative_paths );
our $resources_path=$cfg->val( 'files' , 'resources_path');
$resources_path = "$ENV{APP_ROOT}/$resources_path" if ( $use_relative_paths && $resources_path !~ /^\// );
our $out_path=$cfg->val( 'files' , 'out_path');
$out_path = "$ENV{APP_ROOT}/$out_path" if ( $use_relative_paths && $out_path !~ /^\// );
our $pack_file=$cfg->val( 'files' , 'pack_file');
$pack_file = "$ENV{APP_ROOT}/$pack_file" if ( $use_relative_paths && $pack_file !~ /^\// );
our $units_path=$cfg->val( 'files' , 'units_path');
our $upgrades_path=$cfg->val( 'files' , 'upgrades_path');
our $images_path=$cfg->val( 'files' , 'images_path');
our $glestkeys=$cfg->val( 'files' , 'glestkeys');
$glestkeys = "$ENV{APP_ROOT}/$glestkeys" if ( $use_relative_paths && $glestkeys !~ /^\// );
our $summary = $cfg->val('files', 'summary');
our $svg_fontcolor = $cfg->val( 'style', 'svg_fontcolor');
our @armor_types;
our @attack_types;
our @resource_order = split(/:/, $cfg->val( 'style', 'resource_order') );
my $now_string = localtime;
my $me = $0;
$me =~ s/^.+\///;
our $footer=$cfg->val( 'style', 'footer');
our $map_legend = $cfg->val('style', 'map_legend');
#$footer =~ s/VAR_CREATED_BY/<I><A HREF=\"http:\/\/rupp.de\/glest\/\">$me<\/A><\/I>, version: <I>$version<\/I>, using config-file: <I>$cfg_file<\/I>, on: <I>$now_string<\/I> /;
# ^ timestamp should be in the one common footer
$footer =~ s/VAR_CREATED_BY/<I><A HREF=\"http:\/\/rupp.de\/glest\/\">$me<\/A><\/I>, version: <I>$version<\/I>, using config-file: <I>$cfg_file<\/I>/;
our $level_hp = $cfg->val('all', 'level_hp');
our $level_ep = $cfg->val('all', 'level_ep');
our $level_sight = $cfg->val('all', 'level_sight');
our $level_armor = $cfg->val('all', 'level_armor');
$|=1;
if ( ! -e $factions_path ) {
die "ERROR: cant find factions_path: $factions_path, check $cfg_file\n";
}
if ( ! -e $resources_path ) {
die "ERROR: cant find resources_path: $resources_path, check $cfg_file\n";
}
mkdir $out_path;
mkdir "$out_path/images";
if ( ! -w $out_path ) {
die "cant find out_path: $out_path or no write permission\n";
}
#our @factions = bsd_glob("$factions_path/magi*");
#our @factions = bsd_glob("$factions_path/norsemen");
#our @factions = bsd_glob("$factions_path/tec*");
#our @factions = bsd_glob("$factions_path/roma*");
#our @factions = bsd_glob("$factions_path/egy*");
our @factions = bsd_glob("$factions_path/*");
our @resources = bsd_glob( "$resources_path/*");
our @all_html_pages;
our %h_all_html_pages;
our @special_html_pages;
push @special_html_pages, "compare.html;Compare Units";
push @special_html_pages, "all.html;All Units of all Factions";
our %damage_multiplier;
our %icon;
our %max_hp;
our %max_ep;
our %regeneration;
our %regeneration_ep;
our %building;
our %armor;
our %armor_type;
our %sight;
our %time;
our %height;
our %upgrade;
our %upgrade_effects;
our %upgrades_for;
our %move_speed;
our %production_speed;
our %worker;
our %combat;
our %air_unit;
our %land_unit;
our %created_by_unit;
our %c_unit_allows;
our %c_unit_requires;
our %c_all;
our %c_resource_requirement;
our %c_resource_store;
our %c_harvested_resources;
our %max_load;
our %hits_per_unit;
our %c_unit_requirements;
our %c_upgrade_requirements;
our %u_levels;
our %graph_files;
our %c_nodes;
our %c_edges;
our %c_edges_from;
our %edges_relation;
our %multi_hop;
our %multi_hop_upgrade;
# for storing skills:
our %c_skill;
our %c_command;
our %speed;
our %ep_cost;
our %skill_type;
our %attack_range;
our %attack_strenght;
our %attack_var;
our %attack_type;
our %attack_start_time;
our %attack_land;
our %attack_air;
our %splash;
our %splash_radius;
our %splash_damage_all;
# for storing commands:
our %commands_of_unit;
our %command_type;
our %command_icon;
our %morph_skill;
our %morph_unit;
our %morph_discount;
our %move_skill;
our %move_loaded_skill;
our %attack_skill;
our %repair_skill;
our %build_skill;
our %produce_skill;
our %upgrade_skill;
our %harvest_skill;
our %produce_unit;
our %c_produced_units;
our %c_repaired_units;
our $graph_all;
our $graph_buildings;
our $graph_buildings_units;
our %tips;
# create page with all keys
if ( -f $glestkeys ) {
&create_glestkey_page();
}
if ( $cfg->val('files', 'load_tips') ) {
&load_tip_files();
}
if ( $pack_file ) {
&create_armor_vs_attack( $pack_file );
}
################################################
# built HTML for selecting faction
our $all_faction_links_overview ="";
foreach my $faction_path ( @factions ) {
my $faction = $faction_path;
$faction =~ s/.+\///;
my $faction_pretty = &format_name( $faction );
$all_faction_links_overview .= "&nbsp;<A HREF=${faction}_overview.html>$faction_pretty</a> |&nbsp;\n";
}
# remove last pipe
$all_faction_links_overview =~ s/ \|&nbsp;$//;
# built HTML-links for special pages:
our $special_pages ="Special Pages: ";
foreach my $page_tmp ( @special_html_pages ) {
my ( $page, $title ) = split(/;/, $page_tmp );
$page =~ s/$out_path\///;
$special_pages .= "<A HREF=\"$page\">$title</a> |\n";
}
# remove last pipe
chop $special_pages;
chop $special_pages;
chop $special_pages;
################################################
# copy resource images
mkdir "$out_path/images";
mkdir "$out_path/images/resources";
foreach my $resource_path ( @resources ) {
my $resource = $resource_path;
$resource =~ s/.+\///;
system "cp $resource_path/images/$resource.bmp $out_path/images/resources";
}
################################################
# read all units and draw graphs
foreach my $faction_path ( @factions ) {
my $faction = $faction_path;
$faction =~ s/.+\///;
my $faction_pretty = &format_name( $faction );
#my $graph = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "twopi" , overlap => "false");
#my $graph = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "fdp", concentrate => 1 , overlap => 0, epsilon => 0.01 );
$graph_all = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "dot", rankdir => 0 , overlap => 'false', concentrate => 1, epsilon => 0.01 );
# layout twopi, doesn't "bend" edges around nodes so the result doesn't look as good as it could
#$graph_all = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "twopi", rankdir => 0 , overlap => 'false', concentrate => 0, epsilon => 0.01 );
$graph_buildings = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "dot", rankdir => 0 , overlap => 'false', concentrate => 1, epsilon => 0.01 );
$graph_buildings_units = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "dot", rankdir => 0 , overlap => 'false', concentrate => 1, epsilon => 0.01 );
# good, from left to right:, not exactly 16:9 ;)
#my $graph = GraphViz->new( bgcolor => "0.5666,0,0.086", layout => "dot", rankdir => 1 , overlap => 0 );
print ("doing faction: $faction in path: <$faction_path>/<$units_path>\n") if ($debug);
mkdir ("$out_path/$images_path");
mkdir ("$out_path/$images_path/${faction}");
#system "cp $faction_path/loading_screen.jpg $out_path/$images_path/${faction}";
# read XML-files for all units
chdir ("$faction_path/$units_path");
opendir(UNITS, "." ) || die "cant open directory $faction_path/$units_path\n";
my @units = grep { !/\./ } readdir(UNITS);
closedir(UNITS);
foreach my $unit ( @units ) {
push @{ $c_all{"$faction"} }, $unit;
my $u = "$faction:$unit";
print "reading unit: $faction:$unit in $faction_path\n" if ( $debug );
my $unit_file ="$faction_path/$units_path/$unit/$unit.xml";
mkdir ("$out_path/$images_path/${faction}/$unit");
my ( $icon ) = &read_unit( $unit_file, $faction, $faction_path, $unit);
system "cp $faction_path/$units_path/$unit/images/$icon $out_path/$images_path/${faction}/$unit";
if ($generate_g3d_images == 1) {
my $full_png = $icon;
$full_png=~ s/\.[^.]+$//;
# use the height from the units XML-file for a rough guess on zooming the model to the right size
my $unit_height = $height{ $u };
# max to 6
$unit_height = 6 if ( $unit_height > 6 );
my $zoom = $cfg->val('style', 'unit_png_unit_zoom') - ( $unit_height * 0.15 );
# set buildings to config-value because some have just height=2 in XML
$zoom = $cfg->val('style', 'unit_png_building_zoom') if ( $building{ $u } );
my $save_as = "$out_path/$images_path/${faction}/$unit/$full_png-full.png";
if ( ! -e $save_as ) {
my $g3d_generate_cmd = "$g3dviewer_path --load-unit=$faction_path/$units_path/$unit,stop_skill,attack_skill --load-model-animation-value=0.5 --load-particle-loop-value=8 --zoom-value=$zoom --rotate-x-value=".$cfg->val('style', 'unit_png_rotate_x_value')." --rotate-y-value=".$cfg->val('style', 'unit_png_rotate_y_value')." --auto-screenshot=disable_grid,saveas-$save_as";
print "generating G3D using: [$g3d_generate_cmd]\n" if ( $debug );
my $ret = `$g3d_generate_cmd`;
print "g3d_generate said: $ret\n";
# if we need to resize the image the code below does it
#
my $image = new Image::Magick;
$image->Read($save_as);
#$image->Resize(
#width =>$cfg->val('style', 'unit_png_width'),
#height =>$cfg->val('style', 'unit_png_height')
#);
$image->Trim();
$image->Write($save_as);
#exit;
}
else {
print "g3d image already exist, skipping: $save_as\n";
}
}
}
# read XML-files for all upgrades
chdir ("$faction_path/$upgrades_path");
opendir(UPGRADES, "." ) || die "cant open directory $faction_path/$upgrades_path\n";
my @upgrades = grep { !/\./ } readdir(UPGRADES);
closedir(UPGRADES);
foreach my $upgrade ( @upgrades ) {
push @{ $c_all{"$faction"} }, $upgrade;
print "reading upgrade: $faction:$upgrade in $faction_path\n" if ( $debug );
my $upgrade_file ="$faction_path/$upgrades_path/$upgrade/$upgrade.xml";
mkdir ("$out_path/$images_path/${faction}/$upgrade");
my ( $icon ) = &read_unit( $upgrade_file, $faction, $faction_path, $upgrade );
system "cp $faction_path/$upgrades_path/$upgrade/images/$icon $out_path/$images_path/${faction}/$upgrade";
}
# don't clutter the diagram with direct links (mostly "requirement") if there's an indirect link with 2 hops.
# f.e. don't show a link that the technodrom is a requirement of the defense-tower because there's a link from
# technodrom to advanced architecture and a link from there to defense tower.
&check_multi_hops($faction);
# now the graphviz-nodes are set, do the edges
foreach my $edge ( @{$c_edges{"$faction"}} ) {
my ( $unit_from, $unit_to, $style, $relation ) = split(/:/, $edge );
print "dedge: deciding edge for $faction:$unit_from:$unit_to - $relation -style: $style\n";
# only show requirement-link of there's no build, morph or produce link
# otherwise graphviz would show a dotted line where a solid one makes more sense
if (
(
$relation eq "Requirement" ||
$relation eq "Upgrade-Requirement"
) && (
$edges_relation{"$faction:$unit_from:$unit_to:Build"} ||
$edges_relation{"$faction:$unit_from:$unit_to:Morph"} ||
$edges_relation{"$faction:$unit_from:$unit_to:Produce"}
)
) {
}
else {
my $dont_link_in_all=0;
if (
$multi_hop{"$faction:$unit_from:$unit_to"} &&
$relation ne "Build" &&
$relation ne "Morph" &&
$relation ne "Produce"
) {
$dont_link_in_all=1;
print "dedge: not showing edge $faction:$unit_from:$unit_to\n";
}
if ( $relation eq "Requirement" && $building{"$faction:$unit_to"} ) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
# only draw in the buildings-only-map if the requirement is also a building (f.e. in egypt a priest is needed for the obelisk)
if ( $building{"$faction:$unit_from"} ) {
$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
}
elsif (
$relation eq "Requirement" ||
$relation eq "Upgrade-Requirement"
) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
print "dedge: SHOWING edge $faction:$unit_from:$unit_to\n";
if ( !$upgrade{"$faction:$unit_from"} ) {
$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
}
elsif ( $relation eq "Build" ) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
#$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
elsif ( $relation eq "Upgrade" ) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
##$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
##$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
elsif ( $relation eq "Morph" ) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
##$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
elsif ( $relation eq "Produce" ) {
$graph_all -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor ) if (!$dont_link_in_all);
$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
##$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
else {
die "shouldnt happen, grep me 545454545: $relation\n";
}
}
}
# create edges in diagrams which don't show the upgrades but go via an upgrade
# f.e. edge from technodrome to defense tower via advanced architecture
foreach my $multihop ( keys %multi_hop_upgrade ) {
my ( $faction_hop, $unit_from, $unit_to ) = split(/:/, $multihop );
if ( $faction eq $faction_hop ) {
print "found multihop from building to building $unit_from to $unit_to\n";
my $style="dotted";
$graph_buildings_units -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
$graph_buildings -> add_edge("$unit_from" => "$unit_to", style => $style, color => $svg_fontcolor );
}
}
&export_graphs($faction);
if (
$cfg->val('all', 'build_clickable_map') &&
$cfg->val('all', 'export_graph') =~ /as_png/ &&
$cfg->val('all', 'export_graph') =~ /as_cmapx/
) {
&build_clickable_map( $faction );
}
}
####################################################################################
# now that we have all the unit- and upgrade-requirements: export HTML
####################################################################################
# for all and everything table:
my $all_html_table="";
my $col_order_tmp = $cfg->val('style', 'columns_all_table');
$col_order_tmp =~ s/\s//g;
my ( @col_order ) =split(/,/, $col_order_tmp );
foreach my $faction_path ( @factions ) {
my $faction = $faction_path;
$faction =~ s/.+\///;
my $faction_pretty = &format_name( $faction );
my $full_all = "<P>&nbsp;<P><HR><H1>Unit Details for Faction $faction_pretty</H1>\n";
my $overview_all = "<TABLE BORDER=1 WIDTH=\"100%\"><TR> <TH> Name
<TH> Total Cost
<TH> Hit Points
<TH> Rege- nerate
<TH> Armor Strength
<TH> Armor Type
<TH> Sight Range
";
my $overview_combat = "<H3>Combat Units</H3> $overview_all
<TH> Move Speed
<TH> Air / Ground
<TH> Attack Strength Land
<TH> Attack Strength Air
<TH> Attack Range
";
my $overview_worker = "<H3>Worker Units</H3> $overview_all
<TH> Move Speed
<TH> Air / Ground
";
my $overview_building = "<H3>Buildings</H3> $overview_all
<TH>Storage
";
my $overview_upgrades = "<H3>Upgrades</H3><TABLE BORDER=1><TR> <TH WIDTH=200> Name
<TH> Cost
<TH> Increases
<TH> Affects
<TH> Enables to build
";
# now we have read all the XMLs, loop again over all units and export them to HTML
foreach my $unit ( sort @{$c_all{"$faction"}} ) {
my $full = "";
# collect all columns seperatly and build tables in the end as configured
my %col = ();
my $u = "$faction:$unit";
print "doing HTML for $u\n" if ( $debug );
my $full_tmp = "";
my $found = 0;
my $unit_pretty = &format_name( $unit );
$col{'name'} = $unit;
$col{'name_pretty'} = $unit_pretty;
$col{'name_link'} = &link_unit($faction, $unit);
$col{'faction'} = $faction;
$col{'faction_pretty'} = &format_name( $faction );
# FULL
$full .= "\n<TABLE BORDER=1>";
$full .= "<TR><TD WIDTH=250><A NAME=\"${unit}_full\"></A>".&html_icon( $u, 64 )."</TD><TD WIDTH=500> <B>$unit_pretty</B></TD></TR>\n";
if ($generate_g3d_images == 1) {
$full .= "<TR><TD COLSPAN=2 WIDTH=750><A NAME=\"${unit}_G3Dfull\"></A>".&html_icon_png( $u, $cfg->val('style', 'unit_png_width'), $cfg->val('style', 'unit_png_height') )."</TD></TR>\n";
}
if ( $upgrade{$u} ) {
$full .= "<TR><TD>Type:</TD><TD>Upgrade</TD></TR>\n";
$col{'type'} = "Upgrade";
}
elsif ( $building{$u} ) {
$full .= "<TR><TD>Type:</TD><TD>Building</TD></TR>\n";
$col{'type'} = "Building";
}
else {
$full .= "<TR><TD>Type:</TD><TD>";
if ( $worker{$u} ) {
$full .= "Worker Unit<br>\n";
$col{'type'} = "Worker Unit";
}
# a unit might fight and build so no elsif!
if ( $combat{$u} ) {
$full .= "Combat Unit\n";
$col{'type'} = "Combat Unit";
}
$full .= "</TD></TR>\n";
}
if ( $tips{ $unit } ) {
$full .= "<TR><TD>Description:</TD><TD> ".$tips{ "${unit}_info" }."</TD></TR>\n";
$col{'tip'} = $tips{ "${unit}_info" };
}
# put cost together
my $full_tmp_cost;
my ( $cost, $cost_icon, $cost_icon_overview );
# loop over creation-methods because f.e. guard might be produced in barracks or upgraded from swordman
my $num_creation_methods =@{$created_by_unit{ $u }};
my $num_method=0;
$full .= "<TR><TD>Creation:</TD><TD>";
foreach my $created_by_unit_tmp ( @{$created_by_unit{ $u }} ) {
$num_method++;
my ( $created_by_u, $method, $discount ) = split(/:/, $created_by_unit_tmp );
my ( $cost_tmp, $cost_icon_tmp, $cost_icon_overview_tmp ) = &calc_cost_of_unit( $u, $created_by_u, $method, $discount );
$cost_icon .= $cost_icon_tmp;
my %cost_hash;
my ( @cost_resources ) = split(/,/, $cost_tmp );
foreach my $cost_res ( @cost_resources ) {
my ( $resource, $amount ) = split(/:/, $cost_res );
$col{"${resource}_${num_method}"} = $amount;
$cost_hash{ $resource } = $amount;
}
my $created;
if ( $method eq "morph" ) {
$created = "upgraded from";
$full .= "Morphing from ".&link_unit($faction, ${created_by_u})."<BR>\n";
$col{"creation_${num_method}"} = "Morphed from ".&link_unit( $faction, ${created_by_u});
}
elsif ( $method eq "produce" ) {
$created = "produced by";
$full .= "Produced by ".&link_unit($faction, ${created_by_u})."<BR>\n";
$col{"creation_${num_method}"} = "Produced by ".&link_unit( $faction, ${created_by_u});
}
elsif ( $method eq "build" ) {
$created = "built by";
$full .= "Built by ".&link_unit($faction, ${created_by_u})."<BR>\n";
$col{"creation_${num_method}"} = "Built by ".&link_unit( $faction, ${created_by_u});
}
elsif ( $method eq "upgrade" ) {
$created = "upgraded by";
$full .= "Upgraded by ".&link_unit($faction, ${created_by_u})."<BR>\n";
$col{"creation_${num_method}"} = "Upgraded by ".&link_unit( $faction, ${created_by_u});
}
else {
print "method: $method for $u $created_by_u\n";
}
if ( $num_creation_methods == 1 ) {
$full_tmp_cost .= "<TR><TD>Total Cost: </TD><TD> $cost_icon_tmp\n";
}
else {
# f.e. guard might be produced in barracks or upgraded from swordman
$full_tmp_cost .= "<TR><TD>Total Cost when ${created} ".&format_name($created_by_u).": </TD><TD> $cost_icon_tmp\n";
}
# prefer cost for produce-method in overview if more than one method (guard) because that's less micromanagement for player
if (
$num_creation_methods == 1 ||
$num_creation_methods >= 2 &&
$method eq "produce"
) {
$cost_icon_overview = $cost_icon_overview_tmp;
}
}
$full .= "</TD></TR>\n";
# put storage of resources together
my $storage="";
my $storage_icon="";
foreach my $resource_stored ( @{$c_resource_store{"$faction:$unit"}} ) {
my ( $resource, $amount ) = split(/:/, $resource_stored );
$storage .= &format_name($resource).":&nbsp;$amount, ";
$storage_icon .= &html_icon_resource($resource, 16)."&nbsp;$amount&nbsp;";
}
# remove trailing ", "
chop $storage;
chop $storage;
print "storage: $storage\n";
$col{"storage"} = $storage;
# do commands & skills
my $commands="";
my $full_attack_tmp="";
my $full_move_tmp="";
my $full_morph_tmp="";
my $full_repair_tmp="";
my $full_harvest_tmp="";
my $max_strength_vs_land = 0;
my $max_strength_vs_land_var = 0;
my $max_strength_vs_air = 0;
my $max_strength_vs_air_var = 0;
my $max_range = 0;
my $max_move_speed = 0;
my $num_move_command=0;
foreach my $c ( @{$commands_of_unit{"$u:move"}} ) {
$num_move_command++;
################################################################
# MOVE-command
################################################################
my ( $faction, $unit, $command ) = split(/:/, $c );
my $skill = $move_skill{ $c };
my $s = "$faction:$unit:$skill";
$full_move_tmp .= "<TR><TD> Move Command: ".&format_name($command)." </TD><TD> Speed: ".$speed{ $s }."</TD></TR>\n";
$col{"move_speed_${num_move_command}"} = $speed{ $s };
if ( $speed{ $s } > $max_move_speed ) {
$max_move_speed = $speed{ $s };
}
}
my $skill_on_hold_position="";
# don't ask me why this doesn't work ???????????
#$num_of_attacks = @{$commands_of_unit{"$u:attack"}};
# so do workaround:
my $num_of_attacks = 0;
foreach my $x ( @{$commands_of_unit{"$u:attack"}} ) {
$num_of_attacks++;
}
foreach my $c ( @{$commands_of_unit{"$u:attack_stopped"}} ) {
my ( $faction, $unit, $command ) = split(/:/, $c );
my $command_pretty = &format_name( $command );
$commands .= "$command_pretty, ";
# defensive-buildings like defense tower don't have an attack skill but just an attack_stopped skill
# so show this as main attack
if ( !$num_of_attacks ) {
my $full_attack_tmp_tmp;
( $full_attack_tmp_tmp, $max_strength_vs_land, $max_strength_vs_land_var, $max_strength_vs_air, $max_strength_vs_air_var, $max_range, $max_move_speed ) =
&show_attack( $c, $max_strength_vs_land, $max_strength_vs_land_var, $max_strength_vs_air, $max_strength_vs_air_var, $max_range, $max_move_speed );
$full_attack_tmp .= $full_attack_tmp_tmp;
}
else {
$skill_on_hold_position= $attack_skill{ $c };
if ( $c_upgrade_requirements{ $c } ) {
print "skill requires: $c_upgrade_requirements{ $c }\n";
$skill_on_hold_position .= ";$c_upgrade_requirements{ $c }";
}
}
}
# do all commands with <type value=attack>
my $num_attack=0;
foreach my $c ( @{$commands_of_unit{"$u:attack"}} ) {
my ( $faction, $unit, $command ) = split(/:/, $c );
my $command_pretty = &format_name( $command );
$commands .= "$command_pretty, ";
$num_move_command++;
$num_attack++;
my ($strength, $var, $range, $type, $speed, $start_time, $ep_cost ) ="";
my $full_attack_tmp_tmp;
(
$full_attack_tmp_tmp,
$max_strength_vs_land,
$max_strength_vs_land_var,
$max_strength_vs_air,
$max_strength_vs_air_var,
$max_range,
$max_move_speed,
$col{"attack_strength_$num_attack"},
$col{"attack_var_$num_attack"},
$col{"attack_range_$num_attack"},
$col{"attack_type_$num_attack"},
$col{"attack_speed_$num_attack"},
$col{"attack_start_time_$num_attack"},
$col{"attack_ep_cost_$num_attack"},
$col{"used_on_hold_position_$num_attack"},
$col{"target_$num_attack"},
) =
&show_attack( $c, $max_strength_vs_land, $max_strength_vs_land_var, $max_strength_vs_air, $max_strength_vs_air_var, $max_range, $max_move_speed, $skill_on_hold_position );
$full_attack_tmp .= $full_attack_tmp_tmp;
my $move_skill = $move_skill{ $c };
if ( $move_skill) {
my $ms = "$faction:$unit:$move_skill";
$col{"move_speed_${num_move_command}"} = $speed{ $ms };
}
}
$col{"max_move_speed"} = $max_move_speed;
# show levels
if ( $u_levels{ $u } ) {
my $level_num = 0;
$full_attack_tmp .= "<TR><TD>Level(s):</TD><TD>\n";
foreach my $level ( @{ $u_levels{ $u }} ) {
$level_num++;
$col{"max_level"} = $level_num;
my ( $name, $kills ) = split(/:/, $level );
$full_attack_tmp .= "<B>".&format_name($name)."</b> at $kills kills<BR>\n";
# let do some mathz:
$full_attack_tmp .= "Hitpoints: ".int( $max_hp{ $u } * $level_hp ** ( $level_num - 1))." -> ". int( $max_hp{ $u } * ( $level_hp ** $level_num) )."<BR>\n";
if ( $max_ep{ $u } ) {
$full_attack_tmp .= "Energy Points: ".int( $max_ep{ $u } * $level_ep ** ( $level_num -1))." -> ".int( $max_ep{ $u } * $level_ep ** $level_num)."<BR>\n";
}
$full_attack_tmp .= "Armor Strength: ".int($armor{ $u } * $level_armor ** ($level_num-1))." -> ".int( $armor{ $u } * $level_armor ** $level_num )."<BR>\n";
$full_attack_tmp .= "Sight: ".int($sight{ $u } * $level_sight ** ( $level_num -1))." -> ".int( $sight{ $u } * $level_sight ** $level_num )."<BR>\n";
# as specified in the code, thanks titi for digging it out
#maxHp+= ut->getMaxHp()*50/100;
#maxEp+= ut->getMaxEp()*50/100;
#sight+= ut->getSight()*20/100;
#armor+= ut->getArmor()*50/100;
}
$full_attack_tmp .= "</TD></TR>\n";
}
# show available upgrades for this unit
if ( $upgrades_for{ $u } ) {
$full_attack_tmp .= "<TR><TD>Upgrades Available:</TD><TD>";
foreach my $upgrade_tmp ( @{ $upgrades_for{ $u }} ) {
my ( $u_faction, $u_upgrade ) = split(/:/, $upgrade_tmp );
my ( $upgrade_benefits, $upgrade_benefits_html ) = &do_upgrade_benefits( $upgrade_tmp );
my $str_tmp = &link_unit($faction, $u_upgrade);
$str_tmp .= " ($upgrade_benefits)" if ( $upgrade_benefits );
$str_tmp .= "<BR>\n";
$full_attack_tmp .= $str_tmp;
$col{"available_upgrades"} .= $str_tmp;
}
$full_attack_tmp .= "</TD></TR>\n";
}
# morphing
my $num_morph_skill=0;
foreach my $c ( @{$commands_of_unit{"$u:morph"}} ) {
my ( $faction, $unit, $command ) = split(/:/, $c );
my $skill = $morph_skill{ $c };
my $s = "$faction:$unit:$skill";
my $skill_short = $skill;
$skill_short =~ s/_skill$//;
print "morph_command: $command $c\n";
$full_morph_tmp .= "<TR><TD> Morph Skill: ".&format_name($skill_short)." </TD><TD>";
# since f.e. the technician can morph into different units, find the one for this skill
foreach my $command ( @{$c_command{ $u }} ) {
my $c = "$u:$command";
print "comparing command: $skill of $c\n";
if ( $morph_skill{ $c } && $morph_skill{ $c } eq $skill ) {
print "fitting morph_skill and command $skill of $c\n";
$full_morph_tmp .= "Morphing to: ".&link_unit($faction, $morph_unit{ $c }).&html_icon($faction.":".$morph_unit{ $c }, 64)."<BR>\n";
$full_morph_tmp .= "Refund (Discount): ".$morph_discount{ $c }."&nbsp;%<BR>\n";
$full_morph_tmp .="Morph Speed: ".$speed{ $s }."<BR>\n";
$num_morph_skill++;
$col{"morphing_to_$num_morph_skill"} = &link_unit($faction, $morph_unit{ $c });
$col{"morphing_discount_$num_morph_skill"} = $morph_discount{ $c }."&nbsp;%<BR>\n";
$col{"morphing_speed_$num_morph_skill"} = $speed{ $s }."<BR>\n";
}
}
$full_morph_tmp .= "</TD></TR>\n";
}
# repairing
my $num_heal=0;
foreach my $c ( @{$commands_of_unit{"$u:repair"}} ) {
$num_heal++;
my ( $faction, $unit, $command ) = split(/:/, $c );
my $skill = $repair_skill{ $c };
my $s = "$faction:$unit:$skill";
my $skill_short = $skill;
$skill_short =~ s/_skill$//;
print "repair_command: $command $c\n";
$full_repair_tmp .= "<TR><TD> Repair/Heal Skill: ".&format_name($skill_short)." </TD><TD>".&format_name($skill_short)."ing: ";
$col{"heal_skill_$num_heal"} = &format_name($skill_short);
foreach my $uu ( @{$c_repaired_units{$c}} ) {
$full_repair_tmp .= &link_unit($faction, $uu).", ";
$col{"heal_units_$num_heal"} .= &link_unit($faction, $uu).", ";
}
chop $full_repair_tmp;
chop $full_repair_tmp;
chop $col{"heal_units_$num_heal"};
chop $col{"heal_units_$num_heal"};
$full_repair_tmp .="<BR>\n";
$full_repair_tmp .="Repair/Heal Speed: ".$speed{ $s }."<BR>\n";
$full_repair_tmp .= "</TD></TR>\n";
$col{"heal_speed_$num_heal"} = $speed{ $s };
}
# harvesting/mining
my $num_mine=0;
foreach my $c ( @{$commands_of_unit{"$u:harvest"}} ) {
$num_mine++;
my ( $faction, $unit, $command ) = split(/:/, $c );
my $skill = $harvest_skill{ $c };
my $s = "$faction:$unit:$skill";
my $skill_short = $skill;
$skill_short =~ s/_skill$//;
print "harvest_command: $command $c\n";
$full_harvest_tmp .= "<TR><TD> Harvest/Mine Skill: ".&format_name($skill_short)." </TD><TD>";
$col{"mine_speed_$num_heal"} = $speed{ $s };
$col{"mine_resource_$num_mine"} = "";
foreach my $resource ( @{$c_harvested_resources{$c}} ) {
$full_harvest_tmp .= &html_icon_resource( $resource, 32 );
$col{"mine_resource_$num_mine"} .= &format_name( $resource ).", ";
}
chop $col{"mine_resource_$num_mine"};
chop $col{"mine_resource_$num_mine"};
$full_harvest_tmp .="<BR>\n";
$full_harvest_tmp .="Speed: ".$speed{ $s }."<BR>\n";
$full_harvest_tmp .="Max Load: ".$max_load{ $c }."<BR>\n";
$full_harvest_tmp .="Hits per Unit: ".$hits_per_unit{ $c }."<BR>\n";
$full_harvest_tmp .= "</TD></TR>\n";
$col{"mine_speed_$num_mine"} = $speed{ $s };
$col{"mine_max_load_$num_mine"} = $max_load{ $c };
$col{"mine_hits_per_unit_$num_mine"} = $hits_per_unit{ $c };
}
# finnished with commands & skills
##########################################################
# first do name & costs, thats the same for all
my $overview_tmp = "<TR>";
$overview_tmp .= "<TD> ".&html_icon($u, 32).&link_unit($faction, $unit)."</TD>";
$overview_tmp .= "<TD>$cost_icon_overview\n";
$full .= $full_tmp_cost;
if ( $storage ) {
$full .= "<TR><TD>Storage:</TD><TD>$storage_icon\n";
if ( $storage =~ /wood/i && $storage !~ /gold/i ) {
$full .= "(Hint: This also means a worker can drop of his harvested wood into this building so it's useful to build it near trees.)";
}
$full .= "</TD></TR>\n";
}
$full .= "<TR><TD>Production Time:</TD><TD>".$time{$u}."</TD></TR>\n";
$col{"production_time"} = $time{$u};
if ( !$upgrade{$u} ) {
# OVERVIEW
$overview_tmp .= "<TD ALIGN=CENTER>".$max_hp{$u}."</TD>";
$overview_tmp .= "<TD ALIGN=CENTER>".( $regeneration{$u} || "-")."</TD>";
$overview_tmp .= "<TD ALIGN=CENTER>".( $armor{$u} || "-")."</TD>";
$overview_tmp .= "<TD ALIGN=CENTER>".( &link_attack_and_armor_types($armor_type{$u} ) )."</TD>";
$overview_tmp .= "<TD ALIGN=CENTER>".( $sight{$u} || "-")."</TD>";
$full .= "<TR><TD>Maximum Hitpoints:</TD><TD>".$max_hp{$u}."</TD></TR>\n";
$full .= "<TR><TD>Regeneration of Hitpoints:</TD><TD>".($regeneration{$u} || "-")."</TD></TR>\n";
$full .= "<TR><TD>Maximum Energy Points:</TD><TD>".$max_ep{$u}."</TD></TR>\n" if ( $max_ep{$u});
$full .= "<TR><TD>Regeneration Energy Points:</TD><TD>".$regeneration_ep{$u}."</TD></TR>\n" if ( $regeneration_ep{$u});
$full .= "<TR><TD>Armor-Strength:</TD><TD>".($armor{$u} || "-")."</TD></TR>\n";
$full .= "<TR><TD>Armor-Type:</TD><TD>".&link_attack_and_armor_types($armor_type{$u})."</TD></TR>\n";
$full .= "<TR><TD>Sight-Range:</TD><TD>".($sight{$u} || "-")."</TD></TR>\n";
$col{"max_hp"} = $max_hp{$u};
$col{"regeneration"} = $regeneration{$u};
$col{"max_ep"} = $max_ep{$u} if ( $max_ep{$u});
$col{"regeneration_ep"} = $regeneration_ep{$u} if ( $regeneration_ep{$u});
$col{"armor"} = $armor{$u};
$col{"armor_type"} = &link_attack_and_armor_types($armor_type{$u});
$col{"sight"} = $sight{$u};
}
else {
# handle upgrades
print "handling upgrade $u - $production_speed{$u} - $armor{$u}\n";
# do Increases:
my ( $upgrade_benefits, $upgrade_benefits_html ) = &do_upgrade_benefits( $u );
$full .= $upgrade_benefits_html;
$overview_tmp .= "<TD ALIGN=CENTER >&nbsp;".$upgrade_benefits;
$overview_tmp .= "<TD ALIGN=CENTER>&nbsp;";
$col{"upgrade_affects"} ="";
my $units="";
foreach my $unit_tmp ( @{$upgrade_effects{$u}} ) {
$units .= &link_unit($faction, $unit_tmp).", ";
$col{"upgrade_affects"} .= &link_unit($faction, $unit_tmp).", ";
}
chop ($units);
chop ($units);
chop $col{"upgrade_affects"};
chop $col{"upgrade_affects"};
$overview_tmp .= ($units || "")."\n";
$full .= "<TR><TD>Affects Units:</TD><TD> ".($units || "")."</TD></TR>\n" if ( $units );
}
# handle requirements. this won't go into $col for the all-table because that's not usefull in a 2D-sheet
my $req_overview_tmp;
for my $relation ('Build', 'Produce', 'Upgrade', 'Requirement', 'Upgrade-Requirement', 'Command' ) {
$found = 0;
if ( $relation =~ /Require/i ) {
$full_tmp = "<TR><TD>'$unit_pretty' is a $relation for:</TD><TD>";
}
elsif ( $relation =~ /Command/i ) {
$full_tmp = "<TR><TD>'$unit_pretty' enables commands:</TD><TD>";
}
else {
$full_tmp = "<TR><TD>'$unit_pretty' is able to $relation:</TD><TD>";
}
my $last_command="";
foreach my $unit_allows ( @{$c_unit_allows{"$faction:$unit:$relation"}} ) {
my ( $faction, $req_unit, $command ) = split(/:/, $unit_allows );
my $req_unit_pretty = &format_name( $req_unit );
$found = 1;
if ( $command ) {
$full_tmp .= &format_name($command)." : ".&link_unit($faction, $req_unit)."<br>\n";
if ( $command ne $last_command ) {
$req_overview_tmp .= "Enables command '<i>".&format_name($command)."</i>' for: ";
}
$req_overview_tmp .= &link_unit($faction, $req_unit).", ";
$last_command=$command;
}
else {
$full_tmp .= &link_unit($faction, $req_unit)."<br>\n";
$req_overview_tmp .= &link_unit($faction, $req_unit).", ";
}
}
$full_tmp .= "</TD></TR>\n";
if ( $found ) {
print "found enables for $u\n";
$full .= $full_tmp;
# detect unit & command in one cell
my $found_unit_command = grep /<A HREF=.*Enables command/, $req_overview_tmp;
if ( !$found_unit_command ) {
$req_overview_tmp = "<TD>$req_overview_tmp";
}
}
}
if ( defined $req_overview_tmp && length $req_overview_tmp ) {
chop $req_overview_tmp;
chop $req_overview_tmp;
}
$req_overview_tmp = $req_overview_tmp || "<TD>&nbsp;";
# print what's needed to build this unit and what is enabled to built by this unit
$found = 0;
$full_tmp = "<TR><TD>Needed to build '$unit_pretty':</TD><TD>";
foreach my $unit_requirement ( @{$c_unit_requires{"$faction:$unit"}} ) {
my ( $faction, $req_unit ) = split(/:/, $unit_requirement );
my $req_unit_pretty = &format_name( $req_unit );
$full_tmp .= &link_unit($faction, $req_unit)."<br>\n";
$found = 1;
}
$full_tmp .= "</TD></TR>\n";
if ( $found ) {
$full .= $full_tmp;
}
if ( $building{$u} ) {
$overview_building .= $overview_tmp;
$overview_building .= "<TD>$storage_icon</TD>\n";
}
elsif ( $upgrade{$u} ) {
$overview_tmp .= $req_overview_tmp;
$overview_upgrades .= $overview_tmp;
}
if ( $worker{$u} ) {
$overview_worker .= $overview_tmp;
$overview_worker .= "<TD ALIGN=CENTER>".($max_move_speed || "--" )."</TD>\n";
my ( $o_tmp, $f_tmp ) = &do_air_ground( $u );
$overview_worker .= $o_tmp;
$col{"air_ground"} = $o_tmp;
$full .= $f_tmp;
}
if ( $combat{$u} ) {
$overview_combat .= $overview_tmp;
$overview_combat .= "<TD ALIGN=CENTER>".($max_move_speed || "--" )."\n";
my ( $o_tmp, $f_tmp ) = &do_air_ground( $u );
$overview_combat .= $o_tmp;
$col{"air_ground"} = $o_tmp;
# avoid writting the movement-type twice into technician (worker+combat unit)
if ( !$worker{$u} ) {
$full .= $f_tmp;
}
$overview_combat .= "<TD ALIGN=CENTER>";
if ($max_strength_vs_land ) {
# next line is showing damage as plus/minus, e.g. 300+-150 (which i prefer because otherwise everybody has to calculate the
# average to tell that 200-400 is stronger than 50-450)
$overview_combat .= "$max_strength_vs_land&nbsp;+-&nbsp;$max_strength_vs_land_var";
$col{"max_strength_vs_land"} = $max_strength_vs_land;
$col{"max_strength_vs_land_var"} = $max_strength_vs_land_var;
# next line is showing damage as range, e.g. 150-450
#$overview_combat .= ($max_strength_vs_land - $max_strength_vs_land_var )."-".($max_strength_vs_land + $max_strength_vs_land_var );
}
else {
$overview_combat .= "--\n";
}
$overview_combat .= "</TD>";
$overview_combat .= "<TD ALIGN=CENTER>";
if ($max_strength_vs_air ) {
$overview_combat .= "$max_strength_vs_air&nbsp;+-&nbsp;$max_strength_vs_air_var";
#$overview_combat .= ($max_strength_vs_air - $max_strength_vs_air_var )."-".($max_strength_vs_air + $max_strength_vs_air_var );
$col{"max_strength_vs_air"} = $max_strength_vs_air;
$col{"max_strength_vs_air_var"} = $max_strength_vs_air_var;
}
else {
$overview_combat .= "--\n";
}
$overview_combat .= "</TD>";
$overview_combat .= "<TD ALIGN=CENTER>".($max_range || "--" )."</TD>\n";
$col{"max_range"} = $max_range;
}
$full .= $full_move_tmp;
$full .= $full_morph_tmp;
$full .= $full_attack_tmp;
$full .= $full_repair_tmp;
$full .= $full_harvest_tmp;
$full .= "</TABLE><P>\n";
$full_all .= $full;
my $unit_html = "$out_path/${faction}_${unit}_full.html";
push @all_html_pages, $unit_html;
my $unit_title = &format_name( $unit )." - of the $faction_pretty Faction";
$h_all_html_pages{"$faction:units"} .= "$unit_html:$unit_title;";
open (UNIT, "> $unit_html") || die "cant write unit-html: $unit_html\n";
print UNIT &header($unit_title);
print UNIT &choose_faction_html( $faction )."<P>\n";
print UNIT $full;
print UNIT $footer;
close UNIT;
# do all all everything table
$all_html_table .= "<TR>\n";
foreach my $co ( @col_order ) {
# align everything centered except numbers
my $align ="CENTER";
if ( $col{"$co"} && $col{"$co"} =~ /^\d+$/ ) {
$align="RIGHT";
}
$all_html_table .= " <TD ALIGN=$align>".($col{"$co"} || "")."</TD>\n";
}
$all_html_table .= "</TR>\n";
}
$overview_combat .= "</TABLE>\n";
$overview_worker .= "</TABLE>\n";
$overview_building .= "</TABLE>\n";
$overview_upgrades .= "</TABLE>\n";
my $overview_html = "<H1>Overview for Faction: $faction_pretty</H1>\n\n";
$overview_html .= $overview_combat;
$overview_html .= $overview_worker;
$overview_html .= $overview_building;
$overview_html .= $overview_upgrades;
# create full-page for this faction
my $html_page = "${faction}_techtree.html";
my $outfile = "$out_path/$html_page";
open (HTML, "> $outfile") || die "can't write outfile: $outfile\n";
push @all_html_pages, $html_page;
my $title = "$faction_pretty Techtree of Glest - Version $version\n";
$h_all_html_pages{"$faction:techtree"} .= "$outfile:$title";
print HTML &header( $title, $faction );
print HTML &choose_faction_html( $faction )."<P>\n";
print HTML &diagram_links_html( $faction )."<P>\n";
print HTML $overview_html;
print HTML $full_all;
print HTML $footer;
close (HTML);
# create overview-page for this faction
$outfile = "$out_path/${faction}_overview.html";
open (HTML, "> $outfile") || die "can't write faction overview $outfile\n";
push @all_html_pages, $outfile;
$title = "$faction_pretty Overview\n";
$h_all_html_pages{"$faction:overview"} = "$outfile:$title";
print HTML &header( $title, $faction );
print HTML &choose_faction_html( $faction )."<P>\n";
print HTML &diagram_links_html( $faction )."<P>\n";
print HTML &show_special_pages()."<P>\n";
print HTML $overview_html;
print HTML $footer;
close (HTML);
}
print "creating all and everything table\n";
my $outfile = "$out_path/all.html";
open (HTML_ALL, "> $outfile") || die "can't write all table $outfile\n";
push @all_html_pages, $outfile;
my $title = "All Units of all Factions\n";
$h_all_html_pages{"all"} = "$outfile:$title";
print HTML_ALL &header( $title );
print HTML_ALL &choose_faction_html()."<P>\n";
print HTML_ALL &show_special_pages()."<P>\n";
print HTML_ALL "<TABLE BORDER=0 ID=table_all><THEAD><TR>";
# do table header
foreach my $co ( @col_order ) {
print HTML_ALL "<TH>".&format_name( $co )."</TH>";
}
print HTML_ALL "</THEAD><TBODY>";
print HTML_ALL $all_html_table;
print HTML_ALL "</TBODY></TABLE>\n";
print HTML_ALL $footer;
close (HTML_ALL);
print "creating global summary page\n";
$outfile = "$out_path/$summary";
open (HTML, "> $outfile") || die "can't write summary page $outfile\n";
print HTML &header("MegaGlest Techtree Summary");
print HTML &choose_faction_html()."<P>\n";
print HTML &show_special_pages()."<P>\n";
print HTML "<A NAME=factions></a><H2>Factions:</H2>\n";
foreach my $faction_path ( @factions ) {
my $faction = $faction_path;
$faction =~ s/.+\///;
my ( @units ) =split(/;/, $h_all_html_pages{"$faction:units"} );
print HTML "<A NAME=$faction></a>\n";
print HTML "<H3>".&format_name($faction).":</H3>\n";
my ( $overview_page, $overview_title ) = split(/:/, $h_all_html_pages{"$faction:overview"} );
$overview_page =~ s/$out_path\///;
print HTML "<B>Overview:</B> <a href=\"$overview_page\">$overview_title</a><BR>\n";
my ( $full_page, $full_title ) = split(/:/, $h_all_html_pages{"$faction:techtree"} );
$full_page =~ s/$out_path\///;
print HTML "<B>All in one Page:</B> <a href=\"$full_page\">$full_title</a><BR>\n";
print HTML "<H4>Techtree Diagrams:</H4>\n";
print HTML "<UL>\n";
foreach my $map ('all', 'buildings', 'buildings_units') {
if ( $cfg->val('all', 'build_clickable_map') ) {
my ( $page, $title ) = split(/:/, $h_all_html_pages{"$faction:$map"} );
$page =~ s/$out_path\///;
print HTML "<LI><a href=\"$page\">$title</a>\n";
}
else {
# do SVG-diagrams
my $page = $graph_files{ "$faction:svg:$map" };
$page =~ s/$out_path\///;
my $title = "Techtree Diagram for ".&format_name( $faction )." - ".&format_name($map) ;
print HTML "<LI><a href=\"$page\">$title</a>\n";
}
}
print HTML "</UL>\n";
print HTML "<H4>Units, Buildings & Upgrades:</H4>\n";
print HTML "<UL>\n";
foreach my $unit ( @units ) {
my ( $page, $title ) = split(/:/, $unit );
$page =~ s/$out_path\///;
print HTML "<LI><a href=\"$page\">$title</a>\n";
}
print HTML "</UL>\n";
}
print HTML $footer;
close HTML;
# copy static files to outpath
mkdir "$out_path/js";
mkdir "$out_path/css";
system "cp $ENV{APP_ROOT}/media/*.html $out_path";
system "cp $ENV{APP_ROOT}/media/*.ico $out_path";
system "cp $ENV{APP_ROOT}/media/*.css $out_path";
system "cp $ENV{APP_ROOT}/media/*.js $out_path/js";
system "cp -r $ENV{APP_ROOT}/media/datatables $out_path/images";
exit 0;
###############################################################################
# end of main(), now subs
###############################################################################
sub create_glestkey_page {
my $html_page = "glestkeys.html";
my $title = "Keyboard Assignment";
push @special_html_pages, "$html_page;$title";
my $outfile = "$out_path/$html_page";
open (HTML, "> $outfile") || die "can't write $outfile\n";
print HTML header($title);
print HTML "Note: Keyboard assignment can be changed in glestuserkeys.ini.<P>\n";
print HTML "<TABLE BORDER=1><TH>Name<TH>Key\n";
open (KEYS, "< $glestkeys") || die "can't read glestkeys: $glestkeys\n";
while (my $line =<KEYS>) {
next if ( $line =~ /^;/ );
if ( $line =~ /(.+)=(.+)/ ) {
my $name = $1;
my $key = $2;
$name =~ s/^hotkey//gi;
my $name_pretty = $name;
# make name pretty, e.g. CameraRotateUp => Camera Rotate Up
# spaces before uppercase-chars, expect if preceeded by uppercase, then it's an abbreviation like GUI
$name_pretty =~ s/(?<![[:upper:]])([[:upper:]])/ $1/g;
# SaveGUILayout => Save GUI Layout
$name_pretty =~ s/([[:upper:]])([[:upper:]])([[:upper:]])([[:lower:]])/$1$2 $3$4/g;
# space before numbers:
$name_pretty =~ s/(\d)/ $1/;
$key =~ s/^vk//;
$key =~ s/\'//g;
print HTML "<TR><TD>$name_pretty</TD><TD ALIGN=CENTER>$key</TD></TR>\n";
}
}
print HTML "</TABLE>\n";
print HTML $footer;
close HTML;
close KEYS;
}
sub read_unit {
my ($xml_file, $faction, $faction_path, $unit, $graph) = @_;
my $xpath = XML::XPath->new( $xml_file );
my $unit_pretty = &format_name ( $unit );
# index for all assoc arrays
my $u = "$faction:$unit";
print "reading XML for $u\n" if ( $debug );
$upgrade{$u} = get_value($xpath, "/upgrade");
my $resource_requirements = "";
if ( $upgrade{$u} ) {
$icon{$u} = get_value($xpath, "/upgrade/image/\@path");
# where to find resource-requirements, used below
$resource_requirements = $xpath->find("/upgrade/resource-requirements/resource");
# effects is a typo in the original glest-XML, i'll keep it in some variables
my $effects = $xpath->find("/upgrade/effects/unit");
foreach my $effected ( $effects->get_nodelist ) {
XML::XPath::XMLParser::as_string( $effected ) =~ /name=\"(.+?)\"/;
my $unit_tmp = $1;
push @{ $upgrade_effects{ $u } }, $unit_tmp;
push @{ $upgrades_for{ "$faction:$unit_tmp" } }, $u;
}
$max_hp{$u} = get_value($xpath, "/upgrade/max-hp" );
$max_ep{$u} = get_value($xpath, "/upgrade/max-ep" );
$sight{$u} = get_value($xpath, "/upgrade/sight" );
$attack_strenght{$u} = get_value($xpath, "/upgrade/attack-strenght" );
$attack_range{$u} = get_value($xpath, "/upgrade/attack-range" );
$armor{$u} = get_value($xpath, "/upgrade/armor" );
$move_speed{$u} = get_value($xpath, "/upgrade/move-speed" );
$production_speed{$u} = get_value($xpath, "/upgrade/production-speed" );
$time{$u} = get_value($xpath, "/upgrade/time/\@value");
}
else {
# do units and buildings ...
$icon{$u} = get_value($xpath, "/unit/parameters/image/\@path");
# where to find resource-requirements, used below
$resource_requirements = $xpath->find("/unit/parameters/resource-requirements/resource");
# basic unit stats:
$max_hp{$u} = get_value($xpath, "/unit/parameters/max-hp/\@value");
$regeneration{$u} = get_value($xpath, "/unit/parameters/max-hp/\@regeneration" );
$max_ep{$u} = get_value($xpath, "/unit/parameters/max-ep/\@value");
$regeneration_ep{$u} = get_value($xpath, "/unit/parameters/max-ep/\@regeneration" );
$armor{$u} = get_value($xpath, "/unit/parameters/armor/\@value");
$armor_type{$u} = get_value($xpath, "/unit/parameters/armor-type/\@value");
$sight{$u} = get_value($xpath, "/unit/parameters/sight/\@value");
$time{$u} = get_value($xpath, "/unit/parameters/time/\@value");
$height{$u} = get_value($xpath, "/unit/parameters/height/\@value");
if ( get_value($xpath, "/unit/parameters/fields/field[\@value='land']") ) {
$land_unit{ $u } = 1;
}
# no elsif because some units are land & air, f.e. genie
if ( get_value($xpath, "/unit/parameters/fields/field[\@value='air']") ) {
$air_unit{ $u } = 1;
}
# decide if it's a worker unit by checking if it can built something
$building{$u} = get_value($xpath, "/unit/skills/skill/name[\@value='be_built_skill']");
if ( get_value($xpath, "/unit/skills/skill/type[\@value='build']") ) {
$worker{ $u } = "1";
}
else {
$worker{ $u } = "0";
}
# now the multi-value stuff:
# skills:
my $skills_path = $xpath->find("/unit/skills/skill/name/\@value");
foreach my $skill_xml ( $skills_path->get_nodelist ) {
XML::XPath::XMLParser::as_string( $skill_xml ) =~ /value=\"(.+?)\"/;
my $skill = $1;
# ignore useless skills
if ( $skill !~ /stop/i && $skill !~ /die/i && $skill !~ /loaded/i && $skill !~ /be_built/i ) {
print "skill: $skill\n";
push @{ $c_skill{ $u } }, $skill;
# index-var for storing all skills:
my $s = "$u:$skill";
$speed{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/speed/\@value");
$ep_cost{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/ep-cost/\@value");
$skill_type{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/type/\@value");
print "skill-type: <".$skill_type{ $s }.">\n";
if ( $skill_type{ $s } =~ /attack/i ) {
$combat{ $u } = 1;
$attack_range{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-range/\@value");
$attack_strenght{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-strenght/\@value");
$attack_var{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-var/\@value");
$attack_type{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-type/\@value");
$attack_start_time{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-start-time/\@value");
$attack_land{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-fields/field[\@value='land']");
$attack_air{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/attack-fields/field[\@value='air']");
my $splash = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/splash/\@value");
$splash{ $s } = 1 if ( $splash =~ /true/ );
if ( $splash{ $s } ) {
$splash_radius{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/splash/radius/\@value");
$splash_damage_all{ $s } = get_value($xpath, "/unit/skills/skill/name[\@value='$skill']/parent::*/splash/damage-all/\@value");
}
}
}
}
##########################################
# COMMANDS:
##########################################
my $commands_path = $xpath->find("/unit/commands/command/name/\@value");
foreach my $command_xml ( $commands_path->get_nodelist ) {
XML::XPath::XMLParser::as_string( $command_xml ) =~ /value=\"(.+?)\"/;
my $command = $1;
print "command: $command\n";
push @{ $c_command{ $u } }, $command;
# index-var for storing all skills:
my $c = "$u:$command";
my $command_icon_tmp = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/image/\@path");
$command_icon{ $c } = $command_icon_tmp;
$command_icon{ $c } =~ s/.+\///;
if ( $command_icon{ $c }) {
print "command icon: ".$command_icon{ $c }." for $c\n" ;
# commented to save time, not used anyway yet
system "cp $faction_path/$units_path/$unit/$command_icon_tmp $out_path/$images_path/${faction}/$unit";
}
$move_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/move-skill/\@value");
$move_loaded_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/move-loaded-skill/\@value");
$attack_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/attack-skill/\@value");
$repair_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/repair-skill/\@value");
$build_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/build-skill/\@value");
$upgrade_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/upgrade-skill/\@value");
$harvest_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/harvest-skill/\@value");
$command_type{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/type/\@value");
print "command-type: <".$command_type{ $c }.">\n";
push @{ $commands_of_unit{ "$u:$command_type{ $c }" } }, $c;
my $unit_requirements = $xpath->find("/unit/commands/command/name[\@value='$command']/parent::*/unit-requirements/*");
foreach my $unit_requirement ( $unit_requirements->get_nodelist ) {
print "req: ".XML::XPath::XMLParser::as_string( $unit_requirement ) . "\n";
XML::XPath::XMLParser::as_string( $unit_requirement ) =~ /name=\"(.+?)\"/;
my $req_name = $1;
print "FFF unit-req: $c of $u - $req_name\n";
# this can be multivalued, but not used yet so i'll be lazy
$c_unit_requirements{ $c } = $req_name;
}
my $upgrade_requirements = $xpath->find("/unit/commands/command/name[\@value='$command']/parent::*/upgrade-requirements/*");
foreach my $upgrade_requirement ( $upgrade_requirements->get_nodelist ) {
print "req: ".XML::XPath::XMLParser::as_string( $upgrade_requirement ) . "\n";
XML::XPath::XMLParser::as_string( $upgrade_requirement ) =~ /name=\"(.+?)\"/;
my $req_name = $1;
print "FFF-upgrade-req: $c of $u - $req_name\n";
# this can be multivalued, but not used yet so i'll be lazy
$c_upgrade_requirements{ $c } = $req_name;
push @{ $c_unit_allows{"$faction:$req_name:Command"} }, "$c";
}
if ( $command_type{ $c } =~ /morph/i ) {
print "found morph command: $command\n";
$morph_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/morph-skill/\@value");
my $morph_to_unit = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/morph-unit/\@name");
$morph_unit{ $c } = $morph_to_unit;
$morph_discount{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/discount/\@value");
# a guard my be produced in a barrack and morphed from a swordman so %created_by_unit has to be multivalued for each unit
push @{$created_by_unit{ "$faction:$morph_to_unit" } } , "$unit:morph:$morph_discount{ $c }";
}
elsif ( $command_type{ $c } =~ /produce/i ) {
$produce_skill{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/produce-skill/\@value");
my $produce_unit_tmp = get_value($xpath, "/unit/commands/command/type[\@value='produce']/parent::*/produced-unit");
$produce_unit{ $c } = $produce_unit_tmp;
push @{ $c_produced_units{ $u } }, $produce_unit_tmp;
}
elsif ( $command_type{ $c } =~ /repair/i ) {
my $repaired_units = $xpath->find("/unit/commands/command/name[\@value='$command']/parent::*/repaired-units/*");
foreach my $repaired_unit ( $repaired_units->get_nodelist ) {
XML::XPath::XMLParser::as_string( $repaired_unit ) =~ /name=\"(.+?)\"/;
push @{ $c_repaired_units{ $c } }, $1;
}
}
elsif ( $command_type{ $c } =~ /harvest/i ) {
my $harvested_resources = $xpath->find("/unit/commands/command/name[\@value='$command']/parent::*/harvested-resources/*");
foreach my $harvested_resource ( $harvested_resources->get_nodelist ) {
XML::XPath::XMLParser::as_string( $harvested_resource ) =~ /name=\"(.+?)\"/;
push @{ $c_harvested_resources{ $c } }, $1;
}
$max_load{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/max-load/\@value");
$hits_per_unit{ $c } = get_value($xpath, "/unit/commands/command/name[\@value='$command']/parent::*/hits-per-unit/\@value");
}
}
}
# now read $resource_requirements as set above
foreach my $resource_requirement ( $resource_requirements->get_nodelist ) {
print "req: ".XML::XPath::XMLParser::as_string( $resource_requirement ) . "\n";
XML::XPath::XMLParser::as_string( $resource_requirement ) =~ /name=\"(.+?)\" amount=\"(.+?)\"/;
my $req_name = $1;
my $req_amount = $2;
print "cost: $u $req_name:$req_amount\n";
if ( $req_amount ) {
push @{ $c_resource_requirement{ $u } }, "$req_name:$req_amount";
# sort cows to workers but avoid buildings giving food
if ( $req_amount < 0 && $req_name eq "food" && !$building{ $u } ) {
$worker{ $u } = "1";
}
}
}
# now read resources stored
my $resources_stored = $xpath->find("/unit/parameters/resources-stored/resource");
foreach my $resource_stored ( $resources_stored->get_nodelist ) {
print "req: ".XML::XPath::XMLParser::as_string( $resource_stored ) . "\n";
XML::XPath::XMLParser::as_string( $resource_stored ) =~ /name=\"(.+?)\" amount=\"(.+?)\"/;
my $res_name = $1;
my $res_amount = $2;
print "resource store: $u $res_name:$res_amount\n";
if ( $res_amount ) {
push @{ $c_resource_store{ $u } }, "$res_name:$res_amount";
}
}
# read levels
my $levels_path = $xpath->find("/unit/parameters/levels/level");
foreach my $level_xml ( $levels_path->get_nodelist ) {
XML::XPath::XMLParser::as_string( $level_xml ) =~ /name=\"(.+?)\" kills=\"(.+?)\"/;
my $name = $1;
my $kills = $2;
push @{ $u_levels{ $u } }, "$name:$kills";
}
my $url = &link_unit($faction, $unit, undef, undef, "file_only" );
# no /g to avoid spreading "shield level 2" in 3 rows
$unit_pretty =~ s/ /\n/;
# create graphviz-node
&g_add_node( $faction, $unit, $unit_pretty, $url, $building{$u}, $upgrade{$u} );
# definition of
# a. where to find requiremtns in the XML-data
# 1. if it's stored as parent-child or child-parent (REQUIREMENT, COMMAND)
# 2. which style of arrow should be used in graph (see cpan.org for graphviz-documentation)
# 3. relation between units (Produce, Build, ...)
my %req_data;
$req_data{"/unit/parameters/unit-requirements/*"} = "REQUIREMENT:dotted:Requirement";
$req_data{"/unit/parameters/upgrade-requirements/*"} = "REQUIREMENT:dotted:Upgrade-Requirement";
$req_data{"/unit/commands/command/type[\@value='upgrade']/parent::*/produced-upgrade"} = "COMMAND:solid:Upgrade";
$req_data{"/unit/commands/command/type[\@value='morph']/parent::*/morph-unit"} = "COMMAND:dashed:Morph";
$req_data{"/unit/commands/command/type[\@value='produce']/parent::*/produced-unit"} = "COMMAND:solid:Produce";
$req_data{"/unit/commands/command/type[\@value='build']/parent::*/buildings/building"} = "COMMAND:bold:Build";
foreach my $location ( keys %req_data ) {
my ( $order, $style, $relation ) = split(/:/, $req_data{"$location"} );
my $unit_requirements = $xpath->find("$location");
foreach my $unit_requirement ( $unit_requirements->get_nodelist ) {
print "req: ".XML::XPath::XMLParser::as_string( $unit_requirement ) . "\n";
XML::XPath::XMLParser::as_string( $unit_requirement ) =~ /name=\"(.+?)\"/;
my $req_name = $1;
# generating an hash of an array
if ( $order eq "COMMAND" ) {
&g_add_edge($faction, $unit, $req_name, $style, $relation );
if ( $relation eq "Morph" ) {
# dealt with in section skills
}
elsif ( $relation eq "Build" ) {
push @{$created_by_unit{ "$faction:$req_name" } } , "$unit:build";
push @{ $c_unit_allows{"$u:Build"} }, "$faction:$req_name";
print "build: $u = $req_name:build\n";
}
elsif ( $relation eq "Produce" ) {
push @{$created_by_unit{ "$faction:$req_name" } } , "$unit:produce";
push @{ $c_unit_allows{"$u:Produce"} }, "$faction:$req_name";
print "produce: $u = $req_name:produce\n";
}
elsif ( $relation eq "Upgrade" ) {
push @{$created_by_unit{ "$faction:$req_name" } } , "$unit:upgrade";
push @{ $c_unit_allows{"$u:Upgrade"} }, "$faction:$req_name";
push @{ $c_unit_requires{"$faction:$req_name"} }, $u;
print "upgrade: $u = $req_name:upgrade\n";
# some commands to upgrade of the egypt faction contain unit-requirements and upgrade-requirements
# f.e. research_scarab of the temple
my $command = get_value($xpath, "$location/parent::*/produced-upgrade[\@name='$req_name']/parent::*/name");
my $c = "$faction:$unit:$command";
my $req_name_upgrade = $c_upgrade_requirements{ $c };
if ( $req_name_upgrade ) {
print "FFF-found upgrade-req command $c to get $req_name requires: $faction:$req_name_upgrade\n";
push @{ $c_unit_requires{"$faction:$req_name"} }, "$faction:$req_name_upgrade";
&g_add_edge($faction, $req_name_upgrade, $req_name, "dotted", "Upgrade-Requirement" );
}
my $req_name_unit = $c_unit_requirements{ $c };
if ( $req_name_unit ) {
print "FFF-found unit-req command: $c to get $req_name requires: $faction:$req_name_unit\n";
push @{ $c_unit_requires{"$faction:$req_name"} }, "$faction:$req_name_unit";
&g_add_edge($faction, $req_name_unit, $req_name, "dotted", "Requirement" );
}
}
else {
die "grep me: ererrerrrerere\n";
#push @{ $c_unit_allows{$u} }, "$faction:$req_name";
#push @{ $c_unit_requires{"$faction:$req_name"} }, $u;
}
}
elsif ( $order eq "REQUIREMENT" ) {
&g_add_edge($faction, $req_name, $unit, $style, $relation );
push @{ $c_unit_allows{"$faction:$req_name:$relation"} }, $u;
push @{ $c_unit_requires{$u} }, "$faction:$req_name";
}
else {
die "unknown order: $order . grep me <sadsaasdsas\n";
}
}
}
$icon{ $u } =~ s/^.+\///;
return ( $icon{$u} );
}
sub header {
my ( $title, $faction ) = @_;
$title .= " (".$glest_version.") ";
my $header = $cfg->val('style', 'header' );
$header =~ s/VAR_TITLE/$title/g;
$header =~ s/VAR_SUMMARY/$summary/g;
return $header;
}
sub format_name {
# make "shield_level_1" => "Shield Level 1"
my ( $name ) = @_;
$name =~ s/_/ /g;
$name =~ s/(.)/\u$1/;
$name =~ s/( )(.)/$1\u$2/g;
return $name;
}
sub get_value {
my ( $xpath, $location ) = @_;
my $nodeset = $xpath->find("$location");
print "doing location $location\n";
my ($node) = $nodeset->get_nodelist;
my $value;
if ( $node ) {
my $attribute = XML::XPath::XMLParser::as_string( $node );
# get only the value of an attribute, XML::Xpath returns f.e. regeneration="3", we want just 3
if ( $attribute =~ /(?<!value-percent-multiplier)[ \t]*=[ \t]*\"[ \t]*(.+?)[ \t]*\"/ ) {
$value = $1;
if ( $attribute =~ /value-percent-multiplier[ \t]*=[ \t]*\"[ \t]*true[ \t]*\"/ ) {
$value = "$value%";
}
}
#else {
# $value = $attribute;
#}
}
return $value;
}
sub g_add_node {
my ( $faction, $unit, $unit_pretty, $url, $building, $upgrade ) = @_;
#print "g_add_node: $unit, <$url>, $building, $upgrade\n";
push @{ $c_nodes{"$faction"} }, "$unit:$unit_pretty:$url:".($building || "").":".($upgrade || "");
if ( $building ) {
$graph_all -> add_node($unit, shape => 'house', color=> 'red', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor );
$graph_buildings_units-> add_node($unit, shape => 'house', color=> 'red', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor );
$graph_buildings -> add_node($unit, shape => 'house', color=> 'red', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor );
}
elsif ( $upgrade ) {
$graph_all -> add_node($unit, shape => 'parallelogram', color=> 'green' , label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
##$graph_buildings_units -> add_node($unit, shape => 'parallelogram', color=> 'green' , label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
##$graph_buildings -> add_node($unit, shape => 'parallelogram', color=> 'green' , label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
}
# combat or work unit
else {
$graph_all -> add_node($unit, color => 'magenta', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
$graph_buildings_units -> add_node($unit, color => 'magenta', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
##$graph_buildings -> add_node($unit, color => 'magenta', label => $unit_pretty, URL => $url, fontcolor => $svg_fontcolor);
}
}
sub g_add_edge {
my ( $faction, $unit_from, $unit_to, $style, $relation ) = @_;
push @{ $c_edges{"$faction"} }, "$unit_from:$unit_to:$style:$relation";
push @{ $c_edges_from{"$faction:$unit_from"} }, "$unit_from:$unit_to:$style:$relation";
$edges_relation{"$faction:$unit_from:$unit_to:$relation"}=1;
}
sub check_multi_hops {
my ( $faction ) = @_;
# loop over all edges and check each
foreach my $edge ( @{$c_edges{"$faction"}} ) {
my ( $unit_from, $unit_to, $style, $relation ) = split(/:/, $edge );
print "#################edge_check1: $unit_from -> $unit_to\n";
# only check for Requirement and Upgrade-Requirement
if ( $relation =~ /Requirement/i ) {
# do recursion in check_edges:
if ( &check_edges( $faction, $unit_from, $unit_to, 0 ) ) {
$multi_hop{"$faction:$unit_from:$unit_to"}=1;
print "edge_check5: $faction:$unit_from:$unit_to =1\n";
}
}
# find multihop from building via upgrade to building to include in graphs without upgrades
# f.e. techndrome via advanced architecture to defense tower
elsif (
$relation eq "Upgrade" &&
$building{"$faction:$unit_from"}
) {
# in our example, check all edges from advanced architecture for links to buildings
REC: foreach my $edge ( @{$c_edges_from{"$faction:$unit_to"}} ) {
my ( $o_unit_from, $o_unit_to, $o_style, $o_relation ) = split(/:/, $edge );
if ( $building{ "$faction:$o_unit_to"} ) {
print "upgrade-multihop: $unit_from to $o_unit_to\n";
$multi_hop_upgrade{"$faction:$unit_from:$o_unit_to"}=1;
}
}
}
}
}
sub check_edges {
# recursive function to walk thru the branch of the tree and find a multi_hop
my ( $faction, $unit_from, $unit_to, $recursion_depth ) = @_;
$recursion_depth++;
my $found_multihop=0;
print "edge_check2: $faction, $unit_from, $unit_to, $recursion_depth\n";
REC: foreach my $edge ( @{$c_edges_from{"$faction:$unit_from"}} ) {
my ( $o_unit_from, $o_unit_to, $o_style, $o_relation ) = split(/:/, $edge );
print "edge_check3: $o_unit_from -> $o_unit_to\n";
if (
$unit_to eq $o_unit_to &&
# skip the record we're just checking
$recursion_depth > 1
) {
$found_multihop=1;
print "edge_check4: found an end at $o_unit_from to $unit_to\n";
last REC;
}
else {
# here &check_edges() recursivly calls itself until it finds something or $recursion_depth ==4:
if ( $recursion_depth < 4 ) {
$found_multihop = &check_edges( $faction, $o_unit_to, $unit_to, $recursion_depth );
}
}
last REC if ( $found_multihop );
}
return $found_multihop;
}
sub export_graphs {
my ( $faction ) = @_;
my ( @as_functions ) = split(/;/, $cfg->val('all', 'export_graph'));
foreach my $as_function ( @as_functions ) {
my $extension = $as_function;
if ( $extension =~ s/^as_// ) {
# all
my $graph_file ="$out_path/$images_path/$faction/${faction}_techtree_graph_all.$extension";
$graph_files{ "$faction:$extension:all" } = $graph_file;
open (OUTGRAPH, "> $graph_file") || die "cant write graph-file: $graph_file\n";
print OUTGRAPH $graph_all->$as_function;
close OUTGRAPH;
# buildings & units
$graph_file ="$out_path/$images_path/$faction/${faction}_techtree_graph_buildings.$extension";
$graph_files{ "$faction:$extension:buildings" } = $graph_file;
open (OUTGRAPH, "> $graph_file") || die "cant write graph-file: $graph_file\n";
print OUTGRAPH $graph_buildings->$as_function;
close OUTGRAPH;
# buildings
$graph_file ="$out_path/$images_path/$faction/${faction}_techtree_graph_buildings_units.$extension";
$graph_files{ "$faction:$extension:buildings_units" } = $graph_file;
open (OUTGRAPH, "> $graph_file") || die "cant write graph-file: $graph_file\n";
print OUTGRAPH $graph_buildings_units->$as_function;
close OUTGRAPH;
}
else {
die "ERROR: wrong function in ini-files: export_graph: $as_function\n\n";
}
}
}
sub build_clickable_map {
my ( $faction ) = @_;
my %cmapx;
$cmapx{'all'} = $graph_all->as_cmapx;
$cmapx{'buildings'} = $graph_buildings->as_cmapx;
$cmapx{'buildings_units'} = $graph_buildings_units->as_cmapx;
foreach my $map ('buildings', 'buildings_units', 'all') {
my $png = $graph_files{"$faction:png:map"};
my $graph_file = "$out_path/${faction}_techtree_clickable_map_${map}.html";
$graph_files{ "$faction:click_map:${map}" } = $graph_file;
open (OUTHTML, "> $graph_file") || die "cant write graph-file: $graph_file\n";
my $title = "Clickable Techtree Diagram for ".&format_name($faction)." - ".&format_name( $map );
push @all_html_pages, $graph_file;
$h_all_html_pages{"$faction:$map"} = "$graph_file:$title";
print OUTHTML &header($title);
print OUTHTML &choose_faction_html( $faction )."<P>\n";
print OUTHTML &diagram_links_html( $faction )."<P>\n";
print OUTHTML "<img src=\"images/$faction/${faction}_techtree_graph_${map}.png\" usemap=#test>\n";
print OUTHTML $cmapx{$map};
print OUTHTML $map_legend;
close OUTHTML;
}
}
sub calc_cost_of_unit {
# calculate amount for morphed units, f.e. battemachine morphed from technician
# technician costs 150 gold
# battlemachine costs 150 gold, 300 wood with 40% discount = 90 gold + 180 wood
# = 240 gold + 180 wood total (food = 1 from battlemachine because technician is gone)
# note: the "discount" is actually a refund, you pay 150 gold at morphing to the battlemachine and get 60 back when it's done
my ( $u, $created_by_u, $method, $discount, $ignore_food ) = @_;
print "\ncalc_cost_of_unit: $u\n";
my ( $faction, $unit ) = split(/:/, $u );
my ( $cost, $cost_icon, $cost_icon_overview );
my ( $morph_cost, $morph_cost_icon, $morph_cost_icon_overview );
my $cost_icon_discount;
my %morph_cost_resource;
if ( $method eq "morph" ) {
foreach my $created_by_unit_tmp ( @{$created_by_unit{ "$faction:$created_by_u" }} ) {
my ( $o_created_by_u, $o_method, $o_discount ) = split(/:/, $created_by_unit_tmp );
# here calc_cost_of_unit recusivly calls itself:
( $morph_cost, $morph_cost_icon, $morph_cost_icon_overview ) = &calc_cost_of_unit("$faction:$created_by_u", $o_created_by_u, $o_method, $o_discount, "ignore_food" );
my (@res_amounts) = split(/,/, $morph_cost );
foreach my $res_amount ( @res_amounts ) {
my ( $res, $amount ) = split(/:/, $res_amount );
$morph_cost_resource{ $res } = $amount;
print "morph_cost_resource of $u res: $res = $amount\n";
}
}
}
# loop over @resource_order to get it in the proper order (medival programmig ;)
foreach my $resource_now ( @resource_order ) {
# part 1: stupid fix for thortotem (250 stone )+ thor (gold + wood) so loop again over all resources ( @resource_order )
foreach my $resource_requirement ( @{$c_resource_requirement{$u}}, @resource_order ) {
my ( $resource, $amount ) = split(/:/, $resource_requirement );
# ignore food, housing, energy if i have to calculate the cost of a unit morphed from
if (
!$ignore_food ||
$ignore_food && (
$resource eq "gold" ||
$resource eq "wood" ||
$resource eq "stone"
)
) {
my ($amount_with_discount, $amount_total);
# part 2: stupid fix for thortotem + thor: add cost of stone in this case:
if (
!$amount &&
$resource eq $resource_now
) {
if (
$morph_cost_resource{ $resource } &&
# and check it's not in @{c_resource_requirement}, this is really stupid but i don't come up with a good solution at this
# time of the day ;)
( join(":", @{$c_resource_requirement{$u}} ) !~ /$resource/ )
) {
$amount_total = $morph_cost_resource{ $resource_now };
my ( $cost_tmp, $cost_icon_tmp, $cost_icon_overview_tmp ) = &add_costs( $resource, $amount_total );
$cost .= $cost_tmp;
$cost_icon .= $cost_icon_tmp;
$cost_icon_overview .= $cost_icon_overview_tmp;
}
}
elsif ( $resource eq $resource_now ) {
# oly use 1st letter in uppercase
my $resource_char = $resource;
$resource_char =~ s/^(.).+/\u$1/;
if ( $method && $method eq "morph" ) {
# get discount/refund and add cost of unit morphed from
if ( $resource eq "gold" || $resource eq "wood" || $resource eq "stone" ) {
$amount_with_discount = int($amount * (100-$discount)/100);
}
else {
# no discount for food, energy, housing, ...
$amount_with_discount = $amount;
}
$amount_total = $amount_with_discount + ($morph_cost_resource{ $resource } || 0 );
$cost_icon_discount .= &html_icon_resource($resource, 16)."&nbsp;$amount_with_discount&nbsp;";
}
else {
$amount_total = $amount;
}
my ( $cost_tmp, $cost_icon_tmp, $cost_icon_overview_tmp ) = &add_costs( $resource, $amount_total );
$cost .= $cost_tmp;
$cost_icon .= $cost_icon_tmp;
$cost_icon_overview .= $cost_icon_overview_tmp;
}
}
}
# handle f.e. thor where
if ( $morph_cost_resource{ $resource_now } ) {
}
}
# remove trailing ","
chop $cost;
my $cost_icon_total;
if ( $method && $method eq "morph" ) {
$cost_icon_total = "$cost_icon <BR>(Cost for ".&format_name($unit);
if ( $discount ) {
$cost_icon_total .= " with $discount&nbsp;% discount = $cost_icon_discount";
}
else {
$cost_icon_total .= " = $cost_icon_discount";
}
$cost_icon_total .= "<BR>&nbsp;+ cost for ".&link_unit($faction, $created_by_u)." = $morph_cost_icon )";
}
else {
$cost_icon_total= $cost_icon;
}
print "cost for $u: $cost\n";
return ( $cost, $cost_icon_total, $cost_icon_overview );
}
sub add_costs {
my ( $resource, $amount_total ) = @_;
print "amount_total: $resource: $amount_total \n";
my $cost .= "$resource:$amount_total,";
my $add_nbsp = "";
if ( $amount_total < 100 && ( $resource eq "gold" || $resource eq "wood" || $resource eq "stone" ) ) {
$add_nbsp = "&nbsp;&nbsp;";
}
my $cost_icon .= "<NOBR>".&html_icon_resource($resource, 16)."$amount_total</NOBR>&nbsp;";
my $cost_icon_overview .= "<NOBR>".&html_icon_resource($resource, 16)."$add_nbsp$amount_total</NOBR>&nbsp;";
return ( $cost, $cost_icon, $cost_icon_overview );
}
sub html_icon {
my ( $u, $size ) = @_;
my ( $faction, $unit ) = split(/:/, $u );
return "<IMG SRC=\"$images_path/$faction/$unit/".$icon{$u}."\" HEIGHT=$size WIDTH=$size ALT=\"".&format_name( $unit )."\">";
}
sub html_icon_png {
my ( $u, $width, $height ) = @_;
my ( $faction, $unit ) = split(/:/, $u );
my $full_png = $icon{$u};
$full_png=~ s/\.[^.]+$//;
$full_png = $full_png."-full.png";
#print("==================> USING G3D image [$unit_full_image]\n");
return "<IMG SRC=\"$images_path/$faction/$unit/".$full_png."\" ALT=\"".&format_name( $unit )."\">";
#return "<IMG SRC=\"$images_path/$faction/$unit/".$full_png."\" HEIGHT=$height WIDTH=$width ALT=\"".&format_name( $unit )."\">";
}
sub html_icon_command {
my ( $c, $size ) = @_;
my ( $faction, $unit, $command ) = split(/:/, $c );
if ( !$command_icon{$c} ) {
print "WARNING: no command icon for $c\n";
}
return "<IMG SRC=\"$images_path/$faction/$unit/".$command_icon{$c}."\" HEIGHT=$size WIDTH=$size ALT=\"".&format_name( $command )."\">";
}
sub link_unit {
# create HTML-link to a unit
my ($faction, $unit, $link_text, $link_to_single_units, $file_only ) = @_;
# default to pretty unit name if no link_text passed
if ( !$link_text ) {
$link_text = &format_name($unit);
}
my $link;
if (
$cfg->val('all', 'link_to_single_units') ||
$link_to_single_units
) {
my $file = "${faction}_${unit}_full.html";
if ( $file_only ) {
$link = $file;
}
else {
$link = "<A HREF=\"${file}\">$link_text</A>";
}
}
else {
my $file = "${faction}_techtree.html#${unit}_full";
if ( $file_only ) {
$link = $file;
}
else {
$link = "<A HREF=\"$file\">$link_text</A>";
}
}
return $link;
}
sub link_attack_and_armor_types {
my ( $link_to ) = @_;
my $html = "<a href=\"attack_and_armor_types.html#$link_to\">".&format_name($link_to)."</A>" if ( $link_to );
return $html;
}
sub show_attack {
my ( $c, $max_strength_vs_land, $max_strength_vs_land_var, $max_strength_vs_air, $max_strength_vs_air_var, $max_range, $max_move_speed, $skill_on_hold_position ) = @_;
my ( $faction, $unit, $command ) = split(/:/, $c );
my $command_pretty = &format_name( $command );
my $used_on_hold_position=0;
my $target;
my $full_attack_tmp = "<TR><TD>Attack Command: $command_pretty<BR>".&html_icon_command( $c, 32 )."</TD><TD>\n";
my $skill = $attack_skill{ $c };
# attacks have own move_skills (charge)
my $move_skill = $move_skill{ $c };
my $s = "$faction:$unit:$skill";
my $ms = "$faction:$unit:$move_skill" if ( $move_skill);
my $skill_short = $skill;
$skill_short =~ s/_skill$//;
my $skill_pretty = &format_name( $skill_short );
if ( $attack_land{ $s } ) {
if ( $attack_strenght{ $s } > $max_strength_vs_land ) {
$max_strength_vs_land = $attack_strenght{ $s };
$max_strength_vs_land_var = $attack_var{ $s };
}
}
if ( $attack_air{ $s } ) {
if ( $attack_strenght{ $s } > $max_strength_vs_air ) {
$max_strength_vs_air = $attack_strenght{ $s };
$max_strength_vs_air_var = $attack_var{ $s };
}
}
if (
$attack_land{ $s } &&
$attack_air{ $s }
) {
$target .= "Ground and air";
$full_attack_tmp .= "Target: $target units<BR>\n";
}
elsif (
$attack_air{ $s }
) {
$target .= "Only air";
$full_attack_tmp .= "Target: $target units<BR>\n";
}
elsif (
$attack_land{ $s }
) {
$target .= "Only ground";
$full_attack_tmp .= "Target: $target units<BR>\n";
}
if ( $attack_range{ $s } > $max_range ) {
$max_range = $attack_range{ $s };
}
$full_attack_tmp .= "Strength: $attack_strenght{ $s }+-$attack_var{ $s }<BR>\n";
# show attack as range ( 100-200)
#$full_attack_tmp .= "Strength: ".($attack_strenght{ $s }-$attack_var{ $s })."-".($attack_strenght{ $s }+$attack_var{ $s })."<BR>\n";
#$full_attack_tmp .= "Strength-Variance: ".$attack_var{ $s }."<BR>\n";
#$full_attack_tmp .= "Strength: ".$attack_strenght{ $s }."<BR>\n";
#$full_attack_tmp .= "Strength-Variance: ".$attack_var{ $s }."<BR>\n";
$full_attack_tmp .= "Range: ".$attack_range{ $s }."<BR>\n";
if ( $splash{ $s } ) {
$full_attack_tmp .= "Splash-Radius: $splash_radius{ $s }<BR>\n";
$full_attack_tmp .= "Splash also damages own units!<BR>\n" if ($splash_damage_all{ $s });
}
$full_attack_tmp .= "Type: ".&link_attack_and_armor_types($attack_type{ $s })." <BR>\n";
$full_attack_tmp .= "Attack Speed: ".$speed{ $s }."<BR>\n";
$full_attack_tmp .= "Start Time: ".$attack_start_time{ $s }."<BR>\n";
$full_attack_tmp .= "Energy-Cost: ".$ep_cost{ $s }."<BR>\n" if ( $ep_cost{ $s });
if ( $skill_on_hold_position ) {
my ( $s, $requirement ) = split(/;/, $skill_on_hold_position );
if ( $skill eq $s ) {
$used_on_hold_position="true";
$full_attack_tmp .= "This Attack Skill is used on \"Hold Position\"<BR>\n";
$full_attack_tmp .= "(\"Hold Position\" requires ".&link_unit($faction, $requirement).")<BR>\n" if ( $requirement);
}
}
if ( $ms) {
print "speed: $speed{ $ms } of $ms\n" ;
if ( $speed{ $ms } > $max_move_speed ) {
$max_move_speed = $speed{ $ms };
$full_attack_tmp .= "Special Move Speed: ".$speed{ $ms }." (".&format_name( $move_skill).")<BR>\n";
}
}
$full_attack_tmp .= "</TD></TR>\n";
return (
$full_attack_tmp,
$max_strength_vs_land,
$max_strength_vs_land_var,
$max_strength_vs_air,
$max_strength_vs_air_var,
$max_range,
$max_move_speed,
$attack_strenght{ $s },
$attack_var{ $s },
$attack_range{ $s },
$attack_type{ $s },
$speed{ $s },
$attack_start_time{ $s },
$ep_cost{ $s },
$used_on_hold_position,
$target,
);
}
sub html_icon_resource {
# return <IMG SRC=...> for resource (gold, wood, stone, ...)
my ($resource, $size) = @_;
return "<IMG SRC=\"images/resources/$resource.bmp\" HEIGHT=$size WIDTH=$size ALT=\"".&format_name( $resource )."\">";
}
sub load_tip_files {
foreach my $faction_path ( @factions ) {
my $faction = $faction_path;
$faction =~ s/.+\///;
my $faction_pretty = &format_name( $faction );
my $tip_file = "$faction_path/lang/${faction}_en.lng";
print "tip-file: $tip_file\n";
open (TIPS, "< $tip_file") || die "can't read tip-file: $tip_file\n";
while (my $line =<TIPS>) {
next if ( $line =~ /^;/ );
if ( $line =~ /(.+)=(.+)/ ) {
my $name = $1;
my $key = $2;
$tips{ $name } = $key;
}
}
close TIPS;
}
}
sub choose_faction_html {
my ( $faction ) = @_;
my $tmp_links = $all_faction_links_overview;
if ( $faction ) {
my $faction_pretty = &format_name( $faction );
$tmp_links =~ s/>($faction_pretty)</><I>$1<\/I></;
}
return "<H4>Choose faction: $tmp_links </H4><P>\n";
}
sub diagram_links_html {
my ( $faction ) = @_;
my $graph_file;
my $html="<H4>Techtree Diagrams: ";
for my $type ('buildings', 'buildings_units', 'all') {
#if ( $graph_files{ "$faction:click_map:$type" } ) {
if ( $cfg->val('all', 'build_clickable_map') ) {
$graph_file = "${faction}_techtree_clickable_map_${type}.html";
#$graph_file = $graph_files{ "$faction:click_map:$type" };
}
elsif ( $graph_files{ "$faction:svg:$type" } ) {
$graph_file = "${faction}_techtree_graph_${type}.svg";
}
$graph_file =~ s/.+\///;
$html .= "<a href=\"$graph_file\">".&format_name($type)."</a> |\n";
}
chop $html;
chop $html;
chop $html;
$html .="</H4>\n";
return $html;
}
sub create_armor_vs_attack {
my ( $pack_file ) = @_;
my $xpath = XML::XPath->new( $pack_file );
my $armor_types_xml = $xpath->find("/tech-tree/armor-types/armor-type");
foreach my $armor_type ( $armor_types_xml->get_nodelist ) {
XML::XPath::XMLParser::as_string( $armor_type ) =~ /name=\"(.+?)\"/;
my $armor_type_tmp = $1;
push @armor_types, $armor_type_tmp;
print "armor-type: $armor_type_tmp\n";
}
my $attack_types_xml = $xpath->find("/tech-tree/attack-types/attack-type");
foreach my $attack_type ( $attack_types_xml->get_nodelist ) {
XML::XPath::XMLParser::as_string( $attack_type ) =~ /name=\"(.+?)\"/;
my $attack_type_tmp = $1;
push @attack_types, $attack_type_tmp;
print "attack-type: $attack_type_tmp\n";
}
my $damage_multipliers_xml = $xpath->find("/tech-tree/damage-multipliers/damage-multiplier");
foreach my $damage_multiplier_tmp ( $damage_multipliers_xml->get_nodelist ) {
XML::XPath::XMLParser::as_string( $damage_multiplier_tmp ) =~ /attack=\"(.+?)\" armor=\"(.+?)\" value=\"(.+?)\"/;
my $attack = $1;
my $armor = $2;
my $value = $3;
$damage_multiplier{"$attack:$armor"} = $value;
print "damage_multiplier for $attack vs $armor = $value\n";
}
my $table = "";
$table .= "<TABLE BORDER=1><TR><TH>&nbsp;</TH>\n";
foreach my $armor ( @armor_types ) {
$table .= "<TH>&nbsp;".format_name($armor)."&nbsp;</TH>\n";
}
$table .= "</TR>\n";
foreach my $attack ( @attack_types ) {
$table .= "<TR><TH>&nbsp;".&format_name( $attack)."&nbsp;</TH>\n";
foreach my $armor ( @armor_types ) {
my $mul = ($damage_multiplier{"$attack:$armor"} || 1);
if ( $mul > 1 ) {
#$table .= "<TD BGCOLOR=LIGHTGREEN>";
$table .= "<TD>";
}
elsif ( $mul < 1 ) {
#$table .= "<TD BGCOLOR=ORANGE>";
$table .= "<TD>";
}
else {
$table .= "<TD>";
}
$table .= "&nbsp;".$mul;
$table .= "</TD>";
}
$table .= "</TR>\n";
}
$table .= "</TABLE>\n";
my $html_page = "attack_and_armor_types.html";
my $outfile = "$out_path/$html_page";
open (HTML, "> $outfile") || die "can't write outfile: $outfile\n";
my $title = "Damage Multipliers for Attack Types versus Armor Types";
push @special_html_pages, "$html_page;$title";
print HTML &header($title);
print HTML "<H5>Values larger than 1 mean more damage, smaller than 1 less damage.</H5><P>\n";
print HTML $table;
my $pack_file_short = $pack_file;
$pack_file =~ s/.+\///;
print HTML "<H5>This information is extracted from $pack_file.</H5><P>\n";
print HTML $footer;
close HTML;
}
sub do_air_ground {
# show if unit is on field air,ground or both
my ( $u ) = @_;
my $overview_tmp .= "<TD ALIGN=CENTER>";
my $full_tmp .= "<TR><TD>Movement Type:</TD><TD>";
# air + land means land (f.e. tech archer)
# units can't be both, although that would seem ok for the genie
if (
$land_unit{ $u } ||
(
$air_unit{ $u } &&
$land_unit{ $u }
)
) {
$overview_tmp .= "Ground";
$full_tmp .= "Ground Unit";
}
elsif ( $air_unit{ $u } ) {
$overview_tmp .= "Air";
$full_tmp .= "Air Unit";
}
else {
print "WARNING: unit neither air nor ground: $u\n";
}
$overview_tmp .= "</TD>\n";
$full_tmp .= "</TD>\n";
return ( $overview_tmp, $full_tmp );
}
sub show_special_pages {
return "<H4>$special_pages</H4>";
}
sub do_upgrade_benefits {
# show the benefit of an upgrade
my ( $u ) = @_;
my $upgrade_benefits="";
my $upgrade_benefits_html="";
$upgrade_benefits_html .= "<TR><TD>Increase Hitpoints:&nbsp;</TD><TD>+".$max_hp{$u}."</TD></TR>\n" if ( $max_hp{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Energy-Points:&nbsp;</TD><TD>+".$max_ep{$u}."</TD></TR>\n" if ( $max_ep{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Sight:&nbsp;</TD><TD>+".$sight{$u}."</TD></TR>\n" if ( $sight{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Attack&nbsp;Strength:&nbsp;</TD><TD>+".$attack_strenght{$u}."</TD></TR>\n" if ( $attack_strenght{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Attack&nbsp;Range:&nbsp;</TD><TD>+".$attack_range{$u}."</TD></TR>\n" if ( $attack_range{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Armor:&nbsp;</TD><TD>+".$armor{$u}."</TD></TR>\n" if ( $armor{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Move:&nbsp;</TD><TD>+".$move_speed{$u}."</TD></TR>\n" if ( $move_speed{$u} );
$upgrade_benefits_html .= "<TR><TD>Increase Production&nbsp;Speed:&nbsp;</TD><TD>+".$production_speed{$u}."</TD></TR>\n" if ( $production_speed{$u} );
$upgrade_benefits = $upgrade_benefits_html;
# for overview remove HTML-tags
$upgrade_benefits =~ s/<\/?TD>//gi;
$upgrade_benefits =~ s/<TR>//gi;
$upgrade_benefits =~ s/<\/TR>/, /gi;
$upgrade_benefits =~ s/Increase //gi;
# remove last coma
$upgrade_benefits =~ s/, $//g;
# remove trailing whitespace
$upgrade_benefits =~ s/\s+$//g;
return ( $upgrade_benefits, $upgrade_benefits_html );
}