Files
sillytavern-rts-mode/ui/ResourcePanel.js
T
2025-08-03 22:35:36 -07:00

220 lines
8.8 KiB
JavaScript

/**
* Creates and returns the enhanced status panel element.
* @param {HTMLElement} rootEl - The root element to append to (optional).
* @returns {HTMLDivElement}
*/
export function createResourcePanel(rootEl) {
const panel = document.createElement('div');
panel.id = 'rts-resource-panel';
panel.className = 'rts-status-panel';
panel.innerHTML = `
<div class="rts-panel-section">
<h3>Status Overview</h3>
<div id="rts-overview-stats">
<div class="stat-item">Turn: <span id="turn-counter">1</span></div>
<div class="stat-item">Zone: <span id="current-zone">Unknown</span></div>
<div class="stat-item">Threat: <span id="threat-level">Low</span></div>
</div>
</div>
<div class="rts-panel-section">
<h3>Casualties</h3>
<div id="rts-casualties-stats">
<div class="stat-item">Total Deaths: <span id="total-deaths">0</span></div>
<div class="stat-item">Recent: <span id="recent-deaths">0</span></div>
</div>
<div id="rts-recent-casualties" class="scrollable-list"></div>
</div>
<div class="rts-panel-section">
<h3>Escaped Animals</h3>
<div id="rts-animals-stats">
<div class="stat-item">Active Threats: <span id="active-animals">0</span></div>
</div>
<div id="rts-escaped-animals" class="scrollable-list"></div>
</div>
<div class="rts-panel-section">
<h3>Personnel</h3>
<div id="rts-personnel-stats">
<div class="stat-item">Alive: <span id="alive-personnel">0</span></div>
<div class="stat-item">Injured: <span id="injured-personnel">0</span></div>
<div class="stat-item">Missing: <span id="missing-personnel">0</span></div>
</div>
<div id="rts-personnel-list" class="scrollable-list"></div>
</div>
<div class="rts-panel-section">
<h3>Active Incidents</h3>
<div id="rts-incidents-stats">
<div class="stat-item">Emergency: <span id="emergency-incidents">0</span></div>
<div class="stat-item">Ongoing: <span id="ongoing-incidents">0</span></div>
</div>
<div id="rts-incidents-list" class="scrollable-list"></div>
</div>
`;
if (rootEl) {
rootEl.appendChild(panel);
}
return panel;
}
/**
* Updates the resource panel with current game state
* @param {object} gameState - Current game state
*/
export function updateResourcePanel(gameState) {
if (!gameState) return;
// Helper function to safely update text content
const safeUpdateText = (id, value) => {
const element = document.getElementById(id);
if (element) {
element.textContent = value;
} else {
console.warn(`RTS: Element with id '${id}' not found for update`);
}
};
// Update overview stats
safeUpdateText('turn-counter', gameState.turn || 1);
safeUpdateText('current-zone', gameState.currentZone || 'Unknown');
safeUpdateText('threat-level', gameState.threatLevel || 'Low');
// Update casualties
const casualties = gameState.casualties || {};
const totalDeaths = casualties.total || 0;
const recentDeaths = casualties.recent || [];
safeUpdateText('total-deaths', totalDeaths);
safeUpdateText('recent-deaths', recentDeaths.length);
// Update recent casualties list
const casualtiesList = document.getElementById('rts-recent-casualties');
if (!casualtiesList) {
console.warn('RTS: Casualties list element not found');
return;
}
casualtiesList.innerHTML = '';
if (recentDeaths && recentDeaths.length > 0) {
recentDeaths.slice(0, 5).forEach(casualty => {
const item = document.createElement('div');
item.className = 'list-item casualty';
// Safely access casualty properties
const name = casualty.name || 'Unknown victim';
const cause = casualty.cause || casualty.causeOfDeath || 'Unknown cause';
const perpetrator = casualty.perpetrator || casualty.killedBy || 'Unknown';
const location = casualty.location || 'Unknown location';
const turn = casualty.turn || '?';
item.innerHTML = `<strong>${name}</strong><br>
<small>${cause} by ${perpetrator}</small><br>
<small>@ ${location} (Turn ${turn})</small>`;
casualtiesList.appendChild(item);
});
} else {
const noData = document.createElement('div');
noData.className = 'list-item';
noData.innerHTML = '<small style="color: rgba(255,255,255,0.5);">No recent casualties</small>';
casualtiesList.appendChild(noData);
}
// Update escaped animals
const animals = gameState.escapedAnimals || {};
safeUpdateText('active-animals', (animals.active || []).length);
const animalsList = document.getElementById('rts-escaped-animals');
if (!animalsList) {
console.warn('RTS: Escaped animals list element not found');
return;
}
animalsList.innerHTML = '';
if (animals.active && animals.active.length > 0) {
animals.active.forEach(animal => {
const item = document.createElement('div');
item.className = 'list-item animal';
item.innerHTML = `<strong>${animal.name}</strong> (${animal.type})<br>
<small>${animal.behavior} @ ${animal.currentLocation}</small><br>
<small>Threat: ${animal.threat}</small>`;
animalsList.appendChild(item);
});
}
// Update personnel
const personnel = gameState.personnel || {};
safeUpdateText('alive-personnel', (personnel.alive || []).length);
safeUpdateText('injured-personnel', (personnel.injured || []).length);
safeUpdateText('missing-personnel', (personnel.missing || []).length);
const personnelList = document.getElementById('rts-personnel-list');
if (!personnelList) {
console.warn('RTS: Personnel list element not found');
return;
}
personnelList.innerHTML = '';
// Show alive personnel
if (personnel.alive && personnel.alive.length > 0) {
personnel.alive.forEach(person => {
const item = document.createElement('div');
item.className = 'list-item personnel alive';
item.innerHTML = `<strong>${person.name}</strong> (${person.type})<br>
<small>Status: ${person.status}</small><br>
<small>@ (${person.position.x}, ${person.position.y})</small>`;
personnelList.appendChild(item);
});
}
// Show injured personnel
if (personnel.injured && personnel.injured.length > 0) {
personnel.injured.forEach(person => {
const item = document.createElement('div');
item.className = 'list-item personnel injured';
item.innerHTML = `<strong>${person.name}</strong> (${person.type})<br>
<small>INJURED - ${person.status}</small><br>
<small>@ (${person.position.x}, ${person.position.y})</small>`;
personnelList.appendChild(item);
});
}
// Update incidents
const incidents = gameState.activeIncidents || {};
safeUpdateText('emergency-incidents', (incidents.emergency || []).length);
safeUpdateText('ongoing-incidents', (incidents.ongoing || []).length);
const incidentsList = document.getElementById('rts-incidents-list');
if (!incidentsList) {
console.warn('RTS: Incidents list element not found');
return;
}
incidentsList.innerHTML = '';
// Show emergency incidents
if (incidents.emergency && incidents.emergency.length > 0) {
incidents.emergency.forEach(incident => {
const item = document.createElement('div');
item.className = 'list-item incident emergency';
item.innerHTML = `<strong>EMERGENCY</strong><br>
<small>${incident.type || 'Unknown'}</small><br>
<small>${incident.description || 'No details'}</small>`;
incidentsList.appendChild(item);
});
}
// Show ongoing incidents
if (incidents.ongoing && incidents.ongoing.length > 0) {
incidents.ongoing.forEach(incident => {
const item = document.createElement('div');
item.className = 'list-item incident ongoing';
item.innerHTML = `<strong>Ongoing</strong><br>
<small>${incident.type || 'Unknown'}</small><br>
<small>${incident.description || 'No details'}</small>`;
incidentsList.appendChild(item);
});
}
}