diff --git "a/index-3.js" "b/index-3.js" new file mode 100644--- /dev/null +++ "b/index-3.js" @@ -0,0 +1,2859 @@ +// 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]) => { + if (!collectible.isUnlocked) { + const result = collectible.logic.call(this, { + collectibleData: collectible.data, + gameState: this.getGameState(), + context: context, + progress: collectible.progress + }); + + if (result && result.unlocked) { + collectible.isUnlocked = true; + collectible.unlockedAt = Date.now(); + collectible.progress = result.progress || {}; + this.unlockedCollectibles.push(`${collectibleType}:${id}`); + + this.emit('collectibleUnlocked', { + type: collectibleType, + id: id, + data: collectible.data, + rewards: collectible.data.rewards + }); + + console.log(`[Crocobras] Collectible '${id}' débloqué !`); + } + } + }); + } + + /** + * crocotive: Fonction créative pour des messages aléatoires envoyés par différents personnages. + * @param {string} messageType - Type de message (crocodile, arm, narrator, etc.) + * @param {Object} messageData - Données des messages + * @param {Function} messageLogic - Logique de sélection des messages + */ + crocotive(messageType, messageData, messageLogic) { + if (typeof messageLogic !== 'function') { + throw new Error("crocotive: messageLogic doit être une fonction."); + } + + if (!this.creativeMessages) { + this.creativeMessages = {}; + } + + this.creativeMessages[messageType] = { + data: { + messages: messageData.messages || [], + frequency: messageData.frequency || 'random', + conditions: messageData.conditions || {}, + speakers: messageData.speakers || [messageType], + ...messageData + }, + logic: messageLogic, + lastMessage: null, + messageHistory: [] + }; + + this.emit('creativeMessagesRegistered', { type: messageType, data: messageData }); + console.log(`[Crocobras] Messages créatifs '${messageType}' enregistrés.`); + } + + /** + * Déclenche un message créatif + * @param {string} messageType - Type de message à déclencher + * @param {Object} [context] - Contexte pour la sélection du message + */ + triggerCreativeMessage(messageType, context = {}) { + if (!this.creativeMessages || !this.creativeMessages[messageType]) return null; + + const messageSystem = this.creativeMessages[messageType]; + const gameState = this.getGameState(); + + const result = messageSystem.logic.call(this, { + messageData: messageSystem.data, + gameState: gameState, + context: context, + history: messageSystem.messageHistory + }); + + if (result && result.message) { + messageSystem.lastMessage = { + timestamp: Date.now(), + message: result.message, + speaker: result.speaker || messageType, + context: context + }; + + messageSystem.messageHistory.push(messageSystem.lastMessage); + + // Garder seulement les 20 derniers messages + if (messageSystem.messageHistory.length > 20) { + messageSystem.messageHistory.shift(); + } + + this.emit('creativeMessageTriggered', { + type: messageType, + message: result.message, + speaker: result.speaker, + context: context + }); + + console.log(`[Crocobras] Message créatif (${result.speaker}): ${result.message}`); + return result; + } + + return null; + } + + /** + * croconage: Permet aux développeurs de créer leurs propres personnages personnalisés. + * @param {string} characterId - ID unique du personnage + * @param {Object} characterData - Données du personnage + * @param {Function} characterLogic - Logique de comportement du personnage + */ + croconage(characterId, characterData, characterLogic) { + if (typeof characterLogic !== 'function') { + throw new Error("croconage: characterLogic doit être une fonction."); + } + + if (!this.customCharacters) { + this.customCharacters = {}; + this.activeCharacters = []; + } + + this.customCharacters[characterId] = { + data: { + name: characterData.name || 'Personnage sans nom', + type: characterData.type || 'neutral', + health: characterData.health || 100, + abilities: characterData.abilities || [], + appearance: characterData.appearance || {}, + personality: characterData.personality || {}, + ...characterData + }, + logic: characterLogic, + isActive: false, + state: 'idle', + interactions: [], + lastUpdate: Date.now() + }; + + this.emit('customCharacterCreated', { id: characterId, data: characterData }); + console.log(`[Crocobras] Personnage personnalisé '${characterId}' créé.`); + } + + /** + * Active un personnage personnalisé + * @param {string} characterId - ID du personnage à activer + * @param {Object} [spawnData] - Données d'apparition + */ + spawnCharacter(characterId, spawnData = {}) { + if (!this.customCharacters || !this.customCharacters[characterId]) return false; + + const character = this.customCharacters[characterId]; + if (character.isActive) return false; + + character.isActive = true; + character.state = spawnData.initialState || 'idle'; + character.lastUpdate = Date.now(); + + if (!this.activeCharacters.includes(characterId)) { + this.activeCharacters.push(characterId); + } + + character.logic.call(this, { + characterData: character.data, + gameState: this.getGameState(), + spawnData: spawnData, + action: 'spawn' + }); + + this.emit('characterSpawned', { + id: characterId, + data: character.data, + spawnData: spawnData + }); + + console.log(`[Crocobras] Personnage '${characterId}' apparu dans le jeu.`); + return true; + } + + /** + * Met à jour un personnage personnalisé + * @param {string} characterId - ID du personnage à mettre à jour + * @param {Object} [updateData] - Données de mise à jour + */ + updateCharacter(characterId, updateData = {}) { + if (!this.customCharacters || !this.customCharacters[characterId] || !this.customCharacters[characterId].isActive) { + return; + } + + const character = this.customCharacters[characterId]; + character.lastUpdate = Date.now(); + + const result = character.logic.call(this, { + characterData: character.data, + gameState: this.getGameState(), + updateData: updateData, + currentState: character.state, + action: 'update' + }); + + if (result) { + character.state = result.newState || character.state; + + if (result.interaction) { + character.interactions.push({ + timestamp: Date.now(), + interaction: result.interaction, + context: updateData + }); + } + + this.emit('characterUpdated', { + id: characterId, + state: character.state, + result: result + }); + } + } + + // ================= NOUVELLES FONCTIONNALITÉS v1.3.0 ================= + + /** + * crocojom: Permet aux développeurs de créer des quêtes et missions dynamiques qui s'adaptent aux choix des joueurs. + * @param {string} questId - ID unique de la quête + * @param {Object} questData - Données de la quête (objectifs, branches, récompenses) + * @param {Function} questLogic - Logique personnalisée de la quête dynamique + */ + crocojom(questId, questData, questLogic) { + if (typeof questLogic !== 'function') { + throw new Error("crocojom: questLogic doit être une fonction."); + } + + if (!this.dynamicQuests) { + this.dynamicQuests = {}; + this.activeQuests = []; + } + + this.dynamicQuests[questId] = { + data: { + title: questData.title || 'Quête dynamique', + description: questData.description || '', + branches: questData.branches || {}, + currentBranch: questData.startBranch || 'start', + playerChoices: [], + rewards: questData.rewards || {}, + conditions: questData.conditions || {}, + ...questData + }, + logic: questLogic, + isActive: false, + progress: {} + }; + + this.emit('dynamicQuestCreated', { questId, data: questData }); + console.log(`[Crocobras] Quête dynamique '${questId}' créée.`); + } + + /** + * Démarre une quête dynamique + * @param {string} questId - ID de la quête à démarrer + * @param {Object} [initialChoices] - Choix initiaux du joueur + */ + startDynamicQuest(questId, initialChoices = {}) { + if (!this.dynamicQuests || !this.dynamicQuests[questId]) return false; + + const quest = this.dynamicQuests[questId]; + quest.isActive = true; + quest.data.playerChoices = [initialChoices]; + quest.progress = { startTime: Date.now() }; + + this.activeQuests.push(questId); + + quest.logic.call(this, quest.data, quest.progress, 'start'); + + this.emit('dynamicQuestStarted', { questId, choices: initialChoices }); + console.log(`[Crocobras] Quête dynamique '${questId}' démarrée.`); + return true; + } + + /** + * Effectue un choix dans une quête dynamique + * @param {string} questId - ID de la quête + * @param {Object} choice - Choix du joueur + */ + makeDynamicQuestChoice(questId, choice) { + if (!this.dynamicQuests || !this.dynamicQuests[questId] || !this.dynamicQuests[questId].isActive) { + return false; + } + + const quest = this.dynamicQuests[questId]; + quest.data.playerChoices.push(choice); + + const result = quest.logic.call(this, quest.data, quest.progress, 'choice', choice); + + if (result && result.newBranch) { + quest.data.currentBranch = result.newBranch; + } + + this.emit('dynamicQuestChoice', { questId, choice, result }); + console.log(`[Crocobras] Choix effectué dans la quête '${questId}': ${JSON.stringify(choice)}`); + return result; + } + + /** + * crocera: Permet aux développeurs de créer leur propre système de climat qui interagit avec le comportement des crocodiles ou du bras. + * @param {string} weatherId - ID unique du climat + * @param {Object} weatherData - Données météorologiques + * @param {Function} weatherLogic - Logique personnalisée du climat + */ + crocera(weatherId, weatherData, weatherLogic) { + if (typeof weatherLogic !== 'function') { + throw new Error("crocera: weatherLogic doit être une fonction."); + } + + if (!this.weatherSystems) { + this.weatherSystems = {}; + this.currentWeather = null; + } + + this.weatherSystems[weatherId] = { + data: { + name: weatherData.name || 'Climat personnalisé', + effects: weatherData.effects || {}, + intensity: weatherData.intensity || 1.0, + duration: weatherData.duration || 30000, + crocodileEffects: weatherData.crocodileEffects || {}, + armEffects: weatherData.armEffects || {}, + visualEffects: weatherData.visualEffects || {}, + ...weatherData + }, + logic: weatherLogic, + isActive: false, + startTime: null + }; + + this.emit('weatherSystemCreated', { weatherId, data: weatherData }); + console.log(`[Crocobras] Système climatique '${weatherId}' créé.`); + } + + /** + * Active un système climatique + * @param {string} weatherId - ID du climat à activer + */ + activateWeather(weatherId) { + if (!this.weatherSystems || !this.weatherSystems[weatherId]) return false; + + // Désactiver le climat actuel + if (this.currentWeather) { + this.weatherSystems[this.currentWeather].isActive = false; + } + + const weather = this.weatherSystems[weatherId]; + weather.isActive = true; + weather.startTime = Date.now(); + this.currentWeather = weatherId; + + weather.logic.call(this, weather.data, this.getGameState()); + + this.emit('weatherActivated', { weatherId, data: weather.data }); + console.log(`[Crocobras] Climat '${weatherId}' activé.`); + + // Désactiver automatiquement après la durée + if (weather.data.duration > 0) { + setTimeout(() => { + this.deactivateWeather(weatherId); + }, weather.data.duration); + } + + return true; + } + + /** + * Désactive un système climatique + * @param {string} weatherId - ID du climat à désactiver + */ + deactivateWeather(weatherId) { + if (!this.weatherSystems || !this.weatherSystems[weatherId]) return false; + + this.weatherSystems[weatherId].isActive = false; + if (this.currentWeather === weatherId) { + this.currentWeather = null; + } + + this.emit('weatherDeactivated', { weatherId }); + console.log(`[Crocobras] Climat '${weatherId}' désactivé.`); + return true; + } + + /** + * crocogiw: Permet aux développeurs de créer des crocodiles ou des événements spéciaux qui n'apparaissent qu'à certains moments clés. + * @param {string} specialId - ID de l'élément spécial + * @param {Object} specialData - Données de l'élément spécial + * @param {Function} specialLogic - Logique de déclenchement personnalisée + */ + crocogiw(specialId, specialData, specialLogic) { + if (typeof specialLogic !== 'function') { + throw new Error("crocogiw: specialLogic doit être une fonction."); + } + + if (!this.specialElements) { + this.specialElements = {}; + } + + this.specialElements[specialId] = { + data: { + type: specialData.type || 'crocodile', + triggerConditions: specialData.triggerConditions || {}, + behavior: specialData.behavior || {}, + rewards: specialData.rewards || {}, + rarity: specialData.rarity || 'rare', + cooldown: specialData.cooldown || 0, + ...specialData + }, + logic: specialLogic, + isActive: false, + lastTriggered: null, + triggerCount: 0 + }; + + this.emit('specialElementCreated', { specialId, data: specialData }); + console.log(`[Crocobras] Élément spécial '${specialId}' créé.`); + } + + /** + * Vérifie et déclenche les éléments spéciaux selon les conditions + * @param {Object} [gameContext] - Contexte du jeu pour les vérifications + */ + checkSpecialElements(gameContext = {}) { + if (!this.specialElements) return; + + Object.entries(this.specialElements).forEach(([specialId, element]) => { + if (element.isActive) return; + + const now = Date.now(); + const cooldownPassed = !element.lastTriggered || + (now - element.lastTriggered) >= element.data.cooldown; + + if (cooldownPassed) { + const shouldTrigger = element.logic.call(this, element.data, { + ...this.getGameState(), + ...gameContext + }); + + if (shouldTrigger) { + this.triggerSpecialElement(specialId); + } + } + }); + } + + /** + * Déclenche un élément spécial + * @param {string} specialId - ID de l'élément spécial à déclencher + */ + triggerSpecialElement(specialId) { + if (!this.specialElements || !this.specialElements[specialId]) return false; + + const element = this.specialElements[specialId]; + element.isActive = true; + element.lastTriggered = Date.now(); + element.triggerCount++; + + this.emit('specialElementTriggered', { + specialId, + data: element.data, + triggerCount: element.triggerCount + }); + + console.log(`[Crocobras] Élément spécial '${specialId}' déclenché !`); + return true; + } + + /** + * crocorin: Permet de définir des comportements IA avancés avec prise de décisions personnalisées pour les crocodiles. + * @param {number} crocoId - ID du crocodile + * @param {Object} aiConfig - Configuration de l'IA avancée + * @param {Function} decisionLogic - Logique de prise de décision personnalisée + */ + crocorin(crocoId, aiConfig, decisionLogic) { + if (typeof decisionLogic !== 'function') { + throw new Error("crocorin: decisionLogic doit être une fonction."); + } + + if (!this.advancedCrocodileAI) { + this.advancedCrocodileAI = {}; + } + + this.advancedCrocodileAI[crocoId] = { + config: { + learningRate: aiConfig.learningRate || 0.1, + memorySize: aiConfig.memorySize || 50, + decisionFrequency: aiConfig.decisionFrequency || 1000, + personalityTraits: aiConfig.personalityTraits || {}, + adaptiveRules: aiConfig.adaptiveRules || [], + ...aiConfig + }, + decisionLogic: decisionLogic, + memory: [], + currentDecision: null, + decisionHistory: [], + learningData: {} + }; + + this.emit('advancedAICreated', { crocoId, config: aiConfig }); + console.log(`[Crocobras] IA avancée configurée pour le crocodile ${crocoId}.`); + } + + /** + * Exécute la prise de décision IA avancée pour un crocodile + * @param {number} crocoId - ID du crocodile + * @param {Object} [situation] - Situation actuelle pour la prise de décision + */ + executeAdvancedAIDecision(crocoId, situation = {}) { + if (!this.advancedCrocodileAI || !this.advancedCrocodileAI[crocoId]) return null; + + const ai = this.advancedCrocodileAI[crocoId]; + const gameState = this.getGameState(); + + const decision = ai.decisionLogic.call(this, { + crocoId: crocoId, + config: ai.config, + memory: ai.memory, + gameState: gameState, + situation: situation, + learningData: ai.learningData + }); + + if (decision) { + ai.currentDecision = decision; + ai.decisionHistory.push({ + timestamp: Date.now(), + decision: decision, + situation: situation, + gameState: { ...gameState } + }); + + // Ajouter à la mémoire + ai.memory.push({ + timestamp: Date.now(), + type: 'decision', + data: decision, + context: situation + }); + + // Limiter la taille de la mémoire + if (ai.memory.length > ai.config.memorySize) { + ai.memory.shift(); + } + + this.emit('advancedAIDecision', { crocoId, decision, situation }); + console.log(`[Crocobras] Décision IA avancée pour crocodile ${crocoId}: ${JSON.stringify(decision)}`); + } + + return decision; + } + + /** + * crocomp: Permet d'analyser les données du jeu selon la personnalisation JavaScript du développeur. + * @param {string} analysisId - ID de l'analyse + * @param {Object} analysisConfig - Configuration de l'analyse + * @param {Function} analysisLogic - Logique d'analyse personnalisée + */ + crocomp(analysisId, analysisConfig, analysisLogic) { + if (typeof analysisLogic !== 'function') { + throw new Error("crocomp: analysisLogic doit être une fonction."); + } + + if (!this.gameAnalytics) { + this.gameAnalytics = {}; + this.analyticsData = {}; + } + + this.gameAnalytics[analysisId] = { + config: { + dataPoints: analysisConfig.dataPoints || [], + updateInterval: analysisConfig.updateInterval || 5000, + reportFormat: analysisConfig.reportFormat || 'simple', + triggers: analysisConfig.triggers || [], + ...analysisConfig + }, + logic: analysisLogic, + lastUpdate: Date.now(), + reports: [] + }; + + this.analyticsData[analysisId] = {}; + + this.emit('gameAnalyticsCreated', { analysisId, config: analysisConfig }); + console.log(`[Crocobras] Système d'analyse '${analysisId}' créé.`); + } + + /** + * Exécute une analyse des données de jeu + * @param {string} analysisId - ID de l'analyse à exécuter + * @param {Object} [customData] - Données personnalisées pour l'analyse + */ + runGameAnalysis(analysisId, customData = {}) { + if (!this.gameAnalytics || !this.gameAnalytics[analysisId]) return null; + + const analytics = this.gameAnalytics[analysisId]; + const gameState = this.getGameState(); + + const report = analytics.logic.call(this, { + config: analytics.config, + gameState: gameState, + analyticsData: this.analyticsData[analysisId], + customData: customData, + previousReports: analytics.reports + }); + + if (report) { + analytics.reports.push({ + timestamp: Date.now(), + report: report + }); + analytics.lastUpdate = Date.now(); + + this.emit('gameAnalysisCompleted', { analysisId, report }); + console.log(`[Crocobras] Analyse '${analysisId}' terminée.`); + } + + return report; + } + + /** + * crocotina: Permet aux développeurs d'écrire leurs propres fonctions personnalisées en JavaScript pour leur code et leur jeu. + * @param {string} functionName - Nom de la fonction personnalisée + * @param {Function} customFunction - Fonction personnalisée du développeur + * @param {Object} [options] - Options de la fonction + */ + crocotina(functionName, customFunction, options = {}) { + if (typeof customFunction !== 'function') { + throw new Error("crocotina: customFunction doit être une fonction."); + } + + if (!this.customFunctions) { + this.customFunctions = {}; + } + + this.customFunctions[functionName] = { + function: customFunction, + options: { + async: options.async || false, + parameters: options.parameters || [], + description: options.description || '', + category: options.category || 'general', + ...options + }, + callCount: 0, + lastCalled: null + }; + + this.emit('customFunctionRegistered', { functionName, options }); + console.log(`[Crocobras] Fonction personnalisée '${functionName}' enregistrée.`); + } + + /** + * Exécute une fonction personnalisée + * @param {string} functionName - Nom de la fonction à exécuter + * @param {...any} args - Arguments à passer à la fonction + */ + executeCustomFunction(functionName, ...args) { + if (!this.customFunctions || !this.customFunctions[functionName]) { + console.warn(`[Crocobras] Fonction personnalisée '${functionName}' non trouvée.`); + return null; + } + + const customFunc = this.customFunctions[functionName]; + customFunc.callCount++; + customFunc.lastCalled = Date.now(); + + try { + const result = customFunc.function.call(this, ...args); + + this.emit('customFunctionExecuted', { + functionName, + args, + result, + callCount: customFunc.callCount + }); + + console.log(`[Crocobras] Fonction personnalisée '${functionName}' exécutée.`); + return result; + } catch (error) { + this.emit('customFunctionError', { functionName, error: error.message }); + console.error(`[Crocobras] Erreur dans la fonction '${functionName}': ${error.message}`); + return null; + } + } + + /** + * crocofaf: Permet aux développeurs de créer des mini-jeux personnalisés de quiz pour tuer plus de crocodiles ou obtenir des points/monnaie. + * @param {string} quizId - ID du quiz + * @param {Object} quizData - Données du quiz + * @param {Function} quizLogic - Logique personnalisée du quiz + */ + crocofaf(quizId, quizData, quizLogic) { + if (typeof quizLogic !== 'function') { + throw new Error("crocofaf: quizLogic doit être une fonction."); + } + + if (!this.miniGames) { + this.miniGames = {}; + } + + this.miniGames[quizId] = { + data: { + title: quizData.title || 'Quiz Crocobras', + questions: quizData.questions || [], + rewards: quizData.rewards || {}, + timeLimit: quizData.timeLimit || 30000, + difficulty: quizData.difficulty || 'normal', + categories: quizData.categories || ['general'], + ...quizData + }, + logic: quizLogic, + isActive: false, + currentQuestion: 0, + score: 0, + startTime: null + }; + + this.emit('miniGameCreated', { quizId, data: quizData }); + console.log(`[Crocobras] Mini-jeu quiz '${quizId}' créé.`); + } + + /** + * Démarre un mini-jeu quiz + * @param {string} quizId - ID du quiz à démarrer + */ + startMiniGame(quizId) { + if (!this.miniGames || !this.miniGames[quizId]) return false; + + const quiz = this.miniGames[quizId]; + quiz.isActive = true; + quiz.currentQuestion = 0; + quiz.score = 0; + quiz.startTime = Date.now(); + + quiz.logic.call(this, quiz.data, 'start'); + + this.emit('miniGameStarted', { quizId, data: quiz.data }); + console.log(`[Crocobras] Mini-jeu '${quizId}' démarré.`); + return true; + } + + /** + * Répond à une question du quiz + * @param {string} quizId - ID du quiz + * @param {any} answer - Réponse du joueur + */ + answerQuizQuestion(quizId, answer) { + if (!this.miniGames || !this.miniGames[quizId] || !this.miniGames[quizId].isActive) { + return false; + } + + const quiz = this.miniGames[quizId]; + const result = quiz.logic.call(this, quiz.data, 'answer', { + answer: answer, + currentQuestion: quiz.currentQuestion, + score: quiz.score + }); + + if (result && result.correct) { + quiz.score += result.points || 1; + } + + quiz.currentQuestion++; + + this.emit('quizAnswered', { + quizId, + answer, + result, + score: quiz.score, + question: quiz.currentQuestion + }); + + return result; + } + + /** + * crocojup: Permet aux développeurs de créer et d'afficher des messages temporaires personnalisés. + * @param {string} messageId - ID du message + * @param {Object} messageData - Données du message + * @param {Function} messageLogic - Logique personnalisée du message + */ + crocojup(messageId, messageData, messageLogic) { + if (typeof messageLogic !== 'function') { + throw new Error("crocojup: messageLogic doit être une fonction."); + } + + if (!this.temporaryMessages) { + this.temporaryMessages = {}; + this.activeMessages = []; + } + + this.temporaryMessages[messageId] = { + data: { + text: messageData.text || '', + duration: messageData.duration || 3000, + style: messageData.style || {}, + position: messageData.position || 'center', + animation: messageData.animation || 'fade', + triggers: messageData.triggers || [], + ...messageData + }, + logic: messageLogic, + isActive: false, + displayCount: 0 + }; + + this.emit('temporaryMessageCreated', { messageId, data: messageData }); + console.log(`[Crocobras] Message temporaire '${messageId}' créé.`); + } + + /** + * Affiche un message temporaire + * @param {string} messageId - ID du message à afficher + * @param {Object} [context] - Contexte pour le message + */ + showTemporaryMessage(messageId, context = {}) { + if (!this.temporaryMessages || !this.temporaryMessages[messageId]) return false; + + const message = this.temporaryMessages[messageId]; + message.isActive = true; + message.displayCount++; + + this.activeMessages.push(messageId); + + const result = message.logic.call(this, message.data, context); + + this.emit('temporaryMessageShown', { + messageId, + data: message.data, + context, + result, + displayCount: message.displayCount + }); + + console.log(`[Crocobras] Message temporaire '${messageId}' affiché.`); + + // Masquer automatiquement après la durée + setTimeout(() => { + this.hideTemporaryMessage(messageId); + }, message.data.duration); + + return true; + } + + /** + * Masque un message temporaire + * @param {string} messageId - ID du message à masquer + */ + hideTemporaryMessage(messageId) { + if (!this.temporaryMessages || !this.temporaryMessages[messageId]) return false; + + this.temporaryMessages[messageId].isActive = false; + this.activeMessages = this.activeMessages.filter(id => id !== messageId); + + this.emit('temporaryMessageHidden', { messageId }); + console.log(`[Crocobras] Message temporaire '${messageId}' masqué.`); + return true; + } + + /** + * crocodae: Permet aux développeurs de créer des power-ups temporaires personnalisés selon leur logique JavaScript. + * @param {string} powerUpId - ID du power-up + * @param {Object} powerUpData - Données du power-up + * @param {Function} powerUpLogic - Logique personnalisée du power-up + */ + crocodae(powerUpId, powerUpData, powerUpLogic) { + if (typeof powerUpLogic !== 'function') { + throw new Error("crocodae: powerUpLogic doit être une fonction."); + } + + if (!this.temporaryPowerUps) { + this.temporaryPowerUps = {}; + this.activePowerUps = []; + } + + this.temporaryPowerUps[powerUpId] = { + data: { + name: powerUpData.name || 'Power-up temporaire', + duration: powerUpData.duration || 10000, + effects: powerUpData.effects || {}, + stackable: powerUpData.stackable || false, + cooldown: powerUpData.cooldown || 5000, + rarity: powerUpData.rarity || 'common', + ...powerUpData + }, + logic: powerUpLogic, + isActive: false, + activationTime: null, + usageCount: 0 + }; + + this.emit('temporaryPowerUpCreated', { powerUpId, data: powerUpData }); + console.log(`[Crocobras] Power-up temporaire '${powerUpId}' créé.`); + } + + /** + * Active un power-up temporaire + * @param {string} powerUpId - ID du power-up à activer + * @param {Object} [context] - Contexte d'activation + */ + activateTemporaryPowerUp(powerUpId, context = {}) { + if (!this.temporaryPowerUps || !this.temporaryPowerUps[powerUpId]) return false; + + const powerUp = this.temporaryPowerUps[powerUpId]; + + // Vérifier si déjà actif et non stackable + if (powerUp.isActive && !powerUp.data.stackable) return false; + + powerUp.isActive = true; + powerUp.activationTime = Date.now(); + powerUp.usageCount++; + + if (!powerUp.data.stackable || !this.activePowerUps.includes(powerUpId)) { + this.activePowerUps.push(powerUpId); + } + + powerUp.logic.call(this, powerUp.data, context, 'activate'); + + this.emit('temporaryPowerUpActivated', { + powerUpId, + data: powerUp.data, + context, + usageCount: powerUp.usageCount + }); + + console.log(`[Crocobras] Power-up temporaire '${powerUpId}' activé.`); + + // Désactiver automatiquement après la durée + setTimeout(() => { + this.deactivateTemporaryPowerUp(powerUpId); + }, powerUp.data.duration); + + return true; + } + + /** + * Désactive un power-up temporaire + * @param {string} powerUpId - ID du power-up à désactiver + */ + deactivateTemporaryPowerUp(powerUpId) { + if (!this.temporaryPowerUps || !this.temporaryPowerUps[powerUpId]) return false; + + const powerUp = this.temporaryPowerUps[powerUpId]; + powerUp.isActive = false; + + this.activePowerUps = this.activePowerUps.filter(id => id !== powerUpId); + + powerUp.logic.call(this, powerUp.data, {}, 'deactivate'); + + this.emit('temporaryPowerUpDeactivated', { powerUpId }); + console.log(`[Crocobras] Power-up temporaire '${powerUpId}' désactivé.`); + return true; + } + + /** + * crocolog: Permet aux développeurs de créer leurs propres logs personnalisés pour le jeu. + * @param {string} logId - ID du système de log + * @param {Object} logConfig - Configuration des logs + * @param {Function} logLogic - Logique personnalisée des logs + */ + crocolog(logId, logConfig, logLogic) { + if (typeof logLogic !== 'function') { + throw new Error("crocolog: logLogic doit être une fonction."); + } + + if (!this.customLogs) { + this.customLogs = {}; + } + + this.customLogs[logId] = { + config: { + prefix: logConfig.prefix || '[LOG]', + colors: logConfig.colors || {}, + format: logConfig.format || 'simple', + output: logConfig.output || 'console', + shapes: logConfig.shapes || {}, + filters: logConfig.filters || [], + ...logConfig + }, + logic: logLogic, + entries: [], + lastLog: null + }; + + this.emit('customLogCreated', { logId, config: logConfig }); + console.log(`[Crocobras] Système de log personnalisé '${logId}' créé.`); + } + + /** + * Écrit un log personnalisé + * @param {string} logId - ID du système de log + * @param {string} message - Message à logger + * @param {Object} [data] - Données supplémentaires + */ + writeCustomLog(logId, message, data = {}) { + if (!this.customLogs || !this.customLogs[logId]) return false; + + const logger = this.customLogs[logId]; + const logEntry = { + timestamp: Date.now(), + message: message, + data: data, + level: data.level || 'info' + }; + + logger.entries.push(logEntry); + logger.lastLog = logEntry; + + const formattedLog = logger.logic.call(this, logger.config, logEntry); + + this.emit('customLogWritten', { logId, entry: logEntry, formatted: formattedLog }); + + // Affichage selon la configuration + if (logger.config.output === 'console') { + console.log(formattedLog); + } + + return true; + } + + /** + * crocojust: Permet aux développeurs de créer des logiques de clonage ou d'invocation pour les crocodiles. + * @param {string} cloneId - ID du système de clonage + * @param {Object} cloneData - Données de clonage + * @param {Function} cloneLogic - Logique personnalisée de clonage + */ + crocojust(cloneId, cloneData, cloneLogic) { + if (typeof cloneLogic !== 'function') { + throw new Error("crocojust: cloneLogic doit être une fonction."); + } + + if (!this.crocodileCloning) { + this.crocodileCloning = {}; + } + + this.crocodileCloning[cloneId] = { + data: { + maxClones: cloneData.maxClones || 3, + cloneCooldown: cloneData.cloneCooldown || 5000, + cloneConditions: cloneData.cloneConditions || {}, + cloneProperties: cloneData.cloneProperties || {}, + invocationRules: cloneData.invocationRules || {}, + ...cloneData + }, + logic: cloneLogic, + activeClones: [], + lastCloneTime: null + }; + + this.emit('crocodileCloningCreated', { cloneId, data: cloneData }); + console.log(`[Crocobras] Système de clonage '${cloneId}' créé.`); + } + + /** + * Clone ou invoque des crocodiles + * @param {string} cloneId - ID du système de clonage + * @param {number} sourceCrocoId - ID du crocodile source + * @param {Object} [context] - Contexte du clonage + */ + cloneCrocodile(cloneId, sourceCrocoId, context = {}) { + if (!this.crocodileCloning || !this.crocodileCloning[cloneId]) return false; + + const cloneSystem = this.crocodileCloning[cloneId]; + const now = Date.now(); + + // Vérifier les limites et cooldowns + if (cloneSystem.activeClones.length >= cloneSystem.data.maxClones) return false; + if (cloneSystem.lastCloneTime && (now - cloneSystem.lastCloneTime) < cloneSystem.data.cloneCooldown) { + return false; + } + + const cloneResult = cloneSystem.logic.call(this, cloneSystem.data, { + sourceCrocoId: sourceCrocoId, + gameState: this.getGameState(), + context: context + }); + + if (cloneResult && cloneResult.success) { + const newCloneId = cloneResult.cloneId || Date.now(); + cloneSystem.activeClones.push({ + id: newCloneId, + sourceId: sourceCrocoId, + createdAt: now, + properties: cloneResult.properties || {} + }); + + cloneSystem.lastCloneTime = now; + + this.emit('crocodileCloned', { + cloneId, + sourceId: sourceCrocoId, + newCloneId: newCloneId, + result: cloneResult + }); + + console.log(`[Crocobras] Crocodile ${sourceCrocoId} cloné avec l'ID ${newCloneId}.`); + return newCloneId; + } + + return false; + } + + /** + * crocorare: Permet aux développeurs de créer des crocodiles spéciaux rares avec des comportements spéciaux. + * @param {string} rareId - ID du crocodile rare + * @param {Object} rareData - Données du crocodile rare + * @param {Function} rareLogic - Logique personnalisée du crocodile rare + */ + crocorare(rareId, rareData, rareLogic) { + if (typeof rareLogic !== 'function') { + throw new Error("crocorare: rareLogic doit être une fonction."); + } + + if (!this.rareCrocodiles) { + this.rareCrocodiles = {}; + } + + this.rareCrocodiles[rareId] = { + data: { + name: rareData.name || 'Crocodile Rare', + rarity: rareData.rarity || 'legendary', + spawnChance: rareData.spawnChance || 0.01, + specialAbilities: rareData.specialAbilities || [], + rewards: rareData.rewards || {}, + appearance: rareData.appearance || {}, + behavior: rareData.behavior || {}, + ...rareData + }, + logic: rareLogic, + spawnCount: 0, + lastSpawn: null, + isActive: false + }; + + this.emit('rareCrocodileCreated', { rareId, data: rareData }); + console.log(`[Crocobras] Crocodile rare '${rareId}' créé.`); + } + + /** + * Vérifie et fait apparaître des crocodiles rares + * @param {Object} [spawnContext] - Contexte d'apparition + */ + checkRareCrocodileSpawn(spawnContext = {}) { + if (!this.rareCrocodiles) return; + + Object.entries(this.rareCrocodiles).forEach(([rareId, rareCroco]) => { + if (rareCroco.isActive) return; + + const shouldSpawn = Math.random() < rareCroco.data.spawnChance; + + if (shouldSpawn) { + const spawnResult = rareCroco.logic.call(this, rareCroco.data, { + ...this.getGameState(), + ...spawnContext + }); + + if (spawnResult && spawnResult.spawn) { + rareCroco.isActive = true; + rareCroco.spawnCount++; + rareCroco.lastSpawn = Date.now(); + + this.emit('rareCrocodileSpawned', { + rareId, + data: rareCroco.data, + spawnCount: rareCroco.spawnCount, + result: spawnResult + }); + + console.log(`[Crocobras] Crocodile rare '${rareId}' est apparu !`); + } + } + }); + } + + /** + * crocomd: Permet aux développeurs de créer des mini-tutoriels de démarrage sous forme de dialogues. + * @param {string} tutorialId - ID du tutoriel + * @param {Object} tutorialData - Données du tutoriel + * @param {Function} tutorialLogic - Logique personnalisée du tutoriel + */ + crocomd(tutorialId, tutorialData, tutorialLogic) { + if (typeof tutorialLogic !== 'function') { + throw new Error("crocomd: tutorialLogic doit être une fonction."); + } + + if (!this.tutorials) { + this.tutorials = {}; + } + + this.tutorials[tutorialId] = { + data: { + title: tutorialData.title || 'Tutoriel', + steps: tutorialData.steps || [], + targetLevels: tutorialData.targetLevels || [1], + dialogues: tutorialData.dialogues || [], + rewards: tutorialData.rewards || {}, + optional: tutorialData.optional || false, + ...tutorialData + }, + logic: tutorialLogic, + isActive: false, + currentStep: 0, + completed: false + }; + + this.emit('tutorialCreated', { tutorialId, data: tutorialData }); + console.log(`[Crocobras] Tutoriel '${tutorialId}' créé.`); + } + + /** + * Démarre un tutoriel + * @param {string} tutorialId - ID du tutoriel à démarrer + */ + startTutorial(tutorialId) { + if (!this.tutorials || !this.tutorials[tutorialId]) return false; + + const tutorial = this.tutorials[tutorialId]; + tutorial.isActive = true; + tutorial.currentStep = 0; + + tutorial.logic.call(this, tutorial.data, 'start'); + + this.emit('tutorialStarted', { tutorialId, data: tutorial.data }); + console.log(`[Crocobras] Tutoriel '${tutorialId}' démarré.`); + return true; + } + + /** + * Avance à l'étape suivante du tutoriel + * @param {string} tutorialId - ID du tutoriel + */ + nextTutorialStep(tutorialId) { + if (!this.tutorials || !this.tutorials[tutorialId] || !this.tutorials[tutorialId].isActive) { + return false; + } + + const tutorial = this.tutorials[tutorialId]; + tutorial.currentStep++; + + if (tutorial.currentStep >= tutorial.data.steps.length) { + tutorial.completed = true; + tutorial.isActive = false; + + this.emit('tutorialCompleted', { tutorialId, rewards: tutorial.data.rewards }); + console.log(`[Crocobras] Tutoriel '${tutorialId}' terminé !`); + } else { + tutorial.logic.call(this, tutorial.data, 'step', tutorial.currentStep); + + this.emit('tutorialStepChanged', { + tutorialId, + step: tutorial.currentStep, + stepData: tutorial.data.steps[tutorial.currentStep] + }); + } + + return true; + } + + /** + * crocoglop: Permet aux développeurs de créer des événements facultatifs de personnalisation pour leurs crocodiles. + * @param {number} crocoId - ID du crocodile + * @param {Object} customData - Données de personnalisation + * @param {Function} customLogic - Logique personnalisée + */ + crocoglop(crocoId, customData, customLogic) { + if (typeof customLogic !== 'function') { + throw new Error("crocoglop: customLogic doit être une fonction."); + } + + if (!this.crocodileCustomization) { + this.crocodileCustomization = {}; + } + + this.crocodileCustomization[crocoId] = { + data: { + messages: customData.messages || [], + messageInterval: customData.messageInterval || 2000, + specialBehaviors: customData.specialBehaviors || {}, + visualEffects: customData.visualEffects || {}, + sounds: customData.sounds || {}, + ...customData + }, + logic: customLogic, + isActive: false, + intervals: [], + lastAction: Date.now() + }; + + this.emit('crocodileCustomizationCreated', { crocoId, data: customData }); + console.log(`[Crocobras] Personnalisation créée pour le crocodile ${crocoId}.`); + } + + /** + * Active la personnalisation d'un crocodile + * @param {number} crocoId - ID du crocodile + */ + activateCrocodileCustomization(crocoId) { + if (!this.crocodileCustomization || !this.crocodileCustomization[crocoId]) return false; + + const customization = this.crocodileCustomization[crocoId]; + customization.isActive = true; + + // Démarrer les messages récurrents si configurés + if (customization.data.messages.length > 0 && customization.data.messageInterval > 0) { + const messageInterval = setInterval(() => { + if (customization.isActive) { + const randomMessage = customization.data.messages[ + Math.floor(Math.random() * customization.data.messages.length) + ]; + + this.emit('crocodileCustomMessage', { + crocoId, + message: randomMessage + }); + + console.log(`[Crocobras] Crocodile ${crocoId}: ${randomMessage}`); + } else { + clearInterval(messageInterval); + } + }, customization.data.messageInterval); + + customization.intervals.push(messageInterval); + } + + customization.logic.call(this, customization.data, 'activate'); + + this.emit('crocodileCustomizationActivated', { crocoId }); + console.log(`[Crocobras] Personnalisation activée pour le crocodile ${crocoId}.`); + return true; + } + + /** + * crocofarm: Permet aux développeurs de créer des bébés crocodiles avec leurs logiques de naissance/apparition et comportements. + * @param {string} babyId - ID du système de bébés crocodiles + * @param {Object} babyData - Données des bébés crocodiles + * @param {Function} babyLogic - Logique personnalisée des bébés + */ + crocofarm(babyId, babyData, babyLogic) { + if (typeof babyLogic !== 'function') { + throw new Error("crocofarm: babyLogic doit être une fonction."); + } + + if (!this.babyCrocodiles) { + this.babyCrocodiles = {}; + } + + this.babyCrocodiles[babyId] = { + data: { + maxBabies: babyData.maxBabies || 5, + spawnConditions: babyData.spawnConditions || {}, + growthTime: babyData.growthTime || 15000, + babyBehavior: babyData.babyBehavior || {}, + parentInfluence: babyData.parentInfluence || {}, + appearance: babyData.appearance || {}, + ...babyData + }, + logic: babyLogic, + activeBabies: [], + totalSpawned: 0 + }; + + this.emit('babyCrocodileSystemCreated', { babyId, data: babyData }); + console.log(`[Crocobras] Système de bébés crocodiles '${babyId}' créé.`); + } + + /** + * Fait naître un bébé crocodile + * @param {string} babyId - ID du système de bébés + * @param {number} [parentId] - ID du parent (optionnel) + * @param {Object} [birthContext] - Contexte de naissance + */ + spawnBabyCrocodile(babyId, parentId = null, birthContext = {}) { + if (!this.babyCrocodiles || !this.babyCrocodiles[babyId]) return false; + + const babySystem = this.babyCrocodiles[babyId]; + + if (babySystem.activeBabies.length >= babySystem.data.maxBabies) return false; + + const babyResult = babySystem.logic.call(this, babySystem.data, { + action: 'spawn', + parentId: parentId, + gameState: this.getGameState(), + context: birthContext + }); + + if (babyResult && babyResult.success) { + const newBabyId = babyResult.babyId || Date.now(); + const baby = { + id: newBabyId, + parentId: parentId, + birthTime: Date.now(), + isGrown: false, + properties: babyResult.properties || {} + }; + + babySystem.activeBabies.push(baby); + babySystem.totalSpawned++; + + this.emit('babyCrocodileSpawned', { + babyId, + baby: baby, + parentId: parentId, + result: babyResult + }); + + console.log(`[Crocobras] Bébé crocodile ${newBabyId} né !`); + + // Programmer la croissance + setTimeout(() => { + this.growBabyCrocodile(babyId, newBabyId); + }, babySystem.data.growthTime); + + return newBabyId; + } + + return false; + } + + /** + * Fait grandir un bébé crocodile + * @param {string} babyId - ID du système de bébés + * @param {number} babyInstanceId - ID de l'instance du bébé + */ + growBabyCrocodile(babyId, babyInstanceId) { + if (!this.babyCrocodiles || !this.babyCrocodiles[babyId]) return false; + + const babySystem = this.babyCrocodiles[babyId]; + const baby = babySystem.activeBabies.find(b => b.id === babyInstanceId); + + if (!baby || baby.isGrown) return false; + + baby.isGrown = true; + + const growthResult = babySystem.logic.call(this, babySystem.data, { + action: 'grow', + baby: baby, + gameState: this.getGameState() + }); + + this.emit('babyCrocodileGrown', { + babyId, + baby: baby, + result: growthResult + }); + + console.log(`[Crocobras] Bébé crocodile ${babyInstanceId} a grandi !`); + return true; + } + + /** + * crocenvie: Permet aux développeurs de créer des systèmes d'envies pour les crocodiles. + * @param {string} desireId - ID du système d'envies + * @param {Object} desireData - Données des envies + * @param {Function} desireLogic - Logique personnalisée des envies + */ + crocenvie(desireId, desireData, desireLogic) { + if (typeof desireLogic !== 'function') { + throw new Error("crocenvie: desireLogic doit être une fonction."); + } + + if (!this.crocodileDesires) { + this.crocodileDesires = {}; + } + + this.crocodileDesires[desireId] = { + data: { + desires: desireData.desires || ['eat', 'hunt', 'play', 'rest'], + desireWeights: desireData.desireWeights || {}, + satisfactionLevels: desireData.satisfactionLevels || {}, + desireDecay: desireData.desireDecay || 0.1, + influences: desireData.influences || {}, + ...desireData + }, + logic: desireLogic, + crocodileDesires: {}, + lastUpdate: Date.now() + }; + + this.emit('crocodileDesireSystemCreated', { desireId, data: desireData }); + console.log(`[Crocobras] Système d'envies '${desireId}' créé.`); + } + + /** + * Met à jour les envies d'un crocodile + * @param {string} desireId - ID du système d'envies + * @param {number} crocoId - ID du crocodile + * @param {Object} [context] - Contexte pour les envies + */ + updateCrocodileDesires(desireId, crocoId, context = {}) { + if (!this.crocodileDesires || !this.crocodileDesires[desireId]) return; + + const desireSystem = this.crocodileDesires[desireId]; + + if (!desireSystem.crocodileDesires[crocoId]) { + desireSystem.crocodileDesires[crocoId] = {}; + desireSystem.data.desires.forEach(desire => { + desireSystem.crocodileDesires[crocoId][desire] = Math.random(); + }); + } + + const currentDesires = desireSystem.crocodileDesires[crocoId]; + + const result = desireSystem.logic.call(this, desireSystem.data, { + crocoId: crocoId, + currentDesires: currentDesires, + gameState: this.getGameState(), + context: context + }); + + if (result) { + // Mettre à jour les envies selon le résultat + Object.keys(currentDesires).forEach(desire => { + if (result[desire] !== undefined) { + currentDesires[desire] = Math.max(0, Math.min(1, result[desire])); + } + }); + + desireSystem.lastUpdate = Date.now(); + + this.emit('crocodileDesireUpdated', { + desireId, + crocoId, + desires: currentDesires, + result: result + }); + } + } + + /** + * Obtient les envies actuelles d'un crocodile + * @param {string} desireId - ID du système d'envies + * @param {number} crocoId - ID du crocodile + * @returns {Object|null} Envies actuelles du crocodile + */ + getCrocodileDesires(desireId, crocoId) { + if (!this.crocodileDesires || !this.crocodileDesires[desireId]) return null; + + const desireSystem = this.crocodileDesires[desireId]; + return desireSystem.crocodileDesires[crocoId] || null; + } +} + +// Exporte la classe du jeu +module.exports = CrocobrasGame;