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']); }
/** * Display the combat/action events and mark them as read when displayed. * * @return Response */ public function index() { $char = Player::find(SessionFactory::getSession()->get('player_id')); $events = $this->getEvents($char->id(), 300); $this->readEvents($char->id()); // mark events as viewed. $parts = ['events' => $events, 'has_clan' => (bool) Clan::findByMember($char), 'char' => $char]; return new StreamedViewResponse('Events', 'events.tpl', $parts, ['quickstat' => 'player']); }
/** * The standard homepage * * @return Response */ private function game() { // Get the actual values of the vars. $ninja = Player::find(SessionFactory::getSession()->get('player_id')); $playerInfo = $ninja->data(); $clan = $ninja ? Clan::findByMember($ninja) : null; $unreadCount = Message::where(['send_to' => $ninja->id(), 'unread' => 1])->count(); // Assign these vars to the template. $parts = ['main_src' => '/intro', 'body_classes' => 'main-body', 'version' => 'NW Version 1.7.5 2010.12.05', 'ninja' => $ninja, 'player_info' => $playerInfo, 'clan' => $clan, 'unread_message_count' => $unreadCount]; return new StreamedViewResponse('Live by the Shuriken', 'index.tpl', $parts, ['is_index' => true]); }
/** * @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); } }
/** */ public function setUp() { $this->m_dependencies = new Container(); $this->m_dependencies['session'] = function ($c) { return SessionFactory::getSession(); }; $this->m_dependencies['current_player'] = $this->m_dependencies->factory(function ($c) { return Player::find(SessionFactory::getSession()->get('player_id')); }); }
public function setUp() { $this->char = Player::find(TestAccountCreateAndDestroy::char_id()); SessionFactory::init(new MockArraySessionStorage()); $session = SessionFactory::getSession(); $session->set('player_id', $this->char->id()); // Mock the login. $request = new Request([], []); RequestWrapper::inject($request); }
public static function canKill($clone1, $clone2) { // Input is transformed into if (!$clone1 instanceof Player) { if ($clone1 == Filter::toNonNegativeInt($clone1)) { $char1 = Player::find($clone1); } elseif (is_string($clone1)) { $char1 = Player::find($clone1); } } else { $char1 = $clone1; } if (!$clone2 instanceof Player) { if ($clone2 == Filter::toNonNegativeInt($clone2)) { $char2 = Player::find($clone2); } elseif (is_string($clone2)) { $char2 = Player::find($clone2); } } else { $char2 = $clone2; } // Reject invalid/nonexistent characters if ($char1 === null || $char2 === null) { return false; } // Reject same character if ($char1->id() == $char2->id()) { return false; } // Don't clone kill admins. if ($char1->isAdmin() || $char2->isAdmin()) { return false; } // Reject inactive characters if (!$char1->isActive() || !$char2->isActive()) { return false; } // TODO: Reject inoperative characters // TODO: You can't clone kill yourself.. $host = gethostname(); $server_ip = gethostbyname($host); $untouchable_ips = ['127.0.0.1', '173.203.99.229', $server_ip, '', null]; $account1 = Account::findByChar($char1); $account2 = Account::findByChar($char2); // Reject invalid custom ips if (in_array($account1->getLastIp(), $untouchable_ips) || in_array($account2->getLastIp(), $untouchable_ips)) { return false; } // If characters have the same joint account, and have been logged in recently... if ($account1->getLastIp() === $account2->getLastIp()) { // Activity was already tested above. return true; } return false; }
public function setUp() { SessionFactory::init(new MockArraySessionStorage()); $char_id = TestAccountCreateAndDestroy::char_id(); $char = Player::find($char_id); $account = Account::findByChar($char); $account_id = $account->id(); SessionFactory::getSession()->set('authenticated', true); SessionFactory::getSession()->set('player_id', $char_id); SessionFactory::getSession()->set('account_id', $account_id); }
/** * 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 = Player::find($char_2_id); $legal = new AttackLegal(Player::find($char_id), $char, ['required_turns' => 4000000000, 'ignores_stealth' => true]); $this->assertFalse($legal->check(false)); }
/** * @TODO Document me! */ private function configure() { $char = Player::find(SessionFactory::getSession()->get('player_id')); $peers = $char ? $this->getNearbyPeers($char->id()) : []; $active_ninjas = Player::findActive(5, true); $char_info = $char ? $char->data() : []; $other_npcs = NpcFactory::npcsData(); $npcs = NpcFactory::customNpcs(); $enemy_list = $char ? $this->getCurrentEnemies($char->id()) : []; $recent_attackers = $char ? $this->getRecentAttackers($char) : []; return ['logged_in' => (bool) $char, 'enemy_list' => $enemy_list, 'char_name' => $char ? $char->name() : '', 'npcs' => $npcs, 'other_npcs' => $other_npcs, 'char_info' => $char_info, 'active_ninjas' => $active_ninjas, 'recent_attackers' => $recent_attackers, 'enemy_list' => $enemy_list, 'peers' => $peers]; }
public function testAttackWhenDead() { $attacker = Player::find(SessionFactory::getSession()->get('player_id')); $attacker->death(); $attacker->save(); $char_id_2 = TestAccountCreateAndDestroy::char_id_2(); $params = ['target' => $char_id_2]; $request = Request::create('/attack', 'GET', $params); RequestWrapper::inject($request); $response = $this->controller->index($this->m_dependencies); $this->assertInstanceOf(StreamedViewResponse::class, $response); $reflection = new \ReflectionProperty(get_class($response), 'data'); $reflection->setAccessible(true); $response_data = $reflection->getValue($response); $this->assertNotEmpty($response_data['error']); }
/** * Display the main admin area * * Includes player viewing, account duplicates checking, npc balacing * * @return Response */ public function index() { $request = RequestWrapper::$request; if (!$this->self || !$this->self->isAdmin()) { return new RedirectResponse(WEB_ROOT); } $error = null; $char_infos = null; $char_inventory = null; $first_message = null; $first_char = null; $first_account = null; $first_description = null; $dupes = AdminViews::dupedIps(); $stats = AdminViews::highRollers(); $npcs = NpcFactory::allNonTrivialNpcs(); $trivial_npcs = NpcFactory::allTrivialNpcs(); $char_ids = preg_split("/[,\\s]+/", $request->get('view')); $char_name = trim($request->get('char_name')); if ($char_name) { // View a target non-self character $first_char = Player::findByName($char_name); if (null !== $first_char && null !== $first_char->id()) { $char_ids = [$first_char->id()]; } } if (is_array($char_ids)) { // Get a different first character if an array is specified $first_char = $first_char ? $first_char : Player::find(reset($char_ids)); if ($first_char) { assert($first_char instanceof Player); $first_account = Account::findByChar($first_char); $char_inventory = AdminViews::charInventory($first_char); $first_message = $first_char->messages; $first_description = $first_char->description; } // All the rest multi-character table view try { $char_infos = AdminViews::charInfos($char_ids); } catch (InvalidArgumentException $e) { $error = $e->getMessage(); } } $parts = ['error' => $error, 'stats' => $stats, 'first_char' => $first_char, 'first_description' => $first_description, 'first_message' => $first_message, 'first_account' => $first_account, 'char_infos' => $char_infos, 'dupes' => $dupes, 'char_inventory' => $char_inventory, 'char_name' => $char_name, 'npcs' => $npcs, 'trivial_npcs' => $trivial_npcs]; return new StreamedViewResponse('Admin Actions', 'ninjamaster.tpl', $parts); }
/** * Check if a player can access any of this controllers methods * * This method is a holdover from old times when controllers were * actually directly servable procedural scripts (ah the old days!) * If a page required you to be alive or logged in, we checked if * you were (among a bunch of other things, usually dropping variables * in the global namespace) and if you were not, returned an error. * Now, controllers do this at a class level, which is mostly nonsense * and requires that the router directly serve an error page. * * @return string * @TODO this whole thing should be factored out. */ public function validate() { $error = null; $player = Player::find(SessionFactory::getSession()->get('player_id')); if ((!SessionFactory::getSession()->get('authenticated') || !$player) && static::PRIV) { $error = 'log_in'; } elseif ($player && static::ALIVE) { // That page requires the player to be alive to view it if (!$player->health) { $error = 'dead'; } else { if ($player->hasStatus(FROZEN)) { $error = 'frozen'; } } } return $error; }
/** * Send a private message to a player * * @param Container */ public function sendPersonal(Container $p_dependencies) { $request = RequestWrapper::$request; if ((int) $request->get('target_id')) { $recipient = Player::find((int) $request->get('target_id')); } else { if ($request->get('to')) { $recipient = Player::findByName($request->get('to')); } else { $recipient = null; } } if ($recipient) { Message::create(['send_from' => $p_dependencies['session']->get('player_id'), 'send_to' => $recipient->id(), 'message' => $request->get('message', null), 'type' => 0]); return new RedirectResponse('/messages?command=personal&individual_or_clan=1&message_sent_to=' . rawurlencode($recipient->name()) . '&informational=' . rawurlencode('Message sent to ' . $recipient->name() . '.')); } else { return new RedirectResponse('/messages?command=personal&error=' . rawurlencode('No such ninja to message.')); } }
/** * Displays a template wrapped in the header and footer as needed. */ public function displayPage($template, $title = null, $local_vars = array(), $options = null) { // Updates the quickstat via javascript if requested. $quickstat = isset($options['quickstat']) ? $options['quickstat'] : null; $quickstat = $quickstat ? $quickstat : (isset($local_vars['quickstat']) ? $local_vars['quickstat'] : null); $body_classes = isset($options['body_classes']) ? $options['body_classes'] : (isset($local_vars['body_classes']) ? $local_vars['body_classes'] : null); $is_index = isset($options['is_index']) ? $options['is_index'] : false; $user_id = SessionFactory::getSession()->get('player_id'); $player = Player::find($user_id); $public_char_info = $player ? $player->publicData() : []; // Char info to pass to javascript. $this->assign($local_vars); $this->assign('logged_in', $user_id); $this->assign('user_id', $user_id); $this->assign('title', $title); $this->assign('quickstat', $quickstat); $this->assign('is_index', $is_index); $this->assign('json_public_char_info', $public_char_info ? json_encode($public_char_info) : null); $this->assign('body_classes', $body_classes); $this->assign('main_template', $template); $this->display('full_template.tpl'); }
public function getPlayerIdAttribute($id) { return Player::find($id); }
public function testOfferOfBadNegativeBribe() { $request = new Request(['bribe' => -40]); RequestWrapper::inject($request); $bounty_set = 4444; $initial_gold = 7777; $this->char->setBounty($bounty_set); $this->char->setGold($initial_gold); $this->char->save(); $doshin = new DoshinController(); $doshin->bribe($this->m_dependencies); $final_char = Player::find($this->char->id()); $this->assertLessThan(7777, $final_char->gold); $modified_bounty = $final_char->bounty; $this->assertLessThan($bounty_set, $modified_bounty); $this->assertGreaterThan(0, $modified_bounty); }
public function testCloneKillKillingWipesHealthAndTurns() { $char_id = TestAccountCreateAndDestroy::char_id(); $charObj = Player::find($char_id); $char_id_2 = TestAccountCreateAndDestroy::char_id_2(); $charObj_2 = Player::find($char_id_2); // Will create characters with 127.0.0.1 ip, but that shouldn't be clone kill able. $this->assertFalse(CloneKill::canKill($char_id, $char_id_2)); $this->syncIps('555.66.77.88', $char_id, $char_id_2); $this->assertTrue(CloneKill::canKill($char_id, $char_id_2), 'Should be able to clone kill similar and same ip characters!'); CloneKill::kill($charObj, $charObj, $charObj_2); // Obliterate them. $pc1 = Player::find($char_id); $pc2 = Player::find($char_id_2); $this->assertEquals(0, $pc1->health); $this->assertEquals(0, $pc2->health); $this->assertEquals(0, $pc1->turns); $this->assertEquals(0, $pc2->turns); }
public function testFindPrivateMessagesForACertainChar() { $messageCount = 4; $this->messageData['send_to'] = $this->char_id; $this->messageData['send_from'] = $this->char_id_2; for ($count = 0; $count < $messageCount; $count++) { $this->messageData['message'] = 'Random phpunit test message' . $count; Message::create($this->messageData); // Test deletes these } $char = Player::find($this->char_id); $messages = Message::findByReceiver($char)->all(); $this->assertEquals($messageCount, count($messages)); Message::deleteByReceiver($char, 0); $this->assertEquals(0, Message::countByReceiver($char)); }
/** */ public function testDojoChangeClassLowTurnsDoesNotError() { $request = Request::create('/', 'GET', ['requested_identity' => 'crane']); RequestWrapper::inject($request); $char = Player::find($this->char_id); $char->setStrength(400); $char->setTurns(0); $char->save(); $this->assertNotEmpty($this->controller->changeClass($this->m_dependencies)); }
private function jsonIndex() { DatabaseConnection::getInstance(); $player = Player::find(SessionFactory::getSession()->get('player_id')); $events = []; $messages = []; $unread_messages = null; $unread_events = null; $items = null; if ($player) { $events = DatabaseConnection::$pdo->prepare("SELECT event_id, message AS event, date, send_to, send_from, unread, uname AS sender FROM events JOIN players ON player_id = send_from WHERE send_to = :userID and unread = 1 ORDER BY date DESC"); $events->bindValue(':userID', $player->id()); $events->execute(); $unread_events = $events->rowCount(); $messages = DatabaseConnection::$pdo->prepare("SELECT message_id, message, date, send_to, send_from, unread, uname AS sender FROM messages JOIN players ON player_id = send_from WHERE send_to = :userID1 AND send_from != :userID2 and unread = 1 ORDER BY date DESC"); $messages->bindValue(':userID1', $player->id()); $messages->bindValue(':userID2', $player->id()); $messages->execute(); $unread_messages = $messages->rowCount(); $items = query_array('SELECT item.item_display_name as item, amount FROM inventory join item on inventory.item_type = item.item_id WHERE owner = :user_id ORDER BY item_display_name', [':user_id' => $player->id()]); } return ['player' => $player ? $player->publicData() : [], 'member_counts' => $this->memberCounts(), 'unread_messages_count' => $unread_messages, 'message' => !empty($messages) ? $messages->fetch() : null, 'inventory' => ['inv' => 1, 'items' => $items, 'hash' => md5(strtotime("now"))], 'unread_events_count' => $unread_events, 'event' => !empty($events) ? $events->fetch() : null]; }
/** * Make sure a bounty offer is valid, constrain it by allowable bounty and available gold * * @param Player $char * @param int $p_targetId * @param int $p_amount * @return int */ private function validateBountyOffer(Player $char, $p_targetId, $p_amount) { $error = 0; $target = Player::find($p_targetId); if (!$target) { // Test that target exists $error = 1; } else { $amount = self::calculateMaxOffer($target->bounty, $p_amount); if ($char->gold < $amount) { $error = 2; } if ($amount <= 0) { $error = 3; } if ($target->bounty >= 5000) { $error = 4; } } return $error; }
function testGetClanObjectNumericRating() { $this->markTestIncomplete('Clan rating is not yet implemented'); $player1 = Player::find($this->char_id); $clan = Clan::find($this->clan_id); $this->assertTrue($clan->addMember($player1, $player1)); $this->assertTrue($clan->addMember(Player::find($this->char_id_2), $player1)); $this->assertTrue($clan->rating()); }
/** * Just return a character wholesale */ public static function char() { return Player::find(TestAccountCreateAndDestroy::char_id()); }
/** * @return StreamedViewResponse */ private function render($p_parts) { $account = Account::findById(SessionFactory::getSession()->get('account_id')); $player = Player::find(SessionFactory::getSession()->get('player_id')); $ninjas = $account->getCharacters(); $parts = ['gravatar_url' => $player->avatarUrl(), 'player' => $player->data(), 'account' => $account, 'oauth_provider' => $account ? $account->oauth_provider : '', 'oauth' => $account ? $account->oauth_provider && $account->oauth_id : '', 'ninjas' => $ninjas, 'successMessage' => false, 'error' => false, 'command' => '', 'delete_attempts' => 0]; return new StreamedViewResponse('Your Account', 'account.tpl', array_merge($parts, $p_parts), ['quickstat' => 'player']); }
public function testFindActive() { $result = Player::findActive(5, false); $active = true; $count = 0; foreach ($result as $record) { $active = $active && Player::find($record['player_id'])->active; $count++; } $this->assertTrue($active); $this->assertLessThan(6, $count); }
require_once dirname(__DIR__ . '..') . '/lib/base.inc.php'; use Pimple\Container; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use NinjaWars\core\RouteNotFoundException; use NinjaWars\core\Router; use NinjaWars\core\environment\RequestWrapper; use NinjaWars\core\data\GameLog; use NinjaWars\core\data\Player; use NinjaWars\core\extensions\SessionFactory; // setup our runtime environment require_once LIB_ROOT . 'environment/bootstrap.php'; try { $container = new Container(); $container['current_player'] = function ($c) { return Player::find(SessionFactory::getSession()->get('player_id')); }; $container['session'] = function ($c) { return SessionFactory::getSession(); }; // Update the activity of the page viewer in the database. RequestWrapper::init(); GameLog::updateActivityInfo(RequestWrapper::$request, SessionFactory::getSession()); // get the request information to parse the route $response = Router::route(Request::createFromGlobals(), $container); if ($response instanceof Response) { $response->send(); } else { throw new \RuntimeException('Route returned something other than a Response'); } } catch (RouteNotFoundException $e) {
/** * ???? * * @todo Simplify this invite system. * @param int $user_id * @param int $clan_id * @return void */ private function sendClanJoinRequest($user_id, $clan_id) { DatabaseConnection::getInstance(); $clan_obj = new Clan($clan_id); $leader = $clan_obj->getLeaderInfo(); $leader_id = $leader['player_id']; $user = Player::find($user_id); $username = $user->name(); $confirmStatement = DatabaseConnection::$pdo->prepare('SELECT verification_number FROM players WHERE player_id = :user'); $confirmStatement->bindValue(':user', $user_id); $confirmStatement->execute(); $confirm = $confirmStatement->fetchColumn(); // These ampersands get encoded later. $url = "[href:clan/review/?joiner={$user_id}&confirmation={$confirm}|Confirm Request]"; $join_request_message = 'CLAN JOIN REQUEST: ' . htmlentities($username) . " has sent a request to join your clan.\n If you wish to allow this ninja into your clan click the following link:\n {$url}"; Message::create(['send_from' => $user_id, 'send_to' => $leader_id, 'message' => $join_request_message, 'type' => 0]); }
public function testTurnCostResurrectWithChi() { $turns = 50; $this->char->death(); $this->char->setClass('dragon'); // dragon class has chi skill $this->char->level = ShrineController::FREE_RES_LEVEL_LIMIT; $this->char->turns = $turns; $this->char->save(); $skillList = new Skill(); $this->assertTrue($skillList->hasSkill('chi', $this->char)); $cont = new ShrineController(); $response = $cont->resurrect($this->m_dependencies); $final_char = Player::find($this->char->id()); $reflection = new \ReflectionProperty(get_class($response), 'data'); $reflection->setAccessible(true); $response_data = $reflection->getValue($response); $this->assertTrue(in_array('result-resurrect', $response_data['pageParts'])); $this->assertGreaterThan($this->char->getMaxHealth() / 1.5, $final_char->health); $this->assertLessThan($turns, $final_char->turns); }
public function testControllerAttackAsIfAgainstAMerchant2() { $this->markTestSkipped('Merchants are unreliable to test for now.'); RequestWrapper::inject(Request::create('/npc/attack/merchant2')); $this->char->strength = 9999; $this->char->health = 9999; $init_gold = $this->char->gold; $npco = new Npc('merchant2'); $response = $this->controller->attack($this->m_dependencies); $final_char = Player::find($this->char->id()); $this->assertNotEmpty($response); $reflection = new \ReflectionProperty(get_class($response), 'data'); $reflection->setAccessible(true); $response_data = $reflection->getValue($response); $this->assertEquals('merchant2', $response_data['victim']); $this->assertGreaterThan(0, $npco->minGold()); $this->assertGreaterThan($init_gold, $final_char->gold); }