Remove old scenario selection HTML and testing guide files

This commit is contained in:
Z. Cliffe Schreuders
2026-02-10 12:02:22 +00:00
parent dbede74035
commit 6ad3cda6ae
2 changed files with 0 additions and 719 deletions

View File

@@ -1,295 +0,0 @@
# Global Ink Variables - Testing Guide
## Quick Start Test
### Prerequisites
- Open the game with the `npc-sprite-test2.json` scenario
- Browser console open (F12)
### Test 1: Basic Functionality
1. **Verify Initial State**
```javascript
console.log(window.gameState.globalVariables);
// Should show: { player_joined_organization: false }
```
2. **Start conversation with test_npc_back**
- Click on the back NPC in test_room
- Follow the conversation through to "player_closing"
3. **Make the Join Choice**
- Select "I'd love to join your organization!"
- Observe NPC response
4. **Check Global State**
```javascript
console.log(window.gameState.globalVariables.player_joined_organization);
// Should now be: true
```
### Test 2: Cross-NPC Syncing
1. **Start conversation with container_test_npc (Equipment Officer)**
- Click on the equipment officer NPC
- Start conversation
2. **Observe Menu Options**
- If you joined in Test 1, you should see:
- "Tell me about your equipment"
- **"Show me what you have available"** ← This should appear!
- "Show me your specialist items"
- If you didn't join, only the specialist items option appears
3. **Verify Variable Synced**
```javascript
console.log(window.gameState.globalVariables.player_joined_organization);
// Still true from previous conversation!
```
### Test 3: Direct Phaser Access
1. **Open Console**
2. **Directly Set Variable**
```javascript
window.gameState.globalVariables.player_joined_organization = false;
```
3. **Start new conversation with Equipment Officer**
- Full inventory option should now be GONE
- Only specialist items option appears
4. **Set Back to True**
```javascript
window.gameState.globalVariables.player_joined_organization = true;
```
5. **Start conversation again**
- Full inventory option should reappear
### Test 4: State Persistence
1. **Join organization** (if not already done)
- Complete the test_npc_back conversation
- Choose to join
2. **Talk to Equipment Officer**
- Verify full inventory option is available
3. **End conversation**
- Close the minigame
4. **Reload the page** (F5)
- Wait for game to fully load
5. **Check Global State**
```javascript
console.log(window.gameState.globalVariables.player_joined_organization);
// Should still be true!
```
6. **Talk to Equipment Officer again**
- Full inventory option should still appear
## Debugging Checks
### Verify Scenario Loaded
```javascript
console.log(window.gameScenario.globalVariables);
// Should show: { player_joined_organization: false }
```
### Check All Global Variables
```javascript
console.log('Global Variables:', window.gameState.globalVariables);
console.log('NPC Cache:', Array.from(window.npcManager.inkEngineCache.keys()));
console.log('Saved States:', window.npcConversationStateManager.getSavedNPCs());
```
### Check Variable Change Events
Add this before starting a conversation:
```javascript
// Temporarily enable verbose logging
window.npcConversationStateManager._log = (level, msg, data) => {
console.log(`[${level}]`, msg, data);
};
```
Then start a conversation and watch the console for variable sync messages.
### Verify Ink Variable Names
```javascript
// Check what variables are in test2.ink story
const test2Engine = window.npcManager.inkEngineCache.get('test_npc_back');
if (test2Engine?.story?.variablesState?._defaultGlobalVariables) {
console.log('test2.ink variables:',
Array.from(test2Engine.story.variablesState._defaultGlobalVariables.keys()));
}
// Check equipment officer
const eqEngine = window.npcManager.inkEngineCache.get('container_test_npc');
if (eqEngine?.story?.variablesState?._defaultGlobalVariables) {
console.log('equipment-officer.ink variables:',
Array.from(eqEngine.story.variablesState._defaultGlobalVariables.keys()));
}
```
## Expected Console Output
When everything is working correctly, you should see messages like:
```
🌐 Initialized global variables: {player_joined_organization: false}
✅ Synced player_joined_organization = false to story
🔍 Auto-discovered global variable: player_joined_organization = false
🌐 Global variable changed: player_joined_organization = true (from test_npc_back)
📡 Broadcasted player_joined_organization = true to container_test_npc
✅ Restored global variables: {player_joined_organization: true}
```
## Common Issues & Solutions
### Issue: Full inventory option never appears
**Check:**
1. Did you actually choose "Join organization"?
```javascript
console.log(window.gameState.globalVariables.player_joined_organization);
```
2. Did the Equipment Officer conversation load?
```javascript
console.log(window.npcManager.inkEngineCache.has('container_test_npc'));
```
3. Are the stories properly synced?
```javascript
const eqStory = window.npcManager.inkEngineCache.get('container_test_npc').story;
console.log('Eq Officer has variable:', eqStory.variablesState.GlobalVariableExistsWithName('player_joined_organization'));
console.log('Value:', eqStory.variablesState['player_joined_organization']);
```
### Issue: Variable resets on page reload
**Check:**
1. Was state actually saved?
```javascript
console.log(window.npcConversationStateManager.getNPCState('test_npc_back'));
```
2. Does saved state have global snapshot?
```javascript
const state = window.npcConversationStateManager.getNPCState('test_npc_back');
console.log('Global snapshot:', state?.globalVariablesSnapshot);
```
### Issue: Changes not syncing to other NPCs
**Check:**
1. Are multiple stories loaded?
```javascript
console.log('Loaded stories:', Array.from(window.npcManager.inkEngineCache.keys()));
```
2. Does the variable exist in both stories?
```javascript
// Check each story's variables
window.npcManager.inkEngineCache.forEach((engine, id) => {
const exists = engine.story.variablesState.GlobalVariableExistsWithName('player_joined_organization');
console.log(`${id}: has player_joined_organization =`, exists);
});
```
## Advanced Testing
### Test Auto-Discovery of global_* Variables
1. Create a new Ink file with:
```ink
VAR global_test_flag = false
```
2. Add it to an NPC in scenario
3. Load that NPC's conversation
4. Check console:
```javascript
console.log(window.gameState.globalVariables);
// Should auto-discover: { player_joined_organization: false, global_test_flag: false }
```
### Test Modifying from Phaser Code
1. Get reference to game code:
```javascript
// In Phaser scene, emit an event
window.dispatchEvent(new CustomEvent('player-achievement', {
detail: { achievement: 'joined_org' }
}));
// In listener code:
window.addEventListener('player-achievement', (e) => {
window.gameState.globalVariables.player_joined_organization = true;
});
```
2. Start new NPC conversation
3. Verify variable is synced
### Test Multiple Global Variables
1. Update `npc-sprite-test2.json`:
```json
"globalVariables": {
"player_joined_organization": false,
"reputation": 0,
"quest_stage": 0
}
```
2. Add to Ink files:
```ink
VAR player_joined_organization = false
VAR reputation = 0
VAR quest_stage = 0
```
3. Use in conditionals:
```ink
{reputation >= 5:
You're well known around here
}
```
4. Test syncing multiple variables at once
## Success Criteria
✅ Initial state loads with correct defaults
✅ Variable changes persist in window.gameState
✅ Changes sync to other loaded stories in real-time
✅ Menu options conditionally appear based on variables
✅ State persists across page reloads
✅ Console shows appropriate sync messages
✅ No errors in browser console
✅ Multiple variables can be managed simultaneously
## Performance Notes
The system is optimized for:
- **Few global variables** (< 50 per scenario) ✅
- **Multiple NPCs** (handles all loaded stories) ✅
- **Event-driven syncing** (only syncs on change) ✅
- **No circular loops** (prevents infinite propagation) ✅
If testing with > 100 global variables, monitor console for any performance impact.

View File

@@ -1,424 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Office Adventure Game - Scenario Selection</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #333;
font-family: Arial, sans-serif;
color: white;
}
.container {
width: 80%;
max-width: 800px;
background: rgba(0, 0, 0, 0.7);
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5);
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #3498db;
}
.scenario-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.scenario-card {
background: #444;
border-radius: 5px;
padding: 20px;
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid #555;
}
.scenario-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
background: #4a4a4a;
}
.scenario-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
color: #3498db;
}
.scenario-description {
font-size: 14px;
color: #ccc;
margin-bottom: 15px;
line-height: 1.4;
}
.scenario-difficulty {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 12px;
font-weight: bold;
}
.difficulty-easy {
background: #2ecc71;
color: #fff;
}
.difficulty-medium {
background: #f39c12;
color: #fff;
}
.difficulty-hard {
background: #e74c3c;
color: #fff;
}
.back-button {
display: block;
margin: 30px auto 0;
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
}
.back-button:hover {
background: #2980b9;
}
.scenario-cybok {
margin-top: 10px;
margin-bottom: 15px;
font-size: 12px;
color: #aaa;
}
.cybok-title {
font-weight: bold;
margin-bottom: 5px;
color: #3498db;
}
.cybok-list {
margin: 0;
padding-left: 20px;
}
.cybok-list li {
margin-bottom: 3px;
}
.scenario-cybok-badges {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 10px;
margin-bottom: 15px;
}
.cybok-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
background: #2c3e50;
color: #fff;
cursor: help;
position: relative;
}
.cybok-badge:hover .cybok-tooltip {
display: block;
}
.cybok-tooltip {
display: none;
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.9);
color: #fff;
padding: 10px;
border-radius: 5px;
width: 250px;
z-index: 100;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
font-weight: normal;
font-size: 11px;
margin-bottom: 5px;
}
.cybok-tooltip:after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.9) transparent transparent transparent;
}
.cybok-tooltip-title {
font-weight: bold;
margin-bottom: 5px;
color: #3498db;
}
.cybok-tooltip-list {
margin: 0;
padding-left: 15px;
list-style-type: disc;
}
.cybok-tooltip-list li {
margin-bottom: 2px;
}
</style>
</head>
<body>
<div class="container">
<h1>Select a Scenario</h1>
<div class="scenario-list" id="scenario-list">
<!-- Scenarios will be loaded here dynamically -->
</div>
<button class="back-button" onclick="window.location.href='index.html'">Back to Main Game</button>
</div>
<script>
// List of available scenarios
const scenarios = [
{
id: "encoding_lab",
title: "Encoding and Encryption Lab",
description: "Recover your legendary cookie recipe from mischievous squirrels by solving various encoding and encryption challenges.",
difficulty: "beginner",
file: "scenarios/scenario4.json",
cybok: [
{ ka: "AC", topic: "Algorithms, Schemes and Protocols", keywords: ["Encoding vs Cryptography", "Caesar cipher", "Vigenere cipher", "SYMMETRIC CRYPTOGRAPHY - AES (ADVANCED ENCRYPTION STANDARD)"] },
{ ka: "F", topic: "Artifact Analysis", keywords: ["Encoding and alternative data formats"] },
{ ka: "WAM", topic: "Fundamental Concepts and Approaches", keywords: ["ENCODING", "BASE64"] }
]
},
{
id: "captain_meow",
title: "Captain Meow's Disappearance",
description: "Your beloved kitty sidekick, Captain Meow, has vanished without a trace! Follow the cryptic clues to find him before it's too late.",
difficulty: "medium",
file: "scenarios/scenario1.json",
cybok: [
{ ka: "F", topic: "Operating System Analysis", keywords: ["Steganography", "Encoding and alternative data formats", "SEARCH FOR EVIDENCE", "METADATA"] },
{ ka: "POR", topic: "Privacy Technologies and Democratic Values", keywords: ["METADATA", "STEGANOGRAPHY"] },
{ ka: "AC", topic: "Cryptographic Implementation", keywords: ["Cryptographic Libraries", "ENCRYPTION - TOOLS"] },
{ ka: "AC", topic: "Physical Security", keywords: ["Fingerprint Authentication", "Bluetooth Security", "Physical Locks"] },
{ ka: "AC", topic: "Hashing and Integrity", keywords: ["Hash Functions", "MD5 Hash"] },
{ ka: "AC", topic: "Encoding and Representation", keywords: ["Base64 Encoding", "Octal Encoding", "Hexadecimal (Hex) Encoding"] },
{ ka: "AC", topic: "Algorithms, Schemes and Protocols", keywords: ["ADVANCED ENCRYPTION STANDARD (AES)", "ECB (ELECTRONIC CODE BOOK) BLOCK CIPHER MODE"] }
]
},
{
"id": "ceo_exfil",
"title": "CEO Data Exfiltration",
"description": "Infiltrate the CEO's office and exfiltrate sensitive company data. You'll need to bypass physical security and find ways to access restricted areas.",
"difficulty": "medium",
"file": "scenarios/ceo_exfil.json",
"cybok": [
{ "ka": "F", "topic": "Artifact Analysis", "keywords": ["digital evidence", "document analysis"] },
{ "ka": "AAA", "topic": "Authorisation", "keywords": ["physical access control", "access control mechanisms"] },
{ "ka": "WAM", "topic": "Fundamental Concepts and Approaches", "keywords": ["BLUETOOTH SECURITY", "DEVICE PAIRING"] }
],
"cybok_themes": [
{ "ka": "LR", "topic": "Computer Crimes", "keywords": ["crimes against information systems", "evidence and proof", "CORPORATE ESPIONAGE"] },
{ "ka": "F", "topic": "Definitions and Conceptual Models", "keywords": ["forensic science", "digital (forensic) trace", "conceptual models"] }
]
},
{
"id": "cybok_heist",
"title": "CyBOK Heist: Recover the LaTeX Files",
"description": "You are a cybersecurity student tasked with recovering the Professor's backup of the CyBOK LaTeX source files for the CyBOK 1.1 release. Time to put your physical security skills to the test!",
"difficulty": "beginner",
"file": "scenarios/cybok_heist.json",
"cybok": [
{ "ka": "AC", "topic": "Cryptography", "keywords": ["Base64 encoding", "Password security"] },
{ "ka": "AAA", "topic": "Access Control", "keywords": ["Physical locks", "Key-based access", "PIN-based access"] },
{ "ka": "WAM", "topic": "Fundamental Concepts", "keywords": ["Knowledge Areas", "CyBOK Framework"] }
],
"cybok_themes": [
{ "ka": "F", "topic": "Artifact Analysis", "keywords": ["Physical security", "Security through obscurity"] },
{ "ka": "LR", "topic": "Ethical and Legal", "keywords": ["Educational security testing"] }
]
},
{
id: "asymmetric_encryption",
title: "Asymmetric Encryption with RSA",
description: "Solve cryptographic puzzles using RSA and Diffie-Hellman to escape from a cursed ghost town before you're turned into a llama!",
difficulty: "intermediate",
file: "scenarios/scenario2.json",
cybok: [
{ ka: "AC", topic: "Algorithms, Schemes and Protocols", keywords: ["CRYPTOGRAPHY - ASYMMETRIC - RSA", "DIFFIE-HELLMAN ALGORITHM"] },
{ ka: "AC", topic: "Public-Key Cryptography", keywords: ["public-key encryption", "public-key signatures", "RSA MODULUS", "RSA PROBLEM", "RSA TRANSFORM"] },
{ ka: "AC", topic: "Key Management", keywords: ["key generation"] },
{ ka: "AC", topic: "Cryptographic Implementation", keywords: ["Cryptographic Libraries", "ENCRYPTION - TOOLS"] }
]
},
{
id: "symmetric_encryption",
title: "Symmetric Encryption with AES",
description: "Recover Dr. Knowitall's time machine blueprints by solving AES encryption puzzles before the self-destruct sequence activates.",
difficulty: "intermediate",
file: "scenarios/scenario3.json",
cybok: [
{ ka: "AC", topic: "Algorithms, Schemes and Protocols", keywords: ["ADVANCED ENCRYPTION STANDARD (AES)", "ECB (ELECTRONIC CODE BOOK) BLOCK CIPHER MODE"] },
{ ka: "AC", topic: "Symmetric Cryptography", keywords: ["symmetric primitives", "symmetric encryption and authentication"] },
{ ka: "AC", topic: "Cryptographic Implementation", keywords: ["Cryptographic Libraries", "ENCRYPTION - TOOLS", "Hexadecimal Encoding"] }
]
},
{
"id": "biometric_breach",
"title": "Biometric Security Breach",
"description": "Test the company's biometric security systems by collecting and spoofing fingerprint data to gain unauthorized access.",
"difficulty": "hard",
"file": "scenarios/biometric_breach.json",
"cybok": [
{ "ka": "F", "topic": "Operating System Analysis", "keywords": ["Data acquisition", "BIOMETRIC ANALYSIS", "FINGERPRINT COLLECTION"] },
{ "ka": "SOIM", "topic": "Monitor: Data Sources", "keywords": ["SECURITY LOGS", "ACCESS LOG ANALYSIS"] },
{ "ka": "AAA", "topic": "Authorisation", "keywords": ["ACCESS CONTROL", "BIOMETRIC ACCESS CONTROLS", "IDENTITY VERIFICATION"] },
{ "ka": "SOIM", "topic": "Execute: Mitigation and Countermeasures", "keywords": ["INCIDENT RESPONSE", "EVIDENCE RECOVERY"] }
],
"cybok_themes": [
{ "ka": "LR", "topic": "Computer Crimes", "keywords": ["crimes against information systems", "evidence and proof", "INDUSTRIAL ESPIONAGE"] },
{ "ka": "AAA", "topic": "Authentication", "keywords": ["BIOMETRIC AUTHENTICATION", "identity management", "authentication in distributed systems"] },
{ "ka": "SOIM", "topic": "Human Factors: Incident Management", "keywords": ["incident response methodologies", "SECURITY INCIDENT INVESTIGATION"] }
]
}
];
// Function to create scenario cards
function createScenarioCards() {
const scenarioList = document.getElementById('scenario-list');
// CyBOK Knowledge Area abbreviation mapping
const cybokFullNames = {
"IC": "Introduction to CyBOK",
"FM": "Formal Methods",
"RMG": "Risk Management & Governance",
"LR": "Law & Regulation",
"HF": "Human Factors",
"POR": "Privacy & Online Rights",
"MAT": "Malware & Attack Technologies",
"AB": "Adversarial Behaviours",
"SOIM": "Security Operations & Incident Management",
"F": "Forensics",
"C": "Cryptography",
"AC": "Applied Cryptography",
"OSV": "Operating Systems & Virtualisation Security",
"DSS": "Distributed Systems Security",
"AAA": "Authentication, Authorisation and Accountability",
"SS": "Software Security",
"WAM": "Web & Mobile Security",
"SSL": "Secure Software Lifecycle",
"NS": "Network Security",
"HS": "Hardware Security",
"CPS": "Cyber Physical Systems",
"PLT": "Physical Layer and Telecommunications Security"
};
scenarios.forEach(scenario => {
const card = document.createElement('div');
card.className = 'scenario-card';
card.onclick = function() {
launchScenario(scenario.file);
};
const difficultyClass = `difficulty-${scenario.difficulty.toLowerCase()}`;
let cybokHTML = '';
if (scenario.cybok) {
// Group by Knowledge Area
const kaGroups = {};
scenario.cybok.forEach(item => {
if (!kaGroups[item.ka]) {
kaGroups[item.ka] = [];
}
kaGroups[item.ka].push(item);
});
const badgesHTML = Object.keys(kaGroups).map(ka => {
const topics = kaGroups[ka];
const kaFullName = cybokFullNames[ka] || ka;
const tooltipContent = `
<div class="cybok-tooltip-title">${kaFullName} Topics:</div>
<ul class="cybok-tooltip-list">
${topics.map(item => `
<li>
<strong>${item.topic}</strong>
<ul>
${item.keywords.map(keyword => `<li>${keyword}</li>`).join('')}
</ul>
</li>
`).join('')}
</ul>
`;
return `
<div class="cybok-badge">
CyBOK ${ka}
<div class="cybok-tooltip">
${tooltipContent}
</div>
</div>
`;
}).join('');
cybokHTML = `
<div class="scenario-cybok-badges">
${badgesHTML}
</div>
`;
}
card.innerHTML = `
<div class="scenario-title">${scenario.title}</div>
<div class="scenario-description">${scenario.description}</div>
${cybokHTML}
<div class="scenario-difficulty ${difficultyClass}">${scenario.difficulty.toUpperCase()}</div>
`;
scenarioList.appendChild(card);
});
}
// Function to launch the game with selected scenario
function launchScenario(scenarioFile) {
window.location.href = `index.html?scenario=${encodeURIComponent(scenarioFile)}`;
}
// Initialize the page
document.addEventListener('DOMContentLoaded', createScenarioCards);
</script>
</body>
</html>