Files
Superproject1/js/plugins/YEP_BattleAICore.js
alexpolo1 3cfd07d722 2
2023-04-10 00:05:51 +02:00

1691 lines
62 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// Yanfly Engine Plugins - Battle Artificial Intelligence Core
// YEP_BattleAICore.js
//=============================================================================
var Imported = Imported || {};
Imported.YEP_BattleAICore = true;
var Yanfly = Yanfly || {};
Yanfly.CoreAI = Yanfly.CoreAI || {};
Yanfly.CoreAI.version = 1.15;
//=============================================================================
/*:
* @plugindesc v1.15 This plugin allows you to structure battle A.I.
* patterns with more control.
* @author Yanfly Engine Plugins
*
* @param Dynamic Actions
* @type boolean
* @on YES
* @off NO
* @desc If enabled, enemy actions are decided on the spot instead
* of at the start of turn. NO - false YES - true
* @default true
*
* @param Dynamic Turn Count
* @type boolean
* @on YES
* @off NO
* @desc Decide if the turn count dynamic is counted for earlier or later.
* true - Current Turn + 1 false - Current Turn
* @default false
*
* @param Element Testing
* @type boolean
* @on YES
* @off NO
* @desc If enabled, enemies will test actors on their elements by
* setting them to match first. NO - false YES - true
* @default true
*
* @param Default AI Level
* @type number
* @min 0
* @max 100
* @desc This is the default AI level of all enemies.
* Level 0: Very Random Level 100: Very Strict
* @default 80
*
* @help
* ============================================================================
* Introduction
* ============================================================================
*
* RPG Maker MV's default enemy AI is a bit lackluster even if you managed to
* have it based completely on the rates and switches. There is no way to
* control the way the enemy chooses targets by default, nor are the conditions
* imposed by the default editor enough to satisfy the majority of checks. This
* plugin enables you to set a priority list of conditions, actions, and the
* targets selected for the enemy to go through before making a decision on how
* to participate in battle.
*
* These conditions contain all of the default editor's conditions plus more,
* such as determining the parameter values of a target, whether or not a state
* exists on a target, the target's elemental weakness (or resistances), and
* more before deciding an action. Furthermore, you can set an AI level for the
* enemies to make them more consistent in the way they go about fighting your
* players or more random in the way the enemies treat the priority list, too.
*
* ============================================================================
* Parameters
* ============================================================================
*
* Dynamic Actions
* By default, the enemy's actions are determined at the start of the turn.
* While this works in its own right, enabling Dynamic Actions allow enemies
* to make a decision when the enemy's turn comes up instead. This prompts
* enemies to be more flexible and to appear more intelligent in battle, thus,
* giving your players a bit more of a challenge.
*
* Element Testing
* If this is disabled, enemies will automatically know the elemental weakness,
* resistance, etc. about all actors. If enabled, enemies will need to test out
* the skills on various actors first before making a decision. Until the enemy
* learns about the actor's elemental rates, the enemy is always willing to try
* using the skill on the target actor. However, if the skill itself does not
* possess an element, then no information will be registered. All elemental
* data is reset at the start of each battle for all enemy parties.
*
* Default AI Level
* Not all enemies are intelligent. In fact, some of them are dumb or random.
* Setting the AI Level of a foe at a low number means the foe is more random
* while a higher AI Level foe is more consistent. How the AI Level works is,
* a random number will be checked from 0 to 99. If that enemy's AI Level is
* higher than that number, that action is checked to see if the condition is
* fulfilled or not. If the AI Level is lower than that number, the condition
* is automatically deemed false and continues on to the next action. The check
* is ran each time a new action is checked upon. This random factor is only
* applied to <AI Priority> lists and do not apply to default actions.
*
* ============================================================================
* Enemy AI Level
* ============================================================================
*
* Enemy AI levels do not determine how difficult they are. Instead, they
* determine how strictly they will follow the <AI Priority> lists. An AI Level
* of 80 means it has an 80% chance of following the prioritized action on the
* AI Priority list before moving onto the next one where there will be another
* 80% chance and so on. If the AI level is lower, the chance is lower, making
* the AI to be more random.
*
* Enemy Notetag:
* <AI Level: x>
* Sets the enemy's AI level to x. The lower x, the more random the enemy.
* The higher for x, the more strict the enemy is about following the AI
* Priority list found in its notebox, too.
*
* ============================================================================
* Enemy AI Priority
* ============================================================================
*
* If an enemy has an AI Priority list, the enemy will go down that list from
* top to bottom (giving the actions at the top more priority than the ones at
* the bottom) looking for any actions whose conditions are fulfilled. If that
* condition is fulfilled, then that action will be the action the enemy will
* partake in.
*
* To set up a Priority List for the enemy, you must place inside the enemy's
* notebox notetags that match the following format:
*
* <AI Priority> <AI Priority>
* condition: SKILL x, target or condition: skill name, target
* condition: SKILL x, target condition: skill name, target
* </AI Priority> </AI Priority>
*
* Any number of conditions and skills can be placed in between the two
* <AI Priority> tags. You can choose to use skill ID's or the skill names.
* However, if you use the skill names, keep in mind that it is not case
* sensitive and if any skills in your database have matching names, the skill
* with the larger skill ID will be the action used.
*
* ============================================================================
* Conditions
* ============================================================================
*
* The following is a list of ways you can format your conditions for the enemy
* to choose the right skill. In addition to deciding whether or not the skill
* will be used, the condition also selects the enemy target. The following
* list will tell you how the conditions are met and what targets will be
* selected for battle.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ALWAYS
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This condition will always be fulfilled. The valid target group is all
* targets within scope.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Always: Skill 10, Lowest HP%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ELEMENT X case
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This allows you to match the element rate of element X (use either a number
* or the name of the element in place of 'X') to see whether or not the
* conditions for the action are fulfilled. Replace 'case' with 'Neutral' for
* normal element rate (under 110% and above 90%), 'Weakness' for anything
* above 100% element rate, 'Resistant' for below 100% element rate, 'Null' for
* 0% element rate, and 'Absorb' for below 0% element rate. Valid targets will
* be those with the matching element rates.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Element Fire Weakness: Fireball, Lowest HP%
* Element Water Resistant: Water Cancel, Highest MAT
* Element 4 Null: Earthquake, Lowest MDF
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* EVAL eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This allows you to use any kind of code to check and fulfill a condition.
* This condition uses all alive members of the skill's scope as valid targets.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Eval user.name() === 'Bat A': Skill 10, Highest HP%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* group ALIVE MEMBERS eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'group' with either 'party' for the player's party or 'troop' for
* the enemy party. This runs the number of party alive members or troop alive
* members in a check to see if the conditions can be fulfilled.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Party Alive Members > 2: Skill 10, Lowest HP%
* Troop Alive Members <= 4: Skill 11, Highest HP%
* Troop Alive Members === $gameVariables.value(3): Skill 12, Random
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* group DEAD MEMBERS eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'group' with either 'party' for the player's party or 'troop' for
* the enemy party. This runs the number of party dead members or troop dead
* members in a check to see if the conditions can be fulfilled.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Party Dead Members > 2: Undead, Highest ATK
* Troop Dead Members <= 4: Life, Highest ATK
* Troop Dead Members === $gameVariables.value(3): Skill 12, Random
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* stat PARAM eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'stat' with either 'atk', 'def', 'mat', 'mdf', 'agi', 'luk',
* 'maxhp', 'maxmp', 'hp', 'mp', 'hp%', 'mp%', or 'level' to run it in a
* condition check again to see if the action gets passed. The group that it
* checks will be based on the skill's scope. If the skill targets foes, then
* all foes will take a check to see if they fulfill the conditions. Likewise
* for party members if the skill is for allies. The valid targets will be
* those who pass the condition check.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: HP% param <= 50%: Heal, Lowest HP%
* MP param > 90: Mana Drain, Highest MP
* ATK param > user.atk: Power Break, Highest ATK
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* type PARTY LEVEL eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'type' with either 'highest', 'lowest', or 'average' to get the
* respective party level for the skill's scope. This will reference the entire
* party's level. If this condition is fulfilled, all targets would become
* valid targets.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Highest Party Level > 10: Skill 10, Lowest MP%
* Lowest Party Level < 12: Skill 11, Lowest HP%
* Average Party Level > 15: Skill 12, Highest HP%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* RANDOM x%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will make the condition based on a random x percent chance. This
* condition allows all possible targets to be valid for targeting.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Random 50%: Skill 10, Lowest HP%
* Random 75%: Skill 11, Highest HP%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* STATE === state x
* STATE === state name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will detect if the target scope has state x (or state name if you use
* that instead). If the target does, that target is added into the pool of
* valid targets. Any targets not affected by the state will be ignored.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: State === State 5: DeBlind, Highest ATK
* State === Knockout: Life, Random
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* STATE !== state x
* STATE !== state name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will detect if the target scope does not have state x (or state name if
* you use that instead). If the target doesn't, that target is added into the
* pool of valid targets. Any targets affected by the state will be ignored.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: State !== State 12: Haste, Random
* State !== Courage: Cowardice, Highest ATK
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* SWITCH X case
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'x' with the ID of the switch you wish to check. Replace 'case' with
* either 'on' or 'off' (you may also use 'true' or 'false'). If the switch
* matches the case, the condition is fulfilled and all skill targets become
* valid targets.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Switch 5 On: Skill 10, Lowest HP%
* Switch 6 Off: Skill 11, Highest HP%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* TURN eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will make the condition based on the turn count to be fulfilled by an
* eval statement. This condition allows all possible targets to be valid for
* targeting.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Turn > 3: Skill 10, Lowest hp%
* Turn === 4: Skill 11, Highest hp%
* Turn <= $gameVariables.value(2): Skill 12, Random
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* USER stat PARAM eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'stat' with either 'atk', 'def', 'mat', 'mdf', 'agi', 'luk',
* 'maxhp', 'maxmp', 'hp', 'mp', 'hp%', 'mp%', or 'level' to run it in a
* condition check again to see if the action gets passed. If the user's param
* matches the conditions, the check is fulfilled.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: User HP% param <= 50%: Heal, Lowest HP%
* User MP param > 90: Mana Drain, Highest MP
* User ATK param > user.atk: Power Break, Highest ATK
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* VARIABLE X eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will call forth the value of variable 'x' to partake in an eval
* comparison to see if the condition is fulfilled. If it is, all skill targets
* become valid targets.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Variable 3 > 10: Skill 10, Lowest HP%
* Variable 5 <= 100: Skill 11, Highest HP%
* Variable 2 === user.atk: Skill 12
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* ============================================================================
* Multiple Conditions
* ============================================================================
*
* As of the version 1.11 update, the Battle A.I. Core is now able to support
* multiple conditions. Setting up multiple conditions is relatively simple to
* do and still follows the 'condition: SKILL x, target' format.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* To add multiple conditions, simply insert a +++ between each condition like
* the following examples:
*
* Switch 1 on +++ Switch 2 on: Fire, Lowest HP%
* Turn 3 > 1 +++ Variable 5 <= 100 +++ Switch 3 on: Ice, Lowest HP%
* Random 50% +++ Highest Party Level > 50: Thunder, Highest HP%
*
* In the above examples, all the conditions must be met in order for the
* selected skills to be considered for use.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* For conditions that have strict targeting groups, the targeting group will
* end up becoming the combination of all of the strict targeting groups. For
* example:
*
* STATE === Blind +++ STATE === Fear: Dark, Lowest HP%
*
* In this example, the enemy will only use the 'Dark' skill on a target that
* is both affected by 'Blind' and 'Fear'. If there are multiple targets, then
* the target with the lowest HP% will become the target the enemy will cast
* the 'Dark' on.
*
* STATE !== Blind +++ ATK param >= 150: Darkness, Highest ATK
*
* In the above example, the enemy will use the 'Darkness' skill against any
* target that isn't blinded and has an ATK parameter of at least 150. If there
* are multiple targets, then the enemy will first cast 'Darkness' on the
* target with the highest ATK before casting it on a target with a lower ATK.
*
* ============================================================================
* Targeting
* ============================================================================
*
* Targeting is optional but can be done via a small change to the condition.
* All you have to do is add a ',' after the skill to indicate which target in
* the valid target group you would like to target. For example:
*
* Random 50%: Fire, Highest HP%
*
* The condition to be met is the 50% random chance, but if it is fulfilled,
* the target selected will be the member on the targeting scope's team with
* the highest HP percentage. When that happens, the 'Fire' skill will be used
* upon that target.
*
* If no target is specified, a random target will be selected amongst the
* group of valid targets. Otherwise, refer to the following list:
*
* ----------------------------------------------------------------------------
* <<nothing>> Selects a random member of the valid target group.
* First Selects first member of the valid target group.
* User Selects the user itself.
* Highest MaxHP Selects highest MaxHP valid target.
* Highest HP Selects highest HP valid target.
* Highest HP% Selects highest HP% valid target. *Note1
* Highest MaxMP Selects highest MaxMP valid target.
* Highest MP Selects highest MP valid target.
* Highest MP% Selects highest MP% valid target. *Note1
* Highest MaxTP Selects highest MaxTP valid target.
* Highest TP Selects highest TP valid target.
* Highest TP% Selects highest TP% valid target. *Note1
* Highest ATK Selects highest ATK valid target.
* Highest DEF Selects highest DEF valid target.
* Highest MAT Selects highest MAT valid target.
* Highest MDF Selects highest MDF valid target.
* Highest AGI Selects highest AGI valid target.
* Highest LUK Selects highest LUK valid target.
* Highest Level Selects highest Level valid target. *Note2
* Lowest MaxHP Selects lowest MaxHP valid target.
* Lowest HP Selects lowest HP valid target.
* Lowest HP% Selects lowest HP% valid target. *Note1
* Lowest MaxMP Selects lowest MaxMP valid target.
* Lowest MP Selects lowest MP valid target.
* Lowest MP% Selects lowest MP% valid target. *Note1
* Lowest MaxTP Selects lowest MaxMP valid target.
* Lowest TP Selects lowest MP valid target.
* Lowest TP% Selects lowest MP% valid target. *Note1
* Lowest ATK Selects lowest ATK valid target.
* Lowest DEF Selects lowest DEF valid target.
* Lowest MAT Selects lowest MAT valid target.
* Lowest MDF Selects lowest MDF valid target.
* Lowest AGI Selects lowest AGI valid target.
* Lowest LUK Selects lowest LUK valid target.
* Lowest Level Selects lowest Level valid target. *Note2
*
* Note1: This is calculated by dividing the current HP with the MaxHP or the
* current MP with the MaxMP.
*
* Note2: If this is used on an enemy without a proper enemy level plugin
* installed, this will return the player party's highest level.
*
* ----------------------------------------------------------------------------
*
* ============================================================================
* Special Notes
* ============================================================================
*
* If you are using YEP_Taunt.js, enemies will automatically not factor in
* taunts by default. For that matter, targets can be protected by taunts
* effects, which can effectively shut down an enemy's AI performance. However,
* if you want some enemies to consider the taunt effects of an opponent,
* place this notetag inside of the enemy's notebox:
*
* <AI Consider Taunt>
*
* This will make it that when an enemy makes a decision, it will make a right
* decision while thinking of the taunted enemies, too. You can use this for
* smarter enemies while keep this notetag disabled for less intelligent foes.
*
* ============================================================================
* Changelog
* ============================================================================
*
* Version 1.15:
* - Fixed a bug that caused some TP conditions to not work properly.
*
* Version 1.14:
* - Bypass the isDevToolsOpen() error when bad code is inserted into a script
* call or custom Lunatic Mode code segment due to updating to MV 1.6.1.
*
* Version 1.13:
* - Updated for RPG Maker MV version 1.5.0.
*
* Version 1.12:
* - Added 'Dynamic Turn Count' plugin parameter for those who wish to push the
* turn count further by 1 turn in order to adjust for Dynamic Actions. Code
* provided by Talonos.
*
* Version 1.11:
* - Adding the ability to support multiple conditions. Please Read the
* 'Multiple Conditions' section in the help file for more details.
*
* Version 1.10:
* - Lunatic Mode fail safes added.
*
* Version 1.09:
* - Added 'user' to the list of valid skill targets.
* - Added 'USER stat PARAM eval' to valid conditions.
*
* Version 1.08:
* - Neutral elemental resistance is now considered to be above 90% and under
* 110% for a better range of activation.
* - Optimization update.
*
* Version 1.07:
* - Fixed a compatibility bug that caused certain conditions to bypass taunts.
*
* Version 1.06:
* - Fixed a bug that caused 'Highest TP' and 'Lowest TP' target searches to
* crash the game.
*
* Version 1.05:
* - Updated for RPG Maker MV version 1.1.0.
*
* Version 1.04a:
* - Fixed a bug that would cause a crash with the None scope for skills.
* - Switched over a function to operate in another for better optimization.
*
* Version 1.03:
* - Fixed a bug that returned the wrong MP% rate.
*
* Version 1.02:
* - Fixed a bug that targeted the highest parameter enemy instead of lowest.
*
* Version 1.01:
* - Added 'MaxTP' and 'TP' to targets.
* - Compatibility update with Battle Engine Core v1.19+. Turn settings are now
* based 'AI Self Turns' if the enabled.
*
* Version 1.00:
* - Finished Plugin!
*/
//=============================================================================
//=============================================================================
// Parameter Variables
//=============================================================================
Yanfly.Parameters = PluginManager.parameters('YEP_BattleAICore');
Yanfly.Param = Yanfly.Param || {};
Yanfly.Param.CoreAIDynamic = String(Yanfly.Parameters['Dynamic Actions']);
Yanfly.Param.CoreAIDynamic = eval(Yanfly.Param.CoreAIDynamic);
Yanfly.Param.CoreAIDynTurnCnt = String(Yanfly.Parameters['Dynamic Turn Count']);
Yanfly.Param.CoreAIDynTurnCnt = eval(Yanfly.Param.CoreAIDynTurnCnt);
Yanfly.Param.CoreAIElementTest = String(Yanfly.Parameters['Element Testing']);
Yanfly.Param.CoreAIElementTest = eval(Yanfly.Param.CoreAIElementTest);
Yanfly.Param.CoreAIDefaultLevel = Number(Yanfly.Parameters['Default AI Level']);
//=============================================================================
// DataManager
//=============================================================================
Yanfly.CoreAI.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
if (!Yanfly.CoreAI.DataManager_isDatabaseLoaded.call(this)) return false;
if (!Yanfly._loaded_YEP_BattleAICore) {
this.processCoreAINotetags1($dataEnemies);
this.processCoreAINotetags2($dataSkills);
this.processCoreAINotetags3($dataStates);
this.processCoreAINotetags4($dataSystem);
Yanfly._loaded_YEP_BattleAICore = true;
}
return true;
};
DataManager.processCoreAINotetags1 = function(group) {
var note1 = /<(?:AI PRIORITY)>/i;
var note2 = /<\/(?:AI PRIORITY)>/i;
var note3 = /<(?:AI CONSIDER TAUNT|ai considers taunts)>/i;
var note4 = /<(?:AI LEVEL):[ ](\d+)>/i;
for (var n = 1; n < group.length; n++) {
var obj = group[n];
var notedata = obj.note.split(/[\r\n]+/);
obj.aiPattern = [];
var aiPatternFlag = false;
obj.aiConsiderTaunt = false;
obj.aiLevel = Yanfly.Param.CoreAIDefaultLevel * 0.01;
for (var i = 0; i < notedata.length; i++) {
var line = notedata[i];
if (line.match(note1)) {
aiPatternFlag = true;
} else if (line.match(note2)) {
aiPatternFlag = false;
} else if (aiPatternFlag) {
obj.aiPattern.push(line);
} else if (line.match(note3)) {
obj.aiConsiderTaunt = true;
} else if (line.match(note4)) {
obj.aiLevel = parseFloat(RegExp.$1 * 0.01);
}
}
}
};
DataManager.processCoreAINotetags2 = function(group) {
if (Yanfly.SkillIdRef) return;
Yanfly.SkillIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.SkillIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCoreAINotetags3 = function(group) {
if (Yanfly.StateIdRef) return;
Yanfly.StateIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.StateIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCoreAINotetags4 = function(group) {
if (Yanfly.ElementIdRef) return;
Yanfly.ElementIdRef = {};
for (var i = 0; i < group.elements.length; ++i) {
var obj = group.elements[i].toUpperCase();
if (typeof obj === 'string' && obj !== '') Yanfly.ElementIdRef[obj] = i;
}
};
//=============================================================================
// BattleManager
//=============================================================================
if (Yanfly.Param.CoreAIDynamic) {
Yanfly.CoreAI.BattleManager_getNextSubject =
BattleManager.getNextSubject;
BattleManager.getNextSubject = function() {
//this.updateAIPatterns();
var battler = Yanfly.CoreAI.BattleManager_getNextSubject.call(this);
if (battler && battler.isEnemy()) battler.setAIPattern();
return battler;
};
};
BattleManager.updateAIPatterns = function() {
$gameTroop.updateAIPatterns()
};
Yanfly.CoreAI.BattleManager_isInputting = BattleManager.isInputting;
BattleManager.isInputting = function() {
if ($gameTemp._tauntMode) return false;
return Yanfly.CoreAI.BattleManager_isInputting.call(this);
};
//=============================================================================
// Game_Battler
//=============================================================================
Object.defineProperty(Game_Battler.prototype, 'level', {
get: function() {
return this.getLevel();
},
configurable: true
});
if (!Game_Battler.prototype.getLevel) {
Game_Battler.prototype.getLevel = function() {
return $gameTroop.highestLevel();
};
};
Game_Battler.prototype.setAIPattern = function() {
Game_Battler.prototype.makeActions.call(this);
};
Game_Battler.prototype.aiConsiderTaunt = function() {
return false;
};
Game_Battler.prototype.hasSkill = function(skillId) {
return this.skills().contains($dataSkills[skillId]);
};
Game_Battler.prototype.hasState = function(stateId) {
return this.states().contains($dataStates[stateId]);
};
Game_Battler.prototype.notState = function(stateId) {
return !this.isStateAffected(stateId);
};
Game_Battler.prototype.aiLevel = function() {
return Yanfly.Param.CoreAIDefaultLevel * 0.01;
};
//=============================================================================
// Game_Enemy
//=============================================================================
Game_Enemy.prototype.skills = function() {
var skills = []
for (var i = 0; i < this.enemy().actions.length; ++i) {
var skill = $dataSkills[this.enemy().actions[i].skillId]
if (skill) skills.push(skill);
}
skills = AIManager.getPatternSkills(skills, this.enemy().aiPattern);
return skills;
};
Yanfly.CoreAI.Game_Enemy_makeActions = Game_Enemy.prototype.makeActions;
Game_Enemy.prototype.makeActions = function() {
if (this.enemy().aiPattern.length > 0) {
this.setAIPattern();
this.setActionState('waiting');
} else {
Yanfly.CoreAI.Game_Enemy_makeActions.call(this);
}
};
Game_Enemy.prototype.aiConsiderTaunt = function() {
if (!Imported.YEP_Taunt) return false;
return this.enemy().aiConsiderTaunt;
};
Game_Enemy.prototype.setAIPattern = function() {
Game_Battler.prototype.setAIPattern.call(this);
if (this.numActions() <= 0) return;
AIManager.setBattler(this);
for (var i = 0; i < this.enemy().aiPattern.length; ++i) {
if (Math.random() > this.aiLevel()) continue;
var line = this.enemy().aiPattern[i];
if (AIManager.isDecidedActionAI(line)) return;
}
Yanfly.CoreAI.Game_Enemy_makeActions.call(this);
};
Game_Enemy.prototype.aiLevel = function() {
return this.enemy().aiLevel;
};
//=============================================================================
// Game_Unit
//=============================================================================
Game_Unit.prototype.highestLevel = function() {
return $gameParty.highestLevel();
};
Game_Unit.prototype.lowestLevel = function() {
return $gameParty.lowestLevel();
};
Game_Unit.prototype.averageLevel = function() {
return $gameParty.averageLevel();
};
Yanfly.CoreAI.Game_Unit_onBattleStart = Game_Unit.prototype.onBattleStart;
Game_Unit.prototype.onBattleStart = function() {
Yanfly.CoreAI.Game_Unit_onBattleStart.call(this);
};
Game_Unit.prototype.aiElementRateKnown = function(target, elementId) {
return true;
};
Game_Unit.prototype.aiRegisterElementRate = function(target, elementId) {
};
//=============================================================================
// Game_Party
//=============================================================================
Game_Party.prototype.lowestLevel = function() {
return Math.min.apply(null, this.members().map(function(actor) {
return actor.level;
}));
};
Game_Party.prototype.averageLevel = function() {
var level = 0;
for (var i = 0; i < this.members().length; ++i) {
var member = this.members()[i];
if (member) level += member.level;
}
level /= this.members().length;
return level;
};
//=============================================================================
// Game_Troop
//=============================================================================
Game_Troop.prototype.updateAIPatterns = function() {
for (var i = 0; i < this.aliveMembers().length; ++i) {
var member = this.aliveMembers()[i];
if (member) member.setAIPattern();
}
};
Yanfly.CoreAI.Game_Troop_setup = Game_Troop.prototype.setup;
Game_Troop.prototype.setup = function(troopId) {
Yanfly.CoreAI.Game_Troop_setup.call(this, troopId);
this._aiKnownElementRates = {};
};
Game_Troop.prototype.aiElementRateKnown = function(target, elementId) {
if (target.isEnemy()) return true;
if (!Yanfly.Param.CoreAIElementTest) return true;
var index = target.index();
if (this._aiKnownElementRates[index] === undefined) {
this._aiKnownElementRates[index] = [];
}
return this._aiKnownElementRates[index].contains(elementId);
};
Game_Troop.prototype.aiRegisterElementRate = function(target, elementId) {
if (!Yanfly.Param.CoreAIElementTest) return;
var index = target.index();
if (this._aiKnownElementRates[index] === undefined) {
this._aiKnownElementRates[index] = [];
}
if (!this._aiKnownElementRates[index].contains(elementId)) {
this._aiKnownElementRates[index].push(elementId);
}
};
//=============================================================================
// Game_Action
//=============================================================================
Yanfly.CoreAI.Game_Action_apply = Game_Action.prototype.apply;
Game_Action.prototype.apply = function(target) {
Yanfly.CoreAI.Game_Action_apply.call(this, target);
this.aiRegisterElementRate(target);
};
Game_Action.prototype.aiRegisterElementRate = function(target) {
if (this.item().damage.elementId < 0) return;
var elementId = this.item().damage.elementId;
if (this.subject().isActor()) {
$gameParty.aiRegisterElementRate(target, elementId);
} else {
$gameTroop.aiRegisterElementRate(target, elementId);
}
};
//=============================================================================
// AIManager
//=============================================================================
function AIManager() {
throw new Error('This is a static class');
}
AIManager.setBattler = function(battler) {
this._battler = battler;
this._action = battler.action(0);
};
AIManager.battler = function() {
return this._battler;
};
AIManager.action = function() {
return this._action;
};
AIManager.isDecidedActionAI = function(line) {
if (line.match(/[ ]*(.*):[ ](?:SKILL)[ ](\d+),[ ](.*)/i)) {
this._origCondition = String(RegExp.$1);
var condition = String(RegExp.$1);
this._aiSkillId = parseInt(RegExp.$2);
this._aiTarget = String(RegExp.$3);
} else if (line.match(/[ ]*(.*):[ ](?:SKILL)[ ](\d+)/i)) {
this._origCondition = String(RegExp.$1);
var condition = String(RegExp.$1);
this._aiSkillId = parseInt(RegExp.$2);
this._aiTarget = 'RANDOM';
} else if (line.match(/[ ]*(.*):[ ](.*),[ ](.*)/i)) {
this._origCondition = String(RegExp.$1);
var condition = String(RegExp.$1);
this._aiSkillId = Yanfly.SkillIdRef[String(RegExp.$2).toUpperCase()];
this._aiTarget = String(RegExp.$3);
} else if (line.match(/[ ]*(.*):[ ](.*)/i)) {
this._origCondition = String(RegExp.$1);
var condition = String(RegExp.$1);
this._aiSkillId = Yanfly.SkillIdRef[String(RegExp.$2).toUpperCase()];
this._aiTarget = 'RANDOM';
} else {
return false;
}
if (!this.initialCheck(this._aiSkillId)) return false;
if (!this.meetCustomAIConditions(this._aiSkillId)) return false;
this.action().setSkill(this._aiSkillId);
if (!this.passAllAIConditions(condition)) return false;
return true;
};
AIManager.getPatternSkills = function(array, patterns) {
for (var i = 0; i < patterns.length; ++i) {
var line = patterns[i];
if (line.match(/[ ]*(.*):[ ](?:SKILL)[ ](\d+),[ ](.*)/i)) {
var skillId = parseInt(RegExp.$2);
} else if (line.match(/[ ]*(.*):[ ](?:SKILL)[ ](\d+)/i)) {
var skillId = parseInt(RegExp.$2);
} else if (line.match(/[ ]*(.*):[ ](.*),[ ](.*)/i)) {
var skillId = Yanfly.SkillIdRef[String(RegExp.$2).toUpperCase()];
} else if (line.match(/[ ]*(.*):[ ](.*)/i)) {
var skillId = Yanfly.SkillIdRef[String(RegExp.$2).toUpperCase()];
} else {
continue;
}
if ($dataSkills[skillId]) array.push($dataSkills[skillId]);
}
return array;
};
AIManager.initialCheck = function(skillId) {
if (!$dataSkills[skillId]) return false;
if (!this.hasSkill(skillId)) return false;
return this.battler().meetsSkillConditions($dataSkills[skillId]);
};
AIManager.hasSkill = function(skillId) {
return this.battler().hasSkill(skillId);
};
AIManager.meetCustomAIConditions = function(skillId) {
return true;
};
AIManager.getActionGroup = function() {
var action = this.action();
if (Imported.YEP_X_SelectionControl) action.setSelectionFilter(true);
if (!action) return [];
if (action.isForUser()) {
var group = [this.battler()];
} else if (action.isForDeadFriend()) {
var group = action.friendsUnit().deadMembers();
} else if (action.isForFriend()) {
var group = action.friendsUnit().aliveMembers();
} else if (action.isForOpponent()) {
if (this.battler().aiConsiderTaunt()) {
$gameTemp._tauntMode = true;
$gameTemp._tauntAction = action;
var group = action.opponentsUnit().tauntMembers();
$gameTemp._tauntMode = false;
$gameTemp._tauntAction = undefined;
} else {
var group = action.opponentsUnit().aliveMembers();
}
} else {
var group = [];
}
if (this._setActionGroup !== undefined) {
group = Yanfly.Util.getCommonElements(this._setActionGroup, group);
}
this._setActionGroup = group;
return this._setActionGroup;
};
AIManager.setActionGroup = function(group) {
this._setActionGroup = group;
};
AIManager.setProperTarget = function(group) {
this.setActionGroup(group);
var action = this.action();
var randomTarget = group[Math.floor(Math.random() * group.length)];
if (!randomTarget) return action.setTarget(0);
if (group.length <= 0) return action.setTarget(randomTarget.index());
var line = this._aiTarget.toUpperCase();
if (line.match(/FIRST/i)) {
action.setTarget(0);
} else if (line.match(/USER/i)) {
var index = group.indexOf();
action.setTarget(action.subject().index());
} else if (line.match(/HIGHEST[ ](.*)/i)) {
var param = this.getParamId(String(RegExp.$1));
if (param < 0) return action.setTarget(randomTarget.index());
if (param === 8) return this.setHighestHpFlatTarget(group);
if (param === 9) return this.setHighestMpFlatTarget(group);
if (param === 10) return this.setHighestHpRateTarget(group);
if (param === 11) return this.setHighestMpRateTarget(group);
if (param === 12) return this.setHighestLevelTarget(group);
if (param === 13) return this.setHighestMaxTpTarget(group);
if (param === 14) return this.setHighestTpTarget(group);
if (param > 15) return action.setTarget(randomTarget.index());
this.setHighestParamTarget(group, param);
} else if (line.match(/LOWEST[ ](.*)/i)) {
var param = this.getParamId(String(RegExp.$1));
if (param < 0) return action.setTarget(randomTarget.index());
if (param === 8) return this.setLowestHpFlatTarget(group);
if (param === 9) return this.setLowestMpFlatTarget(group);
if (param === 10) return this.setLowestHpRateTarget(group);
if (param === 11) return this.setLowestMpRateTarget(group);
if (param === 12) return this.setLowestLevelTarget(group);
if (param === 13) return this.setLowestMaxTpTarget(group);
if (param === 14) return this.setLowestTpTarget(group);
if (param > 15) return action.setTarget(randomTarget.index());
this.setLowestParamTarget(group, param);
} else {
this.setRandomTarget(group);
}
};
AIManager.getParamId = function(string) {
string = string.toUpperCase()
switch (string) {
case 'MAXHP':
case 'MAX HP':
return 0;
break;
case 'MAXMP':
case 'MAX MP':
case 'MAXSP':
case 'MAX SP':
return 1;
break;
case 'ATK':
case 'STR':
return 2;
break;
case 'DEF':
return 3;
break;
case 'MAT':
case 'INT':
case 'SPI':
return 4;
break;
case 'MDF':
case 'RES':
return 5;
break;
case 'AGI':
case 'SPD':
return 6;
break;
case 'LUK':
return 7;
break;
case 'HP':
return 8;
break;
case 'MP':
case 'SP':
return 9;
break;
case 'HP%':
return 10;
break;
case 'MP%':
case 'SP%':
return 11;
break;
case 'LEVEL':
case 'LV':
case 'LVL':
return 12;
break;
case 'MAXTP':
return 13;
break;
case 'TP':
return 14;
break;
}
return -1;
};
AIManager.setHighestHpRateTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.hp / target.mhp > maintarget.hp / maintarget.mhp) {
maintarget = target;
}
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestHpFlatTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.hp > maintarget.hp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestHpRateTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.hp / target.mhp < maintarget.hp / maintarget.mhp) {
maintarget = target;
}
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestHpFlatTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.hp < maintarget.hp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestMpRateTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.mp / target.mmp > maintarget.mp / maintarget.mmp) {
maintarget = target;
}
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestMpFlatTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.mp > maintarget.mp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestMpRateTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.mp / target.mmp < maintarget.mp / maintarget.mmp) {
maintarget = target;
}
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestMpFlatTarget = function(group) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.mp < maintarget.mp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestParamTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.param(id) > maintarget.param(id)) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestParamTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.param(id) < maintarget.param(id)) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestLevelTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.level > maintarget.level) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestLevelTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.level < maintarget.level) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestMaxTpTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.tp > maintarget.maxTp()) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestMaxTpTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.tp < maintarget.maxTp()) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setHighestTpTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.tp > maintarget.tp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setLowestTpTarget = function(group, id) {
var maintarget = group[Math.floor(Math.random() * group.length)];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (target.tp < maintarget.tp) maintarget = target;
}
this.action().setTarget(maintarget.index())
};
AIManager.setRandomTarget = function(group) {
var target = group[Math.floor(Math.random() * group.length)];
this.action().setTarget(target.index())
};
AIManager.convertIntegerPercent = function(n) {
n *= 0.01
return String(n);
};
AIManager.elementRateMatch = function(target, elementId, type) {
var rate = target.elementRate(elementId).toFixed(2);
if (this.battler().isActor()) {
if (!$gameParty.aiElementRateKnown(target, elementId)) return true;
} else {
if (!$gameTroop.aiElementRateKnown(target, elementId)) return true;
}
if (['NEUTRAL', 'NORMAL'].contains(type)) {
return rate >= 0.90 && rate <= 1.10;
} else if (['WEAK', 'WEAKNESS', 'VULNERABLE'].contains(type)) {
return rate > 1.00;
} else if (['RESIST', 'RESISTANT', 'STRONG'].contains(type)) {
return rate < 1.00;
} else if (['NULL', 'CANCEL', 'NO EFFECT'].contains(type)) {
return rate === 0.00;
} else if (['ABSORB', 'HEAL'].contains(type)) {
return rate < 0.00;
}
return false;
};
AIManager.passAllAIConditions = function(line) {
this._setActionGroup = undefined;
var conditions = line.split('+++');
if (conditions.length <= 0) return false;
while (conditions.length > 0) {
var condition = conditions.shift().trim();
if (!this.passAIConditions(condition)) return false;
}
return true;
};
AIManager.passAIConditions = function(line) {
// ALWAYS
if (line.match(/ALWAYS/i)) {
return this.conditionAlways();
}
// ELEMENT
if (line.match(/ELEMENT[ ](.*)/i)) {
return this.conditionElement();
}
// EVAL
if (line.match(/EVAL[ ](.*)/i)) {
var condition = String(RegExp.$1);
return this.conditionEval(condition);
}
// GROUP ALIVE MEMBERS EVAL
if (line.match(/(.*)[ ]ALIVE[ ]MEMBERS[ ](.*)/i)) {
var members = String(RegExp.$1);
var condition = String(RegExp.$2);
return this.conditionGroupAlive(members, condition);
}
// GROUP DEAD MEMBERS EVAL
if (line.match(/(.*)[ ]DEAD[ ]MEMBERS[ ](.*)/i)) {
var members = String(RegExp.$1);
var condition = String(RegExp.$2);
return this.conditionGroupDead(members, condition);
}
// USER PARAM EVAL
if (line.match(/USER[ ](.*)[ ]PARAM[ ](.*)/i)) {
var paramId = this.getParamId(String(RegExp.$1));
var condition = String(RegExp.$2);
return this.conditionUserParamEval(paramId, condition);
}
// PARAM EVAL
if (line.match(/(.*)[ ]PARAM[ ](.*)/i)) {
var paramId = this.getParamId(String(RegExp.$1));
var condition = String(RegExp.$2);
return this.conditionParamEval(paramId, condition);
}
// PARTY LEVEL
if (line.match(/(.*)[ ]PARTY[ ]LEVEL[ ](.*)/i)) {
var type = String(RegExp.$1);
var condition = String(RegExp.$2);
return this.conditionPartyLevel(type, condition);
}
// RANDOM x%
if (line.match(/RANDOM[ ](\d+)([%])/i)) {
return this.conditionRandom(parseFloat(RegExp.$1 * 0.01));
}
// STATE === X
if (line.match(/STATE[ ]===[ ](.*)/i)) {
return this.conditionStateHas(String(RegExp.$1));
}
// STATE !== X
if (line.match(/STATE[ ]!==[ ](.*)/i)) {
return this.conditionStateNot(String(RegExp.$1));
}
// SWITCH X case
if (line.match(/SWITCH[ ](\d+)[ ](.*)/i)) {
var switchId = parseInt(RegExp.$1);
var value = String(RegExp.$2)
return this.conditionSwitch(switchId, value);
}
// TURN EVAL
if (line.match(/TURN[ ](.*)/i)) {
return this.conditionTurnCount(String(RegExp.$1));
}
// VARIABLE X eval
if (line.match(/VARIABLE[ ](\d+)[ ](.*)/i)) {
var variableId = parseInt(RegExp.$1);
var condition = String(RegExp.$2)
return this.conditionVariable(variableId, condition);
}
return false;
};
AIManager.conditionAlways = function() {
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionElement = function() {
var line = this._origCondition;
if (line.match(/ELEMENT[ ](\d+)[ ](.*)/i)) {
var elementId = parseInt(RegExp.$1);
var type = String(RegExp.$2).toUpperCase();
} else if (line.match(/ELEMENT[ ](.*)[ ](.*)/i)) {
var elementId = Yanfly.ElementIdRef[String(RegExp.$1).toUpperCase()];
var type = String(RegExp.$2).toUpperCase();
} else {
return false;
}
var group = this.getActionGroup();
var validTargets = [];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (!target) continue;
if (this.elementRateMatch(target, elementId, type)) {
validTargets.push(target);
}
}
if (validTargets.length <= 0) return false;
this.setProperTarget(validTargets);
return true;
};
AIManager.conditionEval = function(condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. EVAL ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionGroupAlive = function(members, condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
members = members.toUpperCase();
if (['TROOP', 'TROOPS', 'ENEMY', 'ENEMIES'].contains(members)) {
members = $gameTroop.aliveMembers();
} else if (['PARTY', 'PLAYER'].contains(members)) {
members = $gameParty.aliveMembers();
} else {
return false;
}
if (members.length <= 0) return false;
condition = 'members.length ' + condition;
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. GROUP ALIVE ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionGroupDead = function(members, condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
members = members.toUpperCase();
if (['TROOP', 'TROOPS', 'ENEMY', 'ENEMIES'].contains(members)) {
members = $gameTroop.deadMembers();
} else if (['PARTY', 'PLAYER'].contains(members)) {
members = $gameParty.deadMembers();
} else {
return false;
}
if (members.length <= 0) return false;
condition = 'members.length ' + condition;
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. GROUP DEAD ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionPartyLevel = function(type, condition) {
if (type.match(/HIGHEST/i)) {
condition = '.highestLevel() ' + condition;
} else if (type.match(/LOWEST/i)) {
condition = '.lowestLevel() ' + condition;
} else if (type.match(/AVERAGE/i)) {
condition = '.averageLevel() ' + condition;
} else {
return false;
}
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
if (action.isForFriend()) {
condition = 'action.friendsUnit()' + condition;
} else if (action.isForOpponent()) {
condition = 'action.opponentsUnit()' + condition;
}
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. PARTY LEVEL ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionUserParamEval = function(paramId, condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
condition = condition.replace(/(\d+)([%])/g, function() {
return this.convertIntegerPercent(parseInt(arguments[1]));
}.bind(this));
if (paramId < 0) return false;
if (paramId >= 0 && paramId <= 7) {
condition = 'user.param(paramId) ' + condition;
} else if (paramId === 8) {
condition = 'user.hp ' + condition;
} else if (paramId === 9) {
condition = 'user.mp ' + condition;
} else if (paramId === 10) {
condition = 'user.hp / user.mhp ' + condition;
} else if (paramId === 11) {
condition = 'user.mp / user.mmp ' + condition;
} else if (paramId === 12) {
condition = 'user.level ' + condition;
}
var group = this.getActionGroup();
var validTargets = [];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (!target) continue;
try {
if (eval(condition)) validTargets.push(target);
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. USER PARAM ERROR')
}
}
if (validTargets.length <= 0) return false;
this.setProperTarget(validTargets);
return true;
};
AIManager.conditionParamEval = function(paramId, condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
condition = condition.replace(/(\d+)([%])/g, function() {
return this.convertIntegerPercent(parseInt(arguments[1]));
}.bind(this));
if (paramId < 0) return false;
if (paramId >= 0 && paramId <= 7) {
condition = 'target.param(paramId) ' + condition;
} else if (paramId === 8) {
condition = 'target.hp ' + condition;
} else if (paramId === 9) {
condition = 'target.mp ' + condition;
} else if (paramId === 10) {
condition = 'target.hp / target.mhp ' + condition;
} else if (paramId === 11) {
condition = 'target.mp / target.mmp ' + condition;
} else if (paramId === 12) {
condition = 'target.level ' + condition;
}
var group = this.getActionGroup();
var validTargets = [];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (!target) continue;
try {
if (eval(condition)) validTargets.push(target);
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. PARAM ERROR')
}
}
if (validTargets.length <= 0) return false;
this.setProperTarget(validTargets);
return true;
};
AIManager.conditionRandom = function(rate) {
if (Math.random() >= rate) return false;
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
AIManager.conditionStateHas = function(condition) {
if (condition.match(/STATE[ ](\d+)/i)) {
var stateId = parseInt(RegExp.$1);
} else {
var stateId = Yanfly.StateIdRef[condition.toUpperCase()];
if (!stateId) return false;
}
if (!$dataStates[stateId]) return false;
var group = this.getActionGroup();
var validTargets = [];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (!target) continue;
if (target.hasState(stateId)) validTargets.push(target);
}
if (validTargets.length <= 0) return false;
this.setProperTarget(validTargets);
return true;
};
AIManager.conditionStateNot = function(condition) {
if (condition.match(/STATE[ ](\d+)/i)) {
var stateId = parseInt(RegExp.$1);
} else {
var stateId = Yanfly.StateIdRef[condition.toUpperCase()];
if (!stateId) return false;
}
if (!$dataStates[stateId]) return false;
var group = this.getActionGroup();
var validTargets = [];
for (var i = 0; i < group.length; ++i) {
var target = group[i];
if (!target) continue;
if (target.notState(stateId)) validTargets.push(target);
}
if (validTargets.length <= 0) return false;
this.setProperTarget(validTargets);
return true;
};
AIManager.conditionSwitch = function(switchId, value) {
if (['ON', 'TRUE', 'YES'].contains(value.toUpperCase())) {
value = true;
} else if (['OFF', 'FALSE', 'NO'].contains(value.toUpperCase())) {
value = false;
} else {
return false;
}
if ($gameSwitches.value(switchId) !== value) return false;
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
if (!Yanfly.Param.CoreAIDynTurnCnt) {
AIManager.conditionTurnCount = function(condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
if (Imported.YEP_BattleEngineCore) {
condition = 'user.turnCount() ' + condition;
} else {
condition = '$gameTroop.turnCount() ' + condition;
}
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. TURN COUNT ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
} else {
// Alternative provided by Talonos
AIManager.conditionTurnCount = function(condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
if (Imported.YEP_BattleEngineCore) {
if (BattleManager._phase === "input" && BattleManager.isTurnBased()) {
condition = '(user.turnCount() + 1) ' + condition;
} else {
condition = 'user.turnCount() ' + condition;
}
} else {
if (BattleManager._phase === "input") {
condition = '($gameTroop.turnCount() + 1) ' + condition;
} else {
condition = '$gameTroop.turnCount() ' + condition;
}
}
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. TURN COUNT ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
} // Yanfly.Param.CoreAIDynamic
AIManager.conditionVariable = function(variableId, condition) {
var action = this.action();
var item = action.item();
var user = this.battler();
var s = $gameSwitches._data;
var v = $gameVariables._data;
condition = '$gameVariables.value(' + variableId + ') ' + condition;
try {
if (!eval(condition)) return false;
} catch (e) {
Yanfly.Util.displayError(e, condition, 'A.I. VARIABLE ERROR');
return false;
}
var group = this.getActionGroup();
this.setProperTarget(group);
return true;
};
//=============================================================================
// Utilities
//=============================================================================
Yanfly.Util = Yanfly.Util || {};
Yanfly.Util.displayError = function(e, code, message) {
console.log(message);
console.log(code || 'NON-EXISTENT');
console.error(e);
if (Utils.RPGMAKER_VERSION && Utils.RPGMAKER_VERSION >= "1.6.0") return;
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
if (!require('nw.gui').Window.get().isDevToolsOpen()) {
require('nw.gui').Window.get().showDevTools();
}
}
};
Yanfly.Util.getCommonElements = function(array1, array2) {
var elements = [];
var length = array1.length;
for (var i = 0; i < length; ++i) {
var element = array1[i];
if (array2.contains(element)) elements.push(element);
}
return elements;
};
//=============================================================================
// End of File
//=============================================================================