/** * Returns neighbor units in given range (radius). * For example, given a Unit X and 1 as range, will return unit * to the left of X AND to the right of X, if they exist (even if dead). * If you provide a side argument, only that side is returned. * So for Unit X, range 1, side left, only the ONE unit to the left of X is returned. * * @param Unit $oUnit * @param int $iRange * @param string $sSide * @return array */ public function getAdjacentUnits(Unit $oUnit, $iRange = 1, $sSide = 'both') { $aAdjacent = array(); while ($iRange > 0) { if ($sSide == 'both' || $sSide == 'left') { if (isset($this->aUnits[$oUnit->getIndex() - $iRange])) { $aAdjacent[] = $this->aUnits[$oUnit->getIndex() - $iRange]; } } if ($sSide == 'both' || $sSide == 'right') { if (isset($this->aUnits[$oUnit->getIndex() + $iRange])) { $aAdjacent[] = $this->aUnits[$oUnit->getIndex() + $iRange]; } } $iRange--; } return array_reverse($aAdjacent); }
/** * Shoots at a given unit. Hit or miss depends on accuracy and other * factors. Can shoot at self and commit suicide with a 100% success rate. * @param \autofight\Interfaces\Unit $oUnit * @return mixed */ public function shoot(iUnit $oUnit) { $aResults = array(); $oResult = new BattleResult(); $oResult->attacker = $this; $oResult->defender = $oUnit; // Calculate hit or miss. $iHitScore = rand(1, 100); $bHit = $iHitScore >= $this->iAccuracy; $oResult->type = $bHit ? BattleLogger::TYPE_HIT : BattleLogger::TYPE_MISS; $oResult->message = $this->determineMessage($iHitScore); $fPercentageOfAccuracy = $iHitScore / $this->iAccuracy * 100; if (!$bHit) { $iAmount = 0; // MISS if ($fPercentageOfAccuracy > 50 && $fPercentageOfAccuracy < 60) { /* If the hit score was between 50% and 60% of accuracy there's a chance the adjacent trooper was hit. */ $aAdjacent = $this->getArmy()->getAdjacentUnits($this, 1); if (!empty($aAdjacent)) { $oUnitToShootAt = $this->getRandomElement($aAdjacent); if ($oUnitToShootAt) { $aResults[] = $this . ' aims at ' . $oUnit . ' but bullet strays towards ' . $oUnitToShootAt . '!'; $aPostMerge = $this->shoot($oUnitToShootAt); } } } else { if ($iHitScore == 1) { // CRITICAL MISS switch (rand(0, 1)) { case 0: // Reduce accuracy by 10 $this->iAccuracy = $this->iAccuracy < 11 ? 1 : $this->iAccuracy - 10; $sAddedMessage = $this . ' has suffered a permanent reduction of accuracy!'; break; case 1: // Reduce health by 10 $this->iHealth = $this->iHealth < 11 ? 1 : $this->iHealth - 10; $sAddedMessage = $this . ' has suffered a permanent reduction of health!'; break; default: break; } } } } else { // HIT if ($iHitScore == 100) { // CRITICAL HIT $iAmount = $this->iDamage * 5; $aResults[] = $this . ' scored a critical hit!!'; } else { $iAmount = $this->iDamage * $iHitScore / 100; } } $oResult->amount = $iAmount; $oUnit->decreaseHealth($iAmount); if (!$oUnit->isAlive()) { $oResult->message = 'kills'; $oResult->type = BattleLogger::TYPE_DEATH; } $aResults[] = $oResult; if (isset($sAddedMessage)) { $aResults[] = $sAddedMessage; } $aPostMerge = isset($aPostMerge) ? $aPostMerge : array(); $aResults = array_merge($aResults, $aPostMerge); return $aResults; }