fixed auto attack messing up cast anim

- fixed auto attack anim for mobs (<3 u ion)
- added hotbar timer updates (<3 u azia)
- fixed actor block bug
- cleaned up substate retardation
- fixed some targetfind issues
- added despawn state
- added messages for in progress commands
- added fields for aoe target, range, battleAnimation to server_battle_commands table
This commit is contained in:
Tahir Akhlaq
2017-08-31 05:56:43 +01:00
parent 4c7928da78
commit c5cc7c2f00
24 changed files with 550 additions and 330 deletions

View File

@@ -20,7 +20,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
this.startTime = DateTime.Now;
owner.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
owner.aiContainer.ChangeTarget(target);
ChangeTarget(target);
attackTime = startTime;
owner.aiContainer.pathFind?.Clear();
// todo: should handle everything here instead of on next tick..
@@ -42,12 +42,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
return true;
}
*/
if (target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget)
owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea(owner.currentLockedTarget == 0xC0000000 ? owner.currentTarget : owner.currentLockedTarget) as Character);
if ((target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget) && owner.isAutoAttackEnabled)
owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea<Character>(owner.currentLockedTarget));
if (target == null || target.IsDead())
{
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER)
if (owner is BattleNpc)
target = ((BattleNpc)owner).hateContainer.GetMostHatedTarget();
}
else
@@ -110,7 +111,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
owner.OnAttack(this, action, ref errorResult);
// handle paralyze/intimidate/sleep/whatever in character thing
owner.DoBattleAction((ushort)BattleActionX01PacketCommand.Attack, 0x19001000, errorResult == null ? action : errorResult);
owner.DoBattleAction((ushort)BattleActionX01PacketCommand.Attack, action.animation, errorResult == null ? action : errorResult);
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
}
@@ -140,11 +141,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
private bool IsAttackReady()
{
return Program.Tick >= attackTime;
// todo: this enforced delay should really be changed if it's not retail..
return Program.Tick >= attackTime && Program.Tick >= owner.aiContainer.GetLastActionTime().AddSeconds(1);
}
private bool CanAttack()
{
if (!owner.isAutoAttackEnabled)
{
return false;
}
if (target == null)
{
return false;
@@ -162,7 +169,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: use a mod for melee range
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > owner.GetAttackRange())
{
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
if (owner is Player)
{
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20);
}

View File

@@ -15,6 +15,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
: base(owner, null)
{
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
owner.Disengage();
canInterrupt = false;
startTime = tick;
despawnTime = startTime.AddSeconds(timeToFadeOut);
@@ -25,7 +26,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: handle raise etc
if (tick >= despawnTime)
{
owner.Spawn(Program.Tick);
if (owner is BattleNpc)
{
owner.Despawn(tick);
}
else
{
// todo: queue a warp for the player
}
return true;
}
return false;

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.send.actor;
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
{
class DespawnState : State
{
private DateTime endTime;
public DespawnState(Character owner, Character target, uint despawnTimeSeconds) :
base(owner, null)
{
startTime = Program.Tick;
endTime = startTime.AddSeconds(despawnTimeSeconds);
}
public override bool Update(DateTime tick)
{
if (tick >= endTime)
{
// todo: send packet to despawn the npc, set it so npc is despawned when requesting spawn packets
owner.zone.BroadcastPacketAroundActor(owner, RemoveActorPacket.BuildPacket(owner.actorId));
owner.QueuePositionUpdate(owner.spawnX, owner.spawnY, owner.spawnZ);
lua.LuaEngine.CallLuaBattleAction(owner, "onDespawn", owner);
return true;
}
return false;
}
}
}

View File

@@ -57,14 +57,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
float spellSpeed = spell.castTimeSeconds;
// command casting duration
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
if (owner is Player)
{
// todo: modify spellSpeed based on modifiers and stuff
((Player)owner).SendStartCastbar(spell.id, Utils.UnixTimeStampUTC(DateTime.Now.AddSeconds(spellSpeed)));
owner.SendChant(0xF, 0x0);
owner.DoBattleAction(spell.id, 0x6F000002, new BattleAction(target.actorId, 30128, 1, 0, 1)); //You begin casting (6F000002: BLM, 6F000003: WHM)
((Player)owner).SendStartCastbar(spell.id, Utils.UnixTimeStampUTC(DateTime.Now.AddSeconds(spellSpeed)));
}
owner.SendChant(0xF, 0x0);
owner.DoBattleAction(spell.id, 0x6F000002, new BattleAction(target.actorId, 30128, 1, 0, 1)); //You begin casting (6F000002: BLM, 6F000003: WHM)
}
}
@@ -106,7 +105,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public override void OnComplete()
{
spell.targetFind.FindWithinArea(target, spell.validTarget);
spell.targetFind.FindWithinArea(target, spell.validTarget, spell.aoeTarget);
isCompleted = true;
var targets = spell.targetFind.GetTargets();
@@ -119,7 +118,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
actions[i++] = action;
}
owner.SendChant(0, 0);
// todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
var errors = (BattleAction[])actions.Clone();
owner.OnCast(this, actions, ref errors);
owner.DoBattleAction(spell.id, spell.battleAnimation, actions);
}
@@ -138,10 +140,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: actually check proc rate/random chance of whatever effect
effectId = list[0].GetStatusEffectId();
}
// todo: which is actually the swing packet
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
//owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
//errorPacket = null;
interrupt = true;
return;
}
@@ -159,7 +157,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
private bool CanCast()
{
return owner.CanCast(target, spell) && !HasMoved();
return owner.CanCast(target, spell) && spell.IsValidTarget(owner, target) && !HasMoved();
}
private bool HasMoved()
@@ -169,13 +167,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public override void Cleanup()
{
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
{
owner.SendChant(0, 0);
if (owner is Player)
{
((Player)owner).SendEndCastbar();
}
// command casting duration
//var packets = new List<SubPacket>();
//owner.zone.BroadcastPacketsAroundActor(owner, packets);
owner.aiContainer.UpdateLastActionTime();
}
public BattleCommand GetSpell()

View File

@@ -90,7 +90,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public override void OnComplete()
{
skill.targetFind.FindWithinArea(target, skill.validTarget);
skill.targetFind.FindWithinArea(target, skill.validTarget, skill.aoeTarget);
isCompleted = true;
var targets = skill.targetFind.GetTargets();
@@ -104,10 +104,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// 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;
//packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, skill.battleAnimation, action.effectId, action.worldMasterTextId, skill.id, action.amount, action.param));
}
// todo: this is fuckin stupid, probably only need *one* error packet, not an error for each action
var errors = (BattleAction[])actions.Clone();
owner.OnWeaponSkill(this, actions, ref errors);
owner.DoBattleAction(skill.id, 0, actions);
}
@@ -126,10 +128,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: actually check proc rate/random chance of whatever effect
effectId = list[0].GetStatusEffectId();
}
// todo: which is actually the swing packet
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
//owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
//errorPacket = null;
interrupt = true;
return;
}
@@ -139,12 +137,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
private bool CanUse()
{
return owner.CanWeaponSkill(target, skill);
return owner.CanWeaponSkill(target, skill) && skill.IsValidTarget(owner, target);
}
public BattleCommand GetWeaponSkill()
{
return skill;
}
public override void Cleanup()
{
owner.aiContainer.UpdateLastActionTime();
}
}
}