diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index 1014bfbe..465fc1c1 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -12,7 +12,7 @@ using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.actors.chara.player; using FFXIVClassic_Map_Server.packets.receive.supportdesk; using FFXIVClassic_Map_Server.actors.chara.ai; -using FFXIVClassic_Map_Server.Actors.Chara; +using FFXIVClassic_Map_Server.packets.send.actor.battle; using FFXIVClassic_Map_Server.actors.chara; namespace FFXIVClassic_Map_Server @@ -2261,7 +2261,7 @@ namespace FFXIVClassic_Map_Server conn.Open(); var query = ("SELECT `id`, name, classJob, lvl, requirements, mainTarget, validTarget, aoeType, aoeRange, aoeTarget, basePotency, numHits, positionBonus, procRequirement, `range`, statusId, statusDuration, statusChance, " + - "castType, castTime, recastTime, mpCost, tpCost, animationType, effectAnimation, modelAnimation, animationDuration, battleAnimation, validUser, comboId1, comboId2, comboStep, accuracyMod, worldMasterTextId FROM server_battle_commands;"); + "castType, castTime, recastTime, mpCost, tpCost, animationType, effectAnimation, modelAnimation, animationDuration, battleAnimation, validUser, comboId1, comboId2, comboStep, accuracyMod, worldMasterTextId, commandType, actionType, actionProperty FROM server_battle_commands;"); MySqlCommand cmd = new MySqlCommand(query, conn); @@ -2306,6 +2306,9 @@ namespace FFXIVClassic_Map_Server battleCommand.comboNextCommandId[0] = reader.GetInt32("comboId1"); battleCommand.comboNextCommandId[1] = reader.GetInt32("comboId2"); battleCommand.comboStep = reader.GetInt16("comboStep"); + battleCommand.commandType = (CommandType) reader.GetInt16("commandType"); + battleCommand.actionProperty = (ActionProperty)reader.GetInt16("actionProperty"); + battleCommand.actionType = (ActionType)reader.GetInt16("actionType"); battleCommand.accuracyModifier = reader.GetFloat("accuracyMod"); battleCommand.worldMasterTextId = reader.GetUInt16("worldMasterTextId"); lua.LuaEngine.LoadBattleCommandScript(battleCommand, "weaponskill"); @@ -2338,6 +2341,60 @@ namespace FFXIVClassic_Map_Server } } + public static void LoadGlobalBattleTraitList(Dictionary battleTraitDict, Dictionary> battleTraitJobDict) + { + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + int count = 0; + conn.Open(); + + var query = ("SELECT `id`, name, classJob, lvl, modifier, bonus FROM server_battle_traits;"); + + MySqlCommand cmd = new MySqlCommand(query, conn); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var id = reader.GetUInt16("id"); + var name = reader.GetString("name"); + var job = reader.GetByte("classJob"); + var level = reader.GetByte("lvl"); + uint modifier = reader.GetUInt32("modifier"); + var bonus = reader.GetInt32("bonus"); + + var trait = new BattleTrait(id, name, job, level, modifier, bonus); + + battleTraitDict.Add(id, trait); + + if(battleTraitJobDict.ContainsKey(job)) + { + battleTraitJobDict[job].Add(id); + } + else + { + battleTraitJobDict[job] = new List(); + battleTraitJobDict[job].Add(id); + } + + count++; + } + } + Program.Log.Info(String.Format("Loaded {0} battle traits.", count)); + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + } + public static void SetExp(Player player, byte classId, int exp) { using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 7dbf36e9..7baa2721 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -85,6 +85,7 @@ + @@ -196,6 +197,7 @@ + diff --git a/FFXIVClassic Map Server/Server.cs b/FFXIVClassic Map Server/Server.cs index 3d0605ee..97f201f5 100644 --- a/FFXIVClassic Map Server/Server.cs +++ b/FFXIVClassic Map Server/Server.cs @@ -54,9 +54,10 @@ namespace FFXIVClassic_Map_Server mWorldManager.LoadActorClasses(); mWorldManager.LoadSpawnLocations(); mWorldManager.LoadBattleNpcs(); - mWorldManager.SpawnAllActors(); mWorldManager.LoadStatusEffects(); mWorldManager.LoadBattleCommands(); + mWorldManager.LoadBattleTraits(); + mWorldManager.SpawnAllActors(); mWorldManager.StartZoneThread(); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT)); diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index 7f3d7684..4345e8a0 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -41,10 +41,12 @@ namespace FFXIVClassic_Map_Server private Dictionary statusEffectList = new Dictionary(); private Dictionary battleCommandList = new Dictionary(); private Dictionary, List> battleCommandIdByLevel = new Dictionary, List>();//Holds battle command ids keyed by class id and level (in that order) + private Dictionary battleTraitList = new Dictionary(); + private Dictionary> battleTraitIdsForClass = new Dictionary>(); private Dictionary battleNpcGenusMods = new Dictionary(); private Dictionary battleNpcPoolMods = new Dictionary(); private Dictionary battleNpcSpawnMods = new Dictionary(); - + private Server mServer; private const int MILIS_LOOPTIME = 333; @@ -1473,6 +1475,11 @@ namespace FFXIVClassic_Map_Server Database.LoadGlobalBattleCommandList(battleCommandList, battleCommandIdByLevel); } + public void LoadBattleTraits() + { + Database.LoadGlobalBattleTraitList(battleTraitList, battleTraitIdsForClass); + } + public BattleCommand GetBattleCommand(uint id) { BattleCommand battleCommand; @@ -1484,5 +1491,19 @@ namespace FFXIVClassic_Map_Server List ids; return battleCommandIdByLevel.TryGetValue(Tuple.Create(classId, level), out ids) ? ids : new List(); } + + public BattleTrait GetBattleTrait(ushort id) + { + BattleTrait battleTrait; + battleTraitList.TryGetValue(id, out battleTrait); + return battleTrait; + } + + public List GetAllBattleTraitIdsForClass(byte classId) + { + List ids; + return battleTraitIdsForClass.TryGetValue(classId, out ids) ? ids : new List(); + } + } } diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 1291e742..c7aff919 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -26,6 +26,9 @@ namespace FFXIVClassic_Map_Server.Actors Appearance = 0x10, Speed = 0x20, Work = 0x40, + Stats = 0x80, + Status = 0x100, + StatusTime = 0x200, AllNpc = 0x6F, AllPlayer = 0x9F @@ -375,6 +378,15 @@ namespace FFXIVClassic_Map_Server.Actors } } + public void ModifySpeed(float mod) + { + for (int i = 0; i < 4; i++) + { + moveSpeeds[i] *= mod; + } + updateFlags |= ActorUpdateFlags.Speed; + } + public void ChangeSpeed(int type, float value) { moveSpeeds[type] = value; diff --git a/FFXIVClassic Map Server/actors/area/Area.cs b/FFXIVClassic Map Server/actors/area/Area.cs index d6b2d35f..99ba2353 100644 --- a/FFXIVClassic Map Server/actors/area/Area.cs +++ b/FFXIVClassic Map Server/actors/area/Area.cs @@ -500,8 +500,8 @@ namespace FFXIVClassic_Map_Server.Actors npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null); npc.LoadEventConditions(actorClass.eventConditions); - npc.SetMaxHP(30000); - npc.SetHP(30000); + npc.SetMaxHP(100); + npc.SetHP(100); npc.ResetMoveSpeeds(); AddActorToZone(npc); diff --git a/FFXIVClassic Map Server/actors/chara/BattleTemp.cs b/FFXIVClassic Map Server/actors/chara/BattleTemp.cs index 0d1c861f..9f46b35f 100644 --- a/FFXIVClassic Map Server/actors/chara/BattleTemp.cs +++ b/FFXIVClassic Map Server/actors/chara/BattleTemp.cs @@ -2,10 +2,11 @@ { class BattleTemp { + //Are these right? public const uint NAMEPLATE_SHOWN = 0; public const uint TARGETABLE = 1; - //public const uint NAMEPLATE_SHOWN2 = 2; - public const uint NAMEPLATE_SHOWN2 = 3; + public const uint NAMEPLATE_SHOWN2 = 2; + //public const uint NAMEPLATE_SHOWN2 = 3; public const uint STAT_STRENGTH = 3; public const uint STAT_VITALITY = 4; @@ -25,13 +26,13 @@ public const uint STAT_ACCURACY = 15; public const uint STAT_NORMALDEFENSE = 18; public const uint STAT_EVASION = 16; - public const uint STAT_ATTACK_MAGIC = 24; - public const uint STAT_HEAL_MAGIC = 25; - public const uint STAT_ENCHANCEMENT_MAGIC_POTENCY = 26; - public const uint STAT_ENFEEBLING_MAGIC_POTENCY = 27; - - public const uint STAT_MAGIC_ACCURACY = 28; - public const uint STAT_MAGIC_EVASION = 29; + public const uint STAT_ATTACK_MAGIC = 23; + public const uint STAT_HEAL_MAGIC = 24; + public const uint STAT_ENCHANCEMENT_MAGIC_POTENCY = 25; + public const uint STAT_ENFEEBLING_MAGIC_POTENCY = 26; + + public const uint STAT_MAGIC_ACCURACY = 27; + public const uint STAT_MAGIC_EVASION = 28; public const uint STAT_CRAFT_PROCESSING = 30; public const uint STAT_CRAFT_MAGIC_PROCESSING = 31; @@ -43,6 +44,6 @@ public float[] castGauge_speed = { 1.0f, 0.25f}; public bool[] timingCommandFlag = new bool[4]; - public ushort[] generalParameter = new ushort[35]; + public short[] generalParameter = new short[35]; } } diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 831c1316..a3f4e5bf 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -117,7 +117,7 @@ namespace FFXIVClassic_Map_Server.Actors public Pet pet; - private Dictionary modifiers = new Dictionary(); + private Dictionary modifiers = new Dictionary(); protected ushort hpBase, hpMaxBase, mpBase, mpMaxBase, tpBase; protected BattleTemp baseStats = new BattleTemp(); @@ -191,6 +191,7 @@ namespace FFXIVClassic_Map_Server.Actors zone.BroadcastPacketsAroundActor(this, propPacketUtil.Done()); } + //This logic isn't correct, order of GetStatusEffects() is not necessarily the same as the actual effects in game. Also sending every time at once isn't needed public List GetActorStatusPackets() { var propPacketUtil = new ActorPropertyPacketUtil("charaWork/status", this); @@ -260,7 +261,7 @@ namespace FFXIVClassic_Map_Server.Actors public void DoBattleAction(ushort commandId, uint animationId, List actions) { - int currentIndex = 0; + int currentIndex = 0; while (true) { @@ -275,7 +276,11 @@ namespace FFXIVClassic_Map_Server.Actors } else break; - animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing. + + //Sending multiple packets at once causes some issues. Setting any combination of these to zero changes what breaks + //animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing. + //commandId = 0; + //sourceActorId = 0; } } @@ -291,20 +296,51 @@ namespace FFXIVClassic_Map_Server.Actors PathTo(target.positionX, target.positionY, target.positionZ, stepSize, maxPath, radius); } - public Int64 GetMod(uint modifier) + public double GetMod(Modifier modifier) { - Int64 res; + return GetMod((uint)modifier); + } + + public double GetMod(uint modifier) + { + double res; if (modifiers.TryGetValue((Modifier)modifier, out res)) return res; return 0; } - public void SetMod(uint modifier, Int64 val) + public void SetMod(uint modifier, double val) { if (modifiers.ContainsKey((Modifier)modifier)) modifiers[(Modifier)modifier] = val; else modifiers.Add((Modifier)modifier, val); + + if (modifier <= 35) + updateFlags |= ActorUpdateFlags.Stats; + } + + public void AddMod(Modifier modifier, double val) + { + AddMod((uint)modifier, val); + } + + public void AddMod(uint modifier, double val) + { + + double newVal = GetMod(modifier) + val; + SetMod(modifier, newVal); + } + + public void SubtractMod(Modifier modifier, double val) + { + AddMod((uint)modifier, val); + } + + public void SubtractMod(uint modifier, double val) + { + double newVal = GetMod(modifier) - val; + SetMod(modifier, newVal); } public virtual void OnPath(Vector3 point) @@ -341,6 +377,21 @@ namespace FFXIVClassic_Map_Server.Actors //DoBattleAction(21001, 0x7C000062, new BattleAction(this.actorId, 0, 1, 0, 0, 1)); //Attack Mode } + if ((updateFlags & ActorUpdateFlags.Status) != 0) + { + List statusPackets = statusEffects.GetStatusPackets(); + packets.AddRange(statusPackets); + statusPackets.Clear(); + updateFlags &= ~ActorUpdateFlags.Status; + } + + if ((updateFlags & ActorUpdateFlags.StatusTime) != 0) + { + packets.AddRange(statusEffects.GetStatusTimerPackets()); + updateFlags &= ~ActorUpdateFlags.StatusTime; + + } + if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0) { var propPacketUtil = new ActorPropertyPacketUtil("charaWork/stateAtQuicklyForAll", this); @@ -351,6 +402,7 @@ namespace FFXIVClassic_Map_Server.Actors propPacketUtil.AddProperty("charaWork.parameterTemp.tp"); packets.AddRange(propPacketUtil.Done()); } + base.PostUpdate(tick, packets); } } @@ -393,11 +445,12 @@ namespace FFXIVClassic_Map_Server.Actors public virtual bool Engage(uint targid = 0, ushort newMainState = 0xFFFF) { // todo: attack the things - if (newMainState != 0xFFFF) + /*if (newMainState != 0xFFFF) { - this.newMainState = newMainState; + currentMainState = newMainState;// this.newMainState = newMainState; + updateFlags |= ActorUpdateFlags.State; } - else if (aiContainer.CanChangeState()) + else*/ if (aiContainer.CanChangeState()) { if (targid == 0) { @@ -423,11 +476,12 @@ namespace FFXIVClassic_Map_Server.Actors public virtual bool Disengage(ushort newMainState = 0xFFFF) { - if (newMainState != 0xFFFF) + /*if (newMainState != 0xFFFF) { - this.newMainState = newMainState; + currentMainState = newMainState;// this.newMainState = newMainState; + updateFlags |= ActorUpdateFlags.State; } - else if (IsEngaged()) + else*/ if (IsEngaged()) { aiContainer.Disengage(); return true; @@ -463,7 +517,8 @@ namespace FFXIVClassic_Map_Server.Actors RecalculateStats(); } - public virtual void Die(DateTime tick) + //AdditionalActions is the list of actions that EXP/Chain messages are added to + public virtual void Die(DateTime tick, BattleActionContainer actionContainer = null) { // todo: actual despawn timer aiContainer.InternalDie(tick, 10); @@ -523,7 +578,7 @@ namespace FFXIVClassic_Map_Server.Actors public byte GetHPP() { - return (byte)(charaWork.parameterSave.hp[0] == 0 ? 0 : (charaWork.parameterSave.hp[0] / charaWork.parameterSave.hpMax[0]) * 100); + return (byte)(charaWork.parameterSave.hp[0] == 0 ? 0 : (charaWork.parameterSave.hp[0] / (float) charaWork.parameterSave.hpMax[0]) * 100); } public void SetHP(uint hp) @@ -558,8 +613,8 @@ namespace FFXIVClassic_Map_Server.Actors // todo: the following functions are virtuals since we want to check hidden item bonuses etc on player for certain conditions public virtual void AddHP(int hp) { - // dont wanna die ded - if (IsAlive()) + // dont wanna die ded, don't want to send update if hp isn't actually changed + if (IsAlive() && hp != 0) { // todo: +/- hp and die // todo: battlenpcs probably have way more hp? @@ -567,9 +622,6 @@ namespace FFXIVClassic_Map_Server.Actors addHp = addHp.Clamp((short)GetMod((uint)Modifier.MinimumHpLock), charaWork.parameterSave.hpMax[0]); charaWork.parameterSave.hp[0] = (short)addHp; - if (charaWork.parameterSave.hp[0] < 1) - Die(Program.Tick); - updateFlags |= ActorUpdateFlags.HpTpMp; } } @@ -586,18 +638,24 @@ namespace FFXIVClassic_Map_Server.Actors public void AddMP(int mp) { - charaWork.parameterSave.mp = (short)(charaWork.parameterSave.mp + mp).Clamp(ushort.MinValue, charaWork.parameterSave.mpMax); + if (IsAlive() && mp != 0) + { + charaWork.parameterSave.mp = (short)(charaWork.parameterSave.mp + mp).Clamp(ushort.MinValue, charaWork.parameterSave.mpMax); - // todo: check hidden effects and shit + // todo: check hidden effects and shit - updateFlags |= ActorUpdateFlags.HpTpMp; + updateFlags |= ActorUpdateFlags.HpTpMp; + } } public void AddTP(int tp) { - if (IsAlive()) + if (IsAlive() && tp != 0) { - charaWork.parameterTemp.tp = (short)((charaWork.parameterTemp.tp + tp).Clamp(0, 3000)); + var addTp = charaWork.parameterTemp.tp + tp; + + addTp = addTp.Clamp((int) GetMod(Modifier.MinimumTpLock), 3000); + charaWork.parameterTemp.tp = (short) addTp; tpBase = (ushort)charaWork.parameterTemp.tp; updateFlags |= ActorUpdateFlags.HpTpMp; @@ -661,12 +719,12 @@ namespace FFXIVClassic_Map_Server.Actors //CalculateBaseStats(); } - public void SetStat(uint statId, uint val) + public void SetStat(uint statId, int val) { - charaWork.battleTemp.generalParameter[statId] = (ushort)val; + charaWork.battleTemp.generalParameter[statId] = (short)val; } - public ushort GetStat(uint statId) + public short GetStat(uint statId) { return charaWork.battleTemp.generalParameter[statId]; } @@ -674,7 +732,7 @@ namespace FFXIVClassic_Map_Server.Actors public virtual float GetSpeed() { // todo: for battlenpc/player calculate speed - return GetMod((uint)Modifier.Speed); + return (float) GetMod((uint)Modifier.Speed); } public virtual void OnAttack(State state, BattleAction action, ref BattleAction error) @@ -688,7 +746,7 @@ namespace FFXIVClassic_Map_Server.Actors } // todo: call onAttack/onDamageTaken - BattleUtils.DamageTarget(this, target, action, DamageTakenType.Attack); + //BattleUtils.DamageTarget(this, target, DamageTakenType.Attack, action); AddTP(200); target.AddTP(100); } @@ -704,7 +762,7 @@ namespace FFXIVClassic_Map_Server.Actors if (zone.FindActorInArea(action.targetId) is Character chara) { //BattleUtils.HandleHitType(this, chara, action); - BattleUtils.DoAction(this, chara, action, DamageTakenType.Magic); + //BattleUtils.DoAction(this, chara, action, DamageTakenType.Magic); } } lua.LuaEngine.GetInstance().OnSignal("spellUsed"); @@ -719,14 +777,11 @@ namespace FFXIVClassic_Map_Server.Actors //Should we just store the character insteado f having to find it again? if (zone.FindActorInArea(action.targetId) is Character chara) { - BattleUtils.DoAction(this, chara, action, DamageTakenType.Weaponskill); + //BattleUtils.DoAction(this, chara, action, DamageTakenType.Weaponskill); } } this.DelTP(skill.tpCost); - //Do procs reset on weaponskills? - ResetProcs(); - lua.LuaEngine.GetInstance().OnSignal("weaponskillUsed"); } public virtual void OnAbility(State state, BattleAction[] actions, BattleCommand ability, ref BattleAction[] errors) @@ -735,7 +790,7 @@ namespace FFXIVClassic_Map_Server.Actors { if (zone.FindActorInArea(action.targetId) is Character chara) { - BattleUtils.DoAction(this, chara, action, DamageTakenType.Ability); + //BattleUtils.DoAction(this, chara, action, DamageTakenType.Ability); } } } @@ -755,9 +810,55 @@ namespace FFXIVClassic_Map_Server.Actors } - public virtual void OnDamageTaken(Character attacker, BattleAction action, DamageTakenType damageTakenType) + public virtual void OnDamageDealt(Character defender, BattleAction action, BattleActionContainer actionContainer = null) { + switch (action.hitType) + { + case (HitType.Miss): + OnMiss(this, action, actionContainer); + break; + default: + OnHit(defender, action, actionContainer); + break; + } + //TP is only gained from autoattacks and abilities + if (action.commandType == CommandType.AutoAttack || action.commandType == CommandType.Ability) + { + //TP gained on an attack is usually 100 * delay. + //Store TP seems to add .1% per point. + double weaponDelay = GetMod(Modifier.AttackDelay) / 1000.0; + var storeTPPercent = 1 + (GetMod(Modifier.StoreTP) * 0.1); + AddTP((int)(weaponDelay * 100 * storeTPPercent)); + } + } + + public virtual void OnDamageTaken(Character attacker, BattleAction action, BattleActionContainer actionContainer = null) + { + switch (action.hitType) + { + case (HitType.Miss): + OnEvade(attacker, action, actionContainer); + break; + case (HitType.Parry): + OnParry(attacker, action, actionContainer); + break; + case (HitType.Block): + OnBlock(attacker, action, actionContainer); + break; + } + + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnDamageTaken, "onDamageTaken", attacker, this, action); + + //TP gain formula seems to be something like 5 * e ^ ( -0.667 * [defender's level] ) * damage taken, rounded up + //This should be completely accurate at level 50, but isn't totally accurate at lower levels. + //Don't know if store tp impacts this + double tpModifier = 5 * Math.Pow(Math.E, (-0.0667 * GetLevel())); + AddTP((int)Math.Ceiling(tpModifier * action.amount)); + + + if (charaWork.parameterSave.hp[0] < 1) + Die(Program.Tick, actionContainer); } public UInt64 GetTempVar(string name) @@ -865,29 +966,8 @@ namespace FFXIVClassic_Map_Server.Actors if (val) { StatusEffect procEffect = Server.GetWorldManager().GetStatusEffect(effectId); - procEffect.SetDuration(5000); + procEffect.SetDuration(5); statusEffects.AddStatusEffect(procEffect, this, true, true); - - string procFunc = ""; - - //is there any reason we need this - switch(procId) - { - case (0): - procFunc = "onEvade"; - break; - case (1): - procFunc = "onBlock"; - break; - case (2): - procFunc = "onParry"; - break; - case (3): - procFunc = "onMiss"; - break; - } - - //lua.LuaEngine.CallLuaBattleFunction(this, procFunc, this); } //Otherwise we're reseting a proc, remove the status else @@ -921,9 +1001,124 @@ namespace FFXIVClassic_Map_Server.Actors } //Called when this character evades attacker's action - public void OnEvade(Character attacker, BattleAction action) + public void OnEvade(Character attacker, BattleAction action, BattleActionContainer actionContainer = null) { + SetProc((ushort)HitType.Evade); + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnEvade, "onEvade", attacker, this, action, actionContainer); } + //Called when this character blocks attacker's action + public void OnBlock(Character attacker, BattleAction action, BattleActionContainer actionContainer = null) + { + SetProc((ushort)HitType.Block); + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnBlock, "onBlock", attacker, this, action, actionContainer); + } + + //Called when this character parries attacker's action + public void OnParry(Character attacker, BattleAction action, BattleActionContainer actionContainer = null) + { + SetProc((ushort)HitType.Parry); + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnParry, "onParry", attacker, this, action, actionContainer); + } + + //Called when this character misses + public void OnMiss(Character defender, BattleAction action, BattleActionContainer actionContainer = null) + { + SetProc((ushort)HitType.Miss); + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnMiss, "onMiss", this, defender, action, actionContainer); + } + + public void OnHit(Character defender, BattleAction action, BattleActionContainer actionContainer = null) + { + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnHit, "onHit", this, defender, action, actionContainer); + } + + //The order of messages that appears after using a command is: + + //1. Cast start messages. (ie "You begin casting... ") + //2. Messages from buffs that activate before the command actually starts, like Power Surge or Presence of Mind. (This may be wrong and these could be the same as 4.) + //3. If the command is a multi-hit command, this is where the "You use [command] on [target]" message goes + + //Then, for each hit: + //4. Buffs that activate before a command hits, like Blindside + //5. The hit itself. For single hit commands this message is "Your [command] hits [target] for x damage" for multi hits it's "[Target] takes x points of damage" + //6. Stoneskin falling off + //6. Buffs that activate after a command hits, like Aegis Boon and Divine Veil + + //After all hits + //7. If it's a multi-hit command there's a "{numhits]fold attack..." message or if all hits miss an "All attacks missed" message + //8. Buffs that fall off after the skill ends, like Excruciate + + //For every target defeated: + //8. Defeat message + //9. EXP message + //10. EXP chain message + + + //folder is probably temporary until move to cached scripts is complete + public void DoBattleCommand(BattleCommand command, string folder) + { + //List actions = new List(); + BattleActionContainer actions = new BattleActionContainer(); + + var targets = command.targetFind.GetTargets(); + bool hitTarget = false; + + if (targets.Count > 0) + { + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnCommandStart, "onCommandStart", this, command, actions); + + foreach (var chara in targets) + { + ushort hitCount = 0; + for (int hitNum = 1; hitNum <= command.numHits; hitNum++) + { + var action = new BattleAction(chara.actorId, command, (byte)GetHitDirection(chara), (byte)hitNum); + + //uncached script + lua.LuaEngine.CallLuaBattleCommandFunction(this, command, folder, "onSkillFinish", this, chara, command, action, actions); + //cached script + //skill.CallLuaFunction(owner, "onSkillFinish", this, chara, command, action, actions); + + if (action.hitType > HitType.Evade && action.hitType != HitType.Resist) + { + hitTarget = true; + hitCount++; + } + } + + if (command.numHits > 1) + { + //You use [command] on [target]. + actions.AddAction(new BattleAction(chara.actorId, 30442, 0, 0, (byte)hitCount)); + } + } + + statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnCommandFinish, "onCommandFinish", this, command, actions); + } + else + { + actions.AddAction(new BattleAction(target.actorId, 30202, 0)); + } + + //Now that we know if we hit the target we can check if the combo continues + if (this is Player player && command.commandType == CommandType.WeaponSkill) + if (command.isCombo && hitTarget) + player.SetCombos(command.comboNextCommandId); + else + player.SetCombos(); + + BattleAction error = new BattleAction(actorId, 0, 0); + actions.CombineLists(); + DoBattleAction(command.id, command.battleAnimation, actions.GetList()); + } + + public List GetPartyMembersInRange(uint range) + { + TargetFind targetFind = new TargetFind(this); + targetFind.SetAOEType(ValidTarget.PartyMember, TargetFindAOEType.Circle, TargetFindAOETarget.Self, range); + targetFind.FindWithinArea(this, ValidTarget.PartyMember, TargetFindAOETarget.Self); + return targetFind.GetTargets(); + } } } \ No newline at end of file diff --git a/FFXIVClassic Map Server/actors/chara/Modifier.cs b/FFXIVClassic Map Server/actors/chara/Modifier.cs index 51a45a01..1858ef9d 100644 --- a/FFXIVClassic Map Server/actors/chara/Modifier.cs +++ b/FFXIVClassic Map Server/actors/chara/Modifier.cs @@ -6,60 +6,92 @@ using System.Threading.Tasks; namespace FFXIVClassic_Map_Server.actors.chara { + //These will need to be redone at some point. remember to update tables in db. + //Consider using text_paramname sheet. that matches up with the stats on armor, but some things will need special handling + //Also, 0-35 should probably match with up BattleTemp enum Modifier : UInt32 { - - None = 0, - Hp = 1, - HpPercent = 2, - Mp = 3, - MpPercent = 4, - Tp = 5, - TpPercent = 6, - Regen = 7, - Refresh = 8, - Strength = 9, - Vitality = 10, - Dexterity = 11, - Intelligence = 12, - Mind = 13, - Piety = 14, - Attack = 15, - Accuracy = 16, - Defense = 17, - Evasion = 18, - MagicAttack = 19, - MagicHeal = 20, // is this needed? shouldnt it just be calc'd from mind - MagicAccuracy = 21, - MagicEvasion = 22, - MagicDefense = 23, - MagicEnhancePotency = 24, - MagicEnfeeblingPotency = 25, - ResistFire = 26, - ResistIce = 27, - ResistWind = 28, - ResistLightning = 29, - ResistEarth = 30, - ResistWater = 31, // <3 u jorge - AttackRange = 32, - Speed = 33, - AttackDelay = 34, + NAMEPLATE_SHOWN = 0, + TARGETABLE = 1, + NAMEPLATE_SHOWN2 = 2, + //NAMEPLATE_SHOWN2 = 3, - CraftProcessing = 35, - CraftMagicProcessing = 36, - CraftProcessControl = 37, + Strength = 3, + Vitality = 4, + Dexterity = 5, + Intelligence = 6, + Mind = 7, + Piety = 8, - HarvestPotency = 38, - HarvestLimit = 39, - HarvestRate = 40, + ResistFire = 9, + ResistIce = 10, + ResistWind = 11, + ResistLightning = 12, + ResistEarth = 13, + ResistWater = 14, - Raise = 41, - MinimumHpLock = 42, // hp cannot fall below this value - AttackType = 43, // slashing, piercing, etc - BlockRate = 44, - Block = 45, - CritRating = 46, - HasShield = 47, // Need this because shields are required for blocks. Could have used BlockRate or Block but BlockRate is provided by Gallant Sollerets and Block is provided by some buffs. - HitCount = 48 // Amount of hits in an auto attack. Usually 1, 2 for h2h, 3 with spinning heel + Accuracy = 15, + Evasion = 16, + Attack = 17, + Defense = 18, //Is there a magic defense stat? 19 maybe? + MagicAttack = 23, + MagicHeal = 24, + MagicEnhancePotency = 25, + MagicEnfeeblingPotency = 26, + + MagicAccuracy = 27, + MagicEvasion = 28, + + CraftProcessing = 30, + CraftMagicProcessing = 31, + CraftProcessControl = 32, + + HarvestPotency = 33, + HarvestLimit = 34, + HarvestRate = 35, + + None = 36, + Hp = 37, + HpPercent = 38, + Mp = 39, + MpPercent = 40, + Tp = 41, + TpPercent = 42, + Regen = 43, + Refresh = 44, + + AttackRange = 45, + Speed = 46, + AttackDelay = 47, + + Raise = 48, + MinimumHpLock = 49, // hp cannot fall below this value + AttackType = 50, // slashing, piercing, etc + BlockRate = 51, + Block = 52, + CritRating = 53, + HasShield = 54, // Need this because shields are required for blocks. Could have used BlockRate or Block but BlockRate is provided by Gallant Sollerets and Block is provided by some buffs. + HitCount = 55, // Amount of hits in an auto attack. Usually 1, 2 for h2h, 3 with spinning heel + + //Flat percent increases to these rates. Probably a better way to do this + RawEvadeRate = 56, + RawParryRate = 57, + RawBlockRate = 58, + RawResistRate = 59, + RawHitRate = 60, + RawCritRate = 61, + + DamageTakenDown = 62, // Percent damage taken down + StoreTP = 63, //.1% extra tp per point. Lancer trait is 50 StoreTP + PhysicalCritRate = 64, //CritRating but only for physical attacks. Increases chance of critting. + PhysicalCritEvasion = 65, //Opposite of CritRating. Reduces chance of being crit by phyiscal attacks + PhysicalCritAttack = 66, //Increases damage done by Physical Critical hits + PhysicalCritResilience = 67, //Decreases damage taken by Physical Critical hits + Parry = 68, //Increases chance to parry + MagicCritPotency = 69, //Increases + Regain = 70, //TP regen, should be -90 out of combat, Invigorate sets to 100+ depending on traits + RegenDown = 71, //Damage over time effects. Separate from normal Regen because of how they are displayed in game + Stoneskin = 72, //Nullifies damage + MinimumTpLock = 73 } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs b/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs index dc00a505..806dbf39 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs @@ -6,7 +6,7 @@ using System.Text; using System.Threading.Tasks; using FFXIVClassic_Map_Server.actors.chara.player; using FFXIVClassic.Common; -using FFXIVClassic_Map_Server.packets.send.actor; +using FFXIVClassic_Map_Server.packets.send.actor.battle; using FFXIVClassic_Map_Server.actors.chara.ai.utils; using MoonSharp.Interpreter; @@ -62,6 +62,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai SongMagic = 8 } + + //What type of command it is + [Flags] + public enum CommandType : ushort + { + //Type of action + None = 0, + AutoAttack = 1, + WeaponSkill = 2, + Ability =3, + Spell = 4 + } + class BattleCommand { public ushort id; @@ -96,13 +109,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai public int aoeRange; //size of aoe effect. (how will this work for box aoes?) public int[] comboNextCommandId = new int[2]; //next two skills in a combo public short comboStep; //Where in a combo string this skill is + public CommandType commandType; + public ActionProperty actionProperty; + public ActionType actionType; - public byte statusTier; //tief of status to put on target + public byte statusTier; //tier of status to put on target + public ulong statusMagnitude = 0; //magnitude of status to put on target public ushort basePotency; //damage variable public float enmityModifier; //multiples by damage done to get final enmity public float accuracyModifier; //modifies accuracy + public float bonusCritRate; //extra crit rate public bool isCombo; + public bool isRanged; + + public bool actionCrit; //Whether any actions were critical hits, used for Excruciate + public lua.LuaScript script; //cached script public TargetFind targetFind; @@ -114,7 +136,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai this.name = name; this.range = 0; this.enmityModifier = 1; - this.accuracyModifier = 1; + this.accuracyModifier = 0; this.statusTier = 1; this.statusChance = 50; this.recastTimeMs = (uint) maxRecastTimeSeconds * 1000; @@ -153,7 +175,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai public bool IsValidMainTarget(Character user, Character target) { targetFind = new TargetFind(user); - + if (aoeType == TargetFindAOEType.Box) { targetFind.SetAOEBox(validTarget, aoeTarget, range, aoeRange); @@ -163,7 +185,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai targetFind.SetAOEType(validTarget, aoeType, aoeTarget, range, aoeRange); } - /* worldMasterTextId 32512 cannot be performed on a KO'd target. @@ -191,7 +212,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { if (user is Player) ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32527, 0x20, (uint)id); - return false; + //return false; } //Proc requirement @@ -362,5 +383,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return target; } + + public ushort GetCommandType() + { + return (ushort) commandType; + } } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/BattleTrait.cs b/FFXIVClassic Map Server/actors/chara/ai/BattleTrait.cs new file mode 100644 index 00000000..f8f41b48 --- /dev/null +++ b/FFXIVClassic Map Server/actors/chara/ai/BattleTrait.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.actors.chara.ai +{ + class BattleTrait + { + public ushort id; + public string name; + public byte job; + public byte level; + public uint modifier; + public int bonus; + + public BattleTrait(ushort id, string name, byte job, byte level, uint modifier, int bonus) + { + this.id = id; + this.name = name; + this.job = job; + this.level = level; + this.modifier = modifier; + this.bonus = bonus; + } + } +} diff --git a/FFXIVClassic Map Server/actors/chara/ai/StatusEffect.cs b/FFXIVClassic Map Server/actors/chara/ai/StatusEffect.cs index 34b64bf3..83c16e40 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/StatusEffect.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/StatusEffect.cs @@ -8,13 +8,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using MoonSharp.Interpreter; +using FFXIVClassic.Common; namespace FFXIVClassic_Map_Server.actors.chara.ai { enum StatusEffectId : uint { RageofHalone = 221021, - + Quick = 223001, Haste = 223002, Slow = 223003, @@ -99,7 +100,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai Retaliation = 223082, Foresight = 223083, Defender = 223084, - Rampage = 223085, + Rampage = 223085, //old effect Enraged = 223086, Warmonger = 223087, Disorientx1 = 223088, @@ -119,10 +120,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai LifeSap = 223102, Farshot = 223103, QuellingStrike = 223104, - RagingStrike = 223105, + RagingStrike = 223105, //old effect HawksEye = 223106, SubtleRelease = 223107, - Decoy = 223108, + Decoy = 223108, //Untraited Profundity = 223109, TranceChant = 223110, RoamingSoul = 223111, @@ -140,10 +141,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai ConcussiveBlowx2 = 223124, ConcussiveBlowx3 = 223125, SkullSunder = 223126, - Bloodletter = 223127, + Bloodletter = 223127, //comboed effect Levinbolt = 223128, - Protect = 223129, - Shell = 223130, + Protect = 223129, //old Protect + Shell = 223130, //old shell Reraise = 223131, ShockSpikes = 223132, Stoneskin = 223133, @@ -219,8 +220,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai StealthIV = 223204, Combo = 223205, GoringBlade = 223206, - Berserk2 = 223207, - Rampage2 = 223208, + Berserk2 = 223207, //new effect + Rampage2 = 223208, //new effect FistsofFire = 223209, FistsofEarth = 223210, FistsofWind = 223211, @@ -249,10 +250,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai Aero = 223235, Outmaneuver2 = 223236, Blindside2 = 223237, - Decoy2 = 223238, - Protect2 = 223239, + Decoy2 = 223238, //Traited + Protect2 = 223239, //new Protect SanguineRite3 = 223240, - Bloodletter2 = 223241, + Bloodletter2 = 223241, //uncomboed effect FullyBlissfulMind = 223242, MagicEvasionDown = 223243, HundredFists = 223244, @@ -327,46 +328,54 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai EvadeProc = 253003, BlockProc = 253004, ParryProc = 253005, - MissProc = 253006 + MissProc = 253006, + EXPChain = 253007 } [Flags] enum StatusEffectFlags : uint { None = 0, - Silent = 1 << 0, // dont display effect loss message + Silent = 1 << 0, // dont display effect loss message //Loss flags - LoseOnDeath = 1 << 1, // effects removed on death - LoseOnZoning = 1 << 2, // effects removed on zoning - LoseOnEsuna = 1 << 3, // effects which can be removed with esuna (debuffs) - LoseOnDispel = 1 << 4, // some buffs which player might be able to dispel from mob - LoseOnLogout = 1 << 5, // effects removed on logging out - LoseOnAttacking = 1 << 6, // effects removed when owner attacks another entity - LoseOnCasting = 1 << 7, // effects removed when owner starts casting - LoseOnDamageTaken = 1 << 8, // effects removed when owner takes damage - LoseOnParry = 1 << 9, // effects removed when owner parries an attack (foresight) - LoseOnEvade = 1 << 10, // effects removed when owner evades an attack (decoy) - LoseOnCrit = 1 << 11, // effects removed when owner deals a critical hit (excruciate) - LoseOnAggro = 1 << 12, // effects removed when owner gains enmity (swiftsong) + LoseOnDeath = 1 << 1, // effects removed on death + LoseOnZoning = 1 << 2, // effects removed on zoning + LoseOnEsuna = 1 << 3, // effects which can be removed with esuna (debuffs) + LoseOnDispel = 1 << 4, // some buffs which player might be able to dispel from mob + LoseOnLogout = 1 << 5, // effects removed on logging out + LoseOnAttacking = 1 << 6, // effects removed when owner attacks another entity + LoseOnCastStart = 1 << 7, // effects removed when owner starts casting + LoseOnAggro = 1 << 8, // effects removed when owner gains enmity (swiftsong) - //Activate flags, do we need the LoseOn flags if we have these? could just remove itself in the activate function - ActivateOnAttack = 1 << 13, - ActivateOnSpell = 1 << 14, - ActivateOnDamageTaken = 1 << 15, - ActivateOnBlock = 1 << 16, - ActivateOnMiss = 1 << 17, + //Activate flags + ActivateOnCastStart = 1 << 9, //Activates when a cast starts. + ActivateOnCommandStart = 1 << 10, //Activates when a command is used, before iterating over targets. Used for things like power surge, excruciate. + ActivateOnCommandFinish = 1 << 11, //Activates when the command is finished, after all targets have been iterated over. Used for things like Excruciate and Resonance falling off. + ActivateOnPreactionTarget = 1 << 12, //Activates after initial rates are calculated for an action against owner + ActivateOnPreactionCaster = 1 << 13, //Activates after initial rates are calculated for an action by owner + ActivateOnDamageTaken = 1 << 14, + ActivateOnHealed = 1 << 15, + + //Should these be rolled into DamageTaken? + ActivateOnMiss = 1 << 16, //Activates when owner misses + ActivateOnEvade = 1 << 17, //Activates when owner evades + ActivateOnParry = 1 << 18, //Activates when owner parries + ActivateOnBlock = 1 << 19, //Activates when owner evades + ActivateOnHit = 1 << 20, //Activates when owner hits + ActivateOnCrit = 1 << 21, //Activates when owner crits //Prevent flags. Sleep/stun/petrify/etc combine these - PreventSpell= 1 << 18, // effects which prevent using spells, such as silence - PreventWeaponSkill = 1 << 19, // effects which prevent using weaponskills, such as pacification - PreventAbility = 1 << 20, // effects which prevent using abilities, such as amnesia - PreventAttack = 1 << 21, // effects which prevent basic attacks - PreventMovement = 1 << 22, // effects which prevent movement such as bind, still allows turning in place - PreventTurn = 1 << 23, // effects which prevent turning such as fixation, still allows movement and actions + PreventSpell = 1 << 22, // effects which prevent using spells, such as silence + PreventWeaponSkill = 1 << 23, // effects which prevent using weaponskills, such as pacification + PreventAbility = 1 << 24, // effects which prevent using abilities, such as amnesia + PreventAttack = 1 << 25, // effects which prevent basic attacks + PreventMovement = 1 << 26, // effects which prevent movement such as bind, still allows turning in place + PreventTurn = 1 << 27, // effects which prevent turning, such as stun + PreventUntarget = 1 << 28, // effects which prevent changing targets, such as fixation - Stealth = 1 << 24, // sneak/invis - Stance = 1 << 25, // effects that do not have a timer + Stealth = 1 << 29, // sneak/invis + Stance = 1 << 30, // effects that do not have a timer } enum StatusEffectOverwrite : byte @@ -380,18 +389,18 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai class StatusEffect { // todo: probably use get;set; - private Character owner; private Character source; private StatusEffectId id; private string name; // name of this effect private DateTime startTime; // when was this effect added + private DateTime endTime; // when this status falls off private DateTime lastTick; // when did this effect last tick private uint duration; // how long should this effect last in seconds private uint tickMs; // how often should this effect proc - private UInt64 magnitude; // a value specified by scripter which is guaranteed to be used by all effects + private double magnitude; // a value specified by scripter which is guaranteed to be used by all effects private byte tier; // same effect with higher tier overwrites this - private UInt64 extra; // optional value + private double extra; // optional value private StatusEffectFlags flags; // death/erase/dispel etc private StatusEffectOverwrite overwrite; // how to handle adding an effect with same id (see StatusEfectOverwrite) private bool silent = false; // do i send a message on losing effect @@ -400,7 +409,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai HitEffect animationEffect; - public StatusEffect(Character owner, uint id, UInt64 magnitude, uint tickMs, uint duration, byte tier = 0) + public StatusEffect(Character owner, uint id, double magnitude, uint tickMs, uint duration, byte tier = 0) { this.owner = owner; this.source = owner; @@ -448,10 +457,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (tickMs != 0 && (tick - lastTick).TotalMilliseconds >= tickMs) { lastTick = tick; - LuaEngine.CallLuaStatusEffectFunction(this.owner, this, "onTick", this.owner, this); + if (LuaEngine.CallLuaStatusEffectFunction(this.owner, this, "onTick", this.owner, this) > 0) + return true; } - if (duration != 0xFFFFFFFF && (tick - startTime).TotalSeconds >= duration) + if (duration >= 0 && tick >= endTime) { return true; } @@ -463,6 +473,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai DynValue res = new DynValue(); + return lua.LuaEngine.CallLuaStatusEffectFunction(chara, this, functionName, args); if (!script.Globals.Get(functionName).IsNil()) { res = script.Call(script.Globals.Get(functionName), args); @@ -470,7 +481,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return (int)res.Number; } - return -1; } public Character GetOwner() @@ -498,6 +508,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return startTime; } + public DateTime GetEndTime() + { + return endTime; + } + public string GetName() { return name; @@ -513,7 +528,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return tickMs; } - public UInt64 GetMagnitude() + public double GetMagnitude() { return magnitude; } @@ -523,7 +538,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return tier; } - public UInt64 GetExtra() + public double GetExtra() { return extra; } @@ -554,6 +569,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai this.lastTick = time; } + public void SetEndTime(DateTime time) + { + endTime = time; + } + + //Refresh the status, updating the end time based on the duration of the status and broadcasts the new time + public void RefreshTime() + { + endTime = DateTime.Now.AddSeconds(GetDuration()); + int index = Array.IndexOf(owner.charaWork.status, GetStatusId()); + + if (index >= 0) + owner.statusEffects.SetTimeAtIndex(index, (uint) Utils.UnixTimeStampUTC(endTime)); + } + public void SetOwner(Character owner) { this.owner = owner; @@ -569,7 +599,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai this.name = name; } - public void SetMagnitude(UInt64 magnitude) + public void SetMagnitude(double magnitude) { this.magnitude = magnitude; } @@ -589,7 +619,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai this.tier = tier; } - public void SetExtra(UInt64 val) + public void SetExtra(double val) { this.extra = val; } diff --git a/FFXIVClassic Map Server/actors/chara/ai/StatusEffectContainer.cs b/FFXIVClassic Map Server/actors/chara/ai/StatusEffectContainer.cs index ed23ba03..c9f9cbe5 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/StatusEffectContainer.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/StatusEffectContainer.cs @@ -21,22 +21,36 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai private readonly Dictionary effects; public static readonly int MAX_EFFECTS = 20; private bool sendUpdate = false; + private DateTime lastTick;// Do all effects tick at the same time like regen? + private List statusSubpackets; + private ActorPropertyPacketUtil statusTimerPropPacketUtil; public StatusEffectContainer(Character owner) { this.owner = owner; this.effects = new Dictionary(); + statusSubpackets = new List(); + statusTimerPropPacketUtil = new ActorPropertyPacketUtil("charawork/Status", owner); } public void Update(DateTime tick) { + //Regen/Refresh/Regain effects tick every 3 seconds + if ((DateTime.Now - lastTick).Seconds >= 3) + { + RegenTick(tick); + lastTick = DateTime.Now; + } // list of effects to remove + + // if (owner is Player) UpdateTimeAtIndex(4, 4294967295); var removeEffects = new List(); - foreach (var effect in effects.Values) + for (int i = 0; i < effects.Values.Count; i++) { // effect's update function returns true if effect has completed - if (effect.Update(tick)) - removeEffects.Add(effect); + if (effects.Values.ElementAt(i).Update(tick)) + removeEffects.Add(effects.Values.ElementAt(i)); + } // remove effects from this list @@ -52,6 +66,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai } } + //regen/refresh/regain + public void RegenTick(DateTime tick) + { + ushort dotTick = (ushort) owner.GetMod(Modifier.RegenDown); + ushort regenTick = (ushort) owner.GetMod(Modifier.Regen); + ushort refreshtick = (ushort) owner.GetMod(Modifier.Refresh); + short regainTick = (short) owner.GetMod(Modifier.Regain); + + //DoTs tick before regen and the full dot damage is displayed, even if some or all of it is nullified by regen. Only effects like stoneskin actually alter the number shown + if (dotTick > 0) + { + BattleAction action = new BattleAction(owner.actorId, 30331, (uint)(HitEffect.HitEffectType | HitEffect.Hit), dotTick); + utils.BattleUtils.HandleStoneskin(owner, action); + // todo: figure out how to make red numbers appear for enemies getting hurt by dots + owner.DelHP(action.amount); + + owner.DoBattleAction(0, 0, action); + } + + //DoTs are the only effect to show numbers, so that doesnt need to be handled for these + owner.AddHP(regenTick); + owner.AddMP(refreshtick); + owner.AddTP(regainTick); + } + public bool HasStatusEffect(uint id) { return effects.ContainsKey(id); @@ -62,7 +101,43 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return effects.ContainsKey((uint)id); } - public bool AddStatusEffect(uint id, UInt64 magnitude, uint tickMs, uint duration, byte tier = 0) + public BattleAction AddStatusForBattleAction(uint id, byte tier = 1) + { + BattleAction action = null; + + if (AddStatusEffect(id, tier)) + action = new BattleAction(owner.actorId, 30328, id | (uint)HitEffect.StatusEffectType); + + return action; + } + + public bool AddStatusEffect(uint id) + { + var se = Server.GetWorldManager().GetStatusEffect(id); + + return AddStatusEffect(se, owner); + } + + public bool AddStatusEffect(uint id, byte tier) + { + var se = Server.GetWorldManager().GetStatusEffect(id); + + se.SetTier(tier); + + return AddStatusEffect(se, owner); + } + + public bool AddStatusEffect(uint id, byte tier, UInt64 magnitude) + { + var se = Server.GetWorldManager().GetStatusEffect(id); + + se.SetMagnitude(magnitude); + se.SetTier(tier); + + return AddStatusEffect(se, owner); + } + + public bool AddStatusEffect(uint id, byte tier, UInt64 magnitude, uint duration, int tickMs = 3000) { var se = Server.GetWorldManager().GetStatusEffect(id); if (se != null) @@ -71,7 +146,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai se.SetStartTime(DateTime.Now); se.SetOwner(owner); } - return AddStatusEffect(se ?? new StatusEffect(this.owner, id, magnitude, tickMs, duration, tier), owner); + return AddStatusEffect(se ?? new StatusEffect(this.owner, id, magnitude, 3000, duration, tier), owner); } public bool AddStatusEffect(StatusEffect newEffect, Character source, bool silent = false, bool hidden = false) @@ -82,12 +157,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai 32002 [@SHEET(xtx/status,$E8(11),3)] fails to take effect. */ - if (HasStatusEffect(newEffect.GetStatusEffectId()) && (newEffect.GetFlags() & (uint)StatusEffectFlags.Stance) != 0) - { - RemoveStatusEffect(newEffect); - return false; - } - var effect = GetStatusEffectById(newEffect.GetStatusEffectId()); bool canOverwrite = false; @@ -112,6 +181,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai effects.Remove(newEffect.GetStatusEffectId()); newEffect.SetStartTime(DateTime.Now); + newEffect.SetEndTime(DateTime.Now.AddSeconds(newEffect.GetDuration())); newEffect.SetOwner(owner); if (effects.Count < MAX_EFFECTS) @@ -127,22 +197,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (!newEffect.GetHidden()) { int index = 0; + + //If effect is already in the list of statuses, get that index, otherwise find the first open index if (owner.charaWork.status.Contains(newEffect.GetStatusId())) index = Array.IndexOf(owner.charaWork.status, newEffect.GetStatusId()); else index = Array.IndexOf(owner.charaWork.status, (ushort) 0); - owner.charaWork.status[index] = newEffect.GetStatusId(); - + //owner.charaWork.status[index] = newEffect.GetStatusId(); + SetStatusAtIndex(index, newEffect.GetStatusId()); //Stance statuses need their time set to an extremely high number so their icon doesn't flash //Adding getduration with them doesn't work because it overflows - uint time = (newEffect.GetFlags() & (uint) StatusEffectFlags.Stance) == 0 ? Utils.UnixTimeStampUTC() + (newEffect.GetDuration()) : 0xFFFFFFFF; - owner.charaWork.statusShownTime[index] = time; - this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(this.owner.actorId, (ushort)index, (ushort)newEffect.GetStatusId())); - } - - { - owner.zone.BroadcastPacketsAroundActor(owner, owner.GetActorStatusPackets()); + uint time = (newEffect.GetFlags() & (uint) StatusEffectFlags.Stance) == 0 ? Utils.UnixTimeStampUTC(newEffect.GetEndTime()) : 0xFFFFFFFF; + SetTimeAtIndex(index, time); + //owner.charaWork.statusShownTime[index] = time; + //owner.zone.BroadcastPacketAroundActor(owner, SetActorStatusPacket.BuildPacket(owner.actorId, (ushort)index, newEffect.GetStatusId())); + //owner.zone.BroadcastPacketsAroundActor(owner, owner.GetActorStatusPackets()); } owner.RecalculateStats(); } @@ -151,14 +221,15 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return false; } - public void RemoveStatusEffect(StatusEffect effect, bool silent = false) + public bool RemoveStatusEffect(StatusEffect effect, bool silent = false) { - if (effect != null && effects.ContainsKey(effect.GetStatusEffectId()) ) + bool removedEffect = false; + if (effect != null && effects.ContainsKey(effect.GetStatusEffectId())) { // send packet to client with effect remove message - if (!silent && !effect.GetSilent() || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0) + if (!silent && !effect.GetSilent() && (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0) { - // todo: send packet to client with effect added message + owner.DoBattleAction(0, 0, new BattleAction(owner.actorId, 30331, effect.GetStatusEffectId())); } //hidden effects not in charawork @@ -178,25 +249,52 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect); owner.RecalculateStats(); sendUpdate = true; + removedEffect = true; } + + return removedEffect; } - public void RemoveStatusEffect(uint effectId, bool silent = false) + public bool RemoveStatusEffect(uint effectId, bool silent = false) { + bool removedEffect = false; foreach (var effect in effects.Values) { if (effect.GetStatusEffectId() == effectId) { RemoveStatusEffect(effect, effect.GetSilent() || silent); + removedEffect = true; break; } } + + return removedEffect; + } + + + //Remove status effect and return the battleaction message instead of sending it immediately + public BattleAction RemoveStatusEffectForBattleAction(uint effectId, ushort worldMasterTextId = 30331) + { + BattleAction action = null; + if (RemoveStatusEffect(effectId, true)) + action = new BattleAction(owner.actorId, worldMasterTextId, effectId); + + return action; + } + + //Remove status effect and return the battleaction message instead of sending it immediately + public BattleAction RemoveStatusEffectForBattleAction(StatusEffect effect, ushort worldMasterTextId = 30331) + { + BattleAction action = null; + if (RemoveStatusEffect(effect, true)) + action = new BattleAction(owner.actorId, worldMasterTextId, effect.GetStatusEffectId()); + return action; } public StatusEffect CopyEffect(StatusEffect effect) { - var newEffect = new StatusEffect(this.owner, effect); - newEffect.SetOwner(this.owner); + var newEffect = new StatusEffect(owner, effect); + newEffect.SetOwner(owner); // todo: should source be copied too? return AddStatusEffect(newEffect, effect.GetSource()) ? newEffect : null; } @@ -204,10 +302,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai public bool RemoveStatusEffectsByFlags(uint flags, bool silent = false) { // build list of effects to remove - var removeEffects = new List(); - foreach (var effect in effects.Values) - if ((effect.GetFlags() & flags) != 0) - removeEffects.Add(effect); + var removeEffects = GetStatusEffectsByFlag(flags); // remove effects from main list foreach (var effect in removeEffects) @@ -231,12 +326,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { var list = new List(); foreach (var effect in effects.Values) - { if ((effect.GetFlags() & flag) != 0) - { list.Add(effect); - } - } + return list; } @@ -268,5 +360,88 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai Database.SavePlayerStatusEffects((Player)owner); } } + + public void CallLuaFunctionByFlag(uint flag, string function, params object[] args) + { + var effects = GetStatusEffectsByFlag(flag); + + object[] argsWithEffect = new object[args.Length + 1]; + + for (int i = 0; i < args.Length; i++) + argsWithEffect[i + 1] = args[i]; + + foreach (var effect in effects) + { + argsWithEffect[0] = effect; + effect.CallLuaFunction(owner, function, argsWithEffect); + } + } + + //Sets the status id at an index. + //Changing a status to another doesn't seem to work. If updating an index that already has an effect, set it to 0 first then to the correct status + public void SetStatusAtIndex(int index, ushort statusId) + { + owner.charaWork.status[index] = statusId; + //owner.zone.BroadcastPacketAroundActor(owner, SetActorStatusPacket.BuildPacket(owner.actorId, (ushort)index, statusId)); + + statusSubpackets.Add(SetActorStatusPacket.BuildPacket(owner.actorId, (ushort)index, statusId)); + owner.updateFlags |= ActorUpdateFlags.Status; + } + + public void SetTimeAtIndex(int index, uint time) + { + owner.charaWork.statusShownTime[index] = time; + statusTimerPropPacketUtil.AddProperty($"charaWork.statusShownTime[{index}]"); + owner.updateFlags |= ActorUpdateFlags.StatusTime; + } + + public List GetStatusPackets() + { + return statusSubpackets; + } + + public List GetStatusTimerPackets() + { + return statusTimerPropPacketUtil.Done(); + } + + public void ResetPropPacketUtil() + { + statusTimerPropPacketUtil = new ActorPropertyPacketUtil("charaWork/status", owner); + } + + //Overwrites effectToBeReplaced with a new status effect + //Returns the message of the new effect being added + //Doing this instead of simply calling remove then add so that the new effect is in the same slot as the old one + //There should be a better way to do this + //Currently causes the icons to blink whenb eing rpelaced + public BattleAction ReplaceEffect(StatusEffect effectToBeReplaced, uint newEffectId, byte tier, double magnitude, uint duration) + { + StatusEffect newEffect = Server.GetWorldManager().GetStatusEffect(newEffectId); + newEffect.SetTier(tier); + newEffect.SetMagnitude(magnitude); + newEffect.SetDuration(duration); + newEffect.SetOwner(effectToBeReplaced.GetOwner()); + effectToBeReplaced.CallLuaFunction(owner, "onLose", owner, effectToBeReplaced); + newEffect.CallLuaFunction(owner, "onGain", owner, newEffect); + effects.Remove(effectToBeReplaced.GetStatusEffectId()); + + newEffect.SetStartTime(DateTime.Now); + newEffect.SetEndTime(DateTime.Now.AddSeconds(newEffect.GetDuration())); + uint time = (newEffect.GetFlags() & (uint)StatusEffectFlags.Stance) == 0 ? Utils.UnixTimeStampUTC(newEffect.GetEndTime()) : 0xFFFFFFFF; + int index = Array.IndexOf(owner.charaWork.status, effectToBeReplaced.GetStatusId()); + + //owner.charaWork.status[index] = newEffect.GetStatusId(); + owner.charaWork.statusShownTime[index] = time; + effects[newEffectId] = newEffect; + + SetStatusAtIndex(index, 0); + + //charawork/status + SetStatusAtIndex(index, (ushort) (newEffectId - 200000)); + SetTimeAtIndex(index, time); + + return new BattleAction(owner.actorId, 30328, (uint) HitEffect.StatusEffectType | newEffectId); + } } -} +} \ No newline at end of file diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs index e36aec88..a83d130d 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/BattleNpcController.cs @@ -149,11 +149,15 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers public override void Cast(Character target, uint spellId) { // todo: + if(owner.aiContainer.CanChangeState()) + owner.aiContainer.InternalCast(target, spellId); } public override void Ability(Character target, uint abilityId) { // todo: + if (owner.aiContainer.CanChangeState()) + owner.aiContainer.InternalAbility(target, abilityId); } public override void RangedAttack(Character target) @@ -211,7 +215,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers return; } owner.SetMod((uint)Modifier.Speed, 5); - if ((tick - lastCombatTickScript).TotalSeconds > 3)//Program.Random.Next(10, 15)) + if ((tick - lastCombatTickScript).TotalSeconds > 3) { Move(); //if (owner.aiContainer.CanChangeState()) diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs index 975fd417..1505d453 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs @@ -21,6 +21,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers public override void Update(DateTime tick) { + /* if (owner.newMainState != owner.currentMainState) { if (owner.newMainState == SetActorStatePacket.MAIN_STATE_ACTIVE) @@ -32,7 +33,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers owner.Disengage(); } owner.currentMainState = (ushort)owner.newMainState; - } + }*/ } public override void ChangeTarget(Character target) diff --git a/FFXIVClassic Map Server/actors/chara/ai/helpers/TargetFind.cs b/FFXIVClassic Map Server/actors/chara/ai/helpers/TargetFind.cs index 9f2f6048..91896b5e 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/helpers/TargetFind.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/helpers/TargetFind.cs @@ -172,7 +172,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai // todo: this is stupid bool withPet = (flags & ValidTarget.Ally) != 0 || masterTarget.allegiance != owner.allegiance; - if (masterTarget != null) + if (masterTarget != null && CanTarget(masterTarget)) targets.Add(masterTarget); if (aoeType != TargetFindAOEType.None) @@ -237,8 +237,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai }*/ - if (targets.Count > 16) - targets.RemoveRange(16, targets.Count - 16); + if (targets.Count > 8) + targets.RemoveRange(8, targets.Count - 8); + + //Curaga starts with lowest health players, so the targets are definitely sorted at least for some abilities + //Other aoe abilities might be sorted by distance? + //Protect is random + targets.Sort(delegate (Character a, Character b) { return a.GetHP().CompareTo(b.GetHP()); }); } /// @@ -351,6 +356,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (target == null || !retarget && targets.Contains(target)) return false; + if ((validTarget & ValidTarget.Player) != 0 && target is Player) + return true; + + if ((validTarget & ValidTarget.PartyMember) != 0 && target.currentParty == owner.currentParty) + return true; + // cant target dead if ((validTarget & ValidTarget.Corpse) == 0 && target.IsDead()) return false; @@ -361,7 +372,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if ((validTarget & ValidTarget.Enemy) != 0 && target.allegiance == owner.allegiance) return false; - if ((validTarget & ValidTarget.PartyMember) == 0 && target.currentParty == owner.currentParty) + if (((validTarget & ValidTarget.PartyMember) == 0) && ((validTarget & ValidTarget.Self) == 0) && target.currentParty == owner.currentParty) return false; if ((validTarget & ValidTarget.PartyMember) != 0 && target.currentParty != owner.currentParty) @@ -384,6 +395,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (validTarget == ValidTarget.Self && aoeType == TargetFindAOEType.None && owner != target) return false; + if ((validTarget & ValidTarget.Self) == 0 && target == owner) + return false; + // this is fuckin retarded, think of a better way l8r if (!ignoreAOE) { diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/AbilityState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/AbilityState.cs index 27e25452..23f306c8 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/AbilityState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/AbilityState.cs @@ -48,15 +48,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state else { //owner.LookAt(target); - - //If owner already has this status effect and it's a stance that gets removed on reuse, remove it and don't continue - var effect = owner.statusEffects.GetStatusEffectById(skill.statusId); - if (effect!= null && (effect.GetFlags() & (uint) StatusEffectFlags.Stance) != 0) - { - owner.statusEffects.RemoveStatusEffect(effect); - interrupt = true; - } - } } @@ -101,35 +92,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget); isCompleted = true; - var targets = skill.targetFind.GetTargets(); - - List actions = new List(); - List effects = owner.statusEffects.GetStatusEffectsByFlag((uint)StatusEffectFlags.ActivateOnAttack); - - foreach (var chara in targets) - { - for (int hitNum = 0; hitNum < skill.numHits; hitNum++) - { - //30328 - Your [ability] grants you the effect of [status] - //30320 - You use [ability]. You recover x HP. - var action = new BattleAction(chara.actorId, skill.worldMasterTextId, 0, 0, 1, 1); - //uncached - lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "ability", "onAbilityFinish", owner, target, skill, action); - //cached - //skill.CallLuaFunction(owner, "onAbilityFinish", owner, target, skill, action); - - //if hit type isn't evade or miss - if (((action.hitType & HitType.Evade) | (action.hitType & HitType.Miss)) == 0) - hitTarget = true; - - actions.AddRange(action.GetAllActions()); - } - } - // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action - BattleAction[] errors = (BattleAction[])actions.ToArray().Clone(); - owner.OnAbility(this, actions.ToArray(), skill, ref errors); - owner.DoBattleAction(skill.id, skill.battleAnimation, actions); + owner.DoBattleCommand(skill, "ability"); } public override void TryInterrupt() diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs index cc72b8c8..2319db0a 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs @@ -32,9 +32,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state public override bool Update(DateTime tick) { - if ((target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget) && owner.isAutoAttackEnabled) - owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea(owner.currentLockedTarget)); + owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea(owner.currentTarget)); if (target == null || target.IsDead()) { @@ -101,25 +100,30 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state // handle paralyze/intimidate/sleep/whatever in Character.OnAttack - List actions = new List(); + // todo: Change this to use a BattleCommand like the other states + + //List actions = new List(); + BattleActionContainer actions = new BattleActionContainer(); + target.SetMod((uint) Modifier.MinimumHpLock, 0); var i = 0; - for (int hitNum = 0; hitNum < owner.GetMod((uint) Modifier.HitCount); hitNum++) + for (int hitNum = 0; hitNum < 1 /* owner.GetMod((uint) Modifier.HitCount)*/; hitNum++) { BattleAction action = new BattleAction(target.actorId, 0x765D, (uint)HitEffect.Hit, 100, (byte)HitDirection.None, (byte) hitNum); - action.battleActionType = BattleActionType.AttackPhysical; + action.commandType = CommandType.AutoAttack; + action.actionType = ActionType.Physical; + action.actionProperty = (ActionProperty) owner.GetMod(Modifier.AttackType); // evasion, miss, dodge, etc to be handled in script, calling helpers from scripts/weaponskills.lua // temporary evade/miss/etc function to test hit effects - utils.BattleUtils.CalcHitType(owner, target, null, action); - actions.AddRange(action.GetAllActions()); + action.DoAction(owner, target, null, actions); } // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action - BattleAction[] errors = (BattleAction[])actions.ToArray().Clone(); - - owner.OnAttack(this, actions[0], ref errorResult); - owner.DoBattleAction(22104, 0x19001000, actions); - target.SetMod((uint) Modifier.MinimumHpLock, 0); + BattleAction[] errors = (BattleAction[])actions.GetList().ToArray().Clone(); + BattleAction error = null;// new BattleAction(0, null, 0, 0); + //owner.DoActions(null, actions.GetList(), ref error); + //owner.OnAttack(this, actions[0], ref errorResult); + owner.DoBattleAction(22104, 0x19001000, actions.GetList()); } public override void TryInterrupt() @@ -148,7 +152,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state private bool CanAttack() { - if (!owner.isAutoAttackEnabled) + if (!owner.isAutoAttackEnabled || target.allegiance == owner.allegiance) { return false; } diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs index e3c6c1cc..14766969 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs @@ -64,6 +64,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onCombo", owner, target, spell); spell.isCombo = true; } + + //Modify spell based on status effects. Need to do it here because they can modify cast times + List effects = owner.statusEffects.GetStatusEffectsByFlag((uint) (StatusEffectFlags.ActivateOnCastStart)); + + //modify skill based on status effects + foreach (var effect in effects) + lua.LuaEngine.CallLuaStatusEffectFunction(owner, effect, "onMagicCast", owner, effect, spell); + if (!spell.IsInstantCast()) { // command casting duration @@ -124,50 +132,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state isCompleted = true; var targets = spell.targetFind.GetTargets(); - - List actions = new List(); - if (targets.Count > 0) - { - List effects = owner.statusEffects.GetStatusEffectsByFlag((uint)StatusEffectFlags.ActivateOnSpell); - - //modify skill based on status effects - foreach (var effect in effects) - lua.LuaEngine.CallLuaStatusEffectFunction(owner, effect, "onWeaponSkill", owner, effect, spell); - - //Now that combos and positionals bonuses are done, we can calculate hits/crits/etc and damage - foreach (var chara in targets) - { - for (int hitNum = 0; hitNum < spell.numHits; hitNum++) - { - var action = new BattleAction(chara.actorId, spell.worldMasterTextId, 0, 0, (byte) hitDir, (byte) hitNum); - lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicFinish", owner, chara, spell, action); - - //if hit type isn't evade or miss - if (action.hitType > HitType.Evade) - hitTarget = true; - - actions.AddRange(action.GetAllActions()); - } - } - } - else - { - //No targets hit, cast failed - actions.Add(new BattleAction(target.actorId, 30202, (uint) (0))); - } - - - // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action - BattleAction[] errors = (BattleAction[])actions.ToArray().Clone(); - owner.OnCast(this, actions.ToArray(), spell, ref errors); - owner.DoBattleAction(spell.id, spell.battleAnimation, actions); - owner.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnCasting); - //Now that we know if we hit the target we can check if the combo continues - if (owner is Player player) - if (spell.isCombo && hitTarget) - player.SetCombos(spell.comboNextCommandId); - else - player.SetCombos(); + owner.DoBattleCommand(spell, "magic"); } public override void TryInterrupt() diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs index a8c3c15e..d0bf7121 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs @@ -77,7 +77,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state } } } - } } @@ -118,55 +117,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state public override void OnComplete() { - bool hitTarget = false; - skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget); isCompleted = true; - var targets = skill.targetFind.GetTargets(); - //Need a variable size list of actions because status effects may add extra actions - //BattleAction[] actions = new BattleAction[targets.Count * skill.numHits]; - List actions = new List(); - List effects = owner.statusEffects.GetStatusEffectsByFlag((uint)StatusEffectFlags.ActivateOnAttack); - - //modify skill based on status effects - foreach (var effect in effects) - effect.CallLuaFunction(owner, "onWeaponSkill", skill); - - //Now that combos and positionals bonuses are done, we can calculate hits/crits/etc and damage for each action - foreach (var chara in targets) - { - for (int hitNum = 0; hitNum < skill.numHits; hitNum++) - { - var action = new BattleAction(chara.actorId, skill.worldMasterTextId, 0, 0, (byte) hitDirection, 1); - //For older versions this will need to be in the database for magic weaponskills - action.battleActionType = BattleActionType.AttackPhysical; - //uncached script - lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillFinish", owner, target, skill, action); - - //cached script - //skill.CallLuaFunction(owner, "onSkillFinish", owner, target, skill, action); - action.hitNum = (byte)hitNum; - - if (action.hitType > HitType.Evade) - hitTarget = true; - - actions.AddRange(action.GetAllActions()); - } - } - - // todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action - BattleAction[] errors = (BattleAction[]) actions.ToArray().Clone(); - owner.OnWeaponSkill(this, actions.ToArray(), skill, ref errors); - owner.DoBattleAction(skill.id, skill.battleAnimation, actions); + owner.DoBattleCommand(skill, "weaponskill"); owner.statusEffects.RemoveStatusEffectsByFlags((uint) StatusEffectFlags.LoseOnAttacking); - //Now that we know if we hit the target we can check if the combo continues - if (owner is Player player) - if (skill.isCombo && hitTarget) - player.SetCombos(skill.comboNextCommandId); - else - player.SetCombos(); + lua.LuaEngine.GetInstance().OnSignal("weaponskillUsed"); } public override void TryInterrupt() diff --git a/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs b/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs index 8ff06ff6..32b96c38 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs @@ -8,6 +8,7 @@ using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor.battle; using FFXIVClassic_Map_Server.actors.chara.player; +using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic.Common; @@ -16,17 +17,28 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils static class BattleUtils { - public static Dictionary HitTypeTextIds = new Dictionary() + public static Dictionary SingleHitTypeTextIds = new Dictionary() { { HitType.Miss, 30311 }, { HitType.Evade, 30310 }, { HitType.Parry, 30308 }, { HitType.Block, 30306 }, - { HitType.Resist, 30306 },//I can't find what the actual textid for resists is + { HitType.Resist, 30310 }, //Resists seem to use the evade text id { HitType.Hit, 30301 }, { HitType.Crit, 30302 } }; + public static Dictionary MultiHitTypeTextIds = new Dictionary() + { + { HitType.Miss, 30449 }, //The attack misses. + { HitType.Evade, 0 }, //Evades were removed before multi hit skills got their own messages, so this doesnt exist + { HitType.Parry, 30448 }, //[Target] parries, taking x points of damage. + { HitType.Block, 30447 }, //[Target] blocks, taking x points of damage. + { HitType.Resist, 0 }, //No spells are multi-hit, so this doesn't exist + { HitType.Hit, 30443 }, //[Target] tales x points of damage + { HitType.Crit, 30444 } //Critical! [Target] takes x points of damage. + }; + public static Dictionary HitTypeEffects = new Dictionary() { { HitType.Miss, 0 }, @@ -38,6 +50,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils { HitType.Crit, HitEffect.Crit } }; + //Most of these numbers I'm fairly certain are correct. The repeated numbers at levels 23 and 48 I'm less sure about but they do match some weird spots in the EXP graph + + public static ushort[] BASEEXP = {150, 150, 150, 150, 150, 150, 150, 150, 150, 150, //Level <= 10 + 150, 150, 150, 150, 150, 150, 150, 150, 160, 170, //Level <= 20 + 180, 190, 190, 200, 210, 220, 230, 240, 250, 260, //Level <= 30 + 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, //Level <= 40 + 370, 380, 380, 390, 400, 410, 420, 430, 430, 440}; //Level <= 50 public static bool TryAttack(Character attacker, Character defender, BattleAction action, ref BattleAction error) { @@ -65,53 +84,61 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils //Damage calculations //Calculate damage of action //We could probably just do this when determining the action's hit type - public static void CalculateDamage(Character attacker, Character defender, BattleCommand skill, BattleAction action) + public static void CalculatePhysicalDamageTaken(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - short dlvl = (short)(defender.GetLevel() - attacker.GetLevel()); - switch (action.hitType) - { - //Misses and evades deal no damage. - case (HitType.Miss): - case (HitType.Evade): - action.amount = 0; - break; - // todo: figure out parry damage reduction. For now assume 25% reduction - case (HitType.Parry): - CalculateParryDamage(attacker, defender, skill, action); - break; - case (HitType.Block): - CalculateBlockDamage(attacker, defender, skill, action); - break; - //There are 3 (or 4?) tiers of resists, each decreasing damage dealt by 25%. For now just assume level 2 resist (50% reduction) - // todo: figure out resist tiers - case (HitType.Resist): - CalculateResistDamage(attacker, defender, skill, action); - break; - case (HitType.Crit): - CalculateCritDamage(attacker, defender, skill, action); - break; - } - ushort finalAmount = action.amount; + // todo: physical resistances //dlvl, Defense, and Vitality all effect how much damage is taken after hittype takes effect //player attacks cannot do more than 9999 damage. - action.amount = (ushort) (finalAmount - CalculateDlvlModifier(dlvl) * (defender.GetMod((uint)Modifier.Defense) + 0.67 * defender.GetMod((uint)Modifier.Vitality))).Clamp(0, 9999); - - + //VIT is turned into Defense at a 3:2 ratio in calculatestats, so don't need to do that here + double damageTakenPercent = 1 - (defender.GetMod(Modifier.DamageTakenDown) / 100.0); + action.amount = (ushort)(action.amount - CalculateDlvlModifier(dlvl) * (defender.GetMod((uint)Modifier.Defense))).Clamp(0, 9999); + action.amount = (ushort)(action.amount * damageTakenPercent).Clamp(0, 9999); } + + public static void CalculateSpellDamageTaken(Character attacker, Character defender, BattleCommand skill, BattleAction action) + { + short dlvl = (short)(defender.GetLevel() - attacker.GetLevel()); + + // todo: elemental resistances + //Patch 1.19: + //Magic Defense has been abolished and no longer appears in equipment attributes. + //The effect of elemental attributes has been changed to that of reducing damage from element-based attacks. + + //http://kanican.livejournal.com/55370.html: + //elemental resistance stats are not actually related to resists (except for status effects), instead they impact damage taken + + + //dlvl, Defense, and Vitality all effect how much damage is taken after hittype takes effect + //player attacks cannot do more than 9999 damage. + double damageTakenPercent = 1 - (defender.GetMod(Modifier.DamageTakenDown) / 100.0); + action.amount = (ushort)(action.amount - CalculateDlvlModifier(dlvl) * (defender.GetMod((uint)Modifier.Defense) + 0.67 * defender.GetMod((uint)Modifier.Vitality))).Clamp(0, 9999); + action.amount = (ushort)(action.amount * damageTakenPercent).Clamp(0, 9999); + } + + public static void CalculateBlockDamage(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - double percentBlocked = defender.GetMod((uint)Modifier.Block) * .2;//Every point of Block adds .2% to how much is blocked - percentBlocked += defender.GetMod((uint)Modifier.Vitality) * .1;//Every point of vitality adds .1% to how much is blocked + double percentBlocked; - percentBlocked = 1 - percentBlocked; - action.amount = (ushort)(action.amount * percentBlocked); + //Aegis boon forces a full block + if (defender.statusEffects.HasStatusEffect(StatusEffectId.AegisBoon)) + percentBlocked = 1.0; + else + { + //Is this a case where VIT gives Block? + percentBlocked = defender.GetMod((uint)Modifier.Block) * 0.002;//Every point of Block adds .2% to how much is blocked + percentBlocked += defender.GetMod((uint)Modifier.Vitality) * 0.001;//Every point of vitality adds .1% to how much is blocked + } + + action.amountMitigated = (ushort)(action.amount * percentBlocked); + action.amount = (ushort)(action.amount * (1.0 - percentBlocked)); } - //don't know crit formula + //don't know exact crit bonus formula public static void CalculateCritDamage(Character attacker, Character defender, BattleCommand skill, BattleAction action) { short dlvl = (short)(defender.GetLevel() - attacker.GetLevel()); @@ -124,14 +151,15 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils // - Crit resilience //bonus -= attacker.GetMod((uint)Modifier.CriticalResilience) * potencyModifier; - //need to add something for bonus potency as a part of skill (ie thundara) + //need to add something for bonus potency as a part of skill (ie thundara, which breaks the cap) action.amount = (ushort)(action.amount * bonus.Clamp(1.15, 1.75));//min bonus of 115, max bonus of 175 } public static void CalculateParryDamage(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - double percentParry = .75; + double percentParry = 0.75; + action.amountMitigated = (ushort)(action.amount * (1 - percentParry)); action.amount = (ushort)(action.amount * percentParry); } @@ -140,80 +168,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils //Or we could have HitTypes for DoubleResist, TripleResist, and FullResist that get used here. public static void CalculateResistDamage(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - double percentResist = .5; + double percentResist = 0.5; + action.amountMitigated = (ushort)(action.amount * (1 - percentResist)); action.amount = (ushort)(action.amount * percentResist); } - //Used for attacks and abilities like Jump that deal damage - public static ushort CalculateAttackDamage(Character attacker, Character defender, BattleAction action) + //It's weird that stoneskin is handled in C# and all other buffs are in scripts right now + //But it's because stoneskin acts like both a preaction and postaction buff in that it falls off after damage is dealt but impacts how much damage is dealt + public static void HandleStoneskin(Character defender, BattleAction action) { - ushort damage = (ushort)100; + var mitigation = Math.Min(action.amount, defender.GetMod(Modifier.Stoneskin)); - if (attacker is Player p) - { - var weapon = p.GetEquipment().GetItemAtSlot(Equipment.SLOT_MAINHAND); - if (weapon != null) - { - var weaponData = Server.GetItemGamedata(weapon.itemId); - - //just some numbers from https://www.bluegartr.com/threads/107403-Stats-and-how-they-work/page24 - damage += (ushort) (2.225 * (weaponData as WeaponItem).damagePower + (attacker.GetMod((uint) Modifier.Attack) * .38)); - - } - } - - // todo: handle all other crap before protect/stoneskin - - // todo: handle crit etc - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Protect) || defender.statusEffects.HasStatusEffect(StatusEffectId.Protect2)) - { - if (action != null) - action.effectId |= (uint)HitEffect.Protect; - } - - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Stoneskin)) - { - if (action != null) - action.effectId |= (uint)HitEffect.Stoneskin; - } - return damage; + action.amount = (ushort) (action.amount - mitigation).Clamp(0, 9999); + defender.SubtractMod((uint)Modifier.Stoneskin, mitigation); } - public static ushort GetCriticalHitDamage(Character attacker, Character defender, BattleAction action) - { - ushort damage = action.amount; - - // todo: - // - // action.effectId |= (uint)HitEffect.Critical; - // - return damage; - } - - public static ushort CalculateSpellDamage(Character attacker, Character defender, BattleAction action) - { - ushort damage = 0; - - // todo: handle all other crap before shell/stoneskin - - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Shell)) - { - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Shell)) - { - } - } - - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Stoneskin)) - { - } - return damage; - } - - public static void DamageTarget(Character attacker, Character defender, BattleAction action, DamageTakenType type, bool sendBattleAction = false) + public static void DamageTarget(Character attacker, Character defender, BattleAction action, BattleActionContainer actionContainer= null) { if (defender != null) { + + defender.DelHP((short)action.amount); + attacker.OnDamageDealt(defender, action, actionContainer); + defender.OnDamageTaken(attacker, action, actionContainer); + // todo: other stuff too if (defender is BattleNpc) { @@ -225,66 +204,75 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils bnpc.hateContainer.UpdateHate(attacker, action.enmity); bnpc.lastAttacker = attacker; } - defender.DelHP((short) action.amount); - defender.OnDamageTaken(attacker, action, type); } } - public static void DoAction(Character user, Character receiver, BattleAction action, DamageTakenType type = DamageTakenType.None) + public static void HealTarget(Character caster, Character target, BattleAction action, BattleActionContainer actionContainer = null) { - switch(action.battleActionType) + if (target != null) { - //split attack into phys/mag? - case (BattleActionType.AttackMagic)://not sure if these use different damage taken formulas - case (BattleActionType.AttackPhysical): - DamageTarget(user, receiver, action, type, false); - break; - case (BattleActionType.Heal): - receiver.AddHP(action.amount); - break; - } + target.AddHP(action.amount); - - if ((type == DamageTakenType.Ability || type == DamageTakenType.Attack) && action.amount != 0) - { - receiver.AddTP(150); - user.AddTP(200); + target.statusEffects.CallLuaFunctionByFlag((uint) StatusEffectFlags.ActivateOnHealed, "onHealed", caster, target, action, actionContainer); } } - /* - * Rate functions - */ + + #region Rate Functions + //How is accuracy actually calculated? - public static double GetHitRate(Character attacker, Character defender, BattleCommand skill) + public static double GetHitRate(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - double hitRate = .80; - //Certain skills have lower or higher accuracy rates depending on position/combo - return hitRate * (skill != null ? skill.accuracyModifier : 1); + double hitRate = 80.0; + + //Add raw hit rate buffs, subtract raw evade buffs, take into account skill's accuracy modifier. + double hitBuff = attacker.GetMod(Modifier.RawHitRate); + double evadeBuff = defender.GetMod(Modifier.RawEvadeRate); + float modifier = skill != null ? skill.accuracyModifier : 0; + hitRate += (hitBuff + modifier).Clamp(0, 100.0); + hitRate -= evadeBuff; + return hitRate.Clamp(0, 100.0); } //Whats the parry formula? - public static double GetParryRate(Character attacker, Character defender, BattleCommand skill) + public static double GetParryRate(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - //Can't parry with shield, must be facing attacker - if (defender.GetMod((uint)Modifier.HasShield) > 0 || !defender.IsFacing(attacker)) + //Can't parry with shield, can't parry rear attacks + if (defender.GetMod((uint)Modifier.HasShield) != 0 || action.param == (byte) HitDirection.Rear) return 0; - return .10; + double parryRate = 10.0; + + parryRate += defender.GetMod(Modifier.Parry) * 0.1;//.1% rate for every point of Parry + + return parryRate + (defender.GetMod(Modifier.RawParryRate)); } - public static double GetCritRate(Character attacker, Character defender, BattleCommand skill) + public static double GetCritRate(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - double critRate = 10;// .0016 * attacker.GetMod((uint)Modifier.CritRating);//Crit rating adds .16% per point - return Math.Min(critRate, .20);//Crit rate is capped at 20% + if (action.actionType == ActionType.Status) + return 0.0; + + //using 10.0 for now since gear isn't working + double critRate = 10.0;// 0.16 * attacker.GetMod((uint)Modifier.CritRating);//Crit rating adds .16% per point + + //Add additional crit rate from skill + //Should this be a raw percent or a flat crit raitng? the wording on skills/buffs isn't clear. + critRate += 0.16 * (skill != null ? skill.bonusCritRate : 0); + + return critRate + attacker.GetMod(Modifier.RawCritRate); } //http://kanican.livejournal.com/55370.html // todo: figure that out - public static double GetResistRate(Character attacker, Character defender, BattleCommand skill) + public static double GetResistRate(Character attacker, Character defender, BattleCommand skill, BattleAction action) { + // todo: add elemental stuff + //Can only resist spells? + if (action.commandType != CommandType.Spell && action.actionProperty <= ActionProperty.Projectile) + return 0.0; - return .95; + return 15.0 + defender.GetMod(Modifier.RawResistRate); } //Block Rate follows 4 simple rules: @@ -292,30 +280,34 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils //(2) Every point in "Block Rate" gives +0.2% rate //(3) True block proc rate is capped at 75%. No clue on a possible floor. //(4) The baseline rate is based on dLVL only(mob stats play no role). The baseline rate is summarized in this raw data sheet: https://imgbox.com/aasLyaJz - public static double GetBlockRate(Character attacker, Character defender, BattleCommand skill) + public static double GetBlockRate(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - //Shields are required to block. - if (defender.GetMod((uint)Modifier.HasShield) == 0)//|| !defender.IsFacing(attacker)) + //Shields are required to block and can't block from rear. + if (defender.GetMod((uint)Modifier.HasShield) == 0 || action.param == (byte)HitDirection.Rear) return 0; - short dlvl = (short) (attacker.GetLevel() - defender.GetLevel()); - double blockRate = (-2.5 * dlvl) - 5; // Base block rate - blockRate += attacker.GetMod((uint) Modifier.Dexterity) * .1;// .1% for every dex - blockRate += attacker.GetMod((uint) Modifier.BlockRate) * .2;// .2% for every block rate - return Math.Min(blockRate, 25); + short dlvl = (short)(defender.GetLevel() - attacker.GetLevel()); + double blockRate = (2.5 * dlvl) + 5; // Base block rate + + //Is this one of those thing where DEX gives block rate and this would be taking DEX into account twice? + blockRate += defender.GetMod((uint)Modifier.Dexterity) * 0.1;// .1% for every dex + blockRate += defender.GetMod((uint)Modifier.BlockRate) * 0.2;// .2% for every block rate + + return Math.Min(blockRate, 25.0) + defender.GetMod((uint)Modifier.RawBlockRate); } - - /* - * HitType helpers. Used for determining if attacks are hits, crits, blocks, etc. and changing their damage based on that - */ + #endregion public static bool TryCrit(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - if (Program.Random.NextDouble() < GetCritRate(attacker, defender, skill)) + if ((Program.Random.NextDouble() * 100) <= action.critRate) { action.hitType = HitType.Crit; CalculateCritDamage(attacker, defender, skill, action); + + if(skill != null) + skill.actionCrit = true; + return true; } @@ -324,7 +316,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils public static bool TryResist(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - if (Program.Random.NextDouble() < GetResistRate(attacker, defender, skill)) + if ((Program.Random.NextDouble() * 100) <= action.resistRate) { action.hitType = HitType.Resist; CalculateResistDamage(attacker, defender, skill, action); @@ -336,10 +328,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils public static bool TryBlock(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - if (Program.Random.NextDouble() < GetBlockRate(attacker, defender, skill)) + if ((Program.Random.NextDouble() * 100) <= action.blockRate) { action.hitType = HitType.Block; - defender.SetProc((int)HitType.Block); CalculateBlockDamage(attacker, defender, skill, action); return true; } @@ -349,10 +340,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils public static bool TryParry(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - if (Program.Random.NextDouble() < GetParryRate(attacker, defender, skill)) + if ((Program.Random.NextDouble() * 100) <= action.parryRate) { action.hitType = HitType.Parry; - defender.SetProc((int)HitType.Parry); CalculateParryDamage(attacker, defender, skill, action); return true; } @@ -363,12 +353,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils //TryMiss instead of tryHit because hits are the default and don't change damage public static bool TryMiss(Character attacker, Character defender, BattleCommand skill, BattleAction action) { - if (Program.Random.NextDouble() > GetHitRate(attacker, defender, skill)) + if ((Program.Random.NextDouble() * 100) >= GetHitRate(attacker, defender, skill, action)) { - action.hitType = HitType.Miss; + action.hitType = (ushort)HitType.Miss; + //On misses, the entire amount is considered mitigated + action.amountMitigated = action.amount; action.amount = 0; - defender.SetProc((int)HitType.Evade); - attacker.SetProc((int)HitType.Miss); return true; } return false; @@ -377,82 +367,167 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils /* * Hit Effecthelpers. Different types of hit effects hits use some flags for different things, so they're split into physical, magical, heal, and status */ - public static void CalcHitType(Character caster, Character target, BattleCommand skill, BattleAction action) + public static void DoAction(Character caster, Character target, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) { - //Might be a simpler way to do this? - switch(action.battleActionType) + switch (action.actionType) { - case (BattleActionType.AttackPhysical): - SetHitEffectPhysical(caster, target, skill, action); + case (ActionType.Physical): + FinishActionPhysical(caster, target, skill, action, actionContainer); break; - case (BattleActionType.AttackMagic): - SetHitEffectMagical(caster, target, skill, action); + case (ActionType.Magic): + FinishActionSpell(caster, target, skill, action, actionContainer); break; - case (BattleActionType.Heal): - SetHitEffectHeal(caster, target, skill, action); + case (ActionType.Heal): + FinishActionHeal(caster, target, skill, action, actionContainer); break; - case (BattleActionType.Status): - SetHitEffectStatus(caster, target, skill, action); + case (ActionType.Status): + FinishActionStatus(caster, target, skill, action, actionContainer); break; } } - public static void SetHitEffectPhysical(Character attacker, Character defender, BattleCommand skill, BattleAction action) + //Determine the hit type, set the hit effect, modify damage based on stoneskin and hit type, hit target + public static void FinishActionPhysical(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) { - //Determine the hittype of the action and change amount of damage it does based on that + //Figure out the hit type and change damage depending on hit type if (!TryMiss(attacker, defender, skill, action)) - if (!TryCrit(attacker, defender, skill, action)) - if (!TryBlock(attacker, defender, skill, action)) - TryParry(attacker, defender, skill, action); + { + //Handle Stoneskin here because it seems like stoneskin mitigates damage done before taking into consideration crit/block/parry damage reductions. + //This is based on the fact that a 0 damage attack due to stoneskin will heal for 0 with Aegis Boon, meaning Aegis Boon didn't mitigate any damage + HandleStoneskin(defender, action); + //Crits can't be blocked (is this true for Aegis Boon and Divine Veil?) or parried so they are checked first. + if (!TryCrit(attacker, defender, skill, action)) + //Block and parry order don't really matter because if you can block you can't parry and vice versa + if (!TryBlock(attacker, defender, skill, action)) + if(!TryParry(attacker, defender, skill, action)) + //Finally if it's none of these, the attack was a hit + action.hitType = HitType.Hit; + } + + //Actions have different text ids depending on whether they're a part of a multi-hit ws or not. + Dictionary textIds = SingleHitTypeTextIds; + + //If this is the first hit of a multi hit command, add the "You use [command] on [target]" action + //Needs to be done here because certain buff messages appear before it. + if (skill != null && skill.numHits > 1) + { + if (action.hitNum == 1) + actionContainer?.AddAction(new BattleAction(attacker.actorId, 30441, 0)); + + textIds = MultiHitTypeTextIds; + } + + //Set the correct textId + action.worldMasterTextId = textIds[action.hitType]; + + //Set the hit effect + SetHitEffectPhysical(attacker, defender, skill, action, actionContainer); + + //Modify damage based on defender's stats + CalculatePhysicalDamageTaken(attacker, defender, skill, action); + + actionContainer.AddAction(action); + action.enmity = (ushort) (action.enmity * (skill != null ? skill.enmityModifier : 1)); + //Damage the target + DamageTarget(attacker, defender, action, actionContainer); + } + + public static void FinishActionSpell(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) + { + //Determine the hit type of the action + if (!TryMiss(attacker, defender, skill, action)) + { + HandleStoneskin(defender, action); + if (!TryCrit(attacker, defender, skill, action)) + if (!TryResist(attacker, defender, skill, action)) + action.hitType = HitType.Hit; + } + + //There are no multi-hit spells + action.worldMasterTextId = SingleHitTypeTextIds[action.hitType]; + + //Set the hit effect + SetHitEffectSpell(attacker, defender, skill, action); + + HandleStoneskin(defender, action); + + CalculateSpellDamageTaken(attacker, defender, skill, action); + + actionContainer.AddAction(action); + + DamageTarget(attacker, defender, action, actionContainer); + } + + public static void FinishActionHeal(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) + { + //Set the hit effect + SetHitEffectHeal(attacker, defender, skill, action); + + actionContainer.AddAction(action); + + HealTarget(attacker, defender, action, actionContainer); + } + + public static void FinishActionStatus(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) + { + //Set the hit effect + SetHitEffectStatus(attacker, defender, skill, action); + + TryStatus(attacker, defender, skill, action, actionContainer, false); + + actionContainer.AddAction(action); + } + + public static void SetHitEffectPhysical(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer) + { var hitEffect = HitEffect.HitEffectType; + HitType hitType = action.hitType; //Don't know what recoil is actually based on, just guessing //Crit is 2 and 3 together - if (action.hitType == HitType.Crit) + if (hitType == HitType.Crit) hitEffect |= HitEffect.CriticalHit; else { + //It's not clear what recoil level is based on for physical attacks double percentDealt = (100.0 * (action.amount / defender.GetMaxHP())); if (percentDealt > 5.0) hitEffect |= HitEffect.RecoilLv2; - else if(percentDealt > 10) + else if (percentDealt > 10) hitEffect |= HitEffect.RecoilLv3; } - action.worldMasterTextId = HitTypeTextIds[action.hitType]; - hitEffect |= HitTypeEffects[action.hitType]; - if (skill != null && skill.isCombo && action.hitType > HitType.Evade) + hitEffect |= HitTypeEffects[hitType]; + + //For combos that land, add the combo effect + if (skill != null && skill.isCombo && hitType > HitType.Evade && hitType != HitType.Evade) hitEffect |= (HitEffect)(skill.comboStep << 15); //if attack hit the target, take into account protective status effects - if (action.hitType >= HitType.Parry) + if (hitType >= HitType.Parry) { //Protect / Shell only show on physical/ magical attacks respectively. if (defender.statusEffects.HasStatusEffect(StatusEffectId.Protect)) if (action != null) hitEffect |= HitEffect.Protect; - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Stoneskin)) if (action != null) hitEffect |= HitEffect.Stoneskin; } - action.effectId = (uint) hitEffect; + + action.effectId = (uint)hitEffect; } - public static void SetHitEffectMagical(Character attacker, Character defender, BattleCommand skill, BattleAction action) + public static void SetHitEffectSpell(Character attacker, Character defender, BattleCommand skill, BattleAction action, BattleActionContainer actionContainer = null) { - //Determine the hit type of the action - if (!TryMiss(attacker, defender, skill, action)) - if (!TryCrit(attacker, defender, skill, action)) - TryResist(attacker, defender, skill, action); - - var hitEffect = HitEffect.MagicEffectType; + var hitEffect = HitEffect.MagicEffectType; + HitType hitType = action.hitType; //Recoil levels for spells are a bit different than physical. Recoil levels are used for resists. //Lv1 is for larger resists, Lv2 is for smaller resists and Lv3 is for no resists. Crit is still used for crits - if (action.hitType == HitType.Resist) + if (hitType == HitType.Resist) { //todo: calculate resist levels and figure out what the difference between Lv1 and 2 in retail was. For now assuming a full resist with 0 damage dealt is Lv1, all other resists Lv2 if (action.amount == 0) @@ -460,26 +535,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils else hitEffect |= HitEffect.RecoilLv2; } - else if (action.hitType == HitType.Crit) - hitEffect |= HitEffect.Crit; else hitEffect |= HitEffect.RecoilLv3; - action.worldMasterTextId = HitTypeTextIds[action.hitType]; - hitEffect |= HitTypeEffects[action.hitType]; + hitEffect |= HitTypeEffects[hitType]; if (skill != null && skill.isCombo) hitEffect |= (HitEffect)(skill.comboStep << 15); //if attack hit the target, take into account protective status effects - if (action.hitType >= HitType.Block) + if (hitType >= HitType.Block) { //Protect / Shell only show on physical/ magical attacks respectively. if (defender.statusEffects.HasStatusEffect(StatusEffectId.Shell)) if (action != null) hitEffect |= HitEffect.Shell; - if (defender.statusEffects.HasStatusEffect(StatusEffectId.Stoneskin)) if (action != null) hitEffect |= HitEffect.Stoneskin; @@ -501,14 +572,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils public static void SetHitEffectStatus(Character caster, Character receiver, BattleCommand skill, BattleAction action) { - var hitEffect = (uint) HitEffect.StatusEffectType | skill.statusId; + var hitEffect = (uint)HitEffect.StatusEffectType | skill.statusId; action.effectId = hitEffect; - } - public static int CalculateSpellDamage(Character attacker, Character defender, BattleCommand spell) - { - // todo: spell formulas and stuff (stoneskin, mods, stats, etc) - return 69; + action.hitType = HitType.Hit; } public static uint CalculateSpellCost(Character caster, Character target, BattleCommand spell) @@ -518,7 +585,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils // todo: calculate cost for mob/player if (caster is BattleNpc) { - + } else { @@ -527,12 +594,56 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils return scaledCost; } + + //IsAdditional is needed because additional actions may be required for some actions' effects + //For instance, Goring Blade's bleed effect requires another action so the first action can still show damage numbers + //Sentinel doesn't require an additional action because it doesn't need to show those numbers + //this is stupid + public static void TryStatus(Character caster, Character target, BattleCommand skill, BattleAction action, BattleActionContainer battleActions, bool isAdditional = true) + { + double rand = Program.Random.NextDouble(); + + //Statuses only land for non-resisted attacks and attacks that hit + if (skill != null && skill.statusId != 0 && (action.hitType > HitType.Evade && action.hitType != HitType.Resist) && rand < skill.statusChance) + { + StatusEffect effect = Server.GetWorldManager().GetStatusEffect(skill.statusId); + //Because combos might change duration or tier + if (effect != null) + { + effect.SetDuration(skill.statusDuration); + effect.SetTier(skill.statusTier); + effect.SetMagnitude(skill.statusMagnitude); + effect.SetOwner(target); + if (target.statusEffects.AddStatusEffect(effect, caster)) + { + //If we need an extra action to show the status text + if (isAdditional) + battleActions.AddAction(target.actorId, 30328, skill.statusId | (uint) HitEffect.StatusEffectType); + } + else + action.worldMasterTextId = 32002;//Is this right? + } + else + { + //until all effects are scripted and added to db just doing this + if (target.statusEffects.AddStatusEffect(skill.statusId, skill.statusTier, skill.statusMagnitude, skill.statusDuration, 3000)) + { + //If we need an extra action to show the status text + if (isAdditional) + battleActions.AddAction(target.actorId, 30328, skill.statusId | (uint) HitEffect.StatusEffectType); + } + else + action.worldMasterTextId = 32002;//Is this right? + } + } + } + //Convert a HitDirection to a BattleCommandPositionBonus. Basically just combining left/right into flank public static BattleCommandPositionBonus ConvertHitDirToPosition(HitDirection hitDir) { BattleCommandPositionBonus position = BattleCommandPositionBonus.None; - switch(hitDir) + switch (hitDir) { case (HitDirection.Front): position = BattleCommandPositionBonus.Front; @@ -548,44 +659,168 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils return position; } - //IsAdditional is needed because additional actions may be required for some actions' effects - //For instance, Goring Blade's bleed effect requires another action so the first action can still show damage numbers - //Sentinel doesn't require an additional action because it doesn't need to show those numbers - public static void TryStatus(Character caster, Character target, BattleCommand skill, BattleAction action, bool isAdditional = true) + + #region experience helpers + //See 1.19 patch notes for exp info. + public static ushort GetBaseEXP(Player player, BattleNpc mob) { - double rand = Program.Random.NextDouble(); - (caster as Player).SendMessage(0x20, "", rand.ToString()); - if (skill != null && action.amount < target.GetHP() && skill.statusId != 0 && action.hitType > HitType.Evade && rand < skill.statusChance) + //The way EXP seems to work for most enemies is that it gets the lower character's level, gets the base exp for that level, then uses dlvl to modify that exp + //Less than -19 dlvl gives 0 exp and no message is sent. + //This equation doesn't seem to work for certain bosses or NMs. + //Some enemies might give less EXP? Unsure on this. It seems like there might have been a change in base exp amounts after 1.19 + + //Example: + //Level 50 in a party kills a level 45 enemy + //Base exp is 400, as that's the base EXP for level 45 + //That's multiplied by the dlvl modifier for -5, which is 0.5625, which gives 225 + //That's then multiplied by the party modifier, which seems to be 0.667 regardless of party size, which gives 150 + //150 is then modified by bonus experience from food, rested exp, links, and chains + + int dlvl = mob.GetLevel() - player.GetLevel(); + if (dlvl <= -20) + return 0; + + int baseLevel = Math.Min(player.GetLevel(), mob.GetLevel()); + ushort baseEXP = BASEEXP[baseLevel]; + + double dlvlModifier = 1.0; + + //There's 2 functions depending on if the dlvl is positive or negative. + if (dlvl >= 0) + //I'm not sure if this caps out at some point. This is correct up to at least +9 dlvl though. + dlvlModifier += 0.2 * dlvl; + else + //0.1x + 0.0025x^2 + dlvlModifier += 0.1 * dlvl + 0.0025 * (dlvl * dlvl); + + //The party modifier isn't clear yet. It seems like it might just be 0.667 for any number of members in a group, but the 1.19 notes say it's variable + //There also seem to be some cases where it simply doesn't apply but it isn't obvious if that's correct or when it applies if it is correct + double partyModifier = player.currentParty.GetMemberCount() == 1 ? 1.0 : 0.667; + + baseEXP = (ushort) (baseEXP * dlvlModifier * partyModifier); + + return baseEXP; + } + + //Gets the EXP bonus when enemies link + public static byte GetLinkBonus(ushort linkCount) + { + byte bonus = 0; + + switch (linkCount) { - StatusEffect effect = Server.GetWorldManager().GetStatusEffect(skill.statusId); - //Because combos might change duration or tier + case (0): + break; + case (1): + bonus = 25; + break; + case (2): + bonus = 50; + break; + case (3): + bonus = 75; + break; + case (4): + default: + bonus = 100; + break; + } + + return bonus; + } + + //Gets EXP chain bonus for Attacker fighting Defender + //Official text on EXP Chains: An EXP Chain occurs when players consecutively defeat enemies of equal or higher level than themselves within a specific amount of time. + //Assuming this means that there is no bonus for enemies below player's level and EXP chains are specific to the person, not party + public static byte GetChainBonus(ushort tier) + { + byte bonus = 0; + + switch (tier) + { + case (0): + break; + case (1): + bonus = 20; + break; + case (2): + bonus = 25; + break; + case (3): + bonus = 30; + break; + case (4): + bonus = 40; + break; + default: + bonus = 50; + break; + } + return bonus; + } + + public static byte GetChainTimeLimit(ushort tier) + { + byte timeLimit = 0; + + switch (tier) + { + case (0): + timeLimit = 100; + break; + case (1): + timeLimit = 80; + break; + case (2): + timeLimit = 60; + break; + case (3): + timeLimit = 20; + break; + default: + timeLimit = 10; + break; + } + + return timeLimit; + } + + //Calculates bonus EXP for Links and Chains + public static void AddBattleBonusEXP(Player attacker, BattleNpc defender, BattleActionContainer actionContainer) + { + ushort baseExp = GetBaseEXP(attacker, defender); + + //Only bother calculating the rest if there's actually exp to be gained. + //0 exp sends no message + if (baseExp > 0) + { + int totalBonus = 0;//GetMod(Modifier.bonusEXP) + + var linkCount = defender.GetMobMod(MobModifier.LinkCount); + totalBonus += GetLinkBonus((byte)Math.Min(linkCount, 255)); + + StatusEffect effect = attacker.statusEffects.GetStatusEffectById((uint)StatusEffectId.EXPChain); + ushort expChainNumber = 0; + uint timeLimit = 100; if (effect != null) { - effect.SetDuration(skill.statusDuration); - effect.SetTier(skill.statusTier); - effect.SetOwner(target); - if (target.statusEffects.AddStatusEffect(effect, caster)) - { - //If we need an extra action to show the status text - if (isAdditional) - action.AddStatusAction(target.actorId, skill.statusId); - } - else - action.worldMasterTextId = 32002;//Is this right? - } - else - { - if (target.statusEffects.AddStatusEffect(skill.statusId, 1, 3000, skill.statusDuration, skill.statusTier)) - { - //If we need an extra action to show the status text - if (isAdditional) - action.AddStatusAction(target.actorId, skill.statusId); - } - else - action.worldMasterTextId = 32002;//Is this right? + expChainNumber = effect.GetTier(); + timeLimit = (uint)(GetChainTimeLimit(expChainNumber)); + actionContainer?.AddEXPAction(new BattleAction(attacker.actorId, 33919, 0, expChainNumber, (byte)timeLimit)); } + totalBonus += GetChainBonus(expChainNumber); + + StatusEffect newChain = Server.GetWorldManager().GetStatusEffect((uint)StatusEffectId.EXPChain); + + newChain.SetDuration(timeLimit); + newChain.SetTier((byte)(Math.Min(expChainNumber + 1, 255))); + attacker.statusEffects.AddStatusEffect(newChain, attacker, true, true); + + actionContainer?.AddEXPActions(attacker.AddExp(baseExp, (byte)attacker.GetClass(), (byte)(totalBonus.Min(255)))); } } + + #endregion } -} +} \ No newline at end of file diff --git a/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs b/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs index 23fbf8a3..a9a90b35 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs @@ -143,7 +143,7 @@ namespace FFXIVClassic_Map_Server.Actors } } } - npcWork.hateType = 2; + npcWork.hateType = 3; var propPacketUtil = new ActorPropertyPacketUtil("npcWork/hate", this); propPacketUtil.AddProperty("npcWork.hateType"); return propPacketUtil.Done()[0]; @@ -191,7 +191,22 @@ namespace FFXIVClassic_Map_Server.Actors public override bool CanCast(Character target, BattleCommand spell) { // todo: - return false; + if (target == null) + { + // Target does not exist. + return false; + } + if (Utils.Distance(positionX, positionY, positionZ, target.positionX, target.positionY, target.positionZ) > spell.range) + { + // The target is out of range. + return false; + } + if (!IsValidTarget(target, spell.mainTarget) || !spell.IsValidMainTarget(this, target)) + { + // error packet is set in IsValidTarget + return false; + } + return true; } public override bool CanWeaponSkill(Character target, BattleCommand skill) @@ -256,7 +271,7 @@ namespace FFXIVClassic_Map_Server.Actors updateFlags |= ActorUpdateFlags.AllNpc; } - public override void Die(DateTime tick) + public override void Die(DateTime tick, BattleActionContainer actionContainer = null) { if (IsAlive()) { @@ -270,24 +285,25 @@ namespace FFXIVClassic_Map_Server.Actors { //I think this is, or should be odne in DoBattleAction. Packet capture had the message in the same packet as an attack // defeat/defeats - //((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0))); - + actionContainer?.AddEXPAction(new BattleAction(actorId, 30108, 0)); if (lastAttacker.currentParty != null && lastAttacker.currentParty is Party) { foreach (var memberId in ((Party)lastAttacker.currentParty).members) { - var partyMember = zone.FindActorInArea(memberId); + var partyMember = zone.FindActorInArea(memberId); // onDeath(monster, player, killer) lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, partyMember, lastAttacker); - if (partyMember is Player) - ((Player)partyMember).AddExp(1500, (byte)partyMember.GetClass(), 5); + + // todo: add actual experience calculation and exp bonus values. + if (partyMember is Player player) + BattleUtils.AddBattleBonusEXP(player, this, actionContainer); } } else { // onDeath(monster, player, killer) lua.LuaEngine.CallLuaBattleFunction(this, "onDeath", this, lastAttacker, lastAttacker); - ((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0))); + //((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0))); } } positionUpdates?.Clear(); @@ -413,6 +429,10 @@ namespace FFXIVClassic_Map_Server.Actors this.bnpcId = id; } + public Int64 GetMobMod(MobModifier mobMod) + { + return GetMobMod((uint)mobMod); + } public Int64 GetMobMod(uint mobModId) { @@ -430,10 +450,11 @@ namespace FFXIVClassic_Map_Server.Actors mobModifiers.Add((MobModifier)mobModId, val); } - public override void OnDamageTaken(Character attacker, BattleAction action, DamageTakenType damageTakenType) + public override void OnDamageTaken(Character attacker, BattleAction action, BattleActionContainer actionContainer = null) { if (GetMobMod((uint)MobModifier.DefendScript) != 0) - lua.LuaEngine.CallLuaBattleFunction(this, "onDamageTaken", this, attacker, action.amount, (uint)damageTakenType); + lua.LuaEngine.CallLuaBattleFunction(this, "onDamageTaken", this, attacker, action.amount); + base.OnDamageTaken(attacker, action, actionContainer); } } } diff --git a/FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs b/FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs index fe2600e6..1e525cb0 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs @@ -33,6 +33,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc CallForHelp = 22, // actor with this id outside of target's party with this can attack me FreeForAll = 23, // any actor can attack me Roams = 24, // Do I walk around? - RoamDelay = 25 // What is the delay between roam ticks + RoamDelay = 25, // What is the delay between roam ticks + Linked = 26, // Did I get aggroed via linking? + LinkCount = 27 // How many BattleNPCs got linked with me } } \ No newline at end of file diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 691bf244..7e0a08c2 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -610,7 +610,6 @@ namespace FFXIVClassic_Map_Server.Actors packet.ReplaceActorID(actorId); var packets = packet.GetSubpackets(); - QueuePackets(packets); } catch (Exception e) @@ -1776,10 +1775,29 @@ namespace FFXIVClassic_Map_Server.Actors } + + if ((updateFlags & ActorUpdateFlags.Stats) != 0) + { + var propPacketUtil = new ActorPropertyPacketUtil("charaWork/battleParameter", this); + + for (uint i = 0; i < 35; i++) + { + if (GetMod(i) != charaWork.battleTemp.generalParameter[i]) + { + charaWork.battleTemp.generalParameter[i] = (short)GetMod(i); + propPacketUtil.AddProperty($"charaWork.battleTemp.generalParameter[{i}]"); + } + } + + QueuePackets(propPacketUtil.Done()); + + } + + base.PostUpdate(tick, packets); } - public override void Die(DateTime tick) + public override void Die(DateTime tick, BattleActionContainer actionContainer = null) { // todo: death timer aiContainer.InternalDie(tick, 60); @@ -2219,17 +2237,20 @@ namespace FFXIVClassic_Map_Server.Actors } //Handles exp being added, does not handle figuring out exp bonus from buffs or skill/link chains or any of that - public void AddExp(int exp, byte classId, int bonusPercent = 0) - { + //Returns BattleActions that can be sent to display the EXP gained number and level ups + public List AddExp(int exp, byte classId, byte bonusPercent = 0) + { + List actionList = new List(); exp += (int) Math.Ceiling((exp * bonusPercent / 100.0f)); - //You earn [exp](+[bonusPercent]%) experience point(s). - SendGameMessage(this, Server.GetWorldManager().GetActor(), 33934, 0x44, this, 0, 0, 0, 0, 0, 0, 0, 0, 0, exp, "", bonusPercent); + + //33935: You earn [exp] (+[bonusPercent]%) experience points. + actionList.Add(new BattleAction(actorId, 33935, 0, (ushort)exp, bonusPercent)); + bool leveled = false; int diff = MAXEXP[GetLevel() - 1] - charaWork.battleSave.skillPoint[classId - 1]; //While there is enough experience to level up, keep leveling up, unlocking skills and removing experience from exp until we don't have enough to level up while (exp >= diff && GetLevel() < charaWork.battleSave.skillLevelCap[classId]) { - //Level up LevelUp(classId); leveled = true; @@ -2263,9 +2284,12 @@ namespace FFXIVClassic_Map_Server.Actors QueuePackets(expPropertyPacket.Done()); Database.SetExp(this, classId, charaWork.battleSave.skillPoint[classId - 1]); + + return actionList; } - public void LevelUp(byte classId) + //Increaess level of current class and equips new abilities earned at that level + public void LevelUp(byte classId, List actionList = null) { if (charaWork.battleSave.skillLevel[classId - 1] < charaWork.battleSave.skillLevelCap[classId]) { @@ -2273,8 +2297,10 @@ namespace FFXIVClassic_Map_Server.Actors charaWork.battleSave.skillLevel[classId - 1]++; charaWork.parameterSave.state_mainSkillLevel++; - SendGameMessage(this, Server.GetWorldManager().GetActor(), 33909, 0x44, this, 0, 0, 0, 0, 0, 0, 0, 0, 0, (int) GetLevel()); - //If there's an ability that unlocks at this level, equip it. + //33909: You gain level [level] + actionList?.Add(new BattleAction(actorId, 33909, 0, (ushort) charaWork.battleSave.skillLevel[classId - 1])); + + //If there's any abilites that unlocks at this level, equip them. List commandIds = Server.GetWorldManager().GetBattleCommandIdByLevel(classId, GetLevel()); foreach(uint commandId in commandIds) { @@ -2282,6 +2308,9 @@ namespace FFXIVClassic_Map_Server.Actors byte jobId = ConvertClassIdToJobId(classId); if (jobId != classId) EquipAbilityInFirstOpenSlot(jobId, commandId, false); + + //33926: You learn [command]. + actionList?.Add(new BattleAction(actorId, 33926, commandId)); } } } @@ -2392,11 +2421,52 @@ namespace FFXIVClassic_Map_Server.Actors SetMod((uint)Modifier.AttackType, damageAttribute); SetMod((uint)Modifier.AttackDelay, attackDelay); SetMod((uint)Modifier.HitCount, hitCount); + + //These stats all correlate in a 3:2 fashion + //It seems these stats don't actually increase their respective stats. The magic stats do, however + AddMod((uint)Modifier.Attack, (long)(GetMod(Modifier.Strength) * 0.667)); + AddMod((uint)Modifier.Accuracy, (long)(GetMod(Modifier.Dexterity) * 0.667)); + AddMod((uint)Modifier.Defense, (long)(GetMod(Modifier.Vitality) * 0.667)); + + //These stats correlate in a 4:1 fashion. (Unsure if MND is accurate but it would make sense for it to be) + AddMod((uint)Modifier.MagicAttack, (long)((float)GetMod(Modifier.Intelligence) * 0.25)); + + AddMod((uint)Modifier.MagicAccuracy, (long)((float)GetMod(Modifier.Mind) * 0.25)); + AddMod((uint)Modifier.MagicHeal, (long)((float)GetMod(Modifier.Mind) * 0.25)); + + AddMod((uint)Modifier.MagicEvasion, (long)((float)GetMod(Modifier.Piety) * 0.25)); + AddMod((uint)Modifier.MagicEnfeeblingPotency, (long)((float)GetMod(Modifier.Piety) * 0.25)); + + //VIT correlates to HP in a 1:1 fashion + AddMod((uint)Modifier.Hp, (long)((float)Modifier.Vitality)); + + CalculateTraitMods(); } - public void SetCurrentJob(ushort jobId) + + public bool HasTrait(ushort id) { - currentJob = jobId; - BroadcastPacket(SetCurrentJobPacket.BuildPacket(actorId, jobId), true); + BattleTrait trait = Server.GetWorldManager().GetBattleTrait(id); + + return HasTrait(trait); + } + + public bool HasTrait(BattleTrait trait) + { + return (trait != null) && (trait.job == GetClass()) && (trait.level <= GetLevel()); + } + + public void CalculateTraitMods() + { + var traitIds = Server.GetWorldManager().GetAllBattleTraitIdsForClass((byte) GetClass()); + + foreach(var traitId in traitIds) + { + var trait = Server.GetWorldManager().GetBattleTrait(traitId); + if(HasTrait(trait)) + { + AddMod(trait.modifier, trait.bonus); + } + } } } } diff --git a/FFXIVClassic Map Server/actors/group/MonsterParty.cs b/FFXIVClassic Map Server/actors/group/MonsterParty.cs index 511eca6d..caf2b383 100644 --- a/FFXIVClassic Map Server/actors/group/MonsterParty.cs +++ b/FFXIVClassic Map Server/actors/group/MonsterParty.cs @@ -48,7 +48,7 @@ namespace FFXIVClassic_Map_Server.actors.group public override void SendInitWorkValues(Session session) { - SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex); + SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex); groupWork.setTarget("/_init"); SubPacket test = groupWork.buildPacket(session.id, session.id); diff --git a/FFXIVClassic Map Server/dataobjects/ItemData.cs b/FFXIVClassic Map Server/dataobjects/ItemData.cs index 0b9e5505..d4a38be8 100644 --- a/FFXIVClassic Map Server/dataobjects/ItemData.cs +++ b/FFXIVClassic Map Server/dataobjects/ItemData.cs @@ -535,7 +535,7 @@ namespace FFXIVClassic_Map_Server.dataobjects damagePower = reader.GetInt16("damagePower"); damageInterval = reader.GetFloat("damageInterval"); ammoVirtualDamagePower = reader.GetInt16("ammoVirtualDamagePower"); - dps = damagePower / damageInterval;// this is wrong for bows, might need to store this in db because dps is used for weaponskill damage + dps = (damagePower + ammoVirtualDamagePower) / damageInterval; } } diff --git a/FFXIVClassic Map Server/dataobjects/Session.cs b/FFXIVClassic Map Server/dataobjects/Session.cs index a713efd8..b2baa962 100644 --- a/FFXIVClassic Map Server/dataobjects/Session.cs +++ b/FFXIVClassic Map Server/dataobjects/Session.cs @@ -106,7 +106,7 @@ namespace FFXIVClassic_Map_Server.dataobjects { QueuePacket(RemoveActorPacket.BuildPacket(actorInstanceList[i].actorId)); actorInstanceList.RemoveAt(i); - } + } } //Add new actors or move @@ -123,7 +123,7 @@ namespace FFXIVClassic_Map_Server.dataobjects } else { - QueuePacket(actor.GetSpawnPackets(playerActor, 1)); + QueuePacket(actor.GetSpawnPackets(playerActor, 1)); QueuePacket(actor.GetInitPackets()); QueuePacket(actor.GetSetEventStatusPackets()); diff --git a/FFXIVClassic Map Server/lua/LuaEngine.cs b/FFXIVClassic Map Server/lua/LuaEngine.cs index 72f628ad..9382f4cb 100644 --- a/FFXIVClassic Map Server/lua/LuaEngine.cs +++ b/FFXIVClassic Map Server/lua/LuaEngine.cs @@ -176,8 +176,7 @@ namespace FFXIVClassic_Map_Server.lua public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args) { // todo: this is stupid, load the actual effect name from db table - var name = ((StatusEffectId)effect.GetStatusEffectId()).ToString().ToLower(); - string path = $"./scripts/effects/{name}.lua"; + string path = $"./scripts/effects/{effect.GetName()}.lua"; if (File.Exists(path)) { diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs index 5a1cc77c..f93d478f 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs @@ -22,7 +22,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle //Not setting RecoilLv2 or RecoilLv3 results in the weaker RecoilLv1. //These are the recoil animations that play on the target, ranging from weak to strong. //The recoil that gets set was likely based on the percentage of HP lost from the attack. - //These also have a visual effect with heals but in reverse. RecoilLv1 has a large effect, Lv3 has none. Crit is very large + //These also have a visual effect with heals and spells but in reverse. RecoilLv1 has a large effect, Lv3 has none. Crit is very large + //For spells they represent resists. Lv0 is a max resist, Lv3 is no resist. Crit is still used for crits. + //Heals used the same effects sometimes but it isn't clear what for, it seems random? Possibly something like a trait proccing or even just a bug RecoilLv1 = 0, RecoilLv2 = 1 << 0, RecoilLv3 = 1 << 1, @@ -61,6 +63,8 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle // Required for heal text to be blue, not sure if that's all it's used for Heal = 1 << 8, + MP = 1 << 9, //Causes "MP" text to appear when used with MagicEffectType. | with Heal to make text blue + TP = 1 << 10,//Causes "TP" text to appear when used with MagicEffectType. | with Heal to make text blue //If only HitEffect1 is set out of the hit effects, the "Evade!" pop-up text triggers along with the evade visual. //If no hit effects are set, the "Miss!" pop-up is triggered and no hit visual is played. @@ -76,9 +80,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle Miss = 0, Evade = HitEffect1, Hit = HitEffect1 | HitEffect2, + Crit = HitEffect3, Parry = Hit | HitEffect3, Block = HitEffect4, - Crit = HitEffect3, //Knocks you back away from the attacker. KnockbackLv1 = HitEffect4 | HitEffect2 | HitEffect1, @@ -138,74 +142,192 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle Crit = 6 } - public enum BattleActionType + //Type of action + public enum ActionType : ushort { None = 0, - AttackPhysical = 1, - AttackMagic = 2, + Physical = 1, + Magic = 2, Heal = 3, Status = 4 } + //There's are two columns in gamecommand that are for action property and action element respectively and both have percentages next to them + //the percentages are for what percent that property or element factors into the attack. Astral and Umbral are always 33% because they are both 3 elments combined + //ActionProperty and ActionElement are slightly different. Property defines whta type of attack it is, and 11-13 are used for "sonic, breath, neutral". Neutral is always used for magic + //For Element 11-13 are used for astral, umbral, and healing magic. + //Right now we aren't actually using these but when things like resists get better defined we'll have to + public enum ActionProperty : ushort + { + None = 0, + Slashing = 1, + Piercing = 2, + Blunt = 3, + Projectile = 4, + + Fire = 5, + Ice = 6, + Wind = 7, + Earth = 8, + Lightning = 9, + Water = 10, + + //These I'm not sure about. Check gameCommand.csv + Astral = 11, + Umbral = 12, + Heal = 13 + } + + + /* + public enum ActionProperty : ushort + { + None = 0, + Slashing = 1, + Piercing = 2, + Blunt = 3, + Projectile = 4, + + Fire = 5, + Ice = 6, + Wind = 7, + Earth = 8, + Lightning = 9, + Water = 10, + + Sonic = 11, + Breath = 12, + Neutral = 13, + Astral = 14, + Umbral = 15 + } + + public enum ActionElement : ushort + { + None = 0, + Slashing = 1, + Piercing = 2, + Blunt = 3, + Projectile = 4, + + Fire = 5, + Ice = 6, + Wind = 7, + Earth = 8, + Lightning = 9, + Water = 10, + + //These I'm not sure about. Check gameCommand.csv + Astral = 11, + Umbral = 12, + Heal = 13 + }*/ + + class BattleAction { public uint targetId; public ushort amount; + public ushort amountMitigated; //Amount that got blocked/evaded or resisted public ushort enmity; //Seperate from amount for abilities that cause a different amount of enmity than damage public ushort worldMasterTextId; public uint effectId; //Impact effect, damage/heal/status numbers or name public byte param; //Which side the battle action is coming from public byte hitNum; //Which hit in a sequence of hits this is - public HitType hitType; - - //Need a list of actions for commands that may both deal damage and inflict status effects - public List actionsList; /// - /// this field is not actually part of the packet struct + /// these fields are not actually part of the packet struct /// public uint animation; - public BattleActionType battleActionType; + public CommandType commandType; //What type of command was used (ie weaponskill, ability, etc) + public ActionProperty actionProperty; //Damage type of the action + public ActionType actionType; //Type of this action (ie physical, magic, heal) + public HitType hitType; - public BattleAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte unknown = 1) + //Rates, I'm not sure if these need to be stored like this but with the way some buffs work maybe they do? + //Makes things like Blindside easy at least. + public double parryRate = 0.0; + public double blockRate = 0.0; + public double resistRate = 0.0; + public double hitRate = 0.0; + public double critRate = 0.0; + + public BattleAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte hitNum = 1) { - this.targetId = targetId; + this.targetId = targetId; this.worldMasterTextId = worldMasterTextId; this.effectId = effectId; this.amount = amount; this.param = param; - this.hitNum = unknown; + this.hitNum = hitNum; this.hitType = HitType.Hit; this.enmity = amount; - this.actionsList = new List(); - this.battleActionType = BattleActionType.None; - actionsList.Add(this); + this.commandType = (byte) CommandType.None; } - public void AddStatusAction(uint targetId, uint effectId) + public BattleAction(uint targetId, BattleCommand command, byte param = 0, byte hitNum = 1) { - actionsList.Add(new BattleAction(targetId, 30328, effectId | (uint) HitEffect.StatusEffectType)); + this.targetId = targetId; + this.worldMasterTextId = command.worldMasterTextId; + this.param = param; + this.hitNum = hitNum; + this.commandType = command.commandType; + this.actionProperty = command.actionProperty; + this.actionType = command.actionType; } - public void AddHealAction(uint targetId, ushort amount) + //Order of what (probably) happens when a skill is used: + //Buffs that alter things like recast times or that only happen once per skill usage like Power Surge are activated + //Script calculates damage and handles any special requirements + //Rates are calculated + //Buffs that impact indiviudal hits like Blindside or Blood for Blood are activated + //The final hit type is determined + //Stoneskin takes damage + //Final damage amount is calculated using the hit type and defender's stats + //Buffs that activate or respond to damage like Rampage. Stoneskin gets removed AFTER damage if it falls off. + //Additional effects that are a part of the skill itself or weapon in case of auto attacks take place like status effects + //Certain buffs that alter the whole skill fall off (Resonance, Excruciate) + + public void DoAction(Character caster, Character target, BattleCommand skill, BattleActionContainer battleActions) { - var a = new BattleAction(targetId, 30320, (uint)(HitEffect.MagicEffectType | HitEffect.RecoilLv3 | HitEffect.Heal), amount); - actionsList.Add(a); + //First calculate rates for hit/block/etc + CalcRates(caster, target, skill); + + //Next, modify those rates based on preaction buffs + //Still not sure how we shouldh andle these + PreAction(caster, target, skill, battleActions); + + BattleUtils.DoAction(caster, target, skill, this, battleActions); } - public void CalcHitType(Character caster, Character target, BattleCommand skill) + + //Calculate the chance of hitting/critting/etc + public void CalcRates(Character caster, Character target, BattleCommand skill) { - BattleUtils.CalcHitType(caster, target, skill, this); + hitRate = BattleUtils.GetHitRate(caster, target, skill, this); + critRate = BattleUtils.GetCritRate(caster, target, skill, this); + blockRate = BattleUtils.GetBlockRate(caster, target, skill, this); + parryRate = BattleUtils.GetParryRate(caster, target, skill, this); + resistRate = BattleUtils.GetResistRate(caster, target, skill, this); } - public void TryStatus(Character caster, Character target, BattleCommand skill, bool isAdditional = true) + //These are buffs that activate before the action hits. Usually they change things like hit or crit rates or damage + public void PreAction(Character caster, Character target, BattleCommand skill, BattleActionContainer battleActions) { - BattleUtils.TryStatus(caster, target, skill, this, isAdditional); + target.statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnPreactionTarget, "onPreAction", caster, target, skill, this, battleActions); + + caster.statusEffects.CallLuaFunctionByFlag((uint)StatusEffectFlags.ActivateOnPreactionCaster, "onPreAction", caster, target, skill, this, battleActions); } - public List GetAllActions() + //Try and apply a status effect + public void TryStatus(Character caster, Character target, BattleCommand skill, BattleActionContainer battleActions, bool isAdditional = true) { - return actionsList; + BattleUtils.TryStatus(caster, target, skill, this, battleActions, isAdditional); + } + + public ushort GetHitType() + { + return (ushort)hitType; } } } diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionContainer.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionContainer.cs new file mode 100644 index 00000000..3f3fbd36 --- /dev/null +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionContainer.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.send.actor.battle +{ + class BattleActionContainer + { + private List actionsList = new List(); + + //EXP messages are always the last mesages in battlea ction packets, so they get appended after all the rest of the actions are done. + private List expActionList = new List(); + + public BattleActionContainer() + { + + } + + public void AddAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte hitNum = 0) + { + AddAction(new BattleAction(targetId, worldMasterTextId, effectId, amount, param, hitNum)); + } + + //Just to make scripting simpler + public void AddMPAction(uint targetId, ushort worldMasterTextId, ushort amount) + { + uint effectId = (uint) (HitEffect.MagicEffectType | HitEffect.MP | HitEffect.Heal); + AddAction(targetId, worldMasterTextId, effectId, amount); + } + + public void AddHPAction(uint targetId, ushort worldMasterTextId, ushort amount) + { + uint effectId = (uint)(HitEffect.MagicEffectType | HitEffect.Heal); + AddAction(targetId, worldMasterTextId, effectId, amount); + } + + public void AddTPAction(uint targetId, ushort worldMasterTextId, ushort amount) + { + uint effectId = (uint)(HitEffect.MagicEffectType | HitEffect.TP); + AddAction(targetId, worldMasterTextId, effectId, amount); + } + + public void AddAction(BattleAction action) + { + if (action != null) + actionsList.Add(action); + } + + public void AddActions(List actions) + { + actionsList.AddRange(actions); + } + + public void AddEXPAction(BattleAction action) + { + expActionList.Add(action); + } + + public void AddEXPActions(List actionList) + { + expActionList.AddRange(actionList); + } + + public void CombineLists() + { + actionsList.AddRange(expActionList); + } + + public List GetList() + { + return actionsList; + } + } +} diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs index 1a129183..f5bdde7c 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX01Packet.cs @@ -33,13 +33,12 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle binWriter.Seek(0x20, SeekOrigin.Begin); binWriter.Write((UInt32)1); //Num actions (always 1 for this) binWriter.Write((UInt16)commandId); - binWriter.Write((UInt16)0x810); //? + binWriter.Write((UInt16)0x801); //? binWriter.Write((UInt32)action.targetId); binWriter.Write((UInt16)action.amount); binWriter.Write((UInt16)action.worldMasterTextId); - Program.Log.Info(action.worldMasterTextId); binWriter.Write((UInt32)action.effectId); binWriter.Write((Byte)action.param); diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs index f89b2801..b3d8fca8 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs @@ -104,7 +104,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle binWriter.Seek(0x78, SeekOrigin.Begin); for (int i = 0; i < max; i++) + { binWriter.Write((UInt32)actionList[listOffset + i].effectId); + } binWriter.Seek(0xA0, SeekOrigin.Begin); for (int i = 0; i < max; i++) diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs index 4dbfa17e..cf593d6f 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs @@ -31,9 +31,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle //Missing... last value is float, string in here as well? binWriter.Seek(0x20, SeekOrigin.Begin); - binWriter.Write((UInt32)actionList.Length); //Num actions + binWriter.Write((UInt32)max); //Num actions binWriter.Write((UInt16)commandId); - binWriter.Write((UInt16)0x810); //? + binWriter.Write((UInt16)0x818); //? binWriter.Seek(0x28, SeekOrigin.Begin); for (int i = 0; i < max; i++) @@ -86,9 +86,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle //Missing... last value is float, string in here as well? binWriter.Seek(0x20, SeekOrigin.Begin); - binWriter.Write((UInt32)actionList.Count); //Num actions + binWriter.Write((UInt32)max); //Num actions binWriter.Write((UInt16)commandId); - binWriter.Write((UInt16)0x810); //? + binWriter.Write((UInt16)0x818); //? binWriter.Seek(0x28, SeekOrigin.Begin); for (int i = 0; i < max; i++) diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs index 2c1c4855..b4ba775b 100644 --- a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs +++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs @@ -41,7 +41,7 @@ namespace FFXIVClassic_Map_Server.packets.send.group binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name)); offset++; - } + } } } diff --git a/data/scripts/ability.lua b/data/scripts/ability.lua index be4c0dcb..b3d59883 100644 --- a/data/scripts/ability.lua +++ b/data/scripts/ability.lua @@ -34,27 +34,25 @@ end; --For abilities that inflict statuses, like aegis boon or taunt function onStatusAbilityFinish(caster, target, skill, action) - action.battleActionType = BattleActionType.Status; - action.CalcHitType(caster, target, skill); + --action.CalcHitType(caster, target, skill); + action.DoAction(caster, target, skill); action.TryStatus(caster, target, skill, false); return action.amount; end; function onAttackAbilityFinish(caster, target, skill, action) - action.battleActionType = BattleActionType.AttackPhysical; local damage = math.random(50, 150); action.amount = damage; - action.CalcHitType(caster, target, skill); + action.DoAction(caster, target, skill); return action.amount; end; function onHealAbilityFinish(caster, target, skill, action) - action.battleActionType = BattleActionType.Heal; local amount = math.random(150, 250); action.amount = amount; - action.CalcHitType(caster, target, skill); + action.DoAction(caster, target, skill); action.TryStatus(caster, target, skill, true); return action.amount; end; \ No newline at end of file diff --git a/data/scripts/battleutils.lua b/data/scripts/battleutils.lua index c9c1bdc9..6cfe600e 100644 --- a/data/scripts/battleutils.lua +++ b/data/scripts/battleutils.lua @@ -1,8 +1,64 @@ -BattleActionType = +CommandType = { None = 0, - AttackPhysical = 1, - AttackMagic = 2, + AutoAttack = 1, + Weaponskill = 2, + Ability = 3, + Spell = 4 +} + +ActionType = +{ + None = 0, + Physical = 1, + Magic = 2, Heal = 3, Status = 4 +} + +ActionProperty = +{ + None = 0, + Physical = 1, + Magic = 2, + Heal = 4, + Status = 8, + Ranged = 16 +} + +DamageTakenType = +{ + None, + Attack, + Magic, + Weaponskill, + Ability +} + +HitDirection = +{ + None = 0, + Front = 1, + Right = 2, + Rear = 4, + Left = 8 +} + +HitType = +{ + Miss = 0, + Evade = 1, + Parry = 2, + Block = 3, + Resist = 4, + Hit = 5, + Crit = 6 +} + +TargetFindAOEType = +{ + None = 0, + Circle = 1, + Cone = 2, + Box = 3 } \ No newline at end of file diff --git a/data/scripts/commands/Ability.lua b/data/scripts/commands/Ability.lua index 47b04053..a9429e93 100644 --- a/data/scripts/commands/Ability.lua +++ b/data/scripts/commands/Ability.lua @@ -16,5 +16,4 @@ local attackMagicHandlers = { function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8) player.Ability(command.actorId, targetActor); player:endEvent(); - end \ No newline at end of file diff --git a/data/scripts/commands/ActivateCommand.lua b/data/scripts/commands/ActivateCommand.lua index cec7da25..5afd87dc 100644 --- a/data/scripts/commands/ActivateCommand.lua +++ b/data/scripts/commands/ActivateCommand.lua @@ -10,9 +10,9 @@ Switches between active and passive mode states function onEventStarted(player, command, triggerName) - if (player.newMainState == 0x0000) then + if (player.currentMainState == 0x0000) then player.Engage(0, 0x0002); - elseif (player.newMainState == 0x0002) then + elseif (player.currentMainState == 0x0002) then player.Disengage(0x0000); end player:endEvent(); diff --git a/data/scripts/commands/ChangeJobCommand.lua b/data/scripts/commands/ChangeJobCommand.lua new file mode 100644 index 00000000..4cb38f6a --- /dev/null +++ b/data/scripts/commands/ChangeJobCommand.lua @@ -0,0 +1,6 @@ +function onEventStarted(player, caller, commandRequest, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + + player:SetCurrentJob(17); + + player:EndEvent(); +end \ No newline at end of file diff --git a/data/scripts/commands/EquipAbilityCommand.lua b/data/scripts/commands/EquipAbilityCommand.lua index 6127a8cf..2a92841e 100644 --- a/data/scripts/commands/EquipAbilityCommand.lua +++ b/data/scripts/commands/EquipAbilityCommand.lua @@ -70,7 +70,7 @@ function onEventStarted(player, equipAbilityWidget, triggername, slot, commandid ability = worldManager.GetBattleCommand(commandid); --Is the ability a part of the player's current class? --This check isn't correct because of jobs having different ids - local classId = player:GetClass(); + local classId = player:GetCurrentClassOrJob(); local jobId = player:ConvertClassIdToJobId(classId); if(ability.job == classId or ability.job == jobId) then diff --git a/data/scripts/commands/PointSearchAbility.lua b/data/scripts/commands/PointSearchAbility.lua new file mode 100644 index 00000000..ee05e8c4 --- /dev/null +++ b/data/scripts/commands/PointSearchAbility.lua @@ -0,0 +1,7 @@ + +function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8) + + + player.Cast(command.actorId, targetActor); + player:endEvent(); +end \ No newline at end of file diff --git a/data/scripts/commands/ability/aegis_boon.lua b/data/scripts/commands/ability/aegis_boon.lua new file mode 100644 index 00000000..84d41871 --- /dev/null +++ b/data/scripts/commands/ability/aegis_boon.lua @@ -0,0 +1,18 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27164: Swift Aegis Boon + if caster.HasTrait(27164) then + ability.recastTimeMs = ability.recastTimeMs - 15000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/barrage.lua b/data/scripts/commands/ability/barrage.lua new file mode 100644 index 00000000..6dd5eb5e --- /dev/null +++ b/data/scripts/commands/ability/barrage.lua @@ -0,0 +1,22 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + ability.statusMagnitude = 4; + + --27242: Enhanced Barrage: Adds an additional attack to barrage ( 4 -> 5 ) + if caster.HasTrait(27242) then + ability.statusMagnitude = 5; + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/berserk.lua b/data/scripts/commands/ability/berserk.lua new file mode 100644 index 00000000..5163866b --- /dev/null +++ b/data/scripts/commands/ability/berserk.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27205: Enhanced Berserk: Increases the effect of Berserk by 20% + if caster.HasTrait(27205) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/blindside.lua b/data/scripts/commands/ability/blindside.lua new file mode 100644 index 00000000..a3182ea8 --- /dev/null +++ b/data/scripts/commands/ability/blindside.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27121: Enhanced Blindside + if caster.HasTrait(27121) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/blissful_mind.lua b/data/scripts/commands/ability/blissful_mind.lua new file mode 100644 index 00000000..b38a8b2b --- /dev/null +++ b/data/scripts/commands/ability/blissful_mind.lua @@ -0,0 +1,43 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27362: Enhanced Blissful Mind + if caster.HasTrait(27362) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --Blissful Mind + --223228: Blissful Mind + --223242: Fully Blissful Mind + local buff = caster.statusEffects.GetStatusEffectById(223228) or caster.statusEffects.GetStatusEffectById(223242); + + --If we have a buff then Blissful Mind removes that buff and restores MP. Otherwise, it adds the Blissful Mind effect + if buff ~= nil then + local amount = buff.GetExtra(); + local remAction = caster.statusEffects.RemoveStatusEffectForBattleAction(buff, 30329); + + caster.AddMP(amount); + + actionContainer.AddMPAction(caster.actorId, 30321, amount); + actionContainer.AddAction(remAction); + else + --Blissful mind takes 25% of CURRENT HP and begins storing MP up to that point, at which point the buff changes to indicate its full + local amount = caster.GetHP() * 0.25; + + caster.DelHP(amount); + skill.statusMagnitude = amount; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + end + +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/blood_for_blood.lua b/data/scripts/commands/ability/blood_for_blood.lua new file mode 100644 index 00000000..e722cd9c --- /dev/null +++ b/data/scripts/commands/ability/blood_for_blood.lua @@ -0,0 +1,24 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27283: Enhanced Blood for Blood: Increases damage dealt to enemies by B4B by 25% + if caster.HasTrait(27283) then + ability.statusTier = 2; + end + + --27284: Swift Blood for Blood: Reduces recast time of B4B by 15 seconds + if caster.HasTrait(27284) then + ability.recastTimeMs = ability.recastTimeMs - 15000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/bloodbath.lua b/data/scripts/commands/ability/bloodbath.lua new file mode 100644 index 00000000..6ae86efa --- /dev/null +++ b/data/scripts/commands/ability/bloodbath.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27202: Swift Bloodbath + if caster.HasTrait(27202) then + ability.recastTimeMs = ability.recastTimeMs - 15000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/chameleon.lua b/data/scripts/commands/ability/chameleon.lua new file mode 100644 index 00000000..92e6c1a5 --- /dev/null +++ b/data/scripts/commands/ability/chameleon.lua @@ -0,0 +1,18 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27245: Swift Chameleon + if caster.HasTrait(27245) then + ability.recastTimeMs = ability.recastTimeMs - 60000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + target.hateContainer.UpdateHate(caster, -840); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/cleric_stance.lua b/data/scripts/commands/ability/cleric_stance.lua new file mode 100644 index 00000000..0cae6d8d --- /dev/null +++ b/data/scripts/commands/ability/cleric_stance.lua @@ -0,0 +1,15 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/collusion.lua b/data/scripts/commands/ability/collusion.lua new file mode 100644 index 00000000..e859eb1c --- /dev/null +++ b/data/scripts/commands/ability/collusion.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --8032701: Fighter's Gauntlets: Reduces Collusion cooldown by 10 seconds + if caster.GetEquipment().GetItemAtSlot(14).itemId == 8032701 then + skill.recastTimeMs = skill.recastTimeMs - 10000; + end + + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/cover.lua b/data/scripts/commands/ability/cover.lua new file mode 100644 index 00000000..5bba25bd --- /dev/null +++ b/data/scripts/commands/ability/cover.lua @@ -0,0 +1,23 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --This is for the "Cover" effect the caster receives. + local coverTier = 1 + --8032701: Gallant Surcoat: Enhances Cover + if caster.GetEquipment().GetItemAtSlot(10).itemId == 8032701 then + coverTier = 2; + end + + actionContainer.AddAction(caster.statusEffects.AddStatusForBattleAction(223063, coverTier)); + + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/dark_seal.lua b/data/scripts/commands/ability/dark_seal.lua new file mode 100644 index 00000000..1e2f2cd2 --- /dev/null +++ b/data/scripts/commands/ability/dark_seal.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27320: Swift Dark Seal + if caster.HasTrait(27320) then + ability.recastTimeMs = ability.recastTimeMs - 30000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/decoy.lua b/data/scripts/commands/ability/decoy.lua new file mode 100644 index 00000000..4e6f4d4b --- /dev/null +++ b/data/scripts/commands/ability/decoy.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27244: Enhanced Decoy: Renders Decoy capable of evading melee attacks + if caster.HasTrait(27244) then + ability.statusId = 223238; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/default.lua b/data/scripts/commands/ability/default.lua index 4e71a193..eed87cb9 100644 --- a/data/scripts/commands/ability/default.lua +++ b/data/scripts/commands/ability/default.lua @@ -9,6 +9,5 @@ function onAbilityStart(caster, target, skill) return 0; end; -function onAbilityFinish(caster, target, skill, action) - return onStatusAbilityFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action) end; \ No newline at end of file diff --git a/data/scripts/commands/ability/divine_veil.lua b/data/scripts/commands/ability/divine_veil.lua new file mode 100644 index 00000000..8e853610 --- /dev/null +++ b/data/scripts/commands/ability/divine_veil.lua @@ -0,0 +1,20 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --8051401: Gallant Cuisses + if caster.GetEquipment().GetItemAtSlot(14).itemId == 8051401 then + ability.statusTier = 2; + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/dragonfire_dive.lua b/data/scripts/commands/ability/dragonfire_dive.lua index 91bf8017..4375f9fb 100644 --- a/data/scripts/commands/ability/dragonfire_dive.lua +++ b/data/scripts/commands/ability/dragonfire_dive.lua @@ -9,6 +9,8 @@ function onAbilityStart(caster, target, ability) return 0; end; -function onAbilityFinish(caster, target, skill, action) - return onAttackAbilityFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + action.amount = skill.basePotency; + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/ability/dread_spike.lua b/data/scripts/commands/ability/dread_spike.lua new file mode 100644 index 00000000..c17ac693 --- /dev/null +++ b/data/scripts/commands/ability/dread_spike.lua @@ -0,0 +1,24 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --Need a better way to do this + + for i = 223212,223217 do + local remAction = caster.statusEffects.RemoveStatusEffectForBattleAction(i, 30329) + + if remAction ~= nil then + actionContainer.AddAction(remAction); + skill.statusTier = 2; + break; + end + + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/elusive_jump.lua b/data/scripts/commands/ability/elusive_jump.lua new file mode 100644 index 00000000..f1d12012 --- /dev/null +++ b/data/scripts/commands/ability/elusive_jump.lua @@ -0,0 +1,16 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --How to do enmity? + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/enduring_march.lua b/data/scripts/commands/ability/enduring_march.lua new file mode 100644 index 00000000..ba3969d0 --- /dev/null +++ b/data/scripts/commands/ability/enduring_march.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27203: Enhanced Outmaneuver + if caster.HasTrait(27203) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/excruciate.lua b/data/scripts/commands/ability/excruciate.lua new file mode 100644 index 00000000..1432ddef --- /dev/null +++ b/data/scripts/commands/ability/excruciate.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27321: Enhanced Excruciate: Increases critical rate bonus from Excruciate. + if caster.HasTrait(27321) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/featherfoot.lua b/data/scripts/commands/ability/featherfoot.lua new file mode 100644 index 00000000..f4120804 --- /dev/null +++ b/data/scripts/commands/ability/featherfoot.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27123: Enhanced Featherfoot + if caster.HasTrait(27123) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/fists_of_earth.lua b/data/scripts/commands/ability/fists_of_earth.lua new file mode 100644 index 00000000..8416595e --- /dev/null +++ b/data/scripts/commands/ability/fists_of_earth.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27124: Enhanced Fists of Earth + if caster.HasTrait(27125) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/fists_of_fire.lua b/data/scripts/commands/ability/fists_of_fire.lua new file mode 100644 index 00000000..84ac5ce7 --- /dev/null +++ b/data/scripts/commands/ability/fists_of_fire.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27124: Enhanced Fists of Fire + if caster.HasTrait(27124) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/flash.lua b/data/scripts/commands/ability/flash.lua new file mode 100644 index 00000000..ec4f7b05 --- /dev/null +++ b/data/scripts/commands/ability/flash.lua @@ -0,0 +1,27 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27161: Enhanced Flash: Adds Blind effect to flash + if caster.HasTrait(27161) then + ability.statusChance = 1; + end + + --27162: Enhanced Flash II: Expands Flash to affect enemies near target + if caster.HasTrait(27162) then + ability.aoeTarget = TargetFindAOEType.Circle; + end + + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + action.enmity = 400; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/foresight.lua b/data/scripts/commands/ability/foresight.lua new file mode 100644 index 00000000..a54dff7e --- /dev/null +++ b/data/scripts/commands/ability/foresight.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27201: Swift Foresight + if caster.HasTrait(27201) then + ability.recastTimeMs = ability.recastTimeMs - 15000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/hallowed_ground.lua b/data/scripts/commands/ability/hallowed_ground.lua new file mode 100644 index 00000000..7fe937d3 --- /dev/null +++ b/data/scripts/commands/ability/hallowed_ground.lua @@ -0,0 +1,28 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27245: Swift Chameleon + if caster.HasTrait(27245) then + ability.recastTimeMs = ability.recastTimeMs - 60000; + end + return 0; +end; + +--Get all targets with hate on caster and spread 1140 enmity between them. +function onSkillFinish(caster, target, skill, action, actionContainer) + --[[ + local enemies = caster.GetTargetsWithHate() + local enmity = 1140 / enemies.Count + for enemy in enemies do + enemy.hateContainer.updateHate(enmity); + end]] + + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/hawks_eye.lua b/data/scripts/commands/ability/hawks_eye.lua new file mode 100644 index 00000000..e1b2ed10 --- /dev/null +++ b/data/scripts/commands/ability/hawks_eye.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27240: Enhanced Hawks Eye + --Increases accuracy gained by 50%. (Hawks Eye normally gives 12.5% of your accuracy, Traited it gives 18.75%) + if caster.HasTrait(27240) then + ability.statusTier = 2 + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/invigorate.lua b/data/scripts/commands/ability/invigorate.lua index dc7b46af..6d183947 100644 --- a/data/scripts/commands/ability/invigorate.lua +++ b/data/scripts/commands/ability/invigorate.lua @@ -6,9 +6,24 @@ function onAbilityPrepare(caster, target, ability) end; function onAbilityStart(caster, target, ability) + --27280: Enhanced Invigorate: Increases duration of Invigorate by 15 seconds + if caster.HasTrait(27280) then + ability.statusDuration = ability.statusDuration + 15; + end + + --Drachen Mail: Increases Invigorate TP tick from 100 to 120. + local magnitude = 100; + + --8032704: Drachen Mail + if caster.GetEquipment().GetItemAtSlot(10).itemId == 8032704 then + magnitude = 120; + end + + ability.statusMagnitude = magnitude; return 0; end; -function onAbilityFinish(caster, target, ability, action) - return onStatusAbilityFinish(caster, target, ability, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/ability/jump.lua b/data/scripts/commands/ability/jump.lua index 91bf8017..85f185b6 100644 --- a/data/scripts/commands/ability/jump.lua +++ b/data/scripts/commands/ability/jump.lua @@ -9,6 +9,9 @@ function onAbilityStart(caster, target, ability) return 0; end; -function onAbilityFinish(caster, target, skill, action) - return onAttackAbilityFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/ability/keen_flurry.lua b/data/scripts/commands/ability/keen_flurry.lua new file mode 100644 index 00000000..f06ec21a --- /dev/null +++ b/data/scripts/commands/ability/keen_flurry.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27285: Enhanced Keen Flurry: Reduces recast time of WS used during KF by 50% + if caster.HasTrait(27285) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/life_surge.lua b/data/scripts/commands/ability/life_surge.lua new file mode 100644 index 00000000..06f165fd --- /dev/null +++ b/data/scripts/commands/ability/life_surge.lua @@ -0,0 +1,53 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27282: Enhanced Life Surge: Increases effect of Life Surge by 20% + if caster.HasTrait(27282) then + ability.statusTier = 2; + end + + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --Need a better way to do this + --223212: Power Surge I + --223213: Power Surge II + --223212: Power Surge III + --No message is sent when PS is removed by Life Surge + caster.statusEffects.RemoveStatusEffect(223212, true); + caster.statusEffects.RemoveStatusEffect(223213, true); + caster.statusEffects.RemoveStatusEffect(223214, true); + + + --Using this ability moves to the next LS buff + local removeId = 0; + --223215: Life Surge I + --223216: Life Surge II + --223217: Life Surge III + if caster.statusEffects.HasStatusEffect(223215) then + removeId = 223215; + skill.statusId = 223216; + skill.statusTier = 2; + elseif caster.statusEffects.HasStatusEffect(223216) then + removeId = 223216; + skill.statusId = 223217; + skill.statusTier = 3; + elseif caster.statusEffects.HasStatusEffect(223217) then + effect = caster.statusEffects.GetStatusEffectById(223217) + effect.RefreshTime(); + skill.statusId = 223217; + end + + if not (removeId == 0) then + --caster.statusEffects.RemoveStatusEffect(removeId, true); + caster.statusEffects.ReplaceEffect(caster.statusEffects.GetStatusEffectById(removeId), skill.statusId, skill.statusTier, skill.statusMagnitude, skill.statusDuration); + end + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/light_shot.lua b/data/scripts/commands/ability/light_shot.lua index 91bf8017..4375f9fb 100644 --- a/data/scripts/commands/ability/light_shot.lua +++ b/data/scripts/commands/ability/light_shot.lua @@ -9,6 +9,8 @@ function onAbilityStart(caster, target, ability) return 0; end; -function onAbilityFinish(caster, target, skill, action) - return onAttackAbilityFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + action.amount = skill.basePotency; + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/ability/necrogenesis.lua b/data/scripts/commands/ability/necrogenesis.lua new file mode 100644 index 00000000..ef6f241e --- /dev/null +++ b/data/scripts/commands/ability/necrogenesis.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27322: Swift Dark Seal + if caster.HasTrait(27322) then + ability.recastTimeMs = ability.recastTimeMs - 30000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/outmaneuver.lua b/data/scripts/commands/ability/outmaneuver.lua new file mode 100644 index 00000000..699d7eba --- /dev/null +++ b/data/scripts/commands/ability/outmaneuver.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27164: Enhanced Outmaneuver + if caster.HasTrait(27164) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/parsimony.lua b/data/scripts/commands/ability/parsimony.lua new file mode 100644 index 00000000..ce1ff01a --- /dev/null +++ b/data/scripts/commands/ability/parsimony.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27323: Enhanced Parsimony: Increases MP gained from Parsimony by 25% + if caster.HasTrait(27323) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/power_surge.lua b/data/scripts/commands/ability/power_surge.lua new file mode 100644 index 00000000..54976f89 --- /dev/null +++ b/data/scripts/commands/ability/power_surge.lua @@ -0,0 +1,24 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27281: Enhanced Power Surge: Increases effect of Power Surge by 50% + if caster.HasTrait(27281) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --Need a better way to do this + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(223215)); + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(223216)); + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(223217)); + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/provoke.lua b/data/scripts/commands/ability/provoke.lua new file mode 100644 index 00000000..64830e2d --- /dev/null +++ b/data/scripts/commands/ability/provoke.lua @@ -0,0 +1,21 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27200: Enhanced Provoke: Adds Attack Down effect to Provoke. + if caster.HasTrait(27200) then + ability.statusChance = 1.0; + end + return 0; +end; + +--http://forum.square-enix.com/ffxiv/threads/47393-Tachi-s-Guide-to-Paladin-%28post-1.22b%29 +function onSkillFinish(caster, target, skill, action, actionContainer) + action.enmity = 750; + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/quelling_strike.lua b/data/scripts/commands/ability/quelling_strike.lua new file mode 100644 index 00000000..35c507a4 --- /dev/null +++ b/data/scripts/commands/ability/quelling_strike.lua @@ -0,0 +1,29 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --QS gives 300 TP by default. + skill.statusMagnitude = 300; + --I'm assuming that with raging strikes, that increases to 500. + --and traited that increases again to 750 (or 450 without RS) + if caster.statusEffects.HasStatusEffect(223221) then + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(223221)); + skill.statusMagnitude = 500; + end + + --27241: Enhanced Quelling Strike: Increases TP gained from QS by 50% + if caster.HasTrait(27241) then + skill.statusMagnitude = skill.statusMagnitude * 1.5; + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/raging_strike.lua b/data/scripts/commands/ability/raging_strike.lua new file mode 100644 index 00000000..5e265f08 --- /dev/null +++ b/data/scripts/commands/ability/raging_strike.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27243: Enhanced Raging Strike: Increases effect of Raging Strike by 50% + if caster.HasTrait(27241) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/rampage.lua b/data/scripts/commands/ability/rampage.lua new file mode 100644 index 00000000..49c9bd60 --- /dev/null +++ b/data/scripts/commands/ability/rampage.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27204: Enhanced Rampage + if caster.HasTrait(27204) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/rampart.lua b/data/scripts/commands/ability/rampart.lua new file mode 100644 index 00000000..604d4929 --- /dev/null +++ b/data/scripts/commands/ability/rampart.lua @@ -0,0 +1,27 @@ +require("global"); +require("ability"); +require("battleutils") + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + + --27163: Enhanced Rampart:Expands rampart to affect party members + if caster.HasTrait(27163) then + ability.aoeType = TargetFindAOEType.Circle; + end + + return 0; +end; + +--http://forum.square-enix.com/ffxiv/threads/47393-Tachi-s-Guide-to-Paladin-%28post-1.22b%29 +--180 enmity per member that has enmity on the current enemy +--Need to figure out enmity system +function onSkillFinish(caster, target, skill, action, actionContainer) + action.enmity = 180; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/sacred_prism.lua b/data/scripts/commands/ability/sacred_prism.lua new file mode 100644 index 00000000..9affbf67 --- /dev/null +++ b/data/scripts/commands/ability/sacred_prism.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27360: Swift Sacred Prism: Reduces recast by 30 seconds + if caster.HasTrait(27360) then + ability.recastTimeMs = ability.recastTimeMs - 30000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/second_wind.lua b/data/scripts/commands/ability/second_wind.lua index 7d629434..e6c7ddaf 100644 --- a/data/scripts/commands/ability/second_wind.lua +++ b/data/scripts/commands/ability/second_wind.lua @@ -1,14 +1,39 @@ require("global"); -require("ability"); +require("modifiers"); +--require("ability"); function onAbilityPrepare(caster, target, ability) return 0; end; function onAbilityStart(caster, target, ability) + return 0; end; -function onAbilityFinish(caster, target, ability, action) - return onHealAbilityFinish(caster, target, ability, action) +--http://forum.square-enix.com/ffxiv/threads/51208-2nd-wind-modifier +--The primary modifier for SW is class level. + +--There are three other factors that contribute to SW: +-- PGL's SW trait, which increases potency by 25%. +-- A bonus from INT (2INT=1HP) +-- An additional random integer (580 at level 50. +/- 3%) +function onSkillFinish(caster, target, skill, action, actionContainer) + --Base formula isn't quit known yet + local amount = 100; + --Heals can vary by up to ~3.5% in either direction + amount = math.Clamp(amount * (0.965 + (math.rand() * 7.0)), 0, 9999); + + --PGL gets an INT bonus for Second Wind + if caster.GetClass() == 2 then + amount = amount + caster.GetMod(modifiersGlobal.Intelligence) / 2; + end; + + --27120: Enhanced Second Wind + if caster.HasTrait(27120) then + amount = amount * 1.25; + end; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/ability/sentinel.lua b/data/scripts/commands/ability/sentinel.lua new file mode 100644 index 00000000..4a4b1a7e --- /dev/null +++ b/data/scripts/commands/ability/sentinel.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27160: Enhanced Sentinel + if caster.HasTrait(27160) then + ability.statusTier = 2; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/shroud_of_saints.lua b/data/scripts/commands/ability/shroud_of_saints.lua new file mode 100644 index 00000000..7e5af422 --- /dev/null +++ b/data/scripts/commands/ability/shroud_of_saints.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27361: Swift Shroud of Saints + if caster.HasTrait(27361) then + ability.recastTimeMs = ability.recastTimeMs - 60000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/taunt.lua b/data/scripts/commands/ability/taunt.lua new file mode 100644 index 00000000..a73b5378 --- /dev/null +++ b/data/scripts/commands/ability/taunt.lua @@ -0,0 +1,19 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + --27122: Swift Taunt: Reduces recast time by 15 seconds. + if caster.HasTrait(27121) then + ability.recastTimeMs = ability.recastTimeMs - 15000; + end + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/tempered_will.lua b/data/scripts/commands/ability/tempered_will.lua new file mode 100644 index 00000000..f024acaf --- /dev/null +++ b/data/scripts/commands/ability/tempered_will.lua @@ -0,0 +1,20 @@ +require("global"); +require("ability"); + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --Is this before or after status is gained? + --Will probably need to switch to a flag for this because it might include more than just these 3 effects. + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(228011)); + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(228013)); + actionContainer.AddAction(caster.statusEffects.RemoveStatusEffectForBattleAction(228021)); + + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/ability/vengeance.lua b/data/scripts/commands/ability/vengeance.lua new file mode 100644 index 00000000..69136e37 --- /dev/null +++ b/data/scripts/commands/ability/vengeance.lua @@ -0,0 +1,22 @@ +require("global"); +require("ability"); +require("battleutils") + +function onAbilityPrepare(caster, target, ability) + return 0; +end; + +function onAbilityStart(caster, target, ability) + + --8032703: Fighter's Cuirass: Enhances Vengeance + if caster.GetEquipment().GetItemAtSlot(13).itemId == 8032703 then + skill.statusTier = 2; + end + + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/gm/ba.lua b/data/scripts/commands/gm/ba.lua new file mode 100644 index 00000000..43354441 --- /dev/null +++ b/data/scripts/commands/gm/ba.lua @@ -0,0 +1,29 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "sssss", + description = +[[ +Adds experience to player or . +!giveexp | +!giveexp | +]], +} + +function onTrigger(player, argc, commandId, animationId, textId, effectId, amount) + local sender = "[battleaction] "; + + if player then + cid = tonumber(commandId) or 0; + aid = tonumber(animationId) or 0; + tid = tonumber(textId) or 0; + print(effectId) + eid = tonumber(effectId) or 0; + amt = tonumber(amount) or 0; + + player:DoBattleActionAnimation(cid, aid, tid, eid, amt); + else + print(sender.."unable to add experience, ensure player name is valid."); + end; +end; \ No newline at end of file diff --git a/data/scripts/commands/gm/graphic.lua b/data/scripts/commands/gm/graphic.lua index 1a813b13..d2c0e7fe 100644 --- a/data/scripts/commands/gm/graphic.lua +++ b/data/scripts/commands/gm/graphic.lua @@ -31,4 +31,5 @@ function onTrigger(player, argc, slot, wId, eId, vId, cId) else player:SendMessage(messageID, sender, "No parameters sent! Usage: "..properties.description); end; + end; \ No newline at end of file diff --git a/data/scripts/commands/gm/setsize.lua b/data/scripts/commands/gm/setsize.lua new file mode 100644 index 00000000..87a62425 --- /dev/null +++ b/data/scripts/commands/gm/setsize.lua @@ -0,0 +1,24 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "s", + description = +[[ +Changes appearance for equipment with given parameters. +!graphic +]], +} + +function onTrigger(player, argc, size) + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local sender = "[setappearance] "; + + s = tonumber(size) or 0; + + if player and player.target then + player.target.appearanceIds[0] = s; + player.target.zone.BroadcastPacketAroundActor(player.target, player.target.CreateAppearancePacket()); + end; + +end; \ No newline at end of file diff --git a/data/scripts/commands/gm/setstate.lua b/data/scripts/commands/gm/setstate.lua new file mode 100644 index 00000000..9c1d8e70 --- /dev/null +++ b/data/scripts/commands/gm/setstate.lua @@ -0,0 +1,27 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "s", + description = +[[ +Changes appearance for equipment with given parameters. +!graphic +]], +} + +function onTrigger(player, argc, state) + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local sender = "[setstate] "; + + max = tonumber(state) or 0; + + for s = 0, max do + if player and player.target then + player.target:ChangeState(s); + wait(0.8); + player:SendMessage(0x20, "", "state: "..s); + end; + end + +end; \ No newline at end of file diff --git a/data/scripts/commands/gm/yolo.lua b/data/scripts/commands/gm/yolo.lua index ea971d13..42018e7c 100644 --- a/data/scripts/commands/gm/yolo.lua +++ b/data/scripts/commands/gm/yolo.lua @@ -1,4 +1,5 @@ require("global"); +require("modifiers"); properties = { permissions = 0, @@ -149,16 +150,18 @@ function onTrigger(player, argc, width, height, blockCount) local zone = pos[4]; local w = tonumber(width) or 0; local h = tonumber(height) or 0; + local blocks = tonumber(blockCount) or 0; printf("%f %f %f", x, y, z); --local x, y, z = player.GetPos(); - for i = 0, blockCount do + for i = 0, blocks do for i = 0, w do for j = 0, h do local actor = player.GetZone().SpawnActor(2104001, 'ass', x + (i - (w / 2) * 3), y, z + (j - (h / 2) * 3), rot, 0, 0, true); - actor.ChangeNpcAppearance(1001149) - actor.SetLevel(50); + actor.ChangeNpcAppearance(1001149); + actor.SetMaxHP(10000); + actor.SetHP(10000); + actor.SetMod(modifiersGlobal.HasShield, 1); end - --actor.FollowTarget(player, 3.2); end x = x + 500 diff --git a/data/scripts/commands/gm/zonecount.lua b/data/scripts/commands/gm/zonecount.lua index 74e9a838..ca0f28b4 100644 --- a/data/scripts/commands/gm/zonecount.lua +++ b/data/scripts/commands/gm/zonecount.lua @@ -2,20 +2,18 @@ require("global"); properties = { permissions = 0, - parameters = "sss", + parameters = "", description = [[ -Set movement speed for player. Enter no value to reset to default. -!speed | -!speed | +Get the amount of actors in this zone. +!zonecount ]] } -function onTrigger(player, argc, stop, walk, run) +function onTrigger(player, argc) local message = tostring(player.zone.GetAllActors().Count); - player.SendMessage(0x20, "", message); - + player.SendMessage(0x20, "", message); end \ No newline at end of file diff --git a/data/scripts/commands/magic/aero.lua b/data/scripts/commands/magic/aero.lua index 30039450..3deb8462 100644 --- a/data/scripts/commands/magic/aero.lua +++ b/data/scripts/commands/magic/aero.lua @@ -9,6 +9,14 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + action.statusMagnitude = 15; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/aerora.lua b/data/scripts/commands/magic/aerora.lua index 03c40474..d8e01c53 100644 --- a/data/scripts/commands/magic/aerora.lua +++ b/data/scripts/commands/magic/aerora.lua @@ -15,13 +15,19 @@ function onCombo(caster, target, spell) spell.potency = spell.potency * 1.5; end; -function onMagicFinish(caster, target, spell, action) - local damage = math.random(10, 100); - +function onSkillFinish(caster, target, skill, action, actionContainer) --Dispels an effect on each target. - local effects = target.statusEffects.GetStatusEffectsByFlag(16); --lose on dispel + local effects = target.statusEffects.GetStatusEffectsByFlag2(16); --lose on dispel if effects != nil then target.statusEffects.RemoveStatusEffect(effects[0]); end; - return damage; + + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/ballad_of_magi.lua b/data/scripts/commands/magic/ballad_of_magi.lua index 9b3636fe..8f1a2003 100644 --- a/data/scripts/commands/magic/ballad_of_magi.lua +++ b/data/scripts/commands/magic/ballad_of_magi.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onBuffMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/blizzara.lua b/data/scripts/commands/magic/blizzara.lua index d12d70a3..6fbe1c9b 100644 --- a/data/scripts/commands/magic/blizzara.lua +++ b/data/scripts/commands/magic/blizzara.lua @@ -9,6 +9,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - return magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/blizzard.lua b/data/scripts/commands/magic/blizzard.lua index 36db2947..96482678 100644 --- a/data/scripts/commands/magic/blizzard.lua +++ b/data/scripts/commands/magic/blizzard.lua @@ -8,6 +8,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/burst.lua b/data/scripts/commands/magic/burst.lua index d3f98329..1c94a9f8 100644 --- a/data/scripts/commands/magic/burst.lua +++ b/data/scripts/commands/magic/burst.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, spell) end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/cura.lua b/data/scripts/commands/magic/cura.lua index 51e8820d..6713dadc 100644 --- a/data/scripts/commands/magic/cura.lua +++ b/data/scripts/commands/magic/cura.lua @@ -9,6 +9,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onCureMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide + --2.5 HP per Healing Magic Potency + --0.5 HP per MND + --this is WITH WHM AF chest, don't know formula without AF. AF seems to increase healing by 7-10%? + action.amount = 2.5 * caster.GetMod(modifiersGlobal.MagicHeal) + 0.5 * (caster.GetMod(modifiersGlobal.Mind)); + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/curaga.lua b/data/scripts/commands/magic/curaga.lua index 7456ca1e..dadd1241 100644 --- a/data/scripts/commands/magic/curaga.lua +++ b/data/scripts/commands/magic/curaga.lua @@ -5,11 +5,15 @@ function onMagicPrepare(caster, target, spell) return 0; end; +--Idea: add way to sort list of targets by hp here? function onMagicStart(caster, target, spell) return 0; end; ---http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide read -function onMagicFinish(caster, target, spell, action) - magic.onCureMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/cure.lua b/data/scripts/commands/magic/cure.lua index 51e8820d..cafa30a2 100644 --- a/data/scripts/commands/magic/cure.lua +++ b/data/scripts/commands/magic/cure.lua @@ -1,5 +1,6 @@ require("global"); require("magic"); +require("modifiers"); function onMagicPrepare(caster, target, spell) return 0; @@ -9,6 +10,28 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onCureMagicFinish(caster, target, spell, action) +--http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide +function onSkillFinish(caster, target, skill, action, actionContainer) + + --Non-CNJ + --1.10 per HMP + --0 per MND + local hpPerHMP = 1.10; + local hpPerMND = 0; + + --CNJ + --With AF: + --1.25 HP per Healing Magic Potency + --0.25 HP per MND + --This is WITH AF chest. Without is lower. AF is ~7-10% increase apparently + --I'm guessing without AF hpPerHMP will be 1.1? + if (caster.GetClass() == 23) then + hpPerHMP = 1.25; + hpPerMND = 0.25; + end + + action.amount = hpPerHMP * caster.GetMod(modifiersGlobal.MagicHeal) + hpPerMND * (caster.GetMod(modifiersGlobal.Mind)); + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/default.lua b/data/scripts/commands/magic/default.lua index 51e8820d..6fbe1c9b 100644 --- a/data/scripts/commands/magic/default.lua +++ b/data/scripts/commands/magic/default.lua @@ -9,6 +9,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onCureMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/fira.lua b/data/scripts/commands/magic/fira.lua index 3c7c0942..c7dc3f48 100644 --- a/data/scripts/commands/magic/fira.lua +++ b/data/scripts/commands/magic/fira.lua @@ -14,6 +14,10 @@ function onCombo(caster, target, spell) spell.castTimeMs = spell.castTimeMs / 2; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/firaga.lua b/data/scripts/commands/magic/firaga.lua index 2658db16..e145c551 100644 --- a/data/scripts/commands/magic/firaga.lua +++ b/data/scripts/commands/magic/firaga.lua @@ -14,6 +14,10 @@ function onCombo(caster, target, spell) spell.castTimeMs = spell.castTimeMs / 2; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/fire.lua b/data/scripts/commands/magic/fire.lua index 30039450..cb88bda7 100644 --- a/data/scripts/commands/magic/fire.lua +++ b/data/scripts/commands/magic/fire.lua @@ -9,6 +9,10 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/flare.lua b/data/scripts/commands/magic/flare.lua index eba41392..6fbe1c9b 100644 --- a/data/scripts/commands/magic/flare.lua +++ b/data/scripts/commands/magic/flare.lua @@ -9,8 +9,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - --increase potency based on proximity to target +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; - magic.onMagicFinish(caster, target, spell, action) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/freeze.lua b/data/scripts/commands/magic/freeze.lua index 30039450..5d7349bb 100644 --- a/data/scripts/commands/magic/freeze.lua +++ b/data/scripts/commands/magic/freeze.lua @@ -9,6 +9,14 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --Freeze generates 0 enmity and removes a flat 720 enmity + spell.enmityModifier = 0; + target.hateContainer.UpdateHate(caster, -720); + + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/holy.lua b/data/scripts/commands/magic/holy.lua index 30039450..6fbe1c9b 100644 --- a/data/scripts/commands/magic/holy.lua +++ b/data/scripts/commands/magic/holy.lua @@ -9,6 +9,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/holy_succor.lua b/data/scripts/commands/magic/holy_succor.lua index 5bf11269..77ada4bc 100644 --- a/data/scripts/commands/magic/holy_succor.lua +++ b/data/scripts/commands/magic/holy_succor.lua @@ -9,13 +9,21 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - spell.statusId = 228011; - spell.statusDuration = 25; - spell.statusChance = 1.0; - magic.onCureMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + action.amount = skill.basePotency; + --8071401: Gallant Gauntlets: Enhances Holy Succor + if caster.GetEquipment().GetItemAtSlot(13).itemId == 8071401 then + action.amount = action.amount * 1.10; + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --When cast on another player you also heal 50% of the amount restored. if caster != target then - action.AddHealAction(caster.actorId, (action.amount / 2)); + caster.AddHP(action.amount / 2) + --33012: You recover [amount] HP. + actionContainer.AddHPAction(caster.actorId, 33012, (action.amount / 2)); end end; \ No newline at end of file diff --git a/data/scripts/commands/magic/minuet_of_rigor.lua b/data/scripts/commands/magic/minuet_of_rigor.lua index 9b3636fe..8f1a2003 100644 --- a/data/scripts/commands/magic/minuet_of_rigor.lua +++ b/data/scripts/commands/magic/minuet_of_rigor.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onBuffMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/paeon_of_war.lua b/data/scripts/commands/magic/paeon_of_war.lua index 9b3636fe..8f1a2003 100644 --- a/data/scripts/commands/magic/paeon_of_war.lua +++ b/data/scripts/commands/magic/paeon_of_war.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onBuffMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/protect.lua b/data/scripts/commands/magic/protect.lua index 71670940..6e24db7b 100644 --- a/data/scripts/commands/magic/protect.lua +++ b/data/scripts/commands/magic/protect.lua @@ -1,5 +1,6 @@ require("global"); require("magic"); +require("modifiers"); function onMagicPrepare(caster, target, spell) return 0; @@ -9,6 +10,15 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onStatusMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --Actual amount of def/mdef will be calculated in OnGain + skill.statusMagnitude = caster.GetMod(modifiersGlobal.MagicEnhancePotency); + + --27365: Enhanced Protect: Increases magic defense gained from Protect. + if caster.HasTrait(27365) then + skill.statusTier = 2; + end + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/raise.lua b/data/scripts/commands/magic/raise.lua new file mode 100644 index 00000000..ef5b8ad1 --- /dev/null +++ b/data/scripts/commands/magic/raise.lua @@ -0,0 +1,18 @@ +require("global"); +require("magic"); + +function onMagicPrepare(caster, target, spell) + return 0; +end; + +function onMagicStart(caster, target, spell) + --27363: Enhanced Raise: No longer inflicts weakness. + if caster.HasTrait(27363) then + ability.statusTier = 2; + end + return 0; +end; +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/magic/regen.lua b/data/scripts/commands/magic/regen.lua new file mode 100644 index 00000000..5f93a333 --- /dev/null +++ b/data/scripts/commands/magic/regen.lua @@ -0,0 +1,34 @@ +require("global"); +require("magic"); +require("modifiers"); + +function onMagicPrepare(caster, target, spell) + return 0; +end; + +function onMagicStart(caster, target, spell) + return 0; +end; + +--http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide +function onSkillFinish(caster, target, skill, action, actionContainer) + --For every 1-2-2-1-2 (repeating 3x) then 1-2-1-2-2 (repeating 3x) Enhancing magic potency you have, the amount your Regen cures per tic increases by 1. + --.625 * Enhancing + local slope = 0.625; + local intercept = -110; + + if caster.GetEquipment().GetItemAtSlot(14).itemId == 8051406 then + --I don't know if the numbers in that thread are completely correct because the AF Regen table has 3 1555s in a row. + --If we assume that AF boots multiply both static parts of the regenTick equation by 1.25, we get a decently close match to actual numbers + slope = slope * 1.25; + intercept = intercept * 1.25; + end + + local regenTick = (slope * caster.GetMod(modifiersGlobal.MagicEnhancePotency)) + intercept) + 1; + + + spell.statusMagnitude = regenTick; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/magic/repose.lua b/data/scripts/commands/magic/repose.lua index 30039450..8f1a2003 100644 --- a/data/scripts/commands/magic/repose.lua +++ b/data/scripts/commands/magic/repose.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/sanguine_rite.lua b/data/scripts/commands/magic/sanguine_rite.lua index 71670940..8f1a2003 100644 --- a/data/scripts/commands/magic/sanguine_rite.lua +++ b/data/scripts/commands/magic/sanguine_rite.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onStatusMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/sleep.lua b/data/scripts/commands/magic/sleep.lua index 71670940..8f1a2003 100644 --- a/data/scripts/commands/magic/sleep.lua +++ b/data/scripts/commands/magic/sleep.lua @@ -9,6 +9,7 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onStatusMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/stone.lua b/data/scripts/commands/magic/stone.lua index 30039450..728384d3 100644 --- a/data/scripts/commands/magic/stone.lua +++ b/data/scripts/commands/magic/stone.lua @@ -9,6 +9,14 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + action.statusMagnitude = 50; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/stonera.lua b/data/scripts/commands/magic/stonera.lua index 74593a56..bc535ed2 100644 --- a/data/scripts/commands/magic/stonera.lua +++ b/data/scripts/commands/magic/stonera.lua @@ -12,9 +12,16 @@ end; --Increased damage and conversion to single target function onCombo(caster, target, spell) spell.aoeType = 0; - spell.potency = spell.potency * 1.5; + spell.basePotency = spell.basePotency * 1.5; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/stoneskin.lua b/data/scripts/commands/magic/stoneskin.lua index 71670940..c49b190a 100644 --- a/data/scripts/commands/magic/stoneskin.lua +++ b/data/scripts/commands/magic/stoneskin.lua @@ -9,6 +9,18 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onStatusMagicFinish(caster, target, spell, action) +--http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide +function onSkillFinish(caster, target, skill, action, actionContainer) + + local hpPerPoint = 1.34;--? 1.33? + + --27364: Enhanced Stoneskin: Increases efficacy of Stoneskin + if caster.HasTrait(27364) then + hpPerPoint = 1.96; + end + + spell.statusMagnitude = hpPerPoint * caster.GetMod(modifiersGlobal.MagicEnhancePotency); + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/thundaga.lua b/data/scripts/commands/magic/thundaga.lua index 862f1846..61b2834e 100644 --- a/data/scripts/commands/magic/thundaga.lua +++ b/data/scripts/commands/magic/thundaga.lua @@ -13,6 +13,13 @@ function onCombo(caster, target, spell) spell.critDamageModifier = 1.5; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/thundara.lua b/data/scripts/commands/magic/thundara.lua index b163bc19..a828567a 100644 --- a/data/scripts/commands/magic/thundara.lua +++ b/data/scripts/commands/magic/thundara.lua @@ -15,6 +15,13 @@ function onCombo(caster, target, spell) spell.recastTimeMs = spell.recastTimeMs / 2; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/magic/thunder.lua b/data/scripts/commands/magic/thunder.lua index 36db2947..96482678 100644 --- a/data/scripts/commands/magic/thunder.lua +++ b/data/scripts/commands/magic/thunder.lua @@ -8,6 +8,13 @@ function onMagicStart(caster, target, spell) return 0; end; -function onMagicFinish(caster, target, spell, action) - magic.onMagicFinish(caster, target, spell, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/aura_pulse.lua b/data/scripts/commands/weaponskill/aura_pulse.lua index eeb6b6a0..0bf98213 100644 --- a/data/scripts/commands/weaponskill/aura_pulse.lua +++ b/data/scripts/commands/weaponskill/aura_pulse.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, skill) skill.statusChance = 0.50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/bloodletter.lua b/data/scripts/commands/weaponskill/bloodletter.lua index 4764eb61..645d92d0 100644 --- a/data/scripts/commands/weaponskill/bloodletter.lua +++ b/data/scripts/commands/weaponskill/bloodletter.lua @@ -9,12 +9,18 @@ function onSkillStart(caster, target, skill) return 0; end; ---Inflicts additional damage when bleed ends ---Note for later, going to set bleed tier to 2, when bleed get scripted, check if tier is 2 and add additional damage at the end +--Changes status to Bloodletter from Bloodletter2. Changes icon of dot and adds additional damage at the end. function onCombo(caster, target, skill) - skill.statusTier = 2; + skill.statusId = 223127; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/brutal_swing.lua b/data/scripts/commands/weaponskill/brutal_swing.lua index 5c3b09e4..a304d23e 100644 --- a/data/scripts/commands/weaponskill/brutal_swing.lua +++ b/data/scripts/commands/weaponskill/brutal_swing.lua @@ -14,6 +14,10 @@ function onPositional(caster, target, skill) skill.basePotency = skill.basePotency * 1.5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/chaos_thrust.lua b/data/scripts/commands/weaponskill/chaos_thrust.lua index 118ec4e9..ed58cdab 100644 --- a/data/scripts/commands/weaponskill/chaos_thrust.lua +++ b/data/scripts/commands/weaponskill/chaos_thrust.lua @@ -11,9 +11,16 @@ end; --Increased crit hit rating function onCombo(caster, target, skill) - skill.critRateModifier = 1.5; + skill.bonusCritRate = 100; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/concussive_blow.lua b/data/scripts/commands/weaponskill/concussive_blow.lua index b974bb40..2271f588 100644 --- a/data/scripts/commands/weaponskill/concussive_blow.lua +++ b/data/scripts/commands/weaponskill/concussive_blow.lua @@ -11,8 +11,7 @@ end; --Chance to inflict blind on flank function onPositional(caster, target, skill) - skill.statusChance = 0.50; - skill.statusDuration = 10; + skill.statusChance = 0.75; end; function onCombo(caster, target, skill) @@ -20,6 +19,13 @@ function onCombo(caster, target, skill) end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/default.lua b/data/scripts/commands/weaponskill/default.lua index ffe6d0fc..a9da9873 100644 --- a/data/scripts/commands/weaponskill/default.lua +++ b/data/scripts/commands/weaponskill/default.lua @@ -9,6 +9,13 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/demolish.lua b/data/scripts/commands/weaponskill/demolish.lua index 0bef1791..733e9e4d 100644 --- a/data/scripts/commands/weaponskill/demolish.lua +++ b/data/scripts/commands/weaponskill/demolish.lua @@ -18,6 +18,13 @@ function onCombo(caster, target, skill) end; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/disembowel.lua b/data/scripts/commands/weaponskill/disembowel.lua index 4bbcaddc..b58a2b8e 100644 --- a/data/scripts/commands/weaponskill/disembowel.lua +++ b/data/scripts/commands/weaponskill/disembowel.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, skill) skill.statusDuration = skill.statusDuration * 2; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/doom_spike.lua b/data/scripts/commands/weaponskill/doom_spike.lua index b6b39efa..e40f0057 100644 --- a/data/scripts/commands/weaponskill/doom_spike.lua +++ b/data/scripts/commands/weaponskill/doom_spike.lua @@ -11,9 +11,13 @@ end; --Increased accuracy function onCombo(caster, target, skill) - skill.accuracyModifier = 1.25; + skill.accuracyModifier = 50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/dragon_kick.lua b/data/scripts/commands/weaponskill/dragon_kick.lua index dc0ce4bd..115ab485 100644 --- a/data/scripts/commands/weaponskill/dragon_kick.lua +++ b/data/scripts/commands/weaponskill/dragon_kick.lua @@ -14,6 +14,13 @@ function onPositional(caster, target, skill) skill.statusChance = 0.50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/fast_blade.lua b/data/scripts/commands/weaponskill/fast_blade.lua index b712e316..996efacb 100644 --- a/data/scripts/commands/weaponskill/fast_blade.lua +++ b/data/scripts/commands/weaponskill/fast_blade.lua @@ -13,6 +13,10 @@ function onPositional(caster, target, skill) skill.basePotency = skill.basePotency * 1.25; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/feint.lua b/data/scripts/commands/weaponskill/feint.lua index ffe6d0fc..620db241 100644 --- a/data/scripts/commands/weaponskill/feint.lua +++ b/data/scripts/commands/weaponskill/feint.lua @@ -9,6 +9,10 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/flat_blade.lua b/data/scripts/commands/weaponskill/flat_blade.lua index 2408e76b..0cbd4acf 100644 --- a/data/scripts/commands/weaponskill/flat_blade.lua +++ b/data/scripts/commands/weaponskill/flat_blade.lua @@ -10,9 +10,16 @@ function onSkillStart(caster, target, skill) end; function onCombo(caster, target, skill) - skill.enmityModifier = skill.enmityModifier * 2 + --http://forum.square-enix.com/ffxiv/threads/50479-Gladiator-Paladin-STR-MND-Stat-Caps/page7 + --4.5 is a bonus on top of the 1x of normal flat blade + --This is modified by MND and dlvl and caps at 4.5, dont know the values used though + skill.enmityModifier = 5.5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/fracture.lua b/data/scripts/commands/weaponskill/fracture.lua index 0a4b6193..31a84a97 100644 --- a/data/scripts/commands/weaponskill/fracture.lua +++ b/data/scripts/commands/weaponskill/fracture.lua @@ -9,6 +9,13 @@ function onSkillStart(caster, target, spell) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/full_thrust.lua b/data/scripts/commands/weaponskill/full_thrust.lua index a7e64ba2..7e6e7327 100644 --- a/data/scripts/commands/weaponskill/full_thrust.lua +++ b/data/scripts/commands/weaponskill/full_thrust.lua @@ -9,7 +9,12 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + caster.AddTP(1000); - return weaponskill.onSkillFinish(caster, target, skill, action); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/gloom_arrow.lua b/data/scripts/commands/weaponskill/gloom_arrow.lua index 409ec54d..1045af26 100644 --- a/data/scripts/commands/weaponskill/gloom_arrow.lua +++ b/data/scripts/commands/weaponskill/gloom_arrow.lua @@ -11,9 +11,16 @@ end; --Chance to inflict blind function onCombo(caster, target, skill) - skill.statusChance = 0.90; + skill.statusChance = 0.75; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/godsbane.lua b/data/scripts/commands/weaponskill/godsbane.lua index b61ca390..d47129ac 100644 --- a/data/scripts/commands/weaponskill/godsbane.lua +++ b/data/scripts/commands/weaponskill/godsbane.lua @@ -12,9 +12,34 @@ end; --Increased crit rate function onCombo(caster, target, skill) --Get Berserk statuseffect - skill.critRateModifier = 1.5; + local berserk = caster.statusEffects.GetStatusEffectById(223160); + + --if it isn't nil, remove the AP and Defense mods and reset extra to 0, increase potency + if berserk != nil then + local apPerHit = 20; + local defPerHit = 20; + + if berserk.GetTier() == 2 then + apPerHit = 24; + end + + attacker.SubtractMod(modifiersGlobal.Attack, apPerHit * berserk.GetExtra()); + attacker.Add(modifiersGlobal.Defense, defPerHit * berserk.GetExtra()); + + berserk.SetExtra(0); + + --This is about 50% crit. Don't know if that's what it gave on retail but seems kind of reasonable + skill.critRateBonus = 300; + end; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/goring_blade.lua b/data/scripts/commands/weaponskill/goring_blade.lua index 002b45fb..a63b71ba 100644 --- a/data/scripts/commands/weaponskill/goring_blade.lua +++ b/data/scripts/commands/weaponskill/goring_blade.lua @@ -6,6 +6,7 @@ function onSkillPrepare(caster, target, skill) end; function onSkillStart(caster, target, skill) + skill.statusMagnitude = 25;--could probalby have a status magnitude value return 0; end; @@ -15,10 +16,18 @@ function onPositional(caster, target, skill) end; --Increases bleed damage +--Bleed damage seems like it's 25 with comboed being 38 (25 * 1.5 rounded up) function onCombo(caster, target, skill) - skill.statusTier = 2; + skill.statusMagnitude = 38; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/haymaker.lua b/data/scripts/commands/weaponskill/haymaker.lua index ffe6d0fc..a9da9873 100644 --- a/data/scripts/commands/weaponskill/haymaker.lua +++ b/data/scripts/commands/weaponskill/haymaker.lua @@ -9,6 +9,13 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/heavy_shot.lua b/data/scripts/commands/weaponskill/heavy_shot.lua index ffe6d0fc..620db241 100644 --- a/data/scripts/commands/weaponskill/heavy_shot.lua +++ b/data/scripts/commands/weaponskill/heavy_shot.lua @@ -9,6 +9,10 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/heavy_swing.lua b/data/scripts/commands/weaponskill/heavy_swing.lua index 6cbf7811..ce72c59b 100644 --- a/data/scripts/commands/weaponskill/heavy_swing.lua +++ b/data/scripts/commands/weaponskill/heavy_swing.lua @@ -11,10 +11,14 @@ end; --Increased accuracy function onCombo(caster, target, skill) - skill.accuracyModifier = 1.5; + skill.accuracyModifier = 50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/heavy_thrust.lua b/data/scripts/commands/weaponskill/heavy_thrust.lua index 8a77dc73..cbdea342 100644 --- a/data/scripts/commands/weaponskill/heavy_thrust.lua +++ b/data/scripts/commands/weaponskill/heavy_thrust.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, skill) skill.statusDuration = 10; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/howling_fist.lua b/data/scripts/commands/weaponskill/howling_fist.lua index 47692865..d588268b 100644 --- a/data/scripts/commands/weaponskill/howling_fist.lua +++ b/data/scripts/commands/weaponskill/howling_fist.lua @@ -10,15 +10,19 @@ function onSkillStart(caster, target, skill) end; --Increased accuracy -function onCombo(caster, target, skill) - skill.accuracyModifier = 1; +function onPositional(caster, target, skill) + skill.accuracyModifier = 50; end; --Increased damage function onCombo(caster, target, skill) - skill.potency = skill.potency * 1.5; + skill.basePotency = skill.basePotency * 1.5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/impulse_drive.lua b/data/scripts/commands/weaponskill/impulse_drive.lua index d5a6b5f5..1459ebf6 100644 --- a/data/scripts/commands/weaponskill/impulse_drive.lua +++ b/data/scripts/commands/weaponskill/impulse_drive.lua @@ -11,14 +11,18 @@ end; --Increased damage function onPositional(caster, target, skill) - skill.potency = skill.potency * 1.25 + skill.basePotency = skill.basePotency * 1.25 end; --Increased crit hit rating function onCombo(caster, target, skill) - skill.critRateModifier = 1.25; + skill.bonusCritRate = 200; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/leaden_arrow.lua b/data/scripts/commands/weaponskill/leaden_arrow.lua index 6386e890..e94da64b 100644 --- a/data/scripts/commands/weaponskill/leaden_arrow.lua +++ b/data/scripts/commands/weaponskill/leaden_arrow.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, skill) skill.statusDuration = 60; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/leg_sweep.lua b/data/scripts/commands/weaponskill/leg_sweep.lua index 753d8f40..a8428109 100644 --- a/data/scripts/commands/weaponskill/leg_sweep.lua +++ b/data/scripts/commands/weaponskill/leg_sweep.lua @@ -14,6 +14,13 @@ function onCombo(caster, target, skill) skill.statusChance = 0.50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/maim.lua b/data/scripts/commands/weaponskill/maim.lua index e145272b..861e4315 100644 --- a/data/scripts/commands/weaponskill/maim.lua +++ b/data/scripts/commands/weaponskill/maim.lua @@ -10,9 +10,13 @@ function onSkillStart(caster, target, skill) end; function onCombo(caster, target, skill) - skill.accuracyModifier = 1.5; + skill.accuracyModifier = 50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + skill.Potency = 100; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/overpower.lua b/data/scripts/commands/weaponskill/overpower.lua new file mode 100644 index 00000000..620db241 --- /dev/null +++ b/data/scripts/commands/weaponskill/overpower.lua @@ -0,0 +1,18 @@ +require("global"); +require("weaponskill"); + +function onSkillPrepare(caster, target, skill) + return 0; +end; + +function onSkillStart(caster, target, skill) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/path_of_the_storm.lua b/data/scripts/commands/weaponskill/path_of_the_storm.lua index 710484ed..e8a48aaf 100644 --- a/data/scripts/commands/weaponskill/path_of_the_storm.lua +++ b/data/scripts/commands/weaponskill/path_of_the_storm.lua @@ -12,9 +12,15 @@ end; --Chance to inflict heavy when executed from behind function onPositional(caster, target, skill) skill.statusChance = 0.50; - skill.statusDuration = 5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/phalanx.lua b/data/scripts/commands/weaponskill/phalanx.lua new file mode 100644 index 00000000..620db241 --- /dev/null +++ b/data/scripts/commands/weaponskill/phalanx.lua @@ -0,0 +1,18 @@ +require("global"); +require("weaponskill"); + +function onSkillPrepare(caster, target, skill) + return 0; +end; + +function onSkillStart(caster, target, skill) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/piercing_arrow.lua b/data/scripts/commands/weaponskill/piercing_arrow.lua index ffe6d0fc..620db241 100644 --- a/data/scripts/commands/weaponskill/piercing_arrow.lua +++ b/data/scripts/commands/weaponskill/piercing_arrow.lua @@ -9,6 +9,10 @@ function onSkillStart(caster, target, skill) return 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/pounce.lua b/data/scripts/commands/weaponskill/pounce.lua index 64d41eb1..31089960 100644 --- a/data/scripts/commands/weaponskill/pounce.lua +++ b/data/scripts/commands/weaponskill/pounce.lua @@ -11,9 +11,15 @@ end; function onPositional(caster, target, skill) skill.statusChance = 0.50; - skill.statusDuration = 5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/pummel.lua b/data/scripts/commands/weaponskill/pummel.lua index b9802c0b..996efacb 100644 --- a/data/scripts/commands/weaponskill/pummel.lua +++ b/data/scripts/commands/weaponskill/pummel.lua @@ -13,6 +13,10 @@ function onPositional(caster, target, skill) skill.basePotency = skill.basePotency * 1.25; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action) +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/quick_nock.lua b/data/scripts/commands/weaponskill/quick_nock.lua index a08d59fd..8ff7da1c 100644 --- a/data/scripts/commands/weaponskill/quick_nock.lua +++ b/data/scripts/commands/weaponskill/quick_nock.lua @@ -17,6 +17,10 @@ function onCombo(caster, target, skill) --animation change? end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/rage_of_halone.lua b/data/scripts/commands/weaponskill/rage_of_halone.lua index e5bf1634..d459bdbe 100644 --- a/data/scripts/commands/weaponskill/rage_of_halone.lua +++ b/data/scripts/commands/weaponskill/rage_of_halone.lua @@ -11,9 +11,15 @@ end; --Accuracy increase function onCombo(caster, target, skill) - skill.accuracyModifier = 1; + --Rage of Halone normally has a -40% hit rate modifier. + --Does the combo negate that, or does it make it even more accurate than if it didnt have the modifier? + skill.accuracyModifier = 0; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/rain_of_death.lua b/data/scripts/commands/weaponskill/rain_of_death.lua index a7fb10ac..53e84097 100644 --- a/data/scripts/commands/weaponskill/rain_of_death.lua +++ b/data/scripts/commands/weaponskill/rain_of_death.lua @@ -11,9 +11,16 @@ end; --Chance to inflict stun function onCombo(caster, target, skill) - skill.statusChance = 0.90 + skill.statusChance = 0.75 end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/ring_of_talons.lua b/data/scripts/commands/weaponskill/ring_of_talons.lua index 0972277c..ffa4994a 100644 --- a/data/scripts/commands/weaponskill/ring_of_talons.lua +++ b/data/scripts/commands/weaponskill/ring_of_talons.lua @@ -11,9 +11,13 @@ end; --Increased critical hit rate function onCombo(caster, target, skill) - skill.critRateModifier = 1.5; + skill.bonusCritRate = 100; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/riot_blade.lua b/data/scripts/commands/weaponskill/riot_blade.lua index 85477b46..d4cd7c07 100644 --- a/data/scripts/commands/weaponskill/riot_blade.lua +++ b/data/scripts/commands/weaponskill/riot_blade.lua @@ -12,8 +12,16 @@ end; --Chance to decrease defense when executed from behind the target function onPositional(caster, target, skill) skill.statusChance = 0.75; + skill.statusMagnitude = 100; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/savage_blade.lua b/data/scripts/commands/weaponskill/savage_blade.lua index 0a83c4e2..75985bc7 100644 --- a/data/scripts/commands/weaponskill/savage_blade.lua +++ b/data/scripts/commands/weaponskill/savage_blade.lua @@ -13,7 +13,10 @@ function onCombo(caster, target, skill) skill.basePotency = skill.basePotency * 1.25; end; +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/shadowbind.lua b/data/scripts/commands/weaponskill/shadowbind.lua index b251906a..829a81db 100644 --- a/data/scripts/commands/weaponskill/shadowbind.lua +++ b/data/scripts/commands/weaponskill/shadowbind.lua @@ -11,10 +11,16 @@ end; --Increased Bind duration function onCombo(caster, target, skill) - skill.statusDuration = 10; + skill.statusDuration = 30; end; +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/shield_bash.lua b/data/scripts/commands/weaponskill/shield_bash.lua index 1cfc66c2..a9da9873 100644 --- a/data/scripts/commands/weaponskill/shield_bash.lua +++ b/data/scripts/commands/weaponskill/shield_bash.lua @@ -9,7 +9,13 @@ function onSkillStart(caster, target, skill) return 0; end; +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/shoulder_tackle.lua b/data/scripts/commands/weaponskill/shoulder_tackle.lua index 7bd4c304..2fef254a 100644 --- a/data/scripts/commands/weaponskill/shoulder_tackle.lua +++ b/data/scripts/commands/weaponskill/shoulder_tackle.lua @@ -8,11 +8,19 @@ end; function onSkillStart(caster, target, skill) return 0; end; - -function onSkillFinish(caster, target, skill, action) + +function onSkillFinish(caster, target, skill, action, actionContainer) --chance to influct stun only when target has no enmity towards you - if !(target.hateContainer.HasHateForTarget(caster)) then + if not (target.hateContainer.HasHateForTarget(caster)) then skill.statusChance = 0.50; end - return weaponskill.onSkillFinish(caster, target, skill, action); -end; + + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/simian_thrash.lua b/data/scripts/commands/weaponskill/simian_thrash.lua index 1c44710f..545468c0 100644 --- a/data/scripts/commands/weaponskill/simian_thrash.lua +++ b/data/scripts/commands/weaponskill/simian_thrash.lua @@ -9,11 +9,15 @@ function onSkillStart(caster, target, skill) return 0; end; ---Increased accuracy +--Increased damage function onCombo(caster, target, skill) skill.basePotency = skill.basePotency * 1.5; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/skull_sunder.lua b/data/scripts/commands/weaponskill/skull_sunder.lua index bfa679d4..ac7056dd 100644 --- a/data/scripts/commands/weaponskill/skull_sunder.lua +++ b/data/scripts/commands/weaponskill/skull_sunder.lua @@ -11,9 +11,14 @@ end; --Increased enmity function onCombo(caster, target, skill) - skill.enmityModifier = 1.5; + --https://www.bluegartr.com/threads/107403-Stats-and-how-they-work/page17 + skill.enmityModifier = 2.75; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/spirits_within.lua b/data/scripts/commands/weaponskill/spirits_within.lua index ab7c74fc..193a7a70 100644 --- a/data/scripts/commands/weaponskill/spirits_within.lua +++ b/data/scripts/commands/weaponskill/spirits_within.lua @@ -11,13 +11,19 @@ end; --Increased enmity function onCombo(caster, target, skill) - skill.enmityModifier = 1.5; + skill.enmityModifier = 2.5; end; -function onSkillFinish(caster, target, skill, action) - local damage = math.random(10, 100); +function onSkillFinish(caster, target, skill, action, actionContainer) --Increased damage with higher hp + --random guess local potencyModifier = caster:GetHPP() + 25; - skill.basePotency = skill.basePotency * (potencyModifier / 100); - return weaponskill.onSkillFinish(caster, target, skill, action) + + skill.basePotency = skill.basePotency * potencyModifier; + + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/steel_cyclone.lua b/data/scripts/commands/weaponskill/steel_cyclone.lua index 330b25e8..4f1314cd 100644 --- a/data/scripts/commands/weaponskill/steel_cyclone.lua +++ b/data/scripts/commands/weaponskill/steel_cyclone.lua @@ -11,10 +11,16 @@ end; --Increased critical hit rate function onCombo(caster, target, skill) - skill.critRateModifier = 1.5; + skill.bonusCritRate = 200; end; - -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/sucker_punch.lua b/data/scripts/commands/weaponskill/sucker_punch.lua new file mode 100644 index 00000000..5f188546 --- /dev/null +++ b/data/scripts/commands/weaponskill/sucker_punch.lua @@ -0,0 +1,44 @@ +require("global"); +require("weaponskill"); +require("battleutils"); +require("hiteffect"); + +function onSkillPrepare(caster, target, skill) + return 0; +end; + +function onSkillStart(caster, target, skill) + return 0; +end; + +-- +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, action); + + --additional effect + --Restores MP + --Comboed formula seems to be (0.40 * damage) + 180 + --Uncomboed formula seems to be 0.30 * damage + --These may be wrong. It seems like max mp might influence the slope + + --1.21: Equation used to calculate amount of MP adjusted. + --fug + --This might mean max MP isn't involved and the difference was between patches. need to recheck videos + if action.GetHitType() > HitType.Evade and (action.param == HitDirection.Right or action.param == HitDirection.Left) then + local mpToReturn = 0; + + if skill.isCombo then + mpToReturn = (0.40 * action.amount) + 180; + else + mpToReturn = (0.30 * action.amount); + end + + caster.AddMP(mpToReturn); + --30452: You recover x MP. + actionContainer.AddMPAction(caster.actorId, 30452, mpToReturn); + end +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/true_thrust.lua b/data/scripts/commands/weaponskill/true_thrust.lua index 33b4b40c..ec3d888f 100644 --- a/data/scripts/commands/weaponskill/true_thrust.lua +++ b/data/scripts/commands/weaponskill/true_thrust.lua @@ -11,9 +11,13 @@ end; --Increased accuracy from in front function onPositional(caster, target, skill) - skill.accuracyModifier = 1.25; + skill.accuracyModifier = 50; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/vorpal_thrust.lua b/data/scripts/commands/weaponskill/vorpal_thrust.lua index 7cc84955..7669640d 100644 --- a/data/scripts/commands/weaponskill/vorpal_thrust.lua +++ b/data/scripts/commands/weaponskill/vorpal_thrust.lua @@ -11,9 +11,16 @@ end; --Increased crit rating from behind function onPositional(caster, target, skill) - skill.critRateModifier = 1.25; + skill.bonusCritRate = 200; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); + + --Try to apply status effect + action.TryStatus(caster, target, skill, actionContainer, true); end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/war_drum.lua b/data/scripts/commands/weaponskill/war_drum.lua new file mode 100644 index 00000000..e71feea1 --- /dev/null +++ b/data/scripts/commands/weaponskill/war_drum.lua @@ -0,0 +1,20 @@ +require("global"); +require("weaponskill"); + +function onSkillPrepare(caster, target, skill) + return 0; +end; + +function onSkillStart(caster, target, skill) + return 0; +end; + +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --might be wrong + action.enmity = action.enmity + 400; + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/whirlwind.lua b/data/scripts/commands/weaponskill/whirlwind.lua index 6c1f4678..26b7a7e1 100644 --- a/data/scripts/commands/weaponskill/whirlwind.lua +++ b/data/scripts/commands/weaponskill/whirlwind.lua @@ -14,15 +14,27 @@ function onCombo(caster, target, skill) --Get Berserk statuseffect local berserk = caster.statusEffects.GetStatusEffectById(223160); - --if it isn't nil + --if it isn't nil, remove the AP and Defense mods and reset extra to 0, increase potency if berserk != nil then - berserk.SetTier(1); + local apPerHit = 20; + local defPerHit = 20; + + if berserk.GetTier() == 2 then + apPerHit = 24; + end + + attacker.SubtractMod(modifiersGlobal.Attack, apPerHit * berserk.GetExtra()); + attacker.Add(modifiersGlobal.Defense, defPerHit * berserk.GetExtra()); + + berserk.SetExtra(0); skill.basePotency = skill.basePotency * 1.5; end; - - end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); -end; +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); +end; \ No newline at end of file diff --git a/data/scripts/commands/weaponskill/wide_volley.lua b/data/scripts/commands/weaponskill/wide_volley.lua index bb937e55..a16f8cd1 100644 --- a/data/scripts/commands/weaponskill/wide_volley.lua +++ b/data/scripts/commands/weaponskill/wide_volley.lua @@ -11,9 +11,13 @@ end; --Increased Accuracy function onCombo(caster, target, skill) - skill.accuracyModifier = 1.25; + skill.accuracyModifier = 40; end; -function onSkillFinish(caster, target, skill, action) - return weaponskill.onSkillFinish(caster, target, skill, action); +function onSkillFinish(caster, target, skill, action, actionContainer) + --calculate ws damage + action.amount = skill.basePotency; + + --DoAction handles rates, buffs, dealing damage + action.DoAction(caster, target, skill, actionContainer); end; \ No newline at end of file diff --git a/data/scripts/directors/Quest/QuestDirectorMan0g001.lua b/data/scripts/directors/Quest/QuestDirectorMan0g001.lua index 000bad4d..934e48be 100644 --- a/data/scripts/directors/Quest/QuestDirectorMan0g001.lua +++ b/data/scripts/directors/Quest/QuestDirectorMan0g001.lua @@ -16,6 +16,7 @@ end function onEventStarted(player, actor, triggerName) man0g0Quest = player:GetQuest("Man0g0"); + player:SetMod(modifiersGlobal.MinimumHpLock, 1); player:SendMessage(0x20, "", "Starting"); startTutorialMode(player); callClientFunction(player, "delegateEvent", player, man0g0Quest, "processTtrBtl001", nil, nil, nil); @@ -38,9 +39,11 @@ function onEventStarted(player, actor, triggerName) showTutorialSuccessWidget(player, 9055); --Open TutorialSuccessWidget for attacking enemy openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_TP); waitForSignal("tpOver1000"); + player:SetMod(modifiersGlobal.MinimumTpLock, 1000); closeTutorialWidget(player); openTutorialWidget(player, CONTROLLER_KEYBOARD, TUTORIAL_WEAPONSKILLS); waitForSignal("weaponskillUsed"); + player:SetMod(modifiersGlobal.MinimumTpLock, 0); closeTutorialWidget(player); showTutorialSuccessWidget(player, 9065); --Open TutorialSuccessWidget for weapon skill elseif player:IsDiscipleOfMagic() then @@ -61,6 +64,7 @@ function onEventStarted(player, actor, triggerName) player:SendMessage(0x20, "", "Waiting for mobkill3"); waitForSignal("mobkill"); worldMaster = GetWorldMaster(); + player:SetMod(modifiersGlobal.MinimumHpLock, 0); player:SendMessage(0x20, "", "Sending data packet 'attention'"); player:SendDataPacket("attention", worldMaster, "", 51073, 2); wait(5); diff --git a/data/scripts/effects/aegis_boon.lua b/data/scripts/effects/aegis_boon.lua new file mode 100644 index 00000000..a710e113 --- /dev/null +++ b/data/scripts/effects/aegis_boon.lua @@ -0,0 +1,21 @@ +require("global") +require("modifiers") +require("hiteffect") +require("utils") + +--Forces a full block (0 damage taken) +function onPreAction(caster, target, effect, skill, action, actionContainer) + --If action hit from the rear and is a weaponskill ation + action.blockRate = 100.0; +end; + +--Heals for the amount of HP blocked, up to a certain point. I don't know what determines the cap but it seems to be 703 at level 50. Unsure if it scales down based on level, dlvl, or if that's an arbitrary cap added. +function onBlock(effect, attacker, defender, action, actionContainer) + --Amount blocked + local absorbAmount = math.Clamp(action.amountMitigated, 0, 703); + + --33008: You recover x HP from Aegis Boon + defender.AddHP(absorbAmount); + actionContainer.AddHPAction(defender.actorId, 33008, absorbAmount); + actionContainer.AddAction(defender.statusEffects.RemoveStatusEffectForBattleAction(effect)); +end; \ No newline at end of file diff --git a/data/scripts/effects/aero.lua b/data/scripts/effects/aero.lua new file mode 100644 index 00000000..d6e012ee --- /dev/null +++ b/data/scripts/effects/aero.lua @@ -0,0 +1,8 @@ +--Doesn't do flat damage. 20 on Lv 50 Truffle Hog, 11 on Coincounter, 7 on nael hard, 19 on 52 fachan +function onGain(target, effect) + owner.AddMod(modifiersGlobal.RegenDown, effect.GetMagnitude()); +end; + +function onLose(target, effect) + owner.AddMod(modifiersGlobal.RegenDown, effect.GetMagnitude()); +end; \ No newline at end of file diff --git a/data/scripts/effects/antagonize.lua b/data/scripts/effects/antagonize.lua new file mode 100644 index 00000000..a88cedf7 --- /dev/null +++ b/data/scripts/effects/antagonize.lua @@ -0,0 +1,13 @@ +require("modifiers") + +--Antagonize's enmity bonus is x1.5 (works for both abilities and damage dealt). x1.65 when AF is worn. +--Is does this mean it's 1.5* or 2.5*? +function onCommandStart(effect, owner, skill, actionContainer) + local enmityModifier = 1.5 + + if effect.GetTier() == 2 then + enmityModifier = 1.65; + end + + skill.enmityModifier = skill.enmityModifier + enmityModifier; +end \ No newline at end of file diff --git a/data/scripts/effects/barrage.lua b/data/scripts/effects/barrage.lua new file mode 100644 index 00000000..3273cc49 --- /dev/null +++ b/data/scripts/effects/barrage.lua @@ -0,0 +1,19 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Untraited reduces cooldown by 50% +--Traited reduces cooldown by 100% +function onCommandStart(effect, owner, skill, actionContainer) + --27259: Light Shot + if skill.id == 27259 then + skill.numHits = effect.GetMagnitude(); + end +end; + +function onCommandFinish(effect, owner, skill, actionContainer) + --27259: Light Shot + if skill.id == 27259 then + actionContainer.AddAction(owner.statusEffects.RemoveStatusEffectForBattleAction(effect)); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/berserk2.lua b/data/scripts/effects/berserk2.lua new file mode 100644 index 00000000..fc6b9193 --- /dev/null +++ b/data/scripts/effects/berserk2.lua @@ -0,0 +1,59 @@ +require("modifiers"); +require("battleutils"); + +function onGain(owner, effect) + owner.statusEffects.RemoveStatusEffect(223208); +end + +--Increases attack power and reduces defense with each successful attack +--Does this include weaponskills? +--Is this on every hit or every succesfull skill useage? +function onHit(effect, attacker, defender, action, actionContainer) + --Trait increases effect by 20%. Does this include the reduced defense, + --does this increase the cap or the rate at which you get AP or both? + + if (effect.GetExtra() < 10) then + --This will count how many hits there have been + effect.SetExtra(effect.GetExtra() + 1); + + --If you update these make sure to update them in Whirlwind as well + local apPerHit = 20; + local defPerHit = 20; + + if effect.GetTier() == 2 then + apPerHit = 24; + end + + --Just going to say every hit adds 20 AP up to 200 + --Same for defense + --Traited will be 24 up to 240 + --assuming defense is static + attacker.AddMod(modifiersGlobal.Attack, apPerHit); + attacker.SubtractMod(modifiersGlobal.Defense, defPerHit); + end +end; + +function onDamageTaken(effect, attacker, defender, action, actionContainer) + local apPerHit = 20; + local defPerHit = 20; + + if effect.GetTier() == 2 then + apPerHit = 24; + end + + defender.SubtractMod(modifiersGlobal.Attack, effect.GetExtra() * apPerHit); + defender.SubtractMod(modifiersGlobal.Defense, effect.GetExtra() * defPerHit); + effect.SetExtra(0); +end + +function onLose(owner, effect) + local apPerHit = 20; + local defPerHit = 20; + + if effect.GetTier() == 2 then + apPerHit = 24; + end + + owner.SubtractMod(modifiersGlobal.Attack, effect.GetExtra() * apPerHit); + owner.SubtractMod(modifiersGlobal.Defense, effect.GetExtra() * defPerHit); +end \ No newline at end of file diff --git a/data/scripts/effects/blindside.lua b/data/scripts/effects/blindside.lua new file mode 100644 index 00000000..a88a63fe --- /dev/null +++ b/data/scripts/effects/blindside.lua @@ -0,0 +1,15 @@ +require("modifiers") +require("battleutils") + +--Forces crit of a single WS action from rear. +function onPreAction(caster, target, effect, skill, action, actionContainer) + --If action hit from the rear and is a weaponskill ation + if (action.param == HitDirection.Rear and action.commandType == CommandType.WeaponSkill) then + --Set action's crit rate to 100% + action.critRate = 100.0; + end + + --Remove status and add message + actionsList.AddAction(target.statusEffects.RemoveForBattleAction(effect)); +end; + diff --git a/data/scripts/effects/blissful_mind.lua b/data/scripts/effects/blissful_mind.lua new file mode 100644 index 00000000..1c12cfff --- /dev/null +++ b/data/scripts/effects/blissful_mind.lua @@ -0,0 +1,21 @@ +--The amount of time it takes to fully charge varies depending on how much MP it has to restore, meaning its not just a percent every tick +--Based on a few videos it seems like it heals for 0.5% of max MP every second, traited. This is an early guess but it seems correct +--Untraited is less clear. It could be 0.25%, 0.30%, or 0.40%. Guessing it's 0.30 + +function onTick(owner, effect) + local percentPerSecond = 0.0030; + + if effect.GetTier() == 2 then + percentPerSecond = 0.005; + end + + print(effect.GetExtra()); + + local amount = percentPerSecond * owner.GetMaxMP() + 0.25; + effect.SetExtra(effect.GetExtra() + amount); + if effect.GetExtra() >= effect.GetMagnitude() then + --223242: Fully Blissful Mind + owner.statusEffects.ReplaceEffect(effect, 223242, 1, effect.GetMagnitude(), 0xffffffff); + --owner.statusEffects.ReplaceEffect(effect, true); + end +end \ No newline at end of file diff --git a/data/scripts/effects/blood_for_blood.lua b/data/scripts/effects/blood_for_blood.lua new file mode 100644 index 00000000..e9b8f0fb --- /dev/null +++ b/data/scripts/effects/blood_for_blood.lua @@ -0,0 +1,20 @@ +require("modifiers") +require("hiteffect") + +--Takes 10% of hp rounded down +--Random guess, but increases damage by 10% (12.5% traited)? +function onPreAction(caster, target, effect, skill, action, actionContainer) + local hpToRemove = math.floor(caster.GetHP() * 0.10); + local modifier = 1.10; + + if (effect.GetTier() == 2) then + modifier = 1.25; + end + + action.amount = action.amount * modifier; + caster.DelHP(hpToRemove); + + --Remove status and add message + actionContainer.AddAction(target.statusEffects.RemoveForBattleAction(effect)); +end; + diff --git a/data/scripts/effects/bloodbath.lua b/data/scripts/effects/bloodbath.lua new file mode 100644 index 00000000..2e6ea6a9 --- /dev/null +++ b/data/scripts/effects/bloodbath.lua @@ -0,0 +1,25 @@ +require("modifiers"); +require("battleutils"); + +--Absorb HP on next WS or ability +function onHit(effect, attacker, defender, action, actionContainer) + + --1.21: Absorb HP amount no longer affected by player VIT rating. + --Bloodbath seems based on both defener and attacker's stats, even after 1.21. + --Miser's Mistriss seems to resist the effect, whereas nael gets absorbed more than 100% + --Garuda resists a small amount + --Unclear what it's based on. + --Possibly magic resist? Slashing resist? + + --For now using 1.0 as baseline since that seems to be the average + if action.commandType == CommandType.Weaponskill or action.commandType == CommandType.Ability then + local absorbModifier = 1.0 + local absorbAmount = action.amount * absorbModifier; + + attacker.AddHP(absorbAmount); + --30332: You absorb hp from target + actionContainer.AddHPAction(defender.actorId, 30332, absorbAmount) + --Bloodbath is lost after absorbing hp + actionContainer.AddAction(defender.statusEffects.RemoveStatusEffectForBattleAction(effect)); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/bloodletter.lua b/data/scripts/effects/bloodletter.lua new file mode 100644 index 00000000..487041de --- /dev/null +++ b/data/scripts/effects/bloodletter.lua @@ -0,0 +1,18 @@ +--This is the comboed version of bloodletter. +--All videos I can find have it dealing 15 damage. +--Damage type is projectile. +--DoT damage is combined and all hits on a single tick. ie a blodletter doing 15 damage and aero doing 11 will combine and tick for 26. + +--Bloodletter is apparently impacted by PIE +--http://forum.square-enix.com/ffxiv/threads/35795-STR-DEX-PIE-ATK-Testing/page2 +--Chance to land is also impacted by PIE +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.RegenDown, 15); +end + +--Additional damage is 570 at level 50 +--https://ffxiv.gamerescape.com/w/index.php?title=Bloodletter&oldid=298020 +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.RegenDown, 15); + owner.DelHP(570); +end diff --git a/data/scripts/effects/bloodletter2.lua b/data/scripts/effects/bloodletter2.lua new file mode 100644 index 00000000..0ed394e0 --- /dev/null +++ b/data/scripts/effects/bloodletter2.lua @@ -0,0 +1,8 @@ +--Bloodletter2 is the uncomboed version of Bloodletter. It doesn't deal any additional damage when it falls off but has the same tick damage +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.RegenDown, 15); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.RegenDown, 15); +end diff --git a/data/scripts/effects/cleric_stance.lua b/data/scripts/effects/cleric_stance.lua new file mode 100644 index 00000000..061d13e4 --- /dev/null +++ b/data/scripts/effects/cleric_stance.lua @@ -0,0 +1,13 @@ +require("modifiers") +require("battleutils") + +function onPreAction(caster, target, effect, skill, action, actionContainer) + if skill.commandType == CommandType.Spell then + if action.actionType == ActionType.Heal then + action.amount = action.amount * 0.80; + elseif action.actionType == ActionType.Magic then + action.amount = action.amount * 1.20; + end + end +end; + diff --git a/data/scripts/effects/collusion.lua b/data/scripts/effects/collusion.lua new file mode 100644 index 00000000..ae1d34de --- /dev/null +++ b/data/scripts/effects/collusion.lua @@ -0,0 +1,13 @@ +require("global") +require("modifiers") +require("hiteffect") +require("utils") + +function onHit(effect, attacker, defender, action, actionContainer) + local enmity = action.enmity; + action.enmity = 0; + + defender.hateContainer.UpdateHate(effect.GetSource(), enmity); + --Does collusion send a message? + actionContainer.AddAction(attacker.statusEffects.RemoveStatusEffectForBattleAction(effect)); +end; \ No newline at end of file diff --git a/data/scripts/effects/cover.lua b/data/scripts/effects/cover.lua new file mode 100644 index 00000000..590583a6 --- /dev/null +++ b/data/scripts/effects/cover.lua @@ -0,0 +1,9 @@ +require("global") +require("modifiers") +require("hiteffect") +require("utils") + +--Restores 25% of damage taken as MP. Does not send a message +function onDamageTaken(effect, attacker, defender, action, actionContainer) + defender.AddMP(0.25 * action.amount); +end; \ No newline at end of file diff --git a/data/scripts/effects/decoy.lua b/data/scripts/effects/decoy.lua new file mode 100644 index 00000000..284d13d3 --- /dev/null +++ b/data/scripts/effects/decoy.lua @@ -0,0 +1,16 @@ +require("modifiers") +require("battleutils") + +--This is the untraited version of decoy. + +function onPreAction(caster, target, effect, skill, action, actionContainer) + --Evade single ranged or magic attack + --Traited allows for physical attacks + if skill.isRanged or action.actionType == ActionType.Magic then + --Set action's hit rate to 0 + action.hirRate = 0.0; + end + + --Remove status and add message + actionsList.AddAction(target.statusEffects.RemoveForBattleAction(effect)); +end; \ No newline at end of file diff --git a/data/scripts/effects/decoy2.lua b/data/scripts/effects/decoy2.lua new file mode 100644 index 00000000..d6cbf909 --- /dev/null +++ b/data/scripts/effects/decoy2.lua @@ -0,0 +1,16 @@ +require("modifiers") +require("battleutils") + +--This is the traited version of Decoy. It can also evade physical attacks. + +function onPreAction(caster, target, effect, skill, action, actionContainer) + --Evade single ranged or magic attack + --Traited allows for physical attacks + if skill.isRanged or action.actionType == ActionType.Magic or action.actionType == ActionType.Physical then + --Set action's hit rate to 0 + action.hirRate = 0.0; + end + + --Remove status and add message + actionsList.AddAction(target.statusEffects.RemoveForBattleAction(effect)); +end; \ No newline at end of file diff --git a/data/scripts/effects/defense_down.lua b/data/scripts/effects/defense_down.lua new file mode 100644 index 00000000..28de72b9 --- /dev/null +++ b/data/scripts/effects/defense_down.lua @@ -0,0 +1,7 @@ +function onGain(owner, effect) + owner.SubtractMod(modifiersGlobal.Defense, effect.GetMagnitude()); +end + +function onLose(owner, effect) + owner.AddMod(modifiersGlobal.Defense, effect.GetMagnitude()); +end diff --git a/data/scripts/effects/divine_regen.lua b/data/scripts/effects/divine_regen.lua new file mode 100644 index 00000000..0d29706c --- /dev/null +++ b/data/scripts/effects/divine_regen.lua @@ -0,0 +1,16 @@ +--Consistent 85HP/tick normal; 113HP/tick with AF pants +function onGain(owner, effect) + local magnitude = 85 + + --Need a better way to set magnitude when adding effects + if effect.GetTier() == 2 then + magnitude = 113; + end + effect.SetMagnitude(magnitude); + + owner.AddMod(modifiersGlobal.Regen, effect.GetMagnitude()); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Regen, effect.GetMagnitude()); +end diff --git a/data/scripts/effects/divine_veil.lua b/data/scripts/effects/divine_veil.lua new file mode 100644 index 00000000..edd08034 --- /dev/null +++ b/data/scripts/effects/divine_veil.lua @@ -0,0 +1,23 @@ +require("modifiers") +require("hiteffect") + +--Increases block rate by 100% +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.RawBlockRate, 100); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.RawBlockRate, 100); +end + +--Applys Divine Regen to party in range when healed by cure or cura +function onBlock(caster, target, effect, skill, action, actionContainer) + -- cure cura + if (skill.id == 27346 or skill.id == 27347) and (caster != owner) then + --For each party member in range, add divine regen + for chara in owner.GetPartyMembersInRange(8) do + local addAction = chara.statusEffects.AddStatusForBattleAction(223264, 2); + actionContainer.AddAction(addAction); + end + end +end; \ No newline at end of file diff --git a/data/scripts/effects/dread_spike.lua b/data/scripts/effects/dread_spike.lua new file mode 100644 index 00000000..94888302 --- /dev/null +++ b/data/scripts/effects/dread_spike.lua @@ -0,0 +1,23 @@ +require("modifiers") +require("battleutils") + +--Dread spike completely nullifies a physical action and absorbs how much damage it would have done (when it's powered up) +--I'm going to assume it only absorbs half damage without LS/PS up +--When I say it nullifies an attack, it even gets rid of the message. It's as if the attack didn't happen +--Don't know how this works with multi-hit attacks or even how it works with stoneskin or other buffs that respond to damage +-- I dont really know how this should work... +function onDamageTaken(effect, attacker, defender, action, actionContainer) + if action.actionType == ActionType.Physical then + --maybe this works? + local absorbAmount = action.amount; + action.amount = 0; + action.worldMasterTextId = 0; + + attacker.AddHP(absorbAmount); + --30451: You recover [absorbAmount] HP. + actionContainer.AddHPAction(defender.actorId, 30451, absorbAmount) + --Dread Spike is lost after absorbing hp + actionContainer.AddAction(defender.statusEffects.RemoveStatusEffectForBattleAction(effect)); + end +end; + diff --git a/data/scripts/effects/enduring_march.lua b/data/scripts/effects/enduring_march.lua new file mode 100644 index 00000000..32aaa489 --- /dev/null +++ b/data/scripts/effects/enduring_march.lua @@ -0,0 +1,20 @@ +require("modifiers") + +function onGain(target, effect) + --Traited increases speed by 20%. Assuming that means it actually increases speed instead of simply offsetting the negative speed it has by default + local speedModifier = 0.8; + if effect.GetTier() == 2 then + speedModifier = 1.2; + end + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) * speedModifier); +end; + +function onLose(target, effect) + local speedModifier = 0.8; + if effect.GetTier() == 2 then + speedModifier = 1.2; + end + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) / speedModifier); +end; \ No newline at end of file diff --git a/data/scripts/effects/featherfoot.lua b/data/scripts/effects/featherfoot.lua index fa322f97..13f635c3 100644 --- a/data/scripts/effects/featherfoot.lua +++ b/data/scripts/effects/featherfoot.lua @@ -1,11 +1,26 @@ require("modifiers"); +--15% in ARR, dont know how it worked in 1.0 function onGain(target, effect) - local currEvade = target.GetMod(modifierGlobals.Evasion); - target.SetMod(modifierGlobals.Evasion, currEvade + 15); + target.AddMod(modifiersGlobal.RawEvadeRate, 15); end; function onLose(target, effect) - local currEvade = target.GetMod(modifierGlobals.Evasion); - target.SetMod(modifierGlobals.Evasion, currEvade - 15); + target.SubtractMod(modifiersGlobal.RawEvadeRate, 15); +end; + +--Returns 25%? of amount dodged as MP +function onEvade(effect, attacker, defender, action, actionContainer) + --25% of amount dodged untraited, 50% traited + local percent = 0.25; + if (effect.GetTier() == 2) then + percent = 0.50; + end + + local mpToReturn = percent * action.amountMitigated; + defender.AddMP(math.ceil(mpToReturn)); + --33010: You recover x MP from Featherfoot + actionContainer.AddMPAction(defender.actorId, 33010, mpToReturn); + --Featherfoot is lost after evading + actionContainer.AddAction(defender.statusEffects.RemoveStatusEffectForBattleAction(effect)); end; \ No newline at end of file diff --git a/data/scripts/effects/fists_of_earth.lua b/data/scripts/effects/fists_of_earth.lua index eadc0f32..d9ce7955 100644 --- a/data/scripts/effects/fists_of_earth.lua +++ b/data/scripts/effects/fists_of_earth.lua @@ -1,4 +1,8 @@ function onGain(target, effect) target.statusEffects.RemoveStatusEffect(223209) target.statusEffects.RemoveStatusEffect(223211) -end; \ No newline at end of file +end; + +--Need to do more research on these. +--From what I've seen, they changed the property of the attack to magic and the element to the respective element +--Unsure if it applies to weaponskills or if it's auto attacks only. \ No newline at end of file diff --git a/data/scripts/effects/foresight.lua b/data/scripts/effects/foresight.lua new file mode 100644 index 00000000..2ffcde2f --- /dev/null +++ b/data/scripts/effects/foresight.lua @@ -0,0 +1,15 @@ +require("modifiers") + +function onGain(target, effect) + --Parry is .1% per , Random guess but gonna say it gives 20% worth of parry. + target.AddMod(modifiersGlobal.Parry, 200); +end; + +function onParry(effect, attacker, defender, action, actionContainer) + --Foresight is lost after parrying + actionContainer.AddAction(defender.statusEffects.RemoveStatusEffectForBattleAction(effect)); +end; + +function onLose(target, effect) + target.SubtractMod(modifiersGlobal.Parry, 200); +end; \ No newline at end of file diff --git a/data/scripts/effects/fully_blissful_mind.lua b/data/scripts/effects/fully_blissful_mind.lua new file mode 100644 index 00000000..678c10e5 --- /dev/null +++ b/data/scripts/effects/fully_blissful_mind.lua @@ -0,0 +1,11 @@ +function onGain(owner, effect) + --Using extra because that's what blissful_mind uses + effect.SetExtra(effect.GetMagnitude()); +end + +function onTick(owner, effect) + print("hi") +end + +function onLose(owner, effect) +end diff --git a/data/scripts/effects/goring_blade.lua b/data/scripts/effects/goring_blade.lua new file mode 100644 index 00000000..c1f8d794 --- /dev/null +++ b/data/scripts/effects/goring_blade.lua @@ -0,0 +1,9 @@ +require("modifiers") + +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.RegenDown, effect.GetMagnitude()); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.RegenDown, effect.GetMagnitude()); +end diff --git a/data/scripts/effects/hawks_eye.lua b/data/scripts/effects/hawks_eye.lua new file mode 100644 index 00000000..99876524 --- /dev/null +++ b/data/scripts/effects/hawks_eye.lua @@ -0,0 +1,22 @@ +require("modifiers"); + +--In one capture, hawks eye seemed to give 18.75% additional accuracy (379 to 450) +--The player in this capture was a Dragoon, so this is untraited. +--Traited Hawk's Eye says it increases Accuracy by 50%. +--This could mean traited hawk's eye gives 28.125% (18.75% * 1.5) or it could mean it gives 68.75% (18.75% + 50%) +function onGain(target, effect) + local accuracyMod = 0.1875; + + if effect.GetTier() == 2 then + accuracyMod = 0.28125; + end + + local amountGained = accuracyMod * target.GetMod(modifiersGlobal.Accuracy); + effect.SetMagnitude(amountGained); + target.AddMod(modifiersGlobal.Accuracy, effect.GetMagnitude()); +end; + +function onLose(target, effect) + + target.SubtractMod(modifiersGlobal.Accuracy, effect.GetMagnitude()); +end; \ No newline at end of file diff --git a/data/scripts/effects/heavy.lua b/data/scripts/effects/heavy.lua new file mode 100644 index 00000000..e49f8813 --- /dev/null +++ b/data/scripts/effects/heavy.lua @@ -0,0 +1,13 @@ +require("modifiers") + +function onGain(target, effect) + local speedModifier = 0.5; + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) * speedModifier); +end; + +function onLose(target, effect) + local speedModifier = 0.5; + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) / speedModifier); +end; \ No newline at end of file diff --git a/data/scripts/effects/hp_boost.lua b/data/scripts/effects/hp_boost.lua new file mode 100644 index 00000000..ca20c3b1 --- /dev/null +++ b/data/scripts/effects/hp_boost.lua @@ -0,0 +1,15 @@ +require("modifiers") + +--Battle Voice grants HP_Boost and it sets max hp to 125% normal amount and heals for the difference between current +--This doesn't seem like the correct way to do this. If max HP changes between gainign and losing wont this break? +function onGain(target, effect) + local newMaxHP = target.GetMaxHP() * 1.25; + local healAmount = newMaxHP - target.GetMaxHP(); + + target.SetMaxHP(newMaxHP); + target.AddHP(healAmount); +end; + +function onLose(target, effect) + target.SetMaxHP(target.GetMaxHP() * 0.75); +end; \ No newline at end of file diff --git a/data/scripts/effects/hundred_fists.lua b/data/scripts/effects/hundred_fists.lua new file mode 100644 index 00000000..3622161b --- /dev/null +++ b/data/scripts/effects/hundred_fists.lua @@ -0,0 +1,13 @@ +require("modifiers") + +--will this break with things like slow? +function onGain(target, effect) + local currDelay = target.GetMod(modifiersGlobal.AttackDelay); + target.SetMod(modifiersGlobal.AttackDelay), 0.66 * currDelay); +end; + +function onLose(target, effect) + local currDelay = target.GetMod(modifiersGlobal.AttackDelay); + target.SetMod(modifiersGlobal.AttackDelay), 1.50 * currDelay); +end; + diff --git a/data/scripts/effects/invigorate.lua b/data/scripts/effects/invigorate.lua index 33e1e720..8502c5f0 100644 --- a/data/scripts/effects/invigorate.lua +++ b/data/scripts/effects/invigorate.lua @@ -1,3 +1,8 @@ -function onTick(target, effect) - target.AddTP(100); -end; \ No newline at end of file +--100 TP per tick without AF. 133 TP per tick with AF +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.Regain, effect.GetMagnitude()); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Regain, effect.GetMagnitude()); +end diff --git a/data/scripts/effects/keen_flurry.lua b/data/scripts/effects/keen_flurry.lua new file mode 100644 index 00000000..b9ff8042 --- /dev/null +++ b/data/scripts/effects/keen_flurry.lua @@ -0,0 +1,17 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Untraited reduces cooldown by 50% +--Traited reduces cooldown by 100% +function onCommandStart(effect, owner, skill, actionContainer) + if skill.commandType == CommandType.Weaponskill then + local reduction = 0.5; + + if effect.GetTier() == 2 then + reduction = 1.0; + end + + skill.recastTimeMs = skill.recastTimeMs - (reduction * skill.recastTimeMs); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/life_surge_I.lua b/data/scripts/effects/life_surge_I.lua new file mode 100644 index 00000000..f99655ea --- /dev/null +++ b/data/scripts/effects/life_surge_I.lua @@ -0,0 +1,21 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Heals for 30%? of damage dealt on auto attacks. +--Trait: Increases healing by 20%. Is this the base % or the amount after taking the base percent? +--I'm guessing the way it works is that LSI/II/III have 10/20/30% absorb by default and 30/40/50% traited. +--Seems to match what i can find in videos +function onHit(effect, attacker, defender, action, actionContainer) + if action.commandType == CommandType.AutoAttack then + local healPercent = 0.10; + + if effect.GetTier() == 2 then + healPercent = 0.30; + end + + local amount = math.floor((healPercent * action.amount) + 1); + attacker.AddHP(amount); + actionContainer.AddHPAction(defender.actorId, 30332, amount); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/life_surge_II.lua b/data/scripts/effects/life_surge_II.lua new file mode 100644 index 00000000..22f69cb2 --- /dev/null +++ b/data/scripts/effects/life_surge_II.lua @@ -0,0 +1,17 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +function onHit(effect, attacker, defender, action, actionContainer) + if action.commandType == CommandType.AutoAttack then + local healPercent = 0.20; + + if effect.GetTier() == 2 then + healPercent = 0.40; + end + + local amount = math.floor((healPercent * action.amount) + 1); + attacker.AddHP(amount); + actionContainer.AddHPAction(defender.actorId, 30332, amount); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/life_surge_III.lua b/data/scripts/effects/life_surge_III.lua new file mode 100644 index 00000000..f99655ea --- /dev/null +++ b/data/scripts/effects/life_surge_III.lua @@ -0,0 +1,21 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Heals for 30%? of damage dealt on auto attacks. +--Trait: Increases healing by 20%. Is this the base % or the amount after taking the base percent? +--I'm guessing the way it works is that LSI/II/III have 10/20/30% absorb by default and 30/40/50% traited. +--Seems to match what i can find in videos +function onHit(effect, attacker, defender, action, actionContainer) + if action.commandType == CommandType.AutoAttack then + local healPercent = 0.10; + + if effect.GetTier() == 2 then + healPercent = 0.30; + end + + local amount = math.floor((healPercent * action.amount) + 1); + attacker.AddHP(amount); + actionContainer.AddHPAction(defender.actorId, 30332, amount); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/magic_evasion_down.lua b/data/scripts/effects/magic_evasion_down.lua new file mode 100644 index 00000000..d043c8a5 --- /dev/null +++ b/data/scripts/effects/magic_evasion_down.lua @@ -0,0 +1,8 @@ +--Bloodletter2 is the uncomboed version of Bloodletter. It doesn't deal any additional damage when it falls off but has the same tick damage +function onGain(owner, effect) + owner.SubtractMod(modifiersGlobal.MagicEvasion, effect.GetMagnitude()); +end + +function onLose(owner, effect) + owner.AddMod(modifiersGlobal.MagicEvasion, effect.GetMagnitude()); +end diff --git a/data/scripts/effects/mighty_strikes.lua b/data/scripts/effects/mighty_strikes.lua new file mode 100644 index 00000000..4253d792 --- /dev/null +++ b/data/scripts/effects/mighty_strikes.lua @@ -0,0 +1,12 @@ +require("modifiers") +require("battleutils") + +--Forces crit on attacks made with axes +function onPreAction(caster, target, effect, skill, action, actionContainer) + --Assuming "attacks made with axes" means skills specific to MRD/WAR + if (skill.job == 3 or skill.job == 17) then + --Set action's crit rate to 100% + action.critRate = 100.0; + end +end; + diff --git a/data/scripts/effects/outmaneuver2.lua b/data/scripts/effects/outmaneuver2.lua new file mode 100644 index 00000000..6d5fffbe --- /dev/null +++ b/data/scripts/effects/outmaneuver2.lua @@ -0,0 +1,26 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Add 30 raw block rate. No idea how much block it actually gives. +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.RawBlockRate, 30); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.RawBlockRate, 30); +end + +--Gives 200 TP on block. Traited: Gives 10% of the amount blocked back as MP +function onBlock(effect, attacker, defender, action, actionContainer) + --200 TP on block + defender.AddTP(200); + + --If traited, add 10% of damage taken as MP + if(effect.GetTier() == 2) then + local mpToReturn = math.ceil(0.10 * action.amount); + defender.AddMP(math.ceil(mpToReturn)); + --33009: You recover x MP from Outmaneuver + actionContainer.AddMPAction(defender.actorId, 33009, mpToReturn); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/power_surge_I.lua b/data/scripts/effects/power_surge_I.lua new file mode 100644 index 00000000..ba0fe70e --- /dev/null +++ b/data/scripts/effects/power_surge_I.lua @@ -0,0 +1,30 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--https://www.bluegartr.com/threads/107403-Stats-and-how-they-work/page22 +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.Attack, 115); + owner.SubtractMod(modifiersGlobal.Defense, 158); +end + +function onCommandStart(effect, owner, command, actionContainer) + --if command is a weaponskill or jump + --27266: jump + if command.GetCommandType() == CommandType.Weaponskill or command.id == 27266 then + effect.SetTier(effect.GetTier() + 1); + + --Takes 10 weaponskills/jumps to increase level + if effect.GetTier() > 10 then + local action = owner.statusEffects.ReplaceEffect(effect, 223213, 1, 1, 60); + actionContainer.AddAction(action); + else + effect.RefreshTime(); + end + end +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Attack, 115); + owner.AddMod(modifiersGlobal.Defense, 158); +end \ No newline at end of file diff --git a/data/scripts/effects/power_surge_II.lua b/data/scripts/effects/power_surge_II.lua new file mode 100644 index 00000000..56e4daf0 --- /dev/null +++ b/data/scripts/effects/power_surge_II.lua @@ -0,0 +1,31 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--https://www.bluegartr.com/threads/107403-Stats-and-how-they-work/page22 +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.Attack, 230); + owner.SubtractMod(modifiersGlobal.Defense, 158); +end + +function onCommandStart(effect, owner, command, actionContainer) + --if command is a weaponskill or jump + --27266: jump + if command.GetCommandType() == CommandType.Weaponskill or command.id == 27266 then + effect.SetTier(effect.GetTier() + 1); + + --Takes 10 weaponskills/jumps to increase level + if effect.GetTier() > 10 then + local action = owner.statusEffects.ReplaceEffect(effect, 223214, 1, 1, 60); + actionContainer.AddAction(action); + else + effect.RefreshTime(); + end + end +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Attack, 230); + owner.AddMod(modifiersGlobal.Defense, 158); +end + diff --git a/data/scripts/effects/power_surge_III.lua b/data/scripts/effects/power_surge_III.lua new file mode 100644 index 00000000..8eb171e4 --- /dev/null +++ b/data/scripts/effects/power_surge_III.lua @@ -0,0 +1,24 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--https://www.bluegartr.com/threads/107403-Stats-and-how-they-work/page22 +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.Attack, 345); + owner.SubtractMod(modifiersGlobal.Defense, 158); +end + +function onCommandStart(effect, owner, command, actionContainer) + --if command is a weaponskill or jump + --27266: jump + if command.GetCommandType() == CommandType.Weaponskill or command.id == 27266 then + --At III just refresh the effect + effect.RefreshTime(); + end +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Attack, 345); + owner.AddMod(modifiersGlobal.Defense, 158); +end + diff --git a/data/scripts/effects/protect2.lua b/data/scripts/effects/protect2.lua new file mode 100644 index 00000000..21c40a56 --- /dev/null +++ b/data/scripts/effects/protect2.lua @@ -0,0 +1,43 @@ +require("modifiers") + +function onGain(target, effect) + --Magnitude is caster's Enhancing Magic Potency. + --http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide + --5-4-5-4-5-4-5-4-5 repeating points of Enhancing for 1 defense + --4.56 * Enhancing Potency + local defenseBuff = 5-- 4.56 * effect.GetMagnitude(); + local magicDefenseBuff = 0; + + target.AddMod(modifiersGlobal.Defense, defenseBuff); + + --27365: Enhanced Protect: Increases magic defense gained from Protect. + --There is no "magic defense" stat, instead it gives stats to each resist stat. + --if effect.GetTier() >= 2 then + --7-6-7 repeating + --6.67 * Enhancing Potency + magicDefenseBuff = 5--6.67 * effect.GetMagnitude(); + for i = modifiersGlobal.ResistFire, modifiersGlobal.ResistWater do + target.AddMod(i, magicDefenseBuff); + end + --end + +end; + +function onLose(target, effect) + local defenseBuff = 4.56 * effect.GetMagnitude(); + local magicDefenseBuff = 0; + + target.SubtractMod(modifiersGlobal.Defense, defenseBuff); + + --27365: Enhanced Protect: Increases magic defense gained from Protect. + --There is no "magic defense" stat, instead it gives stats to each resist stat. + --if effect.GetTier() >= 2 then + --7-6-7 repeating + --6.67 * Enhancing Potency + magicDefenseBuff = 6.67 * effect.GetMagnitude(); + for i = modifiersGlobal.ResistFire, modifiersGlobal.ResistWater do + target.SubtractMod(i, magicDefenseBuff); + end + --end +end; + diff --git a/data/scripts/effects/quelling_strike.lua b/data/scripts/effects/quelling_strike.lua new file mode 100644 index 00000000..9fb7f027 --- /dev/null +++ b/data/scripts/effects/quelling_strike.lua @@ -0,0 +1,17 @@ +require("modifiers") +require("hiteffect") +require("battleutils") + +--Untraited reduces cooldown by 50% +--Traited reduces cooldown by 100% +function onCommandStart(effect, owner, skill, actionContainer) + --Does this apply to auto attacks? + if skill.commandType == CommandType.Weaponskill or skill.commandType == CommandType.Ability or skill.commandType == CommandType.Magic then + if skill.actionType == ActionType.Physical or skill.actionType == ActionType.Magic then + --No idea what the enmity effect is + skill.enmityModifier = skill.enmityModifier * 0.5; + + owner.AddTP(effect.GetMagnitude()); + end + end +end; \ No newline at end of file diff --git a/data/scripts/effects/quick.lua b/data/scripts/effects/quick.lua new file mode 100644 index 00000000..65861376 --- /dev/null +++ b/data/scripts/effects/quick.lua @@ -0,0 +1,13 @@ +require("modifiers") + +function onGain(target, effect) + local speedModifier = 1.25; + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) * speedModifier); +end; + +function onLose(target, effect) + local speedModifier = 1.25; + + target.SetMod(modifiersGlobal.Speed, target.GetMod(modifiersGlobal.Speed) / speedModifier); +end; \ No newline at end of file diff --git a/data/scripts/effects/rampage2.lua b/data/scripts/effects/rampage2.lua new file mode 100644 index 00000000..eb48b564 --- /dev/null +++ b/data/scripts/effects/rampage2.lua @@ -0,0 +1,51 @@ +require("global") +require("modifiers") +require("hiteffect") +require("battleutils") +require("utils") + +parryPerDT = 20; +delayMsPerDT = 100; + +function onGain(owner, effect) + owner.statusEffects.RemoveStatusEffect(223207); +end + +--Increases parry rating and attack speed for each hit. (Need more info) +function onDamageTaken(effect, attacker, defender, action, actionContainer) + + --Assuming 20 parry rating every time you're hit up to 200 + --Delay is more complicated. Most axes are around 4 seconds, so i'm gonna assume it cuts off a full second at max + if (effect.GetExtra() < 10) then + effect.SetExtra(effect.GetExtra() + 1); + + attacker.AddMod(modifiersGlobal.Parry, parryPerDT); + attacker.SubtractMod(modifiersGlobal.Delay, delayMsPerDT); + end +end + +--Heals for 50% of damage dealt on crits with a maximum of 20% of max hp +--Also only heals for as much hp as you're missing at most +function onCrit(effect, attacker, defender, action, actionContainer) + local healAmount = math.Clamp(action.amount * 0.50, 0, defender.GetMaxHP() * 0.20); + healAmount = math.Clamp(healAmount, 0, defender.GetMaxHP() - defender.GetHP()); + defender.AddHP(healAmount); + --33012: You recover [healAmount] HP. + actionContainer.AddHPAction(owner.actorId, 33008, healAmount); +end; + +--"Effect fades over time" +function onTick(owner, effect) + --Enduring march prevents fading of rampage effect + if not owner.statusEffects.HasStatusEffect(223078) and (effect.GetExtra() > 0) then + --Going to assume that every 5 seconds a single hits worth of rampage is lost. + attacker.SubtractMod(modifiersGlobal.Parry, parryPerDT); + attacker.AddMod(modifiersGlobal.Delay, delayMsPerDT); + effect.SetExtra(effect.GetExtra() - 1); + end +end + +function onLose(owner, effect) + attacker.SubtractMod(modifiersGlobal.Parry, effect.GetExtra() * parryPerDT); + attacker.AddMod(modifiersGlobal.Delay, effect.GetExtra() * delayMsPerDT); +end \ No newline at end of file diff --git a/data/scripts/effects/rampart.lua b/data/scripts/effects/rampart.lua new file mode 100644 index 00000000..6602e09a --- /dev/null +++ b/data/scripts/effects/rampart.lua @@ -0,0 +1,15 @@ +require("modifiers") + +--Rampart gives 105 defense at level 50. +--Guessing it scales with level. If I had to guess it's either 2.1 * level or (2 * level) + 5. +--I'm going to guess the latter since it always leaves you with a whole number. I could be completely wrong though +--The party_battle_leve has rampart giving 36? defense. It's from an earlier patch so probably useless +function onGain(target, effect) + effect.SetMagnitude(2 * target.GetLevel() + 5); + + target.AddMod(modifiersGlobal.Defense, effect.GetMagnitude()); +end; + +function onLose(target, effect) + target.SubtractMod(modifiersGlobal.Defense, effect.GetMagnitude()); +end; \ No newline at end of file diff --git a/data/scripts/effects/regen.lua b/data/scripts/effects/regen.lua new file mode 100644 index 00000000..ccb4f606 --- /dev/null +++ b/data/scripts/effects/regen.lua @@ -0,0 +1,8 @@ +--Regen is modified by Enhancing Magic Potency. Formula here: http://forum.square-enix.com/ffxiv/threads/41900-White-Mage-A-Guide +function onGain(owner, effect) + owner.AddMod(modifiersGlobal.Regen, effect.magnitude); +end + +function onLose(owner, effect) + owner.SubtractMod(modifiersGlobal.Regen, effect.magnitude); +end diff --git a/data/scripts/effects/sentinel.lua b/data/scripts/effects/sentinel.lua new file mode 100644 index 00000000..d913a34f --- /dev/null +++ b/data/scripts/effects/sentinel.lua @@ -0,0 +1,29 @@ +require("modifiers") + +function onGain(target, effect) + --Untraited Sentinel is 30% damage taken down, traited is 50% + local amount = 30; + if effect.GetTier() == 2 then + amount = 50; + end + + target.AddMod(modifiersGlobal.DamageTakenDown, amount); +end; + +function onLose(target, effect) + local amount = 30; + if effect.GetTier() == 2 then + amount = 50; + end + + target.SubtractMod(modifiersGlobal.DamageTakenDown, amount); +end; + +--Increases action's enmity by 100 for weaponskills +--http://forum.square-enix.com/ffxiv/threads/47393-Tachi-s-Guide-to-Paladin-%28post-1.22b%29 +--Sentinel only works on weaponskills. It's possible that was a bug because the description says actions +function onHit(effect, attacker, defender, action, actionContainer) + if action.commandType == CommandType.WeaponSkill then + action.enmity = action.enmity + 100; + end +end \ No newline at end of file diff --git a/data/scripts/effects/stoneskin.lua b/data/scripts/effects/stoneskin.lua new file mode 100644 index 00000000..74712120 --- /dev/null +++ b/data/scripts/effects/stoneskin.lua @@ -0,0 +1,26 @@ +require("global") +require("utils") +require("modifiers") +require("hiteffect") +require("battleutils") + + +--todo: calculate actual mitigation value based on Source's enhancing magic. info: http://forum.square-enix.com/ffxiv/threads/40800-Enhancing-Magic +--This should also probably be calculated when the spell is cast so it doesnt overwrite a stronger stoneskin +function onGain(owner, effect) + --Going to assume its 1.34 * Enhancing Potency untraited, 1.96 * Enhancing Potency traited. + local potencyModifier = 1.34; + if effect.tier == 2 then + potencyModifier = 1.96; + end + local amount = potencyModifier * effect.source.GetMod(modifiersGlobal.MagicEnhancePotency); + + owner.AddMod(modifiersGlobal.Stoneskin, amount); +end + +--Using extra for how much mitigation stoneskin has +function onPostAction(owner, effect, caster, skill, action, actionContainer) + if (owner.GetMod(modifiersGlobal.Stoneskin) <= 0) then + actionContainer.AddAction(owner.statusEffects.RemoveStatusEffectForBattleAction(effect)); + end +end; \ No newline at end of file diff --git a/data/scripts/effects/vengeance.lua b/data/scripts/effects/vengeance.lua new file mode 100644 index 00000000..bbd919bb --- /dev/null +++ b/data/scripts/effects/vengeance.lua @@ -0,0 +1,17 @@ +require("global") +require("modifiers") +require("hiteffect") +require("utils") + +--Unclear what the exact damage is but it seems like it's the total amount of damage the attack would have done before parrying +function onDamageTaken(effect, attacker, defender, action, actionContainer) + local amount = action.amount + action.mitigatedAmount; + + --Only reflects magical attacks if wearing AF chest + if action.actionType == ActionType.Physical or (action.actionType == ActionType.Magic and effect.GetTier() == 2) then + --30350: Counter! You hit target for x points of damage + --There are counter messages for blocks, can Vengeance be blocked/parried? + attacker.DelHP(amount); + actionContainer.AddHitAction(attacker.actorId, 30350, amount); + end; +end; \ No newline at end of file diff --git a/data/scripts/hiteffect.lua b/data/scripts/hiteffect.lua index 2928f4ed..1285d363 100644 --- a/data/scripts/hiteffect.lua +++ b/data/scripts/hiteffect.lua @@ -1,23 +1,22 @@ HitEffect = { --All HitEffects have the last byte 0x8 - HitEffectType = 8 << 24, - --Status effects use 32 << 24 - StatusEffectType = 32 << 24, + HitEffectType = 134217728, --8 << 24 + --Status effects use 32 <<,24 + StatusEffectType = 536870912,--32 << 24, --Heal effects use 48 << 24 - MagicEffectType = 48 << 24, + MagicEffectType = 805306368,--48 << 24 --Not setting RecoilLv2 or RecoilLv3 results in the weaker RecoilLv1. --These are the recoil animations that play on the target, ranging from weak to strong. --The recoil that gets set was likely based on the percentage of HP lost from the attack. - --These are used for resists for spells. RecoilLV1 is a resist, RecoilLv2 is a partial resist. - --Don't know what CriticalHit is for but it has a larger effect than Lv1 + --These are used for resists for spells. RecoilLV1 is a full resist, RecoilLv2 is a partial resist, RecoilLv3 is no resist, CriticalHit is a crit RecoilLv1 = 0, - RecoilLv2 = 1 << 0, - RecoilLv3 = 1 << 1, + RecoilLv2 = 1, + RecoilLv3 = 2, --Setting both recoil flags triggers the "Critical!" pop-up text and hit visual effect. - CriticalHit = RecoilLv2 | RecoilLv3, + CriticalHit = 3, --Hit visual and sound effects when connecting with the target. --Mixing these flags together will yield different results. @@ -32,10 +31,10 @@ HitEffect = --Basically, takes the attack property as defined by the weapon and shifts it left 2 --For auto attacks attack property is weapon's damageAttributeType1 --Still not totally sure how this works with weaponskills or what hitvisual4 or the other combinations are for - HitVisual1 = 1 << 2, - HitVisual2 = 1 << 3, - HitVisual3 = 1 << 4, - HitVisual4 = 1 << 5, + HitVisual1 = 4, + HitVisual2 = 8, + HitVisual3 = 16, + HitVisual4 = 32, --An additional visual effect that plays on the target when attacked if: @@ -45,61 +44,62 @@ HitEffect = --Another effect plays when both Protect and Shell flags are activated. --Not sure what this effect is. --Random guess: if the attack was a hybrid of both physical and magical and the target had both Protect and Shell buffs applied. - Protect = 1 << 6 | HitEffectType, - Shell = 1 << 7 | HitEffectType, - ProtectShellSpecial = Protect | Shell, - - Heal = 1 << 8,-- Required for heal text to be blue along with HealEffectType, not sure if that's all it's used for + Protect = 64, + Shell = 128, + ProtectShellSpecial = 192,-- Protect | Shell, + Heal = 256,-- Required for heal text to be blue along with HealEffectType, not sure if that's all it's used for + MP = 512, + --If only HitEffect1 is set out of the hit effects, the "Evade!" pop-up text triggers along with the evade visual. --If no hit effects are set, the "Miss!" pop-up is triggered and no hit visual is played. - HitEffect1 = 1 << 9, - HitEffect2 = 1 << 10, --Plays the standard hit visual effect, but with no sound if used alone. - HitEffect3 = 1 << 11, --Yellow effect, crit? - HitEffect4 = 1 << 12, --Plays the blocking animation - HitEffect5 = 1 << 13, - GustyHitEffect = HitEffect3 | HitEffect2, - GreenTintedHitEffect = HitEffect4 | HitEffect1, + HitEffect1 = 512, + HitEffect2 = 1024, --Plays the standard hit visual effect, but with no sound if used alone. + HitEffect3 = 2048, --Yellow effect, crit? + HitEffect4 = 4096, --Plays the blocking animation + HitEffect5 = 8192, + GustyHitEffect = 3072,--HitEffect3 | HitEffect2, + GreenTintedHitEffect = 4608,-- HitEffect4 | HitEffect1, --For specific animations Miss = 0, - Evade = HitEffect1, - Hit = HitEffect1 | HitEffect2, - Parry = Hit | HitEffect3, - Block = HitEffect4, - Crit = HitEffect3, + Evade = 512, + Hit = 1536, --HitEffect1 | HitEffect2, + Parry = 3584, --Hit | HitEffect3, + Block = 4096, + Crit = 2048, --Knocks you back away from the attacker. - KnockbackLv1 = HitEffect4 | HitEffect2 | HitEffect1, - KnockbackLv2 = HitEffect4 | HitEffect3, - KnockbackLv3 = HitEffect4 | HitEffect3 | HitEffect1, - KnockbackLv4 = HitEffect4 | HitEffect3 | HitEffect2, - KnockbackLv5 = HitEffect4 | HitEffect3 | HitEffect2 | HitEffect1, + KnockbackLv1 = 5632,-- HitEffect4 | HitEffect2 | HitEffect1, + KnockbackLv2 = 6144,-- HitEffect4 | HitEffect3, + KnockbackLv3 = 6656,-- HitEffect4 | HitEffect3 | HitEffect1, + KnockbackLv4 = 7168,-- HitEffect4 | HitEffect3 | HitEffect2, + KnockbackLv5 = 7680,-- HitEffect4 | HitEffect3 | HitEffect2 | HitEffect1, --Knocks you away from the attacker in a counter-clockwise direction. - KnockbackCounterClockwiseLv1 = HitEffect5, - KnockbackCounterClockwiseLv2 = HitEffect5 | HitEffect1, + KnockbackCounterClockwiseLv1 = 8192, + KnockbackCounterClockwiseLv2 = 8704,-- HitEffect5 | HitEffect1, --Knocks you away from the attacker in a clockwise direction. - KnockbackClockwiseLv1 = HitEffect5 | HitEffect2, - KnockbackClockwiseLv2 = HitEffect5 | HitEffect2 | HitEffect1, + KnockbackClockwiseLv1 = 9216,-- HitEffect5 | HitEffect2, + KnockbackClockwiseLv2 = 9728,-- HitEffect5 | HitEffect2 | HitEffect1, --Completely drags target to the attacker, even across large distances. - DrawIn = HitEffect5 | HitEffect3, + DrawIn = 10240,-- HitEffect5 | HitEffect3, --An additional visual effect that plays on the target based on according buff. - UnknownShieldEffect = HitEffect5 | HitEffect4, - Stoneskin = HitEffect5 | HitEffect4 | HitEffect1, + UnknownShieldEffect = 12288,-- HitEffect5 | HitEffect4, + Stoneskin = 12800,-- HitEffect5 | HitEffect4 | HitEffect1, --Unknown = 1 << 14, -- Not sure what this flag does; might be another HitEffect. --A special effect when performing appropriate skill combos in succession. --Ex: Thunder (SkillCombo1 Effect) -> Thundara (SkillCombo2 Effect) -> Thundaga (SkillCombo3 Effect) --Special Note: SkillCombo4 was never actually used in 1.0 since combos only chained up to 3 times maximum. - SkillCombo1 = 1 << 15, - SkillCombo2 = 1 << 16, - SkillCombo3 = SkillCombo1 | SkillCombo2, - SkillCombo4 = 1 << 17 + SkillCombo1 = 32768, + SkillCombo2 = 65536, + SkillCombo3 = 98304,-- SkillCombo1 | SkillCombo2, + SkillCombo4 = 131072 --Flags beyond here are unknown/untested. } \ No newline at end of file diff --git a/data/scripts/magic.lua b/data/scripts/magic.lua index 62b15504..15387d97 100644 --- a/data/scripts/magic.lua +++ b/data/scripts/magic.lua @@ -40,32 +40,4 @@ function magic.HandleStoneskin(caster, target, spell, action, statId, modifierId end; ]] return false; -end; - -function magic.onMagicFinish(caster, target, spell, action) - action.battleActionType = BattleActionType.AttackMagic; - local damage = math.random(50, 150); - action.amount = damage; - action.CalcHitType(caster, target, spell); - action.TryStatus(caster, target, spell, true); - return action.amount; -end; - ---For healing magic -function magic.onCureMagicFinish(caster, target, spell, action) - action.battleActionType = BattleActionType.Heal; - local amount = math.random(200, 450); - action.amount = amount; - action.CalcHitType(caster, target, spell); - action.TryStatus(caster, target, spell, true); - return action.amount; -end; - ---For status magic -function magic.onStatusMagicFinish(caster, target, spell, action) - action.battleActionType = BattleActionType.Status; - action.amount = 0; - action.CalcHitType(caster, target, spell); - action.TryStatus(caster, target, spell, false); - return action.amount; end; \ No newline at end of file diff --git a/data/scripts/modifiers.lua b/data/scripts/modifiers.lua index 793b8645..9a2a6a00 100644 --- a/data/scripts/modifiers.lua +++ b/data/scripts/modifiers.lua @@ -1,57 +1,87 @@ -modifiersGlobal = -{ - None = 0, - Hp = 1, - HpPercent = 2, - Mp = 3, - MpPercent = 4, - Tp = 5, - TpPercent = 6, - Regen = 7, - Refresh = 8, - Strength = 9, - Vitality = 10, - Dexterity = 11, - Intelligence = 12, - Mind = 13, - Piety = 14, - Attack = 15, - Accuracy = 16, - Defense = 17, - Evasion = 18, - MagicAttack = 19, - MagicHeal = 20, -- is this needed? shouldnt it just be calc'd from mind - MagicAccuracy = 21, - MagicEvasion = 22, - MagicDefense = 23, - MagicEnhancePotency = 24, - MagicEnfeeblingPotency = 25, - ResistFire = 26, - ResistIce = 27, - ResistWind = 28, - ResistLightning = 29, - ResistEarth = 30, - ResistWater = 31, -- <3 u jorge - AttackRange = 32, - Speed = 33, - AttackDelay = 34, +modifiersGlobal = +{ + NAMEPLATE_SHOWN = 0, + TARGETABLE = 1, + NAMEPLATE_SHOWN2 = 2, + --NAMEPLATE_SHOWN2 = 3, - CraftProcessing = 35, - CraftMagicProcessing = 36, - CraftProcessControl = 37, + Strength = 3, + Vitality = 4, + Dexterity = 5, + Intelligence = 6, + Mind = 7, + Piety = 8, - HarvestPotency = 38, - HarvestLimit = 39, - HarvestRate = 40, + ResistFire = 9, + ResistIce = 10, + ResistWind = 11, + ResistLightning = 12, + ResistEarth = 13, + ResistWater = 14, - Raise = 41, - MinimumHpLock = 42, -- hp cannot fall below this value - AttackType = 43, -- slashing, piercing, etc - BlockRate = 44, - Block = 45, - CritRating = 46, - HasShield = 47, - HitCount = 48 + Accuracy = 15, + Evasion = 16, + Attack = 17, + Defense = 18, --Is there a magic defense stat? 19 maybe? + MagicAttack = 23, + MagicHeal = 24, + MagicEnhancePotency = 25, + MagicEnfeeblingPotency = 26, + + MagicAccuracy = 27, + MagicEvasion = 28, + + CraftProcessing = 30, + CraftMagicProcessing = 31, + CraftProcessControl = 32, + + HarvestPotency = 33, + HarvestLimit = 34, + HarvestRate = 35, + + None = 36, + Hp = 37, + HpPercent = 38, + Mp = 39, + MpPercent = 40, + Tp = 41, + TpPercent = 42, + Regen = 43, + Refresh = 44, + + AttackRange = 45, + Speed = 46, + AttackDelay = 47, + + Raise = 48, + MinimumHpLock = 49, -- hp cannot fall below this value + AttackType = 50, -- slashing, piercing, etc + BlockRate = 51, + Block = 52, + CritRating = 53, + HasShield = 54, -- Need this because shields are required for blocks. Could have used BlockRate or Block but BlockRate is provided by Gallant Sollerets and Block is provided by some buffs. + HitCount = 55, -- Amount of hits in an auto attack. Usually 1, 2 for h2h, 3 with spinning heel + + --Flat percent increases to these rates. Probably a better way to do this + RawEvadeRate = 56, + RawParryRate = 57, + RawBlockRate = 58, + RawResistRate = 59, + RawHitRate = 60, + RawCritRate = 61, + + DamageTakenDown = 62, -- Percent damage taken down + StoreTP = 63, --.1% extra tp per point. Lancer trait is 50 StoreTP + PhysicalCritRate = 64, --CritRating but only for physical attacks. Increases chance of critting. + PhysicalCritEvasion = 65, --Opposite of CritRating. Reduces chance of being crit by phyiscal attacks + PhysicalCritAttack = 66, --Increases damage done by Physical Critical hits + PhysicalCritResilience = 67, --Decreases damage taken by Physical Critical hits + Parry = 68, --Increases chance to parry + MagicCritPotency = 69, --Increases + Regain = 70, --TP regen, should be -90 out of combat, Invigorate sets to 100+ depending on traits + RegenDown = 71, --Damage over time effects. Separate from normal Regen because of how they are displayed in game + Stoneskin = 72, --Nullifies damage + MinimumTpLock = 73 } mobModifiersGlobal = diff --git a/data/scripts/unique/fst0Battle03/Monster/papalymo.lua b/data/scripts/unique/fst0Battle03/Monster/papalymo.lua index afdd66d9..7ed63cac 100644 --- a/data/scripts/unique/fst0Battle03/Monster/papalymo.lua +++ b/data/scripts/unique/fst0Battle03/Monster/papalymo.lua @@ -24,4 +24,5 @@ end function tryAggro(ally, contentGroupCharas) allyGlobal.tryAggro(ally, contentGroupCharas) + end \ No newline at end of file diff --git a/data/scripts/utils.lua b/data/scripts/utils.lua index 2aff7f62..fa5b9770 100644 --- a/data/scripts/utils.lua +++ b/data/scripts/utils.lua @@ -26,4 +26,9 @@ function getDistanceBetweenActors(actor1, actor2) local dz = pos1[2] - pos2[2] return math.sqrt(dx * dx + dy * dy + dz *dz); +end + +function math.Clamp(val, lower, upper) + if lower > upper then lower, upper = upper, lower end -- swap if boundaries supplied the wrong way + return math.max(lower, math.min(upper, val)) end \ No newline at end of file diff --git a/data/scripts/weaponskill.lua b/data/scripts/weaponskill.lua index 6f18f5fa..8fb6dabb 100644 --- a/data/scripts/weaponskill.lua +++ b/data/scripts/weaponskill.lua @@ -1,15 +1,40 @@ -- todo: add enums for status effects in global.lua -require("global") +--require("global") require("battleutils") --[[ statId - see BattleTemp.cs modifier - Modifier.Intelligence, Modifier.Mind (see Modifier.cs) multiplier - ]] -weaponskill = -{ -} + +function CalculateDamage(caster, target, skill, action) + --http://forum.square-enix.com/ffxiv/threads/36412-STR-PIE-ATK-Testing/page2 + --DRG numbers + --Against Level 52 Halberdiers: + --0.8 damage/STR. Caps at 350 + --0.67=0.69 damage/PIE. Hard cap at 310 + --0.35-0.37 damage/ATK for both AA and WS. + + --^ Old? + --http://prestigexiv.guildwork.com/forum/threads/4fecdc94205cb248b5000526-dragoon-and-other-dd-dpsbase-damage-study?page=1#4fecdc94205cb248b5000525 + --10/09/2012 http://forum.square-enix.com/ffxiv/threads/55291-DPS-Testing/page4 + -- 1 point prim: 0.8 damage + -- ATK: .1% damage? .38 damage? + + --Possible formula for melee?: + --local strCap = CalculateCapOfWeapon(caster.getweapon)<- not sure how this is calculated yet, just an example + --local secondaryCap = CalculateSecondaryCapOfWeapon(caster.getweapon) + --local cappedStr = math.min(caster.GetMod(modifiersGlobal.Strength), strCap); + --local cappedSec = math.min(caster.GetMod(caster.secondaryStat), secCap); + --local damageBase = skill.basePotency + (0.85 * cappedStr) + (0.65 * cappedSec); + + --The maximum deviation for weaponskills is ~8%. + --local dev = 0.96 + (math.random() * 8); + --damageBase = math.Clamp(damageBase * dev, 1, 9999); + --return damageBase; + return 100; +end function HandleHealingSkill(caster, target, skill, action, statId, modifierId, multiplier, baseAmount) potency = potency or 1.0; @@ -34,15 +59,4 @@ function HandleStoneskin(caster, target, skill, action, statId, modifierId, dama end; ]] return false; -end; - ---The default onskillfinish for weaponskills. -function weaponskill.onSkillFinish(caster, target, skill, action) - action.battleActionType = BattleActionType.AttackPhysical; - local damage = math.random(50, 150); - action.amount = damage; - - action.CalcHitType(caster, target, skill); - action.TryStatus(caster, target, skill); - return action.amount; end; \ No newline at end of file diff --git a/sql/server_battle_commands.sql b/sql/server_battle_commands.sql index b1f9e2d8..30d820ff 100644 --- a/sql/server_battle_commands.sql +++ b/sql/server_battle_commands.sql @@ -56,8 +56,12 @@ CREATE TABLE `server_battle_commands` ( `comboId1` int(11) NOT NULL DEFAULT '0', `comboId2` int(11) NOT NULL DEFAULT '0', `comboStep` tinyint(4) NOT NULL DEFAULT '0', - `accuracyMod` float unsigned NOT NULL DEFAULT '1', - `worldMasterTextId` smallint(5) unsigned DEFAULT '0', + `accuracyMod` float NOT NULL DEFAULT '1', + `worldMasterTextId` smallint(5) unsigned NOT NULL DEFAULT '0', + `commandType` tinyint(3) unsigned NOT NULL DEFAULT '0', + `actionType` tinyint(3) unsigned NOT NULL DEFAULT '0', + `actionProperty` tinyint(3) unsigned NOT NULL DEFAULT '0', + `isRanged` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; @@ -69,148 +73,148 @@ CREATE TABLE `server_battle_commands` ( LOCK TABLES `server_battle_commands` WRITE; /*!40000 ALTER TABLE `server_battle_commands` DISABLE KEYS */; set autocommit=0; -INSERT INTO `server_battle_commands` VALUES (27100,'second_wind',2,6,3,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,45,0,0,14,519,2,3,234889735,0,0,0,0,1,30320); -INSERT INTO `server_battle_commands` VALUES (27101,'blindside',2,14,3,1,1,0,0,0,100,1,0,0,0,0,223074,60,1,0,0,60,0,0,14,635,2,3,234889851,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27102,'taunt',2,42,4,32,32,0,0,0,100,1,0,0,25,0,223073,0,1,0,0,60,0,0,14,517,2,3,234889733,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27103,'featherfoot',2,2,3,1,1,0,0,0,100,1,0,0,0,0,223075,30,1,0,0,60,0,0,14,535,2,3,234889751,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27104,'fists_of_fire',2,34,4,1,1,0,0,0,100,1,0,0,0,0,223209,4294967295,1,0,0,10,0,0,14,684,2,3,234889900,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27105,'fists_of_earth',2,22,4,1,1,0,0,0,100,1,0,0,0,0,223210,4294967295,1,0,0,10,0,0,14,685,2,3,234889901,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27106,'hundred_fists',15,50,0,1,1,0,0,0,100,1,0,0,0,0,223244,15,1,0,0,900,0,0,14,712,2,3,234889928,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27107,'spinning_heel',15,35,0,1,1,0,0,0,100,1,0,0,0,0,223245,20,1,0,0,120,0,0,14,718,2,3,234889934,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27108,'shoulder_tackle',15,30,0,32,32,0,0,0,100,1,0,0,15,0,223015,0,0.75,0,0,60,0,0,18,1048,205,3,302830616,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27109,'fists_of_wind',15,40,0,1,1,0,0,0,100,1,0,0,0,0,223211,4294967295,1,0,0,10,0,0,14,720,2,3,234889936,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27110,'pummel',2,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1027,1,3,301995011,0,27111,27113,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27111,'concussive_blow',2,10,1,32,32,0,0,0,100,1,4,0,5,0,223007,0,0.75,0,0,30,0,1500,18,20,3,3,302002196,0,27112,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27112,'simian_thrash',2,50,4,32,32,0,0,0,100,9,0,0,5,0,0,0,0,0,0,80,0,2000,18,1003,202,3,302818283,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27113,'aura_pulse',2,38,4,32,32,1,8,1,100,1,0,0,5,0,223003,0,0,0,0,40,0,1500,18,66,203,3,302821442,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27114,'pounce',2,4,4,32,32,0,0,0,100,1,2,0,5,0,223015,0,0.75,0,0,20,0,1500,18,8,3,3,302002184,0,27115,27117,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27115,'demolish',2,30,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,1028,2,3,301999108,0,27116,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27116,'howling_fist',2,46,4,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,80,0,3000,18,1029,2,3,301999109,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27117,'sucker_punch',2,26,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,15,0,1000,18,73,3,3,302002249,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27118,'dragon_kick',15,45,0,32,32,0,0,0,100,1,0,0,5,0,223013,0,0,0,0,60,0,2000,18,1041,204,3,302826513,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27119,'haymaker',2,18,4,32,32,0,0,0,100,1,0,2,5,0,223015,0,0.75,0,0,5,0,250,18,23,201,3,302813207,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27140,'sentinel',3,22,3,1,1,0,0,0,100,1,0,0,0,0,223062,15,1,0,0,90,0,0,14,526,2,3,234889742,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27141,'aegis_boon',3,6,8,1,1,0,0,0,100,1,0,0,0,0,223058,30,1,0,0,60,0,0,14,583,21,3,234967623,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27142,'rampart',3,2,3,1,1,0,0,0,100,1,0,0,0,0,223064,60,1,0,0,120,0,0,14,536,2,3,234889752,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27143,'tempered_will',3,42,8,1,1,0,0,0,100,1,0,0,0,0,223068,20,1,0,0,180,0,0,14,515,2,3,234889731,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27144,'outmaneuver',3,34,8,1,1,0,0,0,100,1,0,0,0,0,223060,30,1,0,0,90,0,0,14,512,21,3,234967552,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27145,'flash',3,14,3,32,32,0,0,0,100,1,0,0,25,0,223007,0,0,0,0,30,0,0,14,696,2,3,234889912,0,0,0,0,1,30101); -INSERT INTO `server_battle_commands` VALUES (27146,'cover',16,30,0,4,4,0,0,0,100,1,0,0,15,0,223063,15,1,0,0,60,0,0,14,725,2,3,234889941,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27147,'divine_veil',16,35,0,1,1,0,0,0,100,1,0,0,0,0,223248,20,1,0,0,60,0,0,14,713,2,3,234889929,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27148,'hallowed_ground',16,50,0,1,1,0,0,0,100,1,0,0,0,0,223249,20,1,0,0,900,0,0,14,709,2,3,234889925,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27149,'holy_succor',16,40,0,2,2,0,0,0,100,1,0,0,15,0,0,0,0,3,2000,10,100,0,1,701,1,3,16782013,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27150,'fast_blade',3,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1023,1,3,301995007,0,27151,27152,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27151,'flat_blade',3,26,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,10,0,1500,18,1024,2,3,301999104,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27152,'savage_blade',3,10,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1000,18,1025,1,3,301995009,0,27153,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27153,'goring_blade',3,50,8,32,32,0,0,0,100,1,2,0,5,0,223206,30,0,0,0,60,0,3000,18,1026,301,3,303223810,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27154,'riot_blade',3,30,8,32,32,0,0,0,100,1,2,0,5,0,223038,0,0,0,0,80,0,2000,18,75,2,3,301998155,0,27155,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27155,'rage_of_halone',3,46,8,32,32,0,0,0,100,5,0,0,5,0,0,0,0,0,0,20,0,1500,18,1008,302,3,303227888,0,0,0,2,0.5,30301); -INSERT INTO `server_battle_commands` VALUES (27156,'shield_bash',3,18,17,32,32,0,0,0,100,1,0,0,5,0,223015,0,0.75,0,0,30,0,250,18,5,26,3,302096389,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27157,'war_drum',3,38,24,32,32,1,8,0,100,1,0,4,5,0,0,0,0,0,0,60,0,500,14,502,21,3,234967542,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27158,'phalanx',3,4,8,32,32,0,0,0,100,1,0,4,5,0,0,0,0,0,0,5,0,250,18,32,1,3,301994016,0,27159,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27159,'spirits_within',16,45,0,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,60,0,3000,18,1044,304,3,303236116,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27180,'provoke',4,14,3,32,32,0,0,0,100,1,0,0,25,0,223034,0,0,0,0,30,0,0,14,600,2,3,234889816,0,0,0,0,1,30101); -INSERT INTO `server_battle_commands` VALUES (27181,'foresight',4,2,3,1,1,0,0,0,100,1,0,0,0,0,223083,30,1,0,0,60,0,0,14,545,2,3,234889761,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27182,'bloodbath',4,6,3,1,1,0,0,0,100,1,0,0,0,0,223081,30,1,0,0,60,0,0,14,581,2,3,234889797,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27183,'berserk',4,22,32,1,1,0,0,0,100,1,0,0,0,0,223160,4294967295,1,0,0,10,0,0,14,682,2,3,234889898,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27184,'rampage',4,34,32,1,1,0,0,0,100,1,0,0,0,0,223064,4294967295,1,0,0,10,0,0,14,546,2,3,234889762,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27185,'enduring_march',4,42,32,1,1,0,0,0,100,1,0,0,0,0,223078,20,1,0,0,180,0,0,14,539,2,3,234889755,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27186,'vengeance',17,30,0,1,1,0,0,0,100,1,0,0,0,0,223250,15,1,0,0,150,0,0,14,714,2,3,234889930,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27187,'antagonize',17,35,0,1,1,0,0,0,100,1,0,0,0,0,223251,15,1,0,0,120,0,0,14,715,2,3,234889931,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27188,'collusion',17,40,0,4,4,0,0,0,100,1,0,0,15,0,223097,15,1,0,0,90,0,0,14,711,2,3,234889927,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27189,'mighty_strikes',17,50,0,1,1,0,0,0,100,1,0,0,0,0,223252,15,1,0,0,900,0,0,14,716,2,3,234889932,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27190,'heavy_swing',4,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,14,1,3,301993998,0,27191,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27191,'skull_sunder',4,10,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,43,1,3,301994027,0,27192,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27192,'steel_cyclone',17,45,0,32,32,1,8,0,100,1,0,0,5,0,223015,0,0.75,0,0,30,0,2000,18,1040,404,3,303645712,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27193,'brutal_swing',4,4,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,20,0,1500,18,15,3,3,302002191,0,27194,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27194,'maim',4,26,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,88,1,3,301994072,0,27195,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27195,'godsbane',4,50,32,32,32,0,0,0,100,3,0,0,5,0,0,0,0,0,0,60,0,3000,18,1014,402,3,303637494,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27196,'path_of_the_storm',4,38,32,32,32,0,0,0,100,1,2,0,5,0,228021,0,0,0,0,30,0,1500,18,44,401,3,303632428,0,27197,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27197,'whirlwind',4,46,32,32,32,1,8,0,100,1,0,0,5,0,0,0,0,0,0,80,0,3000,18,1015,403,3,303641591,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27198,'fracture',4,18,32,32,32,0,0,0,100,1,0,3,5,0,223013,0,0.75,0,0,40,0,500,18,42,3,3,302002218,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27199,'overpower',4,30,1,32,32,2,0,0,100,1,0,3,5,0,0,0,0,0,0,5,0,250,18,89,1,3,301994073,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27220,'hawks_eye',7,6,3,1,1,0,0,0,100,1,0,0,0,0,223106,15,1,0,0,90,0,0,14,516,2,3,234889732,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27221,'quelling_strikes',7,22,3,1,1,0,0,0,100,1,0,0,0,0,223104,30,1,0,0,60,0,0,14,614,2,3,234889830,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27222,'decoy',7,2,3,1,1,0,0,0,100,1,0,0,0,0,223108,60,1,0,0,90,100,0,14,565,2,3,234889781,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27223,'chameleon',7,42,3,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,180,0,0,14,504,2,3,234889720,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27224,'barrage',7,34,64,1,1,0,0,0,100,1,0,0,0,0,223220,60,1,0,0,90,0,0,14,683,2,3,234889899,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27225,'raging_strikes',7,14,64,1,1,0,0,0,100,1,0,0,0,0,223105,4294967295,1,0,0,10,0,0,14,632,2,3,234889848,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27226,'swiftsong',7,26,64,1,1,1,20,0,100,1,0,0,0,0,223224,180,1,0,0,10,100,0,1,150,1,3,16781462,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27227,'battle_voice',18,50,0,1,1,1,0,0,100,1,0,0,0,0,223253,60,1,0,0,900,0,0,14,721,2,3,234889937,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27228,'heavy_shot',7,1,1,32,32,0,0,0,100,1,0,0,25,8,0,0,0,0,0,10,0,1000,18,1036,4,3,302007308,0,27229,27231,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27229,'leaden_arrow',7,10,1,32,32,0,0,0,100,1,0,0,25,0,228021,0,0.75,0,0,30,0,1500,18,1035,4,3,302007307,0,27230,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27230,'wide_volley',7,50,64,32,32,1,8,0,100,1,0,0,25,0,0,0,0,0,0,80,0,2000,18,18,703,3,304869394,0,0,0,3,0.5,30301); -INSERT INTO `server_battle_commands` VALUES (27231,'quick_nock',7,38,64,32,32,2,0,0,100,1,0,0,10,0,0,0,0,0,0,180,0,1000,18,1017,702,3,304866297,0,27232,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27232,'rain_of_death',18,45,0,32,32,1,8,0,100,1,0,0,25,0,223015,0,0.75,0,0,30,0,3000,18,1037,704,3,304874509,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27233,'piercing_arrow',7,4,1,32,32,0,0,0,100,1,0,0,25,8,0,0,0,0,0,20,0,1000,18,1038,1,3,301995022,0,27234,27236,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27234,'gloom_arrow',7,30,1,32,32,0,0,0,100,1,0,0,25,0,223007,0,0,0,0,10,0,1000,18,1039,4,3,302007311,0,27235,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27235,'bloodletter',7,46,64,32,32,0,0,0,100,1,0,0,25,0,223127,0,0.75,0,0,80,0,1500,18,53,701,3,304861237,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27236,'shadowbind',7,18,64,32,32,0,0,0,100,1,0,0,25,0,228011,0,0.9,0,0,40,0,250,18,17,4,3,302006289,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27237,'ballad_of_magi',18,30,0,1,1,1,20,0,100,1,0,0,0,0,223254,180,1,8,3000,10,100,0,1,709,1,3,16782021,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27238,'paeon_of_war',18,40,0,1,1,1,20,0,100,1,0,0,0,0,223255,180,1,8,3000,10,50,1000,1,710,1,3,16782022,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27239,'minuet_of_rigor',18,35,0,1,1,1,20,0,100,1,0,0,0,0,223256,180,1,8,3000,10,100,0,1,711,1,3,16782023,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27258,'refill',7,1,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,32613); -INSERT INTO `server_battle_commands` VALUES (27259,'light_shot',7,1,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,0,0,0,0,0,17,0,1,3,285216768,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27260,'invigorate',8,14,3,1,1,0,0,0,100,1,0,0,0,0,223094,30,1,0,0,90,0,0,14,575,2,3,234889791,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27261,'power_surge',8,34,128,1,1,0,0,0,100,1,0,0,0,0,223212,4294967295,1,0,0,10,0,0,14,686,2,3,234889902,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27262,'life_surge',8,22,128,1,1,0,0,0,100,1,0,0,0,0,223215,4294967295,1,0,0,15,0,250,14,687,2,3,234889903,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27263,'dread_spike',8,42,128,1,1,0,0,0,100,1,0,0,0,0,223218,30,1,0,0,120,0,0,14,686,2,3,234889902,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27264,'blood_for_blood',8,6,3,1,1,0,0,0,100,1,0,0,0,0,223219,60,1,0,0,60,0,0,14,689,2,3,234889905,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27265,'keen_flurry',8,26,3,1,1,0,0,0,100,1,0,0,0,0,223091,30,1,0,0,90,0,0,14,569,2,3,234889785,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27266,'jump',19,30,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,0,0,60,0,0,18,1045,804,3,305284117,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27267,'elusive_jump',19,40,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,180,0,0,18,1046,806,3,305292310,0,0,0,0,1,30101); -INSERT INTO `server_battle_commands` VALUES (27268,'dragonfire_dive',19,50,0,32,32,1,0,0,100,1,0,0,25,0,0,0,0,0,0,900,0,0,18,1045,804,3,305284117,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27269,'true_thrust',8,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1030,2,3,301999110,0,27270,27273,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27270,'leg_sweep',8,30,1,32,32,1,0,0,100,1,0,0,5,0,223015,0,0,0,0,30,0,1000,18,37,1,3,301994021,0,27271,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27271,'doom_spike',8,46,128,32,32,3,0,0,100,1,0,0,5,0,0,0,0,0,0,60,0,3000,18,83,801,3,305270867,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27272,'disembowel',19,35,0,32,32,0,0,0,100,1,0,0,5,0,223005,0,0.75,0,0,30,0,750,18,1042,2,3,301999122,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27273,'heavy_thrust',8,10,1,32,32,0,0,0,100,1,0,0,5,0,223015,0,0.75,0,0,20,0,1500,18,1031,1,3,301995015,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27274,'vorpal_thrust',8,2,1,32,32,0,0,0,100,1,2,0,5,0,0,0,0,0,0,20,0,1500,18,1032,2,3,301999112,0,27275,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27275,'impulse_drive',8,18,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,30,0,1500,18,1033,2,3,301999113,0,27276,27277,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27276,'chaos_thrust',8,50,128,32,32,0,0,0,100,6,0,0,5,0,0,0,0,0,0,80,0,3000,18,40,802,3,305274920,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27277,'ring_of_talons',19,45,0,32,32,1,8,1,100,1,0,0,5,0,0,0,0,0,0,60,0,2000,18,1009,803,3,305279985,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27278,'feint',8,4,1,32,32,0,0,0,100,1,0,1,5,0,0,0,0,0,0,10,0,250,18,39,2,3,301998119,0,27272,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27279,'full_thrust',8,38,128,32,32,0,0,0,100,1,0,1,5,0,0,0,0,0,0,30,0,250,18,1034,801,3,305271818,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27300,'dark_seal',22,14,3,1,1,0,0,0,100,1,0,0,0,0,223119,30,1,0,0,90,0,0,14,518,2,3,234889734,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27301,'resonance',22,22,3,1,1,0,0,0,100,1,0,0,0,0,223114,30,1,0,0,90,0,0,14,669,2,3,234889885,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27302,'excruciate',22,38,256,1,1,0,0,0,100,1,0,0,0,0,223231,30,1,0,0,90,0,0,14,694,2,3,234889910,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27303,'necrogenesis',22,6,3,1,1,0,0,0,100,1,0,0,0,0,223232,30,1,0,0,90,0,0,14,695,2,3,234889911,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27304,'parsimony',22,2,256,1,1,0,0,0,100,1,0,0,0,0,223233,30,1,0,0,90,0,0,14,568,2,3,234889784,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27305,'convert',26,30,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,450,0,0,14,724,2,3,234889940,0,0,0,0,1,30101); -INSERT INTO `server_battle_commands` VALUES (27306,'sleep',22,42,256,32,32,0,0,0,100,1,0,0,25,0,228001,0,0.9,2,3000,0,75,0,1,651,1,3,16781963,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27307,'sanguine_rite',22,30,3,1,1,0,0,0,100,1,0,0,0,0,223117,20,1,0,0,60,120,0,1,152,1,3,16781464,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27308,'blizzard',22,4,256,32,32,0,0,0,100,1,0,0,25,0,228021,0,0.75,2,3000,10,90,0,1,502,1,3,16781814,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27309,'blizzara',22,26,256,32,32,1,0,0,100,1,0,0,25,0,228011,0,0.75,0,0,40,150,0,1,506,1,3,16781818,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27310,'fire',22,10,3,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,3000,8,105,0,1,501,1,3,16781813,0,27311,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27311,'fira',22,34,3,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,5000,16,180,0,1,504,1,3,16781816,0,27312,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27312,'firaga',22,50,256,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,8000,7,255,0,1,700,1,3,16782012,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27313,'thunder',22,1,3,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,2000,6,75,0,1,503,1,3,16781815,0,27314,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27314,'thundara',22,18,256,32,32,0,0,0,100,1,0,0,25,0,223015,0,0.75,0,0,30,135,0,1,508,1,3,16781820,0,27315,27316,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27315,'thundaga',22,46,256,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,5000,45,195,0,1,509,1,3,16781821,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27316,'burst',26,50,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,4000,900,90,0,1,705,1,3,16782017,0,0,0,3,1,30301); -INSERT INTO `server_battle_commands` VALUES (27317,'sleepga',26,45,0,32,32,1,8,0,100,1,0,0,25,0,228001,0,0.9,2,4000,0,100,0,1,704,1,3,16782016,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27318,'flare',26,40,0,1,32,1,8,1,100,1,0,0,25,0,223154,0,0.75,2,8000,120,200,0,1,706,1,3,16782018,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27319,'freeze',26,35,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,5000,120,120,0,1,707,1,3,16782019,0,0,0,0,1,30301); -INSERT INTO `server_battle_commands` VALUES (27340,'sacred_prism',23,34,3,1,1,0,0,0,100,1,0,0,0,0,223225,60,1,0,0,90,0,0,14,690,2,3,234889906,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27341,'shroud_of_saints',23,38,512,1,1,0,0,0,100,1,0,0,0,0,223226,20,1,0,0,180,0,0,14,691,2,3,234889907,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27342,'cleric_stance',23,10,512,1,1,0,0,0,100,1,0,0,0,0,223227,4294967295,1,0,0,30,0,0,14,692,2,3,234889908,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27343,'blissful_mind',23,14,512,1,1,0,0,0,100,1,0,0,0,0,223228,4294967295,1,0,0,30,0,0,14,693,2,3,234889909,0,0,0,0,1,30321); -INSERT INTO `server_battle_commands` VALUES (27344,'presence_of_mind',27,30,0,1,1,0,0,0,100,1,0,0,0,0,223076,0,1,0,0,300,0,0,14,722,2,3,234889938,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27345,'benediction',27,50,0,1,4,1,20,1,100,1,0,0,0,0,0,0,0,0,0,900,0,0,14,723,2,3,234889939,0,0,0,0,1,30320); -INSERT INTO `server_battle_commands` VALUES (27346,'cure',23,2,3,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,5,40,0,1,101,1,3,16781413,0,0,0,0,1,30320); -INSERT INTO `server_battle_commands` VALUES (27347,'cura',23,30,512,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,5,100,0,1,103,1,3,16781415,0,0,0,0,1,30320); -INSERT INTO `server_battle_commands` VALUES (27348,'curaga',23,46,512,4,4,1,15,0,100,1,0,0,25,0,0,0,0,3,3000,10,150,0,1,146,1,3,16781458,0,0,0,0,1,30320); -INSERT INTO `server_battle_commands` VALUES (27349,'raise',23,18,512,128,128,0,0,0,100,1,0,0,25,0,0,0,0,3,10000,300,150,0,1,148,1,3,16781460,0,0,0,0,1,30101); -INSERT INTO `server_battle_commands` VALUES (27350,'stoneskin',23,26,3,2,2,0,0,0,100,1,0,0,25,0,223133,300,1,3,3000,30,50,0,1,133,1,3,16781445,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27351,'protect',23,6,3,4,4,1,20,0,100,1,0,0,25,0,223129,300,1,3,3000,30,80,0,1,1085,1,3,16782397,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27352,'repose',23,50,0,32,32,0,0,0,100,1,0,0,25,0,228001,0,0.9,3,3000,0,80,0,1,151,1,3,16781463,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27353,'aero',23,4,3,32,32,0,0,0,100,1,0,0,25,0,223235,0,0.75,3,3000,6,75,0,1,510,1,3,16781822,0,27354,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27354,'aerora',23,42,512,32,32,1,0,0,100,1,0,0,25,0,0,0,0,3,4000,20,150,0,1,511,1,3,16781823,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27355,'stone',23,1,3,32,32,0,0,0,100,1,0,0,25,0,223243,0,0.75,3,2000,6,75,0,1,513,1,3,16781825,0,27356,0,1,1,30301); -INSERT INTO `server_battle_commands` VALUES (27356,'stonera',23,22,512,32,32,1,0,0,100,1,0,0,25,0,228021,0,0.75,3,3000,30,150,0,1,514,1,3,16781826,0,0,0,2,1,30301); -INSERT INTO `server_battle_commands` VALUES (27357,'esuna',27,40,0,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,10,40,0,1,702,1,3,16782014,0,0,0,0,1,30329); -INSERT INTO `server_battle_commands` VALUES (27358,'regen',27,35,0,2,2,0,0,0,100,1,0,0,25,0,223180,45,1,3,2000,5,20,0,1,703,1,3,16782015,0,0,0,0,1,30328); -INSERT INTO `server_battle_commands` VALUES (27359,'holy',27,45,0,1,32,1,8,1,100,1,0,0,25,0,228011,0,0.9,0,0,300,100,0,1,708,1,3,16782020,0,0,0,0,1,30301); +INSERT INTO `server_battle_commands` VALUES (27100,'second_wind',2,6,3,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,45,0,0,14,519,2,3,234889735,0,0,0,0,0,30320,3,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27101,'blindside',2,14,3,1,1,0,0,0,100,1,0,0,0,0,223237,60,1,0,0,60,0,0,14,635,2,3,234889851,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27102,'taunt',2,42,4,32,32,0,0,0,100,1,0,0,25,0,223073,5,1,0,0,60,0,0,14,517,2,3,234889733,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27103,'featherfoot',2,2,3,1,1,0,0,0,100,1,0,0,0,0,223075,30,1,0,0,60,0,0,14,535,2,3,234889751,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27104,'fists_of_fire',2,34,4,1,1,0,0,0,100,1,0,0,0,0,223209,4294967295,1,0,0,10,0,0,14,684,2,3,234889900,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27105,'fists_of_earth',2,22,4,1,1,0,0,0,100,1,0,0,0,0,223210,4294967295,1,0,0,10,0,0,14,685,2,3,234889901,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27106,'hundred_fists',15,50,0,1,1,0,0,0,100,1,0,0,0,0,223244,15,1,0,0,900,0,0,14,712,2,3,234889928,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27107,'spinning_heel',15,35,0,1,1,0,0,0,100,1,0,0,0,0,223245,20,1,0,0,120,0,0,14,718,2,3,234889934,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27108,'shoulder_tackle',15,30,0,32,32,0,0,0,100,1,0,0,15,0,223015,10,0.75,0,0,60,0,0,18,1048,205,3,302830616,0,0,0,0,0,30301,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27109,'fists_of_wind',15,40,0,1,1,0,0,0,100,1,0,0,0,0,223211,4294967295,1,0,0,10,0,0,14,720,2,3,234889936,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27110,'pummel',2,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1027,1,3,301995011,0,27111,27113,1,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27111,'concussive_blow',2,10,1,32,32,0,0,0,100,1,4,0,5,0,223007,30,0,0,0,30,0,1500,18,20,3,3,302002196,0,27112,0,2,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27112,'simian_thrash',2,50,4,32,32,0,0,0,100,9,0,0,5,0,0,0,0,0,0,80,0,2000,18,1003,202,3,302818283,0,0,0,3,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27113,'aura_pulse',2,38,4,32,32,1,8,1,100,1,0,0,5,0,223003,30,0,0,0,40,0,1500,18,66,203,3,302821442,0,0,0,2,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27114,'pounce',2,4,4,32,32,0,0,0,100,1,2,0,5,0,223015,10,0,0,0,20,0,1500,18,8,3,3,302002184,0,27115,27117,1,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27115,'demolish',2,30,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,1028,2,3,301999108,0,27116,0,2,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27116,'howling_fist',2,46,4,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,80,0,3000,18,1029,2,3,301999109,0,0,0,3,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27117,'sucker_punch',2,26,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,15,0,1000,18,73,3,3,302002249,0,0,0,3,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27118,'dragon_kick',15,45,0,32,32,0,0,0,100,1,0,0,5,0,223013,10,0,0,0,60,0,2000,18,1041,204,3,302826513,0,0,0,0,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27119,'haymaker',2,18,4,32,32,0,0,0,100,1,0,2,5,0,223015,10,0.75,0,0,5,0,250,18,23,201,3,302813207,0,0,0,0,0,30301,2,1,3,0); +INSERT INTO `server_battle_commands` VALUES (27140,'sentinel',3,22,3,1,1,0,0,0,100,1,0,0,0,0,223062,15,1,0,0,90,0,0,14,526,2,3,234889742,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27141,'aegis_boon',3,6,8,1,1,0,0,0,100,1,0,0,0,0,223058,30,1,0,0,60,0,0,14,583,21,3,234967623,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27142,'rampart',3,2,3,1,5,0,8,1,100,1,0,0,0,0,223064,60,1,0,0,120,0,0,14,536,2,3,234889752,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27143,'tempered_will',3,42,8,1,1,0,0,0,100,1,0,0,0,0,223068,20,1,0,0,180,0,0,14,515,2,3,234889731,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27144,'outmaneuver',3,34,8,1,1,0,0,0,100,1,0,0,0,0,223236,30,1,0,0,90,0,0,14,512,21,3,234967552,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27145,'flash',3,14,3,32,32,0,8,0,100,1,0,0,25,0,223007,10,0,0,0,30,0,0,14,696,2,3,234889912,0,0,0,0,0,30101,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27146,'cover',16,30,0,4,4,0,0,0,100,1,0,0,15,0,223173,15,1,0,0,60,0,0,14,725,2,3,234889941,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27147,'divine_veil',16,35,0,1,1,0,0,0,100,1,0,0,0,0,223248,20,1,0,0,60,0,0,14,713,2,3,234889929,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27148,'hallowed_ground',16,50,0,1,1,0,0,0,100,1,0,0,0,0,223249,20,1,0,0,900,0,0,14,709,2,3,234889925,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27149,'holy_succor',16,40,0,2,2,0,0,0,100,1,0,0,15,0,0,0,0,3,2000,10,100,0,1,701,1,3,16782013,0,0,0,0,0,30328,3,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27150,'fast_blade',3,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1023,1,3,301995007,0,27151,27152,1,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27151,'flat_blade',3,26,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,10,0,1500,18,1024,2,3,301999104,0,0,0,2,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27152,'savage_blade',3,10,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1000,18,1025,1,3,301995009,0,27153,0,2,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27153,'goring_blade',3,50,8,32,32,0,0,0,100,1,2,0,5,0,223206,30,0,0,0,60,0,3000,18,1026,301,3,303223810,0,0,0,3,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27154,'riot_blade',3,30,8,32,32,0,0,0,100,1,2,0,5,0,223038,30,0,0,0,80,0,2000,18,75,2,3,301998155,0,27155,0,1,0,30301,2,1,1,1); +INSERT INTO `server_battle_commands` VALUES (27155,'rage_of_halone',3,46,8,32,32,0,0,0,100,5,0,0,5,0,0,0,0,0,0,20,0,1500,18,1008,302,3,303227888,0,0,0,2,-40,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27156,'shield_bash',3,18,17,32,32,0,0,0,100,1,0,0,5,0,223015,5,0.75,0,0,30,0,250,18,5,26,3,302096389,0,0,0,0,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27157,'war_drum',3,38,24,32,32,1,8,0,100,1,0,4,5,0,0,0,0,0,0,60,0,500,14,502,21,3,234967542,0,0,0,0,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27158,'phalanx',3,4,8,32,32,0,0,0,100,1,0,4,5,0,0,0,0,0,0,5,0,250,18,32,1,3,301994016,0,27159,0,1,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27159,'spirits_within',16,45,0,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,60,0,3000,18,1044,304,3,303236116,0,0,0,2,50,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27180,'provoke',4,14,3,32,32,0,0,0,100,1,0,0,25,0,223034,30,0,0,0,30,0,0,14,600,2,3,234889816,0,0,0,0,0,30101,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27181,'foresight',4,2,3,1,1,0,0,0,100,1,0,0,0,0,223083,30,1,0,0,60,0,0,14,545,2,3,234889761,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27182,'bloodbath',4,6,3,1,1,0,0,0,100,1,0,0,0,0,223081,30,1,0,0,60,0,0,14,581,2,3,234889797,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27183,'berserk',4,22,32,1,1,0,0,0,100,1,0,0,0,0,223207,4294967295,1,0,0,10,0,0,14,682,2,3,234889898,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27184,'rampage',4,34,32,1,1,0,0,0,100,1,0,0,0,0,223208,4294967295,1,0,0,10,0,0,14,546,2,3,234889762,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27185,'enduring_march',4,42,32,1,1,0,0,0,100,1,0,0,0,0,223078,20,1,0,0,180,0,0,14,539,2,3,234889755,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27186,'vengeance',17,30,0,1,1,0,0,0,100,1,0,0,0,0,223250,15,1,0,0,150,0,0,14,714,2,3,234889930,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27187,'antagonize',17,35,0,1,1,0,0,0,100,1,0,0,0,0,223251,15,1,0,0,120,0,0,14,715,2,3,234889931,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27188,'collusion',17,40,0,4,4,0,0,0,100,1,0,0,15,0,223097,15,1,0,0,90,0,0,14,711,2,3,234889927,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27189,'mighty_strikes',17,50,0,1,1,0,0,0,100,1,0,0,0,0,223252,15,1,0,0,900,0,0,14,716,2,3,234889932,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27190,'heavy_swing',4,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,14,1,3,301993998,0,27191,0,1,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27191,'skull_sunder',4,10,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,43,1,3,301994027,0,27192,0,2,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27192,'steel_cyclone',17,45,0,32,32,1,8,0,100,1,0,0,5,0,223015,3,0,0,0,30,0,2000,18,1040,404,3,303645712,0,0,0,3,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27193,'brutal_swing',4,4,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,20,0,1500,18,15,3,3,302002191,0,27194,0,1,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27194,'maim',4,26,1,32,32,0,0,0,100,1,0,0,5,0,0,0,0,0,0,30,0,1500,18,88,1,3,301994072,0,27195,0,2,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27195,'godsbane',4,50,32,32,32,0,0,0,100,3,0,0,5,0,0,0,0,0,0,60,0,3000,18,1014,402,3,303637494,0,0,0,3,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27196,'path_of_the_storm',4,38,32,32,32,0,0,0,100,1,2,0,5,0,228021,30,0,0,0,30,0,1500,18,44,401,3,303632428,0,27197,0,1,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27197,'whirlwind',4,46,32,32,32,1,8,0,100,1,0,0,5,0,0,0,0,0,0,80,0,3000,18,1015,403,3,303641591,0,0,0,2,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27198,'fracture',4,18,32,32,32,0,0,0,100,1,0,3,5,0,223013,8,0.75,0,0,40,0,500,18,42,3,3,302002218,0,0,0,0,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27199,'overpower',4,30,1,32,32,2,0,0,100,1,0,3,5,0,0,0,0,0,0,5,0,250,18,89,1,3,301994073,0,0,0,0,0,30301,2,1,1,0); +INSERT INTO `server_battle_commands` VALUES (27220,'hawks_eye',7,6,3,1,1,0,0,0,100,1,0,0,0,0,223106,15,1,0,0,90,0,0,14,516,2,3,234889732,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27221,'quelling_strike',7,22,3,1,1,0,0,0,100,1,0,0,0,0,223104,30,1,0,0,60,0,0,14,614,2,3,234889830,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27222,'decoy',7,2,3,1,1,0,0,0,100,1,0,0,0,0,223108,60,1,0,0,90,100,0,14,565,2,3,234889781,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27223,'chameleon',7,42,3,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,180,0,0,14,504,2,3,234889720,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27224,'barrage',7,34,64,1,1,0,0,0,100,1,0,0,0,0,223220,60,1,0,0,90,0,0,14,683,2,3,234889899,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27225,'raging_strike',7,14,64,1,1,0,0,0,100,1,0,0,0,0,223221,4294967295,1,0,0,10,0,0,14,632,2,3,234889848,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27226,'swiftsong',7,26,64,1,1,1,20,0,100,1,0,0,0,0,223224,180,1,0,0,10,100,0,1,150,1,3,16781462,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27227,'battle_voice',18,50,0,1,1,1,0,0,100,1,0,0,0,0,223253,60,1,0,0,900,0,0,14,721,2,3,234889937,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27228,'heavy_shot',7,1,1,32,32,0,0,0,100,1,0,0,25,8,0,0,0,0,0,10,0,1000,18,1036,4,3,302007308,0,27229,27231,1,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27229,'leaden_arrow',7,10,1,32,32,0,0,0,100,1,0,0,25,0,228021,30,0.75,0,0,30,0,1500,18,1035,4,3,302007307,0,27230,0,2,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27230,'wide_volley',7,50,64,32,32,1,8,0,100,1,0,0,25,0,0,0,0,0,0,80,0,2000,18,18,703,3,304869394,0,0,0,3,-20,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27231,'quick_nock',7,38,64,32,32,2,0,0,100,1,0,0,10,0,0,0,0,0,0,180,0,1000,18,1017,702,3,304866297,0,27232,0,2,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27232,'rain_of_death',18,45,0,32,32,1,8,0,100,1,0,0,25,0,223015,5,0.75,0,0,30,0,3000,18,1037,704,3,304874509,0,0,0,3,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27233,'piercing_arrow',7,4,1,32,32,0,0,0,100,1,0,0,25,8,0,0,0,0,0,20,0,1000,18,1038,1,3,301995022,0,27234,27236,1,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27234,'gloom_arrow',7,30,1,32,32,0,0,0,100,1,0,0,25,0,223007,30,0,0,0,10,0,1000,18,1039,4,3,302007311,0,27235,0,2,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27235,'bloodletter',7,46,64,32,32,0,0,0,100,1,0,0,25,0,223241,30,0.75,0,0,80,0,1500,18,53,701,3,304861237,0,0,0,3,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27236,'shadowbind',7,18,64,32,32,0,0,0,100,1,0,0,25,0,228011,15,0.9,0,0,40,0,250,18,17,4,3,302006289,0,0,0,2,0,30301,2,1,4,1); +INSERT INTO `server_battle_commands` VALUES (27237,'ballad_of_magi',18,30,0,1,1,1,20,0,100,1,0,0,0,0,223254,180,1,8,3000,10,100,0,1,709,1,3,16782021,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27238,'paeon_of_war',18,40,0,1,1,1,20,0,100,1,0,0,0,0,223255,180,1,8,3000,10,50,1000,1,710,1,3,16782022,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27239,'minuet_of_rigor',18,35,0,1,1,1,20,0,100,1,0,0,0,0,223256,180,1,8,3000,10,100,0,1,711,1,3,16782023,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27258,'refill',7,1,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,32613,3,0,0,0); +INSERT INTO `server_battle_commands` VALUES (27259,'light_shot',7,1,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,0,0,0,0,0,17,0,1,3,285216768,0,0,0,0,0,30301,3,1,0,1); +INSERT INTO `server_battle_commands` VALUES (27260,'invigorate',8,14,3,1,1,0,0,0,100,1,0,0,0,0,223094,30,1,0,0,90,0,0,14,575,2,3,234889791,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27261,'power_surge',8,34,128,1,1,0,0,0,100,1,0,0,0,0,223212,60,1,0,0,10,0,0,14,686,2,3,234889902,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27262,'life_surge',8,22,128,1,1,0,0,0,100,1,0,0,0,0,223215,180,1,0,0,15,0,250,14,687,2,3,234889903,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27263,'dread_spike',8,42,128,1,1,0,0,0,100,1,0,0,0,0,223218,30,1,0,0,120,0,0,14,686,2,3,234889902,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27264,'blood_for_blood',8,6,3,1,1,0,0,0,100,1,0,0,0,0,223219,60,1,0,0,60,0,0,14,689,2,3,234889905,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27265,'keen_flurry',8,26,3,1,1,0,0,0,100,1,0,0,0,0,223091,30,1,0,0,90,0,0,14,569,2,3,234889785,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27266,'jump',19,30,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,0,0,60,0,0,18,1045,804,3,305284117,0,0,0,0,0,30301,3,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27267,'elusive_jump',19,40,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,180,0,0,18,1046,806,3,305292310,0,0,0,0,0,30101,3,0,0,0); +INSERT INTO `server_battle_commands` VALUES (27268,'dragonfire_dive',19,50,0,32,32,1,0,0,100,1,0,0,25,0,0,0,0,0,0,900,0,0,18,1045,804,3,305284117,0,0,0,0,0,30301,3,2,5,0); +INSERT INTO `server_battle_commands` VALUES (27269,'true_thrust',8,1,1,32,32,0,0,0,100,1,1,0,5,0,0,0,0,0,0,10,0,1000,18,1030,2,3,301999110,0,27270,27273,1,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27270,'leg_sweep',8,30,1,32,32,1,0,0,100,1,0,0,5,0,223015,8,0,0,0,30,0,1000,18,37,1,3,301994021,0,27271,0,2,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27271,'doom_spike',8,46,128,32,32,3,0,0,100,1,0,0,5,0,0,0,0,0,0,60,0,3000,18,83,801,3,305270867,0,0,0,3,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27272,'disembowel',19,35,0,32,32,0,0,0,100,1,0,0,5,0,223005,15,0.75,0,0,30,0,750,18,1042,2,3,301999122,0,0,0,0,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27273,'heavy_thrust',8,10,1,32,32,0,0,0,100,1,0,0,5,0,223015,4,0.75,0,0,20,0,1500,18,1031,1,3,301995015,0,0,0,0,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27274,'vorpal_thrust',8,2,1,32,32,0,0,0,100,1,2,0,5,0,0,0,0,0,0,20,0,1500,18,1032,2,3,301999112,0,27275,0,1,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27275,'impulse_drive',8,18,1,32,32,0,0,0,100,1,4,0,5,0,0,0,0,0,0,30,0,1500,18,1033,2,3,301999113,0,27276,27277,2,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27276,'chaos_thrust',8,50,128,32,32,0,0,0,100,6,0,0,5,0,0,0,0,0,0,80,0,3000,18,40,802,3,305274920,0,0,0,3,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27277,'ring_of_talons',19,45,0,32,32,1,8,1,100,1,0,0,5,0,0,0,0,0,0,60,0,2000,18,1009,803,3,305279985,0,0,0,3,0,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27278,'feint',8,4,1,32,32,0,0,0,100,1,0,1,5,0,0,0,0,0,0,10,0,250,18,39,2,3,301998119,0,27272,0,1,100,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27279,'full_thrust',8,38,128,32,32,0,0,0,100,1,0,1,5,0,0,0,0,0,0,30,0,250,18,1034,801,3,305271818,0,0,0,0,50,30301,2,1,2,0); +INSERT INTO `server_battle_commands` VALUES (27300,'dark_seal',22,14,3,1,1,0,0,0,100,1,0,0,0,0,223229,30,1,0,0,90,0,0,14,518,2,3,234889734,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27301,'resonance',22,22,3,1,1,0,0,0,100,1,0,0,0,0,223230,30,1,0,0,90,0,0,14,669,2,3,234889885,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27302,'excruciate',22,38,256,1,1,0,0,0,100,1,0,0,0,0,223231,30,1,0,0,90,0,0,14,694,2,3,234889910,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27303,'necrogenesis',22,6,3,1,1,0,0,0,100,1,0,0,0,0,223232,30,1,0,0,90,0,0,14,695,2,3,234889911,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27304,'parsimony',22,2,256,1,1,0,0,0,100,1,0,0,0,0,223233,30,1,0,0,90,0,0,14,568,2,3,234889784,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27305,'convert',26,30,0,1,1,0,0,0,100,1,0,0,0,0,0,0,0,0,0,450,0,0,14,724,2,3,234889940,0,0,0,0,0,30101,3,0,0,0); +INSERT INTO `server_battle_commands` VALUES (27306,'sleep',22,42,256,32,32,0,0,0,100,1,0,0,25,0,228001,60,0.9,2,3000,0,75,0,1,651,1,3,16781963,0,0,0,0,0,30328,4,4,12,0); +INSERT INTO `server_battle_commands` VALUES (27307,'sanguine_rite',22,30,3,1,1,0,0,0,100,1,0,0,0,0,223234,20,1,0,0,60,120,0,1,152,1,3,16781464,0,0,0,0,0,30328,4,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27308,'blizzard',22,4,256,32,32,0,0,0,100,1,0,0,25,0,228021,30,0.75,2,3000,10,90,0,1,502,1,3,16781814,0,0,0,0,0,30301,4,2,6,0); +INSERT INTO `server_battle_commands` VALUES (27309,'blizzara',22,26,256,32,32,1,0,0,100,1,0,0,25,0,228011,30,0.75,0,0,40,150,0,1,506,1,3,16781818,0,0,0,0,0,30301,4,2,6,0); +INSERT INTO `server_battle_commands` VALUES (27310,'fire',22,10,3,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,3000,8,105,0,1,501,1,3,16781813,0,27311,0,1,0,30301,4,2,5,0); +INSERT INTO `server_battle_commands` VALUES (27311,'fira',22,34,3,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,5000,16,180,0,1,504,1,3,16781816,0,27312,0,2,0,30301,4,2,5,0); +INSERT INTO `server_battle_commands` VALUES (27312,'firaga',22,50,256,32,32,1,0,0,100,1,0,0,25,0,0,0,0,2,8000,7,255,0,1,700,1,3,16782012,0,0,0,3,0,30301,4,2,5,0); +INSERT INTO `server_battle_commands` VALUES (27313,'thunder',22,1,3,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,2000,6,75,0,1,503,1,3,16781815,0,27314,0,1,0,30301,4,2,9,0); +INSERT INTO `server_battle_commands` VALUES (27314,'thundara',22,18,256,32,32,0,0,0,100,1,0,0,25,0,223015,4,0.75,0,0,30,135,0,1,508,1,3,16781820,0,27315,27316,2,0,30301,4,2,9,0); +INSERT INTO `server_battle_commands` VALUES (27315,'thundaga',22,46,256,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,5000,45,195,0,1,509,1,3,16781821,0,0,0,3,0,30301,4,2,9,0); +INSERT INTO `server_battle_commands` VALUES (27316,'burst',26,50,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,4000,900,90,0,1,705,1,3,16782017,0,0,0,3,0,30301,4,2,9,0); +INSERT INTO `server_battle_commands` VALUES (27317,'sleepga',26,45,0,32,32,1,8,0,100,1,0,0,25,0,228001,60,0.9,2,4000,0,100,0,1,704,1,3,16782016,0,0,0,0,0,30328,4,4,12,0); +INSERT INTO `server_battle_commands` VALUES (27318,'flare',26,40,0,1,32,1,8,1,100,1,0,0,25,0,223262,30,0.75,2,8000,120,200,0,1,706,1,3,16782018,0,0,0,0,0,30301,4,2,5,0); +INSERT INTO `server_battle_commands` VALUES (27319,'freeze',26,35,0,32,32,0,0,0,100,1,0,0,25,0,0,0,0,2,5000,120,120,0,1,707,1,3,16782019,0,0,0,0,0,30301,4,2,6,0); +INSERT INTO `server_battle_commands` VALUES (27340,'sacred_prism',23,34,3,1,1,0,0,0,100,1,0,0,0,0,223225,60,1,0,0,90,0,0,14,690,2,3,234889906,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27341,'shroud_of_saints',23,38,512,1,1,0,0,0,100,1,0,0,0,0,223226,20,1,0,0,180,0,0,14,691,2,3,234889907,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27342,'cleric_stance',23,10,512,1,1,0,0,0,100,1,0,0,0,0,223227,4294967295,1,0,0,30,0,0,14,692,2,3,234889908,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27343,'blissful_mind',23,14,512,1,1,0,0,0,100,1,0,0,0,0,223228,4294967295,1,0,0,30,0,0,14,693,2,3,234889909,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27344,'presence_of_mind',27,30,0,1,1,0,0,0,100,1,0,0,0,0,223116,30,1,0,0,300,0,0,14,722,2,3,234889938,0,0,0,0,0,30328,3,4,0,0); +INSERT INTO `server_battle_commands` VALUES (27345,'benediction',27,50,0,1,4,1,20,1,100,1,0,0,0,0,0,0,0,0,0,900,0,0,14,723,2,3,234889939,0,0,0,0,0,30320,3,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27346,'cure',23,2,3,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,5,40,0,1,101,1,3,16781413,0,0,0,0,0,30320,4,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27347,'cura',23,30,512,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,5,100,0,1,103,1,3,16781415,0,0,0,0,0,30320,4,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27348,'curaga',23,46,512,4,4,1,15,0,100,1,0,0,25,0,0,0,0,3,3000,10,150,0,1,146,1,3,16781458,0,0,0,0,0,30320,4,3,13,0); +INSERT INTO `server_battle_commands` VALUES (27349,'raise',23,18,512,128,128,0,0,0,100,1,0,0,25,0,0,0,0,3,10000,300,150,0,1,148,1,3,16781460,0,0,0,0,0,30101,4,4,11,0); +INSERT INTO `server_battle_commands` VALUES (27350,'stoneskin',23,26,3,2,2,0,0,0,100,1,0,0,25,0,223133,300,1,3,3000,30,50,0,1,133,1,3,16781445,0,0,0,0,0,30328,4,4,8,0); +INSERT INTO `server_battle_commands` VALUES (27351,'protect',23,6,3,4,4,1,20,0,100,1,0,0,25,0,223239,300,1,3,3000,30,80,0,1,1085,1,3,16782397,0,0,0,0,0,30328,4,4,11,0); +INSERT INTO `server_battle_commands` VALUES (27352,'repose',23,50,0,32,32,0,0,0,100,1,0,0,25,0,228001,60,0.9,3,3000,0,80,0,1,151,1,3,16781463,0,0,0,0,0,30328,4,4,10,0); +INSERT INTO `server_battle_commands` VALUES (27353,'aero',23,4,3,32,32,0,0,0,100,1,0,0,25,0,223235,20,0.75,3,3000,6,75,0,1,510,1,3,16781822,0,27354,0,1,0,30301,4,2,7,0); +INSERT INTO `server_battle_commands` VALUES (27354,'aerora',23,42,512,32,32,1,0,0,100,1,0,0,25,0,0,0,0,3,4000,20,150,0,1,511,1,3,16781823,0,0,0,2,0,30301,4,2,7,0); +INSERT INTO `server_battle_commands` VALUES (27355,'stone',23,1,3,32,32,0,0,0,100,1,0,0,25,0,223243,10,0.75,3,2000,6,75,0,1,513,1,3,16781825,0,27356,0,1,0,30301,4,2,8,0); +INSERT INTO `server_battle_commands` VALUES (27356,'stonera',23,22,512,32,32,1,0,0,100,1,0,0,25,0,228021,30,0.75,3,3000,30,150,0,1,514,1,3,16781826,0,0,0,2,0,30301,4,2,8,0); +INSERT INTO `server_battle_commands` VALUES (27357,'esuna',27,40,0,2,2,0,0,0,100,1,0,0,25,0,0,0,0,3,2000,10,40,0,1,702,1,3,16782014,0,0,0,0,0,30329,4,0,13,0); +INSERT INTO `server_battle_commands` VALUES (27358,'regen',27,35,0,2,2,0,0,0,100,1,0,0,25,0,223180,45,1,3,2000,5,20,0,1,703,1,3,16782015,0,0,0,0,0,30328,4,4,13,0); +INSERT INTO `server_battle_commands` VALUES (27359,'holy',27,45,0,1,32,1,8,1,100,1,0,0,25,0,228011,10,0.9,0,0,300,100,0,1,708,1,3,16782020,0,0,0,0,0,30301,4,2,11,0); /*!40000 ALTER TABLE `server_battle_commands` ENABLE KEYS */; UNLOCK TABLES; commit; @@ -224,4 +228,4 @@ commit; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2018-02-15 0:04:47 +-- Dump completed on 2018-04-18 14:44:11 diff --git a/sql/server_battle_traits.sql b/sql/server_battle_traits.sql new file mode 100644 index 00000000..2c3d7d9d --- /dev/null +++ b/sql/server_battle_traits.sql @@ -0,0 +1,133 @@ +-- MySQL dump 10.13 Distrib 5.7.11, for Win64 (x86_64) +-- +-- Host: localhost Database: ffxiv_server +-- ------------------------------------------------------ +-- Server version 5.7.11 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `server_battle_traits` +-- + +DROP TABLE IF EXISTS `server_battle_traits`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `server_battle_traits` ( + `id` smallint(6) NOT NULL, + `name` varchar(50) NOT NULL, + `classJob` tinyint(4) NOT NULL, + `lvl` tinyint(4) NOT NULL, + `modifier` int(11) NOT NULL DEFAULT '0', + `bonus` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `server_battle_traits` +-- + +LOCK TABLES `server_battle_traits` WRITE; +/*!40000 ALTER TABLE `server_battle_traits` DISABLE KEYS */; +set autocommit=0; +INSERT INTO `server_battle_traits` VALUES (27240,'enhanced_hawks_eye',7,28,0,0); +INSERT INTO `server_battle_traits` VALUES (27242,'enhanced_barrage',7,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27241,'enhanced_quelling_strike',7,32,0,0); +INSERT INTO `server_battle_traits` VALUES (27243,'enhanced_raging_strike',7,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27244,'enhanced_decoy',7,16,0,0); +INSERT INTO `server_battle_traits` VALUES (27245,'swift_chameleon',7,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27246,'enhanced_physical_crit_accuracy',7,40,65,10); +INSERT INTO `server_battle_traits` VALUES (27247,'enhanced_physical_crit_evasion',7,20,66,10); +INSERT INTO `server_battle_traits` VALUES (27248,'enhanced_physical_evasion',7,12,16,8); +INSERT INTO `server_battle_traits` VALUES (27249,'enhanced_physical_accuracy',7,8,16,8); +INSERT INTO `server_battle_traits` VALUES (27250,'enhanced_physical_accuracy_ii',7,24,16,10); +INSERT INTO `server_battle_traits` VALUES (27120,'enhanced_second_wind',2,20,0,0); +INSERT INTO `server_battle_traits` VALUES (27121,'enhanced_blindside',2,24,0,0); +INSERT INTO `server_battle_traits` VALUES (27122,'swift_taunt',2,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27123,'enhanced_featherfoot',2,28,0,0); +INSERT INTO `server_battle_traits` VALUES (27124,'enhanced_fists_of_fire',2,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27125,'enhanced_fists_of_earth',2,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27126,'enhanced_physical_accuracy',2,16,16,8); +INSERT INTO `server_battle_traits` VALUES (27127,'enhanced_physical_attack',2,8,17,8); +INSERT INTO `server_battle_traits` VALUES (27128,'enhanced_physical_attack_ii',2,40,17,10); +INSERT INTO `server_battle_traits` VALUES (27129,'enhanced_evasion',2,12,16,8); +INSERT INTO `server_battle_traits` VALUES (27130,'enhanced_physical_crit_damage',2,32,67,10); +INSERT INTO `server_battle_traits` VALUES (27160,'enhanced_sentinel',3,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27161,'enhanced_flash',3,28,0,0); +INSERT INTO `server_battle_traits` VALUES (27162,'enhanced_flash_ii',3,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27163,'enhanced_rampart',3,12,0,0); +INSERT INTO `server_battle_traits` VALUES (27164,'swift_aegis_boon',3,20,0,0); +INSERT INTO `server_battle_traits` VALUES (27165,'enhanced_outmaneuver',3,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27167,'enhanced_block_rate',3,16,52,10); +INSERT INTO `server_battle_traits` VALUES (27166,'enhanced_physical_crit_resilience',3,32,68,10); +INSERT INTO `server_battle_traits` VALUES (27168,'enhanced_physical_defense',3,8,18,10); +INSERT INTO `server_battle_traits` VALUES (27169,'enhanced_physical_defense_ii',3,24,18,10); +INSERT INTO `server_battle_traits` VALUES (27170,'enhanced_physical_defense_iii',3,40,18,12); +INSERT INTO `server_battle_traits` VALUES (27200,'enhanced_provoke',4,28,0,0); +INSERT INTO `server_battle_traits` VALUES (27201,'swift_foresight',4,20,0,0); +INSERT INTO `server_battle_traits` VALUES (27202,'swift_bloodbath',4,16,0,0); +INSERT INTO `server_battle_traits` VALUES (27203,'enhanced_enduring_march',4,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27204,'enhanced_rampage',4,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27205,'enhanced_berserk',4,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27206,'enhanced_physical_crit_evasion',4,32,66,10); +INSERT INTO `server_battle_traits` VALUES (27207,'enhanced_parry',4,24,69,8); +INSERT INTO `server_battle_traits` VALUES (27208,'enhanced_physical_defense',4,12,18,8); +INSERT INTO `server_battle_traits` VALUES (27209,'enhanced_physical_defense_ii',4,40,18,10); +INSERT INTO `server_battle_traits` VALUES (27210,'enhanced_physical_attack_power',4,8,17,8); +INSERT INTO `server_battle_traits` VALUES (27280,'enhanced_invigorate',8,28,0,0); +INSERT INTO `server_battle_traits` VALUES (27281,'enhanced_power_surge',8,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27282,'enhanced_life_surge',8,32,0,0); +INSERT INTO `server_battle_traits` VALUES (27283,'enhanced_blood_for_blood',8,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27284,'swift_blood_for_blood',8,16,0,0); +INSERT INTO `server_battle_traits` VALUES (27285,'enhanced_keen_flurry',8,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27286,'store_tp',8,12,64,50); +INSERT INTO `server_battle_traits` VALUES (27287,'enhanced_physical_crit_accuracy',8,24,65,10); +INSERT INTO `server_battle_traits` VALUES (27288,'enhanced_physical_attack_power',8,8,17,8); +INSERT INTO `server_battle_traits` VALUES (27289,'enhanced_physical_attack_power_ii',8,20,17,10); +INSERT INTO `server_battle_traits` VALUES (27290,'enhanced_physical_attack_power_iii',8,40,17,10); +INSERT INTO `server_battle_traits` VALUES (27320,'swift_dark_seal',22,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27321,'enhanced_excruciate',22,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27322,'swift_necrogenesis',22,24,0,0); +INSERT INTO `server_battle_traits` VALUES (27323,'enhanced_parsimony',22,16,0,0); +INSERT INTO `server_battle_traits` VALUES (27324,'enhanced_sanguine_rite',22,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27325,'enhanced_enfeebling_magic',22,12,26,8); +INSERT INTO `server_battle_traits` VALUES (27326,'enhanced_enfeebling_magic_ii',22,28,26,10); +INSERT INTO `server_battle_traits` VALUES (27327,'enhanced_magic_potency',22,8,23,8); +INSERT INTO `server_battle_traits` VALUES (27328,'enhanced_magic_potency_ii',22,28,23,10); +INSERT INTO `server_battle_traits` VALUES (27329,'enhanced_magic_crit_potency',22,40,70,10); +INSERT INTO `server_battle_traits` VALUES (27330,'auto-refresh',22,20,45,3); +INSERT INTO `server_battle_traits` VALUES (27360,'swift_sacred_prism',23,40,0,0); +INSERT INTO `server_battle_traits` VALUES (27361,'swift_shroud_of_saints',23,44,0,0); +INSERT INTO `server_battle_traits` VALUES (27362,'enhanced_blissful_mind',23,32,0,0); +INSERT INTO `server_battle_traits` VALUES (27363,'enhanced_raise',23,48,0,0); +INSERT INTO `server_battle_traits` VALUES (27364,'enhanced_stoneskin',23,36,0,0); +INSERT INTO `server_battle_traits` VALUES (27365,'enhanced_protect',23,24,0,0); +INSERT INTO `server_battle_traits` VALUES (27366,'greater_enhancing_magic',23,12,25,8); +INSERT INTO `server_battle_traits` VALUES (27367,'greater_healing',23,8,24,8); +INSERT INTO `server_battle_traits` VALUES (27368,'greater_healing_ii',23,18,24,10); +INSERT INTO `server_battle_traits` VALUES (27369,'enhanced_magic_accuracy',23,16,27,8); +INSERT INTO `server_battle_traits` VALUES (27370,'auto-refresh',23,20,45,3); +/*!40000 ALTER TABLE `server_battle_traits` ENABLE KEYS */; +UNLOCK TABLES; +commit; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2018-04-18 14:44:11 diff --git a/sql/server_battlenpc_pool_mods.sql b/sql/server_battlenpc_pool_mods.sql index affc751a..b76e11ef 100644 --- a/sql/server_battlenpc_pool_mods.sql +++ b/sql/server_battlenpc_pool_mods.sql @@ -1,8 +1,8 @@ --- MySQL dump 10.13 Distrib 5.7.18, for Win64 (x86_64) +-- MySQL dump 10.13 Distrib 5.7.11, for Win64 (x86_64) -- -- Host: localhost Database: ffxiv_server -- ------------------------------------------------------ --- Server version 5.7.18-log +-- Server version 5.7.11 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -40,6 +40,11 @@ LOCK TABLES `server_battlenpc_pool_mods` WRITE; set autocommit=0; INSERT INTO `server_battlenpc_pool_mods` VALUES (2,2,3,1); INSERT INTO `server_battlenpc_pool_mods` VALUES (2,3,3,1); +INSERT INTO `server_battlenpc_pool_mods` VALUES (2,24,0,1); +INSERT INTO `server_battlenpc_pool_mods` VALUES (3,24,0,1); +INSERT INTO `server_battlenpc_pool_mods` VALUES (3,49,1,0); +INSERT INTO `server_battlenpc_pool_mods` VALUES (4,24,0,1); +INSERT INTO `server_battlenpc_pool_mods` VALUES (4,49,1,0); /*!40000 ALTER TABLE `server_battlenpc_pool_mods` ENABLE KEYS */; UNLOCK TABLES; commit; @@ -53,4 +58,4 @@ commit; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2017-09-16 2:43:11 +-- Dump completed on 2018-04-18 14:54:09 diff --git a/sql/server_statuseffects.sql b/sql/server_statuseffects.sql index ff412d0b..f706bc7b 100644 --- a/sql/server_statuseffects.sql +++ b/sql/server_statuseffects.sql @@ -39,39 +39,78 @@ CREATE TABLE `server_statuseffects` ( LOCK TABLES `server_statuseffects` WRITE; /*!40000 ALTER TABLE `server_statuseffects` DISABLE KEYS */; set autocommit=0; -INSERT INTO `server_statuseffects` VALUES (223001,'quick',10,2,0); -INSERT INTO `server_statuseffects` VALUES (223002,'haste',18,2,0); -INSERT INTO `server_statuseffects` VALUES (223004,'petrification',16515074,2,0); -INSERT INTO `server_statuseffects` VALUES (223005,'paralysis',3932162,2,3000); -INSERT INTO `server_statuseffects` VALUES (223006,'silence',262154,2,0); -INSERT INTO `server_statuseffects` VALUES (223007,'blind',10,2,0); -INSERT INTO `server_statuseffects` VALUES (223008,'mute',262154,2,0); -INSERT INTO `server_statuseffects` VALUES (223010,'glare',10,2,0); -INSERT INTO `server_statuseffects` VALUES (223011,'poison',10,2,3000); -INSERT INTO `server_statuseffects` VALUES (223012,'transfixion',8388610,2,0); -INSERT INTO `server_statuseffects` VALUES (223013,'pacification',2621450,2,0); -INSERT INTO `server_statuseffects` VALUES (223014,'amnesia',1048586,2,0); -INSERT INTO `server_statuseffects` VALUES (223015,'stun',16515082,2,0); -INSERT INTO `server_statuseffects` VALUES (223016,'daze',16515082,2,0); -INSERT INTO `server_statuseffects` VALUES (223029,'hp_boost',18,2,0); -INSERT INTO `server_statuseffects` VALUES (223030,'hp_penalty',10,2,0); -INSERT INTO `server_statuseffects` VALUES (223058,'aegis_boon',65554,2,3000); -INSERT INTO `server_statuseffects` VALUES (223060,'outmaneuver',65554,2,3000); -INSERT INTO `server_statuseffects` VALUES (223062,'sentinel',18,2,3000); -INSERT INTO `server_statuseffects` VALUES (223068,'tempered_will',18,2,3000); -INSERT INTO `server_statuseffects` VALUES (223075,'featherfoot',1042,2,0); -INSERT INTO `server_statuseffects` VALUES (223094,'invigorate',18,2,2000); -INSERT INTO `server_statuseffects` VALUES (223129,'protect',10,2,0); -INSERT INTO `server_statuseffects` VALUES (223205,'combo',10,2,3000); -INSERT INTO `server_statuseffects` VALUES (223206,'goring_blade',10,2,3000); -INSERT INTO `server_statuseffects` VALUES (223209,'fists_of_fire',33554466,2,0); -INSERT INTO `server_statuseffects` VALUES (223210,'fists_of_earth',33554466,2,0); -INSERT INTO `server_statuseffects` VALUES (223211,'fists_of_wind',33554466,2,0); -INSERT INTO `server_statuseffects` VALUES (223245,'spinning_heel',18,1,0); -INSERT INTO `server_statuseffects` VALUES (253003,'evade_proc',15,1,0); -INSERT INTO `server_statuseffects` VALUES (253004,'block_proc',15,1,0); -INSERT INTO `server_statuseffects` VALUES (253005,'parry_proc',15,1,0); -INSERT INTO `server_statuseffects` VALUES (253006,'miss_proc',15,1,0); +INSERT INTO `server_statuseffects` VALUES (223001,'quick',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223002,'haste',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223004,'petrification',264241194,2,0); +INSERT INTO `server_statuseffects` VALUES (223005,'paralysis',42,2,3000); +INSERT INTO `server_statuseffects` VALUES (223006,'silence',4194346,2,0); +INSERT INTO `server_statuseffects` VALUES (223007,'blind',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223008,'mute',4194346,2,0); +INSERT INTO `server_statuseffects` VALUES (223010,'glare',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223011,'poison',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223012,'transfixion',268435498,2,0); +INSERT INTO `server_statuseffects` VALUES (223013,'pacification',8388650,2,0); +INSERT INTO `server_statuseffects` VALUES (223014,'amnesia',16777258,2,0); +INSERT INTO `server_statuseffects` VALUES (223015,'stun',264241194,2,0); +INSERT INTO `server_statuseffects` VALUES (223016,'daze',264241194,2,0); +INSERT INTO `server_statuseffects` VALUES (223029,'hp_boost',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223030,'hp_penalty',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223038,'defense_down',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223058,'aegis_boon',528434,2,0); +INSERT INTO `server_statuseffects` VALUES (223062,'sentinel',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223063,'cover',16434,2,0); +INSERT INTO `server_statuseffects` VALUES (223064,'rampart',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223068,'tempered_will',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223075,'featherfoot',131122,2,0); +INSERT INTO `server_statuseffects` VALUES (223078,'enduring_march',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223081,'bloodbath',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223083,'foresight',262194,2,0); +INSERT INTO `server_statuseffects` VALUES (223091,'keen_flurry',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223094,'invigorate',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223097,'collusion',1048626,1,0); +INSERT INTO `server_statuseffects` VALUES (223104,'quelling_strike',1058,2,0); +INSERT INTO `server_statuseffects` VALUES (223106,'hawks_eye',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223108,'decoy',4130,2,0); +INSERT INTO `server_statuseffects` VALUES (223127,'bloodletter',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223173,'covered',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223180,'regen',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223205,'combo',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223206,'goring_blade',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223207,'berserk2',1074806818,1,3000); +INSERT INTO `server_statuseffects` VALUES (223208,'rampage2',1075855394,1,5000); +INSERT INTO `server_statuseffects` VALUES (223209,'fists_of_fire',1073742882,2,0); +INSERT INTO `server_statuseffects` VALUES (223210,'fists_of_earth',1073742882,2,0); +INSERT INTO `server_statuseffects` VALUES (223211,'fists_of_wind',1073742882,2,0); +INSERT INTO `server_statuseffects` VALUES (223212,'power_surge_I',1058,2,0); +INSERT INTO `server_statuseffects` VALUES (223213,'power_surge_II',1058,2,0); +INSERT INTO `server_statuseffects` VALUES (223214,'power_surge_III',1058,2,0); +INSERT INTO `server_statuseffects` VALUES (223215,'life_surge_I',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223216,'life_surge_II',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223217,'life_surge_III',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223218,'dread_spike',16418,2,0); +INSERT INTO `server_statuseffects` VALUES (223221,'raging_strike2',1074855970,1,0); +INSERT INTO `server_statuseffects` VALUES (223227,'cleric_stance',8226,1,0); +INSERT INTO `server_statuseffects` VALUES (223228,'blissful_mind',1073741858,1,1000); +INSERT INTO `server_statuseffects` VALUES (223234,'sanguinerite2',0,1,3000); +INSERT INTO `server_statuseffects` VALUES (223236,'outmaneuver2',524338,2,0); +INSERT INTO `server_statuseffects` VALUES (223237,'blindside2',8226,1,0); +INSERT INTO `server_statuseffects` VALUES (223238,'decoy2',4130,2,0); +INSERT INTO `server_statuseffects` VALUES (223239,'protect2',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223240,'sanguinerite3',0,1,3000); +INSERT INTO `server_statuseffects` VALUES (223241,'bloodletter2',42,2,0); +INSERT INTO `server_statuseffects` VALUES (223242,'fully_blissful_mind',1073741858,1,0); +INSERT INTO `server_statuseffects` VALUES (223243,'magic_evasion_down',50,2,0); +INSERT INTO `server_statuseffects` VALUES (223245,'spinning_heel',50,1,0); +INSERT INTO `server_statuseffects` VALUES (223248,'divine_veil',36914,2,0); +INSERT INTO `server_statuseffects` VALUES (223250,'vengeance',16418,1,5000); +INSERT INTO `server_statuseffects` VALUES (223251,'antagonize',1048626,2,0); +INSERT INTO `server_statuseffects` VALUES (223264,'divine_regen',50,2,0); +INSERT INTO `server_statuseffects` VALUES (228021,'heavy',42,2,0); +INSERT INTO `server_statuseffects` VALUES (253003,'evade_proc',34,1,0); +INSERT INTO `server_statuseffects` VALUES (253004,'block_proc',34,1,0); +INSERT INTO `server_statuseffects` VALUES (253005,'parry_proc',34,1,0); +INSERT INTO `server_statuseffects` VALUES (253006,'miss_proc',34,1,0); +INSERT INTO `server_statuseffects` VALUES (253007,'expchain',34,1,0); /*!40000 ALTER TABLE `server_statuseffects` ENABLE KEYS */; UNLOCK TABLES; commit; @@ -85,4 +124,4 @@ commit; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2018-02-15 0:04:51 +-- Dump completed on 2018-04-18 14:54:11