<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Semiconductor Fab Tycoon - Pump Operations</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
background: linear-gradient(135deg, #0a0e27 0%, #16213e 100%);
color: #00ff00;
padding: 20px;
min-height: 100vh;
}
.header {
text-align: center;
margin-bottom: 30px;
border-bottom: 2px solid #00ff00;
padding-bottom: 15px;
}
.header h1 {
color: #00ff00;
text-shadow: 0 0 10px #00ff00;
margin-bottom: 5px;
font-size: 28px;
}
.facility-name {
color: #ffaa00;
font-size: 14px;
}
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 20px;
max-width: 1800px;
margin: 0 auto;
}
.panel {
background: rgba(0, 20, 40, 0.9);
border: 2px solid #00ff00;
border-radius: 5px;
padding: 20px;
box-shadow: 0 0 20px rgba(0, 255, 0, 0.3);
}
.pump-station {
display: flex;
flex-direction: column;
gap: 15px;
}
.pump-header {
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid #00ff00;
padding-bottom: 10px;
}
.pump-image {
width: 80px;
height: 80px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
border: 2px solid #00ff00;
border-radius: 3px;
flex-shrink: 0;
}
.pump-info {
flex: 1;
}
.pump-name {
font-size: 16px;
font-weight: bold;
color: #00ff00;
}
.pump-model {
font-size: 12px;
color: #ffaa00;
}
.pump-status {
font-size: 11px;
color: #aaa;
margin-top: 3px;
}
.status-healthy {
color: #00ff00;
}
.status-warning {
color: #ffaa00;
}
.status-critical {
color: #ff0000;
animation: blink 0.5s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0.5; }
}
.meters {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.meter {
background: rgba(0, 0, 0, 0.5);
border: 1px solid #00ff00;
border-radius: 3px;
padding: 10px;
}
.meter-label {
font-size: 10px;
color: #aaa;
margin-bottom: 5px;
text-transform: uppercase;
}
.meter-bar {
width: 100%;
height: 20px;
background: #1a1a1a;
border: 1px solid #00ff00;
border-radius: 2px;
overflow: hidden;
position: relative;
}
.meter-fill {
height: 100%;
background: linear-gradient(90deg, #00ff00, #ffaa00);
transition: width 0.3s;
display: flex;
align-items: center;
justify-content: center;
font-size: 9px;
color: #000;
font-weight: bold;
}
.meter-fill.critical {
background: linear-gradient(90deg, #ff0000, #ff4444);
}
.maintenance-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.btn {
background: rgba(0, 255, 0, 0.1);
border: 1px solid #00ff00;
color: #00ff00;
padding: 8px 12px;
border-radius: 3px;
cursor: pointer;
font-family: 'Courier New', monospace;
font-size: 11px;
transition: all 0.2s;
font-weight: bold;
}
.btn:hover:not(:disabled) {
background: rgba(0, 255, 0, 0.3);
box-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn.warning {
background: rgba(255, 170, 0, 0.1);
border-color: #ffaa00;
color: #ffaa00;
}
.btn.danger {
background: rgba(255, 0, 0, 0.1);
border-color: #ff0000;
color: #ff0000;
}
.dashboard {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.stat-box {
background: rgba(0, 255, 0, 0.1);
border: 2px solid #00ff00;
border-radius: 3px;
padding: 15px;
text-align: center;
}
.stat-label {
font-size: 11px;
color: #aaa;
margin-bottom: 8px;
text-transform: uppercase;
}
.stat-value {
font-size: 28px;
color: #00ff00;
font-weight: bold;
text-shadow: 0 0 10px #00ff00;
}
.email-modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 20, 40, 0.95);
border: 3px solid #ff0000;
border-radius: 5px;
padding: 30px;
max-width: 600px;
z-index: 1000;
box-shadow: 0 0 30px rgba(255, 0, 0, 0.5);
max-height: 80vh;
overflow-y: auto;
}
.email-modal.active {
display: block;
}
.email-header {
border-bottom: 2px solid #ff0000;
padding-bottom: 15px;
margin-bottom: 15px;
}
.email-from {
color: #ffaa00;
font-size: 12px;
margin-bottom: 5px;
}
.email-subject {
color: #ff0000;
font-size: 16px;
font-weight: bold;
margin-bottom: 5px;
}
.email-time {
color: #aaa;
font-size: 10px;
}
.email-body {
color: #fff;
line-height: 1.6;
margin-bottom: 20px;
}
.email-image {
width: 100%;
max-height: 300px;
object-fit: contain;
border: 1px solid #ff0000;
margin: 15px 0;
border-radius: 3px;
}
.email-damage {
background: rgba(255, 0, 0, 0.2);
border: 1px solid #ff0000;
padding: 15px;
border-radius: 3px;
color: #ff6666;
margin: 15px 0;
}
.close-email {
background: #ff0000;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 3px;
cursor: pointer;
font-weight: bold;
width: 100%;
}
.close-email:hover {
background: #ff4444;
}
.log-panel {
grid-column: 1 / -1;
max-height: 200px;
overflow-y: auto;
}
.log-entry {
font-size: 11px;
padding: 5px;
border-bottom: 1px solid rgba(0, 255, 0, 0.2);
color: #aaa;
}
.log-entry.error {
color: #ff6666;
background: rgba(255, 0, 0, 0.05);
}
.log-entry.warning {
color: #ffaa00;
}
.log-entry.success {
color: #00ff00;
}
.tool-image {
width: 120px;
height: 120px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
border: 2px solid #00ff00;
border-radius: 3px;
margin: 10px auto;
}
</style>
</head>
<body>
<div class="header">
<h1>⚙️ SEMICONDUCTOR FAB OPERATIONS</h1>
<div class="facility-name">Edwards Pump Systems - Vacuum Technology Division</div>
</div>
<div class="container">
<!-- Main Tool -->
<div class="panel">
<h3 style="color: #ffaa00; margin-bottom: 15px;">📡 TEPHRA DEPOSITION TOOL</h3>
<div class="tool-image" style="background-image: url('https://www.forgenano.com/archivesite/wp-content/uploads/2024/06/TEPHRA.png');"></div>
<div class="stat-label">Wafers Processed</div>
<div class="stat-value" id="wafersProcessed">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Wafers Scrapped</div>
<div class="stat-value" style="color: #ff6666;" id="wafersScrapped">0</div>
</div>
</div>
<!-- Pump Stations -->
<div id="pumpContainer"></div>
<!-- Abatement System -->
<div class="panel">
<h3 style="color: #ffaa00; margin-bottom: 15px;">🔥 EXHAUST ABATEMENT</h3>
<div class="tool-image" style="background-image: url('https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.buschvacuum.com%2Fmedia%2Fmedien%2Fproducts%2Ffamily%2Fgaba%2Fgaba-awe%2Fawe_050_ae%2Fgaba_awe-050-ae_767x510px_technology_767x510.png&f=1&nofb=1&ipt=23d1611467cea7c38bd198650fa0ac92002769feae61d5d31da9e850f238e643');"></div>
</div>
<!-- Global Stats -->
<div class="dashboard">
<div class="stat-box">
<div class="stat-label">System Pressure</div>
<div class="stat-value" id="systemPressure">1.00</div>
<div style="font-size: 10px; color: #aaa; margin-top: 5px;">mTorr</div>
</div>
<div class="stat-box">
<div class="stat-label">Revenue (Wafers/Min)</div>
<div class="stat-value" id="revenue">0</div>
</div>
<div class="stat-box">
<div class="stat-label">Equipment Health</div>
<div class="stat-value" id="globalHealth">100%</div>
</div>
<div class="stat-box">
<div class="stat-label">Downtime Events</div>
<div class="stat-value" id="downtimeEvents">0</div>
<!-- Maintenance Supplies -->
<div class="panel">
<h3 style="color: #ffaa00; margin-bottom: 15px;">🛢️ MAINTENANCE SUPPLIES</h3>
<div class="pump-image" style="background-image: url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRE1TqocuhBJVDV-G9HGueSJHGd2hdNQC5xUCu7qIEeczHRcFXP0X3maDs&s=10'); margin: 10px auto; width: 100px; height: 100px;"></div>
<div class="stat-box" style="margin-top: 10px;">
<div class="stat-label">Oil Status</div>
<div class="stat-value" style="color: #ffaa00;">READY</div>
</div>
</div>
</div>
</div>
<!-- Log -->
<div class="panel log-panel">
<h3 style="color: #ffaa00; margin-bottom: 10px;">📋 SYSTEM LOG</h3>
<div id="systemLog"></div>
</div>
</div>
<!-- Email Alert -->
<div class="email-modal" id="emailModal">
<div class="email-header">
<div class="email-from">FROM: [email protected]</div>
<div class="email-subject" id="emailSubject">CRITICAL ALERT</div>
<div class="email-time" id="emailTime">2026-08-18 14:32:44</div>
</div>
<div class="email-body" id="emailBody"></div>
<img id="emailImage" class="email-image" src="" alt="">
<div class="email-damage" id="emailDamage"></div>
<button class="close-email" onclick="closeEmail()">ACKNOWLEDGE</button>
</div>
<script>
// Game State
const gameState = {
wafersProcessed: 0,
wafersScrapped: 0,
downtimeEvents: 0,
systemPressure: 1.0,
revenue: 0,
time: 0,
pumps: {},
abatement: {}
};
// Pump Configurations
const pumpConfigs = {
qdp80: {
name: '💨 QDP80 Rotary Vane Pump',
model: 'Edwards QDP80',
maxSpeed: 100,
baseReliability: 0.85,
baseCost: 45000,
maintenanceCost: 3000
},
nxds300i: {
name: '💨 NXDs300i Screw Pump',
model: 'Edwards NXDs300i',
maxSpeed: 100,
baseReliability: 0.88,
baseCost: 65000,
maintenanceCost: 4200
},
a65d: {
name: '💨 A65D Dry Pump',
model: 'Edwards A65D',
maxSpeed: 100,
baseReliability: 0.92,
baseCost: 95000,
maintenanceCost: 5500
}
};
const abatementConfig = {
name: '🔥 Thermal Exhaust Abatement',
model: 'Edwards EH2000',
maxTemp: 100,
baseReliability: 0.80,
baseCost: 125000,
maintenanceCost: 7500
};
// Initialize Game
function initGame() {
// Create three pump stations
['qdp80', 'nxds300i', 'a65d'].forEach((pumpType, index) => {
gameState.pumps[pumpType] = {
type: pumpType,
speed: 0,
health: 100,
temperature: 20,
vibration: 0,
hoursRun: 0,
maintenanceInterval: 500,
lastMaintenance: 0,
isFailed: false,
nextFailureTime: Math.random() * 800 + 200
};
});
gameState.abatement = {
temperature: 25,
health: 100,
hoursRun: 0,
maintenanceInterval: 600,
lastMaintenance: 0,
isFailed: false,
nextFailureTime: Math.random() * 900 + 300
};
renderUI();
setInterval(gameLoop, 100);
}
// Main Game Loop
function gameLoop() {
gameState.time += 0.1;
// Update each pump
Object.keys(gameState.pumps).forEach(pumpType => {
updatePump(pumpType);
});
// Update abatement
updateAbatement();
// Calculate revenue (wafers per minute based on active pump)
let activeSpeed = 0;
Object.keys(gameState.pumps).forEach(type => {
if (gameState.pumps[type].speed > 0 && !gameState.pumps[type].isFailed) {
activeSpeed = Math.max(activeSpeed, gameState.pumps[type].speed);
}
});
gameState.revenue = Math.floor(activeSpeed * 0.5);
gameState.wafersProcessed += gameState.revenue / 600; // Convert to per-game-tick
// Update pressure
gameState.systemPressure = Math.max(0.1, 10 - activeSpeed * 0.08);
renderUI();
}
function updatePump(pumpType) {
const pump = gameState.pumps[pumpType];
const config = pumpConfigs[pumpType];
pump.hoursRun += 0.1 / 36;
// Degradation
let healthLoss = 0.01;
if (pump.speed > 80) healthLoss += 0.02;
if (pump.temperature > 70) healthLoss += 0.015;
if (pump.vibration > 80) healthLoss += 0.025;
pump.health = Math.max(0, pump.health - healthLoss);
// Temperature simulation
let tempIncrease = pump.speed * 0.3;
pump.temperature = Math.max(20, pump.temperature + tempIncrease * 0.01 - 0.05);
// Vibration simulation
pump.vibration = pump.speed * (1 - pump.health / 100) * 1.5;
// Failure detection
if (pump.hoursRun > pump.nextFailureTime && !pump.isFailed) {
if (Math.random() < (1 - pump.health / 100) * 0.5) {
failPump(pumpType);
}
}
if (pump.isFailed) {
pump.speed = 0;
pump.health -= 0.1;
}
}
function updateAbatement() {
const abate = gameState.abatement;
abate.hoursRun += 0.1 / 36;
// Get system heat load
let systemHeat = 0;
Object.keys(gameState.pumps).forEach(type => {
if (!gameState.pumps[type].isFailed) {
systemHeat += gameState.pumps[type].temperature * 0.1;
}
});
abate.temperature = Math.max(25, abate.temperature + systemHeat * 0.01 - 0.08);
// Health degradation
let healthLoss = 0.005;
if (abate.temperature > 80) healthLoss += 0.02;
abate.health = Math.max(0, abate.health - healthLoss);
// Failure
if (abate.hoursRun > abate.nextFailureTime && !abate.isFailed) {
if (Math.random() < (1 - abate.health / 100) * 0.3) {
failAbatement();
}
}
if (abate.isFailed) {
abate.temperature += 5;
abate.health -= 0.15;
}
}
function failPump(pumpType) {
const pump = gameState.pumps[pumpType];
pump.isFailed = true;
gameState.downtimeEvents++;
const messages = [
`⚠️ SEAL FAILURE DETECTED on ${pumpConfigs[pumpType].model}`,
`⚠️ BEARING DEGRADATION on ${pumpConfigs[pumpType].model}`,
`⚠️ UNEXPECTED SHUTDOWN: ${pumpConfigs[pumpType].model}`
];
addLog(messages[Math.floor(Math.random() * messages.length)], 'error');
// Critical failure - send email alert
if (Math.random() < 0.3) {
showEmail(
`CRITICAL FAILURE: ${pumpConfigs[pumpType].name}`,
`Your ${pumpConfigs[pumpType].model} has suffered a critical failure.\n\nThe pump seal has catastrophically failed, causing wafer damage.\n\nEstimated cost: $${pumpConfigs[pumpType].baseCost * 0.4} in repairs and lost wafers.`,
'https://via.placeholder.com/400x300?text=Pump+Failure'
);
gameState.wafersScrapped += Math.floor(Math.random() * 50 + 20);
}
}
function failAbatement() {
const abate = gameState.abatement;
abate.isFailed = true;
gameState.downtimeEvents++;
addLog('⚠️ ABATEMENT SYSTEM CRITICAL FAILURE', 'error');
// Environmental alert
showEmail(
'ENVIRONMENTAL ALARM: Abatement System Failure',
'Your exhaust abatement system has failed!\n\nHazardous gases are being vented to atmosphere without treatment.\n\nImmediate EPA notification required.\nRegulatory fines: $50,000+',
'https://via.placeholder.com/400x300?text=Abatement+Failure'
);
}
function setPumpSpeed(pumpType, speed) {
const pump = gameState.pumps[pumpType];
if (!pump.isFailed) {
pump.speed = Math.max(0, Math.min(100, Number(speed)));
addLog(`Set ${pumpConfigs[pumpType].model} to ${speed}% speed`, 'success');
}
}
function performMaintenance(pumpType) {
const pump = gameState.pumps[pumpType];
pump.health = 100;
pump.temperature = 25;
pump.vibration = 0;
pump.lastMaintenance = pump.hoursRun;
pump.isFailed = false;
pump.nextFailureTime = pump.hoursRun + (Math.random() * 400 + 300);
addLog(`✓ Maintenance completed on ${pumpConfigs[pumpType].model}`, 'success');
}
function performAbatementMaintenance() {
const abate = gameState.abatement;
abate.health = 100;
abate.temperature = 30;
abate.lastMaintenance = abate.hoursRun;
abate.isFailed = false;
abate.nextFailureTime = abate.hoursRun + (Math.random() * 500 + 400);
addLog('✓ Abatement system maintenance completed', 'success');
}
function emergencyStop() {
Object.keys(gameState.pumps).forEach(type => {
gameState.pumps[type].speed = 0;
});
addLog('🛑 EMERGENCY STOP ACTIVATED - All pumps shut down', 'warning');
}
function addLog(message, type = 'info') {
const log = document.getElementById('systemLog');
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
const timestamp = new Date().toLocaleTimeString();
entry.textContent = `[${timestamp}] ${message}`;
log.insertBefore(entry, log.firstChild);
// Keep only last 20 entries
while (log.children.length > 20) {
log.removeChild(log.lastChild);
}
}
function showEmail(subject, body, imageUrl) {
const modal = document.getElementById('emailModal');
document.getElementById('emailSubject').textContent = subject;
document.getElementById('emailBody').textContent = body;
document.getElementById('emailImage').src = imageUrl;
document.getElementById('emailTime').textContent = new Date().toLocaleString();
document.getElementById('emailDamage').innerHTML = `<strong>⚠️ INCIDENT REPORT</strong><br>Wafers Damaged: ${Math.floor(Math.random() * 100)}<br>System Downtime: ${Math.floor(Math.random() * 480) + 60} minutes`;
modal.classList.add('active');
}
function closeEmail() {
document.getElementById('emailModal').classList.remove('active');
}
function renderUI() {
// Update pump displays
Object.keys(gameState.pumps).forEach(pumpType => {
renderPump(pumpType);
});
// Update abatement
renderAbatement();
// Update global stats
document.getElementById('wafersProcessed').textContent = Math.floor(gameState.wafersProcessed);
document.getElementById('wafersScrapped').textContent = Math.floor(gameState.wafersScrapped);
document.getElementById('systemPressure').textContent = gameState.systemPressure.toFixed(2);
document.getElementById('revenue').textContent = gameState.revenue;
document.getElementById('downtimeEvents').textContent = gameState.downtimeEvents;
// Global health
let avgHealth = 0;
Object.keys(gameState.pumps).forEach(type => {
avgHealth += gameState.pumps[type].health;
});
avgHealth = (avgHealth / 3 + gameState.abatement.health) / 2;
document.getElementById('globalHealth').textContent = Math.floor(avgHealth) + '%';
}
function renderPump(pumpType) {
const pump = gameState.pumps[pumpType];
const config = pumpConfigs[pumpType];
let container = document.getElementById(`pump-${pumpType}`);
if (!container) {
container = document.createElement('div');
container.id = `pump-${pumpType}`;
container.className = 'panel';
document.getElementById('pumpContainer').appendChild(container);
}
let healthStatus = 'status-healthy';
if (pump.health < 50) healthStatus = 'status-critical';
else if (pump.health < 75) healthStatus = 'status-warning';
let failureIndicator = pump.isFailed ? ' [FAILED]' : '';
container.innerHTML = `
<h3 style="color: #ffaa00; margin-bottom: 15px;">${config.name}${failureIndicator}</h3>
<div class="pump-station">
<div class="pump-header">
<div class="pump-info">
<div class="pump-name">${config.model}</div>
<div class="pump-model">${config.baseCost / 1000}k system</div>
<div class="pump-status ${healthStatus}">
Health: ${Math.floor(pump.health)}% | Temp: ${Math.floor(pump.temperature)}°C | Vibration: ${Math.floor(pump.vibration)}%
</div>
</div>
</div>
<div class="meters">
<div class="meter">
<div class="meter-label">Speed</div>
<div class="meter-bar">
<div class="meter-fill" style="width: ${pump.speed}%">${Math.floor(pump.speed)}%</div>
</div>
</div>
<div class="meter">
<div class="meter-label">Health</div>
<div class="meter-bar">
<div class="meter-fill ${pump.health < 50 ? 'critical' : ''}" style="width: ${pump.health}%">${Math.floor(pump.health)}%</div>
</div>
</div>
<div class="meter">
<div class="meter-label">Temperature</div>
<div class="meter-bar">
<div class="meter-fill ${pump.temperature > 80 ? 'critical' : ''}" style="width: ${Math.min(100, (pump.temperature / 100) * 100)}%">${Math.floor(pump.temperature)}°C</div>
</div>
</div>
<div class="meter">
<div class="meter-label">Vibration</div>
<div class="meter-bar">
<div class="meter-fill ${pump.vibration > 80 ? 'critical' : ''}" style="width: ${Math.min(100, pump.vibration)}%">${Math.floor(pump.vibration)}%</div>
</div>
</div>
</div>
<input type="range" min="0" max="100" value="${pump.speed}"
onchange="setPumpSpeed('${pumpType}', this.value)"
style="width: 100%; cursor: ${pump.isFailed ? 'not-allowed' : 'pointer'};"
${pump.isFailed ? 'disabled' : ''}>
<div class="maintenance-buttons">
<button class="btn" id="btn-stop-${pumpType}" ${pump.isFailed ? 'disabled' : ''}>STOP</button>
<button class="btn" id="btn-50-${pumpType}" ${pump.isFailed ? 'disabled' : ''}>50%</button>
<button class="btn" id="btn-max-${pumpType}" ${pump.isFailed ? 'disabled' : ''}>MAX</button>
<button class="btn warning" id="btn-service-${pumpType}">🔧 SERVICE</button>
</div>
</div>
`;
}
function renderAbatement() {
const abate = gameState.abatement;
let container = document.getElementById('abatementSection');
let healthStatus = 'status-healthy';
if (abate.health < 50) healthStatus = 'status-critical';
else if (abate.health < 75) healthStatus = 'status-warning';
let failureIndicator = abate.isFailed ? ' [FAILED]' : '';
container.innerHTML = `
<div class="pump-header">
<div class="pump-info">
<div class="pump-name">${abatementConfig.name}${failureIndicator}</div>
<div class="pump-model">${abatementConfig.model}</div>
<div class="pump-status ${healthStatus}">
Health: ${Math.floor(abate.health)}% | Temp: ${Math.floor(abate.temperature)}°C
</div>
</div>
</div>
<div class="meters">
<div class="meter">
<div class="meter-label">Temperature</div>
<div class="meter-bar">
<div class="meter-fill ${abate.temperature > 85 ? 'critical' : ''}" style="width: ${Math.min(100, (abate.temperature / 100) * 100)}%">${Math.floor(abate.temperature)}°C</div>
</div>
</div>
<div class="meter">
<div class="meter-label">Health</div>
<div class="meter-bar">
<div class="meter-fill ${abate.health < 50 ? 'critical' : ''}" style="width: ${abate.health}%">${Math.floor(abate.health)}%</div>
</div>
</div>
</div>
<div class="maintenance-buttons">
<button class="btn warning" id="btn-service-abate" style="grid-column: 1 / -1;">🔧 SERVICE ABATEMENT</button>
<button class="btn danger" id="btn-emergency" style="grid-column: 1 / -1;">🛑 EMERGENCY STOP</button>
</div>
`;
}
// Start the game
initGame();
// Attach button event listeners once (not every frame)
function attachButtonListeners() {
// STOP, 50%, MAX buttons for each pump
['qdp80', 'nxds300i', 'a65d'].forEach(pumpType => {
const stopBtn = document.getElementById(`btn-stop-${pumpType}`);
const fiftyBtn = document.getElementById(`btn-50-${pumpType}`);
const maxBtn = document.getElementById(`btn-max-${pumpType}`);
const serviceBtn = document.getElementById(`btn-service-${pumpType}`);
if (stopBtn) stopBtn.addEventListener('click', () => setPumpSpeed(pumpType, 0));
if (fiftyBtn) fiftyBtn.addEventListener('click', () => setPumpSpeed(pumpType, 50));
if (maxBtn) maxBtn.addEventListener('click', () => setPumpSpeed(pumpType, 100));
if (serviceBtn) serviceBtn.addEventListener('click', () => performMaintenance(pumpType));
});
// Abatement buttons
const serviceAbate = document.getElementById('btn-service-abate');
const emergency = document.getElementById('btn-emergency');
if (serviceAbate) serviceAbate.addEventListener('click', performAbatementMaintenance);
if (emergency) emergency.addEventListener('click', emergencyStop);
}
// Call once after game starts
attachButtonListeners();
</script>
</body>
</html>4 views