mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
Implement VM object retrieval and enhance game visuals
- Added `vm_object` method in `mission.rb` to fetch VM details from context or return a fallback. - Introduced new images for VM launchers and flag stations in the assets directory. - Updated `game.js` to preload new VM launcher and flag station images. - Refactored `vm-launcher-minigame.js` to streamline VM handling and improve UI messaging. - Adjusted scenario JSON to utilize the new `vm_object` method for VM data retrieval.
This commit is contained in:
@@ -114,6 +114,17 @@ module BreakEscape
|
||||
|
||||
attr_reader :random_password, :random_pin, :random_code, :vm_context
|
||||
|
||||
# Get a VM from the context by title, or return a fallback VM object
|
||||
# Usage in ERB:
|
||||
# "vm": <%= vm_object('kali', {"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}) %>
|
||||
def vm_object(title, fallback = {})
|
||||
if vm_context && vm_context['hacktivity_mode'] && vm_context['vms']
|
||||
vm = vm_context['vms'].find { |v| v['title'] == title }
|
||||
return vm.to_json if vm
|
||||
end
|
||||
fallback.to_json
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
|
||||
BIN
public/break_escape/assets/objects/flag-station.png
Normal file
BIN
public/break_escape/assets/objects/flag-station.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 427 B |
BIN
public/break_escape/assets/objects/vm-launcher-desktop.png
Normal file
BIN
public/break_escape/assets/objects/vm-launcher-desktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 672 B |
BIN
public/break_escape/assets/objects/vm-launcher-kali.png
Normal file
BIN
public/break_escape/assets/objects/vm-launcher-kali.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 708 B |
BIN
public/break_escape/assets/objects/vm-launcher.png
Normal file
BIN
public/break_escape/assets/objects/vm-launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 585 B |
@@ -364,6 +364,12 @@ export function preload() {
|
||||
this.load.image('pc11', 'objects/pc11.png');
|
||||
this.load.image('pc12', 'objects/pc12.png');
|
||||
|
||||
// VMs Launchers and Flag Stations
|
||||
this.load.image('vm-launcher', 'objects/vm-launcher.png');
|
||||
this.load.image('vm-launcher-kali', 'objects/vm-launcher-kali.png');
|
||||
this.load.image('vm-launcher-desktop', 'objects/vm-launcher-desktop.png');
|
||||
this.load.image('flag-station', 'objects/flag-station.png');
|
||||
|
||||
|
||||
// Laptops
|
||||
this.load.image('laptop7', 'objects/laptop7.png');
|
||||
|
||||
@@ -12,9 +12,8 @@ import { MinigameScene } from '../framework/base-minigame.js';
|
||||
export class VmLauncherMinigame extends MinigameScene {
|
||||
constructor(container, params) {
|
||||
super(container, params);
|
||||
this.vms = params.vms || [];
|
||||
this.vm = params.vm || null;
|
||||
this.hacktivityMode = params.hacktivityMode || false;
|
||||
this.selectedVm = null;
|
||||
this.isLaunching = false;
|
||||
}
|
||||
|
||||
@@ -243,22 +242,22 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
const launcher = document.createElement('div');
|
||||
launcher.className = 'vm-launcher';
|
||||
|
||||
if (this.vms.length === 0) {
|
||||
launcher.innerHTML = this.buildNoVmsMessage();
|
||||
if (!this.vm) {
|
||||
launcher.innerHTML = this.buildNoVmMessage();
|
||||
} else {
|
||||
launcher.innerHTML = this.buildVmList();
|
||||
launcher.innerHTML = this.buildVmDisplay();
|
||||
}
|
||||
|
||||
this.gameContainer.appendChild(launcher);
|
||||
this.attachEventHandlers();
|
||||
}
|
||||
|
||||
buildNoVmsMessage() {
|
||||
buildNoVmMessage() {
|
||||
if (this.hacktivityMode) {
|
||||
return `
|
||||
<div class="no-vms-message">
|
||||
<h4>No VMs Available</h4>
|
||||
<p>No virtual machines are configured for this mission.</p>
|
||||
<h4>No VM Available</h4>
|
||||
<p>No virtual machine is configured for this terminal.</p>
|
||||
<p>Please provision VMs through Hacktivity first.</p>
|
||||
</div>
|
||||
`;
|
||||
@@ -266,85 +265,59 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
return `
|
||||
<div class="no-vms-message standalone-mode">
|
||||
<h2>VM Terminal</h2>
|
||||
<p>You've discovered a computer terminal in the game. To interact with it, you need to launch the virtual machines on your local system.</p>
|
||||
${this.buildStandaloneInstructions()}
|
||||
<p>You've discovered a computer terminal in the game. To interact with it, you need to launch the virtual machine on your local system.</p>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
buildVmList() {
|
||||
const description = this.hacktivityMode
|
||||
? 'Select a VM to open its console. A SPICE viewer file will be downloaded.'
|
||||
: 'These VMs are available for this mission.';
|
||||
|
||||
let html = `
|
||||
<p class="vm-launcher-description">${description}</p>
|
||||
<div class="vm-list">
|
||||
`;
|
||||
|
||||
for (const vm of this.vms) {
|
||||
const hasConsole = vm.enable_console !== false;
|
||||
const statusClass = hasConsole ? 'console' : 'online';
|
||||
const statusText = hasConsole ? 'Console' : 'Active';
|
||||
|
||||
buildVmDisplay() {
|
||||
const hasConsole = this.vm.enable_console !== false;
|
||||
const statusClass = hasConsole ? 'console' : 'online';
|
||||
const statusText = hasConsole ? 'Console' : 'Active';
|
||||
let html = `<p>You've discovered a computer terminal in the game. To interact with it, `
|
||||
|
||||
if (this.hacktivityMode) {
|
||||
html += `
|
||||
<div class="vm-card" data-vm-id="${vm.id}">
|
||||
<div class="vm-header">
|
||||
<span class="vm-title">${this.escapeHtml(vm.title)}</span>
|
||||
<span class="vm-status ${statusClass}">${statusText}</span>
|
||||
</div>
|
||||
<div class="vm-details">
|
||||
${vm.ip ? `<span><span class="vm-detail-label">IP:</span> <span class="vm-ip">${this.escapeHtml(vm.ip)}</span></span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
click the console button, and follow the instructions.</p>
|
||||
`;
|
||||
} else {
|
||||
html += `
|
||||
you need to launch the virtual machine on your local system.</p>
|
||||
`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += `
|
||||
|
||||
<div class="vm-card">
|
||||
<div class="vm-header">
|
||||
<span class="vm-title">${this.escapeHtml(this.vm.title)}</span>
|
||||
<span class="vm-status ${statusClass}">${statusText}</span>
|
||||
</div>
|
||||
<div class="vm-details">
|
||||
${this.vm.ip ? `<span><span class="vm-detail-label">IP:</span> <span class="vm-ip">${this.escapeHtml(this.vm.ip)}</span></span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (this.hacktivityMode) {
|
||||
html += `
|
||||
<div class="vm-actions">
|
||||
<button class="vm-action-btn" id="launch-console-btn" disabled>
|
||||
Select a VM
|
||||
<button class="vm-action-btn" id="launch-console-btn">
|
||||
Open Console: ${this.escapeHtml(this.vm.title)}
|
||||
</button>
|
||||
</div>
|
||||
<div class="launch-status" id="launch-status"></div>
|
||||
`;
|
||||
} else {
|
||||
html += this.buildStandaloneInstructions();
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
buildStandaloneInstructions() {
|
||||
return `
|
||||
<div class="standalone-instructions">
|
||||
<h3>Load These VMs in VirtualBox:</h3>
|
||||
<div class="vm-names">
|
||||
<div class="vm-name-badge">kali</div>
|
||||
<div class="vm-name-badge">desktop</div>
|
||||
</div>
|
||||
<ol>
|
||||
<li>Open VirtualBox on your local machine</li>
|
||||
<li>Import the <strong>kali</strong> and <strong>desktop</strong> VMs (.ova files)</li>
|
||||
<li>Start both VMs and wait for them to boot</li>
|
||||
<li>Note their IP addresses</li>
|
||||
<li>Return to this game to complete the mission</li>
|
||||
</ol>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
attachEventHandlers() {
|
||||
// VM card selection
|
||||
const vmCards = this.gameContainer.querySelectorAll('.vm-card');
|
||||
vmCards.forEach(card => {
|
||||
this.addEventListener(card, 'click', () => this.selectVm(card));
|
||||
});
|
||||
|
||||
// Launch button (Hacktivity mode only)
|
||||
const launchBtn = this.gameContainer.querySelector('#launch-console-btn');
|
||||
if (launchBtn) {
|
||||
@@ -352,33 +325,13 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
}
|
||||
}
|
||||
|
||||
selectVm(card) {
|
||||
if (this.isLaunching) return;
|
||||
|
||||
// Clear previous selection
|
||||
this.gameContainer.querySelectorAll('.vm-card').forEach(c => {
|
||||
c.classList.remove('selected');
|
||||
});
|
||||
|
||||
// Select new card
|
||||
card.classList.add('selected');
|
||||
this.selectedVm = this.vms.find(vm => vm.id == card.dataset.vmId);
|
||||
|
||||
// Update launch button
|
||||
const launchBtn = this.gameContainer.querySelector('#launch-console-btn');
|
||||
if (launchBtn && this.selectedVm) {
|
||||
launchBtn.disabled = false;
|
||||
launchBtn.textContent = `Open Console: ${this.selectedVm.title}`;
|
||||
}
|
||||
}
|
||||
|
||||
async launchConsole() {
|
||||
if (!this.selectedVm || this.isLaunching) return;
|
||||
if (!this.vm || this.isLaunching) return;
|
||||
|
||||
this.isLaunching = true;
|
||||
const launchBtn = this.gameContainer.querySelector('#launch-console-btn');
|
||||
const statusEl = this.gameContainer.querySelector('#launch-status');
|
||||
const vmCard = this.gameContainer.querySelector(`[data-vm-id="${this.selectedVm.id}"]`);
|
||||
const vmCard = this.gameContainer.querySelector('.vm-card');
|
||||
|
||||
launchBtn.disabled = true;
|
||||
launchBtn.classList.add('launching');
|
||||
@@ -391,8 +344,8 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
if (window.hacktivityCable) {
|
||||
// Use ActionCable integration
|
||||
const result = await window.hacktivityCable.requestConsoleFile(
|
||||
this.selectedVm.id,
|
||||
this.selectedVm.event_id
|
||||
this.vm.id,
|
||||
this.vm.event_id
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
@@ -416,7 +369,7 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
this.isLaunching = false;
|
||||
launchBtn.disabled = false;
|
||||
launchBtn.classList.remove('launching');
|
||||
launchBtn.textContent = `Open Console: ${this.selectedVm.title}`;
|
||||
launchBtn.textContent = `Open Console: ${this.vm.title}`;
|
||||
vmCard.classList.remove('launching');
|
||||
}
|
||||
}
|
||||
@@ -429,7 +382,7 @@ export class VmLauncherMinigame extends MinigameScene {
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
console.log('[VmLauncher] Started with', this.vms.length, 'VMs');
|
||||
console.log('[VmLauncher] Started with VM:', this.vm?.title || 'None');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -633,13 +633,13 @@ export function handleObjectInteraction(sprite) {
|
||||
if (sprite.scenarioData.type === "vm-launcher" || sprite.scenarioData.type === "vm_launcher") {
|
||||
console.log('VM Launcher interaction:', sprite.scenarioData);
|
||||
if (window.MinigameFramework) {
|
||||
// Get VM data from scenario or gameConfig
|
||||
const vms = sprite.scenarioData.vms || window.gameConfig?.vms || [];
|
||||
const hacktivityMode = sprite.scenarioData.hacktivityMode || window.gameConfig?.hacktivityMode || false;
|
||||
// Get VM data from scenario
|
||||
const vm = sprite.scenarioData.vm || null;
|
||||
const hacktivityMode = sprite.scenarioData.hacktivityMode || window.breakEscapeConfig?.hacktivityMode || false;
|
||||
|
||||
window.MinigameFramework.startMinigame('vm-launcher', null, {
|
||||
title: sprite.scenarioData.name || 'VM Console Access',
|
||||
vms: vms,
|
||||
vm: vm,
|
||||
hacktivityMode: hacktivityMode,
|
||||
stationId: sprite.scenarioData.id || sprite.objectId
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"takeable": false,
|
||||
"observations": "A terminal interface for accessing the Kali Linux VM. Ready to launch.",
|
||||
"hacktivityMode": <%= vm_context && vm_context['hacktivity_mode'] ? 'true' : 'false' %>,
|
||||
"vms": <%= vm_context && vm_context['vms'] ? vm_context['vms'].to_json : '[{"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}]' %>
|
||||
"vm": <%= vm_object('kali', {"id":1,"title":"kali","ip":"192.168.1.10","enable_console":true}) %>
|
||||
},
|
||||
{
|
||||
"type": "vm-launcher",
|
||||
@@ -53,7 +53,7 @@
|
||||
"takeable": false,
|
||||
"observations": "A terminal interface for accessing the Desktop Linux VM. Ready to launch.",
|
||||
"hacktivityMode": <%= vm_context && vm_context['hacktivity_mode'] ? 'true' : 'false' %>,
|
||||
"vms": <%= vm_context && vm_context['vms'] ? vm_context['vms'].to_json : '[{"id":2,"title":"desktop","ip":"192.168.1.20","enable_console":true}]' %>
|
||||
"vm": <%= vm_object('desktop', {"id":2,"title":"desktop","ip":"192.168.1.20","enable_console":true}) %>
|
||||
},
|
||||
{
|
||||
"type": "notes",
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user