设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 399|回复: 3
打印 上一主题 下一主题

[有事请教] 【技能等级最新插件】有高级货但不会有,求教各位大佬!

[复制链接]

Lv2.观梦者

梦石
0
星屑
323
在线时间
49 小时
注册时间
2021-4-2
帖子
13
跳转到指定楼层
1
发表于 2024-6-29 22:55:52 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 1579406829 于 2024-6-29 23:02 编辑

国外大佬的插件,内容是我自己简单汉化过的。



如果嫌复制下面的代码麻烦,也可以下载原版的。这是链接:https://taaspider.itch.io/taa-skillmastery?download[url]https://taaspider.itch.io/taa-skillmastery[/url]

现在就是说,我自己在尝试运用这个插件,但是老是跳出this.resetScroll is not a function的警告,我不知道是哪里设置有问题,有厉害的大佬可以的话给个运用的教程或者是范例工程文件。

//=============================================================================
// TAA_SkillMastery.js
// Author: taaspider
//=============================================================================

var TAA = TAA || {};
TAA.skm = {};
TAA.skm.Version = "1.3.2";
TAA.skm.PluginName = "TAA_SkillMastery";
TAA.skm.alias = {};
var Imported = Imported || {};

/*:
* @target MV MZ
*
* @plugindesc [1.3.2]技能掌握
* @author T. A. A. (taaspider)
* @url http://taaspider.itch.io/
*
*
* @help
* ============================================================================
* 使用条款
* ============================================================================
* taaspider开发的任何插件都可以免费用于商业和
*非商业性RPG Maker游戏,除非另有说明。只要记得
*信用“Taaspider”。
*
*禁止部分或全部taaspider插件的再分发,除非
*来源于官网:http://taaspider.itch.io允许你
*编辑和更改插件代码供自己使用,但你肯定不是
*允许将代码的任何部分作为自己的代码出售或重用。虽然不是
*需要使用我的插件,你的游戏的免费副本会很好!
*
*如果你喜欢我的作品,可以考虑在下载我的插件时提供捐赠,
*或者向我的Patreon账户提供每月抵押。这将有很大的帮助!
*此外,在facebook上关注我,获得我的活动的第一手消息!
*  Facebook: https://www.facebook.com/taaspider
*  Patreon: https://www.patreon.com/taaspider
*
* ============================================================================
* 介绍
* ============================================================================
*
* 警告:此插件需要RPG Maker MV 1.5.0或以上版本!请确保
*在使用此插件之前,您的RPG Maker MV软件是最新的。
*如果你使用MZ,你不需要任何特定的版本。
*
* -----------------------------------------------------------------------------
*
*此插件提供了添加等级和特定等级设置的功能
*技能。它的目标是让技能掌握的感觉,这意味着作为一个
*角色使用一项技能,他可能会慢慢变得更好。什么“得到”
*更好”意味着完全取决于开发者:技能可以变得更强,
*需要更少的MP来施放,增加一个有致命一击的状态,提升队伍士气
*增加防御,等等。该插件包括伤害调整和自定义
*可应用于特定技能等级的效果,增加趣味性
*随着技能掌握程度的提高而变得更加强大!
*
*该插件的主要特性是:
* -通过JSON文件加载技能水平数据,使其更易于配置
*并在整个游戏开发中进化等级数据;
* -如果您不习惯使用JSON文件,您也可以配置
*通过插件管理器的技能等级数据;
* -不仅提供了级别变化的公式,还允许更精确的
*控制每个新等级的每个技能方面;
* -允许TP增益受技能等级影响;
* -技能描述可以随着等级的提升而改变;
* -特定效果(如应用状态)随着技能等级的提升而改变;
* -使技能水平具有必须满足的特定要求
*在获得技能经验值以达到下一个等级(或阻止某个角色)之前
*首先要学会它);
* -只有当角色在战斗中幸存,或者只有当
*战斗胜利了;
*-定义一个不能升级的技能列表,比如默认攻击和守卫技能;
*
* =============================================================================
* 数据源配置
* =============================================================================
*
* 这个插件提供了两个选项来输入技能等级数据到你的游戏中
* JSON文件或通过插件管理器。
*
*使用JSON文件时,将其放入游戏的数据文件夹并进行配置
*插件管理器,关于它应该如何被读取以及哪个对象代表
*什么。在这种情况下,参数插件管理器技能应该被忽略。
*当使用插件管理器作为输入时,忽略参数JSON Config和关注插件管理器技能参数。
*
*以下部分描述了JSON文件的设置,但结构相同,可以在插件管理器的技能参数中找到。
*
* =============================================================================
* 说明-设置技能水平JSON文件
* =============================================================================
*
* 您的技能水平JSON文件必须具有以下结构:
*  [
*      {
*          "id": <skill id>,
*          "xpType": 1,
*          "default": {
*              "mpCost": <cost>,
*              "tpCost": <cost>,
*              "tpGain": <gain>,
*              "damage": "<damage formula>",
*              "req": "<requirements, if any>",
*              "descr": "<skill description>",
*              "dmgMods": ["<damage modifier tags here>", "<dmgMods>", ...]
*              "customEffect": ["<effects tags here>", "<effect>", ...]
*          },
*          "formulas": {
*              "mpCost": "<cost formula>",
*              "tpCost": "<cost formula>",
*              "tpGain": "<gain formula>",
*              "xp": "<xp formula>"
*          },
*          "levels": [
*              {
*                  "mpCost": <cost>,
*                  "tpCost": <cost>
*                  "tpGain": <gain>,
*                  "damage": "<damage formula>",
*                  "req": "<requirements, if any>",
*                  "descr": "<skill description>",
*                  "dmgMods": ["<damage modifier tags here>", "<dmgMods>", ...]
*                  "customEffect": ["<effects tags here>", "<effect>", ...]
*              },
*              {
*                  "mpCost": <cost>,
*                  ...
*              }
*          ]
*      },
*      {
*          "id": <skill id>,
*          ...
*      }
*  ]
*
* 标签名可以用插件参数定制,所以请随意
*根据您的喜好进行更改。但是请保持描述的结构
*以上否则不起作用。
*
* "xpType" 必须用来识别技能如何获得xp。有三个可能的值:
*  - 1: Skill uses(技能使用)
*  - 2: Battles won(战斗胜利)
*  - 3: Battles survived(战斗幸存)
*
* 如果没有提供值,插件将假定“技能使用”为默认值。
* “default”标记包括在未找到特定级别数据时的默认值
* (因此,如果设置了这些值,则可能不需要为技能的第一个级别定义数据)。
* 该插件将始终首先搜索特定级别的数据,然后搜索默认值,
* 如果没有找到,它将使用通过RPG Maker界面设置的值。
* “formula”数组是可选的,仅当您要为MP和TP成本、TP增益
* 或自定义XP曲线公式设置公式时,才必须使用该数组。 如果设置公式,
* “level”一词将被当前技能级别的插件替换。
* “levels”数组用于包含每个级别引入的特定更改。 如果不更改每个级别的值,
* 则不需要为每个级别定义所有标记。例如,如果MP成本在5级之前保持不变,
* 您可以省略级别1到4中的mpCost标记,并仅在默认数组中使用它,或仅在级别1和5中定义它。
*  "requirements"  标签不同于其他标签,因为它是累积的。
* 因此,更高级别的需求是所有先前级别需求的总和。
* 这是为了防止角色在不满足较弱版本要求的情况下尝试学习更高级别的技能时出现不一致。
* “levels”数组必须按顺序列出级别对象。如果要跳过某个级别上的更改,
* 只需将对象替换为“null”或空对象“{}”,如下例所示:
*  "levels": [
*      null,
*      {
*          "mpCost": <cost>
*      },
*      {},
*      {
*          "tpCost": <cost>
*      }
*  ]
*
* 如果技能在JSON文件中没有定义数据, 技能级别将被禁用(技能将始终列为处于起始级别)。
* 标签“dmgMods”和“customEffects”是特定插件代码的数组,
* 允许您为每个级别编程伤害修改器和特殊自定义效果。
* 有关支持的标记列表,请参阅下面的相应部分。
*
* ============================================================================
* 插件管理器作为源代码
* ============================================================================
*
*
* 通过插件管理器配置技能遵循与从JSON文件配置技能类似的结构。
* 应用相同的选项,但处理一些细节的方式不同:
  * - 每当MP Cost、TP Cost或TP Gain设置为-1时,插件将忽略该值;
*  - 特定技能等级上的空白描述、要求或伤害公式不会覆盖上一等级值,
*    与使用JSON文件时发生的情况相反;
* 只要记住这些规则并遵循参数窗口即可。 请记住,一个级别中设置的参数
* 会覆盖上一个级别中设置的值,但必须为每个级别设置自定义效果和伤害修改器,
* 才能使其生效(这两个级别与其他级别不同)。
*
* ============================================================================
* 技能要求
* ============================================================================
*
* 技能要求被视为评估声明。要使用用户的数据(无论是敌人还是角色),请使用前缀“a”。
*例如,要定义敏捷性高于80的需求,请使用:
*      a.agi > 80
*
* 您可以使用&& (and)或|| (or)添加更多条件。例如:要求敏捷度高于80的技能等级,并具备已学习的id为10的技能:
*      a.agi > 80 && a.hasSkill(10)
*
* 如果你想设定一个特定级别的技能要求,
* 只需使用带有两个参数的hasSkill函数,第一个参数是技能id,第二个参数是所需级别:
*      a.agi>80 && a.hasSkill(10, 2)
*
* ============================================================================
* 伤害修正
* ============================================================================
* 伤害修正是改变技能伤害公式的特殊代码。
*任何特定技能都可以有多个修改器。
*如果设置了特定于级别的修改器,它将替换该技能以前的任何修改器。
*这使得管理从一个级别到另一个级别的伤害进展变得更加容易。
*
* 目前,支持以下修改器:
*
* CRITICAL: <TYPE>
* 将<TYPE>替换为以下选项之一:
  *    - 0 或 NORMAL: 返回MV的默认暴击公式;
*     - 1, NEVER 或 DISABLE: 移除该技能造成暴击的任何机会;
*     - 2, ALWAYS, ENABLE 或 FORCE: 强制所有技能使用暴击;
范例:
*      CRITICAL: 0
*      CRITICAL: ENABLE
*      CRITICAL: NEVER
*
* DAMAGE MOD: <mod>
* DAMAGE MODIFIER: <mod>
*   使用“<mod>”格式之一更改技能伤害公式:
*       - <oper> x, <oper> x%: 将<oper>替换为+、-、*或/。
*      这将应用指定的操作数将损坏公式结果与指定数字相加、相除、相乘或相除;
*     范例:
*          DAMAGE MOD: +10
*          DAMAGE MOD: *2
*          DAMAGE MOD: -5
*          DAMAGE MODIFIER: +2%
*          DAMAGE MODIFIER: *10%
*           - EVAL <expression>: 对<expression>应用评估,将子句附加到伤害公式结果中;
*     范例:
*          DAMAGE MOD: EVAL * (a.hp/a.mhp)
*          DAMAGE MOD: EVAL + (a.mp/5)
*
* 尽管所有示例都以大写字母列出,但该插件不区分大小写。
*
* ============================================================================
* Custom Effects - 自定义效果
* ============================================================================
*
* 当伤害修正在技能执行前应用时,改变伤害输出,自定义效果在技能使用后应用。
*
* 目前,支持以下标记:
*
* ADD STATE: <state> <who> <intensity>
* ADD STATE: <state> <who> IF VAR <var ID> <operand> <value> THEN <intensity>
* ADD STATE: <state> <who> IF VARIABLE <var ID> <operand> <value> THEN <intensity>
* ADD STATE: <state> <who> IF SW <switch ID> <true|false> THEN <intensity>
* ADD STATE: <state> <who> IF SWITCH <switch ID> <true|false> THEN <intensity>
* ADD STATE: <state> <who> EVAL: <eval clause>
* REMOVE STATE: <state> <who> <intensity>
* REMOVE STATE: <state> <who> IF VAR <var ID> <operand> <value> THEN <intensity>
* REMOVE STATE: <state> <who> IF VARIABLE <var ID> <operand> <value> THEN <intensity>
* REMOVE STATE: <state> <who> IF SW <switch ID> <true|false> THEN <intensity>
* REMOVE STATE: <state> <who> IF SWITCH <switch ID> <true|false> THEN <intensity>
* REMOVE STATE: <state> <who> EVAL: <eval clause>
*  使用此效果可在技能使用后添加或移除状态效果。
*  将<state>替换为包含在双引号中的状态ID或状态名称,
*  而<who>必须由以下条款之一代替,规定谁将受到影响:
*      - USER: 影响技能使用者;
*      - PARTY: 影响用户的整个队伍(或敌群,如果被敌人使用);
*      - TARGET, or TARGETS: 影响技能目标,可以是一个或多个;
*      - DEAD ALLIES: 影响所有死亡状态的队伍或者敌群、members;
*      - DEAD ENEMIES: 影响所有死亡状态的敌人, 或者队伍成员;
*      - ALIVE ALLIES: 影响所有活着的人, 或者敌群, members;
*      - ALIVE ENEMIES: 影响所有活着的敌人, 或者队伍成员;
*      - PARTY BUT USER: 影响除使用者之外的整个队伍;
*      - ENEMIES BUT TARGET: 影响除使用者之外的整个队伍;
*   <intensity> 是可选的. 它的工作原理很像编辑器中的百分比。如果省略,插件将假定为100%强度。
* 如果条件可用于测试一个变量值或开关状态。
* 可以使用“THEN<intensity>”设置强度, 但如果省略,插件将再次假定为100%强度。
* <operand>可以是以下任一项:
*     >   >=  <   <=  ==  !=  <>
* 最后,“EVAL”条件会让你发疯。您只需要确保代码将返回一个表示状态强度的数字.
* 您可以引用a作为用户,引用b作为目标。查看下面的示例。
*     范例:
*          ADD STATE: 10 USER
*          REMOVE STATE: "Poison" ALIVE ALLIES
*          ADD STATE: "Bleed" ENEMIES BUT TARGET
*          REMOVE STATE: 15 PARTY
*          ADD STATE: 15 TARGET 50
*          ADD STATE: 15 TARGET IF VARIABLE 1 > 5 THEN 100
*          REMOVE STATE: 15 USER IF SWITCH 1 true
*          ADD STATE: 62 TARGET EVAL: (a.mat > b.mdf) ? 100 : 0
*          ADD STATE: 55 USER EVAL: (a.hp / a.mhp) * 100
*
* SWITCH n: <action>
* SWITCH n - m: <action>
* SWITCH n to m: <action>
*   更改一个或一系列开关状态(替换n和m以指定范围)。
* 标签<action>可以替换为以下效果之一:
*     - on: 将开关设置为true;
*     - off: 将开关设置为false;
*     - toggle: 切换开关的值;
*     - switch x: 复制开关x的值;
*     范例:
*          SWITCH 1: on
*          SWITCH 5 - 10: off
*          SWITCH 2 - 4: toggle
*          SWITCH 10: switch 1
*
* SWITCH n: EVAL <expression>
* SWITCH n - m: EVAL <expression>
*   根据评估操作的结果更改一个或a系列o开关状态(替换n和m以指定您的范围)。
* 标签<expression>必须替换为返回true或false的脚本,
* 或整数(其中任何大于零的值都将变为true,小于或等于零的值都将变为false)。
*     范例:
*          SWITCH 1: EVAL a.hp/a.mhp > 0.5
*          SWITCH 2 - 8: EVAL a.hasSkill(4, 5) && a.mp > 150
*
* VAR x <action>
* VAR x - y <action>
* VARIABLE x <action>
* VARIABLE x to y <action>
*  更改一个或一系列变量值(替换x和y以指定范围)。
*  标签<action>可以替换为以下效果之一:
*      - = N: 将变量或范围设置为值N. 也可以使用"= v[N]"来设置变量N的相同值;
*      - += N: 将N添加到变量的值. 也可以使用"+= v[N]"来添加变量N的值;
*      - -= N: 从变量的值中减去N。 也可以使用"-= v[N]"来减去变量N的值;
*      - *= N: 将变量的值乘以N. 也可以使用"*= v[N]"乘以变量N的值;
*      - /= N: 将变量的值除以N. 也可以使用"/= v[N]"除以变量N的值;
*      - %= N: 用当前值除以N的剩余部分替换变量值.也可以使用"%= v[N]"除以变量N的值;
  *     范例:
*          VAR 1 = 10
*          VARIABLE 7 += v[8]
*          VAR 2 - 7 *= 2
*          VAR 1 to 4 /= 3
*
* VAR x: EVAL <expression>
* VAR x - y: EVAL <expression>
* VARIABLE x: EVAL <expression>
* VARIABLE x - y: EVAL <expression>
*  根据评估操作的结果更改一个或一系列变量值(替换x和y以指定范围)。
*  标签<expression>必须替换为返回大于或等于零的整数的脚本。
*      范例:
*          VAR 1: EVAL Math.floor((a.hp / a.mhp) * 100)
*          VARIABLE 6 - 11: EVAL Math.round(a.mp / a.hp)
*          VARIABLE 3: EVAL $gameVariables.value(1) + a.hp
*
* EVAL: <eval clause>
*   对<eval clause>数据进行评估.
*  你可以使用对象"a" (a.hp, a.mp, a.hasSkill(<skillId>), a.actorId(), ...).访问技能使用者数据
*      范例:
*          EVAL: $gameVariables.setValue(1, a.actorId())
*          EVAL: a.hp > 100 ? $gameVariables.setValue(1, a.hp) : $gameVariables.setValue(1, 100)
*          EVAL: $gameVariables.setValue(1, Math.min(100, a.hp))
*
* COMMON EVENT: N
*   调用编号为N的公共事件。 但有一个重要的限制, 当前不支持将多个公共事件调用作为
*同一技能的自定义效果。如果尝试插入两个或多个公共事件效果,则只会运行最后一个。
* 每个级别可以有一个,但每个级别不能有多个。
*    范例:
*          COMMON EVENT: 10
*
* SUMMON: E[id]
* SUMMON: E[id,n]
* SUMMON: E[id], R[rn], LV[l1]
* SUMMON: E[id,n], R[rn], LV[l1,l2]
* SUMMON: E[id,n], R[rn], LV[+|-l1,+|-l2]
* SUMMON: E[id,n], R[rn], LV[+|-l1%,+|-l2%]
*   结合 "TAA_EnemyReinforcement" 和 "召唤敌人增援". 如果该技能由队伍成员执行,则无效。
*  有三个可能的标签。第一个是强制性的, 并且应始终出现在 ':'之后, 指定要召唤(E)的敌人ID,
*  可选包括必须呼叫敌人的次数,以逗号分隔。
*  其他两个标签(R和LV)可以按任意顺序放置,但只显示一次。
*  R必须是介于0和100之间的数字, 表示召唤成功的概率。 数字越大,成功的概率越高。
*  如果标签不存在,则有100%的可能性。
*  LV可用于确定特定的等级, 或召唤敌人的等级范围。
*  是的,必须启用"Yep_EnemyLevel"才能使其工作,否则它将被忽略。
*  如果指定的纯数字前面没有操作数,绝对数用作与最低或最高等级上限. 如果操作数已就位,
*  该级别是相对于使用该技能的人的级别计算的。例如,如果标签被指定为LV[-5,-2],并且使用技能的敌人处于7级,
*  这意味着被召唤的敌人将有2级和5级,技能使用者等级以下五到两个级别。或者,如果存在%符号,
*  级别范围作为技能使用者等级的附加百分比计算。例如, 一个等级为LV[-30%,+10%]的标签和
*  一个等级为10级的敌人使用该技能,会产生一个等级为7到11级的召唤增援,比技能使用者等级低30%到10%。
*  如果LV标签使用单个数字, 则是有ot但没有操作数, 被召唤的敌人将有精确的结果值作为其等级。
*
* ON CRITICAL
*   将此子句添加到之前任何自定义效果标签的开头,以便仅在技能获得暴击时生效。
*      范例:
*          ON CRITICAL ADD STATE: 5 USER
*          ON CRITICAL SWITCH 3: on
*          ON CRITICAL VAR 7 += 1
*          ON CRITICAL COMMON EVENT: 2
*
* ============================================================================
* Note Tags - 备注 标签
* ============================================================================
*
* 备注标签可以应用于职业, 角色或敌人定义初始技能等级。
* 您可以使用完整标签一次设置一个,或在技能掌握标签之间附上技能列表:
*
* <TAA_SKM: S[1], L[1], X[10]>
*
* 或者
*
* <TAA_SKM>
* S[1], L[1]
* S[2], L[2], X[11]
* </TAA_SKM>
*
* 还可以指定L和X的间隔,如下所示:
*
* <TAA_SKM: S[1], L[1,3], X[0,5]>
*
* 或者
*
* <TAA_SKM>
* S[1], L[1,3], X[0,5]
* </TAA_SKM>
*
* “S”代表技能, 因此,方括号内的数字必须是有效的技能id。
* “L”表示等级,并定义初始等级。"X" 表示 xp 并且是一个可选标记.
* 它定义了技能从已经获得的xp量开始。 这允许你设置敌人,使他们的技能更有可能在战斗中升级,
* 或者让一个可玩的角色在下一个等级的中途拥有技能。
* 如果你指定了L或X的间隔而不是固定的数字, 插件将在间隔内计算一个随机数。
* 通过这种方式,例如,你可以在一个敌群中拥有具有相同技能的随机经验的敌人,
* 这样每一个都可以在不同的时间升级。这里的目标是创造一层不可预测性,让玩家对事情更感兴趣!
*  
* ============================================================================
* 兼容性警告
* ============================================================================
*
* TAA_EnemyReinforcements
* 两个脚本是兼容的,只要确保EnemyReinforcements放在后面
* 插件列表中的SkillMastery。
*
*
* ============================================================================
* Script Calls - 脚本调用
* ============================================================================
*
* $gameSystem.getSkillMpCost(skillId, level)
*   基于技能ID和级别,返回技能MP成本。如果省略了级别,则返回技能的第一个级别的成本。
*
* $gameSystem.getSkillTpCost(skillId, level)
*  基于技能ID和级别,返回技能TP成本。如果省略了级别,则返回技能的第一个级别的成本。
*
* $gameSystem.getSkillTpGain(skillId, level)
*  基于技能ID和等级,返回技能基础TP增益。如果忽略等级,则返回技能第一个等级的基本增益。
*
* $gameSystem.getSkillDescription(skillId, level)
*  基于技能ID和级别,返回技能的描述。如果省略了级别,则返回技能的第一个级别的描述.
*
* $gameSystem.getDamageFormula(skillId, level)
*  基于技能ID和等级,以文本形式返回技能的伤害公式。如果省略级别,则返回技能第一个级别的伤害公式。
*
* $gameSystem.actorMeetsRequirements(skillId, level, actorId)
*  检查角色是否满足指定级别的参考技能的特定要求。如果级别未定义或超出允许的级别范围,
*  则返回技能第一个级别的分析。
*
* $gameSystem.getSkillXpType(skillId)
*  基于技能ID,返回该技能的XP类型:1表示技能使用,2表示赢得的战斗,3表示幸存的战斗。
*
* $gameSystem.getSkillLevel(skillId, actorId)
*  基于技能和角色ID,返回技能级别。如果角色不知道技能,则返回0。
*
* $gameSystem.learnSkill(actorId, skillId, customLevel, customXp)
*   教角色学习参考技能. 您可以使用参数customLevel和customXp在特定级别启动技能,
*   和/或进入下一等级的中途. 如果您希望角色在初始阶段学习技能,
*   并且之前没有任何经验,则可以忽略这两个方面。
*
* $gameSystem.getSkillProgression(actorId, skillId)
*  返回一个介于0和1之间的数字, 其中1表示已达到下一个级别(或已达到最大级别)。
*
* $gameSystem.isSkillKnown(actorId, skillId)
*  如果角色知道技能,则返回true;如果角色不知道,则返回false。
*
* $gameSystem.hasSkill(actorId, skillId, skillLevel)
*  如果角色的技能等级大于或等于skillLevel,则返回true。
* 如果省略skillLevel,则如果技能级别大于或等于最低级别,则返回true。
*
* $gameSystem.getCurrentSkillXp(actorId, skillId)
*  返回技能的当前XP。
*
* $gameSystem.getSkillXpToNextLevel(actorId, skillId)
*   返回角色必须获得多少经验才能达到下一个技能级别。
*
* $gameSystem.getSkillUses(actorId, skillId)
*   返回角色使用该技能的次数.
*
* $gameSystem.gainSkillXp(actorId, skillId, xp)
*   将指定数量的XP添加到角色技能。
*
* $gameSystem.setSkillLevel(actorId, skillId, level)
*   将角色的技能等级上限设置为允许的最大值。
*  
* ============================================================================
* Plugin Commands (MV) - 插件指令(MV)
* ============================================================================
*
* SKM learnSkill <actorId> <skillId> <level>
*  Teach skill referenced by skillId to actor. The third parameter defines at
*  which level the skill will be learned. If the level parameter is left blank,
*  the skill will be learned at the initial level.
*
* SKM learnMultiSkill <actorId> <skillId_1> <skillId_2> ... <skillId_N>
*  Teaches a number of specified skills to actor at the initial level.
*
* SKM gainXp <actorId> <skillId> <xpAmount>
*  Increases skill XP for actor (as long as requirements for the next level are
*  met).
*
* SKM setLevel <actorId> <skillId> <level>
*  Set skill level to a specified value, capped inside the minimum and maximum
*  range.
*  
* ============================================================================
* Plugin Commands (MZ) - 插件指令(MZ)
* ============================================================================
*
* Learn Skill
*   让角色学习一项新技能,设定其初始等级和经验值。
*  使用引擎默认命令添加技能仍然可以在添加的技能处于最低级别时使用。
*
* Learn Multiple Skills
*   同时让角色学习一系列技能. 所有技能都将添加到初始级别.
*
* Gain Skill XP
*  增加角色技能的经验. 获得的经验量可以由一个固定值(parameter XP)或通过一个变量
* (parameter XP from variable)确定。如果XP from变量设置为有效变量,则使用其值。
* 否则将应用固定的XP值。
*
* Change Level
*  改变角色的技能等级,要更改的级别数量可以通过固定值(级别更改)或有效
* 变量(Var的级别更改)指定。
*
* ============================================================================
* Changelog - 更改日志
* ============================================================================
*
*版本1.0.0:
* -初始版本
*版本1.0.1:
* -包括新的自定义效果:
* EVAL条款
*使用eval子句设置变量
*使用eval子句设置开关
* -包含了在等级和经验值注释标签中使用间隔的选项;
*版本1.0.2:
* -一些小的错误修复
* -使用条款的变化
*版本1.1.0:
* -修正了技能等级未在数据库中初始化的错误。使用技能
*会导致游戏崩溃;
* -更新添加/删除状态的自定义效果:
*更改了用于应用/移除状态的功能,以便状态电阻和
*考虑强度。以前总是添加和删除状态
*有100%的几率;
*增加了定义应用/移除状态可能性的选项,
*很像编辑器中的内容;
*添加了在应用/删除状态之前创建条件的选项。
*有三个选项:检查一个变量的值;测试一个开关;
*或者使用eval子句;
*-添加了与TAA _敌人强化相结合的自定义效果,允许技能
*改变强化召唤行为的等级。
*-添加了一个新的插件参数,允许您禁用敌人增强注意
*标签,并只对技能等级使用自定义效果。如果参数被禁用,标记
*包括在技能中的信息,无论技能级别如何,都会被处理。否则,
*只考虑自定义效果召唤子句;
*版本1.1.1:
*-增加了对召唤自定义效果子句中变量的支持;
*版本1.2.0:
*-增加了MZ兼容性;
*-添加了一个新参数来指定一个不应该被分级的技能列表
*(例如,默认攻击和守卫技能)。这阻止了这项技能
*触发升级动画并在动画名称中添加一个级别
*技能列表;
*版本1.2.1:
*修正了一个导致MZ装备场景崩溃的错误;
*版本1.2.2:
* -更改了一个函数调用,以防止在不正确使用技能时崩溃
*已初始化;
* -增加了绘制技能掌握量表的条件,以防止兼容性问题
*带其他插件;
*修正了一个在读取技能掌握数据时会导致游戏崩溃的错误
*在引导时使用插件管理器作为数据源;
* -增加了评估技能时引用当前技能id的变量ID
*要求;
* -增加了两个新参数:
*敌人技能等级提升:允许对敌人禁用技能等级提升;
*锁定特性技能:允许阻止特性提供的技能
*水平上升。如果启用,只有演员有效学习的技能可以
*获得经验;
*版本1.3.0:
* -修正了Fomar0153_EquipmentSkills会导致游戏的兼容性问题
*如果使用水平压力计,会发生碰撞;
*修正了一个会导致插件两次加载插件管理器技能数据的问题,
*在控制台中引起不必要的警告信息;
* -增加了参数,以进一步定制掌握规格;
* -增加了当技能达到极限时可选消息和动画的参数
*最高级别;
* -对消息显示级别进行了小的改进;
* -修正了技能消耗显示的bug
* -包含了一个参数,允许在技能时在TP和MP成本之间添加一个分隔符
*两者都需要。每种成本类型的默认引擎文本颜色不变;
* -增加了一个参数来定义技能成本格式模式;
*版本1.3.1:
* -增加了随着等级提升改变技能名称的能力;
* -增加了选项,允许玩家执行特定级别的技能;
* -代码清理和优化;
*版本1.3.2:
* -插件管理器技能等级设置的生活质量更新;
* -修正了技能等级选择窗口的一些问题;
*
* ============================================================================
* End of Help
* ============================================================================
*
* =================================================================================
* Commands (MZ)
* =================================================================================
*
* @command learnSkill
* @text Learn Skill
* @desc 让角色学习一项新技能。
*
* @arg actor
* @text Actor ID
* @type actor
* @default
* @desc 将学习新技能的角色ID.
*
* @arg skill
* @text New Skill
* @type skill
* @default
* @desc 将要学习的技能.
*
* @arg level
* @text Starting Level
* @type number
* @min 1
* @max 9999
* @default 1
* @desc 学习后的技能初始等级.
*
* @arg xp
* @text Initial Experience
* @type number
* @min 0
* @max 9999
* @default 0
* @desc 定义新技能的初始经验值。该值将限制为下一级别的值。
*
* @command learnMultiSkill
* @text Learn Multiple Skills
* @desc 通过引用技能ID列表,使用一个插件命令学习多种技能。
*
* @arg actor
* @text Actor ID
* @type actor
* @default
* @desc 将从列表中学习技能的角色ID。
*
* @arg skillList
* @text Skill List
* @type skill[]
* @default []
* @desc 角色要学习的技能ID(或变量标记)的逗号分隔列表。所有这些都将在初级阶段学习。
*
* @command gainXp
* @text Gain Skill XP
* @desc 获得技能经验。
*
* @arg actor
* @text Actor
* @type actor
* @default
* @desc 为其增加技能经验的角色。
*
* @arg skill
* @text Skill
* @type skill
* @default
* @desc 增加掌握经验的技能。
*
* @arg xp
* @text XP
* @type number
* @min 1
* @max 9999
* @default 1
* @desc 要获得的XP量(如果未选择任何变量)。如果xp超过下一级阈值,技能将升级。
*
* @arg xpVar
* @text XP from Variable
* @type variable
* @default
* @desc 从中读取要获得的XP量的变量。
*
  * @command changeLevel
* @text Change Level
* @desc 改变角色的技能等级。
*
* @arg actor
* @text Actor
* @type actor
* @default
* @desc 为其增加技能经验的角色。
*
* @arg skill
* @text Skill
* @type skill
* @default
* @desc 增加掌握经验的技能.
*
* @arg operation
* @text Operation
* @type select
* @option =
* @option +
* @option -
* @default +
* @desc 级别更改时应用哪个操作.
*
* @arg value
* @text Level Change
* @type number
* @min 1
* @max 9999
* @default 1
* @desc 根据所选操作应用于技能级别的值(如果未设置值变量).
*
* @arg valueVar
* @text Level Change from Var
* @type variable
* @default
* @desc 变量,从中读取根据所选操作应用于技能级别的值。
*
* =================================================================================
* Parameters
* =================================================================================
*
* @param ---DataSource Config---
* @default
*
* @param Source Type
* @parent ---DataSource Config---
* @text 数据源类型
* @type combo
* @option JSON File
* @option Plugin Manager
* @default JSON File
* @desc 选择将书籍数据加载到游戏中的源类型。
*
* @param Plugin Manager Skills
* @parent ---DataSource Config---
* @type struct<PmSkills>[]
* @default []
* @desc 使用插件管理器按级别配置技能更改。
*
* @param JSON Config
* @parent ---DataSource Config---
* @type struct<JsonConfig>
* @default {"File":"SkillLevels.json","ID Object":"id","Default Object":"default","Level Array Object":"levels","MP Cost Object":"mpCost","TP Cost Object":"tpCost","TP Gain Object":"tpGain","Damage Formula Object":"damage","Requirements Object":"req","Description Object":"descr","Custom Effects Object":"customEffects","Damage Modifiers Object":"dmgMods","EXP Type Object":"xpType","Formula Array Object":"formulas","EXP Formula Object":"xp"}
* @desc 将JSON文件用作数据源时配置属性。
*
* @param ---Default Global Config---
* @default
*
* @param Minimum Level
* @parent ---Default Global Config---
* @type number
* @min 0
* @max 9999
* @default 1
* @desc 任何技能的最低初始等级。
*
* @param Maximum Level
* @parent ---Default Global Config---
* @type number
* @min 1
* @max 9999
* @default 5
* @desc 任何技能所能达到的最高等级.
*
* @param Unleveled Skills
* @parent ---Default Global Config---
* @type skill[]
* @default []
* @desc 没有等级的技能列表,不应升级。
*
* @param Lock Trait Skills
* @parent ---Default Global Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 如果启用,防止技能与特性升级。
*
* @param Skill Name Display
* @parent ---Default Global Config---
* @type text
* @default %1 Lv%2
* @desc 如何显示技能名称?
* %1 - 技能名称  %2 - 技能等级
*
* @param Skill Cost Separator
* @parent ---Default Global Config---
* @type text
* @default +
* @desc 当一个技能同时需要MP和TP时,设置文本来区分MP和TP。
*
* @param Skill Cost Display
* @parent ---Default Global Config---
* @type text
* @default %1 %2
* @desc 我们如何显示技能成本?
* %1 -成本价值  %2 - 成本类型 (TP or MP)
*
* @param Default EXP Formula
* @parent ---Default Global Config---
* @type text
* @default level * 15 + 5
* @desc 默认平衡公式。
*
* @param Show Level up Animation
* @parent ---Default Global Config---
* @type combo
* @option None - 无
* @option Actors Only - 仅角色
* @option Enemies Only - 仅敌人
* @option Always - 总是
* @default Always
* @desc 在技能等级上启用/禁用动画。
*
* @param Level up Animation
* @parent ---Default Global Config---
* @type animation
* @require 1
* @default 51
* @desc 要在技能等级上播放的动画id。
*
* @param Level up Message
* @parent ---Default Global Config---
* @type text
* @default %1 leveled up!
* @desc 要在技能级别上显示的文本。将其留空以不显示任何消息。 %1 - 技能名称 %2 - 角色/敌人名称
*
* @param Max Lv Custom Msg/Anim
* @parent ---Default Global Config---
* @type boolean
* @on ENABLE
* @off DISABLE
* @default false
* @desc 决定当技能达到最高等级时是否使用替代信息和动画。
*
* @param Max Lv Animation
* @parent ---Default Global Config---
* @type animation
* @require 1
* @default 53
* @desc 技能达到最高等级时播放的动画id。
*
* @param Max Lv Message
* @parent ---Default Global Config---
* @type text
* @default %1 reached its maximum potential!
* @desc 技能达到最大值时显示的文本。留空不显示任何消息。%1 -技能名称 %2 -演员/敌人名称
*
* @param Enemy Skill Level Up
* @parent ---Default Global Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 敌方技能应该升级吗?
*
* @param Enemy Level up Message
* @parent ---Default Global Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 我们应该向敌人展示技能提升信息吗?
*
* @param Disable ER Tags
* @parent ---Default Global Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 如果启用,"TAA_EnemyEnhanced"将仅在标签作为技能级别自定义效果添加时起作用。
*
* @param Allow Level Choosing
* @parent ---Default Global Config---
* @type boolean
* @on YES
* @off NO
* @default false
* @desc 如果启用,并且技能等级高于1级,则启用另一个窗口来选择要使用的等级。
*
* @param Level Select Indicator
* @parent ---Default Global Config---
* @type text
* @default >
* @desc 显示玩家可以从技能等级列表中选择使用哪个等级的文本。
*
* @param ---Gauge Config---
* @default
*
* @param Show Mastery Gauge
* @parent ---Gauge Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 显示掌握进度的进度条仪表?
*
* @param Default Gauge Color 1
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 31
* @default 12
* @desc 默认主仪表颜色,如果未设置特定级别颜色。
*
* @param Default Gauge Color 2
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 31
* @default 4
* @desc 默认仪表2颜色,如果未设置特定级别颜色.
*
* @param Custom Gauge Colors
* @parent ---Gauge Config---
* @type struct<GaugeLevelConfig>[]
* @default []
* @desc 按技能级别列出的自定义仪表颜色。
*
* @param Gauge Type
* @parent ---Gauge Config---
* @type combo
* @option Vertical - 垂直
* @option Horizontal - 水平
* @default Vertical
* @desc 仪表应垂直还是水平?
*
* @param Gauge Height
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 32
* @default 32
* @desc 掌握度仪表的高度。
*
* @param Gauge Width
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 9999
* @default 5
* @desc 掌握度仪表的宽度。
*
* @param Gauge Background Color
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 31
* @default 19
* @desc 确定仪表背景色。
*
* @param Gauge Outline
* @parent ---Gauge Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 绘制仪表轮廓?
*
* @param Gauge Outline Thickness
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 15
* @default 2
* @desc 如果启用了轮廓,则确定仪表轮廓的厚度。
*
* @param Gauge Outline Color
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 31
* @default 9
* @desc 确定仪表轮廓颜色。
*
* @param Lock Gauge on Requirements
* @parent ---Gauge Config---
* @type boolean
* @on YES
* @off NO
* @default true
* @desc 定义在未满足下一个技能级别的要求时,是否应突出显示锁定的仪表.
*
* @param Locked Gauge Border Color
* @parent ---Gauge Config---
* @type number
* @min 0
* @max 31
* @default 10
* @desc 在锁定进度条的边界处使用的颜色。
*
* @param ---Level Select Window---
* @default
*
* @param Level Name Display
* @parent ---Level Select Window---
* @type text
* @default %1 Lv%2
* @desc 我们如何显示技能名称?
* %1 - 技能名称  %2 - 技能等级
*
* @param Level Window Max Rows
* @parent ---Level Select Window---
* @type number
* @min 0
* @max 10
* @default 5
*
* @param Level Window Padding
* @parent ---Level Select Window---
* @type number
* @min 0
* @max 999
* @default 18
* @desc 水平窗口填充。
*
* @param Level Window Standard Opacity
* @parent ---Level Select Window---
* @type number
* @min 0
* @max 255
* @default 255
* @desc 水平窗口标准不透明度。
*
* @param Level Window Back Opacity
* @parent ---Level Select Window---
* @type number
* @min 0
* @max 255
* @default 192
* @desc 水平窗口背面不透明度。
*
* @param Level Window Skin
* @parent ---Level Select Window---
* @type file
* @dir img/system
* @require 1
* @default window
* @desc 确定级别窗口外观。
*
*/

//=============================================================================
// JSON File Configuration
//=============================================================================
/*~struct~JsonConfig:
* @param File
* @type text
* @default SkillLevels.json
* @desc 数据文件夹上的技能级别JSON文件.
*
* @param ID Object
* @type text
* @default id
* @desc 技能ID的对象。(默认值:ID)
*
* @param Default Object
* @type text
* @default default
* @desc 使用技能数据的默认结构引用“默认”对象。(默认值:默认)
*
* @param Level Array Object
* @type text
* @default levels
* @desc 对象引用具有特定于级别的数据的数组。(默认值:级别)
*
* @param Name Object
* @type text
* @default name
* @desc 引用技能名称的对象。(默认值:mpCost)
*
* @param MP Cost Object
* @type text
* @default mpCost
* @desc 对象引用技能MP成本。(默认值:mpCost)
*
* @param TP Cost Object
* @type text
* @default tpCost
* @desc 对象引用技能TP成本。 (默认值:  tpCost)
*
* @param TP Gain Object
* @type text
* @default tpGain
* @desc 对象引用技能增益。 (默认值: tpGain)
*
* @param Scope Object
* @type text
* @default scope
* @desc 对象引用技能范围。(默认值:  scope)
*
* @param Damage Formula Object
* @type text
* @default damage
* @desc 对象引用技能伤害公式。(默认值:damage)
*
* @param Requirements Object
* @type text
* @default req
* @desc 对象引用技能要求。这是一次评估。 (默认值: req)
*
* @param Description Object
* @type text
* @default descr
* @desc 对象引用技能描述。 (默认值: descr)
*
* @param Custom Effects Object
* @type note
* @default customEffects
* @desc 对象引用技能自定义效果。 (默认值: customEffects)
*
* @param Damage Modifiers Object
* @type note
* @default dmgMods
* @desc 对象引用技能伤害修饰符。 (默认值: dmgMods)
*
* @param EXP Type Object
* @type text
* @default xpType
* @desc 对象定义升级时使用的XP类型。
*
* @param Formula Array Object
* @type text
* @default formulas
* @desc 包含每个参数的公式对象的可选数组。
*
* @param EXP Formula Object
* @type text
* @default xp
* @desc 对象引用定义升级需要多少XP的公式。
*
*/

//=============================================================================
// Plugin Manager Skills
//=============================================================================
/*~struct~PmSkills:
  *
  * @param Skill ID
  * @type skill
  * @default
  * @desc 当前配置的技能ID。
  *
  * @param XP Type
  * @type select
  * @option Skill Uses - 技能使用
  * @value 1
  * @option Battles Won - 胜利
  * @value 2
  * @option Battles Survived - 战斗存活
  * @value 3
  * @default 1
  * @desc 使用者将如何获得使用此技能的经验?
  *
  * @param Formulas
  * @type struct<SkillFormulas>
  * @default
  * @desc 用于配置数字参数的公式。不建议同时设置公式和特定级别值。
  *
  * @param Default Skill Parameters
  * @type struct<SkillData>
  * @default
  * @desc 如果未启用特定于级别的设置,则为默认技能数据。
  *
  * @param Level Specific Data
  * @type struct<SkillData>[]
  * @desc 特定级别的数据。除了伤害模式和自定义效果外,所有其他一个等级的参数都会替换上一个等级。
  *
  */

//=============================================================================
// Gauge Level Configuration
//=============================================================================
/*~struct~SkillData:
  * @param Name
  * @type text
  * @default
  * @desc 技能名称。如果为空,插件将保持以前的等级值。
  *
  * @param MP Cost
  * @type number
  * @min -1
  * @max 9999
  * @default -1
  * @desc 技能MP成本。如果不想定义值,请设置-1。
  *
  * @param TP Cost
  * @type number
  * @min -1
  * @max 9999
  * @default -1
  * @desc 技能TP成本。如果不想定义值,请设置-1。
  *
  * @param TP Gain
  * @type number
  * @min -1
  * @max 9999
  * @default -1
  * @desc 技能TP增益. 如果不想定义值,请设置-1。
  *
  * @param Scope
  * @type select
  * @option Disable - 禁用
  * @value -1
  * @option None - 无
  * @value 0
  * @option 1 Enemy - 一个敌人
  * @value 1
  * @option All Enemies - 所有敌人
  * @value 2
  * @option 1 Random Enemy - 一个随机敌人
  * @value 3
  * @option 2 Random Enemies - 两个随机敌人
  * @value 4
  * @option 3 Random Enemies - 三个随机敌人
  * @value 5
  * @option 4 Random Enemies - 四个随机敌人
  * @value 6
  * @option 1 Ally - 一个友方单位
  * @value 7
  * @option All Allies - 所有友方单位
  * @value 8
  * @option 1 Ally (Dead) - 一个死亡友方单位
  * @value 9
  * @option All Allies (Dead) - 所有死亡友方单位
  * @value 10
  * @option The User - 使用者
  * @value 11
  * @default -1
  * @desc 按技能级别自定义技能范围。如果不想定义值,请禁用。
  *
  * @param Damage Formula
  * @type text
  * @desc 技能伤害公式(它是一个评估,a=使用者,b=目标)。
  *
  * @param Skill Requirements
  * @type text
  * @desc 学习技能或将进度解锁到某个级别的要求。
  *
  * @param Description
  * @type note
  * @desc 技能描述。仅当要覆盖上一级/默认描述时才设置它。
  *
  * @param Damage Modifiers
  * @type text[]
  * @desc 已启用伤害修改器列表。仅在设置为当前级别时有效。
  *
  * @param Custom Effects
  * @type text[]
  * @desc 启用的自定义效果列表。仅在设置为当前级别时有效。
  *
  */

//=============================================================================
// Skill Level Formula Configuration
//=============================================================================
/*~struct~SkillFormulas:
  *
  * @param EXP Formula
  * @type text
  * @desc 计算技能等级的公式。如果留空,则使用插件默认值(这是一次评估)
  *
  * @param MP Cost
  * @type text
  * @desc 计算技能MP成本的公式。仅当未设置特定值时才引用(这是一次评估)
  *
  * @param TP Cost
  * @type text
  * @desc 计算技能TP成本的公式。仅当未设置特定值时才引用(这是一次评估)
  *
  * @param TP Gain
  * @type text
  * @desc 计算技能增益的公式。仅当未设置特定值时才引用(这是一次评估)
  *
  */

//=============================================================================
// Gauge Level Configuration
//=============================================================================
/*~struct~GaugeLevelConfig:
  *
  * @param Level
  * @type number
  * @min 0
  * @max 9999
  * @desc 受此颜色设置影响的等级。
  *
  * @param Color 1
  * @type number
  * @min 0
  * @max 31
  * @default 12
  * @desc 主仪表颜色。
  *
  * @param Color 2
  * @type number
  * @min 0
  * @max 31
  * @default 4
  * @desc 仪表2颜色。
  *
  */

//=============================================================================
// Local Functions
//=============================================================================

TAA.skm.functions = TAA.skm.functions || {};
TAA.skm.functions.prepareUnleveledList = function(params){
    var list = params ? JSON.parse(params) : [];
    var result = [];
    if(!list || list.length <= 0) return result;
    for(var i=0; i<list.length; i++){
        if(!isNaN(list)){
            result.push(parseInt(list));
        }
    }
    return result;
};

//=============================================================================
// Parameters Setup
//=============================================================================

TAA.skm.Parameters = TAA.skm.Parameters || {};
var Parameters = PluginManager.parameters(TAA.skm.PluginName);

TAA.skm.Parameters.SourceType = Parameters['Source Type'];
TAA.skm.Parameters.JsonConfig = JSON.parse(Parameters['JSON Config']);
TAA.skm.Parameters.PMSkills = JSON.parse(Parameters['Plugin Manager Skills']);

TAA.skm.Parameters.MinLevel = !isNaN(Parameters['Minimum Level']) ? parseInt(Parameters['Minimum Level']) : 1;
TAA.skm.Parameters.MaxLevel = !isNaN(Parameters['Maximum Level']) ? parseInt(Parameters['Maximum Level']) : 5;
TAA.skm.Parameters.Unleveled = TAA.skm.functions.prepareUnleveledList(Parameters['Unleveled Skills']);
TAA.skm.Parameters.LockTraitSkills = JSON.parse(Parameters['Lock Trait Skills']) == true;
TAA.skm.Parameters.SkillName = Parameters['Skill Name Display'];
TAA.skm.Parameters.SkillCostSeparator = Parameters['Skill Cost Separator'] === undefined || Parameters['Skill Cost Separator'] === "" ? " " : Parameters['Skill Cost Separator'];
TAA.skm.Parameters.SkillCostDisplay = Parameters['Skill Cost Display'];
TAA.skm.Parameters.XPFormula = Parameters['Default EXP Formula'];

TAA.skm.Parameters.LvlUpAnimConfig = Parameters['Show Level up Animation'];
TAA.skm.Parameters.LvlUpAnimation = !isNaN(Parameters['Level up Animation']) ? parseInt(Parameters['Level up Animation']) : 51;
TAA.skm.Parameters.LvlUpMsg = Parameters['Level up Message'] || "";
TAA.skm.Parameters.MaxLvMsgEnabled = JSON.parse(Parameters['Max Lv Custom Msg/Anim']) == true;
TAA.skm.Parameters.MaxLvAnimation = !isNaN(Parameters['Max Lv Animation']) ? parseInt(Parameters['Max Lv Animation']) : 53;
TAA.skm.Parameters.MaxLvMsg = Parameters['Max Lv Message'] || "";
TAA.skm.Parameters.EnemyLvlUp = JSON.parse(Parameters['Enemy Skill Level Up']) == true;
TAA.skm.Parameters.EnemyLvlUpMsg = JSON.parse(Parameters['Enemy Level up Message']) == true;
TAA.skm.Parameters.ERTag = Parameters['Disable ER Tags'] === 'true';
TAA.skm.Parameters.AllowLevelSelect = Parameters['Allow Level Choosing'] == 'true';
TAA.skm.Parameters.LevelSelectIndicator = Parameters['Level Select Indicator'] || "";

TAA.skm.Parameters.ShowGauge = JSON.parse(Parameters['Show Mastery Gauge']);
TAA.skm.Parameters.GaugeColor1 = !isNaN(Parameters['Default Gauge Color 1']) ? parseInt(Parameters['Default Gauge Color 1']) : 12;
TAA.skm.Parameters.GaugeColor2 = !isNaN(Parameters['Default Gauge Color 2']) ? parseInt(Parameters['Default Gauge Color 2']) : 4;
TAA.skm.Parameters.CustomGaugeColors = JSON.parse(Parameters['Custom Gauge Colors']);
TAA.skm.Parameters.GaugeType = Parameters['Gauge Type'] || 'Vertical';
TAA.skm.Parameters.GaugeHeight = !isNaN(Parameters['Gauge Height']) ? parseInt(Parameters['Gauge Height']) : 32;
TAA.skm.Parameters.GaugeWidth = !isNaN(Parameters['Gauge Width']) ? parseInt(Parameters['Gauge Width']) : 5;
TAA.skm.Parameters.GaugeBgColor = !isNaN(Parameters['Gauge Background Color']) ? parseInt(Parameters['Gauge Background Color']) : 19;
TAA.skm.Parameters.GaugeOutline = JSON.parse(Parameters['Gauge Outline']) == true;
TAA.skm.Parameters.GaugeOutlineThickness = !isNaN(Parameters['Gauge Outline Thickness']) ? parseInt(Parameters['Gauge Outline Thickness']) : 2;
TAA.skm.Parameters.GaugeOutlineColor = !isNaN(Parameters['Gauge Outline Color']) ? parseInt(Parameters['Gauge Outline Color']) : 9;
TAA.skm.Parameters.LockGaugeOnReqs = JSON.parse(Parameters['Lock Gauge on Requirements']);
TAA.skm.Parameters.LockedGaugeColor = !isNaN(Parameters['Locked Gauge Border Color']) ? parseInt(Parameters['Locked Gauge Border Color']) : 10;
TAA.skm.Parameters.LockedGaugeThickness = !isNaN(Parameters['Locked Gauge Border Thickness']) ? parseInt(Parameters['Locked Gauge Border Thickness']) : 2;

TAA.skm.Parameters.SkillLevelWindow = {};
TAA.skm.Parameters.SkillLevelWindow.SkillName = Parameters['Skill Name Display'];
TAA.skm.Parameters.SkillLevelWindow.MaxRows = !isNaN(Parameters['Level Window Max Rows']) ? parseInt(Parameters['Level Window Max Rows']) : 5;
TAA.skm.Parameters.SkillLevelWindow.Padding = !isNaN(Parameters['Level Window Padding']) ? parseInt(Parameters['Level Window Padding']) : 18;
TAA.skm.Parameters.SkillLevelWindow.StandardOpacity = !isNaN(Parameters['Level Window Standard Opacity']) ? parseInt(Parameters['Level Window Standard Opacity']) : 255;
TAA.skm.Parameters.SkillLevelWindow.BackOpacity = !isNaN(Parameters['Level Window Back Opacity']) ? parseInt(Parameters['Level Window Back Opacity']) : 192;
TAA.skm.Parameters.SkillLevelWindow.WindowSkin = Parameters['Level Window Skin'] !== undefined ? Parameters['Level Window Skin'] : "window";

//=============================================================================
// DataManager
//=============================================================================

TAA.skm.alias.DataManager = TAA.skm.alias.DataManager || {};
TAA.skm.alias.DataManager.createGameObjects = DataManager.createGameObjects;
DataManager.createGameObjects = function(){
    TAA.skm.alias.DataManager.createGameObjects.call(this);
    SkillManager.initialize();
};

if(TAA.skm.Parameters.SourceType === 'JSON File'){
    var file = TAA.skm.Parameters.JsonConfig['File'] || 'SkillLevels.json';
    DataManager._databaseFiles.push({ name: '$dataSkillLevels', src: file });

    TAA.skm.alias.DataManager.loadDataFile = DataManager.loadDataFile;
    DataManager.loadDataFile = function(name, src){
        var file = TAA.skm.Parameters.JsonConfig['File'] || 'SkillLevels.json';
        file = 'Test_' + file;
        if(src === file)
            src = TAA.skm.Parameters.JsonConfig['File'] || 'SkillLevels.json';
        TAA.skm.alias.DataManager.loadDataFile.call(this, name, src);
    }
}

var $dataSkillLevels = $dataSkillLevels || [];

//=============================================================================
// Skill Manager
//=============================================================================

function SkillManager() {
    throw new Error('This is a static class');
}

/**
* Initializes Skill Manager
*
* @static
* @method initialize
*/
SkillManager.initialize = function(){
    if(this._initialized === true)
        return;
    if(TAA.skm.Parameters.SourceType === 'JSON File')
        this.initByJson();
    else
        this.initByPluginManager();
   
    this.customizeDataSkill();
    this._initialized = true;
};

/**
* Initializes Skill Manager through a JSON file
*
* @static
* @method initByJson
*/
SkillManager.initByJson = function(){
    this._defaultDataObject = TAA.skm.Parameters.JsonConfig['Default Object'] || "default";
    this._descriptionObject = TAA.skm.Parameters.JsonConfig['Description Object'] || "descr";
    this._damageFormulaObject = TAA.skm.Parameters.JsonConfig['Damage Formula Object'] || "damage";
    this._idObject = TAA.skm.Parameters.JsonConfig['ID Object'] || "id";
    this._levelArrayObject = TAA.skm.Parameters.JsonConfig['Level Array Object'] || "levels";
    this._reqObject = TAA.skm.Parameters.JsonConfig['Requirements Object'] || "req";
    this._nameObject = TAA.skm.Parameters.JsonConfig['Name Object'] || "name";
    this._mpCostObject = TAA.skm.Parameters.JsonConfig['MP Cost Object'] || "mpCost";
    this._tpCostObject = TAA.skm.Parameters.JsonConfig['TP Cost Object'] || "tpCost";
    this._tpGainObject = TAA.skm.Parameters.JsonConfig['TP Gain Object'] || "tpGain";
    this._scopeObject = TAA.skm.Parameters.JsonConfig['Scope Object'] || "scope";
    this._xpTypeObject = TAA.skm.Parameters.JsonConfig['EXP Type Object'] || "xpType";
    this._customEffectsObject = TAA.skm.Parameters.JsonConfig['Custom Effects Object'] || "customEffects";
    this._damageModifiersObject = TAA.skm.Parameters.JsonConfig['Damage Modifiers Object'] || "dmgMods";
    this._xpFormulaObject = TAA.skm.Parameters.JsonConfig['EXP Formula Object'] || "xp";
    this._formulaArrayObject = TAA.skm.Parameters.JsonConfig['Formula Array Object'] || "formulas";

    this.reorderDataSkillLevels();
};

/**
* Initializes Skill Manager through Plugin Manager skills
*
* @static
* @method initByPluginManager
*/
SkillManager.initByPluginManager = function(){
    this._defaultDataObject = "Default Skill Parameters";
    this._descriptionObject = "Description";
    this._damageFormulaObject = "Damage Formula";
    this._idObject = "Skill ID";
    this._levelArrayObject = "Level Specific Data";
    this._reqObject = "Skill Requirements";
    this._nameObject = "Name";
    this._mpCostObject = "MP Cost";
    this._tpCostObject = "TP Cost";
    this._tpGainObject = "TP Gain";
    this._scopeObject = "Scope";
    this._xpTypeObject = "XP Type";
    this._customEffectsObject = "Custom Effects";
    this._damageModifiersObject = "Damage Modifiers";
    this._xpFormulaObject = "EXP Formula";
    this._formulaArrayObject = "Formulas";
   
    for(var i=0; i < TAA.skm.Parameters.PMSkills.length; i++){
        var skmData = this.parsePMSkillItem(JSON.parse(TAA.skm.Parameters.PMSkills));
        var id = skmData[this._idObject];
        if($dataSkillLevels[id] !== undefined)
            console.error("Duplicated ID: " + id + ". Keeping the first entry.");
        else
            $dataSkillLevels[id] = skmData;
    }
};

/**
* Auxiliary function to parse Plugin Manager skills
*
* @static
* @method parsePMSkillItem
*/
SkillManager.parsePMSkillItem = function(item){
    var skillData = {};
    skillData[this._idObject] = parseInt(item[this._idObject]);
    skillData[this._xpTypeObject] = (item[this._xpTypeObject] !== undefined && item[this._xpTypeObject] !== "") ? parseInt(item[this._xpTypeObject]) : 1;
    var formulas = [];
    if(item[this._formulaArrayObject] !== undefined && item[this._formulaArrayObject] !== "")
        formulas = JSON.parse(item[this._formulaArrayObject]);

    for(var f in formulas){
        var str = formulas[f];
        if(str !== undefined && str !== ""){
            skillData[this._formulaArrayObject] = skillData[this._formulaArrayObject] || {};
            skillData[this._formulaArrayObject][f] = str;
        }
    }
    var defaults = (item[this._defaultDataObject] !== "") ? JSON.parse(item[this._defaultDataObject]) : undefined;
    if(defaults !== undefined)
        this.parseSkillObjectGroup(defaults, this._defaultDataObject, skillData, false);
    var levels = (item[this._levelArrayObject] !== "") ? JSON.parse(item[this._levelArrayObject]) : [];
    if(levels !== undefined && Array.isArray(levels)){
        for(var i=0; i < levels.length; i++){
            this.parseSkillObjectGroup(JSON.parse(levels), this._levelArrayObject, skillData, true);
        }
    }

    if((skillData[this._levelArrayObject] || []).length > 0){
        skillData[this._levelArrayObject].unshift(null);
    }

    return skillData;
};

/**
* Auxiliary function to parse Plugin Manager skills
*
* @static
* @method parseSkillObjectGroup
*/
SkillManager.parseSkillObjectGroup = function(obj, key, skillData, isArray){
    if(isArray) skillData[key] = skillData[key] || [];
    var newObj = {};
    for(var k in obj){
        if(obj[k] === "" || obj[k] === undefined) continue;
        if(k === "MP Cost" || k === "TP Cost" || k === "TP Gain"){
            if(parseInt(obj[k]) >= 0){
                newObj[k] = parseInt(obj[k]);
            }
        }
        else if(k === "Scope"){
            if(obj[k] !== undefined && !isNaN(obj[k])) newObj[k] = obj[k];
        }
        else if(k === "Damage Formula" || k === "Skill Requirements" || k === "Name"){
            newObj[k] = obj[k];
        }
        else if(k === "Description"){
            newObj[k] = JSON.parse(obj[k]);
        }
        else if(obj[k] !== undefined && Array.isArray(JSON.parse(obj[k])) && JSON.parse(obj[k]).length > 0){
            newObj[k] =  newObj[k] || [];
            newObj[k] = JSON.parse(obj[k]);
        }
    }
    if(isArray) skillData[key].push(newObj);
    else skillData[key] = newObj;

    return skillData;
}

/**
* Auxiliary function to reorder skills loaded through a JSON file
*
* @static
* @method reorderDataSkillLevels
*/
SkillManager.reorderDataSkillLevels = function(){
    var orderedArray = [];
    if($dataSkillLevels === undefined || $dataSkillLevels === null || $dataSkillLevels.length === 0)
        return;
   
    for(var i=0; i< $dataSkillLevels.length; i++){
        if($dataSkillLevels !== undefined && $dataSkillLevels[this._idObject] !== undefined){
            var id = $dataSkillLevels[this._idObject];

            if(orderedArray[id] !== undefined)
                console.error("Duplicated ID: " + id + ". Keeping the first entry.");
            else
                orderedArray[id] = $dataSkillLevels;   
        }
    }
    $dataSkillLevels = orderedArray.slice();
};

/**
* Adds custom functions to skill objects to allow ease of access to leveled data
*
* @static
* @method customizeDataSkill
*/
SkillManager.customizeDataSkill = function(){
    if($dataSkills === undefined || $dataSkills === null || $dataSkills.length === 0)
        return;
    for(var i=1; i < $dataSkills.length; i++){
        var skill = $dataSkills;

        // Custom Name
        skill.leveledName = function(level) {
            return SkillManager.getName(this, level);
        };
        // Custom MP Cost
        skill.leveledMpCost = function(level) {
            return SkillManager.getMpCost(this, level);
        };
        // Custom TP Cost
        skill.leveledTpCost = function(level) {
            return SkillManager.getTpCost(this, level);
        };
        // Custom TP Gain
        skill.leveledTpGain = function(level) {
            return SkillManager.getTpGain(this, level);
        };
        // Custom Skill Scope
        skill.leveledScope = function(level) {
            return SkillManager.getScope(this, level);
        };
        // Custom Description
        skill.leveledDescription = function(level) {
            return SkillManager.getDescription(this, level);
        };
        // Custom damage formula
        skill.leveledDamage = function(level){
            return SkillManager.getDamageFormula(this, level);
        };
        // Custom requirement
        skill.requirement = function(level, subject) {
            return SkillManager.requirementsMet(this, level, subject);
        };
        // Custom effects tags
        skill.customEffects = function(subject){
            return SkillManager.getModifiers(this, subject, 'customEffects');
        };
        // Damage modifiers
        skill.damageMods = function(subject){
            return SkillManager.getModifiers(this, subject, 'damageModifiers');
        };

        $dataSkills = skill;
    }
};

/**
* Returns Name for a specified level
*
* @static
* @method getName
*/
SkillManager.getName = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.description;

    var text = undefined;
    if(level === undefined)
        text = this.getDefault(id, 'name');
    else
        text = this.getParamByLevel(id, level, 'name');
   
    if(text !== undefined && text !== "")
        return text;
    else
        return skill.name;
};

/**
* Returns MP Cost for a specified level
*
* @static
* @method getMpCost
*/
SkillManager.getMpCost = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.mpCost;

    var cost = undefined;
    if(level === undefined)
        cost = this.getDefault(id, 'mpCost');
    else
        cost = this.getParamByLevel(id, level, 'mpCost');
   
    if(cost !== undefined && cost >= 0)
        return cost;
    else
        return skill.mpCost;
};

/**
* Returns TP Cost for a specified level
*
* @static
* @method getTpCost
*/
SkillManager.getTpCost = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.tpCost;

    var cost = undefined;
    if(level === undefined)
        cost = this.getDefault(id, 'tpCost');
    else
        cost = this.getParamByLevel(id, level, 'tpCost');
   
    if(cost !== undefined && cost >= 0)
        return cost;
    else
        return skill.tpCost;
};

/**
* Returns TP Gain for a specified level
*
* @static
* @method getTpGain
*/
SkillManager.getTpGain = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.tpGain;

    var cost = undefined;
    if(level === undefined)
        cost = this.getDefault(id, 'tpGain');
    else
        cost = this.getParamByLevel(id, level, 'tpGain');
   
    if(cost !== undefined && cost >= 0)
        return cost;
    else
        return skill.tpGain;
};

/**
*
* @static
* @method getScope
*/
SkillManager.getScope = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.scope;

    var scope = undefined;
    if(level === undefined)
        scope = this.getDefault(id, 'scope');
    else
        scope = this.getParamByLevel(id, level, 'scope');

    if(scope !== undefined && scope >= 0)
        return scope;
    else
        return skill.scope;
};

/**
* Returns skill description for a specified level
*
* @static
* @method getDescription
*/
SkillManager.getDescription = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.description;

    var text = undefined;
    if(level === undefined)
        text = this.getDefault(id, 'description');
    else
        text = this.getParamByLevel(id, level, 'description');
   
    if(text !== undefined && text !== "")
        return text;
    else
        return skill.description;
};

/**
* Returns skill damage formula for a specified level
*
* @static
* @method getDamageFormula
*/
SkillManager.getDamageFormula = function(skill, level){
    var id = this.getSkillId(skill);
    if(id === undefined) return skill.damage.formula;

    var formula = undefined;
    if(level === undefined)
        formula = this.getDefault(id, 'damage');
    else
        formula = this.getParamByLevel(id, level, 'damage');
   
    if(formula !== undefined && formula !== "")
        return formula;
    else
        return skill.damage.formula;
};

/**
* Auxiliary function used to get special params from skill by level
*
* @static
* @method getCodeData
*/
SkillManager.getCodeData = function(skill, subject, level, type){
    var code = undefined;
    var a = subject;
    var id = this.getSkillId(skill);
    if(level === undefined)
        level = TAA.skm.Parameters.MinLevel;
    if(id === undefined) return code;
    if(a._skillMastery[id] === undefined && type !== 'requirements') return code;

    code = this.getParamByLevel(id, level, type);
    return code;
};

/**
* Checks if skill requirements are met for a specified skill and level
*
* @static
* @method requirementsMet
*/
SkillManager.requirementsMet = function(skill, level, subject){
    var code = undefined;
    var a = subject;
    var id = this.getSkillId(skill);
   
    code = this.getCodeData(skill, subject, level, 'requirements');
    if(code === undefined || code === "")
        return true;
   
    try{
        var evalCode = eval(code);
        return evalCode;
    }
    catch(e){
        return true;
    }
};

/**
* Return skill modifiers, like damage modifiers and custom effects
*
* @static
* @method getModifiers
*/
SkillManager.getModifiers = function(skill, subject, type){
    var id = this.getSkillId(skill);
    if(id === undefined || subject._skillMastery[id] === undefined) return "";

    var level = (TAA.skm.Parameters.AllowLevelSelect && !isNaN(subject._skillMastery[id].actingLevel)) ? subject._skillMastery[id].actingLevel : subject._skillMastery[id].level;
    var code = this.getCodeData(skill, subject, level, type);
    return code || "";
};

/**
* Returns a skill ID
*
* @static
* @method getSkillId
*/
SkillManager.getSkillId = function(skill){
    if(skill === undefined) return undefined;
    return skill.id;
};

/**
* Returns skill parameters set in the default object
*
* @static
* @method getDefault
*/
SkillManager.getDefault = function(id, option){
    if($dataSkillLevels[id] === undefined) return undefined;
    if($dataSkillLevels[id][this._defaultDataObject] === undefined) return undefined;
    switch(option){
        case "name":
            return $dataSkillLevels[id][this._defaultDataObject][this._nameObject];
            break;
        case "mpCost":
            return $dataSkillLevels[id][this._defaultDataObject][this._mpCostObject];
            break;
        case "tpCost":
            return $dataSkillLevels[id][this._defaultDataObject][this._tpCostObject];
            break;
        case "tpGain":
            return $dataSkillLevels[id][this._defaultDataObject][this._tpGainObject];
            break;
        case "scope":
            return $dataSkillLevels[id][this._defaultDataObject][this._scopeObject];
            break;
        case "description":
            return $dataSkillLevels[id][this._defaultDataObject][this._descriptionObject];
            break;
        case "requirements":
            return $dataSkillLevels[id][this._defaultDataObject][this._reqObject];
            break;
        case "customEffects":
            return $dataSkillLevels[id][this._defaultDataObject][this._customEffectsObject];
            break;
        case "damageModifiers":
            return $dataSkillLevels[id][this._defaultDataObject][this._damageModifiersObject];
            break;
        case "damage":
            return $dataSkillLevels[id][this._defaultDataObject][this._damageFormulaObject];
        default:
            return undefined;
    }
};

/**
* Returns skill parameters by level
*
* @static
* @method getParamByLevel
*/
SkillManager.getParamByLevel = function(id, level, option){
    var skillData = $dataSkillLevels[id];
    if(skillData === undefined) return undefined;
    var cost;
    var text;
        
    if(skillData[this._levelArrayObject] === undefined || skillData[this._levelArrayObject].length === 0)
        return this.getDefault(id, option);
    switch(option){
        case 'name':
            text = this.getParamFromLevelArray(skillData, level, this._nameObject);
            if(text === undefined) text = this.getDefault(id, option);
            return text;
            break;
        case 'mpCost':
            if(skillData[this._formulaArrayObject] !== undefined && skillData[this._formulaArrayObject][this._mpCostObject] !== undefined){
                cost = this.getParamByFormula(skillData, level, this._mpCostObject);
                if(cost !== undefined) return cost;
            }

            cost = this.getParamFromLevelArray(skillData, level, this._mpCostObject);
            if(cost === undefined) cost = this.getDefault(id, option);
            return cost;
            break;
        case 'tpCost':
            if(skillData[this._formulaArrayObject] !== undefined && skillData[this._formulaArrayObject][this._tpCostObject] !== undefined){
                cost = this.getParamByFormula(skillData, level, this._tpCostObject);
                if(cost !== undefined) return cost;
            }

            cost = this.getParamFromLevelArray(skillData, level, this._tpCostObject);
            if(cost === undefined) cost = this.getDefault(id, option);
            return cost;
            break;
        case 'tpGain':
            if(skillData[this._formulaArrayObject] !== undefined && skillData[this._formulaArrayObject][this._tpGainObject] !== undefined){
                cost = this.getParamByFormula(skillData, level, this._tpGainObject);
                if(cost !== undefined) return cost;
            }

            cost = this.getParamFromLevelArray(skillData, level, this._tpGainObject);
            if(cost === undefined) cost = this.getDefault(id, option);
            return cost;
            break;
        case 'scope':
            var scope = this.getParamFromLevelArray(skillData, level, this._scopeObject);
            if(scope === undefined) scope = this.getDefault(id, option);
            return scope;
            break;
        case 'description':
            text = this.getParamFromLevelArray(skillData, level, this._descriptionObject);
            if(text === undefined) text = this.getDefault(id, option);
            return text;
            break;
        case 'requirements':
            var count = TAA.skm.Parameters.MinLevel;
            var tmp;
            text = "";
            while(count <= level){
                tmp = undefined;
                tmp = this.getParamFromLevelArray(skillData, count, this._reqObject);
                if(tmp !== undefined && tmp !== ""){
                    if(text !== undefined && text !== "") text += " && ";
                    text += tmp;
                }
                count++;
            }
            tmp = undefined;
            tmp = this.getDefault(id, option);
            if(tmp !== undefined && tmp !== ""){
                if(text !== "") text += " && ";
                text += tmp;
            }
            if(text === undefined || text === "") text = true;
            return text;
            break;
        case 'customEffects':
            text = this.getParamFromLevelArray(skillData, level, this._customEffectsObject);
            if(text === undefined) text = this.getDefault(id, option);
            return text;
            break;
        case 'damageModifiers':
            text = this.getParamFromLevelArray(skillData, level, this._damageModifiersObject);
            if(text === undefined) text = this.getDefault(id, option);
            return text;
            break;
        case "damage":
            text = this.getParamFromLevelArray(skillData, level, this._damageFormulaObject);
            if(text === undefined) text = this.getDefault(id, option);
            return text;
            break;
        default:
            return this.getDefault(skillData, object);
    }
};

/**
* Returns skill parameters defined through formulas
*
* @static
* @method getParamByFormula
*/
SkillManager.getParamByFormula = function(skillData, level, param){
    if(skillData[this._formulaArrayObject][param] === undefined) return undefined;

    var expression = skillData[this._formulaArrayObject][param].replace(/level/g, level);
    return eval(expression);
};

/**
* Returns skill XP formula
*
* @static
* @method getXpFormula
*/
SkillManager.getXpFormula = function(skillData){
    if(skillData === undefined || skillData[this._formulaArrayObject] == undefined || skillData[this._formulaArrayObject].length <= 0 || skillData[this._formulaArrayObject][this._xpFormulaObject] === undefined)
        return TAA.skm.Parameters.XPFormula;
    return skillData[this._formulaArrayObject][this._xpFormulaObject];
};

/**
* Returns skill parameter from level array
*
* @static
* @method getParamFromLevelArray
*/
SkillManager.getParamFromLevelArray = function(skillData, level, param){
    var i = 0;
    var result = undefined;
    while(i < skillData[this._levelArrayObject].length && i <= level){
        if(skillData[this._levelArrayObject] !== undefined && skillData[this._levelArrayObject] !== null && Object.keys(skillData[this._levelArrayObject]).length > 0 && skillData[this._levelArrayObject][param] !== undefined)
            result = skillData[this._levelArrayObject][param];
        i++;
    }
    return result;
};

/**
* Returns default mastery object for a skill
*
* @static
* @method getDefaultMasteryObject
*/
SkillManager.getDefaultMasteryObject = function(skillId){
    var obj = {};
    obj.level = TAA.skm.Parameters.MinLevel;
    obj.actingLevel = null;
    obj.xp = 0;
    obj.uses = 0;
    obj.timesUsed = 0;
    if($dataSkillLevels[skillId] === undefined || $dataSkillLevels[skillId][this._xpTypeObject] === undefined)
        obj.xpType = 1;
    else
        obj.xpType = $dataSkillLevels[skillId][this._xpTypeObject];
    return obj;
};

/**
* Increases Skill Mastery by the specified amount
*
* @static
* @method increaseSkillMastery
*/
SkillManager.increaseSkillMastery = function(skillId, masteryObj, xp){
    if(masteryObj.level === TAA.skm.Parameters.MaxLevel || TAA.skm.Parameters.Unleveled.contains(skillId))
        return masteryObj.level;

    var skillData = $dataSkillLevels[skillId];
    var level = masteryObj.level;
    xp += masteryObj.xp;

    var txtFormula = this.getXpFormula(skillData);
    var xpFormula = txtFormula.replace(/level/g, level);
    while(eval(xpFormula) <= xp && level < TAA.skm.Parameters.MaxLevel){
        level++;
        xpFormula = txtFormula.replace(/level/g, level);
    }
    if(level > TAA.skm.Parameters.MaxLevel)
        level = TAA.skm.Parameters.MaxLevel;
    return level;
};

/**
* Forces skill to the specified value
*
* @static
* @method setSkillLevel
*/
SkillManager.setSkillLevel = function(skillId, masteryObj, level){
    if(level > TAA.skm.Parameters.MaxLevel)
        masteryObj.level = TAA.skm.Parameters.MaxLevel;
    else if(level < TAA.skm.Parameters.MinLevel)
        masteryObj.level = TAA.skm.Parameters.MinLevel;
    else
        masteryObj.level = level;
        
    return masteryObj;
};

/**
* Increases skill level
*
* @static
* @method increaseSkillLevel
*/
SkillManager.increaseSkillLevel = function(skillId, masteryObj, level){
    if(skillId && TAA.skm.Parameters.Unleveled.contains(skillId)) return masteryObj;
    var currentLvl = masteryObj.level;
    var newLvl = Math.max(TAA.skm.Parameters.MinLevel, Math.min(currentLvl + level, TAA.skm.Parameters.MaxLevel));

    if(currentLvl !== newLvl)
        masteryObj.level = newLvl;
        
    return masteryObj;
};

/**
* Decreases skill level
*
* @static
* @method decreaseSkillLevel
*/
SkillManager.decreaseSkillLevel = function(skillId, masteryObj, level){
    if(TAA.skm.Parameters.Unleveled.contains(skillId)) return masteryObj;
    var currentLvl = masteryObj.level;
    var newLvl = Math.max(TAA.skm.Parameters.MinLevel, Math.min(currentLvl - level, TAA.skm.Parameters.MaxLevel));

    if(currentLvl !== newLvl)
        masteryObj.level = newLvl;
        
    return masteryObj;
};

/**
* Returns how much XP is required to reach the next level
*
* @static
* @method getXpForLevel
*/
SkillManager.getXpForLevel = function(skillId, level){
    var skillData = $dataSkillLevels[skillId];
    var xpFormula = this.getXpFormula(skillData).replace(/level/g, level);
    return eval(xpFormula);
};

//=============================================================================
// BattleManager
//=============================================================================

BattleManager.skillLevelUpMsg = function(text){
    this._logWindow.addText(text);
};

TAA.skm.alias.BattleManager = TAA.skm.alias.BattleManager || {};
TAA.skm.alias.BattleManager.gainRewards = BattleManager.gainRewards;
BattleManager.gainRewards = function(){
    TAA.skm.alias.BattleManager.gainRewards.call(this);
    this.gainSkillMastery();
};

BattleManager.gainSkillMastery = function(){
    $gameParty.battleMembers().forEach(function(actor){
        var isAlive = actor.isAlive();
        for(var i=0; i < actor.skills().length; i++){
            var skillId = actor.skills().id;
            if(actor._skillMastery[skillId] === null || actor._skillMastery[skillId] === undefined){
                actor.skillLevel(skillId);
            }
            switch(actor._skillMastery[skillId].xpType){
                case 3:
                    if(!isAlive) continue;
                case 2:
                    actor.gainSkillXp(skillId, 1);
                    break;
                default:
                    continue;
            }
        }
    });
};

//=============================================================================
// Game_System
//=============================================================================

Game_System.prototype.getSkillName = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getName($dataSkills[skillId], level);
};

Game_System.prototype.getSkillMpCost = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getMpCost($dataSkills[skillId], level);
};

Game_System.prototype.getSkillTpCost = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getTpCost($dataSkills[skillId], level);
};

Game_System.prototype.getSkillTpGain = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getTpGain($dataSkills[skillId], level);
};

Game_System.prototype.getSkillDescription = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getDescription($dataSkills[skillId], level);
};

Game_System.prototype.getDamageFormula = function(skillId, level){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    return SkillManager.getDamageFormula($dataSkills[skillId], level);
};

Game_System.prototype.actorMeetsRequirements = function(skillId, level, actorId){
    if(level === undefined || level < TAA.skm.Parameters.MinLevel)
        level = TAA.skm.Parameters.MinLevel;
   
    var subject = $gameActors.actor(actorId);
    return SkillManager.requirementsMet($dataSkills[skillId], level, subject);
};

Game_System.prototype.getSkillXpType = function(skillId){
    if($dataSkillLevels[skillId] === undefined) return 1;
    var type = $dataSkillLevels[skillId][SkillManager._xpTypeObject] || 1;
    return type;
};

Game_System.prototype.getSkillLevel = function(skillId, actorId){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return 0;
    return subject.getSkillLevel(skillId);
};

Game_System.prototype.learnSkill = function(actorId, skillId, customLevel, customXp){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return false;
    return subject.learnSkill(skillId, customXp, customLevel);
};

Game_System.prototype.gainSkillXp = function(actorId, skillId, xp){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return false;
    subject.gainSkillXp(skillId, xp);
};

Game_System.prototype.getSkillProgression = function(actorId, skillId){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return false;
    return subject.skillProgression(skillId);
};

Game_System.prototype.isSkillKnown = function(actorId, skillId){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return false;
    return subject.isSkillKnown(skillId);
};

Game_System.prototype.hasSkill = function(actorId, skillId, skillLevel){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return false;
    return subject.hasSkill(skillId, skillLevel);
};

Game_System.prototype.getCurrentSkillXp = function(actorId, skillId){
    var subject = $gameActors.actor(actorId);
    var skill = $dataSkills[skillId];
    var skm = subject._skillMastery[skillId];
    if(skm === undefined) return 0;
    return skm.xp;
};

Game_System.prototype.getSkillXpToNextLevel = function(actorId, skillId){
    var subject = $gameActors.actor(actorId);
    var skill = $dataSkills[skillId];
    var skm = subject._skillMastery[skillId];
    if(skm === undefined) return 0;
    var requiredXp = SkillManager.getXpForLevel(skillId, skm.level);
    if(requiredXp === undefined || requiredXp === 0) return 0;
    return requiredXp - skm.xp;
};

Game_System.prototype.getSkillUses = function(actorId, skillId){
    var subject = $gameActors.actor(actorId);
    var skill = $dataSkills[skillId];
    var skm = subject._skillMastery[skillId];
    if(skm === undefined) return 0;
    return skm.timesUsed;
};

Game_System.prototype.gainSkillXp = function(actorId, skillId, xp){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return;
    return subject.gainSkillXp(skillId, xp);
};

Game_System.prototype.setSkillLevel = function(actorId, skillId, level){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return;
    if(level === undefined || level < TAA.skm.Parameters.MinLevel) return;
    subject.setSkillLevel(skillId, level);
};

Game_System.prototype.increaseSkillLevel = function(actorId, skillId, level){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return;
    if(level === undefined || level < TAA.skm.Parameters.MinLevel) return;
    subject.increaseSkillLevel(skillId, level);
};

Game_System.prototype.decreaseSkillLevel = function(actorId, skillId, level){
    var subject = $gameActors.actor(actorId);
    if(subject === undefined) return;
    if(level === undefined || level < TAA.skm.Parameters.MinLevel) return;
    subject.decreaseSkillLevel(skillId, level);
};

//=============================================================================
// Game_Interpreter
//=============================================================================

TAA.skm.alias.Game_Interpreter = TAA.skm.alias.Game_Interpreter || {};
TAA.skm.alias.Game_Interpreter.pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args){
    TAA.skm.alias.Game_Interpreter.pluginCommand.call(this, command, args);
    if(command.toLowerCase() === 'skm'){
        if(args[0].toLowerCase() === 'learnskill'){
            var actor = (!isNaN(args[1])) ? parseInt(args[1]) : undefined;
            if(actor === undefined) return;
            var skill = (!isNaN(args[2])) ? parseInt(args[2]) : undefined;
            if(skill === undefined) return;
            var level = (!isNaN(args[3])) ? parseInt(args[3]) : undefined;
            var xp = (!isNaN(args[4])) ? parseInt(args[4]) : undefined;
            $gameSystem.learnSkill(actor, skill, level, xp);
        }
        else if(args[0].toLowerCase() === 'learnmultiskill'){
            var size = args.length;
            var actor = (!isNaN(args[1])) ? parseInt(args[1]) : undefined;
            if(actor === undefined) return;
            var i = 2;
            while(i < size){
                var skill = (!isNaN(args)) ? parseInt(args) : undefined;
                if(skill !== undefined) $gameSystem.learnSkill(actor, skill);
                i++;
            }
        }
        else if(args[0].toLowerCase() === 'gainxp'){
            var actor = (!isNaN(args[1])) ? parseInt(args[1]) : undefined;
            if(actor === undefined) return;
            var skill = (!isNaN(args[2])) ? parseInt(args[2]) : undefined;
            if(skill === undefined) return;
            var xp = (!isNaN(args[3])) ? parseInt(args[3]) : undefined;
            if(xp === undefined || xp <= 0) return;
            $gameSystem.gainSkillXp(actor, skill, xp);
        }
        else if(agrs[0].toLowerCase() === 'setlevel'){
            var actor = (!isNaN(args[1])) ? parseInt(args[1]) : undefined;
            if(actor === undefined) return;
            var skill = (!isNaN(args[2])) ? parseInt(args[2]) : undefined;
            if(skill === undefined) return;
            var level = (!isNaN(args[3])) ? parseInt(args[3]) : undefined;
            $gameSystem.setSkillLevel(actor, skill, level);
        }
    }
};

//=============================================================================
// Plugin Commands (MZ)
//=============================================================================

if(Utils.RPGMAKER_NAME === 'MZ'){
    PluginManager.registerCommand(TAA.skm.PluginName, 'learnSkill', args => {
        const actor = parseInt(args.actor);
        const skill = parseInt(args.skill);
        if(isNaN(actor) || isNaN(skill)) return;

        var level = parseInt(args.level);
        var xp = parseInt(args.xp);
        if(isNaN(level) || level < TAA.skm.Parameters.MinLevel) level = TAA.skm.Parameters.MinLevel;
        else if(level > TAA.skm.Parameters.MaxLevel) level = TAA.skm.Parameters.MaxLevel;
        if(isNaN(xp) || xp < 0) xp = 0;

        $gameSystem.learnSkill(actor, skill, level, xp);
    });

    PluginManager.registerCommand(TAA.skm.PluginName, 'learnMultiSkill', args => {
        const actor = parseInt(args.actor);
        var skillList = (args.skillList) ? JSON.parse(args.skillList) : [];
        if(skillList.length <= 0 || isNaN(actor)) return;
        for(var i=0; i < skillList.length; i++){
            var skill = parseInt(skillList);
            if(!isNaN(skill)) $gameSystem.learnSkill(actor, skill);
        }
    });

    PluginManager.registerCommand(TAA.skm.PluginName, 'gainXp', args => {
        const actor = parseInt(args.actor);
        const skill = parseInt(args.skill);
        if(isNaN(actor) || isNaN(skill)) return;

        var xp = !isNaN(args.xpVar) && args.xpVar > 0 ? $gameVariables.value(args.xpVar) : parseInt(args.xp);
        if(isNaN(xp) || xp <= 0) return;
        
        $gameSystem.gainSkillXp(actor, skill, xp);
    });

    PluginManager.registerCommand(TAA.skm.PluginName, 'changeLevel', args => {
        const actor = parseInt(args.actor);
        const skill = parseInt(args.skill);
        const operation = args.operation;
        if(isNaN(actor) || isNaN(skill) || !['=', '+', '-'].contains(operation)) return;
        
        var level = !isNaN(args.valueVar) && args.valueVar > 0 ? $gameVariables.value(args.valueVar) : parseInt(args.value);
        switch(operation){
            case '=':
                $gameSystem.setSkillLevel(actor, skill, level);
                break;
            case '+':
                $gameSystem.increaseSkillLevel(actor, skill, level);
                break;
            case '-':
                $gameSystem.decreaseSkillLevel(actor, skill, level);
                break;
        }
    });
}

//=============================================================================
// Game_BattlerBase
//=============================================================================

TAA.skm.alias.GameBattlerBase = TAA.skm.alias.GameBattlerBase || {};
TAA.skm.alias.GameBattlerBase.initMembers = Game_BattlerBase.prototype.initMembers;
Game_BattlerBase.prototype.initMembers = function(){
    TAA.skm.alias.GameBattlerBase.initMembers.call(this);
    this._skillMastery = [];
    this._skillUses = [];
};

Game_BattlerBase.prototype.setSkillActingLevel = function(skillId, level){
    if(this._skillMastery === undefined) this._skillMastery = [];
    if(!this.isSkillKnown(skillId)) {
        this._skillMastery[skillId] = SkillManager.getDefaultMasteryObject(skillId);
    }
    this._skillMastery[skillId].actingLevel = level;
};

Game_BattlerBase.prototype.clearSkillActingLevel = function(skillId){
    if(this._skillMastery !== undefined && this._skillMastery[skillId] !== undefined){
        this._skillMastery[skillId].actingLevel = null;
    }
};

Game_BattlerBase.prototype.getSkillLevel = function(skillId){
    if(!this.isSkillKnown(skillId))
        return -1;
    else
        return this._skillMastery[skillId].level;
};

Game_BattlerBase.prototype.getSkillActingLevel = function(skillId){
    if(!this.isSkillKnown(skillId))
        return -1;
    else
        return (TAA.skm.Parameters.AllowLevelSelect && !isNaN(this._skillMastery[skillId].actingLevel)) ? this._skillMastery[skillId].actingLevel : this._skillMastery[skillId].level;
};

Game_BattlerBase.prototype.skillLevel = function(skillId){
    if(this._skillMastery === undefined) this._skillMastery = [];
    if(!this.isSkillKnown(skillId)) {
        this._skillMastery[skillId] = SkillManager.getDefaultMasteryObject(skillId);
    }
    return (TAA.skm.Parameters.AllowLevelSelect && this._skillMastery[skillId].actingLevel !== null && !isNaN(this._skillMastery[skillId].actingLevel)) ? this._skillMastery[skillId].actingLevel.clamp(TAA.skm.Parameters.MinLevel, TAA.skm.Parameters.MaxLevel) : this._skillMastery[skillId].level;
};

Game_BattlerBase.prototype.learnSkill = function(skillId, customXp, customLevel){
    if(skillId === undefined || skillId <= 0) return false;
    var level = TAA.skm.Parameters.MinLevel;
    if(customLevel !== undefined)
        level = customLevel;
   
    if(!$dataSkills[skillId].requirement(level, this))
        return false;
   
    this.setSkillLevel(skillId, level);
    if(customXp === undefined || isNaN(customXp) || customXp <= 0)
        return true;
    return this.gainSkillXp(skillId, customXp);
};

Game_BattlerBase.prototype.gainSkillXp = function(skillId, xp){
    if(xp === undefined || isNaN(xp) || xp < 0 || skillId === undefined || skillId <= 0 ||TAA.skm.Parameters.Unleveled.contains(skillId))
        return false;
   
    var level;
    if(this.isSkillKnown(skillId))
        level = Math.min(this._skillMastery[skillId].level, TAA.skm.Parameters.MaxLevel);
    else
        return false;

    if(!$dataSkills[skillId].requirement(level, this))
        return false;
   
    var level = SkillManager.increaseSkillMastery(skillId, this._skillMastery[skillId], xp);
    if(level === undefined) return false;
    if(this._skillMastery[skillId].level < level){
        this._skillMastery[skillId].level = level;
        this._skillMastery[skillId].xp = 0;
    }
    else   
        this._skillMastery[skillId].xp += xp;
    this._skillMastery[skillId].uses = 0;
    return true;
};

Game_BattlerBase.prototype.increaseSkillUseCount = function(skillId, timesUsed){
    this._skillMastery[skillId].timesUsed += timesUsed;
    if(this.isEnemy() && TAA.skm.Parameters.EnemyLvlUp === false){
        // If enemy level up skill is disabled, prevent the counter from being increased
        return false;
    }
    else if(this.isActor() && TAA.skm.Parameters.LockTraitSkills && !this.isLearnedSkill(skillId)){
        // If trait skills are locked, prevent the counter from being increased unless the
        // actor actually knows the skill
        return false;
    }
    if(this._skillMastery[skillId].xpType !== undefined && this._skillMastery[skillId].xpType === 1 && !TAA.skm.Parameters.Unleveled.contains(skillId)){
        return this.gainSkillXp(skillId, timesUsed);
    }
    else
        return true;
};

Game_BattlerBase.prototype.setSkillLevel = function(skillId, level){
    if(!this.isSkillKnown(skillId))
        this.skillLevel(skillId);
    this._skillMastery[skillId] = SkillManager.setSkillLevel(skillId, this._skillMastery[skillId], level);
};

Game_BattlerBase.prototype.increaseSkillLevel = function(skillId, level){
    if(!this.isSkillKnown(skillId))
        this.skillLevel(skillId);
    this._skillMastery[skillId] = SkillManager.increaseSkillLevel(skillId, this._skillMastery[skillId], level);
};

Game_BattlerBase.prototype.decreaseSkillLevel = function(skillId, level){
    if(!this.isSkillKnown(skillId))
        this.skillLevel(skillId);
    this._skillMastery[skillId] = SkillManager.decreaseSkillLevel(skillId, this._skillMastery[skillId], level);
};

Game_BattlerBase.prototype.setSkillXp = function(skillId, xp){
    if(TAA.skm.Parameters.Unleveled.contains(skillId)) return;
    var level = this.getSkillLevel(skillId);
    if(level < 0) return;
    var formula = SkillManager.getXpFormula($dataSkillLevels[skillId]);
    if(!SkillManager.requirementsMet($dataSkills[skillId], level, this)){
        this._skillMastery[skillId].xp = 0;
    }
    else{
        // Ensures xp is always set below the threshold for the next level
        if(formula && xp >= eval(formula)){
            xp = eval(formula + "-1");
        }
        this._skillMastery[skillId].xp = xp;
    }
};

Game_BattlerBase.prototype.skillProgression = function(skillId){
    if(!this.isSkillKnown(skillId)) return 0;
    if(this.isMaxLevelSkill(skillId)) return 1;
    var requiredXp = SkillManager.getXpForLevel(skillId, this._skillMastery[skillId].level);
    if(requiredXp === 0) return 1;
    var prog = this._skillMastery[skillId].xp / requiredXp;
    prog = (prog > 1) ? 1 : prog;
    return Math.min(prog, 1);
};

Game_BattlerBase.prototype.isMaxLevelSkill = function(skillId){
    if(!this.isSkillKnown(skillId))
        return false;
    return this._skillMastery[skillId].level === TAA.skm.Parameters.MaxLevel;
};

Game_BattlerBase.prototype.isSkillKnown = function(skillId){
    if(this._skillMastery[skillId] === undefined || this._skillMastery[skillId] === null)
        return false;
    return true;
};

TAA.skm.alias.GameBattlerBase.skillMpCost = Game_BattlerBase.prototype.skillMpCost;
Game_BattlerBase.prototype.skillMpCost = function(skill){
    if(skill.leveledMpCost === undefined)
        return TAA.skm.alias.GameBattlerBase.skillMpCost.call(this, skill);
    if(!this.isSkillKnown(skill.id))
        this.skillLevel(skill.id);

    let level = (TAA.skm.Parameters.AllowLevelSelect && this._skillMastery[skill.id].actingLevel !== null && !isNaN(this._skillMastery[skill.id].actingLevel)) ? this._skillMastery[skill.id].actingLevel : this._skillMastery[skill.id].level;

    return skill.leveledMpCost(level);
};

TAA.skm.alias.GameBattlerBase.skillTpCost = Game_BattlerBase.prototype.skillTpCost;
Game_BattlerBase.prototype.skillTpCost = function(skill){
    if(skill.leveledTpCost === undefined)
        return TAA.skm.alias.GameBattlerBase.skillTpCost.call(this, skill);
    if(!this.isSkillKnown(skill.id))
        this.skillLevel(skill.id);

        let level = (TAA.skm.Parameters.AllowLevelSelect && this._skillMastery[skill.id].actingLevel !== null && !isNaN(this._skillMastery[skill.id].actingLevel)) ? this._skillMastery[skill.id].actingLevel : this._skillMastery[skill.id].level;
    return skill.leveledTpCost(level);
};

TAA.skm.alias.GameBattlerBase.paySkillCost = Game_BattlerBase.prototype.paySkillCost;
Game_BattlerBase.prototype.paySkillCost = function(skill){
    TAA.skm.alias.GameBattlerBase.paySkillCost.call(this, skill);
    if(!this.isSkillKnown(skill.id)) {
        this._skillMastery[skill.id] = SkillManager.getDefaultMasteryObject(skill.id);
    }
    if($gameParty.inBattle())
        this._skillMastery[skill.id].uses++;
        if(!this._skillUses.contains(skill.id))
            this._skillUses.push(skill.id);
};

Game_BattlerBase.prototype.parseSkillMasteryTags = function(notes){
    if(notes === undefined || notes.length <= 0) return;
   
    var regexArray = [
        /<TAA_SKM:\s*S\[(\d+)\][,]?\s+L\[(\d+\s*(?:,\s*\d+)?)\](?:,\s*X\[(\d+\s*(?:,\s*\d+)?)?\])?\s*>/i,
        /<TAA_SKM>/i,
        /<\/TAA_SKM>/i,
        /\s*S\[(\d+)\][,]?\s+L\[(\d+\s*(?:,\s*\d+)?)\](?:,\s*X\[(\d+\s*(?:,\s*\d+)?)?\])?\s*/i
    ];
    var insideTags = false;
    for(var i=0; i< notes.length; i++){
        var skillArray = [];
        var line = notes;
        if(line.match(regexArray[1])){
            insideTags = true;
        }
        else if(line.match(regexArray[2])){
            insideTags = false;
        }
        else if(insideTags && line.match(regexArray[3])){
            skillArray = this.extractSkillMasteryFromTags(line, RegExp);
        }
        else if(line.match(regexArray[0])){
            skillArray = this.extractSkillMasteryFromTags(line, RegExp);
        }
        
        if(skillArray.length > 0){
            this.setSkillLevel(skillArray[0], skillArray[1]);
            if(skillArray[2] > 0){
                this.setSkillXp(skillArray[0], skillArray[2]);
            }
        }
    }
};

Game_BattlerBase.prototype.extractSkillMasteryFromTags = function(line, exp){
    var result = [];
    var lvl = TAA.skm.Parameters.MinLevel;
    var xp = 0;
    var skillId = exp.$1;
    var lvlStr = exp.$2;
    var xpStr = exp.$3;
    if(lvlStr.match(/^(\d+)\s*,\s*(\d+)\s*$/i)){
        lvl = this.getRandomParamByRange(RegExp.$1, RegExp.$2, TAA.skm.Parameters.MinLevel, TAA.skm.Parameters.MaxLevel);
    }
    else lvl = Math.max(parseInt(lvlStr), TAA.skm.Parameters.MinLevel) <= TAA.skm.Parameters.MaxLevel ? Math.max(parseInt(lvlStr), TAA.skm.Parameters.MinLevel) : TAA.skm.Parameters.MaxLevel;

    if(xpStr.match(/^(\d+)\s*,\s*(\d+)\s*$/i)){
        xp = this.getRandomParamByRange(RegExp.$1, RegExp.$2, 0, SkillManager.getXpForLevel(parseInt(skillId), lvl));
    }
    else xp = parseInt(xpStr);

    result = [parseInt(skillId), lvl, xp];
    if(result[2] === undefined || isNaN(result[2])) result[2] = 0;
   
    return result;
};

Game_BattlerBase.prototype.getRandomParamByRange = function(lowerRange, upperRange, min, max){
    var a = Math.max(lowerRange, min) <= max ? Math.max(lowerRange, min) : max;
    var b = Math.min(upperRange, max) >= min ? Math.min(upperRange, max) : min;
    if(a <= b) return Math.floor(Math.random() * (b - a) + a);
    else return Math.floor(Math.random() * (a - b) + b);
};

Game_BattlerBase.prototype.canPaySkillCostForLevel = function(skill, level) {
    if(this._skillMastery[skill.id] === undefined)
        return this.canPaySkillCost(skill);

    let tpCost = skill.leveledTpCost(level);
    let mpCost = skill.leveledMpCost(level);
    return (this._tp >= tpCost && this._mp >= mpCost);
};

Game_BattlerBase.prototype.canPaySkillCostForAnyLevel = function(skill) {
    if(this._skillMastery[skill.id] === undefined)
        return this.canPaySkillCost(skill);
   
    let currentLevel = this._skillMastery[skill.id].level;
    for(var i = TAA.skm.Parameters.MinLevel; i<=currentLevel; i++){
        let tpCost = skill.leveledTpCost(i);
        let mpCost = skill.leveledMpCost(i);

        if(this._tp >= tpCost && this._mp >= mpCost) return true;
    }

    return false;
};

TAA.skm.alias.GameBattlerBase.meetsSkillConditions = Game_BattlerBase.prototype.meetsSkillConditions;
Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
    if(TAA.skm.Parameters.AllowLevelSelect !== true)
        return TAA.skm.alias.GameBattlerBase.meetsSkillConditions.call(this, skill);

    let generalConditions = (this.meetsUsableItemConditions(skill) &&
        this.isSkillWtypeOk(skill) && !this.isSkillSealed(skill.id) &&
        !this.isSkillTypeSealed(skill.stypeId));

    return generalConditions && this.canPaySkillCostForAnyLevel(skill);
};

Game_BattlerBase.prototype.meetsSkillConditionsForLevel = function(skill, level) {
    let generalConditions = (this.meetsUsableItemConditions(skill) &&
        this.isSkillWtypeOk(skill) && !this.isSkillSealed(skill.id) &&
        !this.isSkillTypeSealed(skill.stypeId));

    return generalConditions && this.canPaySkillCostForLevel(skill, level);
};

//=============================================================================
// Game_Battler
//=============================================================================

TAA.skm.alias.GameBattler = TAA.skm.alias.GameBattler || {};
TAA.skm.alias.GameBattler.onAllActionsEnd = Game_Battler.prototype.onAllActionsEnd;
Game_Battler.prototype.onAllActionsEnd = function(){
    TAA.skm.alias.GameBattler.onAllActionsEnd.call(this);
    this.processSkillUses();
};

Game_Battler.prototype.processSkillUses = function(){
    for(var i=0; i < this._skillUses.length; i++){
        var id = this._skillUses;
        var previousLevel = this._skillMastery[id].level;

        if(this.increaseSkillUseCount(id, this._skillMastery[id].uses)){
            var newLevel = this._skillMastery[id].level;
            if(newLevel > previousLevel){
                var playAnim = false;
                var mirror = false;
                switch(TAA.skm.Parameters.LvlUpAnimConfig){
                    case "Actors Only":
                        if(this.isActor())
                            playAnim = true;
                        break;
                    case "Enemies Only":
                        if(this.isEnemy()){
                            playAnim = true;
                            mirror = true;
                        }
                        break;
                    case "Always":
                        playAnim = true;
                        break;
                    default:
                        playAnim = false;
                }
                // show text on level up?
                if(TAA.skm.Parameters.LvlUpMsg !== "" && (this.isActor() || (this.isEnemy() && TAA.skm.Parameters.EnemyLvlUpMsg))){
                    var text = this.prepareSkillLvlUpText(id);
                    BattleManager.skillLevelUpMsg(text);
                }
                if(playAnim && TAA.skm.Parameters.LvlUpAnimation > 0){
                    let anim = TAA.skm.Parameters.LvlUpAnimation;
                    if(this.isMaxLevelSkill(id) && TAA.skm.Parameters.MaxLvMsgEnabled && TAA.skm.Parameters.MaxLvAnimation > 0)
                        anim = TAA.skm.Parameters.MaxLvAnimation;
                    if(Utils.RPGMAKER_NAME === 'MZ')
                        $gameTemp.requestAnimation([this], anim, mirror);
                    else
                        this.startAnimation(anim, mirror);
                }
            }
        }
        if(this._skillMastery[id].uses > 0) this._skillMastery[id].uses = 0;
    }
    this.resetSkillUseCounter();
};

Game_Battler.prototype.prepareSkillLvlUpText = function(skillId){
    if(skillId === undefined || skillId <= 0 || $dataSkills[skillId] === undefined) return "";

    var msg = TAA.skm.Parameters.LvlUpMsg;
    if(this.isMaxLevelSkill(skillId) && TAA.skm.Parameters.MaxLvMsgEnabled && TAA.skm.Parameters.MaxLvMsg !== "" && this.isActor())
        msg = TAA.skm.Parameters.MaxLvMsg;

    var text = msg.replace(/%1/g, $dataSkills[skillId].name);
    text = text.replace(/%2/g, this.name());
    return text || "";
};

Game_Battler.prototype.resetSkillUseCounter = function(){
    this._skillUses = [];
};


//=============================================================================
// Game_Actor
//=============================================================================

TAA.skm.alias.GameActor = TAA.skm.alias.GameActor || {};
TAA.skm.alias.GameActor.setup = Game_Actor.prototype.setup;
Game_Actor.prototype.setup = function(actorId){
    TAA.skm.alias.GameActor.setup.call(this, actorId);
    this.initStartingSkills();
};

Game_Actor.prototype.initStartingSkills = function(){
    var notes = $dataActors[this._actorId].note.split(/[\r\n]+/);
    this.parseSkillMasteryTags(notes);
};

TAA.skm.alias.GameActor.learnSkill = Game_Actor.prototype.learnSkill;
Game_Actor.prototype.learnSkill = function(skillId, customXp, customLevel){
    Game_BattlerBase.prototype.learnSkill.call(this, skillId, customXp, customLevel);
    TAA.skm.alias.GameActor.learnSkill.call(this, skillId);
};

TAA.skm.alias.GameActor.hasSkill = Game_Actor.prototype.hasSkill;
Game_Actor.prototype.hasSkill = function(skillId, skillLevel){
    var hasSkill = TAA.skm.alias.GameActor.hasSkill.call(this, skillId);

    if((skillLevel === undefined && skillLevel < TAA.skm.Parameters.MinLevel) || hasSkill === false || isNaN(skillLevel))
        return hasSkill;

    if(this.skillLevel(skillId) >= skillLevel)
        return true;
    else
        return false;
};

//=============================================================================
// Game_Enemy
//=============================================================================

TAA.skm.alias.GameEnemy = TAA.skm.alias.GameEnemy || {};
TAA.skm.alias.GameEnemy.setup = Game_Enemy.prototype.setup;
Game_Enemy.prototype.setup = function(enemyId, x, y){
    TAA.skm.alias.GameEnemy.setup.call(this, enemyId, x, y);
    this.initStartingSkills();
};

Game_Enemy.prototype.initStartingSkills = function(){
    var notes = $dataEnemies[this._enemyId].note.split(/[\r\n]+/);
    this.parseSkillMasteryTags(notes);
};

TAA.skm.alias.GameEnemy.hasSkill = Game_Enemy.prototype.hasSkill;
Game_Enemy.prototype.hasSkill = function(skillId, skillLevel){
    var hasSkill = false;
    if(skillId === undefined || skillId <= 0) return false;
    for(var i=0; i < this._actions.length; i++){
        var item = this._actions._item;
        if(item !== undefined && item._dataClass === "skill" && item._itemId === skillId){
            hasSkill = true;
            break;
        }
    }
    if(hasSkill === true){
        return (this.skillLevel(skillId) >= skillLevel);
    }
    return false;
};

//=============================================================================
// Game_Action
//=============================================================================

TAA.skm.alias.GameAction = TAA.skm.alias.GameAction || {};
TAA.skm.alias.GameAction.initialize = Game_Action.prototype.initialize;
Game_Action.prototype.initialize = function(subject, forcing) {
    TAA.skm.alias.GameAction.initialize.call(this, subject, forcing);
    this._skmCriticalModifier = undefined;
    this._skmIsCritical = false;
};

TAA.skm.alias.GameAction.apply = Game_Action.prototype.apply;
Game_Action.prototype.apply = function(target){
    this.applySkillModifiers(0, true, target);
    TAA.skm.alias.GameAction.apply.call(this, target);
    this.applyCustomSkillEffects(target);
    this.clearModifiers();
};

TAA.skm.alias.GameAction.itemCri = Game_Action.prototype.itemCri;
Game_Action.prototype.itemCri = function(target){
    var result = TAA.skm.alias.GameAction.itemCri.call(this, target);
    switch(this._skmCriticalModifier){
        case 'force':
        case 'always':
        case 'enable':
        case '2':
            result = 1;
            break;
        case 'never':
        case 'disable':
        case '1':
            result = 0;
            break;
        default:
            // no action
    }
    return result;
};

TAA.skm.alias.GameAction.makeDamageValue = Game_Action.prototype.makeDamageValue;
Game_Action.prototype.makeDamageValue = function(target, critical){
    this._skmIsCritical = critical;
    var value = TAA.skm.alias.GameAction.makeDamageValue.call(this, target, critical);
    value = this.applySkillModifiers(value, undefined, target);
    return value;
};

TAA.skm.alias.GameAction.evalDamageFormula = Game_Action.prototype.evalDamageFormula;
Game_Action.prototype.evalDamageFormula = function(target){
    if(this.item().leveledDamage === undefined)
        return TAA.skm.alias.GameAction.evalDamageFormula.call(this, target);
    try{
        var item = this.item();
        var a = this.subject();
        var b = target;
        var v = $gameVariables._data;
        var sign = ([3, 4].contains(item.damage.type) ? -1 : 1);
        var value = Math.max(eval(item.leveledDamage(a.skillLevel(item.id))), 0) * sign;
        if(isNaN(value)) value = 0;
        return value;
    } catch(e) {
        return 0;
    }
};

TAA.skm.alias.GameAction.applyItemUserEffect = Game_Action.prototype.applyItemUserEffect;
Game_Action.prototype.applyItemUserEffect = function(target){
    var skill = this.item();
    if(skill.leveledTpGain === undefined || skill.id === undefined)
        TAA.skm.alias.GameAction.applyItemUserEffect.call(this, target);
    else{
        var level = this.subject().skillLevel(skill.id);
        var value = Math.floor(skill.leveledTpGain(level) * this.subject().tcr);
        this.subject().gainSilentTp(value);
    }
};

Game_Action.prototype.applyCustomSkillEffects = function(target){
    var skill = this.item();
    var mods = $dataSkills[skill.id].customEffects(this.subject());
    if(mods !== undefined && Array.isArray(mods) && mods.length > 0)
        this.processCustomEffects(mods, target);
};

Game_Action.prototype.applySkillModifiers = function(value, critical, target){
    var skill = this.item();
    var mods = $dataSkills[skill.id].damageMods(this.subject());
   
    if(mods !== undefined && Array.isArray(mods) && mods.length > 0){
        if(critical){
            return this.processDamageModifiers(0, mods, target);
        }
        value = this.processDamageModifiers(value, mods, target);
    }        

    return value;
};

Game_Action.prototype.processDamageModifiers = function(value, mods, target){
    var a = this.subject();
    var b = target;
    var skill = this.item();
    for(var i=0; i< mods.length; i++){
        if(mods.match(/CRITICAL:\s*(0|1|2|FORCE|ALWAYS|ENABLE|NEVER|DISABLE|NORMAL)/i)){
            this._skmCriticalModifier = String(RegExp.$1).toLowerCase();
            return value;
        }
        else if(mods.match(/DAMAGE MOD(?:IFIER)?:\s*([\*\+\-\/][0-9]+%|[\*\+\-\/][0-9]+|EVAL\s+.*)/i)){
            var m = String(RegExp.$1);
            var modString = "";
            if(m.match(/^EVAL\s+(.*)/i)){
                modString += String(RegExp.$1);
            }
            else if(m.match(/([\*\+\-\/])([0-9]+)(%)?/i)){
                modString += "value " + RegExp.$1 + " ";
                var modifier = parseInt(RegExp.$2);
                if(RegExp.$3 === '%'){
                    if(RegExp.$1 === '*' || RegExp.$1 === '/')
                        modifier /= 100;
                    else if(RegExp.$1 === '+' || RegExp.$1 === '-')
                        modifier = (modifier/100) * value;
                }
                modString += modifier;
            }

            if(modString !== ""){
                try{
                    value = eval(modString);
                }
                catch(e){
                    console.error("Failed to eval clause: '" + modString + "'");
                }
            }
        }
    }
    return value;
};

Game_Action.prototype.processCustomEffects = function(mods, target){
    var a = this.subject();
    var b = target;
    var skill = this.item();
    for(var i=0; i< mods.length; i++){
        if(mods.match(/(ON CRITICAL)?\s*(ADD|REMOVE) STATE:\s*([0-9]+|\".*\")\s*(USER|PARTY|TARGET[Ss]?|(?:DEAD|ALIVE)\s*(?:ALLIES|ENEMIES)|PARTY BUT USER|ENEMIES BUT TARGET)\s*([0-9]+|IF VAR(?:IABLE)? [0-9]+ (?:>|>=|<|<=|==|!=|<>) [0-9]+\s*(?:THEN [0-9]+)?|IF SW(?:ITCH)? [0-9]+ (?:true|false)\s*(?:THEN [0-9]+)?|EVAL: .*)?/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var operation = RegExp.$2;
            var state = isNaN(RegExp.$3) ? TAA.util.getStateIdByName(RegExp.$3) : parseInt(RegExp.$3);
            var affected = this.customEffectsTargets(RegExp.$4, target);
            var intensity = 1;
            if(RegExp.$5 !== undefined && RegExp.$5 !== ""){
                if(!isNaN(RegExp.$5)){
                    intensity = (parseInt(RegExp.$5)/100).toFixed(2);
                }
                else{
                    var conditional = RegExp.$5;
                    if(conditional.match(/IF VAR(?:IABLE)? ([0-9]+) (>|>=|<|<=|==|!=|<>) ([0-9]+)\s*(?:THEN ([0-9]+))?/i)){
                        var varId = RegExp.$1;
                        var op = RegExp.$2;
                        var value = RegExp.$3;
                        if(eval("$gameVariables.value(" + varId + ") " + op + " value")){
                            if(!isNaN(RegExp.$4) && RegExp.$4 !== "")
                                intensity = (parseInt(RegExp.$5)/100).toFixed(2);
                        }
                        else continue;
                    }
                    else if(conditional.match(/IF SW(?:ITCH)? ([0-9]+) (true|false)\s*(?:THEN ([0-9]+))?/i)){
                        var swId = RegExp.$1;
                        var value = RegExp.$2;
                        if(eval("$gameSwitches.value(" + swId + ") === value")){
                            if(!isNaN(RegExp.$3) && RegExp.$3 !== "")
                                intensity = (parseInt(RegExp.$3)/100).toFixed(2);
                        }
                        else continue;
                    }
                    else if(conditional.match(/EVAL: (.*)/i)){
                        if(RegExp.$1 !== undefined && RegExp.$1 !== ""){
                            var tmp = eval(RegExp.$1);
                            if(!isNaN(tmp) && tmp >= 0)
                                intensity = (parseInt(tmp)/100).toFixed(2);
                        }
                    }
                }
            }
            var effect = {"code":21,"dataId":state,"value1":intensity,"value2":0};
            if(affected !== undefined && affected.length > 0 && !isNaN(state) && state > 0){
                if(operation.toUpperCase() === 'ADD'){
                    for(var i=0; i < affected.length; i++){
                        if(affected.addState !== undefined)
                            this.itemEffectAddState(affected, effect);
                        else{
                            console.error("processCustomEffects: Failed to determine affected");
                            console.error(affected);
                        }
                    }
                }
                else if(operation.toUpperCase() === 'REMOVE'){
                    for(var i=0; i < affected.length; i++){
                        if(affected.removeState !== undefined)
                            affected.removeState(state);
                        else{
                            console.error("processCustomEffects: Failed to determine affected");
                            console.error(affected);
                        }
                    }
                }
            }
        }
        else if(mods.match(/(ON CRITICAL)?\s*SWITCH ([0-9]+|[0-9]+ \- [0-9]+|[0-9]+ to [0-9]+)\s*:\s*(on|off|true|false|toggle|switch [0-9]+)/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var sw = String(RegExp.$2);
            var operation = String(RegExp.$3);
            if(sw.match(/([0-9]+) (?:\-|to) ([0-9]+)/i)){
                var lowerRange = parseInt(RegExp.$1);
                var upperRange = parseInt(RegExp.$2);
                $gameSwitches.setValueOnRange(lowerRange, upperRange, operation);
            }
            else{
                var op = $gameSwitches.convertOperationToEval('sw', operation);
                try{
                    $gameSwitches.setValue(sw, eval(op));
                } catch(e){
                    console.error("Failed to eval sentence: " + op);
                }
            }
        }
        else if(mods.match(/(ON CRITICAL)?\s*SWITCH\s+([0-9]+|[0-9]+ \- [0-9]+|[0-9]+ to [0-9]+)\s*:\s*EVAL\s+(.*)/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var sw = String(RegExp.$2);
            var evalClause = eval(RegExp.$3);
            if(typeof evalClause !== "boolean"){
                if(isNaN(evalClause)){
                    continue;
                }
                else{
                    evalClause = evalClause > 0 ? true : false;
                }
            }
            if(sw.match(/([0-9]+) (?:\-|to) ([0-9]+)/i)){
                var lowerRange = parseInt(RegExp.$1);
                var upperRange = parseInt(RegExp.$2);
                $gameSwitches.setValueOnRange(lowerRange, upperRange, operation);
            }
            else{
                $gameSwitches.setValue(sw, evalClause);
            }
        }
        else if(mods.match(/(ON CRITICAL)?\s*(?:VAR|VARIABLE)\s+([0-9]+|[0-9]+ \- [0-9]+|[0-9]+ to [0-9]+)\s*(=|\+=|\-=|\*=|\/=|%=)\s*([0-9]+|v\[[0-9]+\])/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var vr = RegExp.$2;
            var operator = RegExp.$3;
            var value = RegExp.$4;
            if(vr.match(/([0-9]+) (?:\-|to) ([0-9]+)/i)){
                var lowerRange = RegExp.$1;
                var upperRange = RegExp.$2;
                $gameVariables.setValueOnRange(lowerRange, upperRange, operator, value);
            }
            else{
                var intValue = $gameVariables.getIdFromReference(value);
                $gameVariables.evalOperator(parseInt(vr), operator, intValue);
            }
        }
        else if(mods.match(/(ON CRITICAL)?\s*(?:VAR|VARIABLE)\s+([0-9]+|[0-9]+ \- [0-9]+|[0-9]+ to [0-9]+)\s*:\s*EVAL\s+(.*)/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var vr = String(RegExp.$2);
            var evalClause = eval(RegExp.$3);
            if(isNaN(evalClause)) evalClause = 0;
            if(vr.match(/([0-9]+) (?:\-|to) ([0-9]+)/i)){
                var lowerRange = RegExp.$1;
                var upperRange = RegExp.$2;
                $gameVariables.setValueOnRange(lowerRange, upperRange, "=", evalClause);
            }
            else{
                $gameVariables.evalOperator(parseInt(vr), "=", evalClause);
            }
        }
        else if(mods.match(/(ON CRITICAL)?\s*EVAL:\s*(.*)/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var evalStr = RegExp.$2;
            eval(evalStr);
        }
        else if(mods.match(/(ON CRITICAL)?\s*COMMON EVENT\s*:\s*([0-9]+)/i)){
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var event = RegExp.$2;
            $gameTemp.reserveCommonEvent(event);
            $gameTroop._interpreter.setupReservedCommonEvent();
        }
        else if(mods.match(/(ON CRITICAL)?\s*SUMMON: e\[(v?[0-9]+)(?:,\s*(v?[0-9]+))?\]\s*(?:,\s*r\[v?[0-9]{1,3}\]|,\s*lv\[(?:\+|\-|v)?[0-9]+%?(?:,\s*(?:\+|\-|v)?[0-9]+%?)?\])*/i)){
            if(TAA.enr === undefined || Object.keys(TAA.enr).length === 0 || a.isActor() || SceneManager._scene.addReinforcement === undefined) continue; // if TAA_EnemyReinforcements is not enabled, or subject is an actor, or is not battle scene
            if(RegExp.$1.toLowerCase() === "on critical" && !this._skmIsCritical)
                continue;
            var enemyId = RegExp.$2;
            var qtt = RegExp.$3;
            if(enemyId.match(/v([0-9]+)/i))
                enemyId = $gameVariables.value(RegExp.$1);
            else
                enemyId = parseInt(enemyId);
            if(qtt !== undefined && qtt.match(/v([0-9]+)/i))
                qtt = $gameVariables.value(RegExp.$1);
            else if(qtt !== '' && !isNaN(qtt))
                qtt = parseInt(qtt);
            if(isNaN(qtt) || qtt === '')
                qtt = 1;
            if(isNaN(enemyId) || enemyId < 1) continue;
            var r = 100;
            if(mods.match(/r\[(v?)([0-9]+)\]/i)){
                if(['v', 'V'].contains(RegExp.$1))
                    r = $gameVariables.value(RegExp.$2);
                else
                    r = parseInt(RegExp.$2);
            }
            var lowerLevel = 0;
            var upperLevel = 0;
            if(mods.match(/lv\[(\+|\-)?(v)?([0-9]+)(%)?(?:,\s*(\+|\-)?(v)?([0-9]+)(%)?)?\]/i)){
               
                var lowerSign = RegExp.$1;
                if(['v', 'V'].contains(RegExp.$2))
                    var lowerValue = $gameVariables.value(RegExp.$3);
                else
                    var lowerValue = parseInt(RegExp.$3);
                var lowerPercent = RegExp.$4;
                var upperSign = RegExp.$5;
                if(['v', 'V'].contains(RegExp.$6))
                    var upperValue = $gameVariables.value(RegExp.$7);
                else
                    var upperValue = parseInt(RegExp.$7);
                var upperPercent = RegExp.$8;
                var subjectLevel = a._level;
                if(!isNaN(lowerValue)){
                    if(lowerSign === '+' || lowerSign === '-'){
                        if(lowerPercent === '%')
                            lowerLevel = Math.max(1, Math.round(eval(subjectLevel + lowerSign + "(" + lowerValue + "/100)*" + subjectLevel)));
                        else
                            lowerLevel = Math.max(1, eval(subjectLevel + lowerSign + lowerValue));
                    }
                    else
                        lowerLevel = lowerValue;
                    if(!isNaN(upperValue)){
                        if(upperSign === '+' || upperSign === '-' ){
                            if(upperPercent === '%')
                                upperLevel = Math.max(lowerLevel, Math.round(eval(subjectLevel + upperSign + "(" + upperValue + "/100)*" + subjectLevel)));
                            else
                                upperLevel = Math.max(lowerLevel, eval(subjectLevel + upperSign + upperValue));
                        }
                        else
                            upperLevel = upperValue;
                    }
                }
            }
            var realCalls = $gameTroop.getAnsweredCalls();
            while(qtt > 0){
                if($gameTroop.availableReinforcementSlotsCount() > 0){
                    var randomValue = Math.random() * 100;
                    if( r >= randomValue){
                        SceneManager._scene.addReinforcement(enemyId, lowerLevel, upperLevel);
                        realCalls[enemyId] = realCalls[enemyId] || 0;
                        realCalls[enemyId]++;
                    }
                    qtt--;
                }
                else qtt = 0;
            }
            $gameTroop.saveAnsweredCalls(realCalls);
            if(Object.keys(realCalls).length <= 0) this.makeSuccess(target);
        }
    }
};

if(TAA.enr !== undefined && TAA.enr !== null){
    TAA.skm.alias.GameAction.processReinforcementCalls = Game_Action.prototype.processReinforcementCalls;
    Game_Action.prototype.processReinforcementCalls = function(target){
        if(TAA.skm.Parameters.ERTag === false){
            TAA.skm.alias.GameAction.processReinforcementCalls.call(this, target);
        }
    };
}

Game_Action.prototype.customEffectsTargets = function(text, target){
    var targets = [];
    var allyGroup;
    var enemyGroup;
    var party;
    var id;
    if(this.subject().isActor()){
        allyGroup = $gameParty;
        enemyGroup = $gameTroop;
    }
    else if(this.subject().isEnemy()){
        allyGroup = $gameTroop;
        enemyGroup = $gameParty;
    }
    switch(text.toUpperCase()){
        case 'USER':
            targets.push(this.subject());
            break;
        case 'PARTY':
            if(this.subject().isActor()){
                targets = $gameParty.battleMembers().slice();
            }
            else if(this.subject().isEnemy()){
                targets = $gameTroop._enemies.slice();
            }
            break;
        case 'TARGET':
        case 'TARGETS':
            if(Array.isArray(target))
                targets = target;
            else
                targets.push(target);
            break;
        case 'ALIVE ALLIES':
            if(allyGroup !== undefined){
                targets = allyGroup.aliveMembers().slice();
            }
            break;
        case 'DEAD ALLIES':
            if(allyGroup !== undefined){
                targets = allyGroup.deadMembers().slice();
            }
            break;
        case 'ALIVE ENEMIES':
            if(enemyGroup !== undefined){
                targets = enemyGroup.aliveMembers().slice();
            }
            break;
        case 'DEAD ENEMIES':
            if(enemyGroup !== undefined){
                targets = enemyGroup.deadMembers().slice();
            }
            break;
        case 'PARTY BUT USER':
            if(this.subject().isActor()){
                party = allyGroup.battleMembers();
                id = this.subject().actorId();
            }
            else{
                party = allyGroup._enemies;
                id = this.subject().enemyId();
            }
        case 'ENEMIES BUT TARGET':
            if(party === undefined){
                if(target.isActor()){
                    party = enemyGroup.battleMembers();
                    id = target.actorId();
                }
                else{
                    party = enemyGroup._enemies;
                    id = this.subject().enemyId();
                }
            }
            for(var i=0; i < party.length; i++){
                if(id !== party){
                    if(this.subject().isActor())
                        targets.push($gameActors.actor(party));
                    else
                        targets.push($dataEnemies[party]);
                }
            }
            break;
        default:
            console.error("customEffectsTargets: Failed to identify custom effects targets. Check your custom effects syntax.");
    }
    return targets;
};

Game_Action.prototype.clearModifiers = function(){
    this._skmCriticalModifier = undefined;
    this._skmIsCritical = false;
    if(this.subject() && DataManager.isSkill(this.item()))
        this.subject().clearSkillActingLevel(this.item().id);
};

TAA.skm.alias.GameAction.checkItemScope = Game_Action.prototype.checkItemScope;
Game_Action.prototype.checkItemScope = function(list){
    var skillId = this.item().id;
    if(this.subject()._skillMastery === undefined || this.subject()._skillMastery[skillId] === undefined || this.item().leveledScope === undefined)
        return TAA.skm.alias.GameAction.checkItemScope.call(this, list);
   
    var skillLevel = this.subject().getSkillActingLevel(skillId);
    if(skillLevel <= 0) skillLevel = undefined;
    return list.contains(this.item().leveledScope(skillLevel));
};

//=============================================================================
// Game_Switches
//=============================================================================

TAA.skm.alias.GameSwitches = TAA.skm.alias.GameSwitches || {};
Game_Switches.prototype.setValueOnRange = function(lowerRange, upperRange, operation){
    var op = this.convertOperationToEval('sw', operation);
    var sw = lowerRange;
    while(sw <= upperRange){
        try{
            $gameSwitches.setValue(sw, eval(op));
        } catch(e){
            console.error("Failed to eval sentence: " + op);
        }
        
        sw++;
    }
};

Game_Switches.prototype.convertOperationToEval = function(swVarName, operation){
    var op = 'false';
    switch(String(operation)){
        case 'on':
        case 'true':
            op = 'true';
            break;
        case 'off':
        case 'false':
            op = 'false';
            break;
        case 'toggle':
            op = "!$gameSwitches.value(" + swVarName + ")";
            break;
        default:
            if(String(operation).match(/switch ([0-9]+)/i))
                op = "$gameSwitches.value(" + RegExp.$1 + ")";
            else
                op = "$gameSwitches.value(" + swVarName + ")";
    }
   
    return op;
};

//=============================================================================
// Game_Variables
//=============================================================================

TAA.skm.alias.GameVariables = TAA.skm.alias.GameVariables || {};
Game_Variables.prototype.setValueOnRange = function(lowerRange, upperRange, operator, value){
    var intValue = this.getIdFromReference(value);
   
    for(var i=lowerRange; i <= upperRange; i++){
        this.evalOperator(i, operator, intValue);
    }
};

Game_Variables.prototype.getIdFromReference = function(value){
    var intValue;
    if(isNaN(value) && value.match(/v\[([0-9]+)\]/i))
        intValue = parseInt(RegExp.$1);
    else
        intValue = parseInt(value);
    return intValue;
};

Game_Variables.prototype.evalOperator = function(id, operator, intValue){
    if(operator === '='){
        $gameVariables.setValue(id, intValue);
    }
    else{
        var operStr = $gameVariables.value(id) + " " + operator.replace(/=/, '') + " " + intValue;
        try{
            $gameVariables.setValue(id, eval(operStr));
        } catch(e){
            console.error("Failed to eval sentence: " + operStr);
        }
    }
};

//=============================================================================
// Window_Base
//=============================================================================

TAA.skm.alias.WindowBase = TAA.skm.alias.WindowBase || {};
TAA.skm.alias.WindowBase.drawItemName = Window_Base.prototype.drawItemName;
Window_Base.prototype.drawItemName = function(item, x, y, width){
    var drawSKMGauge = true;
    width = width || 312;
    if((TAA.skm.Parameters.ShowGauge !== undefined && TAA.skm.Parameters.ShowGauge === false) || (DataManager.isSkill(item) && TAA.skm.Parameters.Unleveled.contains(item.id)))
        drawSKMGauge = false;
    if(drawSKMGauge && DataManager.isSkill(item)){
        var isVertical = (TAA.skm.Parameters.GaugeType === 'Vertical') ? true : false;
        this.drawSKMGauge(item, x, y, width, isVertical);
        if(isVertical === true){
            var gWidth = !isNaN(TAA.skm.Parameters.GaugeWidth) ? TAA.skm.Parameters.GaugeWidth : 6;
            x += gWidth + 3;
        }
        
        if (item) {
            if(Utils.RPGMAKER_NAME === 'MZ')
                var iconBoxWidth = ImageManager.iconWidth + 4;
            else
                var iconBoxWidth = Window_Base._iconWidth + 4;
            this.resetTextColor();
            this.drawIcon(item.iconIndex, x + 2, y + 2);
            var name = this.setupSkillMasteryName(item, this._actor.skillLevel(item.id));
            this.drawText(name, x + iconBoxWidth, y, width - iconBoxWidth);
        }
    }
    else
        TAA.skm.alias.WindowBase.drawItemName.call(this, item, x, y, width);
};

Window_Base.prototype.drawSKMGauge = function(item, x, y, width, isVertical){
    var gX = x;
    var gY = y;
    if(this._actor === undefined) return;
    var colors = this.getSKMGaugeColors(item);
    if(Utils.RPGMAKER_NAME === 'MZ'){
        var color1 = ColorManager.textColor(colors[0]);
        var color2 = ColorManager.textColor(colors[1]);
        var backColor = ColorManager.textColor(TAA.skm.Parameters.GaugeBgColor);
        var outlineColor = ColorManager.textColor(TAA.skm.Parameters.GaugeOutlineColor);
        var iconWidth = ImageManager.iconWidth;
    }
    else{
        var color1 = this.textColor(colors[0]);
        var color2 = this.textColor(colors[1]);
        var backColor = this.textColor(TAA.skm.Parameters.GaugeBgColor);
        var outlineColor = this.textColor(TAA.skm.Parameters.GaugeOutlineColor);
        var iconWidth = Window_Base._iconWidth;
    }
    var gHeight = !isNaN(TAA.skm.Parameters.GaugeHeight) ? TAA.skm.Parameters.GaugeHeight : 32;
    var gWidth = !isNaN(TAA.skm.Parameters.GaugeWidth) ? TAA.skm.Parameters.GaugeWidth : 6;
   
    if(this.lineHeight() > gHeight && isVertical){
        var round = Math.floor((this.lineHeight() - gHeight)/2);
        gY += round;
    }
    if(isVertical === false) {
        gWidth = width - iconWidth - 5;
        gX = x + iconWidth + 5;
        gY = y + this.lineHeight() - gHeight;
    }

    if(TAA.skm.Parameters.LockGaugeOnReqs === true && (!SkillManager.requirementsMet(item, this._actor.skillLevel(item.id), this._actor)) || (TAA.skm.Parameters.LockTraitSkills && !this._actor.isLearnedSkill(item.id)))
        return this.drawLockedSKMGauge(item, gX, gY, gWidth, gHeight, isVertical);
    if(isNaN(backColor) || backColor < 0){
        if(Utils.RPGMAKER_NAME === 'MZ')
            backColor = ColorManager.gaugeBackColor();
        else
            backColor = this.gaugeBackColor();
    }
    if(TAA.skm.Parameters.GaugeOutline === true && !isNaN(TAA.skm.Parameters.GaugeOutlineThickness) && TAA.skm.Parameters.GaugeOutlineThickness > 0){
        this.contents.fillRect(gX, gY, gWidth, gHeight, outlineColor);
        gWidth -= TAA.skm.Parameters.GaugeOutlineThickness * 2;
        gHeight -= TAA.skm.Parameters.GaugeOutlineThickness * 2;
        gX += TAA.skm.Parameters.GaugeOutlineThickness;
        gY += TAA.skm.Parameters.GaugeOutlineThickness;
    }
    this.contents.fillRect(gX, gY, gWidth, gHeight, backColor);
    var masteryRate = this._actor.skillProgression(item.id);
    var rate = 0;
    if(isVertical === true){
        rate = Math.floor(gHeight * masteryRate);
        gY += gHeight - rate;
        gHeight = rate;
    }
    else{
        rate = Math.floor(gWidth * masteryRate);
        gWidth = rate;
    }
   
    this.contents.gradientFillRect(gX, gY, gWidth, gHeight, color1, color2, isVertical);
};

Window_Base.prototype.getSKMGaugeColors = function(skill){
    var skillLevel = this._actor.getSkillLevel(skill.id);
    var color1 = !isNaN(TAA.skm.Parameters.GaugeColor1) ? TAA.skm.Parameters.GaugeColor1 : 12;
    var color2 = !isNaN(TAA.skm.Parameters.GaugeColor2) ? TAA.skm.Parameters.GaugeColor2 : 4;
    if(TAA.skm.Parameters.CustomGaugeColors !== undefined && TAA.skm.Parameters.CustomGaugeColors.length > 0){
        var i = 0;
        while(i < TAA.skm.Parameters.CustomGaugeColors.length){
            var custom = JSON.parse(TAA.skm.Parameters.CustomGaugeColors[i++]);
            if(parseInt(custom['Level']) === skillLevel){
                color1 = parseInt(custom['Color 1']);
                color2 = parseInt(custom['Color 2']);
                i += TAA.skm.Parameters.CustomGaugeColors.length;
            }
        }
    }
    return [color1, color2];
};

Window_Base.prototype.drawLockedSKMGauge = function(item, x, y, width, height, isVertical){
    var lockColor;
    if(!isNaN(TAA.skm.Parameters.LockedGaugeColor)){
        if(Utils.RPGMAKER_NAME === 'MZ')
            lockColor = ColorManager.textColor(TAA.skm.Parameters.LockedGaugeColor);
        else
            lockColor = this.textColor(TAA.skm.Parameters.LockedGaugeColor);
    }
    else{
        if(Utils.RPGMAKER_NAME === 'MZ')
            lockColor = ColorManager.textColor(10);
        else
            lockColor = this.textColor(10);
    }
    var backColor = TAA.skm.Parameters.GaugeBgColor;
    if(isNaN(backColor) || backColor < 0){
        if(Utils.RPGMAKER_NAME === 'MZ')
            backColor = ColorManager.gaugeBackColor();
        else
            backColor = this.gaugeBackColor();
    }
    var pad = !isNaN(TAA.skm.Parameters.LockedGaugeThickness) ? TAA.skm.Parameters.LockedGaugeThickness : 2;
    this.contents.fillRect(x, y, width, height, lockColor);
    this.contents.fillRect(x+pad, y+pad, width-(pad*2), height-(pad*2), backColor);
};

Window_Base.prototype.setupSkillMasteryName = function(skill, level){
    if(TAA.skm.Parameters.SkillName === undefined || TAA.skm.Parameters.SkillName === "") return skill.name;

    let name = SkillManager.getName(skill, level);
    var result = TAA.skm.Parameters.SkillName.replace(/%1/g, name);
    return result.replace(/%2/g, level);
};

//=============================================================================
// Window_SkillList
//=============================================================================

TAA.skm.alias.Window_SkillList = TAA.skm.alias.Window_SkillList || {};
TAA.skm.alias.Window_SkillList.drawSkillCost = Window_SkillList.prototype.drawSkillCost;
Window_SkillList.prototype.drawSkillCost = function(skill, x, y, width){
    if(!DataManager.isSkill(skill) && TAA.skm.Parameters.Unleveled.contains(skill.id))
        TAA.skm.alias.Window_SkillList.drawSkillCost.call(this, skill, x, y, width);
    else if(TAA.skm.Parameters.AllowLevelSelect && this._actor.skillLevel(skill.id) > 1){
        if(Utils.RPGMAKER_NAME === 'MZ'){
            this.changeTextColor(ColorManager.mpCostColor());
        }
        else{
            this.changeTextColor(this.mpCostColor());
        }
        this.drawText(TAA.skm.Parameters.LevelSelectIndicator, x, y, width, "right");
    }
    else{
        let tpCost = this._actor.skillTpCost(skill);
        let mpCost = this._actor.skillMpCost(skill);
        let tpCostTxt = "";
        let mpCostTxt = "";
        let align = 'right';
        if(tpCost > 0 && mpCost > 0){
            width -= this.textWidth(TAA.skm.Parameters.SkillCostSeparator) + this.costWidth();
        }
        if(tpCost > 0){
            tpCostTxt = TAA.skm.Parameters.SkillCostDisplay.replace(/%1/g, tpCost + "");
            tpCostTxt = tpCostTxt.replace(/%2/g, "TP");
            if(Utils.RPGMAKER_NAME === 'MZ'){
                this.changeTextColor(ColorManager.tpCostColor());
            }
            else{
                this.changeTextColor(this.tpCostColor());
            }
            this.drawText(tpCostTxt, x, y, width, align);
            if(mpCost > 0){
                this.resetTextColor();
                width += this.textWidth(TAA.skm.Parameters.SkillCostSeparator);
                this.drawText(TAA.skm.Parameters.SkillCostSeparator, x, y, width, align);
                width += this.costWidth();
            }
        }
        if(mpCost > 0){
            mpCostTxt = TAA.skm.Parameters.SkillCostDisplay.replace(/%1/g, mpCost + "");
            mpCostTxt = mpCostTxt.replace(/%2/g, "MP");
            if(Utils.RPGMAKER_NAME === 'MZ'){
                this.changeTextColor(ColorManager.mpCostColor());
            }
            else{
                this.changeTextColor(this.mpCostColor());
            }
            this.drawText(mpCostTxt, x, y, width, align);
        }
    }
};

TAA.skm.alias.Window_SkillList.costWidth = Window_SkillList.prototype.costWidth;
Window_SkillList.prototype.costWidth = function() {
    let pattern = TAA.skm.Parameters.SkillCostDisplay.replace(/%1/g, "000");
    pattern = pattern.replace(/%2/g, "AA");
    return this.textWidth(pattern);
};

//=============================================================================
// Window_SkillLevelList
//=============================================================================

function Window_SkillLevelList() {
    this.initialize.apply(this, arguments);
};

Window_SkillLevelList.prototype = Object.create(Window_Selectable.prototype);
Window_SkillLevelList.prototype.constructor = Window_SkillLevelList;

Window_SkillLevelList.prototype.initialize = function(width){
    let w = Math.max(Math.round(Graphics.boxWidth/3), width);
    let h = this.standardPadding() * 2;
    if(Utils.RPGMAKER_NAME === 'MZ'){
        var rect = new Rectangle(0, 0, w, h);
        Window_Selectable.prototype.initialize.call(this, rect);
    }
    else
        Window_Selectable.prototype.initialize.call(this, 0, 0, w, h);
    this._actor = undefined;
    this.setStandardOpacity();
    this.clearData();
    this.update();
};

Window_SkillLevelList.prototype.clearData = function(){
    this._skill = null;
    this._skillNameData = [];
    this._skillCostData = [];
    this._numOfLevels = 0;
    this._scrollY = 0;
};

Window_SkillLevelList.prototype.setActor = function(actor) {
    if (this._actor !== actor) {
        this._actor = actor;
        this.refresh();
        this.resetScroll();
    }
};

Window_SkillLevelList.prototype.maxCols = function() {
    return 1;
};

Window_SkillLevelList.prototype.spacing = function() {
    return 48;
};

Window_SkillLevelList.prototype.maxItems = function() {
    return Math.min(TAA.skm.Parameters.SkillLevelWindow.MaxRows, this._numOfLevels);
};

Window_SkillLevelList.prototype.item = function() {
    return this._data && this.index() >= 0 ? this._data[this.index() + 1] : null;
};

Window_SkillLevelList.prototype.selectLast = function() {
    this.select(0);
};

Window_SkillLevelList.prototype.maxRows = function() {
    return Math.max(Math.min(this.maxItems(), this._numOfLevels), 1);
};

Window_SkillLevelList.prototype.isEnabled = function(index) {
    return this._actor && this._actor.meetsSkillConditionsForLevel(this._skill, (index+1));
};

Window_SkillLevelList.prototype.isCurrentItemEnabled = function() {
    return this.isEnabled(this.index());
};

Window_SkillLevelList.prototype.drawAllItems = function() {
    var topIndex = this.topIndex();
    for (var i = 0; i < this.maxPageItems(); i++) {
        var index = topIndex + i;
        if (index < this.maxItems()) {
            this.drawItem(index);
        }
        if(index+1 >= this._numOfLevels) break;
    }
};

Window_SkillLevelList.prototype.drawItemName = function(text, x, y, width) {
    width = width || 312;
    if (text) {
        this.resetTextColor();
        this.drawText(text, x, y, width);
    }
};

Window_SkillLevelList.prototype.drawItem = function(index) {
    let realIndex = index + 1;
    var name = this._skillNameData[realIndex];
    var cost = this._skillCostData[realIndex];
    var costWidth = this.costWidth();
    var rect = this.itemRect(index);
    rect.width -= this.textPadding();
    this.changePaintOpacity(this.isEnabled(index));
    this.drawItemName(name, rect.x, rect.y, rect.width - costWidth);
    this.drawSkillCost(cost, rect.x, rect.y, rect.width);
    this.changePaintOpacity(1);
};

Window_SkillLevelList.prototype.costWidth = function() {
    return this.textWidth('000');
};

Window_SkillLevelList.prototype.drawSkillCost = function(cost, x, y, width) {
    let costText = "";
    if(!isNaN(cost.tp) && cost.tp > 0) {
        costText = TAA.skm.Parameters.SkillCostDisplay.replace(/%1/g, cost.tp + "");
        costText = costText.replace(/%2/g, "TP");
        this.changeTextColor(this.hpGaugeColor1());
        this.drawText(costText, x, y, width, 'right');
    }
    else if(!isNaN(cost.mp) && cost.mp > 0){
        costText = TAA.skm.Parameters.SkillCostDisplay.replace(/%1/g, cost.mp + "");
        costText = costText.replace(/%2/g, "MP");
        this.changeTextColor(this.mpCostColor());
        this.drawText(costText, x, y, width, 'right');
    }
};

Window_SkillLevelList.prototype.updateHelp = function() {
    let item = {description: SkillManager.getDescription(this._skill, this.index()) }
    this.setHelpWindowItem(item);
};

Window_SkillLevelList.prototype.refresh = function() {
    this.contents.clear();
    this.createContents();
    this.drawAllItems();
};

Window_SkillLevelList.prototype.standardWidth = function(){
    return Math.round(Graphics.boxWidth / 3);
};

Window_SkillLevelList.prototype.relocateWindow = function(x, y, rect, pad){
    let outOfBounds = false;
    if((x + this.width) > Graphics.boxWidth){
        this._maxWidth = x + this.standardWidth();
        x -= rect.width + this.width;
        if(x < 0) {
            x = pad;
            outOfBounds = true;
        }
    }
    else{
        this._maxWidth = Graphics.boxWidth;
    }
    this.x = x;
   
    if((y + this.windowHeight() > Graphics.boxHeight) || (outOfBounds && ((y + this.windowHeight() + rect.height) > Graphics.boxHeight))){
        y = Math.max(0, y - this._numOfLevels * (this.lineHeight() - 1) - this.standardPadding());
        if(outOfBounds)
            y -= rect.height;
    }
    else if(outOfBounds)
        y += rect.height;
   
    this.y = y;
};

Window_SkillLevelList.prototype.setSkillData = function(skill, level, rect, listY, pad){
    if(!DataManager.isSkill(skill))
        return;

    let x = rect.x + rect.width + pad;
    let y = rect.y + listY + pad;

    this.clearData();
    this._skill = skill;
    this._numOfLevels = level;
    this.height = this.windowHeight();
    this.relocateWindow(x, y, rect, pad);

    for(var i=1; i<=level; i++){
        let name = TAA.skm.Parameters.SkillLevelWindow.SkillName.replace(/%1/g,SkillManager.getName(skill, i));
        let mpCost = SkillManager.getMpCost(skill, i);
        let tpCost = SkillManager.getTpCost(skill, i);
        let cost = {mp:mpCost, tp:tpCost};
        
        this._skillNameData = name.replace(/%2/g, i);
        this._skillCostData = cost;
    }
    this.refresh();
};

Window_SkillLevelList.prototype.standardPadding = function() {
    return TAA.skm.Parameters.SkillLevelWindow.Padding;
};

Window_SkillLevelList.prototype.setStandardOpacity = function() {
    var opacity = TAA.skm.Parameters.SkillLevelWindow.StandardOpacity;
    if(opacity === undefined) opacity = 255;
    this.opacity = opacity;
};

Window_SkillLevelList.prototype.standardBackOpacity = function(){
    this._windowBackOpacity = TAA.skm.Parameters.SkillLevelWindow.BackOpacity;
    return this._windowBackOpacity;
};

TAA.skm.alias.Window_SkillLevelList = {};
TAA.skm.alias.Window_SkillLevelList.loadWindowskin = Window_SkillLevelList.prototype.loadWindowskin;
Window_SkillLevelList.prototype.loadWindowskin = function(){
    if(TAA.skm.Parameters.SkillLevelWindow.WindowSkin)
        this.windowskin = ImageManager.loadSystem(TAA.skm.Parameters.SkillLevelWindow.WindowSkin);
    else
        TAA.skm.alias.Window_SkillLevelList.loadWindowskin.call(this);
};

Window_SkillLevelList.prototype.windowWidth = function(){
    return this.width;
};

Window_SkillLevelList.prototype.windowHeight = function(){
    return this._numOfLevels * this.lineHeight() + this.standardPadding() * 2;
};

Window_SkillLevelList.prototype.activate = function() {
    Window_Selectable.prototype.activate.call(this);
    this.select(0);
    this.visible = true;
    this.active = true;
};

Window_SkillLevelList.prototype.deactivate = function() {
    Window_Selectable.prototype.deactivate.call(this);
    this.visible = false;
    this.active = false;
};

Window_SkillLevelList.prototype.currentSelection = function(){
    let skillId = this._skill.id;
    let level = this.index()+1;
    return [skillId, level];
};

//=============================================================================
// Scene_Skill
//=============================================================================

TAA.skm.alias.Scene_Skill = {};
TAA.skm.alias.Scene_Skill.create = Scene_Skill.prototype.create;
Scene_Skill.prototype.create = function() {
    TAA.skm.alias.Scene_Skill.create.call(this);
    this.createSkillLevelWindow();
};

Scene_Skill.prototype.createSkillLevelWindow = function(){
    this._skillLevelWindow = new Window_SkillLevelList((Math.round(this._itemWindow.width/this._itemWindow.maxCols()) - this._itemWindow.standardPadding()));
    this._skillLevelWindow.setHelpWindow(this._helpWindow);
    this._skillLevelWindow.setHandler('ok', this.commandSkillLevel.bind(this));
    this._skillLevelWindow.setHandler('cancel', this.onSkillLevelCancel.bind(this));
   
    var index = this.children.indexOf(this._windowLayer);
    this.addChildAt(this._skillLevelWindow, index);
};

Scene_Skill.prototype.startSkillLevelWindow = function(){
    let selectedSkill = this._itemWindow.item();
    let selectedRect = this._itemWindow.itemRect(this._itemWindow.index());
    let actor = this._itemWindow._actor;
    this._skillLevelWindow.setActor(actor);
    this._skillLevelWindow.setSkillData(selectedSkill, actor.skillLevel(selectedSkill.id), selectedRect, this._itemWindow.y, this._itemWindow.standardPadding());
    this._skillLevelWindow.activate();
};

TAA.skm.alias.Scene_Skill.onItemOk = Scene_Skill.prototype.onItemOk;
Scene_Skill.prototype.onItemOk = function() {
    let selectedSkill = this._itemWindow.item();
    let actor = this._itemWindow._actor;
    let currentLevel = actor.skillLevel(selectedSkill.id);
    if(TAA.skm.Parameters.AllowLevelSelect !== true || currentLevel < 2)
        TAA.skm.alias.Scene_Skill.onItemOk.call(this);
    else{
        this.startSkillLevelWindow();
    }
};

Scene_Skill.prototype.onItemCancel = function() {
    this._itemWindow.deselect();
    this._skillTypeWindow.activate();
};

Scene_Skill.prototype.commandSkillLevel = function() {
    let actingLevel = this._skillLevelWindow.currentSelection();
    this._actor.setSkillActingLevel(actingLevel[0], actingLevel[1]);
    TAA.skm.alias.Scene_Skill.onItemOk.call(this);
};

Scene_Skill.prototype.onSkillLevelCancel = function() {
    this._skillLevelWindow.deselect();
    this._skillLevelWindow.deactivate();
    this._itemWindow.activate();
};

TAA.skm.alias.Scene_Skill.useItem = Scene_Skill.prototype.useItem;
Scene_Skill.prototype.useItem = function() {
    TAA.skm.alias.Scene_Skill.useItem.call(this);
    this._actor.clearSkillActingLevel(this.item().id);
    this._statusWindow.refresh();
    this._itemWindow.refresh();
};

TAA.skm.alias.Scene_Skill.refreshActor = Scene_Skill.prototype.refreshActor;
Scene_Skill.prototype.refreshActor = function() {
    TAA.skm.alias.Scene_Skill.refreshActor.call(this);
    var actor = this.actor();
    this._skillLevelWindow.setActor(actor);
};

//=============================================================================
// Scene_Battle
//=============================================================================

TAA.skm.alias.Scene_Battle = {};
TAA.skm.alias.Scene_Battle.createAllWindows = Scene_Battle.prototype.createAllWindows;
Scene_Battle.prototype.createAllWindows = function() {
    TAA.skm.alias.Scene_Battle.createAllWindows.call(this);
    this.createSkillLevelWindow();
};

Scene_Battle.prototype.createSkillLevelWindow = function(){
    this._skillLevelWindow = new Window_SkillLevelList((Math.round(this._itemWindow.width/this._itemWindow.maxCols()) - this._itemWindow.standardPadding()));
    this._skillLevelWindow.setHelpWindow(this._helpWindow);
    this._skillLevelWindow.setHandler('ok', this.commandSkillLevel.bind(this));
    this._skillLevelWindow.setHandler('cancel', this.onSkillLevelCancel.bind(this));
   
    var index = this.children.indexOf(this._windowLayer);
    this.addChildAt(this._skillLevelWindow, index);
};

TAA.skm.alias.Scene_Battle.changeInputWindow = Scene_Battle.prototype.changeInputWindow;
Scene_Battle.prototype.changeInputWindow = function() {
    if(!this._skillLevelWindow.active)
        TAA.skm.alias.Scene_Battle.changeInputWindow.call(this);
};

Scene_Battle.prototype.startSkillLevelWindow = function(){
    let selectedSkill = this._skillWindow.item();
    let selectedRect = this._skillWindow.itemRect(this._skillWindow.index());
    let actor = this._skillWindow._actor;
    this._skillLevelWindow.setActor(actor);
    this._skillLevelWindow.setSkillData(selectedSkill, actor.skillLevel(selectedSkill.id), selectedRect, this._skillWindow.y, this._skillWindow.standardPadding());
    this._actorCommandWindow.deactivate();
    this._skillLevelWindow.activate();
};

TAA.skm.alias.Scene_Battle.onSkillOk = Scene_Battle.prototype.onSkillOk;
Scene_Battle.prototype.onSkillOk = function() {
    let selectedSkill = this._skillWindow.item();
    let actor = this._skillWindow._actor;
    let currentLevel = actor.skillLevel(selectedSkill.id);
    if(TAA.skm.Parameters.AllowLevelSelect !== true || currentLevel < 2)
        TAA.skm.alias.Scene_Battle.onSkillOk.call(this);
    else{
        this.startSkillLevelWindow();
    }
};

Scene_Battle.prototype.commandSkillLevel = function() {
    let actingLevel = this._skillLevelWindow.currentSelection();
    this._skillWindow._actor.setSkillActingLevel(actingLevel[0], actingLevel[1]);
    TAA.skm.alias.Scene_Battle.onSkillOk.call(this);
};

Scene_Battle.prototype.onSkillLevelCancel = function() {
    this._skillLevelWindow.deselect();
    this._skillLevelWindow.deactivate();
    this._skillWindow.activate();
};

//=============================================================================
// TAA.util
//=============================================================================

TAA.util = TAA.util || {};
if(TAA.util.getStateIdByName === undefined){
    TAA.util.getStateIdByName = function(stateName){
        var i = 0;
        while(i < $dataStates.length){
            if($dataStates.name === stateName)
                return i;
            i++;
        }
        return 0;
    }
}

Lv3.寻梦者

梦石
0
星屑
2015
在线时间
602 小时
注册时间
2012-4-8
帖子
426
2
发表于 2024-6-29 23:30:43 | 只看该作者
本帖最后由 505681468 于 2024-6-29 23:35 编辑

Window_SkillLevelList.prototype.setActor 中调用了 this.resetScroll

Window_SkillLevelList 继承了 Window_Selectable
在 MV 中,Window_Selectable 有 resetScroll
在 MZ 中,好像取消了这个方法

【↓ 不保证效果,没验证过 ↓】



可以移植 mv 的方法
  1. Window_Selectable.prototype.resetScroll = function() {
  2.     this.setTopRow(0);
  3. };
复制代码

也可以注销插件 resetScroll 的调用
按理来说只是一个窗口滚动重置,应该不碍事
  1. Window_SkillLevelList.prototype.setActor = function(actor) {
  2.     if (this._actor !== actor) {
  3.         this._actor = actor;
  4.         this.refresh();
  5.         //this.resetScroll();
  6.     }
  7. };
复制代码
pokemon 和 digimon 正在路上
回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
323
在线时间
49 小时
注册时间
2021-4-2
帖子
13
3
 楼主| 发表于 2024-6-29 23:38:30 | 只看该作者
505681468 发表于 2024-6-29 23:30
Window_SkillLevelList.prototype.setActor 中调用了 this.resetScroll

Window_SkillLevelList 继承了 Win ...

感谢大佬,代码是添加在这个插件里的吗?
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
2015
在线时间
602 小时
注册时间
2012-4-8
帖子
426
4
发表于 2024-6-29 23:40:53 | 只看该作者
1579406829 发表于 2024-6-29 23:38
感谢大佬,代码是添加在这个插件里的吗?


代码直接插后面试试
pokemon 和 digimon 正在路上
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-16 08:23

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表