Hint for first part
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
/* Game1 entry point built with Webpack Encore */
|
||||
import './styles/game1.css';
|
||||
|
||||
let sequenceFinished = false;
|
||||
let stillPlayingSound = true;
|
||||
|
||||
function subscribeToMercure(mercurePublicUrl, topic) {
|
||||
try {
|
||||
const url = mercurePublicUrl + '?topic=' + encodeURIComponent(topic);
|
||||
@@ -10,6 +13,25 @@ function subscribeToMercure(mercurePublicUrl, topic) {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('[Mercure][game1] Update:', data);
|
||||
|
||||
// data is [sendTo, message]
|
||||
if (Array.isArray(data) && data.length >= 2) {
|
||||
const messageContainer = document.getElementById('message-container');
|
||||
if (messageContainer) {
|
||||
const msgEl = document.createElement('div');
|
||||
msgEl.className = 'message';
|
||||
msgEl.textContent = data[1];
|
||||
msgEl.style.color = '#0F0'; // Green for incoming messages
|
||||
msgEl.style.marginBottom = '10px';
|
||||
messageContainer.appendChild(msgEl);
|
||||
if(stillPlayingSound)
|
||||
playSound();
|
||||
console.log('[Mercure][game1] sequenceFinished status:', sequenceFinished);
|
||||
if (sequenceFinished) {
|
||||
flashRed();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Mercure][game1] Raw event:', event.data);
|
||||
}
|
||||
@@ -25,6 +47,28 @@ function subscribeToMercure(mercurePublicUrl, topic) {
|
||||
}
|
||||
}
|
||||
|
||||
function playSound() {
|
||||
const sound = document.getElementById('message-sound');
|
||||
if (sound) {
|
||||
sound.currentTime = 0;
|
||||
sound.play().catch(e => console.warn('[Audio] Playback failed:', e));
|
||||
}
|
||||
}
|
||||
|
||||
function flashRed() {
|
||||
console.log('[Game1] Triggering flashRed');
|
||||
const body = document.body;
|
||||
body.classList.remove('flash-red');
|
||||
void body.offsetWidth; // Trigger reflow to restart animation
|
||||
body.classList.add('flash-red');
|
||||
|
||||
// Also remove it after animation finishes so it's clean for inspection
|
||||
setTimeout(() => {
|
||||
body.classList.remove('flash-red');
|
||||
console.log('[Game1] Removed flash-red class');
|
||||
}, 150);
|
||||
}
|
||||
|
||||
async function fetchJson(url, options = {}) {
|
||||
const opts = { ...options };
|
||||
const headers = new Headers(opts.headers || {});
|
||||
@@ -125,16 +169,26 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
const printNextMessage = () => {
|
||||
if (currentMessageIndex < messages.length) {
|
||||
|
||||
const msg = messages[currentMessageIndex];
|
||||
const msgEl = document.createElement('div');
|
||||
msgEl.className = 'message';
|
||||
|
||||
let extraClass = '';
|
||||
if(msg[2])
|
||||
extraClass = msg[2];
|
||||
|
||||
msgEl.className = 'message ' + extraClass;
|
||||
msgEl.textContent = msg[0];
|
||||
msgEl.style.color = '#F00';
|
||||
msgEl.style.marginBottom = '10px';
|
||||
messageContainer.appendChild(msgEl);
|
||||
|
||||
playSound();
|
||||
|
||||
currentMessageIndex++;
|
||||
setTimeout(printNextMessage, msg[1]);
|
||||
if (sequenceFinished) {
|
||||
flashRed();
|
||||
}
|
||||
} else {
|
||||
// After it has printed a set of messages, it has to start a timer of 2 seconds
|
||||
console.log('[Game1] All messages printed. Starting 2s timer to expand message-container height...');
|
||||
@@ -146,6 +200,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Add event listener for Enter key
|
||||
inputField.addEventListener('keypress', async (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
stillPlayingSound = false;
|
||||
sequenceFinished = false;
|
||||
const message = inputField.value.trim();
|
||||
if (message && apiEchoUrl) {
|
||||
inputField.value = '';
|
||||
@@ -163,6 +219,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
|
||||
console.log('[Game1] message-container height changed to 400vh and input enabled');
|
||||
sequenceFinished = true;
|
||||
console.log('[Game1] sequenceFinished is now TRUE');
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,6 +47,10 @@ div#message-container {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div.message {
|
||||
color: #C0C0C0;
|
||||
}
|
||||
|
||||
div#input {
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -54,10 +58,32 @@ div#input {
|
||||
input#input-message {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #000;
|
||||
border: 1px solid #F00;
|
||||
color: #F00;
|
||||
background: #111;
|
||||
border: 1px solid #A00000;
|
||||
color: #C0C0C0;
|
||||
font-size: 18px;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.flash-red::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100px;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(to top, rgba(255, 0, 0, 0.8), transparent);
|
||||
animation: flash-red-anim 0.1s linear forwards;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
@keyframes flash-red-anim {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/audio/message.mp3
Normal file
BIN
public/audio/message.mp3
Normal file
Binary file not shown.
@@ -8,6 +8,8 @@ use App\Game\Entity\Player;
|
||||
use App\Game\Repository\SessionSettingRepository;
|
||||
use App\Tech\Entity\User;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\Mercure\HubInterface;
|
||||
use Symfony\Component\Mercure\Update;
|
||||
|
||||
class GameResponseService
|
||||
{
|
||||
@@ -15,10 +17,11 @@ class GameResponseService
|
||||
private Security $security,
|
||||
private PlayerService $playerService,
|
||||
private SessionSettingRepository $sessionSettingRepository,
|
||||
private HubInterface $hub,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getGameResponse(string $raw)
|
||||
public function getGameResponse(string $raw) : array
|
||||
{
|
||||
$info = json_decode($raw, true);
|
||||
|
||||
@@ -83,8 +86,10 @@ class GameResponseService
|
||||
if(!in_array('chat', $rechten))
|
||||
return ['result' => ['Unknown command']];
|
||||
|
||||
$this->handleChatMessage($message);
|
||||
break;
|
||||
if($this->handleChatMessage($message, $player))
|
||||
return ['result' => ['succesfully send']];
|
||||
else
|
||||
return ['result' => ['Error sending']];
|
||||
case '/help':
|
||||
return ['result' => $this->getHelpCommand($rechten)];
|
||||
case '/decode':
|
||||
@@ -101,7 +106,6 @@ class GameResponseService
|
||||
default:
|
||||
return ['result' => ['Unknown command']];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private function checkConsoleCommando(string $message, Player $player, bool $sudo = false) : array
|
||||
@@ -124,6 +128,9 @@ class GameResponseService
|
||||
|
||||
$this->playerService->saveCurrentPwdOfPlayer($player, $newLocation);
|
||||
return ['result' => ['Path: ' . $newLocation]];
|
||||
case 'pwd':
|
||||
$pwd = $this->playerService->getCurrentPwdOfPlayer($player);
|
||||
return ['result' => ['Path: ' . $pwd]];
|
||||
case 'rm':
|
||||
break;
|
||||
case 'sudo':
|
||||
@@ -161,6 +168,13 @@ class GameResponseService
|
||||
$messages[] = ' USAGE: /decode {message}';
|
||||
$messages[] = '';
|
||||
break;
|
||||
case 'pwd':
|
||||
$messages[] = 'pwd';
|
||||
$messages[] = ' This message will let you know what your current location is.';
|
||||
$messages[] = ' It will show you the folder you are in so you can continue navigating the server.';
|
||||
$messages[] = ' USAGE: pwd';
|
||||
$messages[] = '';
|
||||
break;
|
||||
case 'cat':
|
||||
$messages[] = 'cat';
|
||||
$messages[] = ' To read a file, use cat {filename}.';
|
||||
@@ -210,9 +224,42 @@ class GameResponseService
|
||||
return $messages;
|
||||
}
|
||||
|
||||
private function handleChatMessage(string $message)
|
||||
private function handleChatMessage(string $message, Player $player) : bool
|
||||
{
|
||||
$messageParts = explode(' ', $message);
|
||||
$toSingle = false;
|
||||
|
||||
if (isset($messageParts[1]) &&
|
||||
is_numeric($messageParts[1]) &&
|
||||
$messageParts[1] >= 1 &&
|
||||
$messageParts[1] <= 3) {
|
||||
|
||||
$toSingle = true;
|
||||
}
|
||||
|
||||
$chatMessage = array_shift($messageParts);
|
||||
$sendTo = 0;
|
||||
|
||||
if ($toSingle) {
|
||||
$sendTo = array_shift($messageParts);
|
||||
}
|
||||
|
||||
$message = $player->getUser()->getUsername() . ': ' . $chatMessage;
|
||||
foreach($messageParts as $messagePart) {
|
||||
$message .= $messagePart . ' ';
|
||||
}
|
||||
|
||||
$message = trim($message);
|
||||
|
||||
$activeGame = $player->getSession()?->getId();
|
||||
|
||||
if(is_null($activeGame))
|
||||
return false;
|
||||
|
||||
$topic = $_ENV['MERCURE_TOPIC_BASE'] . '/game/hub-' . $activeGame;
|
||||
$this->hub->publish(new Update($topic, json_encode([$sendTo, $message])));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function handleDecodeMessage(string $message, Player $player)
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
<div id="game-container">
|
||||
<div id="mercure-config"
|
||||
data-mercure-public-url="{{ mercure_public_url|e('html_attr') }}"
|
||||
data-topic="{{ (mercure_topic_base ~ '/game/hub')|e('html_attr') }}"
|
||||
data-topic="{{ (mercure_topic_base ~ '/game/hub-' ~ session.id)|e('html_attr') }}"
|
||||
data-api-ping-url="{{ path('game_api_ping')|e('html_attr') }}"
|
||||
data-api-echo-url="{{ path('game_api_message')|e('html_attr') }}"
|
||||
data-user-id="{{ user_id|e('html_attr') }}"
|
||||
style="display:none">
|
||||
</div>
|
||||
|
||||
@@ -28,6 +27,9 @@
|
||||
<div id="message-container">
|
||||
|
||||
</div>
|
||||
<audio id="message-sound" style="display:none">
|
||||
<source src="{{ asset('audio/message.mp3') }}" type="audio/mpeg">
|
||||
</audio>
|
||||
<div id="input">
|
||||
<input type="text" disabled id="input-message">
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user