function getbodygraph($object, $hitgroups, $disparmor = '', $headers = 1, $dec = 0)
{
    $positions = array('HITGROUP_HEAD' => '78,22', 'HITGROUP_CHEST' => '78,86', 'HITGROUP_STOMACH' => '78,136', 'HITGROUP_LEFTARM' => '122,122', 'HITGROUP_RIGHTARM' => '32,122', 'HITGROUP_LEFTLEG' => '56,222', 'HITGROUP_RIGHTLEG' => '94,222');
    global $armors, $range;
    $graph = '';
    $header = '';
    if (!is_array($disparmor)) {
        $disparmor = array($disparmor);
    }
    foreach ($disparmor as $armor) {
        $graph .= "<td><div class='bodygraph'>";
        $armordata = array();
        foreach ($positions as $key => $val) {
            $armordata[$key] = isset($armors[$armor][$key]) ? round($armors[$armor][$key], 2) : 1;
        }
        $dist = dist($GLOBALS['range'], 'IN');
        $header .= "<th>{$armor} @ {$dist}</th>";
        foreach ($armordata as $key => $val) {
            $eq = '';
            if (isset($object["Damage"])) {
                $basedmg = damageatrange($object['Damage'], $range);
                $result = $basedmg * $armors['No Armor'][$key];
                $eq .= "base damage: {$basedmg}\nbase hitgroup: * {$armors['No Armor'][$key]}\n";
                if ($hitgroups[$key]) {
                    $result *= $hitgroups[$key];
                    $eq .= "ammo hitgroup: * {$hitgroups[$key]}\n";
                }
                if ($armor != 'No Armor') {
                    $eq .= "armor hitgroup: * {$val}\n";
                    $result *= $val;
                }
                if ($object['bulletcount'] > 1) {
                    $eq .= "bullet count: * {$object['bulletcount']}\n";
                    $result *= $object['bulletcount'];
                }
                $eq .= "total: {$result}\n";
            } else {
                $result = $val * $armordata[$key] * $hitgroups[$key];
            }
            $result = round($result, $dec);
            $coords = explode(',', $positions[$key]);
            $graph .= "<div title='{$eq}' style='position: absolute; left: {$coords[0]}px; top: {$coords[1]}px; width: 100px; text-align: center; transform: translate(-50%, -50%);'>{$result}</div>";
        }
        $graph .= "</div></td>";
    }
    if ($headers) {
        $retval = "<table><tr>{$header}</tr><tr>{$graph}</tr></table>";
    } else {
        $retval = "<table><tr>{$graph}</tr></table>";
    }
    return $retval;
}
function GenerateStatTable()
{
    global $stats_tables, $theater, $upgrades, $armors, $range;
    $armors = array('No Armor' => $theater['player_settings']['damage']['DamageHitgroups']);
    foreach ($theater["player_gear"] as $gearname => $data) {
        $gear = getobject("player_gear", $gearname);
        $img = getvgui($gearname, 'css');
        $thisitem = array();
        $thisitem['Img'] = $img;
        $thisitem['Name'] = getlookup($gear['print_name']);
        $thisitem['Team'] = printval($gear, "team_access");
        $thisitem['Slot'] = printval($gear, "gear_slot");
        $thisitem['Cost'] = printval($gear, "gear_cost");
        $thisitem['Weight'] = printval($gear, "gear_weight");
        $thisitem['Ammo'] = printval($gear, "extra_ammo");
        if (isset($gear["DamageHitgroups"])) {
            $thisitem['DamageHitgroups'] = getbodygraph($gear, $gear["DamageHitgroups"], '', 0, 2);
        }
        $stats_tables['Gear']['items'][$gearname] = $thisitem;
        if ($data["gear_slot"] == 'armor') {
            $armors[$thisitem['Name']] = $gear["DamageHitgroups"];
        }
    }
    foreach ($theater["weapons"] as $wpnname => $data) {
        if (isset($data["IsBase"])) {
            continue;
        }
        $thisitem = array();
        $item = getobject("weapons", $wpnname);
        $pn = getlookup($item["print_name"]);
        $img = getvgui($wpnname, 'css');
        $thisitem['Img'] = $img;
        $thisitem['Name'] = getlookup($item["print_name"]);
        $thisitem['Class'] = printval($item, "weapon_class");
        $thisitem['CR'] = printval($item, "class_restricted") ? printval($item, "class_restricted") : 0;
        $thisitem['Length'] = dist($item["barrel_length"], 'IN');
        $thisitem['Cost'] = printval($item, "weapon_cost");
        $thisitem['Slot'] = printval($item, "weapon_slot");
        $thisitem['Weight'] = printval($item, "weapon_weight");
        $thisitem['RPM'] = printval($item, "rounds_per_minute");
        $thisitem['Sway'] = printval($item, "sway");
        $thisitem['Damage'] = 0;
        if (isset($item["ballistics"])) {
            $thisitem['Fire Modes'] = printval($item["ballistics"], "FireModes");
        } else {
            $thisitem['Fire Modes'] = 'single';
        }
        if (isset($item["explosives"])) {
            $thisitem['Ammo'] = printval($item["explosives"], "entity", 1);
            $expammo = getobject("ammo", $item["ammo_clip"]["ammo_type"]);
            $thisitem['Carry'] = printval($expammo, "carry");
            $thisitem['Carry Max'] = printval($expammo, "carry");
        } elseif (isset($item["ammo_clip"])) {
            $ammo = getobject("ammo", $item["ammo_clip"]["ammo_type"]);
            $dmg = damageatrange($ammo['Damage'], $range);
            $thisitem['Damage'] = $dmg;
            if ($ammo['bulletcount'] > 1) {
                $thisitem['Damage'] = $dmg * $ammo['bulletcount'] . " max ({$ammo['bulletcount']} pellets)";
            }
            $thisitem['DamageChart'] = printval($ammo, "Damage");
            $thisitem['Spread'] = getspreadgraph($item["ballistics"]['spread']) . "<br>{$item["ballistics"]['spread']}";
            $thisitem['Recoil'] = getrecoilgraph($item['recoil']);
            $thisitem['Ammo'] = printval($item["ammo_clip"], "ammo_type", 1);
            if ($item["ammo_clip"]["clip_max_rounds"] > 1 && !$item["ballistics"]["singleReload"]) {
                $thisitem['Magazine'] = printval($item["ammo_clip"], "clip_max_rounds");
                $thisitem['Carry'] = printval($item["ammo_clip"], "clip_default") . " (" . $item["ammo_clip"]["clip_max_rounds"] * $item["ammo_clip"]["clip_default"] . ")\n";
                $thisitem['Carry Max'] = printval($item["ammo_clip"], "clip_max") . " (" . $item["ammo_clip"]["clip_max_rounds"] * $item["ammo_clip"]["clip_max"] . ")\n";
            } else {
                $thisitem['Magazine'] = printval($item["ammo_clip"], "clip_max_rounds");
                $thisitem['Carry'] = printval($item["ammo_clip"], "clip_default");
                $thisitem['Carry Max'] = printval($item["ammo_clip"], "clip_max");
            }
        } elseif (isset($item["melee"])) {
            $thisitem['Damage'] = printval($item["melee"], "MeleeDamage");
        }
        $stats_tables['Weapons']['items'][$wpnname] = $thisitem;
    }
    foreach ($theater["weapon_upgrades"] as $upname => $data) {
        if (isset($data["IsBase"])) {
            continue;
        }
        //		if ((substr($upname,0,5) == "base_") || (substr($upname,-5,5) == "_base")) {
        //			continue;
        //		}
        $upgrade = getobject("weapon_upgrades", $upname, 1);
        $img = getvgui($upname, 'css');
        $thisitem = array();
        if (isset($upgrade['attach_weapon'])) {
            if (isset($stats_tables['Weapons']['items'][$upgrade['attach_weapon']])) {
                $stats_tables['Weapons']['items'][$upgrade['attach_weapon']]['Img'] = $img;
            }
        }
        if (substr($upname, 0, 5) == "ammo_") {
            $link = "<br><a href='#{$upgrade['ammo_type_override']}'>{$upgrade['ammo_type_override']} [{$upgrade['upgrade_cost']}]</a>";
            $fn = 'Ammo';
        } else {
            $link = "<a href='#{$upname}'>" . getlookup($upgrade['print_name']) . " [{$upgrade['upgrade_cost']}]</a><br>";
            $fn = 'Upgrades';
        }
        // Add ammo and upgrade links to weapon items
        if (isset($upgrade['allowed_weapons']['weapon'])) {
            $tmp = $upgrade['allowed_weapons']['weapon'];
            $upgrade['allowed_weapons'] = is_array($tmp) ? $tmp : array($tmp);
        }
        $aw = array();
        if (isset($upgrade['allowed_weapons'])) {
            foreach ($upgrade['allowed_weapons'] as $order => $witem) {
                $aw[] = "<a href='#{$witem}'>{$stats_tables['Weapons']['items'][$witem]['Name']}</a>";
                $stats_tables['Weapons']['items'][$witem][$fn] .= $link;
            }
        }
        $thisitem['Img'] = $img;
        $thisitem['Name'] = getlookup($upgrade['print_name']);
        $thisitem['Slot'] = printval($upgrade, "upgrade_slot");
        $thisitem['CR'] = printval($upgrade, "class_restricted");
        $thisitem['Cost'] = printval($upgrade, "upgrade_cost");
        $thisitem['Ammo Type'] = printval($upgrade, "ammo_type_override", 1);
        $thisitem['Abilities'] = printval($upgrade, "weapon_abilities");
        $thisitem['Weapons'] = implode("<br>", $aw);
        $stats_tables['Upgrades']['items'][$upname] = $thisitem;
    }
    foreach ($theater["ammo"] as $ammoname => $data) {
        // Hide rockets and grenades (so we can link to them in #explosives), and other items we don't want to see at all
        if (substr($ammoname, 0, 7) == "rocket_" || substr($ammoname, 0, 8) == "grenade_" || $ammoname == 'default' || $ammoname == 'no_carry') {
            continue;
        }
        $ammo = getobject("ammo", $ammoname);
        if (!isset($ammo['carry'])) {
            continue;
        }
        $thisitem = array();
        $thisitem['Name'] = "<a id='{$ammoname}'>{$ammoname}</a>";
        $thisitem['Carry'] = printval($ammo, "carry");
        $thisitem['Mag'] = printval($ammo, "magsize");
        $dmg = damageatrange($ammo['Damage'], $range);
        if ($ammo['bulletcount'] > 1) {
            $dmg = $dmg * $ammo['bulletcount'] . " max ({$ammo['bulletcount']} pellets)";
        }
        $thisitem['Damage'] = $dmg;
        $thisitem['DamageGraph'] = printval($ammo, "Damage");
        $thisitem['PenetrationPower'] = damageatrange($ammo["PenetrationPower"], $range);
        $thisitem['PenetrationGraph'] = printval($ammo, "PenetrationPower");
        $thisitem['Tracer'] = "Type: {$ammo["tracer_type"]}<br>Frequency: {$ammo["tracer_frequency"]}<br>Low Ammo: {$ammo["tracer_lowammo"]}";
        $thisitem['Suppression'] = printval($ammo, "SuppressionIncrement");
        $thisitem['DamageHitgroups'] = getbodygraph($ammo, $ammo["DamageHitgroups"], array_keys($armors));
        $stats_tables['Ammo']['items'][$ammoname] = $thisitem;
    }
    foreach ($theater["explosives"] as $explosivename => $data) {
        if (isset($data["IsBase"])) {
            continue;
        }
        $explosive = getobject("explosives", $explosivename);
        $thisitem = array();
        $thisitem['Name'] = "<a id='{$explosivename}'>{$explosivename}</a>";
        $thisitem['Class'] = printval($explosive, "entity_class");
        $thisitem['FuseTime'] = printval($explosive, "FuseTime");
        if (isset($explosive["Cookable"])) {
            $thisitem['Cookable'] = printval($explosive, "Cookable");
        } else {
            $thisitem['Cookable'] = 1;
        }
        if (isset($explosive["RocketStartSpeed"])) {
            $speeds = array($explosive["RocketStartSpeed"]);
            if (isset($explosive["RocketTopSpeed"])) {
                if (isset($explosive["RocketAcceleration"])) {
                    for ($i = $explosive["RocketStartSpeed"] + $explosive["RocketAcceleration"]; $i < $explosive["RocketTopSpeed"]; $i += $explosive["RocketAcceleration"]) {
                        $speeds[] = $i;
                    }
                }
                $speeds[] = $explosive["RocketTopSpeed"];
            }
        }
        if (count($speeds) > 1) {
            $thisitem['Speed'] = getgraph($speeds, 'Speed', 'Time');
        } else {
            $thisitem['Speed'] = dist($explosive["RocketStartSpeed"], 'IN') . "/s";
        }
        $dmg = $range < $explosive["DetonateDamageRadius"] ? round($explosive["DetonateDamage"] * ($explosive["DetonateDamageRadius"] / ($explosive["DetonateDamageRadius"] - $range)), 2) : 0;
        $thisitem['Damage'] = $dmg;
        if (isset($explosive["AreaDamageAmount"])) {
            $thisitem['DamageGraph'] = "AreaDamageTime: {$explosive["AreaDamageTime"]}<br>AreaDamageFrequency: {$explosive["AreaDamageFrequency"]}<br>AreaDamageMinRadius: " . dist($explosive["AreaDamageMinRadius"], 'IN') . "<br>AreaDamageMaxRadius: " . dist($explosive["AreaDamageMaxRadius"], 'IN') . "<br>AreaDamageGrowSpeed: {$explosive["AreaDamageGrowSpeed"]}<br>AreaDamageAmount: {$explosive["AreaDamageAmount"]}<br>DamageType: {$explosive["DamageType"]}";
        } else {
            $thisitem['DamageGraph'] = getcirclegraph($explosive) . "<br>DetonateDamage: {$explosive["DetonateDamage"]}<br>DetonatePenetrationRadius: " . dist($explosive["DetonatePenetrationRadius"], 'IN') . "<br>DetonateDamageRadius: " . dist($explosive["DetonateDamageRadius"], 'IN');
            if (isset($explosive["DetonateFlashDuration"])) {
                $thisitem['DamageGraph'] .= "<br>DetonateFlashDuration: {$explosive["DetonateFlashDuration"]}";
            }
        }
        $stats_tables['Explosives']['items'][$explosivename] = $thisitem;
    }
    foreach ($theater['player_templates'] as $classname => $classdata) {
        $thisitem = array();
        $thisitem['Name'] = getlookup($classdata['print_name']);
        $thisitem['Team'] = printval($classdata, "team");
        $thisitem['Models'] = printval($classdata, "models");
        if (isset($classdata["buy_order"])) {
            foreach ($classdata["buy_order"] as $order => $buyitem) {
                foreach ($buyitem as $type => $item) {
                    $thisitem['Buy order'] .= "<a href='#{$item}'>{$item}</a><br>";
                }
            }
        }
        if (isset($classdata["allowed_items"])) {
            foreach ($classdata["allowed_items"] as $order => $aitem) {
                foreach ($aitem as $type => $item) {
                    if (is_array($item)) {
                        foreach ($item as $it => $in) {
                            $thisitem['Allowed Items'] .= "<a href='#{$in}'>[{$type}] {$in}</a><br>";
                        }
                    } else {
                        $thisitem['Allowed Items'] .= "<a href='#{$item}'>{$item}</a><br>";
                    }
                }
            }
        }
        $stats_tables['Classes']['items'][$classname] = $thisitem;
    }
    // Teams are goofy because of display method
    foreach ($theater['teams'] as $teamname => $teamdata) {
        $thisitem = '<table>';
        $tn = getlookup($teamdata['name']);
        $stats_tables['Teams']['fields'][$tn] = 1;
        if (isset($teamdata['logo'])) {
            $thisitem .= "<div style='text-align: center;'><img src='data/materials/vgui/{$teamdata['logo']}.png' style='width: 64px; height: 64px;'></div>\n";
        }
        if (isset($teamdata['squads'])) {
            foreach ($teamdata['squads'] as $squad => $squaddata) {
                $sn = getlookup($squad);
                $thisitem .= "<tr><td><h3>{$sn}</h3></td></tr><tr><td>\n";
                foreach ($squaddata as $order => $slot) {
                    foreach ($slot as $title => $role) {
                        $label = getlookup($title);
                        $thisitem .= "<a href='#{$role}'>{$label}<br>\n";
                    }
                }
                $thisitem .= "</td></tr>\n";
            }
        }
        $thisitem .= "</table>\n";
        $stats_tables['Teams']['items'][0][$tn] = $thisitem;
    }
    // Do cleanup and make links between items here
    foreach (array_keys($stats_tables) as $sectionname) {
        ksort($stats_tables[$sectionname]['items']);
    }
}
function printarray($object, $index, $link = 0, $nulldisp = '&nbsp;', $prefix = '')
{
    $data = '';
    if ($prefix != '') {
        $prefix .= '->';
    }
    global $range;
    $graph = in_array($index, array('Damage', 'PenetrationPower', 'PhysicsImpulse', 'PenetrationDamage')) ? 1 : 0;
    if ($graph) {
        if (!isset($object[$index][$range])) {
            $object[$index][$range] = damageatrange($object[$index], $range);
        }
        ksort($object[$index]);
    }
    $arr = array();
    $dmg = array();
    foreach ($object[$index] as $rangedist => $rangedmg) {
        if (is_array($rangedmg)) {
            $arr[] = printarray($object[$index], $rangedist, $link, $nulldisp, $prefix . $rangedist);
        } else {
            $disprange = $graph ? dist($rangedist, 'IN') : $rangedist;
            $dmg[$rangedist] = $rangedmg;
            if ($index == 'Damage' && (isset($object['bulletcount']) && $object['bulletcount'] > 1)) {
                $totaldmg = $rangedmg * $object['bulletcount'];
                $dmg[$rangedist] = $totaldmg;
                $arr[] = "{$prefix}{$disprange}: {$totaldmg}";
            } else {
                if ($index == 'DamageHitgroups' && $object['Damage']) {
                    $basedmg = array_shift(array_values($object['Damage']));
                    if ($object['bulletcount'] > 1) {
                        $basedmg = $basedmg * $object['bulletcount'];
                    }
                    $arr[] = "{$prefix}{$disprange}: {$rangedmg} (" . $rangedmg * $basedmg . " dmg)";
                } else {
                    $arr[] = "{$prefix}{$disprange}: {$rangedmg}";
                }
            }
        }
    }
    if ($graph) {
        $data = getgraph($dmg, $index) . "<br>\n";
    }
    return $data . implode('<br>', $arr);
}