/** * Calculate time when job would be completed, and expend production queues. * @global Product $ChronoBoost * @global Product $Nexus * @global Product $Warpgate * @param Job $job * @param float $time * @param bool $tentative If true, chronoboosts will not be logged. Use this * to perform dry runs of the queue use. * @return array(int,array) First element is time job would be completed, * second element is list of production queues used. */ public function queue($job, $time = null, $tentative = false) { global $ChronoBoost, $Nexus, $Warpgate; if ($this->debug) { tracemsg("Timeline::queue(" . $job . ", " . simple_time($time) . ", " . ($tentative ? "true" : "false") . ")"); } if ($time === null) { $time = $job->timeStarted; } if ($this->debug) { tracemsg("Timeline::queue(), job starts at " . simple_time($time)); } // choose queues list($queueTypesExpended, $expendAll) = $job->queueTypesExpended(); if ($queueTypesExpended !== null) { $queues = $this->queues->choose($time, $queueTypesExpended, $expendAll, $job->tagsRequired); } // build time $buildTime = $job->duration(); if (isset($queues) && count($queues) == 1 && $queues[0]->structure == $Warpgate) { $buildTime -= WARPGATE_QUEUE_REDUCTION; } // previous chrono boost overlaps this job if (isset($queues) && count($queues) == 1 && $queues[0]->chronoboosted + $ChronoBoost->timeCost > $time) { $boostTime = $queues[0]->chronoboosted; // calculate overlap with job $overlapStart = max($boostTime, $time); $overlapEnd = min($boostTime + $ChronoBoost->timeCost * CHRONO_BOOST_RATE, $time + $buildTime); $overlap = max(0, $overlapEnd - $overlapStart); // reduce build time $buildTime -= $overlap - $overlap / CHRONO_BOOST_RATE; } // chrono boosts if (isset($queues) && count($queues) == 1) { // process chronoboosts in an alternate reality $spellcasters = clone $this->spellcasters; for ($i = 0; $i < $job->chronoboost; $i++) { // start time of chrono boost $boostTime = max($queues[0]->chronoboosted + $ChronoBoost->timeCost, $spellcasters->when($Nexus, $ChronoBoost->energyCost)); if ($boostTime < $time + $buildTime) { $boostTime = max($boostTime, $time + CHRONO_BOOST_HUMAN_DELAY); // calculate overlap with job $overlapStart = max($boostTime, $time); $overlapEnd = min($boostTime + $ChronoBoost->timeCost * CHRONO_BOOST_RATE, $time + $buildTime); $overlap = max(0, $overlapEnd - $overlapStart); // reduce build time $buildTime -= $overlap - $overlap / CHRONO_BOOST_RATE; // expend spellcasters $spellcasters->update($boostTime); $spellcasters->expend($Nexus, $ChronoBoost->energyCost, $boostTime); // log chronoboost & reserve energy if (!$tentative) { $this->addCheckpoint(new Checkpoint("<em>CB: " . $job->description() . "</em>", $boostTime, $boostTime + $ChronoBoost->timeCost)); $spellcaster = $this->spellcasters->reserve($Nexus, $ChronoBoost->energyCost, $boostTime); } // queue is now chrono boosted $queues[0]->chronoboosted = $boostTime; } } } // build complete $completed = $time + $buildTime; // queue is now unavailable if (isset($queues)) { foreach ($queues as $queue) { $queue->busy($time, $completed, $job->busiesQueues()); } return array($completed, $queues); } else { return array($completed, null); } }