UNPKG

crocobras

Version:

Noyau logique du jeu « Le bras d'un mec », où les joueurs combattent des crocodiles pour protéger un bras.

1,311 lines (1,124 loc) 107 kB
// crocobras/index.js const EventEmitter = require('events'); const nekomaths = require('nekomaths'); // Pour les nombres aléatoires // --- Configuration du jeu (peut être personnalisé par le développeur utilisateur) --- const DEFAULT_GAME_SETTINGS = { initialArmHealth: 100, // Exemple de vie du bras crocoDamage: 25, // Dégâts d'un croco qui mange le bras initialCrocodiles: 1, // Nombre de crocos au niveau 1 crocoPerLevel: 1, // Crocos supplémentaires par niveau crocoSpeedMultiplier: 1.1, // Crocos plus rapides à chaque niveau levelUpThreshold: 5 // Crocos à tuer pour passer au niveau suivant (modifiable via croconumber) }; class CrocobrasGame extends EventEmitter { constructor(settings = {}) { super(); this.settings = { ...DEFAULT_GAME_SETTINGS, ...settings }; this.armHealth = this.settings.initialArmHealth; this.currentLevel = 1; this.crocodilesRemaining = 0; // Nombre de crocos à tuer pour le niveau actuel this.crocodilesSpawnedThisLevel = 0; // Crocos déjà apparus ce niveau this.killedCrocodilesThisLevel = 0; // Crocos tués dans le niveau actuel this.isGameOver = false; this.isGameRunning = false; // Stocke les crocos actifs pour la logique de collision // En vrai jeu, ce serait un tableau d'objets avec position, vitesse, etc. // Ici, on gère juste le nombre. this.activeCrocodiles = []; this.initializeLevel(); } /** * Initialise le niveau actuel : détermine le nombre de crocodiles à tuer. * Peut être appelé manuellement par crocolevel. * @param {number} [level] - Niveau spécifique à initialiser. Si non fourni, utilise currentLevel. */ initializeLevel(level = this.currentLevel) { this.currentLevel = level; this.killedCrocodilesThisLevel = 0; this.crocodilesSpawnedThisLevel = 0; // Calcul du nombre total de crocos pour ce niveau // Tu as dit "un crocodile de plus que le niveau suivant arrive en même temps" // Interprétation: Niveau 1 -> 1 croco, Niveau 2 -> 2 crocos, etc. this.crocodilesToSpawnTotal = this.settings.initialCrocodiles + (this.currentLevel - 1) * this.settings.crocoPerLevel; this.crocodilesRemaining = this.crocodilesToSpawnTotal; // Pour l'UI du développeur utilisateur this.emit('levelInitialized', { level: this.currentLevel, crocodilesToKill: this.crocodilesToSpawnTotal, armHealth: this.armHealth }); console.log(`[Crocobras] Niveau ${this.currentLevel} initialisé. Crocodiles à tuer : ${this.crocodilesToSpawnTotal}`); } /** * Démarre la partie. * @returns {boolean} True si le jeu a démarré, false s'il était déjà en cours. */ startGame() { if (this.isGameRunning) { this.emit('gameAlreadyRunning'); return false; } this.isGameRunning = true; this.isGameOver = false; this.armHealth = this.settings.initialArmHealth; this.currentLevel = 1; this.initializeLevel(1); this.emit('gameStarted', { level: this.currentLevel, armHealth: this.armHealth }); console.log("[Crocobras] Partie démarrée !"); return true; } /** * Gère la fin de partie. * @fires CrocobrasGame#gameOver * @returns {boolean} True si le jeu est terminé, false sinon (si déjà game over). */ crocover() { if (this.isGameOver) return false; this.isGameOver = true; this.isGameRunning = false; this.emit('gameOver', { finalLevel: this.currentLevel, reason: 'Arm eaten' }); console.log("[Crocobras] GAME OVER ! Le bras a été mangé."); return true; } /** * Redémarre le jeu au niveau 1. * @fires CrocobrasGame#gameReset */ crocoreset() { this.armHealth = this.settings.initialArmHealth; this.currentLevel = 1; this.correctGuesses = 0; // Si jamais tu as une logique de devinette cachée this.isGameOver = false; this.isGameRunning = false; // Ne pas démarrer automatiquement, l'utilisateur appellera startGame() this.killedCrocodilesThisLevel = 0; this.crocodilesSpawnedThisLevel = 0; this.activeCrocodiles = []; // Vide les crocos actifs this.initializeLevel(1); // Réinitialise le premier niveau this.emit('gameReset', { level: this.currentLevel, armHealth: this.armHealth }); console.log("[Crocobras] Jeu réinitialisé au niveau 1."); } /** * Simule un crocodile mangeant le bras. * Déclenche la perte de points de vie ou le game over. * @fires CrocobrasGame#armEaten * @fires CrocobrasGame#gameOver */ crocobouffe() { if (!this.isGameRunning || this.isGameOver) { console.log("[Crocobras] Ignoré: le jeu n'est pas en cours ou est terminé."); return; } this.armHealth = nekomaths.neksub(this.armHealth, this.settings.crocoDamage); this.emit('armEaten', { currentHealth: this.armHealth, damageTaken: this.settings.crocoDamage }); console.log(`[Crocobras] Un crocodile a mangé le bras ! Vie restante : ${this.armHealth}`); if (this.armHealth <= 0) { this.crocover(); } } /** * Simule un coup de feu tiré. Ne gère pas si la cible est touchée. * Les développeurs utilisent `crocofuls` pour la logique de détection. * @fires CrocobrasGame#shotFired */ crocotire() { if (!this.isGameRunning || this.isGameOver) { this.emit('gameNotRunning'); return; } this.emit('shotFired'); console.log("[Crocobras] Coup de feu tiré !"); } /** * Simule la mort d'un crocodile. * @fires CrocobrasGame#crocoKilled * @fires CrocobrasGame#levelUp * @returns {boolean} True si un crocodile a été tué, false si aucun n'est à tuer. */ crocokill() { if (!this.isGameRunning || this.isGameOver) { this.emit('gameNotRunning'); return false; } if (this.killedCrocodilesThisLevel < this.crocodilesToSpawnTotal) { this.killedCrocodilesThisLevel = nekomaths.nekadd(this.killedCrocodilesThisLevel, 1); this.crocodilesRemaining = nekomaths.neksub(this.crocodilesToSpawnTotal, this.killedCrocodilesThisLevel); this.emit('crocoKilled', { killedCount: this.killedCrocodilesThisLevel, remainingCount: this.crocodilesRemaining, level: this.currentLevel }); console.log(`[Crocobras] Crocodile tué ! Restant : ${this.crocodilesRemaining}/${this.crocodilesToSpawnTotal}`); if (this.killedCrocodilesThisLevel >= this.crocodilesToSpawnTotal) { this.levelUp(); // Passe au niveau suivant } return true; } else { this.emit('noMoreCrocosToKill'); console.log("[Crocobras] Tous les crocodiles du niveau actuel sont déjà tués."); return false; } } /** * Permet aux développeurs de définir le nombre de crocos à tuer pour un niveau donné. * OU de définir le seuil pour le passage de niveau. * @param {number} [targetCrocosPerLevel] - Nombre de crocodiles requis pour passer le niveau actuel. * @param {number} [levelToApply] - Le niveau auquel appliquer ce seuil. Si non fourni, applique à levelUpThreshold. */ croconumber(targetCrocosPerLevel = DEFAULT_GAME_SETTINGS.levelUpThreshold) { // Cette fonction peut être interprétée de deux façons: // 1. Définir le nombre de crocos à tuer pour le level up (ce que tu as dit "double pour le niveau suivant") // 2. Définir le nombre de crocos qui apparaissent // Je vais opter pour la 1ère (seuil de level up) comme le plus utile pour la personnalisation. // La quantité de crocos qui apparaissent est déjà gérée par initializeLevel. this.settings.levelUpThreshold = targetCrocosPerLevel; this.emit('levelUpThresholdUpdated', targetCrocosPerLevel); console.log(`[Crocobras] Seuil de crocos à tuer pour passer le niveau mis à jour : ${targetCrocosPerLevel}`); } /** * Fait monter le jeu de niveau. * @fires CrocobrasGame#levelUp */ levelUp() { if (this.isGameOver) { this.emit('gameNotRunning'); return; } this.currentLevel = nekomaths.nekadd(this.currentLevel, 1); this.emit('levelUp', { newLevel: this.currentLevel }); console.log(`[Crocobras] BRAVO ! Vous passez au niveau ${this.currentLevel} !`); this.initializeLevel(this.currentLevel); // Réinitialise les compteurs pour le nouveau niveau } // --- Fonctions d'accès aux états (pour l'UI) --- getGameState() { return { armHealth: this.armHealth, currentLevel: this.currentLevel, crocodilesRemaining: this.crocodilesRemaining, crocodilesToSpawnTotal: this.crocodilesToSpawnTotal, killedCrocodilesThisLevel: this.killedCrocodilesThisLevel, isGameOver: this.isGameOver, isGameRunning: this.isGameRunning }; } /** * crocofuls: Permet de définir une logique de détection de tir personnalisée. * Cette fonction ne fait rien directement, elle est là comme un hook ou un concept. * C'est au développeur d'appeler `crocokill()` si sa logique de `crocofuls` détecte un coup réussi. * @param {Function} customGunLogic - Une fonction de callback que le développeur fournira. */ crocofuls(customGunLogic) { if (typeof customGunLogic === 'function') { this.emit('customGunLogicDefined', customGunLogic); console.log("[Crocobras] Logique de tir personnalisée définie. Le développeur doit l'appeler !"); } else { throw new Error("crocofuls: L'argument doit être une fonction."); } } /** * crocoanm: Ce package ne gère PAS les sons/musiques directement. * Cette fonction est un simple émetteur d'événements pour indiquer au développeur * qu'il est temps de jouer un son ou une musique. * @param {string} soundType - Le type de son ('shot', 'crocoGrowl', 'musicLoop', 'gameOverSound'). */ crocoanm(soundType) { this.emit('playAnimationSound', soundType); console.log(`[Crocobras] Événement de son émis : ${soundType}.`); } /** * crocustom: Permet aux développeurs d'étendre la logique du jeu avec leurs propres fonctions. * C'est une fonction "fourre-tout" pour la personnalisation avancée. * Le développeur peut passer un objet de nouvelles fonctions ou un callback pour modifier le jeu. * @param {Function|object} customization - Une fonction ou un objet contenant des personnalisations. */ crocustom(customization) { if (typeof customization === 'function') { customization(this); // Passe l'instance du jeu au développeur pour qu'il puisse interagir. this.emit('gameCustomized', 'function'); } else if (typeof customization === 'object' && customization !== null) { Object.assign(this, customization); // Fusionne les propriétés dans l'instance du jeu this.emit('gameCustomized', 'object'); } else { throw new Error("crocustom: L'argument doit être une fonction ou un objet."); } console.log("[Crocobras] Personnalisation avancée appliquée via crocustom."); } /** * crocopow: Permet au développeur de créer ses propres power-ups avec sa logique JavaScript. * @param {string} powerUpType - Type/nom du power-up personnalisé * @param {Function} powerUpLogic - Fonction qui définit l'effet du power-up * @param {Object} [options] - Options supplémentaires (durée, valeur, etc.) */ crocopow(powerUpType, powerUpLogic, options = {}) { if (typeof powerUpLogic !== 'function') { throw new Error("crocopow: powerUpLogic doit être une fonction."); } if (!this.customPowerUps) { this.customPowerUps = {}; } this.customPowerUps[powerUpType] = { logic: powerUpLogic, options: { duration: 5000, value: 1, ...options } }; this.emit('customPowerUpRegistered', { type: powerUpType, options }); console.log(`[Crocobras] Power-up personnalisé '${powerUpType}' enregistré.`); } /** * Déclenche un power-up personnalisé * @param {string} powerUpType - Type du power-up à activer */ activatePowerUp(powerUpType) { if (!this.customPowerUps || !this.customPowerUps[powerUpType]) { console.warn(`[Crocobras] Power-up '${powerUpType}' non trouvé.`); return false; } const powerUp = this.customPowerUps[powerUpType]; powerUp.logic.call(this, powerUp.options); this.emit('powerUpActivated', { type: powerUpType, options: powerUp.options }); console.log(`[Crocobras] Power-up '${powerUpType}' activé !`); return true; } /** * crocoboost: Permet au développeur de créer des systèmes de boost temporaires ou de cadeaux. * @param {string} boostType - Type de boost (ex: 'speedBoost', 'damageBoost', 'healthBoost') * @param {number} value - Valeur du boost * @param {number} duration - Durée en millisecondes * @param {Function} [onExpire] - Callback appelé quand le boost expire */ crocoboost(boostType, value, duration, onExpire = null) { if (!this.activeBoosts) { this.activeBoosts = {}; } // Appliquer le boost this.activeBoosts[boostType] = { value: value, startTime: Date.now(), duration: duration, onExpire: onExpire }; this.emit('boostActivated', { type: boostType, value, duration }); console.log(`[Crocobras] Boost '${boostType}' activé pour ${duration}ms avec valeur ${value}.`); // Programmer l'expiration du boost setTimeout(() => { if (this.activeBoosts && this.activeBoosts[boostType]) { delete this.activeBoosts[boostType]; if (onExpire) onExpire(); this.emit('boostExpired', { type: boostType }); console.log(`[Crocobras] Boost '${boostType}' expiré.`); } }, duration); } /** * Vérifie si un boost est actif * @param {string} boostType - Type de boost à vérifier * @returns {boolean|Object} False si inactif, sinon retourne les données du boost */ getActiveBoost(boostType) { return this.activeBoosts && this.activeBoosts[boostType] ? this.activeBoosts[boostType] : false; } /** * crocolife: Permet au développeur de définir un système de points de vie pour les crocodiles. * @param {number} crocoId - ID unique du crocodile * @param {number} health - Points de vie du crocodile * @param {Object} [options] - Options supplémentaires (maxHealth, regeneration, etc.) */ crocolife(crocoId, health, options = {}) { if (!this.crocodileHealths) { this.crocodileHealths = {}; } this.crocodileHealths[crocoId] = { currentHealth: health, maxHealth: options.maxHealth || health, regeneration: options.regeneration || 0, lastRegenTime: Date.now(), ...options }; this.emit('crocodileHealthSet', { crocoId, health, options }); console.log(`[Crocobras] Crocodile ${crocoId} a maintenant ${health} points de vie.`); } /** * Inflige des dégâts à un crocodile spécifique * @param {number} crocoId - ID du crocodile * @param {number} damage - Dégâts à infliger * @returns {boolean} True si le crocodile est mort, false sinon */ damageCrocodile(crocoId, damage) { if (!this.crocodileHealths || !this.crocodileHealths[crocoId]) { // Si pas de système de vie défini, comportement par défaut (mort en 1 coup) return this.crocokill(); } const croco = this.crocodileHealths[crocoId]; croco.currentHealth = nekomaths.neksub(croco.currentHealth, damage); this.emit('crocodileDamaged', { crocoId, damage, remainingHealth: croco.currentHealth }); console.log(`[Crocobras] Crocodile ${crocoId} reçoit ${damage} dégâts. Vie restante: ${croco.currentHealth}`); if (croco.currentHealth <= 0) { delete this.crocodileHealths[crocoId]; this.emit('crocodileKilledByDamage', { crocoId }); return this.crocokill(); } return false; } /** * crocoarmure: Permet au développeur de personnaliser la force des crocodiles. * @param {number} crocoId - ID du crocodile * @param {number} strength - Force/armure du crocodile * @param {Function} [strengthLogic] - Logique personnalisée pour calculer la force */ crocoarmure(crocoId, strength, strengthLogic = null) { if (!this.crocodileStrengths) { this.crocodileStrengths = {}; } this.crocodileStrengths[crocoId] = { baseStrength: strength, currentStrength: strength, strengthLogic: strengthLogic, lastUpdate: Date.now() }; this.emit('crocodileStrengthSet', { crocoId, strength }); console.log(`[Crocobras] Crocodile ${crocoId} a maintenant une force de ${strength}.`); } /** * Met à jour la force d'un crocodile selon sa logique personnalisée * @param {number} crocoId - ID du crocodile * @param {Object} [context] - Contexte pour la logique (niveau, temps, etc.) */ updateCrocodileStrength(crocoId, context = {}) { if (!this.crocodileStrengths || !this.crocodileStrengths[crocoId]) return; const croco = this.crocodileStrengths[crocoId]; if (croco.strengthLogic) { const newStrength = croco.strengthLogic.call(this, croco.currentStrength, context); croco.currentStrength = newStrength; croco.lastUpdate = Date.now(); this.emit('crocodileStrengthUpdated', { crocoId, newStrength, context }); console.log(`[Crocobras] Force du crocodile ${crocoId} mise à jour: ${newStrength}`); } } /** * crocorap: Permet aux développeurs de personnaliser la vitesse des crocodiles. * @param {number} crocoId - ID du crocodile * @param {number} speed - Vitesse du crocodile * @param {Function} [speedModifier] - Fonction pour modifier la vitesse dynamiquement */ crocorap(crocoId, speed, speedModifier = null) { if (!this.crocodileSpeeds) { this.crocodileSpeeds = {}; } this.crocodileSpeeds[crocoId] = { baseSpeed: speed, currentSpeed: speed, speedModifier: speedModifier, lastUpdate: Date.now() }; this.emit('crocodileSpeedSet', { crocoId, speed }); console.log(`[Crocobras] Crocodile ${crocoId} a maintenant une vitesse de ${speed}.`); } /** * Met à jour la vitesse d'un crocodile * @param {number} crocoId - ID du crocodile * @param {Object} [factors] - Facteurs influençant la vitesse (niveau, boosts, etc.) */ updateCrocodileSpeed(crocoId, factors = {}) { if (!this.crocodileSpeeds || !this.crocodileSpeeds[crocoId]) return; const croco = this.crocodileSpeeds[crocoId]; if (croco.speedModifier) { const newSpeed = croco.speedModifier.call(this, croco.baseSpeed, factors); croco.currentSpeed = newSpeed; croco.lastUpdate = Date.now(); this.emit('crocodileSpeedUpdated', { crocoId, newSpeed, factors }); console.log(`[Crocobras] Vitesse du crocodile ${crocoId} mise à jour: ${newSpeed}`); } } /** * crocopop: Permet au développeur de créer des systèmes de danse/esquive sur les crocodiles. * @param {number} crocoId - ID du crocodile * @param {string} danceType - Type de danse/mouvement ('dodge', 'spin', 'jump', etc.) * @param {Function} danceLogic - Logique de la danse/esquive * @param {Object} [options] - Options (durée, probabilité d'esquive, etc.) */ crocopop(crocoId, danceType, danceLogic, options = {}) { if (typeof danceLogic !== 'function') { throw new Error("crocopop: danceLogic doit être une fonction."); } if (!this.crocodileDances) { this.crocodileDances = {}; } if (!this.crocodileDances[crocoId]) { this.crocodileDances[crocoId] = {}; } this.crocodileDances[crocoId][danceType] = { logic: danceLogic, options: { duration: 1000, dodgeChance: 0.3, ...options }, isActive: false }; this.emit('crocodileDanceRegistered', { crocoId, danceType, options }); console.log(`[Crocobras] Danse '${danceType}' enregistrée pour le crocodile ${crocoId}.`); } /** * Déclenche une danse/esquive pour un crocodile * @param {number} crocoId - ID du crocodile * @param {string} danceType - Type de danse à exécuter * @returns {boolean} True si la danse a été déclenchée, false sinon */ triggerCrocodileDance(crocoId, danceType) { if (!this.crocodileDances || !this.crocodileDances[crocoId] || !this.crocodileDances[crocoId][danceType]) { return false; } const dance = this.crocodileDances[crocoId][danceType]; if (dance.isActive) return false; // Déjà en cours dance.isActive = true; const result = dance.logic.call(this, crocoId, dance.options); this.emit('crocodileDanceTriggered', { crocoId, danceType, result }); console.log(`[Crocobras] Crocodile ${crocoId} exécute la danse '${danceType}'.`); // Fin automatique de la danse après la durée setTimeout(() => { if (this.crocodileDances && this.crocodileDances[crocoId] && this.crocodileDances[crocoId][danceType]) { this.crocodileDances[crocoId][danceType].isActive = false; this.emit('crocodileDanceEnded', { crocoId, danceType }); } }, dance.options.duration); return true; } /** * crocoexplose: Fait exploser un crocodile à sa mort, infligeant des dégâts de zone. * @param {number} crocoId - ID du crocodile qui explose * @param {number} explosionDamage - Dégâts de l'explosion * @param {number} explosionRadius - Rayon de l'explosion * @param {Function} [explosionLogic] - Logique personnalisée d'explosion */ crocoexplose(crocoId, explosionDamage, explosionRadius, explosionLogic = null) { const explosion = { damage: explosionDamage, radius: explosionRadius, logic: explosionLogic, source: crocoId }; // Si logique personnalisée fournie, l'utiliser if (explosionLogic && typeof explosionLogic === 'function') { explosionLogic.call(this, explosion); } else { // Logique par défaut : dégâts au bras si dans le rayon this.handleDefaultExplosion(explosion); } this.emit('crocodileExploded', { crocoId, damage: explosionDamage, radius: explosionRadius }); console.log(`[Crocobras] Crocodile ${crocoId} explose ! Dégâts: ${explosionDamage}, Rayon: ${explosionRadius}`); } /** * Gère l'explosion par défaut (dégâts au bras) * @private */ handleDefaultExplosion(explosion) { // Dans un vrai jeu, on vérifierait la distance entre l'explosion et les cibles // Ici, on simule des dégâts au bras const armDamage = Math.floor(explosion.damage * 0.5); // 50% des dégâts à l'explosion this.armHealth = nekomaths.neksub(this.armHealth, armDamage); this.emit('explosionDamageToArm', { damage: armDamage, source: explosion.source, currentArmHealth: this.armHealth }); console.log(`[Crocobras] L'explosion inflige ${armDamage} dégâts au bras. Vie restante: ${this.armHealth}`); if (this.armHealth <= 0) { this.crocover(); } } /** * Version améliorée de crocokill qui prend en compte les nouvelles mécaniques * @param {number} [crocoId] - ID spécifique du crocodile tué (optionnel) * @returns {boolean} True si un crocodile a été tué, false sinon */ crocokillAdvanced(crocoId = null) { const killed = this.crocokill(); // Appel de la fonction originale if (killed && crocoId) { // Nettoyer les données du crocodile mort if (this.crocodileHealths && this.crocodileHealths[crocoId]) { delete this.crocodileHealths[crocoId]; } if (this.crocodileStrengths && this.crocodileStrengths[crocoId]) { delete this.crocodileStrengths[crocoId]; } if (this.crocodileSpeeds && this.crocodileSpeeds[crocoId]) { delete this.crocodileSpeeds[crocoId]; } if (this.crocodileDances && this.crocodileDances[crocoId]) { delete this.crocodileDances[crocoId]; } this.emit('crocodileDataCleared', { crocoId }); } return killed; } /** * crocom: Permet d'écrire des systèmes de combo qui augmentent le score ou déclenchent des effets spéciaux. * @param {string} comboType - Type de combo (ex: 'killStreak', 'perfectAim', 'rapidKills') * @param {Function} comboLogic - Logique du combo qui gère le déclenchement et les effets * @param {Object} [options] - Options du combo (seuil, multiplicateur, durée, etc.) */ crocom(comboType, comboLogic, options = {}) { if (typeof comboLogic !== 'function') { throw new Error("crocom: comboLogic doit être une fonction."); } if (!this.combos) { this.combos = {}; this.comboCounters = {}; } this.combos[comboType] = { logic: comboLogic, options: { threshold: 3, multiplier: 1.5, resetTime: 5000, maxLevel: 10, ...options }, isActive: false, level: 0 }; this.comboCounters[comboType] = 0; this.emit('comboRegistered', { type: comboType, options }); console.log(`[Crocobras] Combo '${comboType}' enregistré.`); } /** * Déclenche la vérification d'un combo * @param {string} comboType - Type de combo à vérifier * @param {Object} [context] - Contexte pour la logique du combo */ triggerCombo(comboType, context = {}) { if (!this.combos || !this.combos[comboType]) return false; const combo = this.combos[comboType]; this.comboCounters[comboType]++; const result = combo.logic.call(this, this.comboCounters[comboType], combo.options, context); if (result && this.comboCounters[comboType] >= combo.options.threshold) { combo.isActive = true; combo.level = Math.min(combo.level + 1, combo.options.maxLevel); this.emit('comboTriggered', { type: comboType, level: combo.level, counter: this.comboCounters[comboType], result: result }); console.log(`[Crocobras] Combo '${comboType}' niveau ${combo.level} déclenché !`); // Reset automatique après un délai setTimeout(() => { this.resetCombo(comboType); }, combo.options.resetTime); } return result; } /** * Remet à zéro un combo * @param {string} comboType - Type de combo à reset */ resetCombo(comboType) { if (this.combos && this.combos[comboType]) { this.combos[comboType].isActive = false; this.combos[comboType].level = 0; this.comboCounters[comboType] = 0; this.emit('comboReset', { type: comboType }); console.log(`[Crocobras] Combo '${comboType}' remis à zéro.`); } } /** * crocomode: Permet aux développeurs de créer leurs propres modes de défis. * @param {string} modeName - Nom du mode de défi * @param {Function} modeLogic - Logique personnalisée du mode * @param {Object} [settings] - Paramètres spécifiques au mode */ crocomode(modeName, modeLogic, settings = {}) { if (typeof modeLogic !== 'function') { throw new Error("crocomode: modeLogic doit être une fonction."); } if (!this.gameModes) { this.gameModes = {}; } this.gameModes[modeName] = { logic: modeLogic, settings: { timeLimit: null, objectives: [], rewards: {}, difficulty: 'normal', ...settings }, isActive: false, progress: {} }; this.emit('gameModeRegistered', { name: modeName, settings }); console.log(`[Crocobras] Mode de jeu '${modeName}' enregistré.`); } /** * Active un mode de jeu spécifique * @param {string} modeName - Nom du mode à activer * @param {Object} [parameters] - Paramètres d'activation */ activateGameMode(modeName, parameters = {}) { if (!this.gameModes || !this.gameModes[modeName]) { console.warn(`[Crocobras] Mode '${modeName}' non trouvé.`); return false; } const mode = this.gameModes[modeName]; mode.isActive = true; mode.progress = { startTime: Date.now(), ...parameters }; mode.logic.call(this, mode.settings, mode.progress); this.emit('gameModeActivated', { name: modeName, settings: mode.settings, progress: mode.progress }); console.log(`[Crocobras] Mode '${modeName}' activé !`); return true; } /** * crocorpes: Permet aux développeurs de créer des armures avec des propriétés spéciales. * @param {string} armorType - Type d'armure * @param {Object} properties - Propriétés de l'armure * @param {Function} [armorLogic] - Logique personnalisée de l'armure */ crocorpes(armorType, properties, armorLogic = null) { if (!this.armors) { this.armors = {}; this.equippedArmor = null; } this.armors[armorType] = { properties: { defense: 0, resistance: {}, effects: [], durability: 100, ...properties }, logic: armorLogic, isEquipped: false }; this.emit('armorCreated', { type: armorType, properties }); console.log(`[Crocobras] Armure '${armorType}' créée.`); } /** * Équipe une armure * @param {string} armorType - Type d'armure à équiper */ equipArmor(armorType) { if (!this.armors || !this.armors[armorType]) return false; // Déséquiper l'armure actuelle if (this.equippedArmor) { this.armors[this.equippedArmor].isEquipped = false; } // Équiper la nouvelle armure this.armors[armorType].isEquipped = true; this.equippedArmor = armorType; // Appliquer la logique de l'armure si elle existe if (this.armors[armorType].logic) { this.armors[armorType].logic.call(this, this.armors[armorType].properties); } this.emit('armorEquipped', { type: armorType, properties: this.armors[armorType].properties }); console.log(`[Crocobras] Armure '${armorType}' équipée.`); return true; } /** * crocodial: Permet aux développeurs de créer leurs propres dialogues personnalisés. * @param {string} dialogueId - Identifiant unique du dialogue * @param {Object} dialogueData - Données du dialogue (textes, choix, conditions) * @param {Function} [dialogueLogic] - Logique personnalisée du dialogue */ crocodial(dialogueId, dialogueData, dialogueLogic = null) { if (!this.dialogues) { this.dialogues = {}; this.currentDialogue = null; } this.dialogues[dialogueId] = { data: { texts: [], choices: [], conditions: {}, speaker: 'narrator', ...dialogueData }, logic: dialogueLogic, isActive: false, currentStep: 0 }; this.emit('dialogueCreated', { id: dialogueId, data: dialogueData }); console.log(`[Crocobras] Dialogue '${dialogueId}' créé.`); } /** * Lance un dialogue * @param {string} dialogueId - ID du dialogue à lancer * @param {Object} [context] - Contexte pour le dialogue */ startDialogue(dialogueId, context = {}) { if (!this.dialogues || !this.dialogues[dialogueId]) return false; const dialogue = this.dialogues[dialogueId]; dialogue.isActive = true; dialogue.currentStep = 0; this.currentDialogue = dialogueId; if (dialogue.logic) { dialogue.logic.call(this, dialogue.data, context); } this.emit('dialogueStarted', { id: dialogueId, data: dialogue.data, context: context }); console.log(`[Crocobras] Dialogue '${dialogueId}' démarré.`); return true; } /** * crocomise: Permet aux développeurs d'écrire des logiques de missions ou quêtes. * @param {string} missionId - ID unique de la mission * @param {Object} missionData - Données de la mission (objectifs, récompenses, etc.) * @param {Function} missionLogic - Logique personnalisée de la mission */ crocomise(missionId, missionData, missionLogic) { if (typeof missionLogic !== 'function') { throw new Error("crocomise: missionLogic doit être une fonction."); } if (!this.missions) { this.missions = {}; this.activeMissions = []; this.completedMissions = []; } this.missions[missionId] = { data: { title: 'Mission sans titre', description: '', objectives: [], rewards: {}, difficulty: 'normal', timeLimit: null, ...missionData }, logic: missionLogic, status: 'available', // available, active, completed, failed progress: {}, startTime: null }; this.emit('missionCreated', { id: missionId, data: missionData }); console.log(`[Crocobras] Mission '${missionId}' créée.`); } /** * Démarre une mission * @param {string} missionId - ID de la mission à démarrer */ startMission(missionId) { if (!this.missions || !this.missions[missionId]) return false; const mission = this.missions[missionId]; if (mission.status !== 'available') return false; mission.status = 'active'; mission.startTime = Date.now(); mission.progress = {}; this.activeMissions.push(missionId); mission.logic.call(this, mission.data, mission.progress); this.emit('missionStarted', { id: missionId, data: mission.data, progress: mission.progress }); console.log(`[Crocobras] Mission '${missionId}' démarrée.`); return true; } /** * Complète une mission * @param {string} missionId - ID de la mission à compléter * @param {Object} [results] - Résultats de la mission */ completeMission(missionId, results = {}) { if (!this.missions || !this.missions[missionId]) return false; const mission = this.missions[missionId]; if (mission.status !== 'active') return false; mission.status = 'completed'; this.activeMissions = this.activeMissions.filter(id => id !== missionId); this.completedMissions.push(missionId); this.emit('missionCompleted', { id: missionId, data: mission.data, results: results, rewards: mission.data.rewards }); console.log(`[Crocobras] Mission '${missionId}' terminée !`); return true; } /** * crocomons: Permet aux développeurs de créer leurs propres systèmes de monnaie et boutique. * @param {string} currencyName - Nom de la monnaie * @param {Object} shopData - Données de la boutique (articles, prix, etc.) * @param {Function} purchaseLogic - Logique d'achat personnalisée */ crocomons(currencyName, shopData, purchaseLogic) { if (typeof purchaseLogic !== 'function') { throw new Error("crocomons: purchaseLogic doit être une fonction."); } if (!this.economy) { this.economy = { currencies: {}, shop: {}, inventory: {}, transactions: [] }; } this.economy.currencies[currencyName] = { amount: shopData.startingAmount || 0, properties: shopData.currencyProperties || {} }; this.economy.shop[currencyName] = { items: shopData.items || [], logic: purchaseLogic, settings: shopData.settings || {} }; this.emit('economySystemCreated', { currency: currencyName, shopData }); console.log(`[Crocobras] Système économique '${currencyName}' créé.`); } /** * Effectue un achat dans la boutique * @param {string} currencyName - Nom de la monnaie utilisée * @param {string} itemId - ID de l'article à acheter * @param {number} [quantity] - Quantité à acheter */ purchase(currencyName, itemId, quantity = 1) { if (!this.economy || !this.economy.shop[currencyName]) return false; const shop = this.economy.shop[currencyName]; const currency = this.economy.currencies[currencyName]; const result = shop.logic.call(this, { itemId: itemId, quantity: quantity, currency: currency, inventory: this.economy.inventory, shop: shop }); if (result.success) { this.economy.transactions.push({ timestamp: Date.now(), type: 'purchase', currencyName: currencyName, itemId: itemId, quantity: quantity, cost: result.cost }); this.emit('purchaseCompleted', { currencyName, itemId, quantity, result }); console.log(`[Crocobras] Achat réussi: ${quantity}x ${itemId}`); } return result; } /** * crocodym: Permet aux développeurs de coder des logiques de changements environnementaux. * @param {string} environmentId - ID de l'environnement * @param {Object} environmentData - Données de l'environnement * @param {Function} environmentLogic - Logique des changements environnementaux */ crocodym(environmentId, environmentData, environmentLogic) { if (typeof environmentLogic !== 'function') { throw new Error("crocodym: environmentLogic doit être une fonction."); } if (!this.environments) { this.environments = {}; this.currentEnvironment = null; } this.environments[environmentId] = { data: { obstacles: [], effects: [], climate: 'normal', visibility: 1.0, ...environmentData }, logic: environmentLogic, isActive: false, lastUpdate: Date.now() }; this.emit('environmentCreated', { id: environmentId, data: environmentData }); console.log(`[Crocobras] Environnement '${environmentId}' créé.`); } /** * Active un environnement * @param {string} environmentId - ID de l'environnement à activer * @param {Object} [parameters] - Paramètres d'activation */ activateEnvironment(environmentId, parameters = {}) { if (!this.environments || !this.environments[environmentId]) return false; // Désactiver l'environnement actuel if (this.currentEnvironment) { this.environments[this.currentEnvironment].isActive = false; } const environment = this.environments[environmentId]; environment.isActive = true; environment.lastUpdate = Date.now(); this.currentEnvironment = environmentId; environment.logic.call(this, environment.data, parameters); this.emit('environmentActivated', { id: environmentId, data: environment.data, parameters }); console.log(`[Crocobras] Environnement '${environmentId}' activé.`); return true; } /** * crocopay: Permet aux développeurs de scripter des logiques pour des changements d'assets personnalisés. * @param {string} assetType - Type d'asset (background, crocodile, arm, etc.) * @param {Object} assetData - Données de l'asset * @param {Function} customizationLogic - Logique de personnalisation */ crocopay(assetType, assetData, customizationLogic) { if (typeof customizationLogic !== 'function') { throw new Error("crocopay: customizationLogic doit être une fonction."); } if (!this.assetCustomization) { this.assetCustomization = {}; this.equippedAssets = {}; } if (!this.assetCustomization[assetType]) { this.assetCustomization[assetType] = {}; } const assetId = assetData.id || `${assetType}_${Date.now()}`; this.assetCustomization[assetType][assetId] = { data: { name: assetData.name || 'Asset sans nom', rarity: assetData.rarity || 'common', unlocked: assetData.unlocked || false, price: assetData.price || 0, ...assetData }, logic: customizationLogic, isEquipped: false }; this.emit('assetCreated', { type: assetType, id: assetId, data: assetData }); console.log(`[Crocobras] Asset '${assetId}' de type '${assetType}' créé.`); } /** * Équipe un asset personnalisé * @param {string} assetType - Type d'asset * @param {string} assetId - ID de l'asset à équiper */ equipAsset(assetType, assetId) { if (!this.assetCustomization || !this.assetCustomization[assetType] || !this.assetCustomization[assetType][assetId]) { return false; } const asset = this.assetCustomization[assetType][assetId]; if (!asset.data.unlocked) return false; // Déséquiper l'asset actuel du même type if (this.equippedAssets[assetType]) { const currentAsset = this.assetCustomization[assetType][this.equippedAssets[assetType]]; if (currentAsset) currentAsset.isEquipped = false; } // Équiper le nouvel asset asset.isEquipped = true; this.equippedAssets[assetType] = assetId; asset.logic.call(this, asset.data); this.emit('assetEquipped', { type: assetType, id: assetId, data: asset.data }); console.log(`[Crocobras] Asset '${assetId}' équipé pour '${assetType}'.`); return true; } /** * crocia: Permet aux développeurs de coder des comportements IA personnalisés pour les crocodiles. * @param {number} crocoId - ID du crocodile * @param {string} aiType - Type d'IA (aggressive, defensive, smart, random, etc.) * @param {Function} aiLogic - Logique de l'IA personnalisée * @param {Object} [aiSettings] - Paramètres de l'IA */ crocia(crocoId, aiType, aiLogic, aiSettings = {}) { if (typeof aiLogic !== 'function') { throw new Error("crocia: aiLogic doit être une fonction."); } if (!this.crocodileAI) { this.crocodileAI = {}; } this.crocodileAI[crocoId] = { type: aiType, logic: aiLogic, settings: { aggressiveness: 0.5, intelligence: 0.5, adaptability: 0.3, memory: [], ...aiSettings }, state: 'idle', lastDecision: Date.now(), decisions: [] }; this.emit('crocodileAISet', { crocoId, aiType, settings: aiSettings }); console.log(`[Crocobras] IA '${aiType}' configurée pour le crocodile ${crocoId}.`); } /** * Met à jour l'IA d'un crocodile * @param {number} crocoId - ID du crocodile * @param {Object} [context] - Contexte pour la prise de décision */ updateCrocodileAI(crocoId, context = {}) { if (!this.crocodileAI || !this.crocodileAI[crocoId]) return; const ai = this.crocodileAI[crocoId]; const gameState = this.getGameState(); const decision = ai.logic.call(this, { crocoId: crocoId, gameState: gameState, aiState: ai.state, settings: ai.settings, memory: ai.settings.memory, context: context }); if (decision) { ai.state = decision.newState || ai.state; ai.lastDecision = Date.now(); ai.decisions.push({ timestamp: Date.now(), decision: decision, context: context }); // Garder seulement les 10 dernières décisions en mémoire if (ai.decisions.length > 10) { ai.decisions.shift(); } this.emit('crocodileAIDecision', { crocoId, decision, aiType: ai.type, context }); } } /** * crocohab: Permet aux développeurs de scripter des logiques d'accessoires à collecter ou de succès. * @param {string} collectibleType - Type de collectible (achievement, item, trophy, etc.) * @param {Object} collectibleData - Données du collectible * @param {Function} collectibleLogic - Logique de collecte personnalisée */ crocohab(collectibleType, collectibleData, collectibleLogic) { if (typeof collectibleLogic !== 'function') { throw new Error("crocohab: collectibleLogic doit être une fonction."); } if (!this.collectibles) { this.collectibles = {}; this.unlockedCollectibles = []; } if (!this.collectibles[collectibleType]) { this.collectibles[collectibleType] = {}; } const collectibleId = collectibleData.id || `${collectibleType}_${Date.now()}`; this.collectibles[collectibleType][collectibleId] = { data: { name: collectibleData.name || 'Collectible sans nom', description: collectibleData.description || '', rarity: collectibleData.rarity || 'common', rewards: collectibleData.rewards || {}, requirements: collectibleData.requirements || {}, ...collectibleData }, logic: collectibleLogic, isUnlocked: false, unlockedAt: null, progress: {} }; this.emit('collectibleCreated', { type: collectibleType, id: collectibleId, data: collectibleData }); console.log(`[Crocobras] Collectible '${collectibleId}' de type '${collectibleType}' créé.`); } /** * Vérifie et débloque des collectibles * @param {string} collectibleType - Type de collectible à vérifier * @param {Object} [context] - Contexte pour la vérification */ checkCollectibles(collectibleType, context = {}) { if (!this.collectibles || !this.collectibles[collectibleType]) return; Object.entries(this.collectibles[collectibleType]).forEach(([id, collectible]) => {