Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- class Battle {
- private $attacker;
- private $defender;
- private $type;
- private $log;
- private $attackerStartLevel;
- private $defenderStartLevel;
- private $attackerExp;
- private $defenderExp;
- private $kudosChange;
- private $buffBattleSpeed;
- private $buffExperience;
- private $buffKudos;
- /**
- * @param Bot $attacker
- * @param Bot $defender
- */
- public function __construct($attacker, $defender, $type, $limits = null) {
- $this->attacker = $attacker;
- $this->defender = $defender;
- $this->type = $type;
- $this->log = new BattleLog($type, $defender->getId());
- $this->attackerStartLevel = $attacker->getLevel();
- $this->defenderStartLevel = $defender->getLevel();
- global $db, $player;
- $db->query('
- SELECT SUM(unseen) AS unseen
- FROM attacks
- WHERE defender = ?;
- ', 'i', $player->getId());
- $row = $db->fetchRow();
- $this->log->setAttackCount((int) $row['unseen']);
- if ($type === 'fight') {
- $this->log->setAttacksLeft($limits->getAttacksLeft($defender));
- $this->log->setIsOnline($defender->isOnline());
- // Dickhead trophy
- if ($defender->isOnline()) {
- $attacker->getTrophies()->give(208);
- }
- }
- }
- public function getAttackerStartLevel() {
- return $this->attackerStartLevel;
- }
- public function getDefenderStartLevel() {
- return $this->defenderStartLevel;
- }
- public function doBattle() {
- $attackerHP = $this->attacker->getMaxHP();
- $defenderHP = $this->defender->getMaxHP();
- $attempts = 0;
- $blocks = 0;
- $hitsInARow = 0;
- // see who hits first
- $attackerIntRoll = mt_rand(0, $this->attacker->getIntel());
- $defenderIntRoll = mt_rand(0, $this->defender->getIntel());
- $attackerTurn = $attackerIntRoll >= $defenderIntRoll;
- $shieldPresent = $this->attacker->hasShield() || $this->defender->hasShield();
- // statistics
- $attackerStats = array();
- $attackerStats['attempts'] = 0;
- $attackerStats['maxHit'] = 0;
- $attackerStats['blocks'] = 0;
- $attackerStats['misses'] = 0;
- $attackerStats['inflicted'] = 0;
- $defenderStats = array();
- $defenderStats['attempts'] = 0;
- $defenderStats['maxHit'] = 0;
- $defenderStats['blocks'] = 0;
- $defenderStats['misses'] = 0;
- $defenderStats['inflicted'] = 0;
- // main battle loop
- while (true) {
- // bookkeeping
- $hitsInARow++;
- $isPrimary = $shieldPresent ? $hitsInARow === 1 : $attempts % 4 === 0 || $attempts % 4 === 1;
- $attempts++;
- // do the attempt
- if ($attackerTurn) {
- $attempt = $this->attempt($this->attacker, $this->defender, $isPrimary);
- $attempt['who'] = $this->attacker->getName();
- $attackerStats['attempts']++;
- switch ($attempt['type']) {
- case 'hit':
- $this->checkDamageTrophies($this->attacker, $attempt['damage']);
- $defenderHP -= $attempt['damage'];
- $attempt['stage'] = $this->getStage($defenderHP, $this->defender->getMaxHP());
- $attempt['isPrimary'] = $isPrimary;
- $attackerStats['maxHit'] = max($attackerStats['maxHit'], $attempt['damage']);
- $attackerStats['inflicted'] += $attempt['damage'];
- break;
- case 'block':
- $defenderStats['blocks']++;
- break;
- case 'miss':
- $attackerStats['misses']++;
- break;
- }
- $attempt['condition'] = $this->doConditionChecks($this->attacker, $this->defender, $attempt['type'], $isPrimary);
- } else {
- $attempt = $this->attempt($this->defender, $this->attacker, $isPrimary);
- $attempt['who'] = $this->defender->getName();
- $defenderStats['attempts']++;
- switch ($attempt['type']) {
- case 'hit':
- $this->checkDamageTrophies($this->defender, $attempt['damage']);
- $attackerHP -= $attempt['damage'];
- $attempt['stage'] = $this->getStage($attackerHP, $this->attacker->getMaxHP());
- $attempt['isPrimary'] = $isPrimary;
- $defenderStats['maxHit'] = max($defenderStats['maxHit'], $attempt['damage']);
- $defenderStats['inflicted'] += $attempt['damage'];
- break;
- case 'block':
- $attackerStats['blocks']++;
- break;
- case 'miss':
- $defenderStats['misses']++;
- break;
- }
- $attempt['condition'] = $this->doConditionChecks($this->defender, $this->attacker, $attempt['type'], $isPrimary);
- }
- $this->log->addAttempt($attempt);
- // check if battle is over
- if ($attackerHP <= 0 || $attempts >= 300) {
- // Skin Of Your Teeth trophy
- if ($defenderHP < 5 && $this->type === 'fight') {
- $this->defender->getTrophies()->give(125);
- }
- // Can't Touch This trophy
- if ($defenderHP === $this->defender->getMaxHP() && $this->type === 'fight') {
- $this->defender->getTrophies()->give(126);
- }
- $winner = $this->defender->getName();
- $isWin = false;
- break;
- } else if ($defenderHP <= 0) {
- // Skin Of Your Teeth trophy
- if ($attackerHP < 5 && $this->type === 'fight') {
- $this->attacker->getTrophies()->give(125);
- }
- // Can't Touch This trophy
- if ($attackerHP === $this->attacker->getMaxHP() && $this->type === 'fight') {
- $this->attacker->getTrophies()->give(126);
- }
- $winner = $this->attacker->getName();
- $isWin = true;
- break;
- }
- // switch turn if necessary
- if ($attackerTurn) {
- if ($hitsInARow === 2 || $this->attacker->hasShield() || !$shieldPresent) {
- $attackerTurn = false;
- $hitsInARow = 0;
- }
- } else {
- if ($hitsInARow === 2 || $this->defender->hasShield() || !$shieldPresent) {
- $attackerTurn = true;
- $hitsInARow = 0;
- }
- }
- }
- $this->log->setSummaryMeta($winner);
- $this->setMetaData();
- $this->setSummary($attackerStats, $defenderStats);
- if ($this->type === 'train') {
- // trainer trophies
- if ($isWin) {
- // to avoid writing these all out, use the fact that Infant is id = 1 and trophy = 127
- $this->attacker->getTrophies()->give($this->defender->getId() + 126);
- }
- $this->attackerExp = round(Formulas::getExperienceTrain(
- $isWin,
- $this->defender->getLevel(),
- $this->attacker->getLevel(),
- $attackerStats['inflicted'],
- $this->attacker->getIntel(),
- $attackerStats['blocks'] + $defenderStats['blocks'],
- $attackerStats['attempts'] + $defenderStats['attempts'])
- * ($this->getBuffExperience() / 100));
- $this->kudosChange = round(Formulas::getKudosGain(
- $this->defender->getLevel(),
- $this->attacker->getLevel(),
- $attackerStats['inflicted'],
- $this->attacker->getIntel())
- * ($this->getBuffKudos() / 100));
- } else {
- if ($this->attacker->hasClan() && $this->defender->hasClan()) {
- $energyExchange = new EnergyExchange($this->attacker, $this->defender, $isWin, $attackerStats['attempts'] + $defenderStats['attempts']);
- $energy = $energyExchange->exchange();
- $this->log->setEnergy($energy);
- }
- $this->attackerExp = round(Formulas::getExperienceFight(
- $isWin,
- $this->defender->getLevel(),
- $this->attacker->getLevel(),
- $attackerStats['inflicted'],
- $this->attacker->getIntel(),
- $this->defender->getRatio(true),
- $attackerStats['blocks'] + $defenderStats['blocks'],
- $attackerStats['attempts'] + $defenderStats['attempts'],
- 1) // TODO: change when clans are in
- * ($this->getBuffExperience() / 100));
- if ($isWin) {
- if ($this->defender->isOnline()) {
- $this->kudosChange = max(1, round($this->defender->getKudos() / 15 * ($this->getBuffKudos() / 100)));
- } else {
- $this->kudosChange = max(1, round($this->defender->getKudos() / 3 * ($this->getBuffKudos() / 100)));
- }
- } else {
- $this->kudosChange = -1 * max(1, round($this->attacker->getKudos() / 3));
- }
- // Thief trophy
- if ($this->kudosChange > 100000) {
- $this->attacker->getTrophies()->give(209);
- }
- // Master Thief trophy
- if ($this->kudosChange > 1000000) {
- $this->attacker->getTrophies()->give(210);
- }
- // award target
- $this->defenderExp = Formulas::getExperienceFight(
- !$isWin,
- $this->attacker->getLevel(),
- $this->defender->getLevel(),
- $defenderStats['inflicted'],
- $this->defender->getIntel(),
- $this->attacker->getRatio(true),
- $attackerStats['blocks'] + $defenderStats['blocks'],
- $attackerStats['attempts'] + $defenderStats['attempts'],
- 1); // TODO: change when clans are in
- global $meta;
- $this->defender->award(-1 * $this->kudosChange, $this->defenderExp, $meta->getTime() + floor($attempts * $this->getAttemptDelayMillis() / 1000), 'fight', !$isWin);
- }
- $repairs = $this->attacker->getRepairs();
- if ($repairs['cost'] <= $this->attacker->getKudos() + $this->kudosChange) {
- $enough = true;
- $this->attacker->repairAll($repairs['cost']);
- } else {
- $enough = false;
- }
- $this->attacker->commitEquipmentChanges();
- $this->log->setRepairs(array(
- 'enough' => $enough,
- 'cost' => $repairs['cost'],
- 'trashed' => $repairs['trashed']
- ));
- $this->setRewards($attempts, $isWin, $enough ? $repairs['cost'] : 0);
- $this->log->setDelay($this->getAttemptDelayMillis());
- global $db;
- $db->query('
- UPDATE buffs_bots
- SET duration = duration - 1
- WHERE bot_id = ? AND active = true;
- ', 'i', $this->attacker->getId());
- $db->query('
- DELETE
- FROM buffs_bots
- WHERE bot_id = ? AND duration = 0;
- ', 'i', $this->attacker->getId());
- // Trashed trophy
- $this->attacker->getEquipment()->trashedTrophy();
- }
- private function checkDamageTrophies($bot, $damage) {
- if ($damage >= 10) {
- $bot->getTrophies()->give(108);
- }
- if ($damage >= 100) {
- $bot->getTrophies()->give(109);
- }
- if ($damage >= 700) {
- $bot->getTrophies()->give(110);
- }
- if ($damage >= 2000) {
- $bot->getTrophies()->give(111);
- }
- }
- public function doConditionChecks($hitter, $hittee, $type, $isPrimary) {
- $damage = array();
- switch ($type) {
- case 'hit':
- // hitter's weapon
- $damage[] = $this->doConditionCheck($hitter, $isPrimary ? $hitter->getEquipment()->getPrimary() : $hitter->getEquipment()->getSecondary());
- // hittee's armor
- $damage[] = $this->doConditionCheck($hittee, $hittee->getEquipment()->getBody());
- $damage[] = $this->doConditionCheck($hittee, $hittee->getEquipment()->getHelmet());
- $damage[] = $this->doConditionCheck($hittee, $hittee->getEquipment()->getGloves());
- $damage[] = $this->doConditionCheck($hittee, $hittee->getEquipment()->getBoots());
- break;
- case 'block':
- // hitter's weapon
- $damage[] = $this->doConditionCheck($hitter, $isPrimary ? $hitter->getEquipment()->getPrimary() : $hitter->getEquipment()->getSecondary());
- // hittee's shield
- if ($hittee->hasShield()) {
- $damage[] = $this->doConditionCheck($hittee, $hittee->getEquipment()->getSecondary());
- }
- break;
- case 'miss':
- // nothing
- break;
- }
- // remove nulls from array
- return array_values(array_filter($damage, function ($val) { return isset($val); }));
- }
- public function doConditionCheck($bot, $item) {
- if (!isset($item) || $item->getName() === 'fist' || $item->getName() === 'none') {
- return null;
- } else {
- if (mt_rand2() < $item->getDamageProbability($bot->getStr(), $bot->getDex())) {
- $item->doDamage();
- return array(
- 'who' => $bot->getName(),
- 'item' => $item->getName()
- );
- } else {
- return null;
- }
- }
- }
- public function setRewards($attempts, $isWin, $repairCost) {
- global $meta;
- $this->levelBefore = $this->attacker->getLevel();
- $this->attacker->award($this->kudosChange - $repairCost, $this->attackerExp, $meta->getTime() + floor($attempts * $this->getAttemptDelayMillis() / 1000), $this->type, $isWin);
- $this->levelAfter = $this->attacker->getLevel();
- $this->log->setRewards(
- $this->kudosChange,
- $this->attacker->getKudos(),
- $this->attackerExp,
- $this->attacker->getXPTNL(),
- $this->levelAfter - $this->levelBefore);
- }
- /**
- * @param array $attackerStats
- * @param array $defenderStats
- */
- private function setSummary($attackerStats, $defenderStats) {
- if ($attackerStats['attempts'] !== 0) {
- $attackerStats['average'] = round($attackerStats['inflicted'] / $attackerStats['attempts'], 1);
- } else {
- $attackerStats['average'] = 0;
- }
- if ($defenderStats['attempts'] !== 0) {
- $defenderStats['average'] = round($defenderStats['inflicted'] / $defenderStats['attempts'], 1);
- } else {
- $defenderStats['average'] = 0;
- }
- $this->log->setSummary($attackerStats, $defenderStats);
- }
- /**
- * @param Bot $hitter
- * @param Bot $hittee
- * @param bool $isPrimary Whether or not this attempt is being made with the primary weapon.
- * @return array Returns an attempt array.
- */
- private function attempt($hitter, $hittee, $isPrimary) {
- // check for miss
- $hitChance = $hitter->getHitChance($hittee);
- if (mt_rand2() > $hitChance) {
- $attempt['type'] = 'miss';
- return $attempt;
- }
- // check for block
- $blockChance = $hittee->getBlock();
- if (mt_rand2() < $blockChance) {
- $attempt['type'] = 'block';
- return $attempt;
- }
- // calculate damage
- if ($isPrimary) {
- $minDamage = $hitter->getPrimaryMinDamage();
- $maxDamage = $hitter->getPrimaryMaxDamage();
- } else {
- $minDamage = $hitter->getSecondaryMinDamage();
- $maxDamage = $hitter->getSecondaryMaxDamage();
- }
- $attempt['type'] = 'hit';
- $attempt['damage'] = round(mt_rand($minDamage, $maxDamage) * (1 - $hittee->getAbsorb()));
- return $attempt;
- }
- private function setMetaData() {
- $this->log->setAttacker(
- $this->attacker->getName(),
- $this->attacker->getColor(),
- $this->attacker->getMaxHP(),
- $this->attacker->getPrimaryName(),
- $this->attacker->hasShield() ? null : $this->attacker->getSecondaryName());
- $this->log->setDefender(
- $this->defender->getName(),
- $this->defender->getColor(),
- $this->defender->getPrimaryName(),
- $this->defender->hasShield() ? null : $this->defender->getSecondaryName());
- }
- private function getStage($HP, $maxHP) {
- $percentage = $HP / $maxHP;
- switch (true) {
- case $percentage >= 1.0:
- return 0;
- case $percentage >= 0.8:
- return 1;
- case $percentage >= 0.6:
- return 2;
- case $percentage >= 0.4:
- return 3;
- case $percentage >= 0.2:
- return 4;
- case $percentage > 0.0:
- return 5;
- default:
- return 6;
- }
- }
- public function getLog($settings) {
- return $this->log->toJSON($settings);
- }
- public function getAttacker() {
- return $this->attacker;
- }
- public function getDefender() {
- return $this->defender;
- }
- public function getAttackerExp() {
- return $this->attackerExp;
- }
- public function getDefenderExp() {
- return $this->defenderExp;
- }
- // positive means attacker won, negative means defender won
- public function getKudosChange() {
- return $this->kudosChange;
- }
- public function attackerWon() {
- return $this->kudosChange > 0;
- }
- public function getBuffBattleSpeed() {
- if (!isset($this->buffBattleSpeed)) {
- $this->buffBattleSpeed = 100;
- foreach ($this->attacker->getBuffs() as $buff) {
- if (!$buff->isActive()) {
- continue;
- }
- foreach ($buff->getEffects() as $effect) {
- if ($effect->getName() === 'battle speed' && $effect->getValue() > $this->buffBattleSpeed) {
- $this->buffBattleSpeed = $effect->getValue();
- }
- }
- }
- }
- return $this->buffBattleSpeed;
- }
- // TODO: currently rounds to nearest 20 because battle code is rather fragile...should be able to remove this restriction eventually
- public function getAttemptDelayMillis() {
- $baseDelay = round(800 * 100 / $this->getBuffBattleSpeed());
- return floor(($baseDelay + 20 - 1) / 20) * 20;
- }
- public function getBuffExperience() {
- if (!isset($this->buffExperience)) {
- $this->buffExperience = 100;
- foreach ($this->attacker->getBuffs() as $buff) {
- if (!$buff->isActive()) {
- continue;
- }
- foreach ($buff->getEffects() as $effect) {
- if ($effect->getName() === 'experience' && $effect->getValue() > $this->buffExperience) {
- $this->buffExperience = $effect->getValue();
- }
- }
- }
- }
- return $this->buffExperience;
- }
- public function getBuffKudos() {
- if (!isset($this->buffKudos)) {
- $this->buffKudos = 100;
- foreach ($this->attacker->getBuffs() as $buff) {
- if (!$buff->isActive()) {
- continue;
- }
- foreach ($buff->getEffects() as $effect) {
- if ($effect->getName() === 'kudos' && $effect->getValue() > $this->buffKudos) {
- $this->buffKudos = $effect->getValue();
- }
- }
- }
- }
- return $this->buffKudos;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement