diff --git a/src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php b/src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php index 0252f843..86058a20 100644 --- a/src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php +++ b/src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php @@ -42,6 +42,25 @@ + + + + + + + + + acore_resurrection_scroll != '1') echo 'style="display:none;"'?>> + + + + + + + @@ -126,6 +145,10 @@ jQuery("#acore-name-unlock-thresholds-add").on("click", () => addThreshold()); + jQuery('#acore_resurrection_scroll').on('change', function() { + jQuery('.acore_resurrection_scroll_config').toggle(); + }); + acore_name_unlock_thresholds as $i => $threshold) { if ($threshold[0] != "" && $threshold[1] != "") { echo "addThreshold($i, $threshold[0], $threshold[1]);"; diff --git a/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollController.php b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollController.php new file mode 100644 index 00000000..ff8ad2d6 --- /dev/null +++ b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollController.php @@ -0,0 +1,80 @@ +view = new ResurrectionScrollView($this); + } + + public function render() + { + $data = $this->getScrollData(); + echo $this->view->getRender($data); + } + + private function getScrollData() + { + $accId = ACoreServices::I()->getAcoreAccountId(); + + if (!isset($accId) || !is_numeric($accId)) { + return null; + } + + $conn = ACoreServices::I()->getCharacterEm()->getConnection(); + + // Get scroll account data + $scrollData = null; + try { + $query = "SELECT `AccountId`, `EndDate`, `Expired` + FROM `mod_ress_scroll_accounts` + WHERE `AccountId` = ?"; + $stmt = $conn->prepare($query); + $stmt->bindValue(1, $accId); + $res = $stmt->executeQuery(); + $scrollData = $res->fetchAssociative(); + } catch (\Exception $e) { + // Table may not exist if module is not installed + } + + // Get most recent character logout time + $lastLogout = null; + try { + $query = "SELECT MAX(`logout_time`) as `last_logout` + FROM `characters` + WHERE `account` = ? AND `deleteDate` IS NULL"; + $stmt = $conn->prepare($query); + $stmt->bindValue(1, $accId); + $res = $stmt->executeQuery(); + $row = $res->fetchAssociative(); + if ($row && $row['last_logout']) { + $lastLogout = (int) $row['last_logout']; + } + } catch (\Exception $e) { + // Ignore + } + + $daysInactive = (int) Opts::I()->acore_resurrection_scroll_days_inactive; + $isEligible = false; + if ($lastLogout) { + $daysSinceLogout = (int) ((time() - $lastLogout) / 86400); + $isEligible = $daysSinceLogout >= $daysInactive; + } + + return [ + 'accountId' => $accId, + 'scrollData' => $scrollData, + 'lastLogout' => $lastLogout, + 'daysInactive' => $daysInactive, + 'isEligible' => $isEligible, + ]; + } +} diff --git a/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php new file mode 100644 index 00000000..4f11e8ee --- /dev/null +++ b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php @@ -0,0 +1,46 @@ +acore_resurrection_scroll == '1') { + add_submenu_page('profile.php', 'Scroll of Resurrection', 'Scroll of Resurrection', 'read', ACORE_SLUG . '-resurrection-scroll', array($this, 'acore_resurrection_scroll_menu_page')); + } + } + + function acore_resurrection_scroll_menu_page() + { + $controller = new ResurrectionScrollController(); + $controller->render(); + } +} + +function resurrection_scroll_menu_init() +{ + $menu = ResurrectionScrollMenu::I(); + + add_action('admin_menu', array($menu, 'acore_resurrection_scroll_menu')); +} diff --git a/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollView.php b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollView.php new file mode 100644 index 00000000..345fa33b --- /dev/null +++ b/src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollView.php @@ -0,0 +1,189 @@ +controller = $controller; + } + + public function getRender($data) + { + ob_start(); + + wp_enqueue_style('bootstrap-css', '//cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css', array(), '5.1.3'); + wp_enqueue_style('acore-css', ACORE_URL_PLG . 'web/assets/css/main.css', array(), '0.1'); + wp_enqueue_script('bootstrap-js', '//cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', array(), '5.1.3'); + + // Determine account status + $hasData = $data && isset($data['scrollData']) && $data['scrollData']; + $isExpired = $hasData && $data['scrollData']['Expired'] == 1; + $endDate = $hasData ? (int) $data['scrollData']['EndDate'] : null; + $now = time(); + $isActive = $hasData && !$isExpired && $endDate > $now; + $lastLogout = $data && isset($data['lastLogout']) ? $data['lastLogout'] : null; + $daysInactive = $data ? (int) $data['daysInactive'] : 0; + $isEligible = $data ? $data['isEligible'] : false; + + if ($isActive) { + $statusLabel = 'Active'; + $statusClass = 'success'; + } elseif ($isExpired || ($hasData && $endDate <= $now)) { + $statusLabel = 'Expired'; + $statusClass = 'secondary'; + } else { + $statusLabel = 'Not Enrolled'; + $statusClass = 'warning'; + } + +?> + +
+

Scroll of Resurrection

+ +
+
+
+
+
Your Account Status
+
+ +
Unable to retrieve account information.
+ + + + + + + + + + + + + + + + + + + + + + +
Scroll Status
Eligibility + + Enrolled + + Eligible + - Log in to the game server to activate + + Not Eligible + setTimestamp($eligibleTimestamp); + $daysRemaining = (int) ceil(($eligibleTimestamp - time()) / 86400); + if ($daysRemaining > 0) { + echo '- Eligible on ' . esc_html($eligibleDate->format('M j, Y - H:i')) . ' (' . $daysRemaining . ' days remaining)'; + } + } ?> + +
Last Character Logout + setTimestamp($lastLogout); + $daysSince = (int) ((time() - $lastLogout) / 86400); + echo esc_html($logoutDate->format('M j, Y - H:i')) . ' (' . $daysSince . ' days ago)'; + } else { + echo 'No characters found'; + } ?> +
Bonus Expires + setTimestamp($endDate); + echo esc_html($expireDate->format('M j, Y - H:i')); + if ($isActive) { + $daysLeft = (int) ceil(($endDate - $now) / 86400); + echo ' (' . $daysLeft . ' days remaining)'; + } + ?> +
+ +
+
+
+ +
+
+
+
Overview
+
+

+ The Scroll of Resurrection is a comeback incentive for inactive players. + If your account has been inactive for an extended period, you will automatically receive + rested XP bonuses when you log in, helping you catch up faster. +

+

+ The bonus grants a full rested XP pool for your current level each time + you log in or level up, and lasts for a limited duration from your first eligible login. +

+
+
+
+
+ +
+
+
+
+
How It Works
+
+
    +
  1. When you log in, the system checks how long your account has been inactive.
  2. +
  3. If you have been away for long enough, your account becomes eligible for the bonus.
  4. +
  5. You receive a full rested XP pool on every login and level-up.
  6. +
  7. The bonus lasts for a set number of days from your first eligible login.
  8. +
  9. Once the duration expires, the bonus stops automatically.
  10. +
+
+
+
+ +
+
+
+
Player Commands
+
+ + + + + + + + + + + + + + + + + +
CommandDescription
.rscroll infoView your scroll eligibility status, last logout date, and bonus expiration
.rscroll disableToggle the rested XP bonus on or off for your character (already earned XP is kept)
+
+
+
+
+
+ + '0']; + public $acore_resurrection_scroll=""; + public $acore_resurrection_scroll_days_inactive="180"; public $acore_item_restoration=""; public $acore_name_unlock_thresholds = [ [5, 30], // level < 5 -> 30 days diff --git a/src/acore-wp-plugin/src/boot.php b/src/acore-wp-plugin/src/boot.php index ea262eec..b404616d 100644 --- a/src/acore-wp-plugin/src/boot.php +++ b/src/acore-wp-plugin/src/boot.php @@ -9,6 +9,7 @@ require_once ACORE_PATH_PLG . 'src/Components/AdminPanel/AdminPanel.php'; require_once ACORE_PATH_PLG . 'src/Components/CharactersMenu/CharactersMenu.php'; require_once ACORE_PATH_PLG . 'src/Components/UnstuckMenu/UnstuckMenu.php'; +require_once ACORE_PATH_PLG . 'src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php'; require_once ACORE_PATH_PLG . 'src/Components/ServerInfo/ServerInfo.php'; require_once ACORE_PATH_PLG . 'src/Components/Tools/ToolsInfo.php'; require_once ACORE_PATH_PLG . 'src/Components/UserPanel/UserMenu.php';