alert(' . json_encode(t('shop.payment_processing')) . ');'; } // Import from config: $shop = $config['shop']; if ($shop['loginToView'] === true) protect_page(); $loggedin = user_logged_in(); function shop_db_offer_columns(): array { $columns = array(); $rows = db()->fetchAll("SHOW COLUMNS FROM `znote_shop_offers`;"); if (is_array($rows)) { foreach ($rows as $row) { if (!empty($row['Field'])) { $columns[(string)$row['Field']] = true; } } } return $columns; } function shop_load_db_offers(): array { $columns = shop_db_offer_columns(); $where = !empty($columns['active']) ? "WHERE `active` = 1" : ""; $order = !empty($columns['sort_order']) ? "ORDER BY `sort_order` ASC, `id` ASC" : "ORDER BY `id` ASC"; $rows = db()->fetchAll(" SELECT `id`, `type`, `itemid`, `count`, `description`, `points` FROM `znote_shop_offers` {$where} {$order}; "); if (!is_array($rows)) { return array(); } $offers = array(); foreach ($rows as $row) { $itemid = (int)$row['itemid']; if ((int)$row['type'] === 5 && $itemid > 0) { $male = (int)floor($itemid / 10000); $female = (int)($itemid % 10000); $itemid = array($male, $female); } $offers[(int)$row['id']] = array( 'type' => (int)$row['type'], 'itemid' => $itemid, 'count' => (int)$row['count'], 'description' => (string)$row['description'], 'points' => (int)$row['points'], ); } return $offers; } $shop_list = shop_load_db_offers(); if ($loggedin === true) { $postedShopSession = (string)($_POST['session'] ?? ''); $storedShopSession = (string)($_SESSION['shop_session'] ?? ''); if (!empty($_POST['buy']) && $postedShopSession !== '' && $storedShopSession !== '' && hash_equals($storedShopSession, $postedShopSession)) { unset($_SESSION['shop_session']); $time = time(); $cid = (int)$user_data['id']; // Sanitizing post, setting default buy value $buy = false; $post = (int)$_POST['buy']; foreach ($shop_list as $key => $value) { if ($key === $post) { $buy = $value; } } if ($buy === false) die("Error: Shop offer ID mismatch."); // Plugins may adjust what this offer costs - a discount code, a happy // hour, a loyalty rebate. The filtered value is what gets checked, // charged and logged, so the three can never disagree. $buy['points'] = max(0, (int)znote_hook_filter('shop.price', (int)$buy['points'], array( 'account_id' => $cid, 'offer_id' => $post, 'offer' => $buy, ))); // If this is an outfit offer, convert array into an integer. if ($buy['type'] == 5) { if (is_array($buy['itemid'])) { if (COUNT($buy['itemid']) == 2) $buy['itemid'] = ($buy['itemid'][0] * 1000) + $buy['itemid'][1]; else $buy['itemid'] = $buy['itemid'][0]; } } $db = db(); if (!$db->beginTransaction()) { die("Failed to start shop transaction."); } $data = $db->fetchOne("SELECT `points` FROM `znote_accounts` WHERE `account_id` = ? LIMIT 1 FOR UPDATE;", [$cid]); if (!$data) { $db->rollback(); die("0: Account is not converted to work with Znote AAC"); } $old_points = (int)$data['points']; if ($old_points < $buy['points']) { $db->rollback(); echo 'You need more points, this offer cost '.$buy['points'].' points.'; } else { $expense_points = (int)$buy['points']; $orderReady = true; if (!$db->execute( "UPDATE `znote_accounts` SET `points` = `points` - ? WHERE `account_id` = ? AND `points` >= ?;", [$expense_points, $cid, $expense_points] )) { $orderReady = false; } // Do the magic (insert into db, or change sex etc) // If type is 2 or 3 if ($orderReady && $buy['type'] == 2) { // Add premium days to account $orderReady = user_account_add_premdays($cid, $buy['count']); $successMessage = 'You now have '.$buy['count'].' additional days of premium membership.'; } else if ($orderReady) { $orderReady = $db->execute( "INSERT INTO `znote_shop_orders` (`account_id`, `type`, `itemid`, `count`, `time`) VALUES (?, ?, ?, ?, ?);", [$cid, (int)$buy['type'], (int)$buy['itemid'], (int)$buy['count'], $time] ); if ($buy['type'] == 3) { $successMessage = ''. t('shop.gender_unlocked') .''; } else if ($buy['type'] == 4) { $successMessage = ''. t('shop.name_unlocked') .''; } else { $successMessage = 'Your order is ready to be delivered. Write this command in-game to get it: [!shop].
Make sure you are in depot and can carry it before executing the command!
'; } } if ($orderReady) { $orderReady = $db->execute( "INSERT INTO `znote_shop_logs` (`account_id`, `player_id`, `type`, `itemid`, `count`, `points`, `time`) VALUES (?, 0, ?, ?, ?, ?, ?);", [$cid, (int)$buy['type'], (int)$buy['itemid'], (int)$buy['count'], (int)$buy['points'], $time] ); } if ($orderReady) { $db->commit(); $user_znote_data['points'] = $old_points - $expense_points; echo $successMessage; // Plugins can react to a purchase - a coupon ledger, a Discord message, // a loyalty counter. They cannot change what was bought; this is a // notification, fired after the points have already been taken. znote_hook('shop.purchased', array( 'account_id' => $cid, 'offer_id' => $post, 'type' => $buy['type'], 'itemid' => $buy['itemid'], 'count' => $buy['count'], 'points' => $buy['points'], )); $buy['points'] = 0; } else { $db->rollback(); echo 'Shop purchase failed. Please try again or contact staff.'; } } //var_dump($buy); //echo ''. $_POST['buy'] .''; } } view('shop'); theme_close();