Advanced Event Activation

Advanced Event Activation

Comme tous mes plugins, ce script est publié sous licence CC BY 4.0.

C’est un script tout bête dont l’idée m’est venue quand j’ai voulu faire un garde qui réagirait en voyant le joueur passer devant lui. Bien sur, c’est assez facile de le faire en event, mais j’ai cherché une méthode plus rapide. Aussi j’ai créé ce plugin :

//=============================================================================
// Sphinx-Advanced-Event-Activation.js
//=============================================================================

/*:
 * @plugindesc Condition d'activation d'event avancées
 * @author Sphinx
 *
 * @help
 * //==========================================================================
 * // Plugin : Sphinx-Advanced-Event-Activation
 * // Date   : 29 mars 2020
 * // Auteur : Sphinx
 * //==========================================================================
 * Ce script est destiné à ajouter des conditions d'activation de pages
 * d'events
 * Pour utiliser ce script, créez un commentaire au tout début d'une page d'un
 * event. Le commentaire d'activation doit contenir une condition par ligne.
 * Si toutes les conditions sont remplies, alors la page de l'event sera
 * activée.
 * 
 * Les conditions peuvent faire référence au joueur, grâce au mot clé @player,
 * et/ou à l'évent en cours, grâce au mot clé @event.
 * 
 * Les conditions sont obligatoirement des comparaisons de nombres tels que les
 * coordonnées du joueur ou de l'évent, leur direction, ...
 * L'important étant de comparer, avec l'un des 6 opérateurs disponibles :
 *     - >  : Supérieur strict
 *     - >= : Supérieur ou égal
 *     - == : Egal
 *     - <= : Inférieur ou égal
 *     - <  : Inférieur stric
 *     - != : Différent
 * 
 * Dans les conditions, vous pouvez utiliser les opérateurs mathématiques
 * simples disponibles :
 *     - + : Addition
 *     - - : Soustraction
 *     - * : Multiplication
 *     - / : Division
 *     - % : Modulo
 * 
 * Dans les conditions vous pouvez aussi utiliser une des constantes définies
 * suivantes :
 *     BOTTOM : 2
 *     LEFT   : 4
 *     RIGHT  : 6
 *     TOP    : 8
 * Ce sont les 4 valeurs correspondant aux 4 directions utilisées par le jeu
 * 
 * Voici quelques exemples de conditions valides
 *     - L'event s'active si le joueur regarde vers le bas :
 *           ¤ @player.direction == BOTTOM
 *     - L'event s'active si le joueur et l'event sont sur la même colonne :
 *           ¤ @player.x == @event.x
 *     - L'event s'active si le joueur se trouve sur la ligne en dessous de
 *       l'event :
 *           ¤ @player.y == @event.y + 1
 *     - L'event s'active si le joueur se trouve dans une zone rectangulaire
 *       comprise entre (10;10) et (20;20) inclus :
 *           ¤ @player.x >= 10
 *           ¤ @player.x <= 20
 *           ¤ @player.y >= 10
 *           ¤ @player.y <= 20
 * 
 * Ce dernier exemple contient les 4 conditions écrites. Dans ce cas, comme dit
 * précédemment, toutes les conditions doivent être remplies pour que la page
 * de l'event s'active
 * 
 * Dépendances :
 *     Aucune
 */
(function() {
	// Constantes utilisables dans les formules
	SphinxAEAConstants = {
		BOTTOM: 2,
		LEFT: 4,
		RIGHT: 6,
		TOP: 8
	};
	
	// Fonction de rafraichissement des events (la méthode refresh classique actualise l'ensemble de la map causant un certain lag)
	Game_Map.prototype.refreshEvents = function() {
		this.events().forEach(event => {
			event.refresh();
		});
	};
	
	// Rafraichissement des events à chaque changement de direction d'un event ou du joueur
	Game_CharacterBase.prototype.sphinxAEASetDirection = Game_CharacterBase.prototype.setDirection;
	Game_CharacterBase.prototype.setDirection = function(d) {
		hasTurned = d != this._direction;
		Game_CharacterBase.prototype.sphinxAEASetDirection.call(this, d);
		if(hasTurned && $gameMap != null) {
			$gameMap.refreshEvents();
		}
	};
	
	// Rafraichissement des events à chaque pas d'un event ou du joueur
	Game_CharacterBase.prototype.sphinxAEAUpdateMove = Game_CharacterBase.prototype.updateMove;
	Game_CharacterBase.prototype.updateMove = function() {
		Game_CharacterBase.prototype.sphinxAEAUpdateMove.call(this);
		if(!this.isMoving()) {
			$gameMap.refreshEvents();
		}
	};
	
	// Rafraichissement des events à l'arrivée du joueur sur la map
	Game_Player.prototype.sphinxAEAPerformTransfer = Game_Player.prototype.performTransfer;
	Game_Player.prototype.performTransfer = function() {
		Game_Player.prototype.sphinxAEAPerformTransfer.call(this);
		$gameMap.refreshEvents();
	}
	
	// Conditions d'activation de la page de l'évent
	Game_Event.prototype.sphinxAEAMeetsConditions = Game_Event.prototype.meetsConditions;
	Game_Event.prototype.meetsConditions = function(page) {
		// Si les conditions normales d'activation ne sont pas remplies, alors on active pas l'event
		if(!Game_Event.prototype.sphinxAEAMeetsConditions.call(this, page)) return false;
		
		// Les conditions normales d'activation de la page de l'évent sont remplies
		
		// Si la première commande de la page n'est pas un commentaire, alors on active normalement l'event
		if(page.list[0].code != 108) return true;
		
		// Récupération de toutes les conditions avancées
		page.advancedConditions = [];
		var index = 0;
		do {
			regexpValidCondition = /^\s*(\s*([\+\-\*\/]|[A-Z]+|\d+|\@[a-z\.]+)\s*)+(\s*(<|<=|={2}|>=|>|!=)\s*)(\s*([\+\-\*\/]|[A-Z]+|\d+|\@[a-z\.]+)\s*)+\s*$/;
			if(page.list[index].parameters[0].match(regexpValidCondition)) page.advancedConditions.push(page.list[index].parameters[0]);
			++index;
		} while(page.list[index].code == 108 || page.list[index].code == 408);
		
		// Initialisation du booléen qui sera retourné à la fin de la fonction
		// La page de l'event sera activée si aucune condition n'est pas remplie (autrement dit si toutes les conditions sont remplies)
		isActivated = true;
		
		// Analyse des conditions avancées d'activation
		page.advancedConditions.forEach(advancedCondition => {
			// Regexp de découpage de la condition
			operatorRegexp = /\s*<|<=|\={2}|>=|>|!=\s*/;
			// Si la condition est une condition valide (si elle contient bien un opérateur);
			if(advancedCondition.match(operatorRegexp)) {
				// Découpage des opérandes et extraction de l'opérateur
				operands = advancedCondition.split(operatorRegexp).slice(0, 2);//.map(operand => operand.trim());
				comparisonOperator = advancedCondition.match(operatorRegexp)[0].trim();
				
				// Pour chaque opérande
				operands = operands.map(operand => {
					// Extraction des valeurs et des opérateurs
					extractRegexp = /([\+\-\*\/]|[A-Z]+|\d+|\@[a-z\.]+)/g;
					extracted = operand.match(extractRegexp);
					
					// Analyse et calcul de l'opérande
					result = 0;
					operandOperation = "+";
					extracted.forEach(value => {
						switch(true) {
							// Opérateur
							case /[\+\-\*\/]/.test(value):
								operandOperation = value;
								value = null;
								break;
							
							// Constantes
							case /[A-Z]+/.test(value):
								value = SphinxAEAConstants[value];
								break;
							
							// Nombre
							case /\d+/.test(value):
								value = parseInt(value, 10);
								break;
							
							// Variable (@player ou @event)
							case /\@[a-z\.]+/.test(value):
								// Découpage des appels de fonctions
								value = value.split(".");
								
								// Pour chaque fonction
								var analyzedValue = null;
								value.forEach(v => {
									// Si c'est le premier appel, alors interprétation du nom de la variable
									if(analyzedValue == null) {
										switch(v) {
											// Joueur
											case "@player":
												analyzedValue = $gamePlayer;
												break;
											// Event courant
											case "@event":
												analyzedValue = this;
												break;
											// Tout autre valeur sera ignorée
											default:
												analyzedValue = 0;
												break;
										}
									}
									// Si la valeur actuellement enregistrée est un objet qui contient une clé égale à v
									else if(typeof analyzedValue == "object" && analyzedValue[v] != null) {
										// Si clé v de la valeur actuellement enregistrée est une fonction, appel de cette fonction et enregistrement de son résultat
										if(typeof analyzedValue[v] == "function") analyzedValue = analyzedValue[v].call(analyzedValue);
										
										// Sinon, enregistrement de la valeur de la clé v de la valeur actuellement enregistrée
										else analyzedValue = analyzedValue[v];
									}
								});
								// Récupération du résultat de l'interprétation de la variable
								value = analyzedValue;
								break;
						}
						// Selon l'opérateur mathématique :
						switch(operandOperation) {
							// Addition
							case "+":
								result += value;
								break;
							// Soustraction
							case "-":
								result -= value;
								break;
							// Multiplication
							case "*":
								result *= value;
								break;
							// Division
							case "/":
								result /= value;
								break;
							// Modulo
							case "%":
								result %= value;
								break;
						}
					});
					// Résultat retourné à la fonction map
					return result;
				});
				
				// Selon l'opérateur de comparaison utilisée
				switch(comparisonOperator) {
					// Supérieur strict
					case ">":
						if(operands[0] <= operands[1]) isActivated = false;
						break;
					// Supérieur ou égal
					case ">=":
						if(operands[0] < operands[1]) isActivated = false;
						break;
					// Egal
					case "==":
						if(operands[0] != operands[1]) isActivated = false;
						break;
					// Inférieur ou égal
					case "<=":
						if(operands[0] > operands[1]) isActivated = false;
						break;
					// Inférieur strict
					case "<":
						if(operands[0] >= operands[1]) isActivated = false;
						break;
					// Différent
					case "!=":
						if(operands[0] == operands[1]) isActivated = false;
						break;
				}
			}
		});
		
		// Retourne le booléen indiquant si la page remplit toutes ses conditions ou non
		return isActivated;
	};
})();

Utilisation

Pour utiliser ce script, créez un commentaire au tout début d’une page d’un event. Le commentaire d’activation doit contenir une condition par ligne. Si toutes les conditions sont remplies, alors la page de l’event sera activée.

Les conditions peuvent faire référence au joueur, grâce au mot clé @player, et/ou à l’évent en cours, grâce au mot clé @event.

Les conditions sont obligatoirement des comparaisons de nombres tels que les coordonnées du joueur ou de l’évent, leur direction, … L’important étant de comparer, avec l’un des 6 opérateurs disponibles :

  • > : Supérieur strict
  • >= : Supérieur ou égal
  • == : Egal
  • <= : Inférieur ou égal
  • < : Inférieur stric
  • != : Différent

Dans les conditions, vous pouvez utiliser les opérateurs mathématiques
simples disponibles :

  • + : Addition
  • – : Soustraction
  • * : Multiplication
  • / : Division
  • % : Modulo

Dans les conditions vous pouvez aussi utiliser une des constantes définies
suivantes :

  • BOTTOM : 2
  • LEFT : 4
  • RIGHT : 6
  • TOP : 8

Ce sont les 4 valeurs correspondant aux 4 directions utilisées par le jeu

Voici quelques exemples de conditions valides :

  • L’event s’active si le joueur regarde vers le bas :
    • @player.direction == BOTTOM
  • L’event s’active si le joueur et l’event sont sur la même colonne :
    • @player.x == @event.x
  • L’event s’active si le joueur se trouve sur la ligne en dessous de l’event :
    • @player.y == @event.y + 1
  • L’event s’active si le joueur se trouve dans une zone rectangulaire comprise entre (10;10) et (20;20) inclus :
    • @player.x >= 10
    • @player.x <= 20
    • @player.y >= 10
    • @player.y <= 20

Ce dernier exemple contient les 4 conditions écrites. Dans ce cas, comme dit
précédemment, toutes les conditions doivent être remplies pour que la page
de l’event s’active.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.