diff --git a/www/include/Git.php b/www/include/Git.php index 3906505..8431641 100644 --- a/www/include/Git.php +++ b/www/include/Git.php @@ -1,5 +1,6 @@ execute("git clone --filter=blob:none --depth 1 --sparse {$escRepo} --branch {$escBranch} {$escDestDir}"); + $out = $this->execute("git clone --filter=blob:none --depth 1 --sparse {$escRepo} --branch {$escBranch} {$escDestDir}"); foreach ($sparseFolders as $folder) { $escFolder = escapeshellarg($folder); - $this->execute("cd {$escDestDir} && git sparse-checkout add {$escFolder}"); + $out = $this->execute("cd {$escDestDir} && git sparse-checkout add {$escFolder}"); } } else { - $this->execute("git clone {$escRepo} {$escDestDir}"); + $out = $this->execute("git clone {$escRepo} {$escDestDir}"); + print_r($out); } } private function execute($command) { - $output = shell_exec($command); + $output = null; + $retval = null; + logDebug($command); + exec($command, $output, $retval); + + if ($retval != 0) { + logDebug("Returned with status $retval and output: \n"); + print_r($output); + exit ($retval); + } + return $output; } } diff --git a/www/index.php b/www/index.php index a615f07..42bc095 100755 --- a/www/index.php +++ b/www/index.php @@ -1,4 +1,7 @@ - \ No newline at end of file + diff --git a/www/res/scripts/calculations.php b/www/res/scripts/calculations.php index a018ef9..73f3a44 100644 --- a/www/res/scripts/calculations.php +++ b/www/res/scripts/calculations.php @@ -1,28 +1,50 @@ MuzzleSalvoSize; - if ($mss == 1){ - $bones = 0; - foreach($weapon->RackBones as $rack){ - $bones += count((array)$rack->MuzzleBones); + + /// Now we need determine if the weapon fires from multiple muzzles simultaneously (or close to it). + if (property_exists($weapon, 'RackFireTogether') && ($weapon->RackFireTogether == 1)) { + /// Count up all the muzzles in all the racks + foreach ($weapon->RackBones as $rack) { + $MuzzleCount += count((array)$rack->MuzzleBones); } - return $bones; + $firecycle = $mss * $MuzzleCount; } - else{ - return $mss * count((array)$weapon->RackBones); + // Do all real weapons have MuzzleSalvoDelay? + // else if (property_exists($weapon, 'MuzzleSalvoDelay') && $weapon->MuzzleSalvoDelay == 0) { + else if ($weapon->MuzzleSalvoDelay == 0) { + /// Count only the muzzles in the first rack, since RackFireTogether is false + /// We do not use MuzzleSalvoSize (mss) when MuzzleSalvoDelay is 0. + /// Cast to an array, in case it is only a string instead of an array, (PHP 8) + $MuzzleCount = count((array)$weapon->RackBones[0]->MuzzleBones); + $firecycle = $MuzzleCount; + } else { + $firecycle = $mss; } + } + + return $firecycle; + } // Source : https://github.com/spooky/unitdb/blob/master/app/js/dps.js // (calculations provided by Exotic_retard) - function calculateDps($stdClassWeapon, $unitID){ + function calculateDps($stdClassWeapon, $unitID, $Projectile){ $weapon = arrayCastRecursive($stdClassWeapon); // StdClass are a PAIN to use in PHP // Hardcoded exceptions $specials = [ - 'UEL0103', // lobo - 'XSL0103', // zthuee 'DAA0206', // mercy 'XAA0306' // solace ]; @@ -31,7 +53,7 @@ function calculateDps($stdClassWeapon, $unitID){ $shots = 1; - if (isset($weapon["MuzzleSalvoSize"])) $shots = calculateFireCycle($stdClassWeapon); + if (isset($weapon["MuzzleSalvoSize"])) $shots = calculateFireCycle($stdClassWeapon, $unitID); // fall back to the old calculation formula for the special snowflakes @@ -46,7 +68,7 @@ function calculateDps($stdClassWeapon, $unitID){ // in theory if your total MuzzleSalvoDelay is longer than the reload time your weapon waits for the reload time twice, // but thats pretty much a bug so not taken into account here - + /// BTW - SpookyDB uses round(), not floor(), based on the values seen there. Values will not match between DBs. floor() is the correct method. $trueReload = max(0.1*floor(10 / $weapon["RateOfFire"]), 0.1); $trueReload = max( ($weapon["RackSalvoChargeTime"] ?? 0) + ($weapon["RackSalvoReloadTime"] ?? 0) + @@ -54,22 +76,32 @@ function calculateDps($stdClassWeapon, $unitID){ $trueReload ); - $trueSalvoSize = 1; - if (($weapon["MuzzleSalvoDelay"] ?? 0) > 0) { // if theres no muzzle delay, all muzzles fire at the same time - $trueSalvoSize = ($weapon["MuzzleSalvoSize"] ?? 1); - } else if ($weapon["RackBones"] && count($weapon["RackBones"]) > 0) { // dummy weapons dont have racks - if ($weapon["RackFireTogether"]) { - $trueSalvoSize = count($weapon["RackBones"]) * count($weapon["RackBones"][0]["MuzzleBones"]); - } else if (count($weapon["RackBones"]) > 0) { - $trueSalvoSize = count($weapon["RackBones"][0]["MuzzleBones"]); +/* + Code for calculating missile/projectile count should only be done in calculateFireCycle. + We don't want to calculate fire cycles in two places. Just use the value returned from that function. +*/ + $trueSalvoSize = $shots; + + $trueDamage = $weapon["Damage"] * ($weapon["DoTPulses"] ?? 1) + ($weapon["InitialDamage"] ?? 0); + + /// For weapons with fragmentation shells (Lobo, Zthuee, Salvation). + if (isset($Projectile) && property_exists($Projectile->Physics, 'Fragments')) { + $trueSalvoSize = $trueSalvoSize * $Projectile->Physics->Fragments; + /// Exception for Salvation + if ($unitID == "XAB2307") { + /// Salvation uses a shell that fragments into 6 shells, which then fragments into 6 more. + /// Only first fragmentation is accounted for above. Hard code the 2nd one by multiplying by 6. + $trueSalvoSize = $trueSalvoSize * 6; } + } - $trueDamage = $weapon["Damage"]*($weapon["DoTPulses"] ?? 1) + ($weapon["InitialDamage"] ?? 0); - // beam weapons are a thing and do their own thing. yeah good luck working out that. - $trueDamage = max((floor(($weapon["BeamLifetime"] ?? 0) / (($weapon["BeamCollisionDelay"] ?? 0)+0.1))+1)*$weapon["Damage"], $trueDamage); + $trueDamage = max((floor(($weapon["BeamLifetime"] ?? 0) / (($weapon["BeamCollisionDelay"] ?? 0) + 0.1)) + 1) * $weapon["Damage"], $trueDamage); + if ($trueSalvoSize == 0) $trueSalvoSize = 1; // Adjustment needed for beam weapons + $salvoDamage = $trueSalvoSize * $trueDamage * ($isSpecial ? $shots : 1); + $trueDPS = ($salvoDamage / $trueReload); return $trueDPS; diff --git a/www/res/scripts/functions.php b/www/res/scripts/functions.php index 3451ad6..e403900 100755 --- a/www/res/scripts/functions.php +++ b/www/res/scripts/functions.php @@ -1,19 +1,38 @@ '; + print_r($val); + echo ''; +} + +// For some values, I want to see the decimals, unless they don't exist. +function number_format_unlimited_precision($number, $decimal = '.') +{ + $broken_number = explode($decimal, $number); + if (count($broken_number) == 2) { + return number_format($broken_number[0]) . $decimal . $broken_number[1]; + } else { + return number_format($broken_number[0]); + } +} + function categorizeUnitData($categoriesOrder, $userSettings, $dataUnits){ $finalData = array(); @@ -26,16 +45,17 @@ function categorizeUnitData($categoriesOrder, $userSettings, $dataUnits){ /// This chunk of code can be used to skip units lacking an icon, a preview, or basic general information. /// Useful to avoid displaying debug units. - /* + /// Filter is >necessary<, in fact, because some of these units can cause the script to fail. + /// Added filter to prevent units that don't have a 'faction'. if (!property_exists($item, 'StrategicIconName') || !property_exists($item, 'General') || - !property_exists($item->General, 'Icon')){ + !property_exists($item->General, 'Icon') || + !property_exists($item->General, 'FactionName')) { continue; } - */ /// Formatting the Faction name to ensure it has good casing : Aeon, Cybran, Seraphim, UEF, Nomads - $faction = formatFaction($item->General->FactionName); + $faction = formatFaction($item->General->FactionName); /// Adding the army to the list, given the user said he wanted to see it. if (!in_array($faction, $armies) && in_array($faction, $userSettings['showArmies'])){ @@ -501,10 +521,11 @@ function displayBuildlist($info, $thisUnit, $userSettings, $dataUnits, $dataLoc) /// Checks every unit in the $data to see which ones correspond to the right buildable category /// and populates the $buildable with them foreach($dataUnits as $unit){ - foreach($thisUnit->Economy->BuildableCategory as $buildableCategory){ + /// (array) Type cast needed in case BuildableCategory is only a string (for PHP 8) + foreach((array)$thisUnit->Economy->BuildableCategory as $buildableCategory){ $buildableRequirements = explode(' ', $buildableCategory); $canBuild = true; - foreach($buildableRequirements as $requirement){ + foreach((array)$buildableRequirements as $requirement){ if (!in_array($requirement, $unit->Categories) && strtoupper($requirement) != strtoupper($unit->Id)){ $canBuild = false; } @@ -874,21 +895,48 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ '.($thisWeapon->DamageType).' '; - } + } + + + /// If the weapon uses a missile, and we have this missile in the $data, lets display more information about the missile + /// We need to find the missile/projectile before the DPS calculation, in case it uses a fragmentation weapon. + $WeaponProjectile = NULL; + + if (property_exists($thisWeapon, 'ProjectileId')) { + + $foundArr = []; + $found = preg_match('~(?<=projectiles\/).*(?=\/)~', $thisWeapon->ProjectileId, $foundArr); + + if ($found) { + + $projectileId = $foundArr[0]; + /// There has got to be a better way to do this, right? Should make an array for projectiles at some future point. + if (strlen($projectileId) > 0) { + /// searching the needle in the haystack... + foreach ($dataMissiles as $thisMissile) { + if (strtoupper($thisMissile->Id) == strtoupper($projectileId)) { + // found it ! + $WeaponProjectile = $thisMissile; + break; + } + } + } + } + } - /// Approximate DPS + /// Approximate DPS if (property_exists($thisWeapon, 'Damage') && $thisWeapon->Damage > 0 && - $thisWeapon->WeaponCategory != "Death"){ + $thisWeapon->WeaponCategory != "Death"){ echo '
Approximate DPS
- '.format(calculateDps($thisWeapon, $info['Id'])).' + '.format(calculateDps($thisWeapon, $info['Id'], $WeaponProjectile)).'
'; - } + } /// Specific Damage styled display if the weapon has damage if (property_exists($thisWeapon, 'Damage') && @@ -931,7 +979,7 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ Fire cycle
- '.calculateFireCycle($thisWeapon).' projectiles / shot + '.calculateFireCycle($thisWeapon, $info['Id']).' projectiles / shot
'; } @@ -976,75 +1024,55 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ Nuke damage
- '.format($thisWeapon->NukeOuterRingDamage).'-'.format($thisWeapon->NukeInnerRingDamage).' + '.format($thisWeapon->NukeInnerRingDamage).'-'.format($thisWeapon->NukeOuterRingDamage).'
'; } - - /// If the weapon uses a missile, and we have this missile in the $data, lets display more information about the missile - if (property_exists($thisWeapon, 'ProjectileId')){ - - $foundArr = []; - $found = preg_match('~(?<=projectiles\/).*(?=\/)~', $thisWeapon->ProjectileId, $foundArr); - - if ($found){ - - $projectileId = $foundArr[0]; - - if (strlen($projectileId) > 0){ - /// searching the needle in the haystack... - foreach($dataMissiles as $thisMissile){ - if ($thisMissile->Id == strtoupper($projectileId)){ - // found it ! - - /// Display the blueprint + github link - echo ' -
-
- Missile ID/BP -
-
- - '.($projectileId).' - -
-
'; - - /// Display cost if any - if (property_exists($thisMissile, 'Economy')){ - $eco = $thisMissile->Economy; - echo ' -
-
- Missile Cost -
-
-
-
- nrg '.format($eco->BuildCostEnergy).' - Energy cost -
-
- mss '.format($eco->BuildCostMass).' - Mass cost -
-
- tim '.format($eco->BuildTime).' - Build time -
-
-
-
'; - } - break; - } - } - - } - } + + + /// Display the blueprint + github link + if (isset($projectileId)) { + echo ' +
+
+ Missile ID/BP +
+
+ + ' . ($projectileId) . ' + +
+
'; } + /// Display cost if any + if (isset($WeaponProjectile) && property_exists($WeaponProjectile, 'Economy')){ + $eco = $WeaponProjectile->Economy; + echo ' +
+
+ Missile Cost +
+
+
+
+ nrg '.format($eco->BuildCostEnergy).' + Energy cost +
+
+ mss '.format($eco->BuildCostMass).' + Mass cost +
+
+ tim '.format($eco->BuildTime).' + Build time +
+
+
+
'; + } + /// Displaying every generic property now foreach($propertiesToDisplayGreaterThanZero as $thisProp){ if (property_exists($thisWeapon, $thisProp) && @@ -1054,7 +1082,7 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ '.caseFormat($thisProp).'
- '.format($thisWeapon->$thisProp).' + '.number_format_unlimited_precision($thisWeapon->$thisProp).'
'; } @@ -1067,7 +1095,7 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ '.caseFormat($thisProp).'
- '.format($thisWeapon->$thisProp).' + '.number_format_unlimited_precision($thisWeapon->$thisProp).'
'; } @@ -1079,7 +1107,7 @@ function displayWeapon($thisWeapon, $info, $thisUnit, $dataLoc, $userSettings, $ '.caseFormat($thisProp).'
- '.format($thisWeapon->$thisProp).' + '.number_format_unlimited_precision($thisWeapon->$thisProp).'
'; } @@ -1393,6 +1421,7 @@ function displayUnitSupport($info, $thisUnit){ color:'.getFactionColor($info['Faction'], 'bright').';"> Vision : '.($intel->VisionRadius).' '; + if (property_exists($intel, 'RadarRadius')) echo '
Intel, "WaterVisionRadius") || property_exists($thisUnit->Intel, "OmniRadius"))) - ){ + ) + { echo '
'; @@ -1462,7 +1492,7 @@ function displayUnitSupport($info, $thisUnit){ "OmniRadius" ); - foreach($thisUnit->Intel as $key=>$value){ + foreach((array)$thisUnit->Intel as $key=>$value){ if (!in_array($key, $whitelist)){ continue; } @@ -1503,7 +1533,7 @@ function displayUnitAbilities($info, $dataLoc, $lang){
'; - foreach($abilities as $thisAb){ + foreach((array)$abilities as $thisAb){ echo '
clone($repoDir, $version); +/* End of github dependent section */ copyFolder($repoDir . "/projectiles", path($dataFolder, 'projectiles')); copyFolder($repoDir . "/units", path($dataFolder, 'units')); @@ -193,33 +209,40 @@ function locfileToPhp($locContent) unzipFiles("data/loc/loc_US.scd.3599", path($locFolder, 'loc_US.3599')); unzipFiles("data/loc/loc.nx2", path($locFolder, 'loc.nx2')); -$folders = [ 'projectiles.3599', 'units.3599', 'projectiles', 'units', 'loc_US.3599', 'loc.nx2', 'loc' ]; +$folders = [ 'projectiles.3599', 'units.3599', 'projectiles', 'units', 'loc\\loc_US.3599', 'loc\\loc.nx2']; $valid_types = [ 'unit.bp', 'proj.bp', 'db.lua' ]; $blueprints = array(); $bpFiles = array(); $locFiles = array(); -$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dataFolder)); -foreach ($iterator as $file) { - if ($file->isDir()) continue; - $filename = $file->getFilename(); - if ($filename == '.' || $filename == '..') continue; - if (strpos($filename, '_') == false) continue; - list($blueprintId, $type) = explode('_', $filename); - if (!in_array($type, $valid_types)) continue; - - $path = $file->getPathname(); - - if ($type == 'db.lua') { - // get parent folder of file - $parentFolder = basename(dirname($path)); - $lang = strtoupper($parentFolder); - $locFiles[$lang] = $path; - } - else { - $bpFiles[$blueprintId] = $path; - } +// It is >critical< that the folders are read in the order specified by the $folders variable. +// The .3599 folders must be read first, otherwise old values will appear in the results. + +foreach ($folders as $thisFolder) { + $thisPath = $dataFolder."\\".$thisFolder; + + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($thisPath)); + foreach ($iterator as $file) { + if ($file->isDir()) continue; + $filename = $file->getFilename(); + if ($filename == '.' || $filename == '..') continue; + if (strpos($filename, '_') == false) continue; + list($blueprintId, $type) = explode('_', $filename); + if (!in_array($type, $valid_types)) continue; + + $path = $file->getPathname(); + + if ($type == 'db.lua') { + // get parent folder of file + $parentFolder = basename(dirname($path)); + $lang = strtoupper($parentFolder); + $locFiles[$lang] = $path; + } + else { + $bpFiles[$blueprintId] = $path; + } + } } $blueprint = array(); @@ -280,4 +303,4 @@ function hideUpdateMenu() {
-
\ No newline at end of file +