1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-24 13:47:46 +00:00

fixed cast interrupt

- dont allow targeting of mob moving back to spawn
This commit is contained in:
Tahir Akhlaq 2017-08-30 00:14:14 +01:00
parent 2cee5ff573
commit 517bdc0638
17 changed files with 114 additions and 112 deletions

View file

@ -51,9 +51,19 @@ namespace FFXIVClassic.Common
return new Vector3(scalar * rhs.X, scalar * rhs.Y, scalar * rhs.Z);
}
public static Vector3 operator /(Vector3 lhs, Vector3 rhs)
public static Vector3 operator /(Vector3 lhs, float scalar)
{
return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
return new Vector3(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar);
}
public static bool operator !=(Vector3 lhs, Vector3 rhs)
{
return !(lhs?.X == rhs?.X && lhs?.Y == rhs?.Y && lhs?.Z == rhs?.Z);
}
public static bool operator ==(Vector3 lhs, Vector3 rhs)
{
return (lhs?.X == rhs?.X && lhs?.Y == rhs?.Y && lhs?.Z == rhs?.Z);
}
public float Length()
@ -78,7 +88,8 @@ namespace FFXIVClassic.Common
public static float GetAngle(float x, float z, float x2, float z2)
{
return (float)(Math.Atan2((z2 - z), (x2 - x)));
var angle = (float)(Math.Atan((z2 - z) / (x2 - x)));
return (float)(x > x2 ? angle + Math.PI : angle);
}
public Vector3 NewHorizontalVector(float angle, float extents)

View file

@ -2169,12 +2169,12 @@ namespace FFXIVClassic_Map_Server
battleCommand.job = reader.GetByte("classJob");
battleCommand.level = reader.GetByte("lvl");
battleCommand.requirements = (AbilityRequirements)reader.GetUInt16("requirements");
battleCommand.requirements = (BattleCommandRequirements)reader.GetUInt16("requirements");
battleCommand.validTarget = (ValidTarget)reader.GetByte("validTarget");
battleCommand.aoeType = (TargetFindAOEType)reader.GetByte("aoeType");
battleCommand.numHits = reader.GetByte("numHits");
battleCommand.positionBonus = (AbilityPositionBonus)reader.GetByte("positionBonus");
battleCommand.procRequirement = (AbilityProcRequirement)reader.GetByte("procRequirement");
battleCommand.positionBonus = (BattleCommandPositionBonus)reader.GetByte("positionBonus");
battleCommand.procRequirement = (BattleCommandProcRequirement)reader.GetByte("procRequirement");
battleCommand.range = reader.GetInt32("range");
battleCommand.debuffDurationSeconds = reader.GetUInt32("debuffDuration");
battleCommand.buffDurationSeconds = reader.GetUInt32("buffDuration");

View file

@ -403,7 +403,6 @@ namespace FFXIVClassic_Map_Server.Actors
{
// push latest for player
var pos = positionUpdates[currentSubState == SetActorStatePacket.SUB_STATE_PLAYER ? positionUpdates.Count - 1 : 0];
oldPositionX = positionX;
oldPositionY = positionY;
oldPositionZ = positionZ;
@ -413,6 +412,8 @@ namespace FFXIVClassic_Map_Server.Actors
positionY = pos.Y;
positionZ = pos.Z;
zone.UpdateActorPosition(this);
//Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates)
positionUpdates.Remove(pos);
@ -433,10 +434,8 @@ namespace FFXIVClassic_Map_Server.Actors
if ((updateFlags & ActorUpdateFlags.State) != 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);
}
@ -654,7 +653,7 @@ namespace FFXIVClassic_Map_Server.Actors
public bool IsFacing(float x, float z, float angle = 40.0f)
{
angle = (float)(Math.PI * angle / 180);
return Vector3.GetAngle(positionX, positionZ, x, z) < angle;
return Math.Abs(Vector3.GetAngle(positionX, positionZ, x, z) - rotation) < angle;
}
// todo: is this legit?

View file

@ -297,10 +297,16 @@ namespace FFXIVClassic_Map_Server.Actors
packets.Add(new SetActorAppearancePacket(modelId, appearanceIds).BuildPacket(actorId));
}
if ((updateFlags & ActorUpdateFlags.State) != 0)
{
packets.Add(BattleActionX00Packet.BuildPacket(actorId, 0x72000062, 0));
}
// todo: should probably add another flag for battleTemp since all this uses reflection
if ((updateFlags & ActorUpdateFlags.HpTpMp) != 0)
{
var propPacketUtil = new ActorPropertyPacketUtil("charaWork.parameterSave", this);
propPacketUtil.AddProperty("charaWork.parameterSave.mp");
propPacketUtil.AddProperty("charaWork.parameterSave.mpMax");
propPacketUtil.AddProperty("charaWork.parameterTemp.tp");

View file

@ -113,7 +113,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public bool CanChangeState()
{
return GetCurrentState() == null || states.Peek().CanInterrupt();
return GetCurrentState() == null || states.Peek().CanChangeState();
}
public void ChangeTarget(Character target)
@ -294,32 +294,41 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
owner.updateFlags |= ActorUpdateFlags.HpTpMp;
// todo: use the update flags
owner.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
ChangeTarget(null);
ClearStates();
}
public void InternalAbility(Character target, uint abilityId)
{
if (CanChangeState())
{
}
}
public void InternalCast(Character target, uint spellId)
{
if (CanChangeState())
{
ChangeState(new MagicState(owner, target, (ushort)spellId));
}
}
public void InternalWeaponSkill(Character target, uint weaponSkillId)
{
if (CanChangeState())
{
ChangeState(new WeaponSkillState(owner, target, (ushort)weaponSkillId));
}
}
public void InternalMobSkill(Character target, uint mobSkillId)
{
if (CanChangeState())
{
}
}
public void InternalDie(DateTime tick, uint timeToFadeout)
{

View file

@ -12,7 +12,7 @@ using FFXIVClassic_Map_Server.actors.chara.ai.utils;
namespace FFXIVClassic_Map_Server.actors.chara.ai
{
public enum AbilityRequirements : ushort
public enum BattleCommandRequirements : ushort
{
None,
DiscipleOfWar = 0x01,
@ -27,7 +27,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
Conjury = 0x200
}
public enum AbilityPositionBonus : byte
public enum BattleCommandPositionBonus : byte
{
None,
Front = 0x01,
@ -35,7 +35,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
Flank = 0x04
}
public enum AbilityProcRequirement : byte
public enum BattleCommandProcRequirement : byte
{
None,
Evade = 0x01,
@ -50,12 +50,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
public string name;
public byte job;
public byte level;
public AbilityRequirements requirements;
public BattleCommandRequirements requirements;
public ValidTarget validTarget;
public TargetFindAOEType aoeType;
public byte numHits;
public AbilityPositionBonus positionBonus;
public AbilityProcRequirement procRequirement;
public BattleCommandPositionBonus positionBonus;
public BattleCommandProcRequirement procRequirement;
public int range;
public uint debuffDurationSeconds;
public uint buffDurationSeconds;
@ -158,7 +158,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
}
// todo: check target requirements
if (requirements != AbilityRequirements.None)
if (requirements != BattleCommandRequirements.None)
{
if (false)
{

View file

@ -248,8 +248,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private bool IsWithinCone(Character target, bool withPet)
{
// todo:
return false;
// todo: make this actual cone
return owner.IsFacing(target, angle) && Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) < extents;
}
private void AddTarget(Character target, bool withPet)

View file

@ -76,17 +76,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
// todo: too far, path to player if mob, message if player
// owner.ResetMoveSpeeds();
owner.moveState = 2;
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER && owner.GetSpeed() != 0)
{
// todo: actual stat based range
if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > 10)
{
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
owner.aiContainer.pathFind.PathInRange(target.positionX, target.positionY, target.positionZ, 1.5f, owner.GetAttackRange());
ChangeTarget(target);
return false;
}
}
lastActionTime = DateTime.Now;
// todo: adjust cooldowns with modifiers
}
@ -165,14 +154,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
// todo:
waitTime = tick.AddSeconds(10);
owner.OnRoam(tick);
}
if (tick >= lastRoamUpdate && !owner.aiContainer.pathFind.IsFollowingPath())
if (!owner.aiContainer.pathFind.IsFollowingPath())
{
// will move on next tick
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
owner.aiContainer.pathFind.PathInRange(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 20.0f);
}
}
if (tick >= neutralTime)
@ -181,10 +170,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{
if (!owner.isMovingToSpawn && owner.aiContainer.pathFind.AtPoint() && owner.aggroType != AggroType.None)
{
uint levelDifference = (uint)Math.Abs(owner.charaWork.parameterSave.state_mainSkillLevel - ((Player)player).charaWork.parameterSave.state_mainSkillLevel);
uint levelDifference = (uint)Math.Abs(owner.charaWork.parameterSave.state_mainSkillLevel - player.charaWork.parameterSave.state_mainSkillLevel);
if (levelDifference < 10 || (owner.aggroType & AggroType.IgnoreLevelDifference) != 0 && ((BattleNpcController)owner.aiContainer.GetController()).CanAggroTarget((Player)player))
owner.hateContainer.AddBaseHate((Player)player);
if (levelDifference <= 10 || (owner.aggroType & AggroType.IgnoreLevelDifference) != 0 && CanAggroTarget(player))
{
owner.hateContainer.AddBaseHate(player);
break;
}
}
}
}
@ -246,13 +238,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
continue;
float mobDistance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, chara.positionX, chara.positionY, chara.positionZ);
if (mobDistance < 0.70f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
if (mobDistance < 0.50f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
{
owner.aiContainer.pathFind.PathInRange(targetPos, 1.3f, 1.8f);
owner.aiContainer.pathFind.PathInRange(targetPos, 1.3f, chara.GetAttackRange());
break;
}
}
}
FaceTarget();
}
}
}
@ -281,6 +274,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{
return false;
}
if (owner.GetSpeed() == 0)
{
return false;
}
return true;
}
@ -339,12 +336,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
hasInvisible = hasSneak;
}
if (detectSight && !hasInvisible && isFacing)
return CanSeePoint(target.positionX, target.positionY, target.positionZ);
if ((owner.aggroType & AggroType.LowHp) != 0 && target.GetHPP() < 75)
return CanSeePoint(target.positionX, target.positionY, target.positionZ);
if (detectSight && !hasInvisible && isFacing)
return CanSeePoint(target.positionX, target.positionY, target.positionZ);
return false;
}

View file

@ -16,7 +16,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
public AttackState(Character owner, Character target) :
base(owner, target)
{
this.canInterrupt = true;
this.canInterrupt = false;
this.startTime = DateTime.Now;
owner.ChangeState(SetActorStatePacket.MAIN_STATE_ACTIVE);
@ -43,12 +43,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
}
*/
if (target == null || owner.target != target || owner.target?.actorId != owner.currentLockedTarget)
owner.aiContainer.ChangeTarget(target = Server.GetWorldManager().GetActorInWorld(owner.currentLockedTarget == 0xC0000000 ? owner.currentTarget : owner.currentLockedTarget) as Character);
owner.aiContainer.ChangeTarget(target = owner.zone.FindActorInArea(owner.currentLockedTarget == 0xC0000000 ? owner.currentTarget : owner.currentLockedTarget) as Character);
if (target == null || target.IsDead())
{
//if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER)
// target = ((BattleNpc)owner).hateContainer.GetMostHatedTarget();
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_MONSTER)
target = ((BattleNpc)owner).hateContainer.GetMostHatedTarget();
}
else
{

View file

@ -35,7 +35,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
}
else
{
errorResult = null;
errorResult = new BattleAction(owner.actorId, 32553, 0);
interrupt = true;
}
}
@ -47,7 +47,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
if (returnCode != 0)
{
interrupt = true;
errorResult = new BattleAction(target.actorId, (ushort)(returnCode == -1 ? 32558 : returnCode), 0, 0, 0, 1);
errorResult = new BattleAction(target.actorId, (ushort)(returnCode == -1 ? 32553 : returnCode), 0, 0, 0, 1);
}
else
{
@ -97,9 +97,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: send paralyzed/sleep message etc.
if (errorResult != null)
{
//owner.zone.BroadcastPacketAroundActor(owner, errorResult);
owner.DoBattleAction(spell.id, errorResult.animation, errorResult);
errorResult = null;
}
owner.DoBattleAction(spell.id, 0x7F000002, new BattleAction(target.actorId, 0, 1, 0, 1));
}
public override void OnComplete()
@ -109,7 +109,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
var targets = spell.targetFind.GetTargets();
BattleAction[] actions = new BattleAction[targets.Count];
List<SubPacket> packets = new List<SubPacket>();
var i = 0;
foreach (var chara in targets)
{
@ -144,6 +143,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
return;
}
if (HasMoved())
{
errorResult = new BattleAction(owner.actorId, 30211, 0);
errorResult.animation = 0x7F000002;
interrupt = true;
return;
}
interrupt = !CanCast();
}
@ -154,7 +161,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
private bool HasMoved()
{
return (Utils.DistanceSquared(owner.GetPosAsVector3(), startPos) > 4.0f);
return (owner.GetPosAsVector3() != startPos);
}
public override void Cleanup()

View file

@ -83,7 +83,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
// todo: send paralyzed/sleep message etc.
if (errorResult != null)
{
owner.DoBattleAction(skill.id, 0, errorResult);
owner.DoBattleAction(skill.id, errorResult.animation, errorResult);
errorResult = null;
}
}

View file

@ -1971,6 +1971,13 @@ namespace FFXIVClassic_Map_Server.Actors
return false;
}
if (target.isMovingToSpawn)
{
// That command cannot be performed on the current target.
SendGameMessage(Server.GetWorldManager().GetActor(), 32547, 0x20);
return false;
}
// enemy only
if ((validTarget & ValidTarget.Enemy) != 0)
{
@ -1980,7 +1987,6 @@ namespace FFXIVClassic_Map_Server.Actors
SendGameMessage(Server.GetWorldManager().GetActor(), 32547, 0x20);
return false;
}
if (currentParty != null && target.currentParty == currentParty)
{
// That command cannot be performed on a party member.
@ -2030,7 +2036,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (Utils.Distance(positionX, positionY, positionZ, target.positionX, target.positionY, target.positionZ) > spell.range)
{
// The target is out of range.
SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20, spell.id);
SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20, (uint)spell.id);
return false;
}
if (!IsValidTarget(target, spell.validTarget) || !spell.IsValidTarget(this, target))

View file

@ -112,7 +112,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
/// <summary>
/// this field is not actually part of the packet struct
/// </summary>
//public uint animation;
public uint animation;
public BattleAction(uint targetId, ushort worldMasterTextId, uint effectId, ushort amount = 0, byte param = 0, byte unknown = 0)
{

View file

@ -22,14 +22,6 @@ function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, ta
return;
end
--Does the target exist
target = player:getZone():FindActorInArea(targetActor);
if (target == nil) then
player:SendGameMessage(GetWorldMaster(), 30203, 0x20);
player:endEvent();
return;
end
player.Ability(command.actorId, targetActor);
player:endEvent();

View file

@ -19,5 +19,4 @@ function onEventStarted(player, command, triggerName)
end
player:endEvent();
sendSignal("playerActive");
end
end;

View file

@ -14,23 +14,6 @@ local attackMagicHandlers = {
}
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
print(command.actorId)
--Are they in active mode?
if (player:GetState() != 2) then
player:SendGameMessage(GetWorldMaster(), 32503, 0x20);
player:endEvent();
return;
end
--Does the target exist
target = player:getZone():FindActorInArea(targetActor);
if (target == nil) then
player:SendGameMessage(GetWorldMaster(), 30203, 0x20);
player:endEvent();
return;
end
player.Cast(command.actorId, targetActor);
player:endEvent();
end
end;

View file

@ -18,18 +18,9 @@ function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, ta
return;
end
--Does the target exist
target = player:getZone():FindActorInArea(targetActor);
if (target == nil) then
player:SendGameMessage(GetWorldMaster(), 30203, 0x20);
player:endEvent();
return;
end
if not player.aiContainer.IsEngaged() then
player.Engage(targetActor);
end;
player.WeaponSkill(command.actorId, targetActor);
player:endEvent();
end
end;