';
/* -------------------------------
--- Znote AAC forum ---
-------------------------------
Created by Znote.
Version 1.4.
Changelog (1.0 --> 1.2):
- Updated to the new date/clock time system
- Bootstrap design support.
Changelog (1.2 --> 1.3):
- Show character outfit as avatar
- Show in-game position
Changelog (1.3 -> 1.4):
- Fix SQL query error when editing Board name.
*/
// BBCode rendering now lives in engine/function/bbcode.php as znote_bbcode().
function znote_forum_editor_assets() {
static $loaded = false;
if ($loaded) return;
$loaded = true;
$v = '3.2.1';
?>
0)
? 'Up to ' . $max . ' image' . ($max === 1 ? '' : 's') . ' per post.'
: 'Images are not allowed in forum posts.';
?>
" picker plus the submit button.
*
* This used to be a , which browsers draw as a scrolling list
* box with nothing selected by default - so submitting without first clicking a
* name posted no character id at all and the action silently did nothing. A
* plain dropdown always has a value, and when the account has a single
* character there is nothing to choose, so it is shown as a label instead.
*/
function znote_forum_style() {
static $done = false;
if ($done) return;
$done = true;
echo ' ' . "\n";
}
/** Short relative time for the board / thread lists. */
function znote_forum_ago($ts) {
$ts = (int)$ts;
if ($ts <= 0) return '';
$d = time() - $ts;
if ($d < 0) $d = 0;
if ($d < 60) return t('forum.ago_now');
if ($d < 3600) return t('forum.ago_min', array('n' => (int)floor($d / 60)));
if ($d < 86400) return t('forum.ago_hour', array('n' => (int)floor($d / 3600)));
if ($d < 2592000) return t('forum.ago_day', array('n' => (int)floor($d / 86400)));
return date('M j, Y', $ts);
}
function znote_forum_e($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function znote_forum_character_picker(array $chars, string $field, string $submitLabel, string $submitClass = 'btn btn-primary') {
znote_forum_style();
$only = (count($chars) === 1) ? reset($chars) : null;
?>
= t('forum.post_as') ?>
fetchAll("SELECT `id`, `name`, `group_id` FROM `players` WHERE `level` >= 1 AND `account_id` = ?;", [$user_data['id']]);
else $yourChars = db()->fetchAll("SELECT `id`, `name`, `group_id` FROM `players` WHERE `level` >= ? AND `account_id` = ?;", [(int)$config['forum']['level'], $user_data['id']]);
if (!$yourChars) $yourChars = array();
$charCount = count($yourChars);
$yourAccess = accountAccess($user_data['id'], znote_server_adapter()->normalizedEngine());
if ($admin) {
if (!empty($_POST)) {
$guilds = db()->fetchAll("SELECT `id`, `name` FROM `guilds` ORDER BY `name`;");
$guilds[] = array('id' => '0', 'name' => 'No guild');
}
$yourAccess = 100;
}
// Your characters, indexed by char_id
$charData = array();
foreach ($yourChars as $char) {
$charData[$char['id']] = $char;
if (get_character_guild_rank($char['id']) > 0) {
$guild = get_player_guild_data($char['id']);
$charData[$char['id']]['guild'] = $guild['guild_id'];
$charData[$char['id']]['guild_rank'] = $guild['rank_level'];
} else $charData[$char['id']]['guild'] = '0';
}
$cooldownw = array(
$user_znote_data['cooldown'],
time(),
$user_znote_data['cooldown'] - time()
);
/////////////////
// Guild Leader & admin
$leader = false;
foreach($charData as $char) {
if ($char['guild'] > 0 && $char['guild_rank'] == 3) $leader = true;
}
if ($admin && !empty($_POST) || $leader && !empty($_POST)) {
$admin_thread_delete = getValue($_POST['admin_thread_delete'] ?? null);
$admin_thread_close = getValue($_POST['admin_thread_close'] ?? null);
$admin_thread_open = getValue($_POST['admin_thread_open'] ?? null);
$admin_thread_sticky = getValue($_POST['admin_thread_sticky'] ?? null);
$admin_thread_unstick = getValue($_POST['admin_thread_unstick'] ?? null);
$admin_thread_id = getValue($_POST['admin_thread_id'] ?? null);
// delete thread
if ($admin_thread_delete !== false) {
$admin_thread_id = (int)$admin_thread_id;
$access = false;
if (!$admin) {
$thread = db()->fetchOne("SELECT `forum_id` FROM `znote_forum_threads` WHERE `id` = ?;", [$admin_thread_id]);
$forum = db()->fetchOne("SELECT `guild_id` FROM `znote_forum` WHERE `id` = ?;", [$thread['forum_id']]);
foreach($charData as $char) if ($char['guild'] == $forum['guild_id'] && $char['guild_rank'] == 3) $access = true;
} else $access = true;
if ($access) {
// Delete all associated posts
db()->execute("DELETE FROM `znote_forum_posts` WHERE `thread_id` = ?;", [$admin_thread_id]);
// Delete thread itself
db()->execute("DELETE FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$admin_thread_id]);
acp_log('forum.thread_delete', '#' . $admin_thread_id, ['scope' => $admin ? 'owner' : 'guild_leader']);
echo ''. t('forum.thread_deleted'). ' ';
} else echo ''. t('forum.perm_denied'). '
';
}
// Close thread
if ($admin_thread_close !== false) {
$admin_thread_id = (int)$admin_thread_id;
$access = false;
if (!$admin) {
$thread = db()->fetchOne("SELECT `forum_id` FROM `znote_forum_threads` WHERE `id` = ?;", [$admin_thread_id]);
$forum = db()->fetchOne("SELECT `guild_id` FROM `znote_forum` WHERE `id` = ?;", [$thread['forum_id']]);
foreach($charData as $char) if ($char['guild'] == $forum['guild_id'] && $char['guild_rank'] == 3) $access = true;
} else $access = true;
if ($access) {
db()->execute("UPDATE `znote_forum_threads` SET `closed` = 1 WHERE `id` = ? LIMIT 1;", [$admin_thread_id]);
acp_log('forum.thread_close', '#' . $admin_thread_id, ['scope' => $admin ? 'owner' : 'guild_leader']);
echo ''. t('forum.thread_closed'). ' ';
} else echo ''. t('forum.perm_denied'). '
';
}
// open thread
if ($admin_thread_open !== false) {
$admin_thread_id = (int)$admin_thread_id;
$access = false;
if (!$admin) {
$thread = db()->fetchOne("SELECT `forum_id` FROM `znote_forum_threads` WHERE `id` = ?;", [$admin_thread_id]);
$forum = db()->fetchOne("SELECT `guild_id` FROM `znote_forum` WHERE `id` = ?;", [$thread['forum_id']]);
foreach($charData as $char) if ($char['guild'] == $forum['guild_id'] && $char['guild_rank'] == 3) $access = true;
} else $access = true;
if ($access) {
db()->execute("UPDATE `znote_forum_threads` SET `closed` = 0 WHERE `id` = ? LIMIT 1;", [$admin_thread_id]);
acp_log('forum.thread_open', '#' . $admin_thread_id, ['scope' => $admin ? 'owner' : 'guild_leader']);
echo ''. t('forum.thread_opened'). ' ';
} else echo ''. t('forum.perm_denied2') .'
';
}
// stick thread
if ($admin_thread_sticky !== false) {
$admin_thread_id = (int)$admin_thread_id;
$access = false;
if (!$admin) {
$thread = db()->fetchOne("SELECT `forum_id` FROM `znote_forum_threads` WHERE `id` = ?;", [$admin_thread_id]);
$forum = db()->fetchOne("SELECT `guild_id` FROM `znote_forum` WHERE `id` = ?;", [$thread['forum_id']]);
foreach($charData as $char) if ($char['guild'] == $forum['guild_id'] && $char['guild_rank'] == 3) $access = true;
} else $access = true;
if ($access) {
db()->execute("UPDATE `znote_forum_threads` SET `sticky` = 1 WHERE `id` = ? LIMIT 1;", [$admin_thread_id]);
acp_log('forum.thread_sticky', '#' . $admin_thread_id, ['scope' => $admin ? 'owner' : 'guild_leader']);
echo ''. t('forum.thread_stuck2'). ' ';
} else echo ''. t('forum.perm_denied2') .'
';
}
// unstick thread
if ($admin_thread_unstick !== false) {
$admin_thread_id = (int)$admin_thread_id;
$access = false;
if (!$admin) {
$thread = db()->fetchOne("SELECT `forum_id` FROM `znote_forum_threads` WHERE `id` = ?;", [$admin_thread_id]);
$forum = db()->fetchOne("SELECT `guild_id` FROM `znote_forum` WHERE `id` = ?;", [$thread['forum_id']]);
foreach($charData as $char) if ($char['guild'] == $forum['guild_id'] && $char['guild_rank'] == 3) $access = true;
} else $access = true;
if ($access) {
db()->execute("UPDATE `znote_forum_threads` SET `sticky` = 0 WHERE `id` = ? LIMIT 1;", [$admin_thread_id]);
acp_log('forum.thread_unsticky', '#' . $admin_thread_id, ['scope' => $admin ? 'owner' : 'guild_leader']);
echo ''. t('forum.thread_unstuck2'). ' ';
} else echo ''. t('forum.perm_denied2') .'
';
}
}
/////////////////
// ADMIN FUNCT
if ($admin && !empty($_POST)) {
$admin_post_id = getValue($_POST['admin_post_id'] ?? null);
$admin_post_delete = getValue($_POST['admin_post_delete'] ?? null);
$admin_category_delete = getValue($_POST['admin_category_delete'] ?? null);
$admin_category_edit = getValue($_POST['admin_category_edit'] ?? null);
$admin_category_id = getValue($_POST['admin_category_id'] ?? null);
$admin_update_category = getValue($_POST['admin_update_category'] ?? null);
$admin_category_name = getValue($_POST['admin_category_name'] ?? null);
$admin_category_access = getValue($_POST['admin_category_access'] ?? null);
$admin_category_closed = getValue($_POST['admin_category_closed'] ?? null);
$admin_category_hidden = getValue($_POST['admin_category_hidden'] ?? null);
$admin_category_guild_id = getValue($_POST['admin_category_guild_id'] ?? null);
if ($admin_category_access === false) $admin_category_access = 0;
if ($admin_category_closed === false) $admin_category_closed = 0;
if ($admin_category_hidden === false) $admin_category_hidden = 0;
if ($admin_category_guild_id === false) $admin_category_guild_id = 0;
$admin_board_create_name = getValue($_POST['admin_board_create_name'] ?? null);
$admin_board_create_access = getValue($_POST['admin_board_create_access'] ?? null);
$admin_board_create_closed = getValue($_POST['admin_board_create_closed'] ?? null);
$admin_board_create_hidden = getValue($_POST['admin_board_create_hidden'] ?? null);
$admin_board_create_guild_id = getValue($_POST['admin_board_create_guild_id'] ?? null);
if ($admin_board_create_access === false) $admin_board_create_access = 0;
if ($admin_board_create_closed === false) $admin_board_create_closed = 0;
if ($admin_board_create_hidden === false) $admin_board_create_hidden = 0;
if ($admin_board_create_guild_id === false) $admin_board_create_guild_id = 0;
// Create board
if ($admin_board_create_name !== false) {
// Insert data
db()->execute("INSERT INTO `znote_forum` (`name`, `access`, `closed`, `hidden`, `guild_id`)
VALUES (?, ?, ?, ?, ?);", [
$admin_board_create_name,
$admin_board_create_access,
$admin_board_create_closed,
$admin_board_create_hidden,
$admin_board_create_guild_id,
]);
acp_log('forum.board_create', (string)$admin_board_create_name, ['access' => $admin_board_create_access, 'guild_id' => $admin_board_create_guild_id]);
echo ''. t('forum.board_created'). ' ';
}
//////////////////
// update category
if ($admin_update_category !== false) {
$admin_category_id = (int)$admin_category_id;
// Update the category
db()->execute("UPDATE `znote_forum` SET
`name` = ?,
`access` = ?,
`closed` = ?,
`hidden` = ?,
`guild_id` = ?
WHERE `id` = ? LIMIT 1;", [
$admin_category_name,
$admin_category_access,
$admin_category_closed,
$admin_category_hidden,
$admin_category_guild_id,
$admin_category_id,
]);
acp_log('forum.board_update', '#' . $admin_category_id, ['access' => $admin_category_access, 'guild_id' => $admin_category_guild_id]);
echo ''. t('forum.board_updated'). ' ';
}
//////////////////
// edit category
if ($admin_category_edit !== false) {
$admin_category_id = (int)$admin_category_id;
$category = db()->fetchOne("SELECT `id`, `name`, `access`, `closed`, `hidden`, `guild_id`
FROM `znote_forum` WHERE `id` = ? LIMIT 1;", [$admin_category_id]);
if ($category !== false) {
?>
'. t('forum.cat_not_found'). '';
}
// delete category
if ($admin_category_delete !== false) {
$admin_category_id = (int)$admin_category_id;
// find all threads in category
$threads = db()->fetchAll("SELECT `id` FROM `znote_forum_threads` WHERE `forum_id` = ?;", [$admin_category_id]);
// Then loop through all threads, and delete all associated posts:
foreach($threads as $thread) {
db()->execute("DELETE FROM `znote_forum_posts` WHERE `thread_id` = ?;", [$thread['id']]);
}
// Then delete all threads
db()->execute("DELETE FROM `znote_forum_threads` WHERE `forum_id` = ?;", [$admin_category_id]);
// Then delete the category
db()->execute("DELETE FROM `znote_forum` WHERE `id` = ? LIMIT 1;", [$admin_category_id]);
acp_log('forum.board_delete', '#' . $admin_category_id);
echo '' . t('forum.board_and_threads_deleted') . ' ';
}
// delete post
if ($admin_post_delete !== false) {
$admin_post_id = (int)$admin_post_id;
// Delete the post
db()->execute("DELETE FROM `znote_forum_posts` WHERE `id` = ? LIMIT 1;", [$admin_post_id]);
acp_log('forum.post_delete', '#' . $admin_post_id);
echo ''. t('forum.post_deleted'). ' ';
}
}
// End admin function
// Fetching get values
if (!empty($_GET)) {
$getCat = getValue($_GET['cat'] ?? null);
$getForum = getValue($_GET['forum'] ?? null);
$getThread = getValue($_GET['thread'] ?? null);
$new_thread_category = getValue($_POST['new_thread_category'] ?? null);
$new_thread_cid = getValue($_POST['new_thread_cid'] ?? null);
$create_thread_cid = getValue($_POST['create_thread_cid'] ?? null);
$create_thread_title = getValue($_POST['create_thread_title'] ?? null);
$create_thread_text = getValue($_POST['create_thread_text'] ?? null);
$create_thread_category = getValue($_POST['create_thread_category'] ?? null);
$update_thread_id = getValue($_POST['update_thread_id'] ?? null);
$update_thread_title = getValue($_POST['update_thread_title'] ?? null);
$update_thread_text = getValue($_POST['update_thread_text'] ?? null);
$edit_thread = getValue($_POST['edit_thread'] ?? null);
$edit_thread_id = getValue($_POST['edit_thread_id'] ?? null);
$reply_thread = getValue($_POST['reply_thread'] ?? null);
$reply_text = getValue($_POST['reply_text'] ?? null);
$reply_cid = getValue($_POST['reply_cid'] ?? null);
$edit_post = getValue($_POST['edit_post'] ?? null);
$edit_post_id = getValue($_POST['edit_post_id'] ?? null);
$update_post_id = getValue($_POST['update_post_id'] ?? null);
$update_post_text = getValue($_POST['update_post_text'] ?? null);
// Image cap. The editor checks this too, but that check is a convenience -
// this one is the rule, because a POST does not have to come from the editor.
// Blanking the field makes the save branches below skip, since each requires
// its text to be !== false.
$forumImageLimit = (int)($config['forum']['maxImagesPerPost'] ?? 1);
$forumImageDenied = false;
foreach (array('create_thread_text', 'update_thread_text', 'reply_text', 'update_post_text') as $forumField) {
if ($$forumField !== false && znote_bbcode_count_images($$forumField) > $forumImageLimit) {
$forumImageDenied = true;
$$forumField = false;
}
}
if ($forumImageDenied) {
echo ''
. ($forumImageLimit > 0
? 'Too many images: only ' . $forumImageLimit . ' allowed per post. Nothing was saved.'
: 'Images are not allowed in forum posts. Nothing was saved.')
. '
';
}
/////////////////////
// When you are POSTING in an existing thread
if ($reply_thread !== false && $reply_text !== false && $reply_cid !== false) {
$reply_cid = (int)$reply_cid;
if ($user_znote_data['cooldown'] < time()) {
user_update_znote_account(array('cooldown'=>(time() + $config['forum']['cooldownPost'])));
$thread = db()->fetchOne("SELECT `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$reply_thread]);
if (!is_array($thread) || !isset($charData[$reply_cid])) $access = false;
else if ($thread['closed'] == 1 && $admin === false) $access = false;
else $access = true;
if ($access) {
db()->execute("INSERT INTO `znote_forum_posts` (`thread_id`, `player_id`, `player_name`, `text`, `created`, `updated`) VALUES (?, ?, ?, ?, ?, ?);", [$reply_thread, $reply_cid, $charData[$reply_cid]['name'], $reply_text, time(), time()]);
if ($config['forum']['newPostsBumpThreads']) db()->execute("UPDATE `znote_forum_threads` SET `updated` = ? WHERE `id` = ?;", [time(), $reply_thread]);
} else echo 'You don\'t have permission to post on this thread. [Thread: Closed]
';
} else {
?>
= t('forum.antispam') ?> seconds before you can create or post.
(time() + $config['forum']['cooldownCreate'])));
$category = db()->fetchOne("SELECT `access`, `closed`, `guild_id` FROM `znote_forum` WHERE `id` = ? LIMIT 1;", [$create_thread_category]);
if ($category !== false) {
$access = true;
if (!$admin) {
if ($category['access'] > $yourAccess) $access = false;
if ($category['guild_id'] > 0) {
$status = false;
foreach($charData as $char) {
if ($char['guild'] == $category['guild_id']) $status = true;
}
if (!$status) $access = false;
}
if ($category['closed'] > 0) $access = false;
}
if ($access) {
db()->execute("INSERT INTO `znote_forum_threads`
(`forum_id`, `player_id`, `player_name`, `title`, `text`, `created`, `updated`, `sticky`, `hidden`, `closed`)
VALUES (?, ?, ?, ?, ?, ?, ?, 0, 0, 0);", [
$create_thread_category,
$create_thread_cid,
$charData[$create_thread_cid]['name'],
$create_thread_title,
$create_thread_text,
time(),
time(),
]);
SendGet(array('cat'=>$create_thread_category), 'forum.php');
} else echo ''. t('forum.perm_thread'). '
';
} else echo t('forum.cat_missing');
} else {
?>
= t('forum.antispam') ?> seconds before you can create or post.
fetchOne("SELECT `id`, `player_name`, `text`, `thread_id` FROM `znote_forum_posts` WHERE `id` = ? LIMIT 1;", [$update_post_id]);
if (!is_array($post)) $post = array('id' => 0, 'player_name' => '', 'text' => '', 'thread_id' => 0);
$thread = db()->fetchOne("SELECT `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$post['thread_id']]);
// Verify access
$access = PlayerHaveAccess($yourChars, $post['player_name']);
if ($thread !== false && $thread['closed'] == 1 && $admin === false) $access = false;
if ($admin) $access = true;
//if ($thread === false) $access = false;
if ($access) {
db()->execute("UPDATE `znote_forum_posts` SET `text` = ?, `updated` = ? WHERE `id` = ?;", [$update_post_text, time(), $update_post_id]);
if ($admin) acp_log('forum.post_update', '#' . (int)$update_post_id);
echo '' . t('forum.post_updated') . ' ';
} else echo "" . t('forum.edit_post_denied') . "
";
}
/////////////////////
// When you ARE updating thread
if ($update_thread_id !== false && $update_thread_title !== false && $update_thread_text !== false) {
// Fetch the thread data
$thread = db()->fetchOne("SELECT `id`, `player_name`, `title`, `text`, `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$update_thread_id]);
if (!is_array($thread)) $thread = array('id' => 0, 'player_name' => '', 'title' => '', 'text' => '', 'closed' => 0);
// Verify access
$access = PlayerHaveAccess($yourChars, $thread['player_name']);
if ($thread['closed'] == 1 && $admin === false) $access = false;
if ($admin) $access = true;
if ($access) {
db()->execute("UPDATE `znote_forum_threads` SET `title` = ?, `text` = ? WHERE `id` = ?;", [$update_thread_title, $update_thread_text, $update_thread_id]);
if ($admin) acp_log('forum.thread_update', '#' . (int)$update_thread_id, ['title' => (string)$update_thread_title]);
echo ''. t('forum.thread_updated'). ' ';
} else echo "" . t('forum.edit_thread_denied') . "
";
}
/////////////////////
// When you want to edit a post
if ($edit_post_id !== false && $edit_post !== false) {
// Fetch the post data
$post = db()->fetchOne("SELECT `id`, `thread_id`, `text`, `player_name` FROM `znote_forum_posts` WHERE `id` = ? LIMIT 1;", [$edit_post_id]);
if (!is_array($post)) $post = array('id' => 0, 'thread_id' => 0, 'text' => '', 'player_name' => '');
$thread = db()->fetchOne("SELECT `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$post['thread_id']]);
if (!is_array($thread)) $thread = array('closed' => 0);
// Verify access
$access = PlayerHaveAccess($yourChars, $post['player_name']);
if ($thread['closed'] == 1 && $admin === false) $access = false;
if ($admin) $access = true;
if ($access) {
?>
= t('forum.edit_post') ?>
'. t('forum.no_edit_post') .' ';
} else
/////////////////////
// When you want to edit a thread
if ($edit_thread_id !== false && $edit_thread !== false) {
// Fetch the thread data
$thread = db()->fetchOne("SELECT `id`, `title`, `text`, `player_name`, `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$edit_thread_id]);
$access = PlayerHaveAccess($yourChars, $thread['player_name']);
if ($thread['closed'] == 1) $access = false;
if ($admin) $access = true;
if ($access) {
?>
= t('forum.edit_thread') ?>
'. t('forum.edit_denied'). ' ';
} else
/////////////////////
// When you want to view a thread
if ($getThread !== false) {
$getThread = (int)$getThread;
$threadData = db()->fetchOne("SELECT `id`, `forum_id`, `player_id`, `player_name`, `title`, `text`, `created`, `updated`, `sticky`, `hidden`, `closed` FROM `znote_forum_threads` WHERE `id` = ? LIMIT 1;", [$getThread]);
if ($threadData !== false) {
$category = db()->fetchOne("SELECT `hidden`, `access`, `guild_id` FROM `znote_forum` WHERE `id` = ? LIMIT 1;", [$threadData['forum_id']]);
if ($category === false) die("Thread category does not exist.");
$access = true;
$leader = false;
if ($category['hidden'] == 1 || $category['access'] > 1 || $category['guild_id'] > 0) {
$access = false;
if ($category['hidden'] == 1) $access = PlayerHaveAccess($yourChars, $threadData['player_name']);
if ($category['access'] > 1 && $yourAccess >= $category['access']) $access = true;
foreach($charData as $char) {
if ($category['guild_id'] == $char['guild']) $access = true;
if ($char['guild_rank'] == 3) $leader = true;
}
if ($admin) $access = true;
}
if ($access) {
$threadPlayer = ($config['forum']['outfit_avatars'] || $config['forum']['player_position']) ? db()->fetchOne("SELECT `id`, `group_id`, `sex`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons` FROM `players` WHERE `id` = ?;", [$threadData['player_id']]) : false;
?>
= t('forum.title') ?> /
". $threadData['title'] .""; ?>
= t('forum.op_tag') ?>
0 && ($threadData['closed'] == 0 || $yourAccess > 3)): ?>
= t('forum.quote') ?>
fetchAll("SELECT `id`, `player_id`, `player_name`, `text`, `created`, `updated` FROM `znote_forum_posts` WHERE `thread_id` = ? ORDER BY `created`;", [$threadData['id']]);
if ($posts !== false) {
// Load extra data (like outfit avatars?)
$players = array();
$extra = false;
if ($config['forum']['outfit_avatars'] || $config['forum']['player_position']) {
$extra = true;
foreach($posts as $post)
if (!isset($players[$post['player_id']]))
$players[$post['player_id']] = array();
$playerIds = array_keys($players);
$playerIdPlaceholders = implode(',', array_fill(0, count($playerIds), '?'));
$sql_players = db()->fetchAll("SELECT `id`, `group_id`, `sex`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons` FROM `players` WHERE `id` IN ({$playerIdPlaceholders});", $playerIds);
foreach ($sql_players as $player)
$players[$player['id']] = $player;
}
foreach($posts as $post) {
?>
0 && ($threadData['closed'] == 0 || $yourAccess > 3)) {
?>
= t('forum.quote') ?>
0) {
if ($threadData['closed'] == 0 || $yourAccess > 3) {
?>
= t('forum.reply_title') ?>
' . t('forum.thread_closed_note') . '';
} else {
?>= t('forum.level_required', ['level' => (int)$config['forum']['level']]) ?>
' . t('forum.perm_denied3') . '';
} else {
?>
= t('forum.thread_unavailable') ?>
= t('forum.thread_unavailable_text') ?>
0 && !empty($_GET['forum'])) {
$tmpCat = getValue($_GET['cat'] ?? null);
$tmpCatName = getValue($_GET['forum'] ?? null);
?>
= t('forum.go_back_to') ?>
= t('forum.go_back') ?>
fetchOne("SELECT `access`, `closed`, `guild_id` FROM `znote_forum` WHERE `id` = ? LIMIT 1;", [$new_thread_category]);
if ($category !== false) {
$access = true;
if (!$admin) {
if ($category['access'] > $yourAccess) $access = false;
if ($category['guild_id'] > 0) {
$status = false;
foreach($charData as $char) {
if ($char['guild'] == $category['guild_id']) $status = true;
}
if (!$status) $access = false;
}
if ($category['closed'] > 0) $access = false;
}
if ($access) {
?>
= t('forum.create_thread_new') ?>
'. t('forum.perm_thread'). ' ';
}
} else
/////////////////////
// When category is specified
if ($getCat !== false) {
$getCat = (int)$getCat;
// Fetch category rules
$category = db()->fetchOne("SELECT `name`, `access`, `closed`, `hidden`, `guild_id` FROM `znote_forum` WHERE `id` = ? AND `access` <= ? LIMIT 1;", [$getCat, $yourAccess]);
if ($category !== false && $category['guild_id'] > 0 && !$admin) {
$access = false;
foreach($charData as $char) if ($category['guild_id'] == $char['guild']) $access = true;
if ($access !== true) $category = false;
}
if ($category !== false) {
$getCatInt = (int)$getCat;
echo '' . t('forum.boards') . ' / ' . znote_forum_e($category['name']) . ' ';
echo '
' . znote_forum_e($category['name']) . ' ';
$threads = db()->fetchAll(
"SELECT `t`.`id`, `t`.`player_name`, `t`.`title`, `t`.`sticky`, `t`.`closed`, `t`.`created`, `t`.`updated`, "
. "COUNT(`p`.`id`) AS `reply_count`, COALESCE(MAX(`p`.`created`), 0) AS `last_reply_at` "
. "FROM `znote_forum_threads` `t` LEFT JOIN `znote_forum_posts` `p` ON `p`.`thread_id` = `t`.`id` "
. "WHERE `t`.`forum_id` = ? "
. "GROUP BY `t`.`id`, `t`.`player_name`, `t`.`title`, `t`.`sticky`, `t`.`closed`, `t`.`created`, `t`.`updated` "
. "ORDER BY `t`.`sticky` DESC, `t`.`updated` DESC;",
[$getCatInt]
);
$lastReplyBy = array();
$lrRows = db()->fetchAll(
"SELECT `x`.`thread_id`, `x`.`player_name` FROM `znote_forum_posts` `x` JOIN ("
. "SELECT `p2`.`thread_id`, MAX(`p2`.`created`) AS `mc` FROM `znote_forum_posts` `p2` "
. "JOIN `znote_forum_threads` `t2` ON `t2`.`id` = `p2`.`thread_id` WHERE `t2`.`forum_id` = ? "
. "GROUP BY `p2`.`thread_id`) `y` ON `y`.`thread_id` = `x`.`thread_id` AND `y`.`mc` = `x`.`created`;",
[$getCatInt]
);
foreach ((array)$lrRows as $row) if (!isset($lastReplyBy[$row['thread_id']])) $lastReplyBy[$row['thread_id']] = $row['player_name'];
$visibleThreads = array();
foreach ((array)$threads as $thread) {
$access = true;
if ($category['hidden'] == 1) {
$access = PlayerHaveAccess($yourChars, $thread['player_name']);
if ($yourAccess > 3 || $admin) $access = true;
}
if ($access) $visibleThreads[] = $thread;
}
?>
$e($thread['player_name']), 'ago' => znote_forum_ago($thread['created']))); ?>
0
? t('forum.last_by', array('name' => $e($replyBy), 'ago' => znote_forum_ago($thread['last_reply_at'])))
: t('forum.no_replies'); ?>
0) {
if ($category['closed'] == 0 || $admin) {
?>
'. t('forum.board_closed'). '';
} else echo ''. t('forum.level_required_new_thread', ['level' => (int)$config['forum']['level']]) .'
';
} else echo ''. t('forum.board_access_denied', ['level' => (int)$config['forum']['level']]) .'
';
}
} else {
//////////////////////
// No category specified, show list of available categories
$boardWhereParams = [];
if ($admin) {
$boardWhere = '';
} else {
$boardWhere = " WHERE `f`.`access` <= ?";
$boardWhereParams[] = (int)$yourAccess;
}
$categories = db()->fetchAll(
"SELECT `f`.`id`, `f`.`name`, `f`.`access`, `f`.`closed`, `f`.`hidden`, `f`.`guild_id`, "
. "COUNT(`t`.`id`) AS `thread_count`, COALESCE(MAX(`t`.`updated`), 0) AS `last_time` "
. "FROM `znote_forum` `f` LEFT JOIN `znote_forum_threads` `t` ON `t`.`forum_id` = `f`.`id`"
. $boardWhere
. " GROUP BY `f`.`id`, `f`.`name`, `f`.`access`, `f`.`closed`, `f`.`hidden`, `f`.`guild_id` ORDER BY `f`.`name`;",
$boardWhereParams
);
$lastThreads = array();
$ltRows = db()->fetchAll(
"SELECT `x`.`forum_id`, `x`.`player_name`, `x`.`title`, `x`.`id` FROM `znote_forum_threads` `x` "
. "JOIN (SELECT `forum_id`, MAX(`updated`) AS `mu` FROM `znote_forum_threads` GROUP BY `forum_id`) `y` "
. "ON `y`.`forum_id` = `x`.`forum_id` AND `y`.`mu` = `x`.`updated`;"
);
foreach ((array)$ltRows as $row) if (!isset($lastThreads[$row['forum_id']])) $lastThreads[$row['forum_id']] = $row;
$guild = false;
foreach ($charData as $char) if ($char['guild'] > 0) $guild = true;
if (!isset($guilds)) {
$guilds = db()->fetchAll("SELECT `id`, `name` FROM `guilds` ORDER BY `name`;");
$guilds[] = array('id' => '0', 'name' => 'No guild');
}
$guildName = array();
foreach ((array)$guilds as $g) $guildName[$g['id']] = $g['name'];
$mainBoards = array();
$guildboard = array();
foreach ((array)$categories as $b) {
$li = $lastThreads[$b['id']] ?? null;
$b['last_author'] = $li['player_name'] ?? '';
$b['last_title'] = $li['title'] ?? '';
if ((int)$b['guild_id'] > 0) {
$inGuild = $admin;
foreach ($charData as $char) if ((int)$b['guild_id'] === (int)$char['guild']) $inGuild = true;
if ($inGuild) $guildboard[] = $b;
} else {
$mainBoards[] = $b;
}
}
$znfBoardRow = static function (array $b) use ($admin, $guildName) {
$e = 'znote_forum_e';
$id = (int)$b['id'];
?>
0 ? '⚔' : '💬'; ?>
0): ?>
· ·
';
theme_close(); ?>