From 7ad40f625aaced4a8b832317bba8b1e8e1aadcca Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Mon, 28 Aug 2017 21:45:01 -0400 Subject: [PATCH] Refactored Demo's battle action code and cleaned things up. --- FFXIVClassic Map Server/actors/Actor.cs | 15 ++---- .../actors/chara/Character.cs | 42 ++++++++++++---- .../actors/chara/ai/BattleCommand.cs | 26 ++++++---- .../actors/chara/ai/state/AttackState.cs | 21 +++----- .../actors/chara/ai/state/MagicState.cs | 37 ++++---------- .../actors/chara/ai/state/State.cs | 3 +- .../actors/chara/ai/state/WeaponSkillState.cs | 33 ++++--------- .../actors/chara/ai/utils/BattleUtils.cs | 2 +- .../actors/chara/npc/BattleNpc.cs | 10 ++-- .../actors/chara/player/Player.cs | 41 ++++++++-------- .../packets/send/Actor/battle/BattleAction.cs | 12 ++++- .../Actor/battle/BattleActionX00Packet.cs | 2 +- .../Actor/battle/BattleActionX10Packet.cs | 48 +++++++++++++++++++ .../Actor/battle/BattleActionX18Packet.cs | 47 ++++++++++++++++++ 14 files changed, 217 insertions(+), 122 deletions(-) diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index a1ad8ce7..0508adb8 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -432,8 +432,10 @@ namespace FFXIVClassic_Map_Server.Actors if ((updateFlags & ActorUpdateFlags.State) != 0) { - packets.Add(SetActorStatePacket.BuildPacket(actorId, currentMainState, currentSubState)); - packets.Add(BattleActionX01Packet.BuildPacket(actorId, actorId, actorId, 0x72000062, 1, 0, 0x05209, 0, 0)); + packets.Add(SetActorStatePacket.BuildPacket(actorId, currentMainState, currentSubState)); + + if (this is Character) + packets.Add(BattleActionX00Packet.BuildPacket(actorId, 0x72000062, 0)); } updateFlags = ActorUpdateFlags.None; zone.BroadcastPacketsAroundActor(this, packets); @@ -709,14 +711,7 @@ namespace FFXIVClassic_Map_Server.Actors return FindRandomPoint(positionX, positionY, positionZ, minRadius, maxRadius); } #endregion - - public SubPacket CreateGameMessagePacket(Actor textIdOwner, ushort textId, byte log, params object[] msgParams) - { - if (msgParams == null || msgParams.Length == 0) - return (GameMessagePacket.BuildPacket(Server.GetWorldManager().GetActor().actorId, textIdOwner.actorId, textId, log)); - else - return (GameMessagePacket.BuildPacket(Server.GetWorldManager().GetActor().actorId, textIdOwner.actorId, textId, log, LuaUtils.CreateLuaParamList(msgParams))); - } + } } diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 8862a8f5..260d0b0a 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -179,9 +179,35 @@ namespace FFXIVClassic_Map_Server.Actors zone.BroadcastPacketAroundActor(this, PlayAnimationOnActorPacket.BuildPacket(actorId, animId)); } - public void DoBattleAction(ushort commandId, uint animationId, uint target) + public void DoBattleAction(ushort commandId, uint animationId) { - zone.BroadcastPacketAroundActor(this, BattleActionX00Packet.BuildPacket(actorId, target, animationId, commandId)); + zone.BroadcastPacketAroundActor(this, BattleActionX00Packet.BuildPacket(actorId, animationId, commandId)); + } + + public void DoBattleAction(ushort commandId, uint animationId, BattleAction action) + { + zone.BroadcastPacketAroundActor(this, BattleActionX01Packet.BuildPacket(actorId, animationId, commandId, action)); + } + + public void DoBattleAction(ushort commandId, uint animationId, BattleAction[] actions) + { + int currentIndex = 0; + + while (true) + { + if (actions.Length - currentIndex >= 18) + BattleActionX18Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex); + else if (actions.Length - currentIndex >= 1) + BattleActionX10Packet.BuildPacket(actorId, animationId, commandId, actions, ref currentIndex); + else if (actions.Length - currentIndex == 1) + { + BattleActionX01Packet.BuildPacket(actorId, animationId, commandId, actions[currentIndex]); + currentIndex++; + } + else + break; + animationId = 0; //If more than one packet is sent out, only send the animation once to avoid double playing. + } } public void DoBattleAction(ushort commandId, uint animationId, List actions) @@ -284,7 +310,7 @@ namespace FFXIVClassic_Map_Server.Actors } } - public virtual bool IsValidTarget(Character target, ValidTarget validTarget, ref SubPacket errorPacket) + public virtual bool IsValidTarget(Character target, ValidTarget validTarget) { return true; } @@ -294,17 +320,17 @@ namespace FFXIVClassic_Map_Server.Actors return true; } - public virtual bool CanCast(Character target, BattleCommand spell, ref SubPacket errorPacket) + public virtual bool CanCast(Character target, BattleCommand spell) { return false; } - public virtual bool CanWeaponSkill(Character target, BattleCommand skill, ref SubPacket errorPacket) + public virtual bool CanWeaponSkill(Character target, BattleCommand skill) { return false; } - public virtual bool CanUseAbility(Character target, BattleCommand ability, ref SubPacket errorPacket) + public virtual bool CanUseAbility(Character target, BattleCommand ability) { return false; } @@ -500,14 +526,14 @@ namespace FFXIVClassic_Map_Server.Actors return moveSpeeds[2] + GetMod((uint)Modifier.Speed); } - public virtual void OnAttack(State state, BattleAction action, ref SubPacket errorPacket) + public virtual void OnAttack(State state, BattleAction action, ref BattleAction error) { // todo: change animation based on equipped weapon action.effectId |= (uint)HitEffect.HitVisual1; // melee var target = state.GetTarget(); // todo: get hitrate and shit, handle protect effect and whatever - if (BattleUtils.TryAttack(this, target, action, ref errorPacket)) + if (BattleUtils.TryAttack(this, target, action, ref error)) { action.amount = BattleUtils.CalculateAttackDamage(this, target, action); //var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1); diff --git a/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs b/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs index 800c48f9..e215a952 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/BattleCommand.cs @@ -97,7 +97,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai return castTimeSeconds == 0; } - public bool IsValidTarget(Character user, Character target, ref SubPacket errorPacket) + public bool IsValidTarget(Character user, Character target) { // todo: set box length.. targetFind = new TargetFind(user); @@ -129,18 +129,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if ((validTarget & (ValidTarget.Corpse | ValidTarget.CorpseOnly)) == 0 && target.IsDead()) { // cannot be perfomed on - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32512, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32512, 0x20, (uint)id); return false; } if (level > user.charaWork.parameterSave.state_mainSkillLevel) { - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32527, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32527, 0x20, (uint)id); return false; } if (tpCost > user.GetTP()) { - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32546, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32546, 0x20, (uint)id); return false; } @@ -149,7 +152,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (BattleUtils.CalculateSpellCost(user, target, this) > user.GetMP()) { // todo: error message - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32545, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32545, 0x20, (uint)id); return false; } @@ -159,7 +163,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai if (false) { // Unable to execute [@SHEET(xtx/command,$E8(1),2)]. Conditions for use are not met. - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32556, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32556, 0x20, (uint)id); return false; } } @@ -169,7 +174,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { if (target != null && target.IsAlive()) { - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32513, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32513, 0x20, (uint)id); return false; } } @@ -180,7 +186,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai target.currentSubState != (user.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER ? SetActorStatePacket.SUB_STATE_PLAYER : SetActorStatePacket.SUB_STATE_MONSTER)) { - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32519, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32519, 0x20, (uint)id); return false; } } @@ -189,7 +196,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai { if (target == null || target.currentSubState != user.currentSubState ) { - errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32516, 0x20, (uint)id); + if (user is Player) + ((Player)user).SendGameMessage(Server.GetWorldManager().GetActor(), 32516, 0x20, (uint)id); return false; } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs index 25267f68..53bb1c8b 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs @@ -87,15 +87,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state public override void OnComplete() { // todo: possible underflow - BattleAction action = new BattleAction(); - errorPacket = null; + BattleAction action = new BattleAction(target.actorId, 0x765D, (uint) HitEffect.Hit, 0, (byte) HitDirection.None); + errorResult = null; //var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1); - action.animation = 0x19001000; - action.targetId = target.actorId; - action.effectId = (uint)HitEffect.Hit; - action.worldMasterTextId = 0x765D; - action.param = (byte)HitDirection.None; // HitDirection (auto attack shouldnt need this afaik) + + // HitDirection (auto attack shouldnt need this afaik) // todo: implement auto attack damage bonus in Character.OnAttack /* @@ -111,14 +108,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state * The above damage bonus also applies to “Shot” attacks by archers. */ - owner.OnAttack(this, action, ref errorPacket); + owner.OnAttack(this, action, ref errorResult); // handle paralyze/intimidate/sleep/whatever in character thing - if (errorPacket == null) - owner.zone.BroadcastPacketAroundActor(owner, BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, action.targetId, action.animation, - 0x8000000 | action.effectId, action.worldMasterTextId, (ushort)BattleActionX01PacketCommand.Attack, action.amount, action.param) - ); - else - owner.zone.BroadcastPacketAroundActor(owner, errorPacket); + owner.DoBattleAction((ushort)BattleActionX01PacketCommand.Attack, 0x19001000, errorResult != null ? action : errorResult); + //this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0); } diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs index 5409f089..86127af8 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/MagicState.cs @@ -28,22 +28,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicPrepare", owner, target, spell); // todo: check recast - if (returnCode == 0 && owner.CanCast(target, spell, ref errorPacket)) + if (returnCode == 0 && owner.CanCast(target, spell)) { // todo: Azia can fix, check the recast time and send error OnStart(); } else - { - if (owner is Player) - { - // "Your battle command fails to activate" - if (errorPacket == null) - errorPacket = owner.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), (ushort)(returnCode == -1 ? 32410 : returnCode), 0x20, owner.actorId); - - ((Player)owner).QueuePacket(errorPacket); - } - errorPacket = null; + { + errorResult = null; interrupt = true; } } @@ -55,7 +47,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state if (returnCode != 0) { interrupt = true; - errorPacket = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, owner.actorId, 0, 0, (ushort)(returnCode == -1 ? 32558 : returnCode), spell.id, 0, 1); + errorResult = new BattleAction(target.actorId, (ushort)(returnCode == -1 ? 32558 : returnCode), 0, 0, 0, 1); } else { @@ -106,9 +98,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state public override void OnInterrupt() { // todo: send paralyzed/sleep message etc. - if (errorPacket != null) + if (errorResult != null) { - owner.zone.BroadcastPacketAroundActor(owner, errorPacket); + //owner.zone.BroadcastPacketAroundActor(owner, errorResult); } } @@ -123,23 +115,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state var i = 0; foreach (var chara in targets) { - var action = new BattleAction(); - action.effectId = spell.effectAnimation; - action.param = (byte)HitDirection.None; // HitDirection (magic shouldnt need this afaik) - action.unknown = 1; - action.targetId = chara.actorId; - action.worldMasterTextId = spell.worldMasterTextId; - action.animation = spell.battleAnimation; + var action = new BattleAction(target.actorId, spell.worldMasterTextId, spell.effectAnimation, 0, (byte) HitDirection.None, 1); action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicFinish", owner, chara, spell, action); actions[i++] = action; //packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, spell.battleAnimation, action.effectId, action.worldMasterTextId, spell.id, action.amount, action.param)); } - owner.zone.BroadcastPacketAroundActor(owner, - spell.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.actorId, owner.actorId, actions[0].animation, spell.id, actions)) : - BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, spell.battleAnimation, actions[0].effectId, actions[0].worldMasterTextId, spell.id, actions[0].amount, actions[0].param) - ); - //owner.zone.BroadcastPacketsAroundActor(owner, packets); + + owner.DoBattleAction(spell.id, spell.effectAnimation, actions); } public override void TryInterrupt() @@ -170,7 +153,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state private bool CanCast() { - return owner.CanCast(target, spell, ref errorPacket) && !HasMoved(); + return owner.CanCast(target, spell) && !HasMoved(); } private bool HasMoved() diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/State.cs b/FFXIVClassic Map Server/actors/chara/ai/state/State.cs index e050d1ee..d37a2195 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/State.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/State.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using FFXIVClassic_Map_Server.Actors; using FFXIVClassic.Common; +using FFXIVClassic_Map_Server.packets.send.actor.battle; namespace FFXIVClassic_Map_Server.actors.chara.ai.state { @@ -18,7 +19,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state protected DateTime startTime; - protected SubPacket errorPacket; + protected BattleAction errorResult; protected bool isCompleted; diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs index b8bca65f..1b4857e7 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/WeaponSkillState.cs @@ -25,22 +25,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillPrepare", owner, target, skill); // todo: check recast - if (returnCode == 0 && owner.CanWeaponSkill(target, skill, ref errorPacket)) + if (returnCode == 0 && owner.CanWeaponSkill(target, skill)) { // todo: Azia can fix, check the recast time and send error OnStart(); } else { - if (owner is Player) - { - // "Your battle command fails to activate" - if (errorPacket == null) - errorPacket = owner.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), (ushort)(returnCode == -1 ? 32410 : returnCode), 0x20, owner.actorId, owner.actorId, owner.actorId, owner.actorId); - - ((Player)owner).QueuePacket(errorPacket); - } - errorPacket = null; + errorResult = null; interrupt = true; } } @@ -52,7 +44,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state if (returnCode != 0) { interrupt = true; - errorPacket = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, owner.actorId, 0, 0, (ushort)(returnCode == -1 ? 32558 : returnCode), skill.id, 0, 1); + errorResult = new BattleAction(owner.actorId, (ushort)(returnCode == -1 ? 32558 : returnCode), 0); } else { @@ -89,9 +81,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state public override void OnInterrupt() { // todo: send paralyzed/sleep message etc. - if (errorPacket != null) + if (errorResult != null) { - owner.zone.BroadcastPacketAroundActor(owner, errorPacket); + owner.DoBattleAction(skill.id, 0, errorResult); } } @@ -107,13 +99,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state var i = 0; foreach (var chara in targets) { - var action = new BattleAction(); - action.effectId = (uint)HitEffect.Hit; - action.param = 1; // HitDirection - action.unknown = 1; - action.targetId = chara.actorId; - action.worldMasterTextId = skill.worldMasterTextId; - action.animation = skill.battleAnimation; + var action = new BattleAction(chara.actorId, skill.worldMasterTextId, (uint)HitEffect.Hit, 0, 1, 1); // evasion, miss, dodge, etc to be handled in script, calling helpers from scripts/weaponskills.lua action.amount = (ushort)lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillFinish", owner, target, skill, action); actions[i++] = action; @@ -121,10 +107,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state //packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, skill.battleAnimation, action.effectId, action.worldMasterTextId, skill.id, action.amount, action.param)); } - owner.zone.BroadcastPacketAroundActor(owner, - skill.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.target.actorId, owner.actorId, actions[0].animation, skill.id, actions)) : - BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, skill.battleAnimation, actions[0].effectId, actions[0].worldMasterTextId, skill.id, actions[0].amount, actions[0].param) - ); + owner.DoBattleAction(skill.id, 0, actions); } public override void TryInterrupt() @@ -155,7 +138,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state private bool CanUse() { - return owner.CanWeaponSkill(target, skill, ref errorPacket); + return owner.CanWeaponSkill(target, skill); } public BattleCommand GetWeaponSkill() diff --git a/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs b/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs index a5b5f09c..a1529246 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/utils/BattleUtils.cs @@ -13,7 +13,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils { static class BattleUtils { - public static bool TryAttack(Character attacker, Character defender, BattleAction action, ref SubPacket errorPacket) + public static bool TryAttack(Character attacker, Character defender, BattleAction action, ref BattleAction error) { // todo: get hit rate, hit count, set hit effect action.effectId |= (uint)(HitEffect.RecoilLv2 | HitEffect.Hit | HitEffect.HitVisual1); diff --git a/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs b/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs index 7b1d375a..acf9cc2c 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/BattleNpc.cs @@ -107,19 +107,19 @@ namespace FFXIVClassic_Map_Server.Actors return true; } - public override bool CanCast(Character target, BattleCommand spell, ref SubPacket errorPacket) + public override bool CanCast(Character target, BattleCommand spell) { // todo: return false; } - public override bool CanWeaponSkill(Character target, BattleCommand skill, ref SubPacket errorPacket) + public override bool CanWeaponSkill(Character target, BattleCommand skill) { // todo: return false; } - public override bool CanUseAbility(Character target, BattleCommand ability, ref SubPacket errorPacket) + public override bool CanUseAbility(Character target, BattleCommand ability) { // todo: return false; @@ -204,9 +204,9 @@ namespace FFXIVClassic_Map_Server.Actors return this.isAtSpawn = Utils.DistanceSquared(positionX, positionY, positionZ, spawnX, spawnY, spawnZ) <= 2500.0f; } - public override void OnAttack(State state, BattleAction action, ref SubPacket errorPacket) + public override void OnAttack(State state, BattleAction action, ref BattleAction error) { - base.OnAttack(state, action, ref errorPacket); + base.OnAttack(state, action, ref error); } } } diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index f40c112f..4c7f9306 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -1956,18 +1956,19 @@ namespace FFXIVClassic_Map_Server.Actors return firstSlot; } + /* public void SendBattleActionX01Packet(uint anim, uint effect, uint text = 0x756D, uint command = 27260, uint param = 0x01, uint idek = 0x01) { var packet = BattleActionX01Packet.BuildPacket(actorId, actorId, currentTarget != 0xC0000000 ? currentTarget : currentLockedTarget, (uint)anim, (uint)effect, (ushort)text, (ushort)command, (ushort)param, (byte)idek); QueuePacket(packet); - } + }*/ - public override bool IsValidTarget(Character target, ValidTarget validTarget, ref SubPacket errorPacket) + public override bool IsValidTarget(Character target, ValidTarget validTarget) { if (target == null) { // Target does not exist. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32511, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32511, 0x20); return false; } @@ -1977,21 +1978,21 @@ namespace FFXIVClassic_Map_Server.Actors if (target.currentSubState == SetActorStatePacket.SUB_STATE_NONE) { // That command cannot be performed on the current target. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32547, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32547, 0x20); return false; } if (currentParty != null && target.currentParty == currentParty) { // That command cannot be performed on a party member. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32548, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32548, 0x20); return false; } // todo: pvp? if (target.currentSubState == currentSubState) { // That command cannot be performed on an ally. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32549, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32549, 0x20); return false; } } @@ -1999,7 +2000,7 @@ namespace FFXIVClassic_Map_Server.Actors if ((validTarget & ValidTarget.Ally) != 0 && target.currentSubState != currentSubState) { // That command cannot be performed on the current target. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32547, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32547, 0x20); return false; } @@ -2011,29 +2012,29 @@ namespace FFXIVClassic_Map_Server.Actors if (target is Player && ((Player)target).playerSession.isUpdatesLocked) { // That command cannot be performed on the current target. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32547, 0x20); + SendGameMessage(Server.GetWorldManager().GetActor(), 32547, 0x20); return false; } return true; } - public override bool CanCast(Character target, BattleCommand spell, ref SubPacket errorPacket) + public override bool CanCast(Character target, BattleCommand spell) { // todo: move the ability specific stuff to ability.cs if (target == null) { // Target does not exist. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32511, 0x20, (uint)spell.id); + SendGameMessage(Server.GetWorldManager().GetActor(), 32511, 0x20, (uint)spell.id); return false; } if (Utils.Distance(positionX, positionY, positionZ, target.positionX, target.positionY, target.positionZ) > spell.range) { // The target is out of range. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32539, 0x20, spell.id); + SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20, spell.id); return false; } - if (!IsValidTarget(target, spell.validTarget, ref errorPacket) || !spell.IsValidTarget(this, target, ref errorPacket)) + if (!IsValidTarget(target, spell.validTarget) || !spell.IsValidTarget(this, target)) { // error packet is set in IsValidTarget return false; @@ -2041,22 +2042,22 @@ namespace FFXIVClassic_Map_Server.Actors return true; } - public override bool CanWeaponSkill(Character target, BattleCommand skill, ref SubPacket errorPacket) + public override bool CanWeaponSkill(Character target, BattleCommand skill) { // todo: see worldmaster ids 32558~32557 for proper ko message and stuff if (target == null) { // Target does not exist. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32511, 0x20, (uint)skill.id); + SendGameMessage(Server.GetWorldManager().GetActor(), 32511, 0x20, (uint)skill.id); return false; } if (Utils.Distance(positionX, positionY, positionZ, target.positionX, target.positionY, target.positionZ) > skill.range) { // The target is out of range. - errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32539, 0x20, (uint)skill.id); + SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20, (uint)skill.id); return false; } - if (!IsValidTarget(target, skill.validTarget, ref errorPacket) || !skill.IsValidTarget(this, target, ref errorPacket)) + if (!IsValidTarget(target, skill.validTarget) || !skill.IsValidTarget(this, target)) { // error packet is set in IsValidTarget return false; @@ -2064,14 +2065,14 @@ namespace FFXIVClassic_Map_Server.Actors return true; } - public override void OnAttack(State state, BattleAction action, ref SubPacket errorPacket) + public override void OnAttack(State state, BattleAction action, ref BattleAction error) { - base.OnAttack(state, action, ref errorPacket); + base.OnAttack(state, action, ref error); - if (errorPacket == null) + if (error == null) { // melee attack animation - action.animation = 0x19001000; + //action.animation = 0x19001000; } var target = state.GetTarget(); //if (target is BattleNpc) diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs index 6973b0bc..5ee1523e 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleAction.cs @@ -109,6 +109,16 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle /// /// this field is not actually part of the packet struct /// - public uint animation; + //public uint animation; + + public BattleAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte unknown = 0) + { + this.targetId = targetId; + this.worldMasterTextId = worldMasterTextId; + this.effectId = effectId; + this.amount = amount; + this.param = param; + this.unknown = unknown; + } } } diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX00Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX00Packet.cs index bdd72f26..9021894a 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX00Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX00Packet.cs @@ -9,7 +9,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle public const ushort OPCODE = 0x013C; public const uint PACKET_SIZE = 0x48; - public static SubPacket BuildPacket(uint sourceActorId, uint targetActorId, uint animationId, ushort commandId) + public static SubPacket BuildPacket(uint sourceActorId, uint animationId, ushort commandId) { byte[] data = new byte[PACKET_SIZE - 0x20]; diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs index ba222166..0c6323c0 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX10Packet.cs @@ -10,6 +10,53 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle { public const ushort OPCODE = 0x013A; public const uint PACKET_SIZE = 0xD8; + + public static SubPacket BuildPacket(uint sourceActorId, uint animationId, ushort commandId, BattleAction[] actionList, ref int currentIndex) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + binWriter.Write((UInt32)sourceActorId); + binWriter.Write((UInt32)animationId); + + //Missing... last value is float, string in here as well? + + binWriter.Seek(0x20, SeekOrigin.Begin); + binWriter.Write((UInt32)actionList.Length); //Num actions (always 1 for this) + binWriter.Write((UInt16)commandId); + binWriter.Write((UInt16)0x810); //? + + //binWriter.Seek(0x20, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt32)action.targetId); + + binWriter.Seek(0x50, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt16)action.amount); + + binWriter.Seek(0x64, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt16)action.worldMasterTextId); + + binWriter.Seek(0x78, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt32)action.effectId); + + binWriter.Seek(0xA0, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((Byte)action.param); + + binWriter.Seek(0xAA, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((Byte)action.unknown); + } + } + + return new SubPacket(OPCODE, sourceActorId, data); + } public static SubPacket BuildPacket(uint sourceActorId, uint animationId, ushort commandId, List actionList, ref int currentIndex) { @@ -57,5 +104,6 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle return new SubPacket(OPCODE, sourceActorId, data); } + } } diff --git a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs index 4a1d58c5..cf49f3dd 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/battle/BattleActionX18Packet.cs @@ -11,6 +11,53 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle public const ushort OPCODE = 0x013B; public const uint PACKET_SIZE = 0x148; + public static SubPacket BuildPacket(uint sourceActorId, uint animationId, ushort commandId, BattleAction[] actionList, ref int currentIndex) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + binWriter.Write((UInt32)sourceActorId); + binWriter.Write((UInt32)animationId); + + //Missing... last value is float, string in here as well? + + binWriter.Seek(0x20, SeekOrigin.Begin); + binWriter.Write((UInt32)actionList.Length); //Num actions (always 1 for this) + binWriter.Write((UInt16)commandId); + binWriter.Write((UInt16)0x810); //? + + binWriter.Seek(0x58, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt32)action.targetId); + + binWriter.Seek(0xA0, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt16)action.amount); + + binWriter.Seek(0xC4, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt16)action.worldMasterTextId); + + binWriter.Seek(0xE8, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((UInt32)action.effectId); + + binWriter.Seek(0x130, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((Byte)action.param); + + binWriter.Seek(0x142, SeekOrigin.Begin); + foreach (BattleAction action in actionList) + binWriter.Write((Byte)action.unknown); + } + } + + return new SubPacket(OPCODE, sourceActorId, data); + } + public static SubPacket BuildPacket(uint sourceActorId, uint animationId, ushort commandId, List actionList, ref int currentIndex) { byte[] data = new byte[PACKET_SIZE - 0x20];