/** * Process a single job, update the timeline accordingly, and handle all * job-specific tasks. * @global Product $SpawnLarvae * @global Product $Warpgate * @global Product $ScoutingWorker * @param Job $job * @param bool $intheFuture */ public function process($job, $intheFuture = false) { global $SpawnLarvae, $Warpgate, $ScoutingWorker; Logger::enter("Timeline::process"); if ($this->debug || Hatcheries::$debug) { tracemsg("Timeline::process(" . $job . ", " . ($intheFuture ? "true" : "false") . ")"); } // reset time completed $job->timeCompleted = INF; // handle mutations up to job start foreach ($job->mutations() as $mutation) { if ($mutation->time < $job->timeStarted) { $this->income->splice($mutation); } } // handle checkpoints up to job start if (!$intheFuture) { $this->processCheckpoints($job->timeStarted); } // update all if (!$intheFuture) { $this->update($job->timeStarted); } // expend resources $this->income->expend($job->mineralCost(), $job->gasCost()); // when is job completed $job->timeCompleted = $job->timeStarted + $job->duration(); // refund resources $this->income->expend(-$job->gasRefund(), 0); $this->income->expend(-$job->mineralRefund(), 0); // use production queues list($queueTypesExpended, $expendAll) = $job->queueTypesExpended(); if ($queueTypesExpended !== null) { list($job->timeCompleted, $queues) = $this->queue($job); } // use energy if ($job->energyCost() > 0) { $this->spellcasters->expend($job->spellcasterTypeExpended(), $job->energyCost(), $job->timeStarted, $job->tagsRequired); } // special case: build is complete in 5 seconds when using a warpgate if (isset($queues) && count($queues) == 1) { if ($queues[0]->structure == $Warpgate) { $job->timeCompleted = $job->timeStarted + 5; } } // use larva if ($job->larvaCost() > 0) { $this->hatcheries->expend($job->timeStarted, $job->larvaCost(), $job->tagsRequired); } // new products if ($job->productsCreated() !== null) { foreach ($job->productsCreated() as $product) { if ($product !== null) { // spawn larvae if ($product->uid == $SpawnLarvae->uid) { $this->hatcheries->vomit($job->timeStarted); } // new hatchery if ($product->type & Base && $product->type & Zerg) { $this->hatcheries->add(new Hatchery($job->timeCompleted, 1, $job->tag)); } // new spellcaster if ($product->type & Spellcaster) { $this->spellcasters->add(new Spellcaster($product, $job->timeCompleted, $job->tag)); } // new farm if ($product->supplyCapacity > 0) { //tracemsg("Adding farm ". $product ." at ". simple_time($job->timeCompleted)); $this->farms->add(new Farm($job->timeCompleted, $product->supplyCapacity)); } } } } // destroy products if ($job->productsDestroyed() !== null) { foreach ($job->productsDestroyed() as $product) { // destroy spellcaster if ($product->type & Spellcaster) { $this->spellcasters->remove($product, $job->timeCompleted); } // destroy farm if ($product->supplyCapacity > 0) { $this->farms->remove($product->supplyCapacity, $job->timeCompleted); } } } // process mutations foreach ($job->mutations() as $mutation) { if ($mutation->time >= $job->timeStarted) { $this->income->splice($mutation); } } // add or morph production queues $queueTypesCreated = $job->queueTypesCreated(); if ($queueTypesCreated !== null) { if (isset($queues) && $job->morph()) { $this->queues->morph($queues, $job->timeStarted, $queueTypesCreated, $job->timeCompleted); } else { foreach ($queueTypesCreated as $queueType) { $this->queues->add(new ProductionQueue($queueType, $job->timeCompleted, $job->tag)); } } } // create event if ($intheFuture) { $this->addCheckpoint(new Checkpoint($job->description(), $job->timeStarted, $job->timeCompleted)); } else { $this->log($job->description(), $job->timeStarted, $job->timeCompleted); } // update supply count if ($this->debug) { tracemsg("Timeline::process(), supply count = " . $this->supplyCount . " + " . $job->supplyCost(false) . "."); } $this->supplyCount += $job->supplyCost(false); Logger::leave("Timeline::process"); }