Luigi's picture
deploy(web): full clean snapshot with app code and assets
12d64f8
raw
history blame
5.9 kB
/**
* HintManager - Context-aware hint system for RTS game
* Shows helpful hints at the right moment with smooth animations
*/
class HintManager {
constructor() {
this.hintQueue = [];
this.currentHint = null;
this.shownHints = new Set();
this.enabled = true;
this.hintElement = null;
this.translations = {};
this.initializeHintElement();
this.loadHintHistory();
}
initializeHintElement() {
// Create hint container
this.hintElement = document.createElement('div');
this.hintElement.id = 'hint-display';
this.hintElement.className = 'hint-container hidden';
// Add to body
document.body.appendChild(this.hintElement);
console.log('[HintManager] Initialized');
}
loadHintHistory() {
// Load previously shown hints from localStorage
try {
const history = localStorage.getItem('rts_shown_hints');
if (history) {
this.shownHints = new Set(JSON.parse(history));
console.log(`[HintManager] Loaded ${this.shownHints.size} shown hints from history`);
}
} catch (error) {
console.warn('[HintManager] Failed to load hint history:', error);
}
}
saveHintHistory() {
// Save shown hints to localStorage
try {
localStorage.setItem('rts_shown_hints', JSON.stringify([...this.shownHints]));
} catch (error) {
console.warn('[HintManager] Failed to save hint history:', error);
}
}
setTranslations(translations) {
this.translations = translations;
}
translate(key) {
return this.translations[key] || key;
}
showHint(hintKey, options = {}) {
if (!this.enabled) return;
// Check if hint was already shown (unless force is true)
if (!options.force && this.shownHints.has(hintKey)) {
return;
}
// Default options
const config = {
duration: 3000, // 3 seconds
priority: 0, // Higher priority = shown first
force: false, // Show even if already shown
position: 'center', // 'center', 'top', 'bottom'
...options
};
// Add to queue with priority
this.hintQueue.push({ key: hintKey, config });
this.hintQueue.sort((a, b) => b.config.priority - a.config.priority);
// Mark as shown
this.shownHints.add(hintKey);
this.saveHintHistory();
// Show if no current hint
if (!this.currentHint) {
this.displayNext();
}
}
displayNext() {
if (this.hintQueue.length === 0) {
this.currentHint = null;
return;
}
const { key, config } = this.hintQueue.shift();
this.currentHint = { key, config };
// Get translated text
const text = this.translate(key);
// Update hint element
this.hintElement.textContent = text;
this.hintElement.className = `hint-container ${config.position}`;
// Fade in
setTimeout(() => {
this.hintElement.classList.add('visible');
}, 50);
// Auto-hide after duration
setTimeout(() => {
this.hide();
}, config.duration);
console.log(`[HintManager] Showing hint: ${key}`);
}
hide() {
if (!this.hintElement) return;
// Fade out
this.hintElement.classList.remove('visible');
// Wait for animation, then show next
setTimeout(() => {
this.displayNext();
}, 500); // Match CSS transition duration
}
enable() {
this.enabled = true;
console.log('[HintManager] Hints enabled');
}
disable() {
this.enabled = false;
this.hide();
console.log('[HintManager] Hints disabled');
}
toggle() {
this.enabled = !this.enabled;
if (!this.enabled) {
this.hide();
}
return this.enabled;
}
reset() {
// Clear history and show all hints again
this.shownHints.clear();
this.saveHintHistory();
console.log('[HintManager] Hint history reset');
}
// Contextual hint triggers
onGameStart() {
this.showHint('hint.game.welcome', { priority: 10, duration: 4000 });
setTimeout(() => {
this.showHint('hint.game.build_barracks', { priority: 9, duration: 4000 });
}, 4500);
}
onFirstUnitSelected() {
this.showHint('hint.controls.movement', { priority: 8 });
}
onFirstBuildingPlaced() {
this.showHint('hint.game.train_units', { priority: 7 });
}
onMultipleUnitsSelected(count) {
if (count >= 3) {
this.showHint('hint.controls.control_groups', { priority: 6 });
}
}
onLowCredits() {
this.showHint('hint.game.low_credits', { priority: 5 });
}
onLowPower() {
this.showHint('hint.game.low_power', { priority: 5 });
}
onFirstCombat() {
this.showHint('hint.combat.attack_move', { priority: 7 });
}
onControlGroupAssigned() {
this.showHint('hint.controls.control_groups_select', { priority: 6, duration: 4000 });
}
onCameraKeyboard() {
this.showHint('hint.controls.camera_keyboard', { priority: 4 });
}
onLanguageChanged() {
this.showHint('hint.ui.language_changed', { priority: 8, duration: 2000 });
}
}
// Export for use in game.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = HintManager;
}