public function index() { $request = RequestWrapper::$request; $target = $request->get('player'); $target_id = $request->get('player_id'); if ($target_id) { $target_player_obj = Player::find($target_id); } else { $target_player_obj = Player::findByName($target); } if ($target_player_obj === null) { $template = 'no-player.tpl'; $viewed_name_for_title = null; $parts = array(); } else { $attack_error = 'You must become a ninja first.'; $clan = Clan::findByMember($target_player_obj); $combat_skills = null; $display_clan_options = false; $items = null; $same_clan = false; $self = false; $targeted_skills = null; $template = 'player.tpl'; $viewed_name_for_title = $target_player_obj->name(); $viewing_player_obj = Player::find(SessionFactory::getSession()->get('player_id')); $kills_today = query_item('SELECT sum(killpoints) FROM levelling_log WHERE _player_id = :player_id AND killsdate = CURRENT_DATE AND killpoints > 0', [':player_id' => $target_player_obj->id()]); $rank_spot = query_item('SELECT rank_id FROM rankings WHERE player_id = :player_id limit 1', [':player_id' => $target_player_obj->id()]); if ($viewing_player_obj !== null) { $viewers_clan = Clan::findByMember($viewing_player_obj); $self = $viewing_player_obj->id() === $target_player_obj->id(); $params = ['required_turns' => 0, 'ignores_stealth' => true]; $AttackLegal = new AttackLegal($viewing_player_obj, $target_player_obj, $params); $AttackLegal->check(false); $attack_error = $AttackLegal->getError(); if (!$attack_error && !$self) { // They're not dead or otherwise unattackable. // Pull the items and some necessary data about them. $inventory = new Inventory($viewing_player_obj); $items = $inventory->counts(); $skillDAO = new SkillDAO(); if (!$viewing_player_obj->isAdmin()) { $combat_skills = $skillDAO->getSkillsByTypeAndClass($viewing_player_obj->_class_id, 'combat', $viewing_player_obj->level); $targeted_skills = $skillDAO->getSkillsByTypeAndClass($viewing_player_obj->_class_id, 'targeted', $viewing_player_obj->level); } else { $combat_skills = $skillDAO->all('combat'); $targeted_skills = $skillDAO->all('targeted'); } } if ($clan && $viewers_clan) { $same_clan = $clan->id == $viewers_clan->id; $display_clan_options = !$self && $same_clan && $viewing_player_obj->isClanLeader(); } } $parts = ['viewing_player_obj' => $viewing_player_obj, 'target_player_obj' => $target_player_obj, 'combat_skills' => $combat_skills, 'targeted_skills' => $targeted_skills, 'self' => $self, 'rank_spot' => $rank_spot, 'kills_today' => $kills_today, 'status_list' => Player::getStatusList($target_player_obj->id()), 'clan' => $clan, 'items' => $items, 'account' => Account::findByChar($target_player_obj), 'same_clan' => $same_clan, 'display_clan_options' => $display_clan_options, 'attack_error' => $attack_error]; } $parts['authenticated'] = SessionFactory::getSession()->get('authenticated', false); $title = 'Ninja' . ($viewed_name_for_title ? ": {$viewed_name_for_title}" : ' Profile'); return new StreamedViewResponse($title, $template, $parts, ['quickstat' => 'player']); }
/** * @return Response */ public function index(Container $p_dependencies) { $request = RequestWrapper::$request; $session = SessionFactory::getSession(); $options = ['blaze' => (bool) $request->get('blaze'), 'deflect' => (bool) $request->get('deflect'), 'duel' => (bool) $request->get('duel'), 'evade' => (bool) $request->get('evasion'), 'attack' => !(bool) $request->get('duel')]; $target = Player::find($request->get('target')); $attacker = Player::find($session->get('player_id')); $skillListObj = new Skill(); $ignores_stealth = false; $required_turns = 0; foreach (array_filter($options) as $type => $value) { $ignores_stealth = $ignores_stealth || $skillListObj->getIgnoreStealth($type); $required_turns += $skillListObj->getTurnCost($type); } $params = ['required_turns' => $required_turns, 'ignores_stealth' => $ignores_stealth]; try { $rules = new AttackLegal($attacker, $target, $params); $attack_is_legal = $rules->check(); $error = $rules->getError(); } catch (\InvalidArgumentException $e) { $attack_is_legal = false; $error = 'Could not determine valid target'; } if (!$attack_is_legal) { // Take away at least one turn even on attacks that fail. $attacker->turns = $attacker->turns - 1; $attacker->save(); $parts = ['target' => $target, 'attacker' => $attacker, 'error' => $error]; return new StreamedViewResponse('Battle Status', 'attack_mod.tpl', $parts, ['quickstat' => 'player']); } else { return $this->combat($attacker, $target, $required_turns, $options); } }
/** * Test that you can't attack if an excessive amount of turns is required */ public function testCantAttackIfExcessiveAmountOfTurnsIsRequired() { $confirm = true; $char_id = TestAccountCreateAndDestroy::create_testing_account($confirm); $this->oldify_character_last_attack($char_id); $char_2_id = TestAccountCreateAndDestroy::create_alternate_testing_account($confirm); $this->oldify_character_last_attack($char_2_id); $char = new Player($char_2_id); $legal = new AttackLegal(new Player($char_id), $char, ['required_turns' => 4000000000, 'ignores_stealth' => true]); $this->assertFalse($legal->check(false)); }
public function index() { $target = $player = first_value(in('ninja'), in('player'), in('find'), in('target')); $target_id = first_value(in('target_id'), in('player_id'), get_char_id($target)); // Find target_id if possible. $target_player_obj = Player::find($target_id); $viewed_name_for_title = null; if ($target_player_obj !== null) { $viewed_name_for_title = $target_player_obj->name(); } if ($target_player_obj === null) { $template = 'no-player.tpl'; $parts = array(); } else { $player_info = $target_player_obj->as_array(); // Pull the info out of the object. if (!$player_info) { $template = 'no-player.tpl'; $parts = array(); } else { $viewing_player_obj = Player::find(self_char_id()); $self = self_char_id() && self_char_id() == $player_info['player_id']; // Record whether this is a self-viewing. if ($viewing_player_obj !== null) { $char_info = $viewing_player_obj->dataWithClan(); $char_id = $viewing_player_obj->id(); $username = $viewing_player_obj->name(); } else { $char_info = []; } $player = $target = $player_info['uname']; // reset the target and target_id vars. $target_id = $player_info['player_id']; // Get the player's kills for this date. $kills_today = query_item('select sum(killpoints) from levelling_log where _player_id = :player_id and killsdate = CURRENT_DATE and killpoints > 0', array(':player_id' => $target_id)); $viewers_clan = $viewing_player_obj !== null ? ClanFactory::clanOfMember($viewing_player_obj) : null; // Attack Legal section $params = array('required_turns' => 0, 'ignores_stealth' => true); // 0 for unstealth. $attack_error = 'You must become a ninja first.'; $attack_allowed = false; if (null !== $viewing_player_obj) { $AttackLegal = new AttackLegal($viewing_player_obj, $target_player_obj, $params); $attack_allowed = $AttackLegal->check(false); $attack_error = $AttackLegal->getError(); } $sel_rank_spot = "SELECT rank_id FROM rankings WHERE player_id = :char_id limit 1"; $rank_spot = query_item($sel_rank_spot, array(':char_id' => $player_info['player_id'])); // Display the player info. $status_list = get_status_list($player); $gurl = $gravatar_url = $target_player_obj->avatarUrl(); if ($viewing_player_obj !== null && !$attack_error && !$self) { // They're not dead or otherwise unattackable. // Attack or Duel $skillDAO = new SkillDAO(); $is_admin = false; if ($viewing_player_obj) { $is_admin = $viewing_player_obj->isAdmin(); } if (!$is_admin) { $combat_skills = $skillDAO->getSkillsByTypeAndClass($viewing_player_obj->_class_id, 'combat', $viewing_player_obj->level); $targeted_skills = $skillDAO->getSkillsByTypeAndClass($viewing_player_obj->_class_id, 'targeted', $viewing_player_obj->level); } else { $combat_skills = $skillDAO->all('combat'); $targeted_skills = $skillDAO->all('targeted'); } // Pull the items and some necessary data about them. $items = inventory_counts($char_id); $valid_items = rco($items); // row count } // End of the there-was-no-attack-error section $set_bounty_section = ''; $communication_section = ''; $player_clan_section = ''; $clan = ClanFactory::clanOfMember($player_info['player_id']); $same_clan = false; // Player clan and clan members if ($clan) { $viewer_clan = $viewing_player_obj ? ClanFactory::clanOfMember($viewing_player_obj) : null; $clan_id = $clan->getID(); $clan_name = $clan->getName(); if ($viewer_clan) { $same_clan = $clan->getID() == $viewer_clan->getID(); $display_clan_options = $viewing_player_obj && !$self && $same_clan && $viewing_player_obj->isClanLeader(); } else { $same_clan = $display_clan_options = false; } } // Send the info to the template. $template = 'player.tpl'; $parts = get_certain_vars(get_defined_vars(), array('char_info', 'viewing_player_obj', 'target_player_obj', 'combat_skills', 'targeted_skills', 'player_info', 'self', 'rank_spot', 'kills_today', 'gravatar_url', 'status_list', 'clan', 'items')); } } return ['template' => $template, 'title' => 'Ninja' . ($viewed_name_for_title ? ": {$viewed_name_for_title}" : ' Profile'), 'parts' => $parts, 'options' => ['quickstat' => 'player']]; }
$ending_turns = null; $level_check = $player->vo->level - $target->vo->level; if ($player->hasStatus(STEALTH)) { $attacker_id = 'A Stealthed Ninja'; } $use_attack_legal = true; if ($command == 'Clone Kill' || $command == 'Harmonize') { $has_skill = true; $use_attack_legal = false; $attack_allowed = true; $attack_error = null; $covert = true; } else { // *** Checks the skill use legality, as long as the target isn't self. $params = ['required_turns' => $turn_cost, 'ignores_stealth' => $ignores_stealth, 'self_use' => $self_use]; $AttackLegal = new AttackLegal($player, $target, $params); $attack_allowed = $AttackLegal->check(); $attack_error = $AttackLegal->getError(); } if (!$attack_error) { // Only bother to check for other errors if there aren't some already. if (!$has_skill || $command == '') { // Set the attack error to display that that skill wasn't available. $attack_error = 'You do not have the requested skill.'; } elseif ($starting_turns < $turn_cost) { $turn_cost = 0; $attack_error = "You do not have enough turns to use {$command}."; } } // Strip down the player info to get the sight data. function pull_sight_data($target)
/** * Use an item on a target * @note /use/ is aliased to useItem externally because use is a php reserved keyword */ public function useItem($give = false, $self_use = false) { // Formats are: // http://nw.local/item/self_use/amanita/ // http://nw.local/item/use/shuriken/10/ // http://nw.local/item/give/shuriken/10/ // http://nw.local/item/use/shuriken/156001/ $slugs = $this->parse_slugs($give, $self_use); // Pull the parsed slugs $link_back = $slugs['link_back']; $selfTarget = $slugs['selfTarget']; $item_in = $slugs['item_in']; // Item identifier, either it's id or internal name $in_target = $slugs['in_target']; $give = $slugs['give']; $target = $in_target; if (positive_int($in_target)) { $target_id = positive_int($target); } else { $target_id = get_char_id($target); } $give = in_array($give, array('on', 'Give')); $player = new Player(self_char_id()); $victim_alive = true; $using_item = true; $item_used = true; $stealthLost = false; $error = false; $suicide = false; $kill = false; $repeat = false; $ending_turns = null; $turns_change = null; $turns_to_take = null; $gold_mod = NULL; $result = NULL; $targetResult = NULL; // result message to send to target of item use $targetName = ''; $targetHealth = ''; $bountyMessage = ''; $resultMessage = ''; $alternateResultMessage = ''; if ($item_in == (int) $item_in && is_numeric($item_in)) { // Can be cast to an id. $item = $item_obj = getItemByID($item_in); } elseif (is_string($item_in)) { $item = $item_obj = $this->getItemByIdentity($item_in); } else { $item = null; } if (!is_object($item)) { return new RedirectResponse(WEB_ROOT . 'inventory?error=noitem'); } else { $item_count = $this->itemCount($player->id(), $item); // Check whether use on self is occurring. $self_use = $selfTarget || $target_id === $player->id(); if ($self_use) { $target = $player->name(); $targetObj = $player; } else { if ($target_id) { $targetObj = new Player($target_id); $target = $targetObj->name(); } } $starting_turns = $player->turns; $username_turns = $starting_turns; $username_level = $player->level; if ($targetObj instanceof Player && $targetObj->id()) { $targets_turns = $targetObj->turns; $targets_level = $targetObj->level; $target_hp = $targetObj->health; } else { $targets_turns = $targets_level = $target_hp = null; } $max_power_increase = 10; $level_difference = $targets_level - $username_level; $level_check = $username_level - $targets_level; $near_level_power_increase = $this->nearLevelPowerIncrease($level_difference, $max_power_increase); // Sets the page to link back to. if ($target_id && ($link_back == "" || $link_back == 'player') && $target_id != $player->id()) { $return_to = 'player'; } else { $return_to = 'inventory'; } // Exceptions to the rules, using effects. if ($item->hasEffect('wound')) { // Minor damage by default items. $item->setTargetDamage(rand(1, $item->getMaxDamage())); // DEFAULT, overwritable. // e.g. Shuriken slices, for some reason. if ($item->hasEffect('slice')) { // Minor slicing damage. $item->setTargetDamage(rand(1, max(9, $player->getStrength() - 4)) + $near_level_power_increase); } // Piercing weapon, and actually does any static damage. if ($item->hasEffect('pierce')) { // Minor static piercing damage, e.g. 1-50 plus the near level power increase. $item->setTargetDamage(rand(1, $item->getMaxDamage()) + $near_level_power_increase); } // Increased damage from damaging effects, minimum of 20. if ($item->hasEffect('fire')) { // Major fire damage $item->setTargetDamage(rand(20, $player->getStrength() + 20) + $near_level_power_increase); } } // end of wounds section. // Exclusive speed/slow turn changes. if ($item->hasEffect('slow')) { $item->setTurnChange(-1 * $this->caltropTurnLoss($targets_turns, $near_level_power_increase)); } else { if ($item->hasEffect('speed')) { $item->setTurnChange($item->getMaxTurnChange()); } } $turn_change = $item_obj->getTurnChange(); $itemName = $item->getName(); $itemType = $item->getType(); $article = self::getIndefiniteArticle($item_obj->getName()); if ($give) { $turn_cost = 1; $using_item = false; } else { $turn_cost = $item->getTurnCost(); } // Attack Legal section $attacker = $player->name(); $params = ['required_turns' => $turn_cost, 'ignores_stealth' => $item_obj->ignoresStealth(), 'self_use' => $item->isSelfUsable()]; assert(!!$selfTarget || $attacker != $target); $AttackLegal = new AttackLegal($player, $targetObj, $params); $attack_allowed = $AttackLegal->check(); $attack_error = $AttackLegal->getError(); // *** Any ERRORS prevent attacks happen here *** if (!$attack_allowed) { //Checks for error conditions before starting. $error = 1; } else { if (is_string($item) || $target == "") { $error = 2; } else { if ($item_count < 1) { $error = 3; } else { /**** MAIN SUCCESSFUL USE ****/ if ($give) { $this->giveItem($player->name(), $target, $item->getName()); $alternateResultMessage = "__TARGET__ will receive your {$item->getName()}."; } else { if (!$item->isOtherUsable()) { // If it doesn't do damage or have an effect, don't use up the item. $resultMessage = $result = 'This item is not usable on __TARGET__, so it remains unused.'; $item_used = false; $using_item = false; } else { if ($item->hasEffect('stealth')) { $targetObj->addStatus(STEALTH); $alternateResultMessage = "__TARGET__ is now stealthed."; $targetResult = ' be shrouded in smoke.'; } if ($item->hasEffect('vigor')) { if ($targetObj->hasStatus(STR_UP1)) { $result = "__TARGET__'s body cannot become more vigorous!"; $item_used = false; $using_item = false; } else { $targetObj->addStatus(STR_UP1); $result = "__TARGET__'s muscles experience a strange tingling."; } } if ($item->hasEffect('strength')) { if ($targetObj->hasStatus(STR_UP2)) { $result = "__TARGET__'s body cannot become any stronger!"; $item_used = false; $using_item = false; } else { $targetObj->addStatus(STR_UP2); $result = "__TARGET__ feels a surge of power!"; } } // Slow and speed effects are exclusive. if ($item->hasEffect('slow')) { $turns_change = $item->getTurnChange(); if ($targetObj->hasStatus(SLOW)) { // If the effect is already in play, it will have a decreased effect. $turns_change = ceil($turns_change * 0.3); $alternateResultMessage = "__TARGET__ is already moving slowly."; } else { if ($targetObj->hasStatus(FAST)) { $targetObj->subtractStatus(FAST); $alternateResultMessage = "__TARGET__ is no longer moving quickly."; } else { $targetObj->addStatus(SLOW); $alternateResultMessage = "__TARGET__ begins to move slowly..."; } } if ($turns_change == 0) { $alternateResultMessage .= " You fail to take any turns from __TARGET__."; } $targetResult = " lose " . abs($turns_change) . " turns."; $targetObj->subtractTurns($turns_change); } else { if ($item->hasEffect('speed')) { // Note that speed and slow effects are exclusive. $turns_change = $item->getTurnChange(); if ($targetObj->hasStatus(FAST)) { // If the effect is already in play, it will have a decreased effect. $turns_change = ceil($turns_change * 0.5); $alternateResultMessage = "__TARGET__ is already moving quickly."; } else { if ($targetObj->hasStatus(SLOW)) { $targetObj->subtractStatus(SLOW); $alternateResultMessage = "__TARGET__ is no longer moving slowly."; } else { $targetObj->addStatus(FAST); $alternateResultMessage = "__TARGET__ begins to move quickly!"; } } // Actual turn gain is 1 less because 1 is used each time you use an item. $targetResult = " gain {$turns_change} turns."; $targetObj->changeTurns($turns_change); // Still adding some turns. } } if ($item->getTargetDamage() > 0) { // *** HP Altering *** $alternateResultMessage .= " __TARGET__ takes " . $item->getTargetDamage() . " damage."; if ($self_use) { $result .= "You take " . $item->getTargetDamage() . " damage!"; } else { if (strlen($targetResult) > 0) { $targetResult .= " You also"; // Join multiple targetResult messages. } $targetResult .= " take " . $item->getTargetDamage() . " damage!"; } $victim_alive = $targetObj->subtractHealth($item->getTargetDamage()); // This is the other location that $victim_alive is set, to determine whether the death proceedings should occur. } if ($item->hasEffect('death')) { $targetObj->death(); $resultMessage = "The life force drains from __TARGET__ and they drop dead before your eyes!"; $victim_alive = false; $targetResult = " be drained of your life-force and die!"; $gold_mod = 0.25; //The Dim Mak takes away 25% of a targets' gold. } if ($turns_change !== null) { // Even if $turns_change is set to zero, let them know that. if ($turns_change > 0) { $resultMessage .= "__TARGET__ has gained back {$turns_change} turns!"; } else { if ($turns_change === 0) { $resultMessage .= "__TARGET__ did not lose any turns!"; } else { $resultMessage .= "__TARGET__ has lost " . abs($turns_change) . " turns!"; } if ($targetObj->turns <= 0) { // Message when a target has no more turns to remove. $resultMessage .= " __TARGET__ no longer has any turns."; } } } if (empty($resultMessage) && !empty($result)) { $resultMessage = $result; } if (!$victim_alive) { // Target was killed by the item. if (!$self_use) { // *** SUCCESSFUL KILL, not self-use of an item *** $attacker_id = $player->hasStatus(STEALTH) ? "A Stealthed Ninja" : $player->name(); if (!$gold_mod) { $gold_mod = 0.15; } $initial_gold = $targetObj->gold(); $loot = floor($gold_mod * $initial_gold); $targetObj->set_gold($initial_gold - $loot); $player->set_gold($player->gold() + $loot); $player->save(); $targetObj->save(); $player->addKills(1); $kill = true; $bountyMessage = Combat::runBountyExchange($player->name(), $target); //Rewards or increases bounty. } else { $loot = 0; $suicide = true; } // Send mails if the target was killed. $this->sendKillMails($player->name(), $target, $attacker_id, $article, $item->getName(), $loot); } else { // They weren't killed. $attacker_id = $player->name(); } if (!$self_use && $item_used) { if (!$targetResult) { error_log('Debug: Issue 226 - An attack was made using ' . $item->getName() . ', but no targetResult message was set.'); } // Notify targets when they get an item used on them. $message_to_target = "{$attacker_id} has used {$article} {$item->getName()} on you"; if ($targetResult) { $message_to_target .= " and caused you to {$targetResult}"; } else { $message_to_target .= '.'; } send_event($player->id(), $target_id, str_replace(' ', ' ', $message_to_target)); } // Unstealth if (!$item->isCovert() && !$item->hasEffect('stealth') && $player->hasStatus(STEALTH)) { //non-covert acts $player->subtractStatus(STEALTH); $stealthLost = true; } else { $stealthLost = false; } } } $targetName = $targetObj->uname; $targetHealth = $targetObj->health; $turns_to_take = 1; if ($item_used) { // *** remove Item *** removeItem($player->id(), $item->getName(), 1); // *** Decreases the item amount by 1. } if ($victim_alive && $using_item) { $repeat = true; } } } } // *** Take away at least one turn even on attacks that fail to prevent page reload spamming *** if ($turns_to_take < 1) { $turns_to_take = 1; } $ending_turns = $player->subtractTurns($turns_to_take); assert($item->hasEffect('speed') || $ending_turns < $starting_turns || $starting_turns == 0); return ['template' => 'inventory_mod.tpl', 'title' => 'Use Item', 'parts' => get_defined_vars(), 'options' => ['body_classes' => 'inventory-use', 'quickstat' => 'player']]; } // Item was not valid object }
$attack_type['duel'] = 'duel'; } else { $attack_type['attack'] = 'attack'; } $target_player = new Player($target); $attacking_player = new Player(self_char_id()); $attacker = $attacking_player->name(); $skillListObj = new Skill(); $ignores_stealth = false; foreach ($attack_type as $type) { $ignores_stealth = $ignores_stealth || $skillListObj->getIgnoreStealth($type); $required_turns += $skillListObj->getTurnCost($type); } // *** Attack Legal section *** $params = array('required_turns' => $required_turns, 'ignores_stealth' => $ignores_stealth); $attack_legal = new AttackLegal($attacking_player, $target_player, $params); $attack_is_legal = $attack_legal->check(); $attack_error = $attack_legal->getError(); // *** MAIN BATTLE ALGORITHM *** if ($attack_is_legal) { // *** Target's stats. *** $target_health = $target_player->health; $target_level = $target_player->level; $target_str = $target_player->getStrength(); // *** Attacker's stats. *** $attacker_health = $attacking_player->health; $attacker_level = $attacking_player->level; $attacker_turns = $attacking_player->turns; $attacker_str = $attacking_player->getStrength(); $starting_target_health = $target_health; $starting_turns = $attacker_turns;
/** * Use, the skills_mod equivalent * * @note Test with urls like: * http://nw.local/skill/use/Fire%20Bolt/10 * http://nw.local/skill/self_use/Unstealth/ * http://nw.local/skill/self_use/Heal/ */ public function useSkill($self_use = false) { // Template vars. $display_sight_table = $generic_skill_result_message = $generic_state_change = $killed_target = $loot = $added_bounty = $bounty = $suicided = $destealthed = null; $error = null; $char_id = SessionFactory::getSession()->get('player_id'); $player = Player::find($char_id); $path = RequestWrapper::getPathInfo(); $slugs = $this->parseSlugs($path); // (fullpath0) /skill1/use2/Fire%20Bolt3/tchalvak4/(beagle5/) $act = isset($slugs[3]) ? $slugs[3] : null; $target = isset($slugs[4]) ? $slugs[4] : null; $target2 = isset($slugs[5]) ? $slugs[5] : null; if (!Filter::toNonNegativeInt($target)) { if ($self_use) { $target = $char_id; } else { if ($target !== null) { $targetObj = Player::findByName($target); $target = $targetObj ? $targetObj->id() : null; } else { $target = null; } } } if ($target2 && !Filter::toNonNegativeInt($target2)) { $target2Obj = Player::findByName($target2); $target2 = $target2Obj ? $target2Obj->id() : null; } $skillListObj = new Skill(); // *** Before level-based addition. $turn_cost = $skillListObj->getTurnCost(strtolower($act)); $ignores_stealth = $skillListObj->getIgnoreStealth($act); $self_usable = $skillListObj->getSelfUse($act); $use_on_target = $skillListObj->getUsableOnTarget($act); $ki_cost = 0; // Ki taken during use. $reuse = true; // Able to reuse the skill. $today = date("F j, Y, g:i a"); // Check whether the user actually has the needed skill. $has_skill = $skillListObj->hasSkill($act, $player); assert($turn_cost >= 0); if ($self_use) { // Use the skill on himself. $return_to_target = false; $target = $player; $target_id = null; } else { if ($target != '' && $target != $player->player_id) { $target = Player::find($target); $target_id = $target->id(); $return_to_target = true; } else { // For target that doesn't exist, e.g. http://nw.local/skill/use/Sight/zigzlklkj error_log('Info: Attempt to use a skill on a target that did not exist.'); return new RedirectResponse(WEB_ROOT . 'skill/?error=' . rawurlencode('Invalid target for skill [' . rawurlencode($act) . '].')); } } $covert = false; $victim_alive = true; $attacker_id = $player->name(); $attacker_char_id = $player->id(); $starting_turns = $player->turns; $level_check = $player->level - $target->level; if ($player->hasStatus(STEALTH)) { $attacker_id = 'A Stealthed Ninja'; } $use_attack_legal = true; if ($act == 'Clone Kill' || $act == 'Harmonize') { $has_skill = true; $use_attack_legal = false; $attack_allowed = true; $attack_error = null; $covert = true; } else { // *** Checks the skill use legality, as long as the target isn't self. $params = ['required_turns' => $turn_cost, 'ignores_stealth' => $ignores_stealth, 'self_use' => $self_use]; $AttackLegal = new AttackLegal($player, $target, $params); $update_timer = isset($this->update_timer) ? $this->update_timer : true; $attack_allowed = $AttackLegal->check($update_timer); $attack_error = $AttackLegal->getError(); } if (!$attack_error) { // Only bother to check for other errors if there aren't some already. if (!$has_skill || $act == '') { // Set the attack error to display that that skill wasn't available. $attack_error = 'You do not have the requested skill.'; } elseif ($starting_turns < $turn_cost) { $turn_cost = 0; $attack_error = "You do not have enough turns to use {$act}."; } } if (!$attack_error) { // Nothing to prevent the attack from happening. // Initial attack conditions are alright. $result = ''; if ($act == 'Sight') { $covert = true; $sight_data = $this->pullSightData($target); $display_sight_table = true; } elseif ($act == 'Steal') { $covert = true; $gold_decrease = min($target->gold, rand(5, 50)); $player->setGold($player->gold + $gold_decrease); $player->save(); $target->setGold($target->gold - $gold_decrease); $target->save(); $msg = "{$attacker_id} stole {$gold_decrease} gold from you."; Event::create($attacker_char_id, $target->id(), $msg); $generic_skill_result_message = "You have stolen {$gold_decrease} gold from __TARGET__!"; } else { if ($act == 'Unstealth') { $state = 'unstealthed'; if ($target->hasStatus(STEALTH)) { $target->subtractStatus(STEALTH); $generic_state_change = "You are now {$state}."; } else { $turn_cost = 0; $generic_state_change = "__TARGET__ is already {$state}."; } } else { if ($act == 'Stealth') { $covert = true; $state = 'stealthed'; if (!$target->hasStatus(STEALTH)) { $target->addStatus(STEALTH); $target->subtractStatus(STALKING); $generic_state_change = "__TARGET__ is now {$state}."; } else { $turn_cost = 0; $generic_state_change = "__TARGET__ is already {$state}."; } } else { if ($act == 'Stalk') { $state = 'stalking'; if (!$target->hasStatus(STALKING)) { $target->addStatus(STALKING); $target->subtractStatus(STEALTH); $generic_state_change = "__TARGET__ is now {$state}."; } else { $turn_cost = 0; $generic_state_change = "__TARGET__ is already {$state}."; } } else { if ($act == 'Kampo') { $covert = true; // *** Get Special Items From Inventory *** $user_id = $player->id(); $root_item_type = 7; $itemCount = query_item('SELECT sum(amount) AS c FROM inventory WHERE owner = :owner AND item_type = :type GROUP BY item_type', [':owner' => $user_id, ':type' => $root_item_type]); $turn_cost = min($itemCount, $starting_turns - 1, 2); // Costs 1 or two depending on the number of items. if ($turn_cost && $itemCount > 0) { // *** If special item count > 0 *** $inventory = new Inventory($player); $inventory->remove('ginsengroot', $itemCount); $inventory->add('tigersalve', $itemCount); $generic_skill_result_message = 'With intense focus you grind the ' . $itemCount . ' roots into potent formulas.'; } else { // *** no special items, give error message *** $turn_cost = 0; $generic_skill_result_message = 'You do not have the necessary ginsengroots or energy to create any Kampo formulas.'; } } else { if ($act == 'Poison Touch') { $covert = true; $target->addStatus(POISON); $target->addStatus(WEAKENED); // Weakness kills strength. $target_damage = rand(self::MIN_POISON_TOUCH, $this->maxPoisonTouch()); $victim_alive = $target->harm($target_damage); $generic_state_change = "__TARGET__ has been poisoned!"; $generic_skill_result_message = "__TARGET__ has taken {$target_damage} damage!"; $msg = "You have been poisoned by {$attacker_id}"; Event::create($attacker_char_id, $target->id(), $msg); } elseif ($act == 'Fire Bolt') { $target_damage = $this->fireBoltBaseDamage($player) + rand(1, $this->fireBoltMaxDamage($player)); $generic_skill_result_message = "__TARGET__ has taken {$target_damage} damage!"; $victim_alive = $target->harm($target_damage); $msg = "You have had fire bolt cast on you by " . $player->name(); Event::create($player->id(), $target->id(), $msg); } else { if ($act == 'Heal' || $act == 'Harmonize') { // This is the starting template for self-use commands, eventually it'll be all refactored. $harmonize = false; if ($act == 'Harmonize') { $harmonize = true; } $hurt = $target->is_hurt_by(); // Check how much the TARGET is hurt (not the originator, necessarily). // Check that the target is not already status healing. if ($target->hasStatus(HEALING) && !$player->isAdmin()) { $turn_cost = 0; $generic_state_change = '__TARGET__ is already under a healing aura.'; } elseif ($hurt < 1) { $turn_cost = 0; $generic_skill_result_message = '__TARGET__ is already fully healed.'; } else { if (!$harmonize) { $original_health = $target->health; $heal_points = $player->getStamina() + 1; $new_health = $target->heal($heal_points); // Won't heal more than possible $healed_by = $new_health - $original_health; } else { $start_health = $player->health; // Harmonize those chakra! $player = $this->harmonizeChakra($player); $healed_by = $player->health - $start_health; $ki_cost = $healed_by; } $target->addStatus(HEALING); $generic_skill_result_message = "__TARGET__ healed by {$healed_by} to " . $target->health . "."; if ($target->id() != $player->id()) { Event::create($attacker_char_id, $target->id(), "You have been healed by {$attacker_id} for {$healed_by}."); } } } else { if ($act == 'Ice Bolt') { if ($target->hasStatus(SLOW)) { $turn_cost = 0; $generic_skill_result_message = '__TARGET__ is already iced.'; } else { if ($target->turns >= 10) { $turns_decrease = rand(1, 5); $target->turns = $target->turns - $turns_decrease; // Changed ice bolt to kill stealth. $target->subtractStatus(STEALTH); $target->subtractStatus(STALKING); $target->addStatus(SLOW); $msg = "Ice bolt cast on you by {$attacker_id}, your turns have been reduced by {$turns_decrease}."; Event::create($attacker_char_id, $target->id(), $msg); $generic_skill_result_message = "__TARGET__'s turns reduced by {$turns_decrease}!"; } else { $turn_cost = 0; $generic_skill_result_message = "__TARGET__ does not have enough turns for you to take."; } } } else { if ($act == 'Cold Steal') { if ($target->hasStatus(SLOW)) { $turn_cost = 0; $generic_skill_result_message = '__TARGET__ is already iced.'; } else { $critical_failure = rand(1, 100); if ($critical_failure > 7) { // *** If the critical failure rate wasn't hit. if ($target->turns >= 10) { $turns_diff = rand(2, 7); $target->turns = $target->turns - $turns_diff; $player->turns = $player->turns + $turns_diff; // Stolen $target->addStatus(SLOW); $msg = "You have had Cold Steal cast on you for {$turns_diff} by {$attacker_id}"; Event::create($attacker_char_id, $target->id(), $msg); $generic_skill_result_message = "You cast Cold Steal on __TARGET__ and take {$turns_diff} turns."; } else { $turn_cost = 0; $generic_skill_result_message = '__TARGET__ did not have enough turns to give you.'; } } else { // *** CRITICAL FAILURE !! $player->addStatus(FROZEN); $unfreeze_time = date('F j, Y, g:i a', mktime(date('G') + 1, 0, 0, date('m'), date('d'), date('Y'))); $failure_msg = "You have experienced a critical failure while using Cold Steal. You will be unfrozen on {$unfreeze_time}"; Event::create((int) 0, $player->id(), $failure_msg); $generic_skill_result_message = "Cold Steal has backfired! You are frozen until {$unfreeze_time}!"; } } } else { if ($act == 'Clone Kill') { // Obliterates the turns and the health of similar accounts that get clone killed. $reuse = false; // Don't give a reuse link. $clone1 = Player::findByName($target); $clone2 = Player::findByName($target2); if (!$clone1 || !$clone2) { $not_a_ninja = $target; if (!$clone2) { $not_a_ninja = $target2; } $generic_skill_result_message = "There is no such ninja as {$not_a_ninja}."; } elseif ($clone1->id() == $clone2->id()) { $generic_skill_result_message = '__TARGET__ is just the same ninja, so not the same thing as a clone at all.'; } elseif ($clone1->id() == $char_id || $clone2->id() == $char_id) { $generic_skill_result_message = 'You cannot clone kill yourself.'; } else { // The two potential clones will be obliterated immediately if the criteria are met in CloneKill. $kill_or_fail = CloneKill::kill($player, $clone1, $clone2); if ($kill_or_fail !== false) { $generic_skill_result_message = $kill_or_fail; } else { $generic_skill_result_message = "Those two ninja don't seem to be clones."; } } } } } } } } } } } } // ************************** Section applies to all skills ****************************** if (!$victim_alive) { // Someone died. if ($target->player_id == $player->player_id) { // Attacker killed themself. $loot = 0; $suicided = true; } else { // Attacker killed someone else. $killed_target = true; $gold_mod = 0.15; $loot = floor($gold_mod * $target->gold); $player->setGold($player->gold + $loot); $target->setGold($target->gold - $loot); $player->addKills(1); $added_bounty = floor($level_check / 5); if ($added_bounty > 0) { $player->setBounty($player->bounty + $added_bounty * 25); } else { if ($target->bounty > 0 && $target->id() !== $player->id()) { // No suicide bounty, No bounty when your bounty getting ++ed. $player->setGold($player->gold + $target->bounty); // Reward the bounty $target->setBounty(0); // Wipe the bounty } } $target_message = "{$attacker_id} has killed you with {$act} and taken {$loot} gold."; Event::create($attacker_char_id, $target->id(), $target_message); $attacker_message = "You have killed {$target} with {$act} and taken {$loot} gold."; Event::create($target->id(), $player->id(), $attacker_message); } } if (!$covert && $player->hasStatus(STEALTH)) { $player->subtractStatus(STEALTH); $destealthed = true; } $target->save(); } // End of the skill use SUCCESS block. $player->turns = $player->turns - max(0, $turn_cost); // Take the skill use cost. $player->save(); $ending_turns = $player->turns; $target_ending_health = $target->health; $target_name = $target->name(); $parts = get_defined_vars(); $options = ['quickstat' => 'player']; return new StreamedViewResponse('Skill Effect', 'skills_mod.tpl', $parts, $options); }
/** * Use an item on a target * * http://nw.local/item/use/shuriken/10/ * * @return Response * @note * /use/ is aliased to useItem externally because use is a php reserved keyword */ public function useItem(Container $p_dependencies) { $slugs = $this->parseSlugs(); $target = $this->findPlayer($slugs['in_target']); $player = Player::find(SessionFactory::getSession()->get('player_id')); $inventory = new Inventory($player); $had_stealth = $player->hasStatus(STEALTH); $error = false; $turns_to_take = 1; // Take away one turn even on attacks that fail to prevent page reload spamming $bounty_message = ''; $display_message = ''; $extra_message = ''; $attacker_label = $player->name(); $loot = null; try { $item = $this->findItem($slugs['item_in']); $article = $item ? self::getIndefiniteArticle($item->getName()) : ''; } catch (\InvalidArgumentException $e) { return new RedirectResponse(WEB_ROOT . 'inventory?error=noitem'); } if (empty($target)) { $error = 2; } else { if ($this->itemCount($player, $item) < 1) { $error = 3; } else { if ($target->id() === $player->id()) { return $this->selfUse(); } else { $params = ['required_turns' => $item->getTurnCost(), 'ignores_stealth' => $item->ignoresStealth()]; $attack_legal = new AttackLegal($player, $target, $params); if (!$attack_legal->check()) { $error = 1; $display_message = $attack_legal->getError(); } else { if (!$item->isOtherUsable()) { $error = 1; $display_message = 'This item cannot be used on others!'; } else { $result = $this->applyItemEffects($player, $target, $item); if ($result['success']) { $message_to_target = "{$attacker_label} has used {$article} " . $item->getName() . " on you{$result['notice']}"; Event::create($player->id(), $target->id(), str_replace(' ', ' ', $message_to_target)); $inventory->remove($item->identity(), 1); if ($target->health <= 0) { // Target was killed by the item $attacker_label = $player->hasStatus(STEALTH) ? "A Stealthed Ninja" : $player->name(); $gold_mod = $item->hasEffect('death') ? 0.25 : 0.15; $loot = floor($gold_mod * $target->gold); $target->setGold($target->gold - $loot); $player->setGold($player->gold + $loot); $player->addKills(1); $bounty_message = Combat::runBountyExchange($player, $target); //Rewards or increases bounty. $this->sendKillMails($player, $target, $attacker_label, $article, $item->getName(), $loot); } } $display_message = $result['message']; $extra_message = $result['extra_message']; } } $player->changeTurns(-1 * $turns_to_take); $target->save(); $player->save(); } } } return $this->renderUse(['action' => 'use', 'return_to' => in_array(RequestWrapper::getPostOrGet('link_back'), ['', 'player']) ? 'player' : 'inventory', 'error' => $error, 'target' => $target, 'resultMessage' => $display_message, 'alternateResultMessage' => $extra_message, 'stealthLost' => $had_stealth && $player->hasStatus(STEALTH), 'repeat' => $target->health > 0 && empty($error), 'item' => $item, 'bountyMessage' => $bounty_message, 'article' => $article, 'loot' => $loot]); }