Compare commits

..

87 Commits

Author SHA1 Message Date
slawkens
67f54eacbc Merge branch 'develop' into feature/refactor-account-lost 2024-09-12 08:24:06 +02:00
slawkens
93641fc68a New hooks in account manage + create 2024-09-08 15:03:18 +02:00
slawkens
ea7e808508 Add more clients (13.22+) 2024-09-08 14:48:59 +02:00
slawkens
da3fc1fc8c Interesting update from opentibiabr (Uptime readable) 2024-09-08 14:48:42 +02:00
slawkens
201f95caa8 Do not create player if there is no players table in db 2024-09-05 15:36:19 +02:00
slawkens
779aa152fa Do not require players & guilds tables 2024-09-05 15:35:55 +02:00
slawkens
d99b22f98b Fix attempts counting 2024-08-26 15:19:37 +02:00
slawkens
35e28350bd Change spaces to tabs 2024-08-26 15:19:17 +02:00
Gabriel Pedro
327dcb5f87 feat: ratelimit (#267)
* feat: rate limit settings

* fix: section label

* fix: real ip

* fix: real ip
2024-08-26 14:53:09 +02:00
Gabriel Pedro
bc8ada6fe2 fix: verified email for login.php (#265)
* fix: required email login verify

* fix: add missing select column

* Revert "fix: add missing select column"

This reverts commit db79e3118a.
2024-08-25 13:40:32 +02:00
Gabriel Pedro
6183b7ee52 chore: drop raw queries (#266)
* chore: eloquent migrate

* fix: typos
2024-08-25 13:38:58 +02:00
Jonatas
760c3ab017 Highscore frags fixed for TFS 0.3 (#263) 2024-08-16 18:19:44 +02:00
slawkens
ab73d60c61 Fix warning if core.account_country is disabled 2024-08-12 23:01:45 +02:00
slawkens
8d8bdb6dac Fix missing groups variable #262. thanks @Scrollog for reporting 2024-08-12 22:54:23 +02:00
slawkens
71c00aa5e0 Use https for outfit & item images 2024-08-01 23:17:07 +02:00
slawkens
1fcdd54c94 Patching from master
OTS_House refactor code + $db->update with nulls
2024-07-25 15:43:42 +02:00
slawkens
c2ec468246 feat: search by email in accounts editor 2024-07-23 22:56:31 +02:00
slawkens
68118fb7c2 Update phpstan.neon 2024-07-23 08:47:22 +02:00
slawkens
5a69b9a802 Update composer.lock 2024-07-23 08:45:55 +02:00
slawkens
45e63b13c3 Update version to 1.0-RC 2024-07-23 08:35:08 +02:00
slawkens
758a8b3330 Prepare changelog for 1.0-RC
Release Candidate.
2024-07-23 08:30:53 +02:00
slawkens
1843728930 Rename to playerSample 2024-07-23 08:07:59 +02:00
slawkens
cde8891b9b Merge branch 'develop' into feature/refactor-account-lost 2024-07-14 05:58:47 +02:00
slawkens
cff62ccba4 Another try 2024-07-12 20:54:12 +02:00
slawkens
28f98db9de Fix PHPStan errors in monsters.php 2024-07-12 20:48:27 +02:00
slawkens
da14e125e9 Fix highscores skill links (Thanks @vyroq) 2024-07-12 20:01:12 +02:00
slawkens
cd49dfc799 Set Admin Account verified by default 2024-07-10 18:12:05 +02:00
slawkens
50a8b8169f [WIP] Account Lost refactor 2024-07-10 18:08:21 +02:00
slawkens
ef79b99b8a Fix monster not found exception 2024-07-10 09:54:54 +02:00
slawkens
9a27403e7d Fixes to account_mail_verify 2024-07-09 23:35:39 +02:00
slawkens
5f63c3b227 Invalidate cached setting 2024-07-09 23:33:00 +02:00
slawkens
203e411b62 Allow account_create_character_create even if account_mail_verify is activated 2024-07-09 23:06:12 +02:00
slawkens
fcb13f3c0f Fixes to account verify - do not allow login without verified email (Thanks @anyeor) 2024-07-09 23:05:36 +02:00
slawkens
d94828772c Rework 5th step of installation, to fix some pointless message about Cache 2024-07-09 22:04:47 +02:00
slawkens
10a739773c Detect tools/ext exists on install to prevent broken installs 2024-07-09 21:29:42 +02:00
slawkens
83b3dc803a Fix 5th step of installer 2024-07-08 19:50:05 +02:00
slawkens
33a47137c9 Fix hooks priority default 2024-06-29 15:09:44 +02:00
slawkens
dc17b701da feat: Hooks priority 2024-06-29 14:05:06 +02:00
slawkens
d30811404b Update players.php 2024-06-28 19:03:06 +02:00
slawkens
a631760dbf Order fraggers by time 2024-06-23 16:10:50 +02:00
slawkens
bc3dcab462 deny all is enough 2024-06-23 09:55:15 +02:00
slawkens
a8d255c04b feat: Plugins pages: subSubFolders 2024-06-14 08:07:52 +02:00
slawkens
813786c768 Update cleanup_players.php 2024-06-14 06:42:45 +02:00
slawkens
0db0ec1aa4 Fix useGuildNick displaying 2024-06-14 06:42:42 +02:00
slawkens
bdc0c43d3f Refactor account routes into sub folders 2024-06-13 22:23:43 +02:00
slawkens
c7a6a539a9 Another approach to fix duplicates - priorities
Priority description: (lower number - higher priority)
1-99 Highest priority - overrides everything, even pages from database, use with caption
100 - default for pages in database
101-999 - recommended range for plugins
1000 - default value for plugins if no other specified
1001 - 9999 - no usage currently
10000 - default myaac routes
2024-06-13 21:35:47 +02:00
slawkens
c1d4b4f80c Make autoload of pages, commands and themes configurable
Not everyone might want them to autoload
2024-06-13 14:36:18 +02:00
slawkens
47a19e85dd Reposition code for setting ranks (addition to previous commit) 2024-06-13 13:07:03 +02:00
slawkens
d9c1b2507c Create guild_rank entries, in case MySQL trigger not loaded 2024-06-13 12:51:29 +02:00
slawkens
4c0739d3e9 Fixed fastRoute duplicate errors 2024-06-13 11:29:06 +02:00
slawkens
afe70a03c5 Fix email_change status 2024-06-11 13:32:22 +02:00
slawkens
3fadf87a7a Fix title on login page 2024-06-11 13:14:15 +02:00
slawkens
c24576165c login.php early exit + fix title 2024-06-11 12:55:02 +02:00
slawkens
1e5c9dcd9b Nothing important, just a space for better look! 2024-06-10 19:43:08 +02:00
slawkens
a04d186c22 Fix highscores frags for TFS 1.x and canary 2024-06-10 18:53:17 +02:00
slawkens
42f99c3edc Fraggers in characters page for TFS 1.x and canary 2024-06-08 23:27:19 +02:00
slawkens
4f4965369d spaces -> tabs 2024-06-05 21:53:58 +02:00
slawkens
57b47ab798 Fix if <flags> are not present in monster.xml 2024-06-05 21:51:50 +02:00
slawkens
9ea2a5067f Order towns by id 2024-06-05 15:10:55 +02:00
slawkens
ec96985872 Revert some breaking change 2024-06-01 18:44:06 +02:00
slawkens
9f2a51b351 Spaces and remove useless function 2024-06-01 15:53:34 +02:00
slawkens
a1d7c94166 Closing tag 2024-06-01 15:51:28 +02:00
slawkens
0c3e3e16dd Set default group_id 2024-06-01 15:51:21 +02:00
slawkens
45dda5e834 Add HOOK_ACCOUNT_CREATE_CHARACTER_* hooks 2024-05-31 22:59:52 +02:00
slawkens
32ae4dde20 Fix closing table elements 2024-05-31 22:57:44 +02:00
slawkens
d3f03fa735 Better place for INSTALL_FINISH hook 2024-05-31 19:21:37 +02:00
slawkens
44eff8092c Fix settings title 2024-05-31 18:30:01 +02:00
slawkens
8ef3d06f1e Fix duplicated routes 2024-05-31 17:22:39 +02:00
slawkens
60bd64a639 Update router.php 2024-05-30 20:40:15 +02:00
slawkens
a1bcb217ec Fixes regarding not working google recaptcha (+few previous commits) 2024-05-30 17:36:07 +02:00
slawkens
933b681a9f Fixed if account_country is disabled 2024-05-30 14:25:31 +02:00
slawkens
e9aea17e1b Close form in proper place 2024-05-30 14:21:52 +02:00
slawkens
060400b074 Revert "Use tables headline for account.create.html.twig"
This reverts commit 64387e085b.
2024-05-30 13:48:59 +02:00
slawkens
6be4a42c5a Revert "Fix form id"
This reverts commit d225c2da26.
2024-05-30 13:48:53 +02:00
slawkens
1e8198635e Enable dev mode on install, prevent noobs asking white page questions 2024-05-30 12:00:26 +02:00
slawkens
be78a0fc45 Do adjustments only if table exist 2024-05-30 11:32:03 +02:00
slawkens
08ac8ebade Add HOOK_INSTALL_FINISH 2024-05-30 11:31:41 +02:00
slawkens
66ecc487a1 One more early exit 2024-05-30 11:18:06 +02:00
slawkens
9e23ec6745 Early exit in 7-finish install 2024-05-30 11:14:16 +02:00
slawkens
968899ef77 Pass $playerSample as parameter to hook 2024-05-30 10:09:31 +02:00
slawkens
3844ad0d71 Fix warnings in basic.js 2024-05-30 09:49:02 +02:00
slawkens
c93bf5a984 create_character_name_min_length => 3 2024-05-30 09:02:19 +02:00
slawkens
50336a810b Fix blessings longer than 3 characters 2024-05-30 08:23:31 +02:00
slawkens
48f6ca0eba Tabs + spaces 2024-05-30 08:20:59 +02:00
slawkens
30107222d4 Add getLongLong function to OTS_Buffer 2024-05-30 08:20:33 +02:00
slawkens
f92b275f70 Update version to beta.2 2024-05-23 23:44:29 +02:00
slawkens
504242fb84 Do not create news about myaac, if any news already exist (on installation) 2024-05-23 23:40:27 +02:00
102 changed files with 2732 additions and 2233 deletions

View File

@@ -1,5 +1,35 @@
# Changelog
## [1.0-RC -23.07.2024]
Changes since 1.0-beta:
### Added
* Feat: Hooks priority (https://github.com/slawkens/myaac/commit/dc17b701da053e04bfa64e21be9247a4f07505e1)
* Make autoload of pages, commands and themes configurable (https://github.com/slawkens/myaac/commit/c1d4b4f80cd6bb85507ee9471e47013955a26a91)
* Fraggers in characters page for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/42f99c3edc8de39cccc5632cb42e88b24579c5a6)
* New hooks: HOOK_INSTALL_FINISH, HOOK_ACCOUNT_CREATE_CHARACTER_* (https://github.com/slawkens/myaac/commit/08ac8ebade106521a5c7396faa5ce7006e629f7c, https://github.com/slawkens/myaac/commit/45dda5e834ff2059faea6ef9be2efa76f1723cbd)
### Changed
* Allow account_create_character_create even if account_mail_verify is activated (https://github.com/slawkens/myaac/commit/203e411b626fe62401a4b74a48420769e512aa39)
* Create guild_rank entries, in case MySQL trigger not loaded (https://github.com/slawkens/myaac/commit/d9c1b2507c81f306970642b35e4bf5f7cc04a6f2, https://github.com/slawkens/myaac/commit/47a19e85dd84e9f3b39a1b29cfc2c04b004832b9)
* Set Admin Account verified by default (https://github.com/slawkens/myaac/commit/cd49dfc79942f3301ce9c0b8d899b9f39bda9a41)
* Refactor account routes into sub folders (https://github.com/slawkens/myaac/commit/bdc0c43d3fd3a51030c3e916bdb9f008468f5ecd)
* Order towns by id (https://github.com/slawkens/myaac/commit/9ea2a5067fc4b75de395f381577b18914132ad84)
* Do not create news about myaac, if any news already exist (on installation (https://github.com/slawkens/myaac/commit/504242fb846b73b56b87bc1e39d070687ad7f5b4)
### Fixed
* Not working google recaptcha plugin (https://github.com/slawkens/myaac/commit/a1bcb217ecf4e21fd58da4ba491da1852029898a)
* Not working account create if account_country is disabled (https://github.com/slawkens/myaac/commit/933b681a9fcdbb6283e0469b3806d2ded492d232)
* Account verify - do not allow login without verified email (Thanks @anyeor, https://github.com/slawkens/myaac/commit/fcb13f3c0fb8ceafda0bd614a229a26a269432bd)
* Detect tools/ext exists on install to prevent broken installs (https://github.com/slawkens/myaac/commit/10a739773c4f2911876bc802a0ee0537c3e00a92)
* Cache reloading each time page refreshes (https://github.com/slawkens/myaac/commit/ec96985872057340112f65073efc0c4bf86dddb0)
* Highscores frags for TFS 1.x and canary (https://github.com/slawkens/myaac/commit/a04d186c22912915f0a7873dfe677ef3b5a23c79)
* Monsters page: monster not found exception (https://github.com/slawkens/myaac/commit/ef79b99b8acc179f14b8475547347d9daca27512)
* Fixed bug if \<flags\> are not present in monster.xml (https://github.com/slawkens/myaac/commit/57b47ab7983f625c7c0ef4f5303a4d07ef172786)
* fastRoute duplicate errors (https://github.com/slawkens/myaac/commit/4c0739d3e93812dff0c33849ea3f38e4e49113ac)
* useGuildNick displaying (https://github.com/slawkens/myaac/commit/0db0ec1aa47e044c26bc403ff5078a2115d086f8)
## [1.0-beta - 18.05.2024]
Minimum PHP version for this release is 8.1.

View File

@@ -8,6 +8,7 @@
* @link https://my-aac.org
*/
use MyAAC\Models\Account as AccountModel;
use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!');
@@ -51,36 +52,51 @@ $acc_type = setting('core.account_types');
<?php
$id = 0;
$search_account = '';
$search_account = $search_account_email = '';
if (isset($_REQUEST['id']))
$id = (int)$_REQUEST['id'];
else if (isset($_REQUEST['search_email'])) {
$search_account_email = $_REQUEST['search_email'];
$accountModel = AccountModel::where('email', $search_account_email)->limit(11)->get(['email', 'id']);
if (count($accountModel) == 0) {
echo_error('No entries found.');
} else if (count($accountModel) == 1) {
$id = $accountModel->first()->getKey();
} else if (count($accountModel) > 10) {
echo_error('Specified e-mail resulted with too many accounts.');
}
}
else if (isset($_REQUEST['search'])) {
$search_account = $_REQUEST['search'];
if (strlen($search_account) < 3 && !Validator::number($search_account)) {
echo_error('Player name is too short.');
$min_size = 3;
if ($nameOrNumberColumn == 'number') {
$min_size = 1;
}
if (strlen($search_account) < $min_size && !Validator::number($search_account)) {
echo_error('Account ' . $nameOrNumberColumn . ' is too short.');
} else {
$query = $db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $db->quote($search_account));
if ($query->rowCount() == 1) {
$query = $query->fetch();
$id = (int)$query['id'];
$query = AccountModel::where($nameOrNumberColumn, '=', $search_account)->limit(11)->get(['id', $nameOrNumberColumn]);
if (count($query) == 0) {
echo_error('No entries found.');
} else if (count($query) == 1) {
$id = $query->first()->getKey();
} else if (count($query) > 10) {
echo_error('Specified name resulted with too many accounts.');
} else {
$query = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` LIKE ' . $db->quote('%' . $search_account . '%'));
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
$str_construct = 'Do you mean?<ul class="mb-0">';
foreach ($query as $row)
$str_construct .= '<li><a href="' . $admin_base . '&id=' . $row['id'] . '">' . $row[$nameOrNumberColumn] . '</a></li>';
$str_construct .= '</ul>';
echo_error($str_construct);
} else if ($query->rowCount() > 10)
echo_error('Specified name resulted with too many accounts.');
else
echo_error('No entries found.');
$str_construct = 'Do you mean?<ul class="mb-0">';
foreach ($query as $row) {
$str_construct .= '<li><a href="' . $admin_base . '&id=' . $row->getKey() . '">' . $row->attributes[$nameOrNumberColumn] . '</a></li>';
}
$str_construct .= '</ul>';
echo_error($str_construct);
}
}
}
?>
<div class="row">
<?php
$groups = new OTS_Groups_List();
if ($id > 0) {
$account = new OTS_Account();
$account->load($id);
@@ -143,7 +159,9 @@ else if (isset($_REQUEST['search'])) {
$rl_loca = $_POST['rl_loca'];
//country
$rl_country = $_POST['rl_country'];
if(setting('core.account_country')) {
$rl_country = $_POST['rl_country'];
}
$web_flags = $_POST['web_flags'];
verify_number($web_flags, 'Web Flags', 1);
@@ -190,7 +208,11 @@ else if (isset($_REQUEST['search'])) {
}
$account->setRLName($rl_name);
$account->setLocation($rl_loca);
$account->setCountry($rl_country);
if(setting('core.account_country')) {
$account->setCountry($rl_country);
}
$account->setCustomField('created', $created);
$account->setWebFlags($web_flags);
$account->setCustomField('web_lastlogin', $web_lastlogin);
@@ -214,7 +236,7 @@ else if (isset($_REQUEST['search'])) {
}
}
} else if ($id == 0) {
$accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ' FROM `accounts` ORDER BY `id` ASC');
$accounts_db = $db->query('SELECT `id`, `' . $nameOrNumberColumn . '`' . ($hasTypeColumn ? ',type' : ($hasGroupColumn ? ',group_id' : '')) . ', email FROM `accounts` ORDER BY `id` ASC');
?>
<div class="col-12 col-sm-12 col-lg-10">
<div class="card card-info card-outline">
@@ -228,6 +250,7 @@ else if (isset($_REQUEST['search'])) {
<th>ID</th>
<th><?= ($nameOrNumberColumn == 'number' ? 'Number' : 'Name'); ?></th>
<?php if($hasTypeColumn || $hasGroupColumn): ?>
<th>E-Mail</th>
<th>Position</th>
<?php endif; ?>
<th style="width: 40px">Edit</th>
@@ -238,6 +261,7 @@ else if (isset($_REQUEST['search'])) {
<tr>
<th><?php echo $account_lst['id']; ?></th>
<td><?php echo $account_lst[$nameOrNumberColumn]; ?></a></td>
<td><?php echo $account_lst['email']; ?></td>
<?php if($hasTypeColumn || $hasGroupColumn): ?>
<td>
<?php if ($hasTypeColumn) {
@@ -585,6 +609,16 @@ else if (isset($_REQUEST['search'])) {
</div>
<div class="card-body">
<div class="row">
<div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?>
<label for="search">Account E-Mail:</label>
<div class="input-group input-group-sm">
<input type="email" class="form-control" id="search_email" name="search_email" value="<?= escapeHtml($search_account_email); ?>" maxlength="255" size="255">
<span class="input-group-append"><button type="submit" class="btn btn-info btn-flat">Search</button></span>
</div>
</form>
</div>
<div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?>

View File

@@ -7,6 +7,9 @@
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
use MyAAC\Models\Account;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Mailer';
@@ -61,15 +64,15 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) {
$add = ' AND `email_verified` = 1';
}
$query = $db->query('SELECT `email` FROM `accounts` WHERE `email` != ""' . $add);
$query = Account::where('email', '!=', '')->get(['email']);
foreach ($query as $email) {
if (_mail($email['email'], $mail_subject, $mail_content)) {
if (_mail($email->email, $mail_subject, $mail_content)) {
$success++;
}
else {
$failed++;
echo '<br />';
error('An error occorred while sending email to <b>' . $email['email'] . '</b>. For Admin: More info can be found in system/logs/mailer-error.log');
error('An error occorred while sending email to <b>' . $email->email . '</b>. For Admin: More info can be found in system/logs/mailer-error.log');
}
}

View File

@@ -24,20 +24,13 @@ $freePremium = $config['lua']['freePremium'];
function admin_give_points($points)
{
global $db, $hasPointsColumn;
global $hasPointsColumn;
if (!$hasPointsColumn) {
displayMessage('Points not supported.');
return;
}
$statement = $db->prepare('UPDATE `accounts` SET `premium_points` = `premium_points` + :points');
if (!$statement) {
displayMessage('Failed to prepare query statement.');
return;
}
if (!Account::query()->increment('premium_points', $points)) {
displayMessage('Failed to add points.');
return;
@@ -47,7 +40,7 @@ function admin_give_points($points)
function admin_give_coins($coins)
{
global $db, $hasCoinsColumn;
global $hasCoinsColumn;
if (!$hasCoinsColumn) {
displayMessage('Coins not supported.');
@@ -62,24 +55,6 @@ function admin_give_coins($coins)
displayMessage($coins . ' coins added to all accounts.', true);
}
function query_add_premium($column, $value_query, $condition_query = '1=1', $params = [])
{
global $db;
$statement = $db->prepare("UPDATE `accounts` SET `{$column}` = $value_query WHERE $condition_query");
if (!$statement) {
displayMessage('Failed to prepare query statement.');
return false;
}
if (!$statement->execute($params)) {
displayMessage('Failed to add premium days.');
return false;
}
return true;
}
function admin_give_premdays($days)
{
global $db, $freePremium;
@@ -94,9 +69,9 @@ function admin_give_premdays($days)
// othire
if ($db->hasColumn('accounts', 'premend')) {
// append premend
if (query_add_premium('premend', '`premend` + :value', '`premend` > :now', ['value' => $value, 'now' => $now])) {
if (Account::where('premend', '>', $now)->increment('premend', $value)) {
// set premend
if (query_add_premium('premend', ':value', '`premend` <= :now', ['value' => $now + $value, 'now' => $now])) {
if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {
@@ -114,11 +89,11 @@ function admin_give_premdays($days)
// tfs 0.x
if ($db->hasColumn('accounts', 'premdays')) {
// append premdays
if (query_add_premium('premdays', '`premdays` + :value', '1=1', ['value' => $days])) {
if (Account::query()->update(['premdays' => $days])) {
// append lastday
if (query_add_premium('lastday', '`lastday` + :value', '`lastday` > :now', ['value' => $value, 'now' => $now])) {
if (Account::where('lastday', '>', $now)->increment('lastday', $value)) {
// set lastday
if (query_add_premium('lastday', ':value', '`lastday` <= :now', ['value' => $now + $value, 'now' => $now])) {
if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {
@@ -142,9 +117,9 @@ function admin_give_premdays($days)
// tfs 1.x
if ($db->hasColumn('accounts', 'premium_ends_at')) {
// append premium_ends_at
if (query_add_premium('premium_ends_at', '`premium_ends_at` + :value', '`premium_ends_at` > :now', ['value' => $value, 'now' => $now])) {
if (Account::where('premium_ends_at', '>', $now)->increment('premium_ends_at', $value)) {
// set premium_ends_at
if (query_add_premium('premium_ends_at', ':value', '`premium_ends_at` <= :now', ['value' => $now + $value, 'now' => $now])) {
if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {

View File

@@ -51,22 +51,20 @@ else if (isset($_REQUEST['search'])) {
if (strlen($search_player) < 3 && !Validator::number($search_player)) {
echo_error('Player name is too short.');
} else {
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($search_player));
if ($query->rowCount() == 1) {
$query = $query->fetch();
$id = (int)$query['id'];
$query = Player::where('name', 'like', '%' . $search_player . '%')->orderBy('name')->limit(11)->get(['id', 'name']);
if (count($query) == 0) {
echo_error('No entries found.');
} else if (count($query) == 1) {
$id = $query->first()->getKey();
} else if (count($query) > 10) {
echo_error('Specified name resulted with too many players.');
} else {
$query = $db->query('SELECT `id`, `name` FROM `players` WHERE `name` LIKE ' . $db->quote('%' . $search_player . '%'));
if ($query->rowCount() > 0 && $query->rowCount() <= 10) {
$str_construct = 'Do you mean?<ul>';
foreach ($query as $row)
$str_construct .= '<li><a href="' . $player_base . '&id=' . $row['id'] . '">' . $row['name'] . '</a></li>';
$str_construct .= '</ul>';
echo_error($str_construct);
} else if ($query->rowCount() > 10)
echo_error('Specified name resulted with too many players.');
else
echo_error('No entries found.');
$str_construct = 'Do you mean?<ul>';
foreach ($query as $row) {
$str_construct .= '<li><a href="' . $player_base . '&id=' . $row->getKey() . '">' . $row->name . '</a></li>';
}
$str_construct .= '</ul>';
echo_error($str_construct);
}
}
}
@@ -202,7 +200,7 @@ else if (isset($_REQUEST['search'])) {
if ($hasBlessingsColumn) {
$blessings = $_POST['blessings'];
verify_number($blessings, 'Blessings', 2);
verify_number($blessings, 'Blessings', 3);
}
$balance = $_POST['balance'];
@@ -274,7 +272,7 @@ else if (isset($_REQUEST['search'])) {
$player->setLossContainers($loss_containers);
$player->setLossItems($loss_items);
}
if ($db->hasColumn('players', 'blessings'))
if ($hasBlessingsColumn)
$player->setBlessings($blessings);
if ($hasBlessingColumn) {
@@ -307,7 +305,7 @@ else if (isset($_REQUEST['search'])) {
}
}
} else if ($id == 0) {
$players_db = $db->query('SELECT `id`, `name`, `level` FROM `players` ORDER BY `id` asc');
$players_db = Player::orderBy('id')->get(['id','name', 'level']);
?>
<div class="col-12 col-sm-12 col-lg-10">
<div class="card card-info card-outline">
@@ -327,11 +325,11 @@ else if (isset($_REQUEST['search'])) {
<tbody>
<?php foreach ($players_db as $player_db): ?>
<tr>
<th><?php echo $player_db['id']; ?></th>
<td><?php echo $player_db['name']; ?></a></td>
<td><?php echo $player_db['level']; ?></a></td>
<th><?php echo $player_db->id; ?></th>
<td><?php echo $player_db->name; ?></a></td>
<td><?php echo $player_db->level; ?></a></td>
<td><a href="?p=players&id=<?php echo $player_db['id']; ?>" class="btn btn-success btn-sm" title="Edit">
<td><a href="?p=players&id=<?php echo $player_db->id; ?>" class="btn btn-success btn-sm" title="Edit">
<i class="fas fa-pencil-alt"></i>
</a>
</td>

View File

@@ -48,7 +48,7 @@ if (!is_array($settingsFile)) {
$settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']);
$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $plugin);
$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $settingsFile['name']);
$settingsParsed = Settings::display($settingsKeyName, $settingsFile['settings']);

View File

@@ -20,13 +20,13 @@
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @copyright 2024 MyAAC
* @link https://my-aac.org
*/
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true;
const MYAAC_VERSION = '1.0-beta';
const MYAAC_VERSION = '1.0-RC';
const DATABASE_VERSION = 40;
const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true));
@@ -156,7 +156,7 @@ if (file_exists(BASE . 'config.local.php')) {
/** @var array $config */
ini_set('log_errors', 1);
if(@$config['env'] === 'dev') {
if(@$config['env'] === 'dev' || defined('MYAAC_INSTALL')) {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

212
composer.lock generated
View File

@@ -137,16 +137,16 @@
},
{
"name": "composer/semver",
"version": "3.4.0",
"version": "3.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6",
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6",
"shasum": ""
},
"require": {
@@ -198,7 +198,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.4.0"
"source": "https://github.com/composer/semver/tree/3.4.2"
},
"funding": [
{
@@ -214,7 +214,7 @@
"type": "tidelift"
}
],
"time": "2023-08-31T09:50:34+00:00"
"time": "2024-07-12T11:35:52+00:00"
},
{
"name": "doctrine/inflector",
@@ -491,16 +491,16 @@
},
{
"name": "illuminate/collections",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
"reference": "f9589f1063a449111dcaa1d68285b507d9483a95"
"reference": "37c863cffb345869dd134eff8e646bc82a19cc96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/collections/zipball/f9589f1063a449111dcaa1d68285b507d9483a95",
"reference": "f9589f1063a449111dcaa1d68285b507d9483a95",
"url": "https://api.github.com/repos/illuminate/collections/zipball/37c863cffb345869dd134eff8e646bc82a19cc96",
"reference": "37c863cffb345869dd134eff8e646bc82a19cc96",
"shasum": ""
},
"require": {
@@ -542,11 +542,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2024-03-20T20:09:13+00:00"
"time": "2024-06-19T14:25:05+00:00"
},
{
"name": "illuminate/conditionable",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/conditionable.git",
@@ -592,7 +592,7 @@
},
{
"name": "illuminate/container",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
@@ -643,7 +643,7 @@
},
{
"name": "illuminate/contracts",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
@@ -691,16 +691,16 @@
},
{
"name": "illuminate/database",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/database.git",
"reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9"
"reference": "ec00738a49e9fb0db4fc19b5d70310e214b32bff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/database/zipball/eb8edf206d3a6eea8894bc6e21f53469e27dd5c9",
"reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9",
"url": "https://api.github.com/repos/illuminate/database/zipball/ec00738a49e9fb0db4fc19b5d70310e214b32bff",
"reference": "ec00738a49e9fb0db4fc19b5d70310e214b32bff",
"shasum": ""
},
"require": {
@@ -760,11 +760,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2024-04-29T13:23:17+00:00"
"time": "2024-07-03T21:35:00+00:00"
},
{
"name": "illuminate/macroable",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -810,16 +810,16 @@
},
{
"name": "illuminate/support",
"version": "v10.48.10",
"version": "v10.48.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582"
"reference": "263f389d81488c237846b69469f91387ca2729f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/ee3a1aaed36d916654ce0ae09dfbd38644a4f582",
"reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582",
"url": "https://api.github.com/repos/illuminate/support/zipball/263f389d81488c237846b69469f91387ca2729f3",
"reference": "263f389d81488c237846b69469f91387ca2729f3",
"shasum": ""
},
"require": {
@@ -877,20 +877,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2024-04-07T17:47:33+00:00"
"time": "2024-05-16T21:33:51+00:00"
},
{
"name": "matomo/device-detector",
"version": "6.3.1",
"version": "6.3.2",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "8096093346917ee2477d802ab3b00c4c091c5cee"
"reference": "fd4042cb6a7f3f985a81aedc075dd59e0b991a51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/8096093346917ee2477d802ab3b00c4c091c5cee",
"reference": "8096093346917ee2477d802ab3b00c4c091c5cee",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/fd4042cb6a7f3f985a81aedc075dd59e0b991a51",
"reference": "fd4042cb6a7f3f985a81aedc075dd59e0b991a51",
"shasum": ""
},
"require": {
@@ -946,7 +946,7 @@
"source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/"
},
"time": "2024-04-12T12:16:21+00:00"
"time": "2024-05-28T10:16:19+00:00"
},
{
"name": "maximebf/debugbar",
@@ -954,12 +954,12 @@
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "40d2d7e986082287b47bb6f675541ba43db09398"
"reference": "c9cb28d5ee6f657fcc48440f38db8bbd140bef83"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/40d2d7e986082287b47bb6f675541ba43db09398",
"reference": "40d2d7e986082287b47bb6f675541ba43db09398",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/c9cb28d5ee6f657fcc48440f38db8bbd140bef83",
"reference": "c9cb28d5ee6f657fcc48440f38db8bbd140bef83",
"shasum": ""
},
"require": {
@@ -1015,7 +1015,7 @@
"issues": "https://github.com/maximebf/php-debugbar/issues",
"source": "https://github.com/maximebf/php-debugbar/tree/master"
},
"time": "2024-04-15T10:55:03+00:00"
"time": "2024-07-02T07:24:16+00:00"
},
{
"name": "mustangostang/spyc",
@@ -1073,16 +1073,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.72.3",
"version": "2.72.5",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83"
"reference": "afd46589c216118ecd48ff2b95d77596af1e57ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83",
"reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed",
"reference": "afd46589c216118ecd48ff2b95d77596af1e57ed",
"shasum": ""
},
"require": {
@@ -1116,8 +1116,8 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-3.x": "3.x-dev",
"dev-master": "2.x-dev"
"dev-master": "3.x-dev",
"dev-2.x": "2.x-dev"
},
"laravel": {
"providers": [
@@ -1176,7 +1176,7 @@
"type": "tidelift"
}
],
"time": "2024-01-25T10:35:09+00:00"
"time": "2024-06-03T19:18:41+00:00"
},
{
"name": "nikic/fast-route",
@@ -1572,16 +1572,16 @@
},
{
"name": "symfony/console",
"version": "v6.4.7",
"version": "v6.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f"
"reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f",
"reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f",
"url": "https://api.github.com/repos/symfony/console/zipball/6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9",
"reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9",
"shasum": ""
},
"require": {
@@ -1646,7 +1646,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.4.7"
"source": "https://github.com/symfony/console/tree/v6.4.9"
},
"funding": [
{
@@ -1662,7 +1662,7 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-06-28T09:49:33+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1733,16 +1733,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
"shasum": ""
},
"require": {
@@ -1792,7 +1792,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
},
"funding": [
{
@@ -1808,20 +1808,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
"shasum": ""
},
"require": {
@@ -1870,7 +1870,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
},
"funding": [
{
@@ -1886,20 +1886,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
"shasum": ""
},
"require": {
@@ -1951,7 +1951,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
},
"funding": [
{
@@ -1967,20 +1967,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
"shasum": ""
},
"require": {
@@ -2031,7 +2031,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
},
"funding": [
{
@@ -2047,20 +2047,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-06-19T12:30:46+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
"reference": "10112722600777e02d2745716b70c5db4ca70442"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/10112722600777e02d2745716b70c5db4ca70442",
"reference": "10112722600777e02d2745716b70c5db4ca70442",
"shasum": ""
},
"require": {
@@ -2104,7 +2104,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.30.0"
},
"funding": [
{
@@ -2120,20 +2120,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-06-19T12:30:46+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
"shasum": ""
},
"require": {
@@ -2184,7 +2184,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
},
"funding": [
{
@@ -2200,7 +2200,7 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/service-contracts",
@@ -2287,16 +2287,16 @@
},
{
"name": "symfony/string",
"version": "v6.4.7",
"version": "v6.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69"
"reference": "76792dbd99690a5ebef8050d9206c60c59e681d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/ffeb9591c61f65a68d47f77d12b83fa530227a69",
"reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69",
"url": "https://api.github.com/repos/symfony/string/zipball/76792dbd99690a5ebef8050d9206c60c59e681d7",
"reference": "76792dbd99690a5ebef8050d9206c60c59e681d7",
"shasum": ""
},
"require": {
@@ -2353,7 +2353,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.7"
"source": "https://github.com/symfony/string/tree/v6.4.9"
},
"funding": [
{
@@ -2369,20 +2369,20 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-06-28T09:25:38+00:00"
},
{
"name": "symfony/translation",
"version": "v6.4.7",
"version": "v6.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "7495687c58bfd88b7883823747b0656d90679123"
"reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/7495687c58bfd88b7883823747b0656d90679123",
"reference": "7495687c58bfd88b7883823747b0656d90679123",
"url": "https://api.github.com/repos/symfony/translation/zipball/a002933b13989fc4bd0b58e04bf7eec5210e438a",
"reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a",
"shasum": ""
},
"require": {
@@ -2448,7 +2448,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v6.4.7"
"source": "https://github.com/symfony/translation/tree/v6.4.8"
},
"funding": [
{
@@ -2464,7 +2464,7 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-05-31T14:49:08+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -2546,16 +2546,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v6.4.7",
"version": "v6.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "7a9cd977cd1c5fed3694bee52990866432af07d7"
"reference": "c31566e4ca944271cc8d8ac6887cbf31b8c6a172"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/7a9cd977cd1c5fed3694bee52990866432af07d7",
"reference": "7a9cd977cd1c5fed3694bee52990866432af07d7",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/c31566e4ca944271cc8d8ac6887cbf31b8c6a172",
"reference": "c31566e4ca944271cc8d8ac6887cbf31b8c6a172",
"shasum": ""
},
"require": {
@@ -2611,7 +2611,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.4.7"
"source": "https://github.com/symfony/var-dumper/tree/v6.4.9"
},
"funding": [
{
@@ -2627,7 +2627,7 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-06-27T13:23:14+00:00"
},
{
"name": "twig/twig",
@@ -2845,16 +2845,16 @@
"packages-dev": [
{
"name": "phpstan/phpstan",
"version": "1.11.1",
"version": "1.11.7",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b"
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e524358f930e41a2b4cca1320e3b04fc26b39e0b",
"reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/52d2bbfdcae7f895915629e4694e9497d0f8e28d",
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d",
"shasum": ""
},
"require": {
@@ -2899,7 +2899,7 @@
"type": "github"
}
],
"time": "2024-05-15T08:00:59+00:00"
"time": "2024-07-06T11:17:41+00:00"
}
],
"aliases": [],

View File

@@ -22,7 +22,7 @@ describe('Create Account Page', () => {
cy.get('#vocation1').check()
cy.get('#accept_rules').check()
cy.get('#form').submit()
cy.get('#createaccount').submit()
// no errors please
cy.contains('The Following Errors Have Occurred:').should('not.exist')

View File

@@ -3,9 +3,9 @@
use Twig\Environment as Twig_Environment;
use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader;
require '../common.php';
const MYAAC_INSTALL = true;
define('MYAAC_INSTALL', true);
require '../common.php';
// includes
require SYSTEM . 'functions.php';
@@ -114,7 +114,7 @@ else if($step == 'finish') {
$email = $_SESSION['var_email'];
$password = $_SESSION['var_password'];
$password_confirm = $_SESSION['var_password_confirm'];
$player_name = $_SESSION['var_player_name'];
$player_name = $_SESSION['var_player_name'] ?? null;
// email check
if(empty($email)) {
@@ -159,12 +159,13 @@ else if($step == 'finish') {
$errors[] = $locale['step_admin_password_confirm_error_not_same'];
}
// player name check
if(empty($player_name)) {
$errors[] = $locale['step_admin_player_name_error_empty'];
}
else if(!Validator::characterName($player_name)) {
$errors[] = $locale['step_admin_player_name_error_format'];
if (isset($player_name)) {
// player name check
if (empty($player_name)) {
$errors[] = $locale['step_admin_player_name_error_empty'];
} else if (!Validator::characterName($player_name)) {
$errors[] = $locale['step_admin_player_name_error_format'];
}
}
if(!empty($errors)) {

View File

@@ -2,10 +2,15 @@
defined('MYAAC') or die('Direct access not allowed!');
// configuration
$dirs_required = [
$dirs_required_writable = [
'system/logs',
'system/cache',
];
$dirs_required = [
'tools/ext' => $locale['step_requirements_folder_not_exists_tools_ext'],
];
$dirs_optional = [
GUILD_IMAGES_DIR => $locale['step_requirements_warning_images_guilds'],
GALLERY_DIR => $locale['step_requirements_warning_images_gallery'],
@@ -18,6 +23,7 @@ $extensions_optional = [
'gd' => $locale['step_requirements_warning_player_signatures'],
'zip' => $locale['step_requirements_warning_install_plugins'],
];
/*
*
* @param string $name
@@ -41,7 +47,7 @@ $failed = false;
// start validating
version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50500), PHP_VERSION);
foreach ($dirs_required as $value)
foreach ($dirs_required_writable as $value)
{
$is_writable = is_writable(BASE . $value) && (MYAAC_OS != 'WINDOWS' || win_is_writable(BASE . $value));
version_check($locale['step_requirements_write_perms'] . ': ' . $value, $is_writable);
@@ -52,6 +58,12 @@ foreach ($dirs_optional as $dir => $errorMsg) {
version_check($locale['step_requirements_write_perms'] . ': ' . $dir, $is_writable, $is_writable ? '' : $errorMsg, true);
}
foreach ($dirs_required as $dir => $errorMsg)
{
$exists = is_dir(BASE . $dir);
version_check($locale['step_requirements_folder_exists'] . ': ' . $dir, $exists, $exists ? '' : $errorMsg);
}
$ini_register_globals = ini_get_bool('register_globals');
version_check('register_long_arrays', !$ini_register_globals, $ini_register_globals ? $locale['on'] : $locale['off']);
@@ -78,4 +90,3 @@ if($failed) {
}
echo '</div>';
?>

View File

@@ -41,57 +41,44 @@ if(!$error) {
$configToSave['cache_engine'] = 'auto';
$configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true);
require BASE . 'install/includes/config.php';
if(!$error) {
require BASE . 'install/includes/database.php';
$content = '';
$saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content);
if ($saved) {
success($locale['step_database_config_saved']);
$_SESSION['saved'] = true;
$locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']);
require BASE . 'config.local.php';
require BASE . 'install/includes/config.php';
if(isset($database_error)) { // we failed connect to the database
error($database_error);
}
else {
if(!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if (!$error) {
require BASE . 'install/includes/database.php';
if(!$db->hasTable('players')) {
$tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$db->hasTable('guilds')) {
$tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if(!$error) {
$twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner']
));
$content = '';
$saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content);
if($saved) {
success($locale['step_database_config_saved']);
$_SESSION['saved'] = true;
if (isset($database_error)) { // we failed connect to the database
error($database_error);
}
else {
$_SESSION['config_content'] = $content;
unset($_SESSION['saved']);
if (!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
if (!$error) {
$twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner']
));
}
}
}
} else {
$_SESSION['config_content'] = $content;
unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
}
}
}

View File

@@ -18,6 +18,7 @@ if(!$error) {
'locale' => $locale,
'session' => $_SESSION,
'account' => $account,
'hasTablePlayers' => $db->hasTable('players'),
'errors' => isset($errors) ? $errors : null,
'buttons' => next_buttons(true, $error ? false : true)
));

View File

@@ -1,5 +1,7 @@
<?php
use MyAAC\Cache\Cache;
use MyAAC\Models\News;
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!');
@@ -7,166 +9,199 @@ defined('MYAAC') or die('Direct access not allowed!');
ini_set('max_execution_time', 300);
if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['saved'])) {
warning($locale['already_installed']);
return;
}
$cache = Cache::getInstance();
if ($cache->enabled()) {
// clear plugin_hooks to have fresh hooks
$cache->delete('plugins_hooks');
}
require SYSTEM . 'init.php';
if($error) {
return;
}
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER)
$account = $_SESSION['var_account'] ?? null;
else
$account_id = $_SESSION['var_account_id'] ?? null;
$password = $_SESSION['var_password'];
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$password = $salt . $password;
}
$account_db = new OTS_Account();
if(isset($account))
$account_db->find($account);
else
$account_db->load($account_id);
if ($db->hasTable('players')) {
$player_name = $_SESSION['var_player_name'];
$player_db = new OTS_Player();
$player_db->find($player_name);
if(!$player_db->isLoaded())
{
$player = new OTS_Player();
$player->setName($player_name);
$player_used = &$player;
}
else {
$player_used = &$player_db;
}
$groups = new OTS_Groups_List();
$player_used->setGroupId($groups->getHighestId());
}
$email = $_SESSION['var_email'];
if($account_db->isLoaded()) {
$account_db->setPassword(encrypt($password));
$account_db->setEMail($email);
$account_db->save();
$account_used = &$account_db;
}
else {
require SYSTEM . 'init.php';
if(!$error) {
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER)
$account = isset($_SESSION['var_account']) ? $_SESSION['var_account'] : null;
else
$account_id = isset($_SESSION['var_account_id']) ? $_SESSION['var_account_id'] : null;
$new_account = new OTS_Account();
if(USE_ACCOUNT_NAME) {
$new_account->create($account);
}
else {
$new_account->create(null, $account_id);
}
$password = $_SESSION['var_password'];
$new_account->setPassword(encrypt($password));
$new_account->setEMail($email);
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$password = $salt . $password;
}
$new_account->save();
$account_db = new OTS_Account();
if(isset($account))
$account_db->find($account);
else
$account_db->load($account_id);
$new_account->setCustomField('created', time());
$new_account->logAction('Account created.');
$player_name = $_SESSION['var_player_name'];
$player_db = new OTS_Player();
$player_db->find($player_name);
$account_used = &$new_account;
}
if(!$player_db->isLoaded())
{
$player = new OTS_Player();
$player->setName($player_name);
if(USE_ACCOUNT_SALT)
$account_used->setCustomField('salt', $salt);
$player_used = &$player;
}
else {
$player_used = &$player_db;
}
$account_used->setCustomField('web_flags', FLAG_ADMIN + FLAG_SUPER_ADMIN);
$account_used->setCustomField('country', 'us');
$account_used->setCustomField('email_verified', 1);
$groups = new OTS_Groups_List();
$player_used->setGroupId($groups->getHighestId());
if($db->hasColumn('accounts', 'group_id'))
$account_used->setCustomField('group_id', $groups->getHighestId());
if($db->hasColumn('accounts', 'type'))
$account_used->setCustomField('type', 6);
$email = $_SESSION['var_email'];
if($account_db->isLoaded()) {
$account_db->setPassword(encrypt($password));
$account_db->setEMail($email);
$account_db->save();
$account_used = &$account_db;
}
else {
$new_account = new OTS_Account();
if(USE_ACCOUNT_NAME) {
$new_account->create($account);
}
else {
$new_account->create(null, $account_id);
}
$new_account->setPassword(encrypt($password));
$new_account->setEMail($email);
$new_account->save();
$new_account->setCustomField('created', time());
$new_account->logAction('Account created.');
$account_used = &$new_account;
}
if(USE_ACCOUNT_SALT)
$account_used->setCustomField('salt', $salt);
$account_used->setCustomField('web_flags', FLAG_ADMIN + FLAG_SUPER_ADMIN);
$account_used->setCustomField('country', 'us');
if($db->hasColumn('accounts', 'group_id'))
$account_used->setCustomField('group_id', $groups->getHighestId());
if($db->hasColumn('accounts', 'type'))
$account_used->setCustomField('type', 6);
if(!$player_db->isLoaded())
$player->setAccountId($account_used->getId());
else
$player_db->setAccountId($account_used->getId());
success($locale['step_database_created_account']);
setSession('account', $account_used->getId());
setSession('password', encrypt($password));
setSession('remember_me', true);
if($player_db->isLoaded()) {
$player_db->save();
}
else {
$player->save();
}
$player_id = 0;
$query = $db->query("SELECT `id` FROM `players` WHERE `name` = " . $db->quote($player_name) . ";");
if($query->rowCount() == 1) {
$query = $query->fetch();
$player_id = $query['id'];
}
$query = $db->query("SELECT `id` FROM `" . TABLE_PREFIX ."news` WHERE `title` LIKE 'Hello!';");
if($query->rowCount() == 0) {
if(query("INSERT INTO `" . TABLE_PREFIX ."news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hide`) VALUES (NULL, '1', UNIX_TIMESTAMP(), '2', 'Hello!', 'MyAAC is just READY to use!', " . $player_id . ", 'https://my-aac.org', '0');
INSERT INTO `myaac_news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hide`) VALUES (NULL, '2', UNIX_TIMESTAMP(), '4', 'Hello tickets!', 'https://my-aac.org', " . $player_id . ", '', '0');")) {
success($locale['step_database_created_news']);
}
}
$settings = Settings::getInstance();
foreach($_SESSION as $key => $value) {
if (in_array($key, ['var_usage', 'var_date_timezone', 'var_client'])) {
if ($key == 'var_usage') {
$key = 'anonymous_usage_statistics';
$value = ((int)$value == 1 ? 'true' : 'false');
} elseif ($key == 'var_date_timezone') {
$key = 'date_timezone';
} elseif ($key == 'var_client') {
$key = 'client';
}
$settings->updateInDatabase('core', $key, $value);
}
}
success('Settings saved.');
$twig->display('install.installer.html.twig', array(
'url' => 'tools/7-finish.php',
'message' => $locale['importing_spinner']
));
if(!isset($_SESSION['installed'])) {
if (!array_key_exists('CI', getenv())) {
$report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL);
if (function_exists('curl_version'))
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $report_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_exec($curl);
curl_close($curl);
}
else if (ini_get('allow_url_fopen') ) {
file_get_contents($report_url);
}
}
$_SESSION['installed'] = true;
}
foreach($_SESSION as $key => $value) {
if(strpos($key, 'var_') !== false)
unset($_SESSION[$key]);
}
unset($_SESSION['saved']);
if(file_exists(CACHE . 'install.txt')) {
unlink(CACHE . 'install.txt');
}
if ($db->hasTable('players')) {
if(!$player_db->isLoaded()) {
$player->setAccountId($account_used->getId());
$player->save();
}
else {
$player_db->setAccountId($account_used->getId());
$player_db->save();
}
}
success($locale['step_database_created_account']);
setSession('account', $account_used->getId());
setSession('password', encrypt($password));
setSession('remember_me', true);
if(!News::all()->count()) {
$player_id = 0;
if ($db->hasTable('players')) {
$tmpNewsPlayer = \MyAAC\Models\Player::where('name', $player_name)->first();
if($tmpNewsPlayer) {
$player_id = $tmpNewsPlayer->id;
}
}
News::create([
'type' => 1,
'date' => time(),
'category' => 2,
'title' => 'Hello!',
'body' => 'MyAAC is just READY to use!',
'player_id' => $player_id,
'comments' => 'https://my-aac.org',
'hide' => 0,
]);
News::create([
'type' => 2,
'date' => time(),
'category' => 4,
'title' => 'Hello tickers!',
'body' => 'https://my-aac.org',
'player_id' => $player_id,
'comments' => '',
'hide' => 0,
]);
success($locale['step_database_created_news']);
}
$settings = Settings::getInstance();
foreach($_SESSION as $key => $value) {
if (in_array($key, ['var_usage', 'var_date_timezone', 'var_client'])) {
if ($key == 'var_usage') {
$key = 'anonymous_usage_statistics';
$value = ((int)$value == 1 ? 'true' : 'false');
} elseif ($key == 'var_date_timezone') {
$key = 'date_timezone';
} elseif ($key == 'var_client') {
$key = 'client';
}
$settings->updateInDatabase('core', $key, $value);
}
}
success('Settings saved.');
$twig->display('install.installer.html.twig', array(
'url' => 'tools/7-finish.php',
'message' => $locale['importing_spinner']
));
if(!isset($_SESSION['installed'])) {
if (!array_key_exists('CI', getenv())) {
$report_url = 'https://my-aac.org/report_install.php?v=' . MYAAC_VERSION . '&b=' . urlencode(BASE_URL);
if (function_exists('curl_version'))
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $report_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_exec($curl);
curl_close($curl);
}
else if (ini_get('allow_url_fopen') ) {
file_get_contents($report_url);
}
}
$_SESSION['installed'] = true;
}
foreach($_SESSION as $key => $value) {
if(strpos($key, 'var_') !== false)
unset($_SESSION[$key]);
}
unset($_SESSION['saved']);
if(file_exists(CACHE . 'install.txt')) {
unlink(CACHE . 'install.txt');
}
$hooks->trigger(HOOK_INSTALL_FINISH_END);

View File

@@ -32,6 +32,9 @@ if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
else {
// import schema
try {
$locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']);
$db->query(file_get_contents(BASE . 'install/includes/schema.sql'));
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
@@ -138,73 +141,74 @@ if(!$db->hasColumn('accounts', 'premium_points')) {
success($locale['step_database_adding_field'] . ' accounts.premium_points...');
}
if($db->hasColumn('guilds', 'checkdata')) {
if(query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' guilds.checkdata...');
}
if(!$db->hasColumn('guilds', 'motd')) {
if(query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_adding_field'] . ' guilds.motd...');
}
else {
if(query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_modifying_field'] . ' guilds.motd...');
}
if(!$db->hasColumn('guilds', 'description')) {
if(query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' guilds.description...');
}
if($db->hasColumn('guilds', 'logo_gfx_name')) {
if(query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) {
$tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp);
success($tmp);
if ($db->hasTable('guilds')) {
if ($db->hasColumn('guilds', 'checkdata')) {
if (query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' guilds.checkdata...');
}
}
else if(!$db->hasColumn('guilds', 'logo_name')) {
if(query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';"))
success($locale['step_database_adding_field'] . ' guilds.logo_name...');
}
if(!$db->hasColumn('players', 'created')) {
if(query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.created...');
}
if (!$db->hasColumn('guilds', 'motd')) {
if (query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_adding_field'] . ' guilds.motd...');
} else {
if (query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';"))
success($locale['step_database_modifying_field'] . ' guilds.motd...');
}
if(!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) {
if(query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.deleted...');
}
if (!$db->hasColumn('guilds', 'description')) {
if (query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' guilds.description...');
}
if($db->hasColumn('players', 'hide_char')) {
if(!$db->hasColumn('players', 'hide')) {
if(query("ALTER TABLE `players` CHANGE `hide_char` `hide` TINYINT(1) NOT NULL DEFAULT 0;")) {
$tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'players.hide', $tmp);
if ($db->hasColumn('guilds', 'logo_gfx_name')) {
if (query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) {
$tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp);
success($tmp);
}
} else if (!$db->hasColumn('guilds', 'logo_name')) {
if (query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';"))
success($locale['step_database_adding_field'] . ' guilds.logo_name...');
}
}
else if(!$db->hasColumn('players', 'hide')) {
if(query("ALTER TABLE `players` ADD `hide` TINYINT(1) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.hide...');
}
if(!$db->hasColumn('players', 'comment')) {
if(query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' players.comment...');
}
if ($db->hasTable('players')) {
if (!$db->hasColumn('players', 'created')) {
if (query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.created...');
}
if($db->hasColumn('players', 'rank_id')) {
if(query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' players.rank_id...');
if (!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) {
if (query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.deleted...');
}
if($db->hasColumn('players', 'guildnick')) {
if(query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' players.guildnick...');
if ($db->hasColumn('players', 'hide_char')) {
if (!$db->hasColumn('players', 'hide')) {
if (query("ALTER TABLE `players` CHANGE `hide_char` `hide` TINYINT(1) NOT NULL DEFAULT 0;")) {
$tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']);
$tmp = str_replace('$FIELD_NEW$', 'players.hide', $tmp);
success($tmp);
}
}
} else if (!$db->hasColumn('players', 'hide')) {
if (query("ALTER TABLE `players` ADD `hide` TINYINT(1) NOT NULL DEFAULT 0;"))
success($locale['step_database_adding_field'] . ' players.hide...');
}
if (!$db->hasColumn('players', 'comment')) {
if (query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' players.comment...');
}
if ($db->hasColumn('players', 'rank_id')) {
if (query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;"))
success($locale['step_database_modifying_field'] . ' players.rank_id...');
if ($db->hasColumn('players', 'guildnick')) {
if (query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' players.guildnick...');
}
}
}
}

View File

@@ -25,30 +25,33 @@ if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['save
require SYSTEM . 'init.php';
$deleted = 'deleted';
if($db->hasColumn('players', 'deletion'))
$deleted = 'deletion';
if ($db->hasTable('players')) {
$deleted = 'deleted';
if ($db->hasColumn('players', 'deletion'))
$deleted = 'deletion';
$time = time();
function insert_sample_if_not_exist($p) {
global $db, $success, $deleted, $time;
$time = time();
function insert_sample_if_not_exist($p)
{
global $db, $success, $deleted, $time;
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name']));
if($query->rowCount() == 0) {
if(!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');"))
$success = false;
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name']));
if ($query->rowCount() == 0) {
if (!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');"))
$success = false;
}
}
}
$success = true;
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
$success = true;
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
if($success) {
success($locale['step_database_imported_players']);
if ($success) {
success($locale['step_database_imported_players']);
}
}
Plugins::installMenus('kathrine', require TEMPLATES . 'kathrine/menus.php');
@@ -77,6 +80,8 @@ if(ModelsFAQ::count() == 0) {
]);
}
$hooks->trigger(HOOK_INSTALL_FINISH);
$db->setClearCacheAfter(true);
$locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_replace('tools/', '',ADMIN_URL), $locale['step_finish_admin_panel'], true), $locale['step_finish_desc']);

View File

@@ -4,6 +4,7 @@ use MyAAC\Models\BoostedCreature;
use MyAAC\Models\PlayerOnline;
use MyAAC\Models\Account;
use MyAAC\Models\Player;
use MyAAC\RateLimit;
require_once 'common.php';
require_once SYSTEM . 'functions.php';
@@ -130,12 +131,29 @@ switch ($action) {
}
$account = $account->first();
$ip = get_browser_real_ip();
$limiter = new RateLimit('failed_logins', setting('core.account_login_attempts_limit'), setting('core.account_login_ban_time'));
$limiter->enabled = setting('core.account_login_ipban_protection');
$limiter->load();
$ban_msg = 'A wrong account, password or secret has been entered ' . setting('core.account_login_attempts_limit') . ' times in a row. You are unable to log into your account for the next ' . setting('core.account_login_ban_time') . ' minutes. Please wait.';
if (!$account) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
}
$current_password = encrypt((USE_ACCOUNT_SALT ? $account->salt : '') . $request->password);
if (!$account || $account->password != $current_password) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
}
@@ -145,16 +163,30 @@ switch ($action) {
if ($accountSecret != null && $accountSecret != '') {
$accountHasSecret = true;
if ($inputToken === false) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError('Submit a valid two-factor authentication token.', 6);
} else {
require_once LIBS . 'rfc6238.php';
if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) {
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
sendError($ban_msg);
}
sendError('Two-factor authentication failed, token is wrong.', 6);
}
}
}
}
$limiter->reset($ip);
if (setting('core.account_mail_verify') && $account->email_verified !== 1) {
sendError('You need to verify your account, enter in our site and resend verify e-mail!');
}
// common columns
$columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons';

View File

@@ -10,24 +10,20 @@ server {
# this is very important, be sure its in your nginx conf - it prevents access to logs etc.
location ~ /system {
deny all;
return 404;
}
location /vendor {
deny all;
return 404;
}
# block .htaccess, CHANGELOG.md, composer.json etc.
# this is to prevent finding software versions
location ~\.(ht|md|json|dist)$ {
deny all;
return 404;
}
# block git files and folders
location ~ /\.git {
return 404;
deny all;
}

View File

@@ -28,7 +28,8 @@ parameters:
- '#Variable \$guild might not be defined#'
- '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#'
# Eloquent models
- '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+()#'
- '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#'
- '#Call to an undefined method object::toArray\(\)#'
# system/pages/highscores.php
- '#Call to an undefined method Illuminate\\Database\\Query\\Builder::withOnlineStatus\(\)#'
- '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$online_status#'

View File

@@ -1,8 +1,6 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
$reward = setting('core.account_mail_confirmed_reward');
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
$rewardCoins = setting('core.account_mail_confirmed_reward_coins');
if ($rewardCoins > 0 && !$hasCoinsColumn) {

View File

@@ -25,7 +25,8 @@
"hooks": {
"Example Hook": {
"type": "BEFORE_PAGE",
"file": "plugins/example/before.php"
"file": "plugins/example/before.php",
"priority": 1000
}
},
"routes": {
@@ -33,12 +34,20 @@
"pattern": "/YourAwesomePage/{name:string}/{page:int}",
"file": "plugins/your-plugin/your-awesome-page.php",
"method": "GET",
"priority": "130"
"priority": 130
},
"Redirect Example": {
"redirect_from": "/redirectExample",
"redirect_to": "account/manage"
}
},
"settings": "plugins/your-plugin-folder/settings.php"
"routes-default-priority": 1000,
"pages-default-priority": 1000,
"settings": "plugins/your-plugin-folder/settings.php",
"autoload": {
"pages": true,
"pagesSubFolders": false,
"commands": true,
"themes": true
}
}

View File

@@ -105,4 +105,8 @@ $config['clients'] = [
1316,
1320,
1321,
1322,
1330,
1332,
1340,
];

View File

@@ -127,6 +127,7 @@ try {
}
if(defined('MYAAC_INSTALL')) {
$error = $e->getMessage();
return; // installer will take care of this
}

View File

@@ -1041,7 +1041,7 @@ function load_config_lua($filename)
return $result;
}
function str_replace_first($search, $replace, $subject) {
function str_replace_first($search,$replace, $subject) {
$pos = strpos($subject, $search);
if ($pos !== false) {
return substr_replace($subject, $replace, $pos, strlen($search));

View File

@@ -134,10 +134,6 @@ $ots = POT::getInstance();
$eloquentConnection = null;
require_once SYSTEM . 'database.php';
if ($config_lua_reload) {
clearCache();
}
// verify myaac tables exists in database
if(!defined('MYAAC_INSTALL') && !$db->hasTable('myaac_account_actions')) {
throw new RuntimeException('Seems that the table myaac_account_actions of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting ' . BASE_URL . 'install');
@@ -163,8 +159,8 @@ date_default_timezone_set(setting('core.date_timezone'));
setting(
[
'core.account_create_character_create',
setting('core.account_create_character_create') && (!setting('core.mail_enabled') || !setting('core.account_mail_verify'))
'core.account_mail_verify',
setting('core.account_mail_verify') && setting('core.mail_enabled')
]
);

View File

@@ -15,15 +15,15 @@
/**
* Basic data access object routines.
*
*
* <p>
* This class defines basic mechanisms for all classes that will represent database accessors. However no coding logic is defined here - only connection handling and PHP core-related stuff to enable variouse operations with objects.
* </p>
*
*
* <p>
* This class is mostly usefull when you create own extensions for POT code.
* </p>
*
*
* @package POT
* @version 0.1.0
*/
@@ -31,14 +31,14 @@ abstract class OTS_Base_DAO implements IOTS_DAO
{
/**
* Database connection.
*
*
* @var PDO
*/
protected $db;
/**
* Sets database connection handler.
*
*
* @version 0.1.0
*/
public function __construct()
@@ -48,11 +48,11 @@ abstract class OTS_Base_DAO implements IOTS_DAO
/**
* Magic PHP5 method.
*
*
* <p>
* Allows object serialisation.
* </p>
*
*
* @return array List of properties that should be saved.
*/
public function __sleep()
@@ -62,7 +62,7 @@ abstract class OTS_Base_DAO implements IOTS_DAO
/**
* Magic PHP5 method.
*
*
* <p>
* Allows object unserialisation.
* </p>
@@ -74,7 +74,7 @@ abstract class OTS_Base_DAO implements IOTS_DAO
/**
* Creates clone of object.
*
*
* <p>
* Copy of object needs to have different ID.
* </p>
@@ -83,38 +83,4 @@ abstract class OTS_Base_DAO implements IOTS_DAO
{
unset($this->data['id']);
}
/**
* Magic PHP5 method.
*
* <p>
* Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}.
* </p>
*
* @version 0.1.0
* @param array $properties List of object properties.
*/
public static function __set_state($properties)
{
// deletes database handle
if( isset($properties['db']) )
{
unset($properties['db']);
}
// initializes new object with current database connection
$object = new self();
// loads properties
foreach($properties as $name => $value)
{
$object->$name = $value;
}
return $object;
}
}
/**#@-*/
?>

View File

@@ -184,8 +184,14 @@ abstract class OTS_Base_DB extends PDO implements IOTS_DB
$query = 'UPDATE '.$this->tableName($table).' SET ';
$count = count($fields);
for ($i = 0; $i < $count; $i++)
$query.= $this->fieldName($fields[$i]).' = '.$this->quote($values[$i]).', ';
for ($i = 0; $i < $count; $i++) {
$value = 'NULL';
if ($values[$i] !== null) {
$value = $this->quote($values[$i]);
}
$query.= $this->fieldName($fields[$i]).' = '.$value.', ';
}
$query = substr($query, 0, -2);
$query.=' WHERE (';

View File

@@ -15,15 +15,15 @@
/**
* Binary buffer container.
*
*
* <p>
* This is generic class for classes that uses buffer-baser read-write operations (it can also emulate C-like pointers).
* <p>
*
*
* <p>
* Note that unlike <var>NetworkMessage</var> class from OTServ C++ source code, in this one reading and writing positions are separated so you can pararelly read and write it's content like for example using object of this class as stack.
* </p>
*
*
* @package POT
* @version 0.1.3
* @property string $buffer Properties binary string.
@@ -39,381 +39,391 @@ class OTS_Buffer
{
/**
* Node properties stream.
*
*
* @var string
*/
protected $buffer;
protected $buffer;
/**
* Properties stream pointer.
*
*
* @var int
*/
protected $pos;
protected $pos;
/**
* Initializes new buffered reader.
*
*
* @param string $buffer Buffer content.
*/
public function __construct($buffer = '')
{
$this->buffer = $buffer;
$this->pos = 0;
}
public function __construct($buffer = '')
{
$this->buffer = $buffer;
$this->pos = 0;
}
/**
* Magic PHP5 method.
*
*
* <p>
* Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}.
* </p>
*
*
* @param array $properties List of object properties.
*/
public static function __set_state($properties)
{
$object = new self();
public static function __set_state($properties)
{
$object = new self();
// loads properties
foreach($properties as $name => $value)
{
$object->$name = $value;
}
// loads properties
foreach($properties as $name => $value)
{
$object->$name = $value;
}
return $object;
}
return $object;
}
/**
* Returs properties stream.
*
*
* @return string Properties stream.
*/
public function getBuffer()
{
return $this->buffer;
}
public function getBuffer()
{
return $this->buffer;
}
/**
* Sets properties stream.
*
*
* @param string Properties stream.
*/
public function setBuffer($buffer)
{
$this->buffer = $buffer;
$this->pos = 0;
}
public function setBuffer($buffer)
{
$this->buffer = $buffer;
$this->pos = 0;
}
/**
* Checks if there is anything left in stream.
*
*
* @return bool False if pointer is at the end of stream.
*/
public function isValid()
{
return $this->pos < strlen($this->buffer);
}
public function isValid()
{
return $this->pos < strlen($this->buffer);
}
/**
* Checks stream end state.
*
*
* @param int $size Amount of bytes that are going to be read.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
protected function check($size = 1)
{
if( strlen($this->buffer) < $this->pos + $size)
{
throw new E_OTS_OutOfBuffer();
}
}
protected function check($size = 1)
{
if( strlen($this->buffer) < $this->pos + $size)
{
throw new E_OTS_OutOfBuffer();
}
}
/**
* Returns single byte.
*
*
* @return int Byte (char) value.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function getChar()
{
// checks buffer size
$this->check();
public function getChar()
{
// checks buffer size
$this->check();
$value = ord($this->buffer[$this->pos]);
$this->pos++;
return $value;
}
$value = ord($this->buffer[$this->pos]);
$this->pos++;
return $value;
}
/**
* Appends single byte to buffer.
*
*
* @param int $char Byte (char) value.
*/
public function putChar($char)
{
$this->buffer .= chr($char);
}
public function putChar($char)
{
$this->buffer .= chr($char);
}
/**
* Returns double byte.
*
*
* @return int Word (short) value.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function getShort()
{
// checks buffer size
$this->check(2);
public function getShort()
{
// checks buffer size
$this->check(2);
$value = unpack('v', substr($this->buffer, $this->pos, 2) );
$this->pos += 2;
return $value[1];
}
$value = unpack('v', substr($this->buffer, $this->pos, 2) );
$this->pos += 2;
return $value[1];
}
/**
* Appends double byte to buffer.
*
*
* @param int $short Word (short) value.
*/
public function putShort($short)
{
$this->buffer .= pack('v', $short);
}
public function putShort($short)
{
$this->buffer .= pack('v', $short);
}
/**
* Returns quater byte.
*
*
* @return int Double word (long) value.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function getLong()
{
// checks buffer size
$this->check(4);
public function getLong()
{
// checks buffer size
$this->check(4);
$value = unpack('V', substr($this->buffer, $this->pos, 4) );
$this->pos += 4;
return $value[1];
}
$value = unpack('V', substr($this->buffer, $this->pos, 4) );
$this->pos += 4;
return $value[1];
}
public function getLongLong()
{
// checks buffer size
$this->check(8);
$value = unpack('P', substr($this->buffer, $this->pos, 8) );
$this->pos += 8;
return $value[1];
}
/**
* Appends quater byte to buffer.
*
*
* @param int $long Double word (long) value.
*/
public function putLong($long)
{
$this->buffer .= pack('V', $long);
}
public function putLong($long)
{
$this->buffer .= pack('V', $long);
}
/**
* Returns string from buffer.
*
*
* <p>
* If length is not given then treats first short value from current buffer as string length.
* </p>
*
*
* @param int|bool $length String length.
* @return string First substring.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function getString($length = false)
{
// reads string length if not given
if($length === false)
{
$length = $this->getShort();
}
public function getString($length = false)
{
// reads string length if not given
if($length === false)
{
$length = $this->getShort();
}
// checks buffer size
$this->check($length);
// checks buffer size
$this->check($length);
// copies substring
$value = substr($this->buffer, $this->pos, $length);
$this->pos += $length;
return $value;
}
// copies substring
$value = substr($this->buffer, $this->pos, $length);
$this->pos += $length;
return $value;
}
/**
* Appends string to buffer.
*
*
* @param string $string Binary length.
* @param bool $dynamic Whether if string length is fixed or not (if it is dynamic then length will be inserted as short before string chunk).
*/
public function putString($string, $dynamic = true)
{
// appends string length if requires
if($dynamic)
{
$this->putShort( strlen($string) );
}
public function putString($string, $dynamic = true)
{
// appends string length if requires
if($dynamic)
{
$this->putShort( strlen($string) );
}
$this->buffer .= $string;
}
$this->buffer .= $string;
}
/**
* Empties buffer.
*/
public function reset()
{
$this->__construct();
}
public function reset()
{
$this->__construct();
}
/**
* Returns current read position.
*
*
* @return int Read position.
*/
public function getPos()
{
return $this->pos;
}
public function getPos()
{
return $this->pos;
}
/**
* Seeks current reading position.
*
*
* @param int $pos Read position.
*/
public function setPos($pos)
{
$this->pos = $pos;
}
public function setPos($pos)
{
$this->pos = $pos;
}
/**
* Returns buffer size.
*
*
* @return int Buffer length.
*/
public function getSize()
{
return strlen($this->buffer);
}
public function getSize()
{
return strlen($this->buffer);
}
/**
* Skips given amount of bytes.
*
*
* @param int $n Bytes to skip.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function skip($n)
{
$this->check($n);
$this->pos += $n;
}
public function skip($n)
{
$this->check($n);
$this->pos += $n;
}
/**
* Magic PHP5 method.
*
*
* @param string $name Property name.
* @return mixed Property value.
* @throws OutOfBoundsException For non-supported properties.
* @throws E_OTS_OutOfBuffer When there is read attemp after end of stream.
*/
public function __get($name)
{
switch($name)
{
// simple properties
case 'buffer':
return $this->buffer;
public function __get($name)
{
switch($name)
{
// simple properties
case 'buffer':
return $this->buffer;
// isValid() wrapper
case 'valid':
return $this->isValid();
// isValid() wrapper
case 'valid':
return $this->isValid();
// getChar() wrapper
case 'char':
return $this->getChar();
// getChar() wrapper
case 'char':
return $this->getChar();
// getShort() wrapper
case 'short':
return $this->getShort();
// getShort() wrapper
case 'short':
return $this->getShort();
// getLong() wrapper
case 'long':
return $this->getLong();
// getLong() wrapper
case 'long':
return $this->getLong();
// getString() wrapper
case 'string':
return $this->getString();
// getString() wrapper
case 'string':
return $this->getString();
// getPos() wrapper
case 'pos':
return $this->getPos();
// getPos() wrapper
case 'pos':
return $this->getPos();
// getSize() wrapper
case 'size':
return $this->getSize();
// getSize() wrapper
case 'size':
return $this->getSize();
default:
throw new OutOfBoundsException();
}
}
default:
throw new OutOfBoundsException();
}
}
/**
* Magic PHP5 method.
*
*
* @version 0.1.3
* @param string $name Property name.
* @param mixed $value Property value.
* @throws OutOfBoundsException For non-supported properties.
*/
public function __set($name, $value)
{
switch($name)
{
// buffer needs to be reset
case 'buffer':
$this->setBuffer($value);
break;
public function __set($name, $value)
{
switch($name)
{
// buffer needs to be reset
case 'buffer':
$this->setBuffer($value);
break;
// putChar() wrapper
case 'char':
$this->putChar($value);
break;
// putChar() wrapper
case 'char':
$this->putChar($value);
break;
// putShort() wrapper
case 'short':
$this->putShort($value);
break;
// putShort() wrapper
case 'short':
$this->putShort($value);
break;
// putLong() wrapper
case 'long':
$this->putLong($value);
break;
// putLong() wrapper
case 'long':
$this->putLong($value);
break;
// putString() wrapper
case 'string':
$this->putString($value);
break;
// putString() wrapper
case 'string':
$this->putString($value);
break;
// setPos() wrapper
case 'pos':
$this->setPos($value);
break;
// setPos() wrapper
case 'pos':
$this->setPos($value);
break;
default:
throw new OutOfBoundsException();
}
}
default:
throw new OutOfBoundsException();
}
}
/**
* Returns string representation of buffer object.
*
*
* @return string Object's buffer.
*/
public function __toString()
{
return $this->buffer;
}
public function __toString()
{
return $this->buffer;
}
/**
* Resets pointer of cloned object.
*/
public function __clone()
{
$this->pos = 0;
}
public function __clone()
{
$this->pos = 0;
}
}
/**#@-*/

View File

@@ -60,12 +60,7 @@ class OTS_House extends OTS_Row_DAO
private $tiles = array();
public function load($id) {
$this->data = $this->db->query('SELECT * FROM `houses` WHERE `id` = ' . $id )->fetch();
foreach($this->data as $key => $value) {
if(is_numeric($key)) {
unset($this->data[$key]);
}
}
$this->data = $this->db->query('SELECT * FROM `houses` WHERE `id` = ' . $id )->fetch(PDO::FETCH_ASSOC);
}
public function find($name)

View File

@@ -57,10 +57,10 @@ class OTS_Monster extends DOMDocument
* @return string Name.
* @throws DOMException On DOM operation error.
*/
public function getName()
{
return $this->documentElement->getAttribute('name');
}
public function getName()
{
return $this->documentElement->getAttribute('name');
}
/**
* Returns monster race.
@@ -68,10 +68,10 @@ class OTS_Monster extends DOMDocument
* @return string Race.
* @throws DOMException On DOM operation error.
*/
public function getRace()
{
return $this->documentElement->getAttribute('race');
}
public function getRace()
{
return $this->documentElement->getAttribute('race');
}
/**
* Returns amount of experience for killing this monster.
@@ -79,10 +79,10 @@ class OTS_Monster extends DOMDocument
* @return int Experience points.
* @throws DOMException On DOM operation error.
*/
public function getExperience()
{
return (int) $this->documentElement->getAttribute('experience');
}
public function getExperience()
{
return (int) $this->documentElement->getAttribute('experience');
}
/**
* Returns monster speed.
@@ -90,10 +90,10 @@ class OTS_Monster extends DOMDocument
* @return int Speed.
* @throws DOMException On DOM operation error.
*/
public function getSpeed()
{
return (int) $this->documentElement->getAttribute('speed');
}
public function getSpeed()
{
return (int) $this->documentElement->getAttribute('speed');
}
/**
* Returns amount of mana required to summon this monster.
@@ -101,18 +101,18 @@ class OTS_Monster extends DOMDocument
* @return int|bool Mana required (false if not possible).
* @throws DOMException On DOM operation error.
*/
public function getManaCost()
{
// check if it is possible to summon this monster
if( $this->documentElement->hasAttribute('manacost') )
{
return (int) $this->documentElement->getAttribute('manacost');
}
else
{
return false;
}
}
public function getManaCost()
{
// check if it is possible to summon this monster
if( $this->documentElement->hasAttribute('manacost') )
{
return (int) $this->documentElement->getAttribute('manacost');
}
else
{
return false;
}
}
/**
* Returns monster HP.
@@ -120,10 +120,10 @@ class OTS_Monster extends DOMDocument
* @return int Hit points.
* @throws DOMException On DOM operation error.
*/
public function getHealth()
{
return (int) $this->documentElement->getElementsByTagName('health')->item(0)->getAttribute('max');
}
public function getHealth()
{
return (int) $this->documentElement->getElementsByTagName('health')->item(0)->getAttribute('max');
}
/**
* Returns all monster flags (in format flagname => value).
@@ -131,20 +131,21 @@ class OTS_Monster extends DOMDocument
* @return array Flags.
* @throws DOMException On DOM operation error.
*/
public function getFlags()
{
$flags = array();
public function getFlags()
{
$flags = array();
// read all flags
foreach( $this->documentElement->getElementsByTagName('flags')->item(0)->getElementsByTagName('flag') as $flag)
{
$flag = $flag->attributes->item(0);
if ($this->documentElement->getElementsByTagName('flags')->item(0)) {
foreach( $this->documentElement->getElementsByTagName('flags')->item(0)->getElementsByTagName('flag') as $flag)
{
$flag = $flag->attributes->item(0);
$flags[$flag->nodeName] = (int) $flag->nodeValue;
}
$flags[$flag->nodeName] = (int) $flag->nodeValue;
}
}
return $flags;
}
return $flags;
}
/**
* Returns specified flag value.
@@ -153,21 +154,21 @@ class OTS_Monster extends DOMDocument
* @return int|bool Flag value (false if not set).
* @throws DOMException On DOM operation error.
*/
public function getFlag($flag)
{
// searches for flag
foreach( $this->documentElement->getElementsByTagName('flags')->item(0)->getElementsByTagName('flag') as $flag)
{
// found
if( $flag->hasAttribute($flag) )
{
return (int) $flag->getAttribute($flag);
}
}
public function getFlag($flag)
{
// searches for flag
foreach( $this->documentElement->getElementsByTagName('flags')->item(0)->getElementsByTagName('flag') as $flag)
{
// found
if( $flag->hasAttribute($flag) )
{
return (int) $flag->getAttribute($flag);
}
}
// not found
return false;
}
// not found
return false;
}
/**
* Returns voices that monster can sound.
@@ -175,64 +176,64 @@ class OTS_Monster extends DOMDocument
* @return array List of voices.
* @throws DOMException On DOM operation error.
*/
public function getVoices()
{
$voices = array();
public function getVoices()
{
$voices = array();
$element = $this->documentElement->getElementsByTagName('voices')->item(0);
$element = $this->documentElement->getElementsByTagName('voices')->item(0);
// checks if it has any voices
if( isset($element) )
{
// loads all voices
foreach( $element->getElementsByTagName('voice') as $voice)
{
$voices[] = $voice->getAttribute('sentence');
}
}
// checks if it has any voices
if( isset($element) )
{
// loads all voices
foreach( $element->getElementsByTagName('voice') as $voice)
{
$voices[] = $voice->getAttribute('sentence');
}
}
return $voices;
}
return $voices;
}
/**
* @return array List of item IDs.
*/
public function getLoot()
{
$loot = array();
public function getLoot()
{
$loot = array();
$element = $this->documentElement->getElementsByTagName('loot')->item(0);
$element = $this->documentElement->getElementsByTagName('loot')->item(0);
// checks if it has any loot
if( isset($element) )
{
// adds all items
foreach( $element->getElementsByTagName('item') as $item)
{
$chance = $item->getAttribute('chance');
if(empty($chance)) {
$chance = $item->getAttribute('chance1');
if(empty($chance)) {
$chance = 100000;
}
}
// checks if it has any loot
if( isset($element) )
{
// adds all items
foreach( $element->getElementsByTagName('item') as $item)
{
$chance = $item->getAttribute('chance');
if(empty($chance)) {
$chance = $item->getAttribute('chance1');
if(empty($chance)) {
$chance = 100000;
}
}
$count = $item->getAttribute('countmax');
if(empty($count)) {
$count = 1;
}
$count = $item->getAttribute('countmax');
if(empty($count)) {
$count = 1;
}
$id = $item->getAttribute('id');
if(empty($id)) {
$id = $item->getAttribute('name');
}
$id = $item->getAttribute('id');
if(empty($id)) {
$id = $item->getAttribute('name');
}
$loot[] = array('id' => $id, 'count' => $count, 'chance' => $chance);
}
}
$loot[] = array('id' => $id, 'count' => $count, 'chance' => $chance);
}
}
return $loot;
}
return $loot;
}
/**
* Returns all possible loot.
@@ -247,33 +248,33 @@ class OTS_Monster extends DOMDocument
* @throws E_OTS_NotLoaded When there is no items list available in global POT instance.
* @throws DOMException On DOM operation error.
*/
public function getItems()
{
$loot = array();
$keys = array();
$items = POT::getInstance()->getItemsList();
public function getItems()
{
$loot = array();
$keys = array();
$items = POT::getInstance()->getItemsList();
$element = $this->documentElement->getElementsByTagName('loot')->item(0);
$element = $this->documentElement->getElementsByTagName('loot')->item(0);
// checks if it has any loot
if( isset($element) )
{
// adds all items
foreach( $element->getElementsByTagName('item') as $item)
{
$id = $item->getAttribute('id');
// checks if it has any loot
if( isset($element) )
{
// adds all items
foreach( $element->getElementsByTagName('item') as $item)
{
$id = $item->getAttribute('id');
// avoid redundancy
if( !in_array($id, $keys) )
{
$keys[] = $id;
$loot[] = $items->getItemType($id);
}
}
}
// avoid redundancy
if( !in_array($id, $keys) )
{
$keys[] = $id;
$loot[] = $items->getItemType($id);
}
}
}
return $loot;
}
return $loot;
}
/**
* Returns look of the monster.
@@ -281,27 +282,27 @@ class OTS_Monster extends DOMDocument
* @return array Look with all the attributes of the look.
* @throws DOMException On DOM operation error.
*/
public function getLook()
{
$look = array();
public function getLook()
{
$look = array();
$element = $this->documentElement->getElementsByTagName('look')->item(0);
$element = $this->documentElement->getElementsByTagName('look')->item(0);
if (!$element) {
return $look;
}
if (!$element) {
return $look;
}
$look['type'] = $element->getAttribute('type');
$look['typeex'] = $element->getAttribute('typeex');
$look['head'] = $element->getAttribute('head');
$look['body'] = $element->getAttribute('body');
$look['legs'] = $element->getAttribute('legs');
$look['feet'] = $element->getAttribute('feet');
$look['addons'] = $element->getAttribute('addons');
$look['corpse'] = $element->getAttribute('corpse');
$look['type'] = $element->getAttribute('type');
$look['typeex'] = $element->getAttribute('typeex');
$look['head'] = $element->getAttribute('head');
$look['body'] = $element->getAttribute('body');
$look['legs'] = $element->getAttribute('legs');
$look['feet'] = $element->getAttribute('feet');
$look['addons'] = $element->getAttribute('addons');
$look['corpse'] = $element->getAttribute('corpse');
return $look;
}
return $look;
}
/**
* Returns all monster summons.
@@ -311,24 +312,24 @@ class OTS_Monster extends DOMDocument
*/
public function getSummons()
{
$summons = array();
{
$summons = array();
$element = $this->documentElement->getElementsByTagName('summons')->item(0);
$element = $this->documentElement->getElementsByTagName('summons')->item(0);
// checks if it has any Summons
if( isset($element) )
{
// adds all summons
foreach( $element->getElementsByTagName('summon') as $item)
{
$chance = $item->getAttribute('chance');
$id = $item->getAttribute('name');
$summons[] = array('name' => $id, 'chance' => $chance);
}
}
return $summons;
}
// checks if it has any Summons
if( isset($element) )
{
// adds all summons
foreach( $element->getElementsByTagName('summon') as $item)
{
$chance = $item->getAttribute('chance');
$id = $item->getAttribute('name');
$summons[] = array('name' => $id, 'chance' => $chance);
}
}
return $summons;
}
/**
* Returns all monster elements.
@@ -336,30 +337,30 @@ class OTS_Monster extends DOMDocument
* @return array elements.
* @throws DOMException On DOM operation error.
*/
public function getElements()
{
$elements = array();
public function getElements()
{
$elements = array();
$element = $this->documentElement->getElementsByTagName('elements')->item(0);
$element = $this->documentElement->getElementsByTagName('elements')->item(0);
// checks if it has any elements
if( isset($element) )
{
// read all elements
foreach( $element->getElementsByTagName('element') as $elementv)
{
$elementv = $elementv->attributes->item(0);
// checks if it has any elements
if( isset($element) )
{
// read all elements
foreach( $element->getElementsByTagName('element') as $elementv)
{
$elementv = $elementv->attributes->item(0);
// checks if element is set
if($elementv->nodeValue > 0)
{
// checks if element is set
if($elementv->nodeValue > 0)
{
$elements[] = array('name' => ucfirst(str_replace('Percent', '', $elementv->nodeName)), 'percent' => $elementv->nodeValue);
}
}
}
}
}
}
return $elements;
}
return $elements;
}
/**
* Checks if monster has given element.
@@ -368,26 +369,26 @@ class OTS_Monster extends DOMDocument
* @return bool element state.
* @throws DOMException On DOM operation error.
*/
public function hasElement($name)
{
$element = $this->documentElement->getElementsByTagName('elements')->item(0);
public function hasElement($name)
{
$element = $this->documentElement->getElementsByTagName('elements')->item(0);
// if doesn't have any elements obviously doesn't have this one too
if( isset($element) )
{
// read all elements
foreach( $element->getElementsByTagName('element') as $element)
{
// checks if this is what we are searching for
if( $element->hasAttribute($name) )
{
return $element->getAttribute($name) > 0;
}
}
}
// if doesn't have any elements obviously doesn't have this one too
if( isset($element) )
{
// read all elements
foreach( $element->getElementsByTagName('element') as $element)
{
// checks if this is what we are searching for
if( $element->hasAttribute($name) )
{
return $element->getAttribute($name) > 0;
}
}
}
return false;
}
return false;
}
/**
* Returns all monster immunities.
@@ -395,30 +396,30 @@ class OTS_Monster extends DOMDocument
* @return array Immunities.
* @throws DOMException On DOM operation error.
*/
public function getImmunities()
{
$immunities = array();
public function getImmunities()
{
$immunities = array();
$element = $this->documentElement->getElementsByTagName('immunities')->item(0);
$element = $this->documentElement->getElementsByTagName('immunities')->item(0);
// checks if it has any immunities
if( isset($element) )
{
// read all immunities
foreach( $element->getElementsByTagName('immunity') as $immunity)
{
$immunity = $immunity->attributes->item(0);
// checks if it has any immunities
if( isset($element) )
{
// read all immunities
foreach( $element->getElementsByTagName('immunity') as $immunity)
{
$immunity = $immunity->attributes->item(0);
// checks if immunity is set
if($immunity->nodeValue > 0)
{
$immunities[] = $immunity->nodeName;
}
}
}
// checks if immunity is set
if($immunity->nodeValue > 0)
{
$immunities[] = $immunity->nodeName;
}
}
}
return $immunities;
}
return $immunities;
}
/**
* Checks if monster has given immunity.
@@ -427,26 +428,26 @@ class OTS_Monster extends DOMDocument
* @return bool Immunity state.
* @throws DOMException On DOM operation error.
*/
public function hasImmunity($name)
{
$element = $this->documentElement->getElementsByTagName('immunities')->item(0);
public function hasImmunity($name)
{
$element = $this->documentElement->getElementsByTagName('immunities')->item(0);
// if doesn't have any immunities obviously doesn't have this one too
if( isset($element) )
{
// read all immunities
foreach( $element->getElementsByTagName('immunity') as $immunity)
{
// checks if this is what we are searching for
if( $immunity->hasAttribute($name) )
{
return $immunity->getAttribute($name) > 0;
}
}
}
// if doesn't have any immunities obviously doesn't have this one too
if( isset($element) )
{
// read all immunities
foreach( $element->getElementsByTagName('immunity') as $immunity)
{
// checks if this is what we are searching for
if( $immunity->hasAttribute($name) )
{
return $immunity->getAttribute($name) > 0;
}
}
}
return false;
}
return false;
}
/**
* Returns monster defense rate.
@@ -454,18 +455,18 @@ class OTS_Monster extends DOMDocument
* @return int Defense rate.
* @throws DOMException On DOM operation error.
*/
public function getDefense()
{
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
public function getDefense()
{
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
// checks if defenses element is set
if( isset($element) )
{
return (int) $element->getAttribute('defense');
}
// checks if defenses element is set
if( isset($element) )
{
return (int) $element->getAttribute('defense');
}
return 0;
}
return 0;
}
/**
* Returns monster armor.
@@ -473,18 +474,18 @@ class OTS_Monster extends DOMDocument
* @return int Armor rate.
* @throws DOMException On DOM operation error.
*/
public function getArmor()
{
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
public function getArmor()
{
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
// checks if defenses element is set
if( isset($element) )
{
return (int) $element->getAttribute('armor');
}
// checks if defenses element is set
if( isset($element) )
{
return (int) $element->getAttribute('armor');
}
return 0;
}
return 0;
}
/**
* Returns list of special defenses.
@@ -492,23 +493,23 @@ class OTS_Monster extends DOMDocument
* @return array List of defense effects.
* @throws DOMException On DOM operation error.
*/
public function getDefenses()
{
$defenses = array();
public function getDefenses()
{
$defenses = array();
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
$element = $this->documentElement->getElementsByTagName('defenses')->item(0);
// checks if it has any defenses
if( isset($element) )
{
foreach( $element->getElementsByTagName('defense') as $defense)
{
$defenses[] = $defense->getAttribute('name');
}
}
// checks if it has any defenses
if( isset($element) )
{
foreach( $element->getElementsByTagName('defense') as $defense)
{
$defenses[] = $defense->getAttribute('name');
}
}
return $defenses;
}
return $defenses;
}
/**
* Returns list of monster attacks.
@@ -516,23 +517,23 @@ class OTS_Monster extends DOMDocument
* @return array List of attafck effects.
* @throws DOMException On DOM operation error.
*/
public function getAttacks()
{
$attacks = array();
public function getAttacks()
{
$attacks = array();
$element = $this->documentElement->getElementsByTagName('attacks')->item(0);
$element = $this->documentElement->getElementsByTagName('attacks')->item(0);
// checks if it has any defenses
if( isset($element) )
{
foreach( $element->getElementsByTagName('attack') as $attack)
{
$attacks[] = $attack->getAttribute('name');
}
}
// checks if it has any defenses
if( isset($element) )
{
foreach( $element->getElementsByTagName('attack') as $attack)
{
$attacks[] = $attack->getAttribute('name');
}
}
return $attacks;
}
return $attacks;
}
/**
* Magic PHP5 method.
@@ -544,59 +545,59 @@ class OTS_Monster extends DOMDocument
* @throws OutOfBoundsException For non-supported properties.
* @throws DOMException On DOM operation error.
*/
public function __get($name)
{
switch($name)
{
case 'name':
return $this->getName();
public function __get($name)
{
switch($name)
{
case 'name':
return $this->getName();
case 'race':
return $this->getRace();
case 'race':
return $this->getRace();
case 'experience':
return $this->getExperience();
case 'experience':
return $this->getExperience();
case 'speed':
return $this->getSpeed();
case 'speed':
return $this->getSpeed();
case 'manaCost':
return $this->getManaCost();
case 'manaCost':
return $this->getManaCost();
case 'health':
return $this->getHealth();
case 'health':
return $this->getHealth();
case 'flags':
return $this->getFlags();
case 'flags':
return $this->getFlags();
case 'voices':
return $this->getVoices();
case 'voices':
return $this->getVoices();
case 'items':
return $this->getItems();
case 'items':
return $this->getItems();
case 'immunities':
return $this->getImmunities();
case 'immunities':
return $this->getImmunities();
case 'defense':
return $this->getDefense();
case 'defense':
return $this->getDefense();
case 'armor':
return $this->getArmor();
case 'armor':
return $this->getArmor();
case 'defenses':
return $this->getDefenses();
case 'defenses':
return $this->getDefenses();
case 'attacks':
return $this->getAttacks();
case 'attacks':
return $this->getAttacks();
case 'look':
return $this->getLook();
case 'look':
return $this->getLook();
default:
throw new OutOfBoundsException();
}
}
default:
throw new OutOfBoundsException();
}
}
/**
* Returns string representation of XML.
@@ -609,18 +610,18 @@ class OTS_Monster extends DOMDocument
* @since 0.1.0
* @return string String representation of object.
*/
public function __toString()
{
$ots = POT::getInstance();
public function __toString()
{
$ots = POT::getInstance();
// checks if display driver is loaded
if( $ots->isDataDisplayDriverLoaded() )
{
return $ots->getDataDisplayDriver()->displayMonster($this);
}
// checks if display driver is loaded
if( $ots->isDataDisplayDriverLoaded() )
{
return $ots->getDataDisplayDriver()->displayMonster($this);
}
return $this->saveXML();
}
return $this->saveXML();
}
}
/**#@-*/

View File

@@ -90,7 +90,7 @@ class OTS_Player extends OTS_Row_DAO
* @version 0.1.2
* @var array
*/
private $data = array('sex' => 0, 'vocation' => 0, 'experience' => 0, 'level' => 1, 'maglevel' => 0, 'health' => 100, 'healthmax' => 100, 'mana' => 100, 'manamax' => 100, 'manaspent' => 0, 'soul' => 0, 'lookbody' => 10, 'lookfeet' => 10, 'lookhead' => 10, 'looklegs' => 10, 'looktype' => 136, 'lookaddons' => 0, 'posx' => 0, 'posy' => 0, 'posz' => 0, 'cap' => 0, 'lastlogin' => 0, 'lastip' => 0, 'save' => true, 'skulltime' => 0, 'skull' => 0, 'balance' => 0, 'lastlogout' => 0, 'blessings' => 0, 'stamina' => 0, 'online' => 0, 'comment' => '', 'created' => 0, 'hide' => 0);
private $data = array('group_id' => 1, 'sex' => 0, 'vocation' => 0, 'experience' => 0, 'level' => 1, 'maglevel' => 0, 'health' => 100, 'healthmax' => 100, 'mana' => 100, 'manamax' => 100, 'manaspent' => 0, 'soul' => 0, 'lookbody' => 10, 'lookfeet' => 10, 'lookhead' => 10, 'looklegs' => 10, 'looktype' => 136, 'lookaddons' => 0, 'posx' => 0, 'posy' => 0, 'posz' => 0, 'cap' => 0, 'lastlogin' => 0, 'lastip' => 0, 'save' => true, 'skulltime' => 0, 'skull' => 0, 'balance' => 0, 'lastlogout' => 0, 'blessings' => 0, 'stamina' => 0, 'online' => 0, 'comment' => '', 'created' => 0, 'hide' => 0);
/**
* Player skills.

View File

@@ -36,6 +36,10 @@ $locale['step_requirements'] = 'Anforderungen';
$locale['step_requirements_title'] = 'Anforderungen überprüfen';
$locale['step_requirements_php_version'] = 'PHP Version';
$locale['step_requirements_write_perms'] = 'Schreibberechtigungen';
$locale['step_requirements_folder_exists'] = 'Ordner ist vorhanden';
$locale['step_requirements_folder_not_exists_tools_ext'] = 'NPM Package Manager wird verwendet für externe JavaScript/CSS Bibliotheken.'
. ' Es sollte via Command Line installiert werden: <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>'
. ' Nachdem das Tool installiert wurde, folgende Befehl sollte ausgeführt in dem Hauptordner des MyAACs: "npm install".';
$locale['step_requirements_failed'] = 'Die Installation wird deaktiviert, bis diese Anforderungen erfüllt sind.</b><br/>Für weitere Informationen siehe <b>README</b> Datei.';
$locale['step_requirements_extension'] = '$EXTENSION$ PHP Erweiterung';

View File

@@ -36,6 +36,10 @@ $locale['step_requirements'] = 'Requirements';
$locale['step_requirements_title'] = 'Requirements check';
$locale['step_requirements_php_version'] = 'PHP Version';
$locale['step_requirements_write_perms'] = 'Write permissions';
$locale['step_requirements_folder_exists'] = 'Directory exists';
$locale['step_requirements_folder_not_exists_tools_ext'] = 'NPM Package Manager is used for external JavaScript/CSS libraries.'
. ' You need to install it through Command Line: <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>'
. ' When you done with installing that tool, execute: "npm install" in the main MyAAC folder.';
$locale['step_requirements_failed'] = 'Installation will be disabled until these requirements will be passed.</b><br/>For more informations see <b>README</b> file.';
$locale['step_requirements_extension'] = '$EXTENSION$ PHP extension';
$locale['step_requirements_warning_images_guilds'] = 'Guild logo upload will not work';

View File

@@ -36,6 +36,10 @@ $locale['step_requirements'] = 'Wymagania';
$locale['step_requirements_title'] = 'Sprawdzanie wymagań';
$locale['step_requirements_php_version'] = 'Wersja PHP';
$locale['step_requirements_write_perms'] = 'Uprawnienia do zapisu';
$locale['step_requirements_folder_exists'] = 'Folder istnieje';
$locale['step_requirements_folder_not_exists_tools_ext'] = 'Manadżer Pakietów NPM jest używany do zewnętrznych bibliotek JavaScript/CSS.'
. ' Trzeba go zainstalować poprzez wiersz poleceń: <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>'
. ' Po instalacji narzędzia, wywołaj następujące polecenie w głownym katalogu MyAAC: "npm install".';
$locale['step_requirements_failed'] = 'Instalacja zostanie zablokowana dopóki te wymagania nie zostaną spełnione.</b><br/>Po więcej informacji zasięgnij do pliku <b>README</b>.';
$locale['step_requirements_extension'] = 'Rozszerzenie PHP - $EXTENSION$';
$locale['step_requirements_warning_images_guilds'] = 'Nie będzie możliwości uploadu obrazków gildii';

View File

@@ -2,6 +2,10 @@
use MyAAC\Settings;
if (!$db->hasTable('players')) {
return;
}
$query = $db->query("SELECT `id` FROM `players` WHERE (`name` = " . $db->quote("Rook Sample") . " OR `name` = " . $db->quote("Sorcerer Sample") . " OR `name` = " . $db->quote("Druid Sample") . " OR `name` = " . $db->quote("Paladin Sample") . " OR `name` = " . $db->quote("Knight Sample") . " OR `name` = " . $db->quote("Account Manager") . ") ORDER BY `id`;");
$highscores_ignored_ids = array();

View File

@@ -12,6 +12,8 @@ defined('MYAAC') or die('Direct access not allowed!');
if(!$logged)
{
$title = 'Login';
if(!empty($errors))
$twig->display('error_box.html.twig', array('errors' => $errors));
@@ -19,7 +21,8 @@ if(!$logged)
'redirect' => $_REQUEST['redirect'] ?? null,
'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number',
'account_login_by' => getAccountLoginByLabel(),
'error' => $errors[0] ?? null
'error' => $errors[0] ?? null,
'errors' => $errors ?? [],
));
return;

View File

@@ -57,14 +57,14 @@ if($email_new_time < 10) {
$twig->display('error_box.html.twig', array('errors' => $errors));
//show form
$twig->display('account.change_mail.html.twig', array(
$twig->display('account.change-email.html.twig', array(
'new_email' => isset($_POST['new_email']) ? $_POST['new_email'] : null
));
}
}
else
{
$twig->display('account.change_mail.html.twig', array(
$twig->display('account.change-email.html.twig', array(
'new_email' => isset($_POST['new_email']) ? $_POST['new_email'] : null
));
}

View File

@@ -76,7 +76,7 @@ if($show_form) {
$countries[$code] = $country;
}
$twig->display('account.change_info.html.twig', array(
$twig->display('account.change-info.html.twig', array(
'countries' => $countries ?? [],
'account_rlname' => $account_rlname,
'account_location' => $account_location,

View File

@@ -21,7 +21,7 @@ $new_password = $_POST['newpassword'] ?? NULL;
$new_password_confirm = $_POST['newpassword_confirm'] ?? NULL;
$old_password = $_POST['oldpassword'] ?? NULL;
if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) {
$twig->display('account.change_password.html.twig');
$twig->display('account.change-password.html.twig');
}
else
{
@@ -52,7 +52,7 @@ else
$twig->display('error_box.html.twig', array('errors' => $errors));
//show form
$twig->display('account.change_password.html.twig');
$twig->display('account.change-password.html.twig');
}
else {
$org_pass = $new_password;

View File

@@ -14,7 +14,7 @@ use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Change Comment';
require __DIR__ . '/base.php';
require PAGES . 'account/base.php';
if(!$logged) {
return;
@@ -68,7 +68,7 @@ if($show_form) {
}
if(isset($player) && $player) {
$twig->display('account.change_comment.html.twig', array(
$twig->display('account.characters.change-comment.html.twig', array(
'player' => $player->toArray()
));
}

View File

@@ -11,7 +11,7 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Change Name';
require __DIR__ . '/base.php';
require PAGES . 'account/base.php';
if(!$logged) {
return;
@@ -109,7 +109,7 @@ else
$twig->display('error_box.html.twig', array('errors' => $errors));
}
$twig->display('account.change_name.html.twig', array(
$twig->display('account.characters.change-name.html.twig', array(
'points' => $points,
'errors' => $errors
//'account_players' => $account_logged->getPlayersList()

View File

@@ -11,7 +11,7 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Change Sex';
require __DIR__ . '/base.php';
require PAGES . 'account/base.php';
if(!$logged) {
return;
@@ -88,7 +88,7 @@ else
if(!empty($errors)) {
$twig->display('error_box.html.twig', array('errors' => $errors));
}
$twig->display('account.change_sex.html.twig', array(
$twig->display('account.characters.change-sex.html.twig', array(
'players' => $account_logged->getPlayersList(false),
'player_sex' => isset($player) ? $player->getSex() : -1,
'points' => $points

View File

@@ -14,7 +14,7 @@ use MyAAC\CreateCharacter;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Create Character';
require __DIR__ . '/base.php';
require PAGES . 'account/base.php';
if(!$logged) {
return;
@@ -43,7 +43,7 @@ if(count($errors) > 0) {
}
if(!$character_created) {
$twig->display('account.create_character.html.twig', array(
$twig->display('account.characters.create.html.twig', array(
'name' => $character_name,
'sex' => $character_sex,
'vocation' => $character_vocation,

View File

@@ -11,7 +11,7 @@
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Delete Character';
require __DIR__ . '/base.php';
require PAGES . 'account/base.php';
if(!$logged) {
return;
@@ -93,5 +93,5 @@ if($show_form) {
$twig->display('error_box.html.twig', array('errors' => $errors));
}
$twig->display('account.delete_character.html.twig');
$twig->display('account.characters.delete.html.twig');
}

View File

@@ -25,16 +25,20 @@ if(!Account::where('email_hash', $hash)->exists()) {
}
else
{
if (Account::where('email_hash', $hash)->where('email_verified', 0)->exists()) {
$query = $query->fetch(PDO::FETCH_ASSOC);
$accountModel = Account::where('email_hash', $hash)->where('email_verified', 0)->first();
if ($accountModel) {
$accountModel->email_verified = 1;
$accountModel->save();
success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now <a href=' . getLink('account/manage') . '>log in</a>.');
$account = new OTS_Account();
$account->load($query['id']);
$account->load($accountModel->id);
if ($account->isLoaded()) {
$hooks->trigger(HOOK_EMAIL_CONFIRMED, ['account' => $account]);
}
}
Account::where('email_hash', $hash)->update('email_verified', 1);
success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this.');
else {
error('Link has expired.');
}
}
?>

View File

@@ -148,6 +148,10 @@ if($save)
}
}
/**
* two hooks for compatibility
*/
$hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SUBMIT, $params);
if (!$hooks->trigger(HOOK_ACCOUNT_CREATE_POST, $params)) {
return;
}
@@ -187,6 +191,8 @@ if($save)
$new_account->setEMail($email);
$new_account->save();
$hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SAVED, ['account' => $new_account]);
if(USE_ACCOUNT_SALT)
$new_account->setCustomField('salt', $salt);
@@ -227,7 +233,7 @@ if($save)
$hash = md5(generateRandomString(16, true, true) . $email);
$new_account->setCustomField('email_hash', $hash);
$verify_url = getLink('account/confirm_email/' . $hash);
$verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.verify.html.twig', array(
'account' => $tmp_account,
'verify_url' => generateLink($verify_url, $verify_url, true)
@@ -236,6 +242,9 @@ if($save)
if(_mail($email, 'New account on ' . $config['lua']['serverName'], $body_html))
{
echo 'Your account has been created.<br/><br/>';
warning("Before you can login - you need to verify your E-Mail. The verification link has been sent to $email. If the message is not coming - remember to check the SPAM folder.");
$twig->display('success.html.twig', array(
'title' => 'Account Created',
'description' => 'Your account ' . $account_type . ' is <b>' . $tmp_account . '</b><br/>You will need the account ' . $account_type . ' and your password to play on ' . configLua('serverName') . '.
@@ -252,15 +261,6 @@ if($save)
}
else
{
if(setting('core.account_create_character_create')) {
// character creation
$character_created = $createCharacter->doCreate($character_name, $character_sex, $character_vocation, $character_town, $new_account, $errors);
if (!$character_created) {
error('There was an error creating your character. Please create your character later in account management page.');
error(implode(' ', $errors));
}
}
if(setting('core.account_create_auto_login')) {
if ($hasBeenCreatedByEMail) {
$_POST['account_login'] = $email;
@@ -311,6 +311,15 @@ if($save)
}
}
if(setting('core.account_create_character_create')) {
// character creation
$character_created = $createCharacter->doCreate($character_name, $character_sex, $character_vocation, $character_town, $new_account, $errors);
if (!$character_created) {
error('There was an error creating your character. Please create your character later in account management page.');
error(implode(' ', $errors));
}
}
return;
}
}

View File

@@ -8,57 +8,46 @@
* @copyright 2023 MyAAC
* @link https://my-aac.org
*/
use MyAAC\RateLimit;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Login';
// new login with data from form
if(!$logged && isset($_POST['account_login'], $_POST['password_login']))
if($logged || !isset($_POST['account_login']) || !isset($_POST['password_login'])) {
return;
}
$login_account = $_POST['account_login'];
$login_password = $_POST['password_login'];
$remember_me = isset($_POST['remember_me']);
$ip = get_browser_real_ip();
if(!empty($login_account) && !empty($login_password))
{
$login_account = $_POST['account_login'];
$login_password = $_POST['password_login'];
$remember_me = isset($_POST['remember_me']);
if(!empty($login_account) && !empty($login_password))
$limiter = new RateLimit('failed_logins', setting('core.account_login_attempts_limit'), setting('core.account_login_ban_time'));
$limiter->enabled = setting('core.account_login_ipban_protection');
$limiter->load();
$account_logged = new OTS_Account();
if (config('account_login_by_email')) {
$account_logged->findByEMail($login_account);
}
if (!config('account_login_by_email') || config('account_login_by_email_fallback')) {
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER) {
$account_logged->find($login_account);
} else {
$account_logged->load($login_account, true);
}
}
if($account_logged->isLoaded() && encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword() && ($limiter->enabled && !$limiter->exceeded($ip))
)
{
if($cache->enabled())
{
$tmp = '';
if($cache->fetch('failed_logins', $tmp))
{
$tmp = unserialize($tmp);
$to_remove = array();
foreach($tmp as $ip => $t)
{
if(time() - $t['last'] >= 5 * 60)
$to_remove[] = $ip;
}
foreach($to_remove as $ip)
unset($tmp[$ip]);
}
else
$tmp = array();
$ip = $_SERVER['REMOTE_ADDR'];
$t = $tmp[$ip] ?? null;
}
$account_logged = new OTS_Account();
if (config('account_login_by_email')) {
$account_logged->findByEMail($login_account);
}
if (!config('account_login_by_email') || config('account_login_by_email_fallback')) {
if(USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER) {
$account_logged->find($login_account);
} else {
$account_logged->load($login_account, true);
}
}
if($account_logged->isLoaded() && encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword()
&& (!isset($t) || $t['attempts'] < 5)
)
{
if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) {
$errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.';
} else {
session_regenerate_id();
setSession('account', $account_logged->getId());
setSession('password', encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password));
@@ -82,44 +71,27 @@ if(!$logged && isset($_POST['account_login'], $_POST['password_login']))
$hooks->trigger(HOOK_LOGIN, array('account' => $account_logged, 'password' => $login_password, 'remember_me' => $remember_me));
}
else
{
$hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me));
$errorMessage = getAccountLoginByLabel() . ' or password is not correct.';
// temporary solution for blocking failed login attempts
if($cache->enabled())
{
if(isset($t))
{
$t['attempts']++;
$t['last'] = time();
if($t['attempts'] >= 5)
$errors[] = 'A wrong password has been entered 5 times in a row. You are unable to log into your account for the next 5 minutes. Please wait.';
else
$errors[] = $errorMessage;
}
else
{
$t = array('attempts' => 1, 'last' => time());
$errors[] = $errorMessage;
}
$tmp[$ip] = $t;
$cache->set('failed_logins', serialize($tmp), 60 * 60); // save for 1 hour
}
else {
$errors[] = $errorMessage;
}
}
$limiter->reset($ip);
}
else {
$errors[] = 'Please enter your ' . getAccountLoginByLabel() . ' and password.';
else
{
$hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me));
}
$hooks->trigger(HOOK_ACCOUNT_LOGIN_POST);
$errorMessage = getAccountLoginByLabel() . ' or password is not correct.';
$limiter->increment($ip);
if ($limiter->exceeded($ip)) {
$errorMessage = 'A wrong password has been entered ' . $limiter->max_attempts . ' times in a row. You are unable to log into your account for the next ' . $limiter->ttl . ' minutes. Please wait.';
}
$errors[] = $errorMessage;
}
}
else {
$errors[] = 'Please enter your ' . getAccountLoginByLabel() . ' and password.';
$hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me));
}
$hooks->trigger(HOOK_ACCOUNT_LOGIN_POST);

View File

@@ -17,532 +17,31 @@ if(!setting('core.mail_enabled'))
return;
}
$action_type = isset($_REQUEST['action_type']) ? $_REQUEST['action_type'] : '';
if($action == '')
{
$action_type = $_REQUEST['action_type'] ?? '';
if($action == '') {
$twig->display('account.lost.form.html.twig');
}
else if($action == 'step1' && $action_type == '') {
$twig->display('account.lost.noaction.html.twig');
}
elseif($action == 'step1' && $action_type == 'email')
{
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_next') < time())
echo 'Please enter e-mail to account with this character.<BR>
<form action="' . getLink('account/lost') . '?action=sendcode" method=post>
<input type=hidden name="character">
<table cellspacing=1 cellpadding=4 border=0 width=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter e-mail to account</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Character: <INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR>
E-mail to account:<INPUT TYPE=text NAME="email" VALUE="" SIZE="40"><BR>
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>'.$nick.'</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60).' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else
echo 'Player or account of player <b>' . $nick . '</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'step1' && $action_type == 'email') {
require PAGES . 'account/lost/step1-email.php';
}
elseif($action == 'sendcode')
{
$email = $_REQUEST['email'];
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_next') < time())
{
if($account->getEMail() == $email)
{
$newcode = generateRandomString(30, true, false, true);
$mailBody = '
You asked to reset your ' . $config['lua']['serverName'] . ' password.<br/>
<p>Account name: '.$account->getName().'</p>
<br />
To do so, please click this link:
<p><a href="' . getLink('account/lost') . '?action=checkcode&code='.$newcode.'&character='.urlencode($nick).'">' . getLink('account/lost') . '?action=checkcode&code='.$newcode.'&character='.urlencode($nick).'</a></p>
<p>or open page: <i>' . getLink('account/lost') . '?action=checkcode</i> and in field "code" write <b>'.$newcode.'</b></p>
<br/>
<p>If you did not request a password change, you may ignore this message and your password will remain unchanged.';
$account_mail = $account->getCustomField('email');
if(_mail($account_mail, $config['lua']['serverName'].' - Recover your account', $mailBody))
{
$account->setCustomField('email_code', $newcode);
$account->setCustomField('email_next', (time() + setting('core.mail_lost_account_interval')));
echo '<br />Details about steps required to recover your account has been sent to <b>' . $account_mail . '</b>. You should receive this email within 15 minutes. Please check your inbox/spam directory.';
}
else
{
$account->setCustomField('email_next', (time() + 60));
echo '<br /><p class="error">An error occurred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
}
else
echo 'Invalid e-mail to account of character <b>'.$nick.'</b>. Try again.';
}
else
{
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>'.$nick.'</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60).' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=email&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'send-code') {
require PAGES . 'account/lost/send-code.php';
}
elseif($action == 'step1' && $action_type == 'reckey')
{
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
echo 'If you enter right recovery key you will see form to set new e-mail and password to account. To this e-mail will be send your new password and account name.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=step2" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter your recovery key</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Character name:&nbsp;<INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR />
Recovery key:&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=text NAME="key" VALUE="" SIZE="40"><BR>
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'step1' && $action_type == 'reckey') {
require PAGES . 'account/lost/step1-reckey.php';
}
elseif($action == 'step2')
{
$rec_key = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
if($account_key == $rec_key)
{
echo '<script type="text/javascript">
function validate_required(field,alerttxt)
{
with (field)
{
if (value==null||value==""||value==" ")
{alert(alerttxt);return false;}
else {return true}
}
}
function validate_email(field,alerttxt)
{
with (field)
{
apos=value.indexOf("@");
dotpos=value.lastIndexOf(".");
if (apos<1||dotpos-apos<2)
{alert(alerttxt);return false;}
else {return true;}
}
}
function validate_form(thisform)
{
with (thisform)
{
if (validate_required(email,"Please enter your e-mail!")==false)
{email.focus();return false;}
if (validate_email(email,"Invalid e-mail format!")==false)
{email.focus();return false;}
if (validate_required(passor,"Please enter password!")==false)
{passor.focus();return false;}
if (validate_required(passor2,"Please repeat password!")==false)
{passor2.focus();return false;}
if (passor2.value!=passor.value)
{alert(\'Repeated password is not equal to password!\');return false;}
}
}
</script>';
echo 'Set new password and e-mail to your account.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=step3" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter new password and e-mail</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Account of character:&nbsp;&nbsp;<INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR />
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT id="passor" TYPE=password NAME="passor" VALUE="" SIZE="40"><BR>
Repeat new password:&nbsp;&nbsp;<INPUT id="passor2" TYPE=password NAME="passor" VALUE="" SIZE="40"><BR>
New e-mail address:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT id="email" TYPE=text NAME="email" VALUE="" SIZE="40"><BR>
<INPUT TYPE=hidden NAME="key" VALUE="'.$rec_key.'">
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo 'Wrong recovery key!';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=reckey&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'step2') {
require PAGES . 'account/lost/step2.php';
}
elseif($action == 'step3')
{
$rec_key = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
$new_pass = trim($_REQUEST['passor']);
$new_email = trim($_REQUEST['email']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
if($account_key == $rec_key)
{
if(Validator::password($new_pass))
{
if(Validator::email($new_email))
{
$account->setEMail($new_email);
$tmp_new_pass = $new_pass;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $new_pass;
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
if(USE_ACCOUNT_SALT)
$account->setCustomField('salt', $salt);
echo 'Your account name, new password and new e-mail.<BR>
<FORM ACTION="' . getLink('account/manage') . '" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Your account name, new password and new e-mail</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Account name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'.$account->getName().'</b><BR>
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'.$new_pass.'</b><BR>
New e-mail address:&nbsp;<b>'.$new_email.'</b><BR>';
if($account->getCustomField('email_next') < time())
{
$mailBody = '
<h3>Your account name and new password!</h3>
<p>Changed password and e-mail to your account in Lost Account Interface on server <a href="'.BASE_URL.'"><b>'.$config['lua']['serverName'].'</b></a></p>
<p>Account name: <b>'.$account->getName().'</b></p>
<p>New password: <b>'.$new_pass.'</b></p>
<p>E-mail: <b>'.$new_email.'</b> (this e-mail)</p>
<br />
<p><u>It\'s automatic e-mail from OTS Lost Account System. Do not reply!</u></p>';
if(_mail($account->getCustomField('email'), $config['lua']['serverName']." - New password to your account", $mailBody))
{
echo '<br /><small>Sent e-mail with your account name and password to new e-mail. You should receive this e-mail in 15 minutes. You can login now with new password!</small>';
}
else
{
echo '<br /><p class="error">An error occurred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
}
else
{
echo '<br /><small>You will not receive e-mail with this informations.</small>';
}
echo '<INPUT TYPE=hidden NAME="account_login" VALUE="'.$account->getId().'">
<INPUT TYPE=hidden NAME="password_login" VALUE="'.$new_pass.'">
</TD></TR></TABLE><BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<INPUT TYPE=image NAME="Login" ALT="Login" SRC="'.$template_path.'/images/global/buttons/sbutton_login.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo Validator::getLastError();
}
else
echo Validator::getLastError();
}
else
echo 'Wrong recovery key!';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=reckey&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'step3') {
require PAGES . 'account/lost/step3.php';
}
elseif($action == 'checkcode')
{
$code = trim($_REQUEST['code']);
$character = stripslashes(trim($_REQUEST['character']));
if(empty($code) || empty($character))
echo 'Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_code') == $code)
{
echo '<script type="text/javascript">
function validate_required(field,alerttxt)
{
with (field)
{
if (value==null||value==""||value==" ")
{alert(alerttxt);return false;}
else {return true}
}
}
function validate_form(thisform)
{
with (thisform)
{
if (validate_required(passor,"Please enter password!")==false)
{passor.focus();return false;}
if (validate_required(passor2,"Please repeat password!")==false)
{passor2.focus();return false;}
if (passor2.value!=passor.value)
{alert(\'Repeated password is not equal to password!\');return false;}
}
}
</script>
Please enter new password to your account and repeat to make sure you remember password.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=setnewpassword" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="'.$character.'">
<INPUT TYPE=hidden NAME="code" VALUE="'.$code.'">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & account name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=password ID="passor" NAME="passor" VALUE="" SIZE="40")><BR />
Repeat new password:&nbsp;<INPUT TYPE=password ID="passor2" NAME="passor2" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
$error= 'Wrong code to change password.';
}
else
$error = 'Account of this character or this character doesn\'t exist.';
}
if(!empty($error))
echo '<span style="color: red"><b>'.$error.'</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'check-code') {
require PAGES . 'account/lost/check-code.php';
}
elseif($action == 'setnewpassword')
{
$newpassword = $_REQUEST['passor'];
$code = $_REQUEST['code'];
$character = stripslashes($_REQUEST['character']);
echo '';
if(empty($code) || empty($character) || empty($newpassword))
echo '<span style="color: red"><b>Error. Try again.</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<BR><FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<INPUT TYPE=image NAME="Back" ALT="Back" SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_code') == $code)
{
if(Validator::password($newpassword))
{
$tmp_new_pass = $newpassword;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newpassword;
$account->setCustomField('salt', $salt);
}
$account->setPassword(encrypt($tmp_new_pass ));
$account->save();
$account->setCustomField('email_code', '');
echo 'New password to your account is below. Now you can login.<BR>
<INPUT TYPE=hidden NAME="character" VALUE="'.$character.'">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Changed password</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
New password:&nbsp;<b>'.$newpassword.'</b><BR />
Account name:&nbsp;&nbsp;&nbsp;<i>(Already on your e-mail)</i><BR />';
$mailBody = '
<h3>Your account name and password!</h3>
<p>Changed password to your account in Lost Account Interface on server <a href="'.BASE_URL.'"><b>'.$config['lua']['serverName'].'</b></a></p>
<p>Account name: <b>'.$account->getName().'</b></p>
<p>New password: <b>'.$newpassword.'</b></p>
<br />
<p><u>It\'s automatic e-mail from OTS Lost Account System. Do not reply!</u></p>';
if(_mail($account->getCustomField('email'), $config['lua']['serverName']." - Your new password", $mailBody))
{
echo '<br /><small>New password work! Sent e-mail with your password and account name. You should receive this e-mail in 15 minutes. You can login now with new password!';
}
else
{
echo '<br /><p class="error">New password work! An error occurred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log';
}
echo '</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<FORM ACTION="' . getLink('account/manage') . '" METHOD=post>
<INPUT TYPE=image NAME="Login" ALT="Login" SRC="'.$template_path.'/images/global/buttons/sbutton_login.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
$error= Validator::getLastError();
}
else
$error= 'Wrong code to change password.';
}
else
$error = 'Account of this character or this character doesn\'t exist.';
}
if(!empty($error))
echo '<span style="color: red"><b>'.$error.'</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
elseif($action == 'set-new-password') {
require PAGES . 'account/lost/set-new-password.php';
}

View File

@@ -0,0 +1,57 @@
<?php
$code = isset($_REQUEST['code']) ? trim($_REQUEST['code']) : '';
$character = isset($_REQUEST['character']) ? stripslashes(trim($_REQUEST['character'])) : '';
if(empty($code) || empty($character))
$twig->display('account.lost.check-code.html.twig', [
'code' => $code,
'characters' => $character,
]);
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
if($account->getCustomField('email_code') == $code) {
echo '
Please enter new password to your account and repeat to make sure you remember password.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=setnewpassword" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="'.$character.'">
<INPUT TYPE=hidden NAME="code" VALUE="'.$code.'">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Passwords</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=password ID="passor" NAME="passor" VALUE="" SIZE="40"><BR />
Repeat new password:&nbsp;<INPUT TYPE=password ID="passor2" NAME="passor2" VALUE="" SIZE="40"><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else {
$error = 'Wrong code to change password.';
}
}
else {
$error = "Account of this character or this character doesn't exist.";
}
}
if(!empty($error)) {
$twig->display('error_box.html.twig', [
'errors' => [$error],
]);
echo '<br/>';
$twig->display('account.lost.check-code.html.twig', [
]);
}

View File

@@ -0,0 +1,56 @@
<?php
$email = $_REQUEST['email'];
$nick = stripslashes($_REQUEST['nick']);
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
if($account->getCustomField('email_next') < time()) {
if($account->getEMail() == $email) {
$newCode = generateRandomString(30, true, false, true);
$mailBody = $twig->render('mail.account.lost.code.html.twig', [
'newCode' => $newCode,
'account' => $account,
'nick' => $nick,
]);
$accountEMail = $account->getCustomField('email');
if(_mail($accountEMail, configLua('serverName') . ' - Recover your account', $mailBody)) {
$account->setCustomField('email_code', $newCode);
$account->setCustomField('email_next', (time() + setting('core.mail_lost_account_interval')));
echo '<br />Details about steps required to recover your account has been sent to <b>' . $accountEMail . '</b>. You should receive this email within 15 minutes. Please check your inbox/spam directory.';
}
else {
$account->setCustomField('email_next', (time() + 60));
error('An error occurred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>');
}
}
else {
echo 'Invalid e-mail to account of character <b>' . htmlspecialchars($nick) . '</b>. Try again.';
}
}
else {
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>' . htmlspecialchars($nick) . '</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60) . ' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else {
echo "Player or account of player <b>" . htmlspecialchars($nick) . "</b> doesn't exist.";
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost') . '?action=step1&action_type=email&nick=' . urlencode($nick),
]);

View File

@@ -0,0 +1,81 @@
<?php
$newPassword = $_REQUEST['passor'];
$code = $_REQUEST['code'];
$character = stripslashes($_REQUEST['character']);
if(empty($code) || empty($character) || empty($newPassword)) {
echo '<span style="color: red"><b>Error. Try again.</b></span><br/>Please enter code from e-mail and name of one character from account. Then press Submit.<br>';
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost') . '?action=check-code',
]);
}
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded())
{
if($account->getCustomField('email_code') == $code)
{
if(Validator::password($newPassword))
{
$tmp_new_pass = $newPassword;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newPassword;
$account->setCustomField('salt', $salt);
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
$account->setCustomField('email_code', '');
$mailBody = $twig->render('mail.account.lost.new-password.html.twig', [
'account' => $account,
'newPassword' => $newPassword,
]);
$statusMsg = '';
if(_mail($account->getCustomField('email'), configLua('serverName') . ' - Your new password', $mailBody)) {
$statusMsg = '<br /><small>New password work! Sent e-mail with your password and account name. You should receive this e-mail in 15 minutes. You can login now with new password!';
}
else {
$statusMsg = '<br /><p class="error">New password work! An error occurred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log';
}
$twig->display('account.lost.finish.new-password.html.twig', [
'statusMsg' => $statusMsg,
'newPassword' => $newPassword,
]);
}
else
$error= Validator::getLastError();
}
else
$error= 'Wrong code to change password.';
}
else
$error = 'Account of this character or this character doesn\'t exist.';
}
if(!empty($error)) {
$twig->display('error_box.html.twig', [
'errors' => [$error],
]);
echo '<br/>';
$twig->display('account.lost.check-code.html.twig', [
'code' => $code,
'character' => $character,
]);
}

View File

@@ -0,0 +1,36 @@
<?php
$nick = stripslashes($_REQUEST['nick']);
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
if($account->getCustomField('email_next') < time()) {
$twig->display('account.lost.step1-email.html.twig', [
'nick' => $nick,
]);
}
else
{
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>'.$nick.'</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60).' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else {
echo "Player or account of player <b>" . htmlspecialchars($nick) . "</b> doesn't exist.";
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost'),
]);

View File

@@ -0,0 +1,39 @@
<?php
$nick = stripslashes($_REQUEST['nick']);
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
echo 'If you enter right recovery key you will see form to set new e-mail and password to account. To this e-mail will be send your new password and account name.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=step2" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter your recovery key</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Character name:&nbsp;<INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR />
Recovery key:&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=text NAME="key" VALUE="" SIZE="40"><BR>
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo 'Account of this character has no recovery key!';
}
else {
echo 'Player or account of player <b>' . htmlspecialchars($nick) . '</b> doesn\'t exist.';
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost'),
]);

View File

@@ -0,0 +1,37 @@
<?php
$recKey = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
$accountKey = $account->getCustomField('key');
if(!empty($accountKey)) {
if($accountKey == $recKey) {
$twig->display('account.lost.step2.html.twig', [
'nick' => $nick,
'recKey' => $recKey,
]);
}
else {
echo 'Wrong recovery key!';
}
}
else {
echo 'Account of this character has no recovery key!';
}
}
else
echo "Player or account of player <b>" . htmlspecialchars($nick) . "</b> doesn't exist.";
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost') . '?action=step1&action_type=reckey&nick=' . urlencode($nick),
]);

View File

@@ -0,0 +1,87 @@
<?php
$recKey = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
$newPassword = trim($_REQUEST['passor']);
$newEmail = trim($_REQUEST['email']);
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded())
{
$accountKey = $account->getCustomField('key');
if(!empty($accountKey)) {
if($accountKey == $recKey) {
if(Validator::password($newPassword)) {
if(Validator::email($newEmail)) {
$account->setEMail($newEmail);
$tmp_new_pass = $newPassword;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newPassword;
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
if(USE_ACCOUNT_SALT) {
$account->setCustomField('salt', $salt);
}
$statusMsg = '';
if($account->getCustomField('email_next') < time()) {
$mailBody = $twig->render('mail.account.lost.new-email.html.twig', [
'account' => $account,
'newPassword' => $newPassword,
'newEmail' => $newEmail,
]);
if(_mail($account->getCustomField('email'), $config['lua']['serverName']." - New password to your account", $mailBody)) {
$statusMsg = '<br /><small>Sent e-mail with your account name and password to new e-mail. You should receive this e-mail in 15 minutes. You can login now with new password!</small>';
}
else {
$statusMsg = '<br /><p class="error">An error occurred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
}
else {
$statusMsg = '<br /><small>You will not receive e-mail with this informations.</small>';
}
$twig->display('account.lost.finish.new-email.html.twig', [
'statusMsg' => $statusMsg,
'account' => $account,
'newPassword' => $newPassword,
'newEmail' => $newEmail,
]);
}
else {
echo Validator::getLastError();
}
}
else {
echo Validator::getLastError();
}
}
else {
echo 'Wrong recovery key!';
}
}
else {
echo 'Account of this character has no recovery key!';
}
}
else {
echo "Player or account of player <b>" . htmlspecialchars($nick) . "</b> doesn't exist.";
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost') . '?action=step1&action_type=reckey&nick=' . urlencode($nick),
]);

View File

@@ -52,7 +52,7 @@ if(empty($recovery_key))
else
{
if(setting('core.account_generate_new_reckey') && setting('core.mail_enabled'))
$account_registered = '<b><span style="color: green">Yes ( <a href="' . getLink('account/register/new') . '"> Buy new Recovery Key </a> )</span></b>';
$account_registered = '<b><span style="color: green">Yes ( <a href="' . getLink('account/register-new') . '"> Buy new Recovery Key </a> )</span></b>';
else
$account_registered = '<b><span style="color: green">Yes</span></b>';
}

View File

@@ -8,6 +8,9 @@
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
use MyAAC\Models\PlayerDeath;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Characters';
@@ -322,17 +325,36 @@ WHERE killers.death_id = '".$death['id']."' ORDER BY killers.final_hit DESC, kil
$frags = array();
$frag_add_content = '';
if($config['characters']['frags'] && $db->hasTable('killers')) {
//frags list by Xampy
$i = 0;
if ($config['characters']['frags']) {
$frags_limit = 10; // frags limit to show? // default: 10
$player_frags = $db->query('SELECT `player_deaths`.*, `players`.`name`, `killers`.`unjustified` FROM `player_deaths` LEFT JOIN `killers` ON `killers`.`death_id` = `player_deaths`.`id` LEFT JOIN `player_killers` ON `player_killers`.`kill_id` = `killers`.`id` LEFT JOIN `players` ON `players`.`id` = `player_deaths`.`player_id` WHERE `player_killers`.`player_id` = '.$player->getId().' ORDER BY `date` DESC LIMIT 0,'.$frags_limit.';')->fetchAll();
if(count($player_frags)) {
$row_count = 0;
foreach($player_frags as $frag)
{
$description = 'Fragged <a href="' . getPlayerLink($frag['name'], false) . '">' . $frag['name'] . '</a> at level ' . $frag['level'];
$frags[] = array('time' => $frag['date'], 'description' => $description, 'unjustified' => $frag['unjustified'] != 0);
if ($db->hasTable('killers')) {
//frags list by Xampy
$i = 0;
$player_frags = $db->query('SELECT `player_deaths`.*, `players`.`name`, `killers`.`unjustified` FROM `player_deaths` LEFT JOIN `killers` ON `killers`.`death_id` = `player_deaths`.`id` LEFT JOIN `player_killers` ON `player_killers`.`kill_id` = `killers`.`id` LEFT JOIN `players` ON `players`.`id` = `player_deaths`.`player_id` WHERE `player_killers`.`player_id` = ' . $player->getId() . ' ORDER BY `date` DESC LIMIT 0,' . $frags_limit . ';')->fetchAll();
if (count($player_frags)) {
$row_count = 0;
foreach ($player_frags as $frag) {
$description = 'Fragged <a href="' . getPlayerLink($frag['name'], false) . '">' . $frag['name'] . '</a> at level ' . $frag['level'];
$frags[] = array('time' => $frag['date'], 'description' => $description, 'unjustified' => $frag['unjustified'] != 0);
}
}
}
else if($db->hasTable('player_deaths') && $db->hasColumn('player_deaths', 'killed_by')) {
$i = 0;
$player_frags = PlayerDeath::where('player_deaths.killed_by', $player->getName())
->join('players', 'players.id', '=', 'player_deaths.player_id')
->limit($frags_limit)
->selectRaw('players.name, player_deaths.*')
->orderBy('player_deaths.time', 'DESC')
->get();
if ($player_frags->count()) {
$row_count = 0;
foreach ($player_frags as $frag) {
$description = 'Fragged <a href="' . getPlayerLink($frag->name, false) . '">' . $frag->name . '</a> at level ' . $frag->level;
$frags[] = array('time' => $frag->time, 'description' => $description, 'unjustified' => $frag->unjustified != 0);
}
}
}
}

View File

@@ -40,7 +40,7 @@ if(count($players_list) > 0)
if(!$rank_guild->isLoaded())
{
$player->setRank();
$player->setGuildNick();
$player->setGuildNick('');
$changed_ranks_of[] = $player->getName();
$deleted_ranks[] = 'ID: '.$player_rank->getId().' - '.$player_rank->getName();
$player_rank->delete();

View File

@@ -10,6 +10,8 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Models\GuildRank;
require __DIR__ . '/base.php';
$guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : NULL;
@@ -113,7 +115,25 @@ if(isset($todo) && $todo == 'save')
$new_guild->setOwner($player);
$new_guild->save();
$new_guild->setCustomField('description', setting('core.guild_description_default'));
//$new_guild->setCustomField('creationdata', time());
if ($db->hasTable('guild_ranks')) {
if (!GuildRank::where('guild_id', $new_guild->getId())->first()) {
$ranks = [
['level' => 3, 'name' => 'the Leader'],
['level' => 2, 'name' => 'a Vice-Leader'],
['level' => 1, 'name' => 'a Member'],
];
foreach ($ranks as $rank) {
GuildRank::create([
'guild_id' => $new_guild->getId(),
'name' => $rank['name'],
'level' => $rank['level'],
]);
}
}
}
$ranks = $new_guild->getGuildRanksList();
$ranks->orderBy('level', POT::ORDER_DESC);
foreach($ranks as $rank) {
@@ -124,14 +144,11 @@ if(isset($todo) && $todo == 'save')
$player->setRank($rank);
}
}
$twig->display('guilds.create.success.html.twig', array(
'guild_name' => $guild_name,
'leader_name' => $player->getName()
));
/*$db->exec('INSERT INTO `guild_ranks` (`id`, `guild_id`, `name`, `level`) VALUES (null, '.$new_guild->getId().', "the Leader", 3)');
$db->exec('INSERT INTO `guild_ranks` (`id`, `guild_id`, `name`, `level`) VALUES (null, '.$new_guild->getId().', "a Vice-Leader", 2)');
$db->exec('INSERT INTO `guild_ranks` (`id`, `guild_id`, `name`, `level`) VALUES (null, '.$new_guild->getId().', "a Member", 1)');*/
}
else {
sort($array_of_player_nig);

View File

@@ -142,9 +142,7 @@ if($logged && count($invited_list) > 0)
}
}
$useGuildNick = false;
if($db->hasColumn('players', 'guildnick'))
$useGuildNick = true;
$useGuildNick = $db->hasTable('guild_members') || $db->hasTable('guild_membership') || $db->hasColumn('players', 'guildnick');
$twig->display('guilds.view.html.twig', array(
'logo' => $guild_logo,
@@ -160,7 +158,6 @@ $twig->display('guilds.view.html.twig', array(
'level_in_guild' => $level_in_guild,
'isLeader' => $guild_leader,
'isVice' => $guild_vice,
'logged' => $logged,
'invited_list' => $invited_list,
'show_accept_invite' => $show_accept_invite,
'useGuildNick' => $useGuildNick

View File

@@ -180,9 +180,9 @@ if (empty($highscores)) {
} else if ($skill == SKILL_FRAGS) // frags
{
if ($db->hasTable('player_killers')) {
$query->addSelect(['value' => PlayerKillers::where('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]);
$query->addSelect(['value' => PlayerKillers::whereColumn('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]);
} else {
$query->addSelect(['value' => PlayerDeath::unjustified()->where('player_deaths.killed_by', 'players.name')->selectRaw('COUNT(*)')]);
$query->addSelect(['value' => PlayerDeath::unjustified()->whereColumn('player_deaths.killed_by', 'players.name')->selectRaw('COUNT(*)')]);
}
} else if ($skill == SKILL_BALANCE) // balance
{

View File

@@ -39,9 +39,12 @@ if (empty($_REQUEST['name'])) {
// display monster
$monster_name = urldecode(stripslashes(ucwords(strtolower($_REQUEST['name']))));
$monster = Monster::where('hide', '!=', 1)->where('name', $monster_name)->first()->toArray();
$monsterModel = Monster::where('hide', '!=', 1)->where('name', $monster_name)->first();
if ($monsterModel && isset($monsterModel->name)) {
/** @var array $monster */
$monster = $monsterModel->toArray();
if (isset($monster['name'])) {
function sort_by_chance($a, $b)
{
if ($a['chance'] == $b['chance']) {

View File

@@ -91,35 +91,67 @@ if($logged && $account_logged && $account_logged->isLoaded()) {
$dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) {
$routes = require SYSTEM . 'routes.php';
$isAlreadyDefined = [];
$routesTmp = [];
$routesFinal = [];
foreach(getDatabasePages() as $page) {
$isAlreadyDefined[$page] = true;
$routesTmp[] = ['*', $page, '__database__/' . $page, true];
$routesFinal[] = ['*', $page, '__database__/' . $page, 100];
}
Plugins::clearWarnings();
foreach (Plugins::getRoutes() as $route) {
if(!isset($isAlreadyDefined[$route[1]])) {
$isAlreadyDefined[$route[1]] = true;
$routesTmp[] = [$route[0], $route[1], $route[2]];
}
$routesFinal[] = [$route[0], $route[1], $route[2], $route[3] ?? 1000];
/*
echo '<pre>';
var_dump($route[1], $route[3], $route[2]);
echo '/<pre>';
*/
}
foreach ($routes as $route) {
if(!isset($isAlreadyDefined[$route[1]])) {
if (strpos($route[2], '__redirect__') === false && strpos($route[2], '__database__') === false) {
$routesTmp[] = [$route[0], $route[1], 'system/pages/' . $route[2]];
}
else {
$routesTmp[] = [$route[0], $route[1], $route[2]];
}
if (!str_contains($route[2], '__redirect__') && !str_contains($route[2], '__database__')) {
$routesFinal[] = [$route[0], $route[1], 'system/pages/' . $route[2], $route[3] ?? 10000];
}
else {
$routesFinal[] = [$route[0], $route[1], $route[2], $route[3] ?? 10000];
}
}
//var_dump($routesTmp);
foreach ($routesTmp as $route) {
// sort required for the next step (filter)
usort($routesFinal, function ($a, $b)
{
// key 3 is priority
if ($a[3] == $b[3]) {
return 0;
}
return ($a[3] < $b[3]) ? -1 : 1;
});
// remove duplicates
// if same route pattern, but different priority
$routesFinal = array_filter($routesFinal, function ($a) {
$aliases = [
[':int', ':string', ':alphanum'],
[':\d+', ':[A-Za-z0-9-_%+\' ]+', ':[A-Za-z0-9]+'],
];
// apply aliases
$a[1] = str_replace($aliases[0], $aliases[1], $a[1]);
static $duplicates = [];
if (isset($duplicates[$a[1]])) {
return false;
}
$duplicates[$a[1]] = true;
return true;
});
/*
echo '<pre>';
var_dump($routesFinal);
echo '</pre>';
die;
*/
foreach ($routesFinal as $route) {
if ($route[0] === '*') {
$route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'];
}

View File

@@ -11,50 +11,56 @@ defined('MYAAC') or die('Direct access not allowed!');
return [
['GET', '', 'news.php'], // empty URL = show news
['GET', 'news/archive/{id:int}[/]', 'news/archive.php'],
['GET', 'news/{id:int}[/]', 'news/archive.php'],
['GET', 'news/archive/{id:int}', 'news/archive.php'],
['GET', 'news/{id:int}', 'news/archive.php'],
// block access to some files
['*', 'account/base[/]', '404.php'], // this is to block account/base.php
['*', 'forum/base[/]', '404.php'],
['*', 'guilds/base[/]', '404.php'],
['*', 'account/base', '404.php', 10], // this is to block account/base.php
['*', 'forum/base', '404.php', 10],
['*', 'guilds/base', '404.php', 10],
[['GET', 'POST'], 'account/password[/]', 'account/change_password.php'],
[['GET', 'POST'], 'account/register/new[/]', 'account/register_new.php'],
[['GET', 'POST'], 'account/email[/]', 'account/change_email.php'],
[['GET', 'POST'], 'account/info[/]', 'account/change_info.php'],
[['GET', 'POST'], 'account/character/create[/]', 'account/create_character.php'],
[['GET', 'POST'], 'account/character/name[/]', 'account/change_name.php'],
[['GET', 'POST'], 'account/character/sex[/]', 'account/change_sex.php'],
[['GET', 'POST'], 'account/character/delete[/]', 'account/delete_character.php'],
[['GET', 'POST'], 'account/character/comment[/{name:[A-Za-z0-9-_%+\']+}]', 'account/change_comment.php'],
['GET', 'account/confirm_email/{hash:alphanum}[/]', 'account/confirm_email.php'],
['GET', 'account/confirm-email/{hash:alphanum}', 'account/confirm-email.php'],
['GET', 'bans/{page:int}[/]', 'bans.php'],
['GET', 'bans/{page:int}', 'bans.php'],
[['GET', 'POST'], 'characters[/{name:string}]', 'characters.php'],
['GET', 'changelog[/{page:int}]', 'changelog.php'],
[['GET', 'POST'], 'monsters[/{name:string}]', 'monsters.php'],
[['GET', 'POST'], 'faq[/{action:string}]', 'faq.php'],
[['GET', 'POST'], 'forum/{action:string}[/]', 'forum.php'],
['GET', 'forum/board/{id:int}[/]', 'forum/show_board.php'],
['GET', 'forum/board/{id:int}/{page:[0-9]+}[/]', 'forum/show_board.php'],
['GET', 'forum/thread/{id:int}[/]', 'forum/show_thread.php'],
['GET', 'forum/thread/{id:int}/{page:int}[/]', 'forum/show_thread.php'],
[['GET', 'POST'], 'forum/{action:string}', 'forum.php'],
['GET', 'forum/board/{id:int}', 'forum/show_board.php'],
['GET', 'forum/board/{id:int}/{page:[0-9]+}', 'forum/show_board.php'],
['GET', 'forum/thread/{id:int}', 'forum/show_thread.php'],
['GET', 'forum/thread/{id:int}/{page:int}', 'forum/show_thread.php'],
['GET', 'gallery/{image:int}[/]', 'gallery.php'],
[['GET', 'POST'], 'gallery/{action:string}[/]', 'gallery.php'],
['GET', 'gallery/{image:int}', 'gallery.php'],
[['GET', 'POST'], 'gallery/{action:string}', 'gallery.php'],
[['GET', 'POST'], 'guilds/{guild:string}[/]', 'guilds/show.php'],
[['GET', 'POST'], 'guilds/{guild:string}', 'guilds/show.php'],
['GET', 'highscores/{list:alphanum}/{vocation:alphanum}/{page:int}[/]', 'highscores.php'],
['GET', 'highscores/{list:alphanum}/{page:int}[/]', 'highscores.php'],
['GET', 'highscores/{list:alphanum}/{vocation:alphanum}[/]', 'highscores.php'],
['GET', 'highscores/{list:alphanum}[/]', 'highscores.php'],
['GET', 'highscores/{list:alphanum}/{vocation:alphanum}/{page:int}', 'highscores.php'],
['GET', 'highscores/{list:alphanum}/{page:int}', 'highscores.php'],
['GET', 'highscores/{list:alphanum}/{vocation:alphanum}', 'highscores.php'],
['GET', 'highscores/{list:alphanum}', 'highscores.php'],
/*
'/^gifts\/history\/?$/' => array('subtopic' => 'gifts', 'action' => 'show_history'),
'/^polls\/[0-9]+\/?$/' => array('subtopic' => 'polls', 'id' => '$1'),
'/^spells\/[A-Za-z0-9-_%]+\/[A-Za-z0-9-_]+\/?$/' => array('subtopic' => 'spells', 'vocation' => '$1', 'order' => '$2'),
'/^houses\/view\/?$/' => array('subtopic' => 'houses', 'page' => 'view')*/
/**
* Deprecated
* To be removed in next versions
* Kept just for compatibility
*/
[['GET', 'POST'], 'account/password', 'account/change-password.php'],
[['GET', 'POST'], 'account/register/new', 'account/register-new.php'],
[['GET', 'POST'], 'account/email', 'account/change-email.php'],
[['GET', 'POST'], 'account/info', 'account/change-info.php'],
[['GET', 'POST'], 'account/character/create', 'account/characters/create.php'],
[['GET', 'POST'], 'account/character/name', 'account/characters/change-name.php'],
[['GET', 'POST'], 'account/character/sex', 'account/characters/change-sex.php'],
[['GET', 'POST'], 'account/character/delete', 'account/characters/delete.php'],
[['GET', 'POST'], 'account/character/comment[/{name:string}]', 'account/characters/change-comment.php'],
['GET', 'account/confirm_email/{hash:alphanum}', 'account/confirm-email.php'],
];

View File

@@ -15,8 +15,7 @@ use MyAAC\Settings;
return [
'name' => 'MyAAC',
'settings' =>
[
'settings' => [
[
'type' => 'category',
'title' => 'General'
@@ -735,7 +734,7 @@ Sent by MyAAC,<br/>
'name' => 'Name Min Length',
'type' => 'number',
'desc' => '',
'default' => 4,
'default' => 3,
],
'create_character_name_max_length' => [
'name' => 'Name Max Length',
@@ -1374,7 +1373,7 @@ Sent by MyAAC,<br/>
'name' => 'Item Images URL',
'type' => 'text',
'desc' => 'Set to <strong>images/items</strong> if you host your own items in images folder',
'default' => 'http://item-images.ots.me/1092/',
'default' => 'https://item-images.ots.me/1092/',
],
'item_images_extension' => [
'name' => 'Item Images File Extension',
@@ -1390,7 +1389,7 @@ Sent by MyAAC,<br/>
'name' => 'Outfit Images URL',
'type' => 'text',
'desc' => 'Set to animoutfit.php for animated outfit',
'default' => 'http://outfit-images.ots.me/outfit.php',
'default' => 'https://outfit-images.ots.me/outfit.php',
],
'outfit_images_wrong_looktypes' => [
'name' => 'Outfit Images Wrong Looktypes',
@@ -1590,6 +1589,34 @@ Sent by MyAAC,<br/>
'account_change_character_sex', '=', 'true',
],
],
[
'type' => 'category',
'title' => 'Security',
],
[
'type' => 'section',
'title' => 'IP Ban Protection',
],
'account_login_ipban_protection' => [
'name' => 'IP Ban Protection',
'type' => 'boolean',
'desc' => 'Activate IP ban protection after exceeding incorrect login attempts',
'default' => true,
],
'account_login_attempts_limit' => [
'name' => 'Login Attempts Limit',
'type' => 'number',
'desc' => 'Number of incorrect login attempts before banning the IP',
'default' => 5, // Ajuste conforme necessário
],
'account_login_ban_time' => [
'name' => 'Ban Time (Minutes)',
'type' => 'number',
'desc' => 'Time in minutes the IP will be banned after exceeding login attempts',
'default' => 30, // Ajuste conforme necessário
],
],
'callbacks' => [
'beforeSave' => function(&$settings, &$values) {
@@ -1658,6 +1685,6 @@ Sent by MyAAC,<br/>
return $success;
},
],
]
];

View File

@@ -149,9 +149,9 @@ class CreateCharacter
if(empty($errors))
{
$char_to_copy_name = config('character_samples')[$vocation];
$char_to_copy = new \OTS_Player();
$char_to_copy->find($char_to_copy_name);
if(!$char_to_copy->isLoaded())
$playerSample = new \OTS_Player();
$playerSample->find($char_to_copy_name);
if(!$playerSample->isLoaded())
$errors[] = 'Wrong characters configuration. Try again or contact with admin. ADMIN: Go to Admin Panel -> Settings -> Create Character and set valid characters to copy names. Character to copy: <b>'.$char_to_copy_name.'</b> doesn\'t exist.';
}
@@ -162,72 +162,72 @@ class CreateCharacter
global $db;
if($sex == "0")
$char_to_copy->setLookType(136);
$playerSample->setLookType(136);
$player = new \OTS_Player();
$player->setName($name);
$player->setAccount($account);
$player->setGroupId(1);
$player->setSex($sex);
$player->setVocation($char_to_copy->getVocation());
$player->setVocation($playerSample->getVocation());
if($db->hasColumn('players', 'promotion'))
$player->setPromotion($char_to_copy->getPromotion());
$player->setPromotion($playerSample->getPromotion());
if($db->hasColumn('players', 'direction'))
$player->setDirection($char_to_copy->getDirection());
$player->setDirection($playerSample->getDirection());
$player->setConditions($char_to_copy->getConditions());
$rank = $char_to_copy->getRank();
$player->setConditions($playerSample->getConditions());
$rank = $playerSample->getRank();
if($rank->isLoaded()) {
$player->setRank($char_to_copy->getRank());
$player->setRank($playerSample->getRank());
}
if($db->hasColumn('players', 'lookaddons'))
$player->setLookAddons($char_to_copy->getLookAddons());
$player->setLookAddons($playerSample->getLookAddons());
$player->setTownId($town);
$player->setExperience($char_to_copy->getExperience());
$player->setLevel($char_to_copy->getLevel());
$player->setMagLevel($char_to_copy->getMagLevel());
$player->setHealth($char_to_copy->getHealth());
$player->setHealthMax($char_to_copy->getHealthMax());
$player->setMana($char_to_copy->getMana());
$player->setManaMax($char_to_copy->getManaMax());
$player->setManaSpent($char_to_copy->getManaSpent());
$player->setSoul($char_to_copy->getSoul());
$player->setExperience($playerSample->getExperience());
$player->setLevel($playerSample->getLevel());
$player->setMagLevel($playerSample->getMagLevel());
$player->setHealth($playerSample->getHealth());
$player->setHealthMax($playerSample->getHealthMax());
$player->setMana($playerSample->getMana());
$player->setManaMax($playerSample->getManaMax());
$player->setManaSpent($playerSample->getManaSpent());
$player->setSoul($playerSample->getSoul());
for($skill = \POT::SKILL_FIRST; $skill <= \POT::SKILL_LAST; $skill++) {
$value = 10;
if (setting('core.use_character_sample_skills')) {
$value = $char_to_copy->getSkill($skill);
$value = $playerSample->getSkill($skill);
}
$player->setSkill($skill, $value);
}
$player->setLookBody($char_to_copy->getLookBody());
$player->setLookFeet($char_to_copy->getLookFeet());
$player->setLookHead($char_to_copy->getLookHead());
$player->setLookLegs($char_to_copy->getLookLegs());
$player->setLookType($char_to_copy->getLookType());
$player->setCap($char_to_copy->getCap());
$player->setLookBody($playerSample->getLookBody());
$player->setLookFeet($playerSample->getLookFeet());
$player->setLookHead($playerSample->getLookHead());
$player->setLookLegs($playerSample->getLookLegs());
$player->setLookType($playerSample->getLookType());
$player->setCap($playerSample->getCap());
$player->setBalance(0);
$player->setPosX(0);
$player->setPosY(0);
$player->setPosZ(0);
if($db->hasColumn('players', 'stamina')) {
$player->setStamina($char_to_copy->getStamina());
$player->setStamina($playerSample->getStamina());
}
if($db->hasColumn('players', 'loss_experience')) {
$player->setLossExperience($char_to_copy->getLossExperience());
$player->setLossMana($char_to_copy->getLossMana());
$player->setLossSkills($char_to_copy->getLossSkills());
$player->setLossExperience($playerSample->getLossExperience());
$player->setLossMana($playerSample->getLossMana());
$player->setLossSkills($playerSample->getLossSkills());
}
if($db->hasColumn('players', 'loss_items')) {
$player->setLossItems($char_to_copy->getLossItems());
$player->setLossContainers($char_to_copy->getLossContainers());
$player->setLossItems($playerSample->getLossItems());
$player->setLossContainers($playerSample->getLossContainers());
}
$player->save();
@@ -245,7 +245,7 @@ class CreateCharacter
for($skill = \POT::SKILL_FIRST; $skill <= \POT::SKILL_LAST; $skill++) {
$value = 10;
if (setting('core.use_character_sample_skills')) {
$value = $char_to_copy->getSkill($skill);
$value = $playerSample->getSkill($skill);
}
$skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $skill);
if($skillExists->rowCount() <= 0) {
@@ -255,7 +255,7 @@ class CreateCharacter
}
if ($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) {
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId()."");
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$playerSample->getId()."");
foreach($loaded_items_to_copy as $save_item) {
$blob = $db->quote($save_item['attributes']);
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);");
@@ -267,6 +267,7 @@ class CreateCharacter
[
'account' => $account,
'player' => $player,
'playerSample' => $playerSample,
'name' => $name,
'sex' => $sex,
'vocation' => $vocation,

View File

@@ -9,6 +9,8 @@ class GuildRank extends Model {
public $timestamps = false;
protected $fillable = ['guild_id', 'name', 'level'];
public function guild()
{
return $this->belongsTo(Guild::class);

View File

@@ -5,7 +5,7 @@ use Illuminate\Database\Eloquent\Model;
class PlayerKillers extends Model {
protected $table = 'players_killers';
protected $table = 'player_killers';
public $timestamps = false;

View File

@@ -23,37 +23,15 @@ class Plugins {
$routes = [];
foreach(self::getAllPluginsJson() as $plugin) {
//
// Get all plugins/*/pages/*.php pages
//
$pluginPages = glob(PLUGINS . $plugin['filename'] . '/pages/*.php');
foreach ($pluginPages as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, 1000];
}
//
// Get all plugins/*/pages/subFolder/*.php pages
//
$pluginPagesSubFolders = glob(PLUGINS . $plugin['filename'] . '/pages/*', GLOB_ONLYDIR);
foreach ($pluginPagesSubFolders as $folder) {
$folderName = pathinfo($folder, PATHINFO_FILENAME);
$subFiles = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/*.php');
foreach ($subFiles as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = $folderName . '/' . pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, 1000];
}
$routesDefaultPriority = 1000;
if (isset($plugin['routes-default-priority'])) {
$routesDefaultPriority = $plugin['routes-default-priority'];
}
$warningPreTitle = 'Plugin: ' . $plugin['name'] . ' - ';
if (isset($plugin['routes'])) {
foreach ($plugin['routes'] as $_name => $info) {
foreach ($plugin['routes'] as $info) {
// default method: get
$method = $info['method'] ?? ['GET'];
if ($method !== '*') {
@@ -70,7 +48,7 @@ class Plugins {
}
if (!isset($info['priority'])) {
$info['priority'] = 100; // default priority
$info['priority'] = $routesDefaultPriority; // default priority taken from plugin.json
}
if (isset($info['redirect_from'])) {
@@ -89,39 +67,75 @@ class Plugins {
// replace first occurrence of / in pattern if found (will be auto-added later)
removeIfFirstSlash($info['pattern']);
foreach ($routes as $id => &$route) {
if($route[1] == $info['pattern']) {
if($info['priority'] < $route[3]) {
self::$warnings[] = $warningPreTitle . "Duplicated route with lower priority: {$info['pattern']}. Disabling this route...";
continue 2;
}
else {
self::$warnings[] = $warningPreTitle . "Duplicated route with lower priority: {$route[1]} ({$route[3]}). Disabling this route...";
unset($routes[$id]);
}
}
}
$routes[] = [$methods, $info['pattern'], $info['file'], $info['priority']];
}
}
}
/*
usort($routes, function ($a, $b)
{
// key 3 is priority
if ($a[3] == $b[3]) {
return 0;
$pagesDefaultPriority = 1000;
if (isset($plugin['pages-default-priority'])) {
$pagesDefaultPriority = $plugin['pages-default-priority'];
}
if (self::getAutoLoadOption($plugin, 'pages', true)) {
//
// Get all plugins/*/pages/*.php pages
//
$pluginPages = glob(PLUGINS . $plugin['filename'] . '/pages/*.php');
foreach ($pluginPages as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, $pagesDefaultPriority];
}
}
if (self::getAutoLoadOption($plugin, 'pagesSubFolders', true)) {
//
// Get all plugins/*/pages/subFolder/*.php pages
//
$pluginPagesSubFolders = glob(PLUGINS . $plugin['filename'] . '/pages/*', GLOB_ONLYDIR);
foreach ($pluginPagesSubFolders as $folder) {
$folderName = pathinfo($folder, PATHINFO_FILENAME);
$subFiles = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/*.php');
foreach ($subFiles as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = $folderName . '/' . pathinfo($file, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $file, $pagesDefaultPriority];
}
return ($a[3] > $b[3]) ? -1 : 1;
});
*/
$subFolders = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/*', GLOB_ONLYDIR);
foreach ($subFolders as $subFolder) {
$subFolderName = pathinfo($subFolder, PATHINFO_FILENAME);
$subSubFiles = glob(PLUGINS . $plugin['filename'] . '/pages/' . $folderName . '/' . $subFolderName . '/*.php');
foreach ($subSubFiles as $subSubFile) {
$subSubFile = str_replace(PLUGINS, 'plugins/', $subSubFile);
$name = $folderName . '/' . $subFolderName . '/' . pathinfo($subSubFile, PATHINFO_FILENAME);
$routes[] = [['get', 'post'], $name, $subSubFile, $pagesDefaultPriority];
}
}
}
}
}
usort($routes, function ($a, $b)
{
// key 3 is priority
if ($a[3] == $b[3]) {
return 0;
}
return ($a[3] < $b[3]) ? -1 : 1;
});
// cleanup before passing back
// priority is not needed anymore
foreach ($routes as &$route) {
unset($route[3]);
}
//foreach ($routes as &$route) {
// unset($route[3]);
//}
if ($cache->enabled()) {
$cache->set('plugins_routes', serialize($routes), 600);
@@ -142,6 +156,10 @@ class Plugins {
$themes = [];
foreach(self::getAllPluginsJson() as $plugin) {
if (!self::getAutoLoadOption($plugin, 'themes', true)) {
continue;
}
$pluginThemes = glob(PLUGINS . $plugin['filename'] . '/themes/*', GLOB_ONLYDIR);
foreach ($pluginThemes as $path) {
$path = str_replace(PLUGINS, 'plugins/', $path);
@@ -170,6 +188,10 @@ class Plugins {
$commands = [];
foreach(self::getAllPluginsJson() as $plugin) {
if (!self::getAutoLoadOption($plugin, 'commands', true)) {
continue;
}
$pluginCommands = glob(PLUGINS . $plugin['filename'] . '/commands/*.php');
foreach ($pluginCommands as $path) {
$commands[] = $path;
@@ -197,13 +219,19 @@ class Plugins {
foreach(self::getAllPluginsJson() as $plugin) {
if (isset($plugin['hooks'])) {
foreach ($plugin['hooks'] as $_name => $info) {
$priority = 1000;
if (str_contains($info['type'], 'HOOK_')) {
$info['type'] = str_replace('HOOK_', '', $info['type']);
}
if (isset($info['priority'])) {
$priority = (int)$info['priority'];
}
if (defined('HOOK_'. $info['type'])) {
$hook = constant('HOOK_'. $info['type']);
$hooks[] = ['name' => $_name, 'type' => $hook, 'file' => $info['file']];
$hooks[] = ['name' => $_name, 'type' => $hook, 'file' => $info['file'], 'priority' => $priority];
} else {
self::$warnings[] = 'Plugin: ' . $plugin['name'] . '. Unknown event type: ' . $info['type'];
}
@@ -211,6 +239,15 @@ class Plugins {
}
}
usort($hooks, function ($a, $b)
{
if ($a['priority'] == $b['priority']) {
return 0;
}
return ($a['priority'] < $b['priority']) ? -1 : 1;
});
if ($cache->enabled()) {
$cache->set('plugins_hooks', serialize($hooks), 600);
}
@@ -776,4 +813,21 @@ class Plugins {
}
}
}
private static function getAutoLoadOption(array $plugin, string $optionName, bool $default = true)
{
if (isset($plugin['autoload'])) {
$autoload = $plugin['autoload'];
if (is_array($autoload)) {
if (isset($autoload[$optionName])) {
return getBoolean($autoload[$optionName]);
}
}
else if (is_bool($autoload)) {
return $autoload;
}
}
return $default;
}
}

120
system/src/RateLimit.php Normal file
View File

@@ -0,0 +1,120 @@
<?php
namespace MyAAC;
class RateLimit
{
public string $key;
public int $max_attempts;
public int $ttl;
public $enabled = false;
protected array $data;
public function __construct(string $key, int $max_attempts, int $ttl)
{
$this->key = $key;
$this->max_attempts = $max_attempts;
$this->ttl = $ttl;
}
public function attempts(string $ip): int
{
if (!$this->enabled) {
return 0;
}
if (isset($this->data[$ip]['attempts'])) {
return $this->data[$ip]['attempts'];
}
return 0;
}
public function exceeded(string $ip): bool {
if (!$this->enabled) {
return false;
}
return $this->attempts($ip) >= $this->max_attempts;
}
public function increment(string $ip): bool
{
global $cache;
if ($this->enabled && $cache->enabled()) {
if (isset($this->data[$ip]['attempts']) && isset($this->data[$ip]['last'])) {
$this->data[$ip]['attempts']++;
$this->data[$ip]['last'] = time();
} else {
$this->data[$ip] = [
'attempts' => 1,
'last' => time(),
];
}
$this->save();
}
return false;
}
public function reset(string $ip): void
{
if (!$this->enabled) {
return;
}
if (isset($this->data[$ip])) {
unset($this->data[$ip]);
}
$this->save();
}
public function save(): void
{
global $cache;
if (!$this->enabled) {
return;
}
$data = $this->data;
$cache->set($this->key, serialize($data), $this->ttl * 60);
}
public function load(): void
{
global $cache;
if (!$this->enabled) {
return;
}
$data = [];
if ($this->enabled && $cache->enabled()) {
$tmp = '';
if ($cache->fetch($this->key, $tmp)) {
$data = unserialize($tmp);
$to_remove = [];
foreach ($data as $ip => $t) {
if (time() - $t['last'] >= ($this->ttl * 60)) {
$to_remove[] = $ip;
}
}
if (count($to_remove)) {
foreach ($to_remove as $ip) {
unset($data[$ip]);
}
$this->save();
}
} else {
$data = [];
}
}
$this->data = $data;
}
}

View File

@@ -382,6 +382,8 @@ class Settings implements \ArrayAccess
}
$this->settingsDatabase[$pluginKeyName][$key] = $value;
// invalidate cache
unset($this->cache[$offset]);
}
#[\ReturnTypeWillChange]

View File

@@ -124,6 +124,6 @@ class Towns
*/
public static function getFromDatabase()
{
return Town::pluck('name', 'id')->toArray();
return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray();
}
}

View File

@@ -45,6 +45,12 @@ define('HOOK_ACCOUNT_CREATE_AFTER_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_FORM', ++$i);
define('HOOK_ACCOUNT_CREATE_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_SUBMIT', ++$i);
define('HOOK_ACCOUNT_CREATE_AFTER_SAVED', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS', ++$i);
define('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT', ++$i);
@@ -54,6 +60,11 @@ define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_FIRST_TABLE', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_VOCATIONS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_TOWNS', ++$i);
define('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_SECOND_TABLE', ++$i);
define('HOOK_ADMIN_HEAD_END', ++$i);
define('HOOK_ADMIN_HEAD_START', ++$i);
define('HOOK_ADMIN_BODY_START', ++$i);
@@ -74,6 +85,8 @@ define('HOOK_GUILDS_AFTER_GUILD_MEMBERS', ++$i);
define('HOOK_GUILDS_AFTER_INVITED_CHARACTERS', ++$i);
define('HOOK_TWIG', ++$i);
define('HOOK_CACHE_CLEAR', ++$i);
define('HOOK_INSTALL_FINISH', ++$i);
define('HOOK_INSTALL_FINISH_END', ++$i);
const HOOK_FIRST = HOOK_STARTUP;
define('HOOK_LAST', $i);

View File

@@ -142,10 +142,14 @@ function updateStatus() {
}
}
$status['uptime'] = $serverStatus->getUptime();
$h = floor($status['uptime'] / 3600);
$m = floor(($status['uptime'] - $h * 3600) / 60);
$status['uptimeReadable'] = $h . 'h ' . $m . 'm';
$uptime = $status['uptime'] = $serverStatus->getUptime();
$m = date('m', $uptime);
$m = $m > 1 ? "$m months, " : ($m == 1 ? 'month, ' : '');
$d = date('d', $uptime);
$d = $d > 1 ? "$d days, " : ($d == 1 ? 'day, ' : '');
$h = date('H', $uptime);
$min = date('i', $uptime);
$status['uptimeReadable'] = "{$m}{$d}{$h}h {$min}m";
$status['monsters'] = $serverStatus->getMonstersCount();
$status['motd'] = $serverStatus->getMOTD();

View File

@@ -1,7 +1,26 @@
{% if new_line is defined and new_line %}
<br/>
{% endif %}
<form action="{% if action is not defined %}{{ getLink('account/manage') }}{% else %}{{ action }}{% endif %}" method="post">
{{ csrf() }}
{{ include('buttons.back.html.twig') }}
</form>
{% set _center = false %}
{% if center is defined and center %}
{% set _center = true %}
{% endif %}
{% if _center %}
<table border="0" cellspacing="1" cellpadding="4" width="100%">
<tbody>
<tr>
<td align="center">
{% endif %}
<form action="{% if action is not defined %}{{ getLink('account/manage') }}{% else %}{{ action }}{% endif %}" method="post">
{{ csrf() }}
{{ include('buttons.back.html.twig') }}
</form>
{% if _center %}
</td>
</tr>
</tbody>
</table>
{% endif %}

View File

@@ -29,7 +29,7 @@ Please enter your password and the new email address. Make sure that you enter a
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/email') }}" method="post">
<form id="form" action="{{ getLink('account/change-email') }}" method="post">
{{ csrf() }}
<input type="hidden" name="changeemailsave" value="1"/>
{{ include('buttons.submit.html.twig') }}

View File

@@ -59,7 +59,7 @@ Here you can tell other players about yourself. This information will be display
<table border="0" cellspacing="0" cellpadding="0" >
<tr>
<td style="border:0px;" >
<form id="form" action="{{ getLink('account/info') }}" method="post">
<form id="form" action="{{ getLink('account/change-info') }}" method="post">
{{ csrf() }}
<input type="hidden" name="changeinfosave" value="1">
{{ include('buttons.submit.html.twig') }}

View File

@@ -38,7 +38,7 @@ Please enter your current password and a new password. For your security, please
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/password') }}" method="post">
<form id="form" action="{{ getLink('account/change-password') }}" method="post">
{{ csrf() }}
{{ include('buttons.submit.html.twig') }}
</form>

View File

@@ -1,6 +1,6 @@
Here you can see and edit the information about your character.<br/>
If you do not want to specify a certain field, just leave it blank.<br/><br/>
<form action="{{ getLink('account/character/comment') }}" method="post">
<form action="{{ getLink('account/characters/change-comment') }}" method="post">
{{ csrf() }}
<div class="TableContainer" >
<table class="Table5" cellpadding="0" cellspacing="0">

View File

@@ -36,7 +36,7 @@ To change a name of character select player and choose a new name.<br/>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/character/name') }}" method="post">
<form id="form" action="{{ getLink('account/characters/change-name') }}" method="post">
{{ csrf() }}
<input type="hidden" name="changenamesave" value="1">
{{ include('buttons.submit.html.twig') }}

View File

@@ -36,7 +36,7 @@ To change a sex of character select player and choose a new sex.<br/>
<table border="0" cellspacing="0" cellpadding="0" >
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/character/sex') }}" method="post">
<form id="form" action="{{ getLink('account/characters/change-sex') }}" method="post">
{{ csrf() }}
<input type="hidden" name="changesexsave" value="1"/>
{{ include('buttons.submit.html.twig') }}

View File

@@ -23,6 +23,9 @@ In any case the name must not violate the naming conventions stated in the <a hr
</div>
<tr>
<td>
{{ hook('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_FIRST_TABLE') }}
<div class="InnerTableContainer">
<table style="width:100%;">
<tr>
@@ -62,8 +65,13 @@ In any case the name must not violate the naming conventions stated in the <a hr
</table>
</div>
</div>
</td>
</tr>
</table>
</div>
{{ hook('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_VOCATION') }}
<div class="InnerTableContainer">
<table style="width: 100%;">
<tr>
@@ -87,7 +95,11 @@ In any case the name must not violate the naming conventions stated in the <a hr
</td>
</tr>
</table>
</td>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_CHARACTER_BEFORE_TOWNS') }}
{% if config.character_towns|length > 1 %}
<td>
<table class="TableContent" width="100%">
@@ -110,9 +122,15 @@ In any case the name must not violate the naming conventions stated in the <a hr
</table>
</td>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_TOWNS') }}
</tr>
</table>
</div>
{{ hook('HOOK_ACCOUNT_CREATE_CHARACTER_AFTER_SECOND_TABLE') }}
</td>
</tr>
</table>
@@ -124,7 +142,7 @@ In any case the name must not violate the naming conventions stated in the <a hr
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/character/create') }}" method="post">
<form id="form" action="{{ getLink('account/characters/create') }}" method="post">
{{ csrf() }}
<input type="hidden" name="save" value="1">
{{ include('buttons.submit.html.twig') }}

View File

@@ -25,7 +25,7 @@ To delete a character enter the name of the character and your password.<br/><br
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/character/delete') }}" method="post">
<form id="form" action="{{ getLink('account/characters/delete') }}" method="post">
{{ csrf() }}
<input type="hidden" name="deletecharactersave" value="1"/>
{{ include('buttons.submit.html.twig') }}

View File

@@ -1,313 +1,315 @@
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_FORM') }}
{% set title = 'Create ' ~ config.lua.serverName ~ ' Account' %}
{% set background = config('darkborder') %}
{% set tableClass = 'Table5' %}
{% set content %}
<table style="width:100%;" >
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_BOXES') }}
<tr>
<td>
<div class="TableShadowContainerRightTop"> <div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div></div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<form action="{{ getLink('account/create') }}" method="post" id="createaccount">
{{ csrf() }}
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_ACCOUNT') }}
{% set title = 'Create ' ~ config.lua.serverName ~ ' Account' %}
{% set background = config('darkborder') %}
{% set tableClass = 'Table5' %}
{% set content %}
<table style="width:100%;" >
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_BOXES') }}
<tr>
<td>
<div class="TableShadowContainerRightTop"> <div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div></div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
{% if not config.account_login_by_email %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.account is defined %} class="red"{% endif %}>Account {% if constant('USE_ACCOUNT_NAME') %}Name{% else %}Number{% endif %}:</span>
{% if not constant('USE_ACCOUNT_NAME') %}
<div id="SuggestAccountNumber">[<a href="#">suggest number</a>]</div>
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_ACCOUNT') }}
{% if not config.account_login_by_email %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.account is defined %} class="red"{% endif %}>Account {% if constant('USE_ACCOUNT_NAME') %}Name{% else %}Number{% endif %}:</span>
{% if not constant('USE_ACCOUNT_NAME') %}
<div id="SuggestAccountNumber">[<a href="#">suggest number</a>]</div>
{% endif %}
</td>
<td>
<input type="text" name="account" id="account_input" size="30" maxlength="{% if constant('USE_ACCOUNT_NAME') %}30{% else %}10{% endif %}" value="{{ account }}" autofocus/>
<img id="account_indicator" src="images/global/general/{% if not save or errors.account is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
{% endif %}
</td>
<td>
<input form="form" type="text" name="account" id="account_input" size="30" maxlength="{% if constant('USE_ACCOUNT_NAME') %}30{% else %}10{% endif %}" value="{{ account }}" autofocus/>
<img id="account_indicator" src="images/global/general/{% if not save or errors.account is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
{% endif %}
<tr><td></td><td><span id="account_error" class="FormFieldError">{% if errors.account is defined %}{{ errors.account }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_ACCOUNT') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.email is defined %} class="red"{% endif %}>Email Address:</span>
</td>
<td>
<input form="form" type="text" name="email" id="email" size="30" maxlength="50" value="{{ email }}" />
<img id="email_indicator" src="images/global/general/{% if not save or errors.email is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr>
<td></td><td><span id="email_error" class="FormFieldError">{% if errors.email is defined %}{{ errors.email }}{% endif %}</span></td>
</tr>
<tr><td></td><td><span id="account_error" class="FormFieldError">{% if errors.account is defined %}{{ errors.account }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_ACCOUNT') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.email is defined %} class="red"{% endif %}>Email Address:</span>
</td>
<td>
<input type="text" name="email" id="email" size="30" maxlength="50" value="{{ email }}" />
<img id="email_indicator" src="images/global/general/{% if not save or errors.email is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr>
<td></td><td><span id="email_error" class="FormFieldError">{% if errors.email is defined %}{{ errors.email }}{% endif %}</span></td>
</tr>
{% if setting('core.mail_enabled') and setting('core.account_mail_verify') %}
<tr><td></td><td><span><strong>Please use real address!<br/>We will send a link to validate your Email.</strong></span></td></tr>
{% endif %}
{% if setting('core.mail_enabled') and setting('core.account_mail_verify') %}
<tr><td></td><td><span><strong>Please use real address!<br/>We will send a link to validate your Email.</strong></span></td></tr>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_EMAIL') }}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_EMAIL') }}
{% if setting('core.account_country') %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.country[0] is defined %} class="red"{% endif %}>Country:</span>
</td>
<td>
<select form="form" name="country" id="account_country">
{% for code, country_ in countries %}
<option value="{{ code }}"{% if(country is defined and country == code) or (country is null and country_recognized == code) %}selected{% endif %}>{{ country_ }}</option>
{% endfor %}
</select>
<img src="" id="account_country_img"/>
</td>
</tr>
{% if errors.country is defined %}
<tr><td></td><td><span class="FormFieldError">{{ errors.country }}</span></td></tr>
{% endif %}
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_COUNTRY') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.password is defined %} class="red"{% endif %}>Password:</span>
</td>
<td>
<input form="form" type="password" name="password" id="password" value="" size="30" maxlength="29" />
<img id="password_indicator" src="images/global/general/{% if not save or errors.password is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr><td></td><td><span id="password_error" class="FormFieldError">{% if errors.password is defined %}{{ errors.password }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORD') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.password is defined %} class="red"{% endif %}>Repeat password:</span>
</td>
<td>
<input form="form" type="password" name="password_confirm" id="password_confirm" value="" size="30" maxlength="29" />
<img id="password_confirm_indicator" src="images/global/general/{% if not save or errors.password is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr><td></td><td><span id="password_confirm_error" class="FormFieldError">{% if errors.password is defined %}{{ errors.password }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS') }}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);"> <div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div> <div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div> </div></div>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_1') }}
{% if (not setting('core.mail_enabled') or not setting('core.account_mail_verify')) and setting('core.account_create_character_create') %}
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_CHARACTER_NAME') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.name is defined %} class="red"{% endif %}>Character Name:</span>
</td>
<td>
<input form="form" id="character_name" name="name" size="{{ setting('core.create_character_name_max_length') }}" maxlength="{{ setting('core.create_character_name_max_length') }}" value="{{ name }}"/>
<img id="character_indicator" src="images/global/general/{% if not save or errors.name is defined %}n{% endif %}ok.gif" style="display: none;" />
<br>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="character_error" class="FormFieldError">{% if errors.name is defined %}{{ errors.name }}{% endif %}</span>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_CHARACTER_NAME') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.sex is defined %} class="red"{% endif %}>Sex:</span>
</td>
<td>
<table width="100%">
<tbody>
{% if setting('core.account_country') %}
<tr>
<td>
{% set i = 0 %}
{% for id, gender in config.genders|reverse(true) %}
{% set i = i + 1 %}
<span style="margin-right:15px;" class="OptionContainer">
<input form="form" type="radio" name="sex" id="sex{{ i }}" value="{{ id }}"{% if sex is not null and sex == id %} checked="checked"{% endif %}>
<label for="sex{{ i }}">{{ gender|lower }}</label>
</span>
{% endfor %}
<td class="LabelV" style="width: 150px">
<span{% if errors.country[0] is defined %} class="red"{% endif %}>Country:</span>
</td>
<td>
<select name="country" id="account_country">
{% for code, country_ in countries %}
<option value="{{ code }}"{% if(country is defined and country == code) or (country is null and country_recognized == code) %}selected{% endif %}>{{ country_ }}</option>
{% endfor %}
</select>
<img src="" id="account_country_img"/>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="sex_error" class="FormFieldError">{% if errors.sex is defined %}{{ errors.sex }}{% endif %}</span>
</td>
</tr>
{% if errors.country is defined %}
<tr><td></td><td><span class="FormFieldError">{{ errors.country }}</span></td></tr>
{% endif %}
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_SEX') }}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_COUNTRY') }}
{% if config.character_samples|length > 1 %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.vocation is defined %} class="red"{% endif %}>Vocation:</span>
</td>
<td>
<table width="100%" >
<tbody>
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.password is defined %} class="red"{% endif %}>Password:</span>
</td>
<td>
<input type="password" name="password" id="password" value="" size="30" maxlength="29" />
<img id="password_indicator" src="images/global/general/{% if not save or errors.password is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr><td></td><td><span id="password_error" class="FormFieldError">{% if errors.password is defined %}{{ errors.password }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORD') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.password is defined %} class="red"{% endif %}>Repeat password:</span>
</td>
<td>
<input type="password" name="password_confirm" id="password_confirm" value="" size="30" maxlength="29" />
<img id="password_confirm_indicator" src="images/global/general/{% if not save or errors.password is defined %}n{% endif %}ok.gif" style="display: none;" />
</td>
</tr>
<tr><td></td><td><span id="password_confirm_error" class="FormFieldError">{% if errors.password is defined %}{{ errors.password }}{% endif %}</span></td></tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS') }}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);"> <div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div> <div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div> </div></div>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_1') }}
{% if setting('core.account_create_character_create') %}
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_CHARACTER_NAME') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.name is defined %} class="red"{% endif %}>Character Name:</span>
</td>
<td>
<input id="character_name" name="name" size="{{ setting('core.create_character_name_max_length') }}" maxlength="{{ setting('core.create_character_name_max_length') }}" value="{{ name }}"/>
<img id="character_indicator" src="images/global/general/{% if not save or errors.name is defined %}n{% endif %}ok.gif" style="display: none;" />
<br>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="character_error" class="FormFieldError">{% if errors.name is defined %}{{ errors.name }}{% endif %}</span>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_CHARACTER_NAME') }}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.sex is defined %} class="red"{% endif %}>Sex:</span>
</td>
<td>
<table width="100%">
<tbody>
<tr>
<td>
{% set i = 0 %}
{% for id, gender in config.genders|reverse(true) %}
{% set i = i + 1 %}
<span style="margin-right:15px;" class="OptionContainer">
<input type="radio" name="sex" id="sex{{ i }}" value="{{ id }}"{% if sex is not null and sex == id %} checked="checked"{% endif %}>
<label for="sex{{ i }}">{{ gender|lower }}</label>
</span>
{% endfor %}
</td>
<td>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="sex_error" class="FormFieldError">{% if errors.sex is defined %}{{ errors.sex }}{% endif %}</span>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_SEX') }}
{% if config.character_samples|length > 1 %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.vocation is defined %} class="red"{% endif %}>Vocation:</span>
</td>
<td>
<table width="100%" >
<tbody>
<tr>
<td>
{% for key, sample_char in config.character_samples %}
<span style="margin-right:15px;" class="OptionContainer">
<input type="radio" name="vocation" id="vocation{{ key }}" value="{{ key }}"
{% if vocation is not null and vocation == key %} checked="checked"{% endif %}>
<label for="vocation{{ key }}">{{ config['vocations'][key] }}</label>
</span>
{% endfor %}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="vocation_error" class="FormFieldError">{% if errors.vocation is defined %}{{ errors.vocation }}{% endif %}</span>
</td>
</tr>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_VOCATION') }}
{% if config.character_towns|length > 1 %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.town is defined %} class="red"{% endif %}>Select your town:</span>
</td>
<td>
<table width="100%" >
<tbody>
<tr>
<td>
{% for town_id in config.character_towns %}
<span style="margin-right:15px;" class="OptionContainer">
<input type="radio" name="town" id="town{{ town_id }}" value="{{ town_id }}"
{% if town is not null and town == town_id %} checked="checked"{% endif %}>
<label for="town{{ town_id }}">{{ config.towns[town_id] }}</label>
</span>
{% endfor %}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_TOWNS') }}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);">
<div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div>
<div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_2') }}
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td colspan="2" ><b>Please select the following check box:</b></td>
</tr>
<tr>
<td colspan="2" >
<span><input type="checkbox" id="accept_rules" name="accept_rules" value="true"{% if accept_rules %}checked{% endif %}/> <label for="accept_rules">I agree to the <a href="?subtopic=rules" target="_blank">{{ config.lua.serverName }} Rules</a>.</label></span>
</td>
</tr>
{% if errors.accept_rules is defined %}
<tr>
<td>
{% for key, sample_char in config.character_samples %}
<span style="margin-right:15px;" class="OptionContainer">
<input form="form" type="radio" name="vocation" id="vocation{{ key }}" value="{{ key }}"
{% if vocation is not null and vocation == key %} checked="checked"{% endif %}>
<label for="vocation{{ key }}">{{ config['vocations'][key] }}</label>
</span>
{% endfor %}
<td colspan="2">
<span class="FormFieldError">{{ errors.accept_rules }}</span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td></td>
<td>
<span id="vocation_error" class="FormFieldError">{% if errors.vocation is defined %}{{ errors.vocation }}{% endif %}</span>
</td>
</tr>
{% endif %}
{% endif %}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);"> <div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div> <div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_VOCATION') }}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_BOXES') }}
{% if config.character_towns|length > 1 %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.town is defined %} class="red"{% endif %}>Select your town:</span>
</td>
<td>
<table width="100%" >
<tbody>
<tr>
<td>
{% for town_id in config.character_towns %}
<span style="margin-right:15px;" class="OptionContainer">
<input form="form" type="radio" name="town" id="town{{ town_id }}" value="{{ town_id }}"
{% if town is not null and town == town_id %} checked="checked"{% endif %}>
<label for="town{{ town_id }}">{{ config.towns[town_id] }}</label>
</span>
{% endfor %}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
{% endif %}
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_TOWNS') }}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);">
<div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div>
<div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_BETWEEN_BOXES_2') }}
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td colspan="2" ><b>Please select the following check box:</b></td>
</tr>
<tr>
<td colspan="2" >
<span><input form="form" type="checkbox" id="accept_rules" name="accept_rules" value="true"{% if accept_rules %}checked{% endif %}/> <label for="accept_rules">I agree to the <a href="?subtopic=rules" target="_blank">{{ config.lua.serverName }} Rules</a>.</label></span>
</td>
</tr>
{% if errors.accept_rules is defined %}
<tr>
<td colspan="2">
<span class="FormFieldError">{{ errors.accept_rules }}</span>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);"> <div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div> <div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_BOXES') }}
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
<br/>
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON') }}
<table width="100%">
<tr align="center">
<td>
<table border="0" cellspacing="0" cellpadding="0" >
<tr>
<td style="border:0px;" >
<form id="form" action="{{ getLink('account/create') }}" method="post">
{{ csrf() }}
<br/>
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_SUBMIT_BUTTON') }}
<table width="100%">
<tr align="center">
<td>
<table border="0" cellspacing="0" cellpadding="0" >
<tr>
<td style="border:0px;" >
<input type="hidden" name="save" value="1" >
{{ include('buttons.submit.html.twig') }}
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_FORM') }}
<script type="text/javascript" src="{{ constant('BASE_URL') }}tools/check_name.js"></script>
<style>

View File

@@ -3,10 +3,12 @@
var lastSend = 0;
$(function() {
updateFlag();
$('#account_country').change(function() {
{% if setting('core.account_country') %}
updateFlag();
});
$('#account_country').change(function() {
updateFlag();
});
{% endif %}
$('#account_input').blur(function() {
checkAccount();

View File

@@ -19,7 +19,7 @@ To generate new recovery key for your account please enter your password.<br/>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0px;">
<form id="form" action="{{ getLink('account/register/new') }}" method="post">
<form id="form" action="{{ getLink('account/register-new') }}" method="post">
{{ csrf() }}
<input type="hidden" name="registeraccountsave" value="1">
{{ include('buttons.submit.html.twig') }}

View File

@@ -61,20 +61,19 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="{{
{{ include('buttons.submit.html.twig') }}
</td>
<tr>
</form>
</table>
</td>
<td>
<table border="0" cellspacing="0" cellpadding="0">
<form action="{{ getLink('account/lost') }}" method="post">
{{ csrf() }}
<tr>
<td style="border:0px;">
<tr>
<td style="border:0px;">
<a href="{{ getLink('account/lost') }}">
{{ include('buttons.account_lost.html.twig') }}
</td>
</tr>
</form>
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>

View File

@@ -0,0 +1,24 @@
Please enter code from e-mail and name of one character from account. Then press Submit.<br/>
<form action="{{ getLink('account/lost') }}?action=check-code" method="post">
<table cellspacing="1" cellpadding="4" border="0" width="100%">
<tr>
<td bgcolor="{{ config('vdarkborder') }}" class="white">
<b>Code & character name</b>
</td>
</tr>
<tr>
<td bgcolor="{{ config('darkborder') }}">
Your code:&nbsp;<input type="text" name="code" value="{{ code }}" size="40"><br/>
Character:&nbsp;<input type="text" name="character" value="{{ character }}" size="40"><br/>
</td>
</tr>
</table>
<br>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center">
{{ include('buttons.submit.html.twig') }}
</td>
</tr>
</table>
</form>

View File

@@ -0,0 +1,26 @@
Your account name, new password and new e-mail.<br/>
<table cellspacing="1" cellpadding="4" border="0" width="100%">
<tr>
<td bgcolor="{{ config('vdarkborder') }}" class="white">
<b>Your account name, new password and new e-mail</b>
</td>
</tr>
<tr>
<td bgcolor="{{ config('darkborder') }}">
Account name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>{{ account.getName() }}</b><br/>
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>{{ newPassword }}</b><br/>
New e-mail address:&nbsp;<b>{{ newEmail }}</b><br/>
{{ statusMsg|raw }}
</td>
</tr>
</table>
<br>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center">
<form action="{{ getLink('account/manage') }}" method="post">
{{ include('buttons.login.html.twig') }}
</form>
</td>
</tr>
</table>

View File

@@ -0,0 +1,23 @@
New password to your account is below. Now you can login.<BR>
<table cellspacing="1" cellpadding="4" border="0" width="100%">
<tr>
<td bgcolor="{{ config('vdarkborder') }}" class="white"><b>Changed password</b></td>
</tr>
<tr>
<td bgcolor="{{ config('darkborder') }}">
New password:&nbsp;<b>{{ newPassword }}</b><br/>
Account name:&nbsp;&nbsp;&nbsp;<i>(Already on your e-mail)</i><br/>
{{ statusMsg|raw }}
</td>
</tr>
</table>
<br/>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center">
<form action="{{ getlink('account/manage') }}" method="post">
{{ include('buttons.submit.html.twig') }}
</form>
</td>
</tr>
</table>

View File

@@ -0,0 +1,23 @@
Please enter e-mail to account with this character.<br/>
<form action="{{ getLink('account/lost') }}?action=send-code" method="post">
<input type=hidden name="character">
<table cellspacing=1 cellpadding=4 border=0 width=100%>
<tr>
<td bgcolor="{{ config('vdarkborder') }}" class="white"><b>Please enter e-mail to account</b></td>
</tr>
<tr>
<td bgcolor="{{ config('darkborder') }}">
Character: <input type=text name="nick" value="{{ nick }}" size="40" readonly="readonly"><br/>
E-mail to account: <input type=text name="email" value="" size="40"><br/>
</td>
</tr>
</table>
<br>
<table cellspacing=0 cellpadding=0 border=0 width=100%>
<tr>
<td><div style="text-align:center">
{{ include('buttons.submit.html.twig') }}</div>
</TD>
</TR>
</table>
</form>

View File

@@ -0,0 +1,27 @@
Set new password and e-mail to your account.<br>
<form action="{{ getLink('account/lost') }}?action=step3" method="post">
<input type="hidden" name="character" value="">
<table cellspacing="1" cellpadding="4" border="0" width="100%">
<tr>
<td bgcolor="{{ config('vdarkborder') }}" class="white">
<b>Please enter new password and e-mail</b>
</td>
</tr>
<tr>
<td bgcolor="{{ config('darkborder') }}">
Account of character:&nbsp;&nbsp;<input type="text" name="nick" value="{{ nick }}" size="40" readonly="readonly"><br/>
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input id="passor" type="password" name="passor" value="" size="40"><br/>
Repeat new password:&nbsp;&nbsp;<input id="passor2" type="password" name="passor" value="" size="40"><br/>
New e-mail address:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input id="email" type="text" name="email" value="" size="40"><br/>
<input type=hidden name="key" VALUE="{{ recKey }}">
</td></tr>
</table>
<br>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center">
{{ include('buttons.submit.html.twig') }}
</td>
</tr>
</table>
</form>

View File

@@ -26,8 +26,8 @@
}
</style>
{% set menus = {
'Create Character': 'account/character/create','Delete Character': 'account/character/delete',
'Change Info': 'account/info', 'Change Password': 'account/password', 'Change Email': 'account/email'
'Create Character': 'account/characters/create','Delete Character': 'account/characters/delete',
'Change Info': 'account/change-info', 'Change Password': 'account/change-password', 'Change Email': 'account/change-email'
} %}
<div id="account-manage">
<div id="one">
@@ -40,10 +40,10 @@
<a href="{{ getLink(link) }}">{{ name }}</a>
{% endfor %}
{% if setting('core.account_change_character_name') %}
<a href="{{ getLink('account/character/name') }}">Change Name</a>
<a href="{{ getLink('account/characters/change-name') }}">Change Name</a>
{% endif %}
{% if setting('core.account_change_character_sex') %}
<a href="{{ getLink('account/character/sex') }}">Change Sex</a>
<a href="{{ getLink('account/characters/change-sex') }}">Change Sex</a>
{% endif %}
<a href="{{ getLink('account/logout') }}">Logout</a>
</div>
@@ -80,7 +80,7 @@
<div style="text-align:center">
A request has been submitted to change the email address of this account to <b>{{ email_new }}</b>. After <b>{{ email_new_time|date("j F Y, G:i:s") }}</b> you can accept the new email address and finish the process. Please cancel the request if you do not want your email address to be changed! Also cancel the request if you have no access to the new email address!
<form action="{{ getLink('account/email') }}" method="post">
<form action="{{ getLink('account/change-email') }}" method="post">
{{ csrf() }}
{% set button_name = 'Edit' %}
{% include('buttons.base.html.twig') %}
@@ -88,6 +88,7 @@
</div>
<br/><br/>
{% endif %}
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_GENERAL_INFORMATION') }}
<a name="General+Information"></a>
<h2>General Information</h2>
<table width="100%">
@@ -99,8 +100,8 @@
{% endif %}
<tr style="background-color: {{ config.darkborder }};" >
<td style="width: 90px;">Email Address:</td>
<td>{{ account_email ~ email_change }}
<form action="{{ getLink('account/email') }}" method="post">
<td>{{ account_email }}{{ email_change|raw }}
<form action="{{ getLink('account/change-email') }}" method="post">
{{ csrf() }}
{% set button_name = 'Change Email' %}
{% include('buttons.base.html.twig') %}
@@ -127,6 +128,7 @@
{% endautoescape %}
</table>
<br/>
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_PUBLIC_INFORMATION') }}
<a name="Public+Information"></a>
<h2>Public Information</h2>
<table width="100%">
@@ -139,12 +141,13 @@
<td >{{ account_location }}</td>
</tr>
</table>
<form action="{{ getLink('account/info') }}" method="post">
<form action="{{ getLink('account/change-info') }}" method="post">
{{ csrf() }}
{% set button_name = 'Change Info' %}
{% include('buttons.base.html.twig') %}
</form>
<br/>
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }}
<a name="Account+Logs" ></a>
<h2>Action Log</h2>
<table>
@@ -164,6 +167,7 @@
{% endautoescape %}
</table>
<br/>
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_CHARACTERS') }}
<a name="Characters" ></a>
<h2>Character list: {{ players|length }} characters.</h2>
<table>
@@ -183,7 +187,7 @@
<td>{% if player.getLastLogin() > 0 %}{{ player.getLastLogin|date('d F Y (H:i)') }}{% else %}Never.{% endif %}</td>
<td>{% if player.isOnline() %}<span style="color: green">ONLINE</span>{% else %}<span style="color: red">Offline</span>{% endif %}</td>
<td>{% if player.isHidden() %}Hidden{% else %}Visible{% endif %}</td>
<td>{% if not player.isDeleted() %}[<a href="{{ getLink('account/character/comment/' ~ player.getName|urlencode) }}" >Edit</a>]{% endif %}</td>
<td>{% if not player.isDeleted() %}[<a href="{{ getLink('account/characters/change-comment?name=' ~ player.getName()|urlencode) }}" >Edit</a>]{% endif %}</td>
</tr>
{% endfor %}
</table>
@@ -191,7 +195,7 @@
<table>
<tr>
<td>
<form action="{{ getLink('account/character/create') }}" method="post" >
<form action="{{ getLink('account/characters/create') }}" method="post" >
{{ csrf() }}
{% set button_name = 'Create Character' %}
{% include('buttons.base.html.twig') %}
@@ -199,7 +203,7 @@
</td>
{% if setting('core.account_change_character_name') %}
<td>
<form action="{{ getLink('account/character/name') }}" method="post" >
<form action="{{ getLink('account/characters/change-name') }}" method="post" >
{{ csrf() }}
{% set button_name = 'Change Name' %}
{% include('buttons.base.html.twig') %}
@@ -208,7 +212,7 @@
{% endif %}
{% if setting('core.account_change_character_sex') %}
<td>
<form action="{{ getLink('account/character/sex') }}" method="post" >
<form action="{{ getLink('account/characters/change-sex') }}" method="post" >
{{ csrf() }}
{% set button_name = 'Change Sex' %}
{% include('buttons.base.html.twig') %}
@@ -216,7 +220,7 @@
</td>
{% endif %}
<td>
<form action="{{ getLink('account/character/delete') }}" method="post">
<form action="{{ getLink('account/characters/delete') }}" method="post">
{{ csrf() }}
{% set button_name = 'Delete Character' %}
{% include('buttons.base.html.twig') %}

View File

@@ -275,7 +275,7 @@
{% for frag in frags %}
<tr bgcolor="{{ getStyle(i) }}">
<td width="20%" align="center">{{ frag.time|date("j M Y, H:i") }}</td>
<td>{{ frag.description|raw }}({% if frag.unjustified %}<span style="color: red; font-size: 10px">Unjustified</span>{% else %}<span style="color: green; font-size: 10px">Justified</span>{% endif %})</td>
<td>{{ frag.description|raw }} ({% if frag.unjustified %}<span style="color: red; font-size: 10px">Unjustified</span>{% else %}<span style="color: green; font-size: 10px">Justified</span>{% endif %})</td>
</tr>
{% set i = i + 1 %}
{% endfor %}

View File

@@ -11,7 +11,7 @@
<select onchange="location = this.value;" aria-label="skillFilter" id="skillFilter">
{% set i = 0 %}
{% for link, name in types %}
<option value="{{ getLink('highscores') }}/{{ link }}{% if vocation is defined %}/{{ vocation }}{% endif %}" class="size_xs">{{ name }}</option>
<option value="{{ getLink('highscores') }}/{{ link }}{% if vocation is not null %}{{ vocation }}{% endif %}" class="size_xs">{{ name }}</option>
{% endfor %}
</select>
</td>
@@ -105,7 +105,7 @@
<tr bgcolor="{{ config.lightborder }}">
<td>
{% for link, name in types %}
<a href="{{ getLink('highscores') }}/{{ link }}{% if vocation is defined %}/{{ vocation }}{% endif %}" class="size_xs">{{ name }}</a><br/>
<a href="{{ getLink('highscores') }}/{{ link }}{% if vocation is not null %}/{{ vocation }}{% endif %}" class="size_xs">{{ name }}</a><br/>
{% endfor %}
</td>
</tr>

View File

@@ -9,7 +9,13 @@
<form action="{{ constant('BASE_URL') }}install/" method="post" autocomplete="off">
<input type="hidden" name="step" id="step" value="finish" />
{% for value in ['email', 'account', 'password', 'password_confirm', 'player_name'] %}
{% set values = ['email', 'account', 'password', 'password_confirm'] %}
{% if hasTablePlayers %}
{% set values = values|merge(['player_name']) %}
{% endif %}
{% for value in values %}
<div class="form-group mb-2">
<label for="vars_{{ value }}">{{ locale['step_admin_' ~ value] }}</label>

View File

@@ -0,0 +1,10 @@
You asked to reset your {{ config('lua')['serverName'] }} password.<br/>
<p>Account name: {{ account.getName() }}</p>
<br/>
To do so, please click this link:
<p>
<a href="{{ getLink('account/lost') }}?action=check-code&code={{ newCode }}&character={{ nick|urlencode }}">{{ getLink('account/lost') }}?action=check-code&code={{ newCode }}&character={{ nick|urlencode }}</a>
</p>
<p>or open page: <i>{{ getLink('account/lost') }}?action=check-code</i> and in field "code" write <b>{{ newCode }}</b></p>
<br/>
<p>If you did not request a password change, you may ignore this message and your password will remain unchanged.

View File

@@ -0,0 +1,7 @@
<h3>Your account name and new password!</h3>
<p>Changed password and e-mail to your account in Lost Account Interface on server <a href="{{ constant('BASE_URL') }}"><b>{{ config('lua')['serverName'] }}</b></a></p>
<p>Account name: <b>{{ account.getName() }}</b></p>
<p>New password: <b>{{ newPassword }}</b></p>
<p>E-mail: <b>{{ $newEmail }}</b> (this e-mail)</p>
<br/>
<p><u>It's automatic e-mail from OTS Lost Account System. Do not reply!</u></p>

View File

@@ -0,0 +1,6 @@
<h3>Your account name and password!</h3>
<p>Changed password to your account in Lost Account Interface on server <a href="{{ constant('BASE_URL') }}"><b>config('lua')['serverName'] }}</b></a></p>
<p>Account name: <b>{{ account.getName() }}</b></p>
<p>New password: <b>{{ newPassword }}</b></p>
<br/>
<p><u>It's automatic e-mail from OTS Lost Account System. Do not reply!</u></p>

Some files were not shown because too many files have changed in this diff Show More