mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-08-02 15:51:53 +02:00
renamed tables for consistency
- added magic.lua (todo: enumerate modifiers and stuff) - moved aggro handling to session position update - some cleanup
This commit is contained in:
parent
6c74222b68
commit
f4016e1a12
25 changed files with 539 additions and 442 deletions
|
@ -613,21 +613,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
return zoneId;
|
||||
}
|
||||
|
||||
// todo: do this properly
|
||||
public bool IsFacing(float x, float z)
|
||||
{
|
||||
var rot1 = this.rotation;
|
||||
|
||||
var dX = this.positionX - x;
|
||||
var dY = this.positionZ - z;
|
||||
|
||||
var rot2 = Math.Atan2(dY, dX);
|
||||
|
||||
var dRot = Math.PI - rot2 + Math.PI / 2;
|
||||
|
||||
return rot1 == (float)dRot;
|
||||
}
|
||||
|
||||
public void LookAt(Actor actor)
|
||||
{
|
||||
if (actor != null)
|
||||
|
@ -667,7 +652,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 Vector3.GetAngle(positionX, positionZ, x, z) < angle;
|
||||
}
|
||||
|
||||
// todo: is this legit?
|
||||
|
@ -725,31 +710,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
}
|
||||
#endregion
|
||||
|
||||
public Player GetAsPlayer()
|
||||
{
|
||||
return currentSubState == SetActorStatePacket.SUB_STATE_PLAYER && this is Player ? ((Player)this) : null;
|
||||
}
|
||||
|
||||
public BattleNpc GetAsMob()
|
||||
{
|
||||
return currentSubState == SetActorStatePacket.SUB_STATE_MONSTER && this is BattleNpc ? ((BattleNpc)this) : null;
|
||||
}
|
||||
|
||||
public Npc GetAsNpc()
|
||||
{
|
||||
return currentSubState != SetActorStatePacket.SUB_STATE_PLAYER && this is Npc ? ((Npc)this) : null;
|
||||
}
|
||||
|
||||
public Actor GetAsActor()
|
||||
{
|
||||
return this is Actor ? ((Actor)this) : null;
|
||||
}
|
||||
|
||||
public Character GetAsCharacter()
|
||||
{
|
||||
return this is Character ? ((Character)this) : null;
|
||||
}
|
||||
|
||||
public SubPacket CreateGameMessagePacket(Actor textIdOwner, ushort textId, byte log, params object[] msgParams)
|
||||
{
|
||||
if (msgParams == null || msgParams.Length == 0)
|
||||
|
|
|
@ -15,6 +15,7 @@ using System.Threading.Tasks;
|
|||
using FFXIVClassic_Map_Server.packets.send;
|
||||
using FFXIVClassic_Map_Server.actors.group;
|
||||
using FFXIVClassic_Map_Server.actors.director;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.controllers;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@ using FFXIVClassic_Map_Server.actors.chara;
|
|||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
using FFXIVClassic_Map_Server.packets.send;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.state;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
|
@ -473,22 +474,33 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
return moveSpeeds[2] + GetMod((uint)Modifier.Speed);
|
||||
}
|
||||
|
||||
public virtual void OnAttack(State state, BattleAction action)
|
||||
public virtual void OnAttack(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
target.DelHP(action.amount);
|
||||
}
|
||||
|
||||
public virtual void OnCast(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnCast(State state, BattleAction action)
|
||||
public virtual void OnWeaponSkill(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnWeaponSkill(State state, BattleAction action)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnAbility(State state, BattleAction action)
|
||||
public virtual void OnAbility(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
|
||||
public void ChangeState(State state)
|
||||
{
|
||||
if (GetCurrentState() != null)
|
||||
if (CanChangeState())
|
||||
{
|
||||
if (states.Count <= 10)
|
||||
{
|
||||
|
|
|
@ -139,6 +139,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
}
|
||||
else
|
||||
{
|
||||
distanceFromPoint = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
private DateTime waitTime;
|
||||
|
||||
private bool firstSpell = true;
|
||||
private DateTime lastRoamScript; // todo: what even is this used as
|
||||
private DateTime lastRoamUpdate;
|
||||
|
||||
private new BattleNpc owner;
|
||||
public BattleNpcController(BattleNpc owner) :
|
||||
|
@ -76,7 +76,7 @@ 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.moveSpeeds[1] != 0)
|
||||
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)
|
||||
|
@ -106,6 +106,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
// todo:
|
||||
lastActionTime = lastUpdate.AddSeconds(5);
|
||||
owner.isMovingToSpawn = true;
|
||||
owner.aiContainer.pathFind.SetPathFlags(PathFindFlags.None);
|
||||
owner.aiContainer.pathFind.PreparePath(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 10);
|
||||
neutralTime = lastActionTime;
|
||||
owner.hateContainer.ClearHate();
|
||||
owner.moveState = 1;
|
||||
|
@ -147,7 +149,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
if (tick >= waitTime)
|
||||
{
|
||||
// todo: aggro cooldown
|
||||
neutralTime = tick.AddSeconds(5);
|
||||
neutralTime = tick.AddSeconds(3);
|
||||
if (owner.aiContainer.pathFind.IsFollowingPath())
|
||||
{
|
||||
owner.aiContainer.pathFind.FollowPath();
|
||||
|
@ -157,8 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
{
|
||||
if (tick >= lastActionTime)
|
||||
{
|
||||
var battlenpc = owner as BattleNpc;
|
||||
owner.aiContainer.pathFind.PathInRange(battlenpc.spawnX, battlenpc.spawnY, battlenpc.spawnZ, 1.5f, 15.0f);
|
||||
|
||||
}
|
||||
}
|
||||
// todo:
|
||||
|
@ -166,6 +167,28 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||
owner.OnRoam(tick);
|
||||
}
|
||||
|
||||
if (tick >= lastRoamUpdate && !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)
|
||||
{
|
||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||
{
|
||||
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);
|
||||
|
||||
if (levelDifference < 10 || (owner.aggroType & AggroType.IgnoreLevelDifference) != 0 && ((BattleNpcController)owner.aiContainer.GetController()).CanAggroTarget((Player)player))
|
||||
owner.hateContainer.AddBaseHate((Player)player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (owner.aiContainer.pathFind.IsFollowingPath())
|
||||
{
|
||||
owner.aiContainer.pathFind.FollowPath();
|
||||
|
@ -223,7 +246,7 @@ 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.90f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
|
||||
if (mobDistance < 0.70f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
|
||||
{
|
||||
owner.aiContainer.pathFind.PathInRange(targetPos, 1.3f, 1.8f);
|
||||
break;
|
||||
|
|
|
@ -88,14 +88,38 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
// todo: possible underflow
|
||||
BattleAction action = new BattleAction();
|
||||
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
||||
errorPacket = 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 = 1; // todo: hit effect doesnt display without this?
|
||||
owner.OnAttack(this, action);
|
||||
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
|
||||
action.param = (byte)HitDirection.None; // HitDirection (auto attack shouldnt need this afaik)
|
||||
|
||||
// todo: implement auto attack damage bonus in Character.OnAttack
|
||||
/*
|
||||
≪Auto-attack Damage Bonus≫
|
||||
Class Bonus 1 Bonus 2
|
||||
Pugilist Intelligence Strength
|
||||
Gladiator Mind Strength
|
||||
Marauder Vitality Strength
|
||||
Archer Dexterity Piety
|
||||
Lancer Piety Strength
|
||||
Conjurer Mind Piety
|
||||
Thaumaturge Mind Piety
|
||||
* The above damage bonus also applies to “Shot” attacks by archers.
|
||||
*/
|
||||
|
||||
owner.OnAttack(this, action, ref errorPacket);
|
||||
// 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);
|
||||
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
|
||||
}
|
||||
|
||||
public override void TryInterrupt()
|
||||
|
@ -104,14 +128,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
// todo: sometimes paralyze can let you attack, get random percentage of actually letting you attack
|
||||
var list = owner.statusEffects.GetStatusEffectsByFlag((uint)StatusEffectFlags.PreventAction);
|
||||
uint effectId = 0;
|
||||
uint statusId = 0;
|
||||
if (list.Count > 0)
|
||||
{
|
||||
// todo: actually check proc rate/random chance of whatever effect
|
||||
effectId = list[0].GetStatusEffectId();
|
||||
statusId = list[0].GetStatusId();
|
||||
}
|
||||
// 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);
|
||||
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, statusId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
|
||||
//owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
|
||||
//errorPacket = null;
|
||||
interrupt = true;
|
||||
|
@ -135,6 +159,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
// todo: shouldnt need to check if owner is dead since all states would be cleared
|
||||
if (owner.aiContainer.IsDead() || target.aiContainer.IsDead())
|
||||
{
|
||||
target = null;
|
||||
return false;
|
||||
}
|
||||
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
this.startPos = owner.GetPosAsVector3();
|
||||
this.startTime = DateTime.Now;
|
||||
// todo: lookup spell from global table
|
||||
this.spell = Server.GetWorldManager().GetAbility(spellId);
|
||||
this.spell = Server.GetWorldManager().GetBattleCommand(spellId);
|
||||
var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, spell, "magic", "onMagicPrepare", owner, target, spell);
|
||||
|
||||
// todo: check recast
|
||||
|
@ -125,20 +125,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
var action = new BattleAction();
|
||||
action.effectId = spell.effectAnimation;
|
||||
action.param = 1;
|
||||
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;
|
||||
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.target.actorId, owner.actorId, spell.battleAnimation, spell.id, actions)) :
|
||||
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.zone.BroadcastPacketsAroundActor(owner, packets);
|
||||
}
|
||||
|
||||
public override void TryInterrupt()
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
this.startTime = DateTime.Now;
|
||||
// todo: lookup skill from global table
|
||||
this.skill = Server.GetWorldManager().GetAbility(skillId);
|
||||
this.skill = Server.GetWorldManager().GetBattleCommand(skillId);
|
||||
var returnCode = lua.LuaEngine.CallLuaBattleCommandFunction(owner, skill, "weaponskill", "onSkillPrepare", owner, target, skill);
|
||||
|
||||
// todo: check recast
|
||||
|
@ -109,10 +109,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
var action = new BattleAction();
|
||||
action.effectId = (uint)HitEffect.Hit;
|
||||
action.param = 1;
|
||||
action.param = 1; // HitDirection
|
||||
action.unknown = 1;
|
||||
action.targetId = chara.actorId;
|
||||
action.worldMasterTextId = skill.worldMasterTextId;
|
||||
action.animation = skill.battleAnimation;
|
||||
// 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,7 +122,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
}
|
||||
|
||||
owner.zone.BroadcastPacketAroundActor(owner,
|
||||
skill.aoeType != TargetFindAOEType.None ? (BattleActionX10Packet.BuildPacket(owner.target.actorId, owner.actorId, skill.battleAnimation, skill.id, actions)) :
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,16 +7,17 @@ using System.Threading.Tasks;
|
|||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
using FFXIVClassic.Common;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
||||
{
|
||||
static class BattleUtils
|
||||
{
|
||||
public static void TryAttack(Character attacker, Character defender, BattleAction action)
|
||||
public static bool TryAttack(Character attacker, Character defender, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
// todo: get hit rate, hit count, set hit effect
|
||||
action.effectId |= (uint)(HitEffect.RecoilLv2 | HitEffect.Hit | HitEffect.HitVisual1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ushort CalculateAttackDamage(Character attacker, Character defender, BattleAction action)
|
||||
|
@ -40,6 +41,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
|||
return damage;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -65,6 +65,16 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
CalculateBaseStats();
|
||||
}
|
||||
|
||||
public uint GetAggroType()
|
||||
{
|
||||
return (uint)aggroType;
|
||||
}
|
||||
|
||||
public void SetAggroType(uint aggroType)
|
||||
{
|
||||
this.aggroType = (AggroType)aggroType;
|
||||
}
|
||||
|
||||
public override void Update(DateTime tick)
|
||||
{
|
||||
this.aiContainer.Update(tick);
|
||||
|
@ -137,6 +147,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
this.isMovingToSpawn = false;
|
||||
this.ResetMoveSpeeds();
|
||||
this.hateContainer.ClearHate();
|
||||
this.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
|
||||
}
|
||||
|
||||
|
@ -145,11 +156,14 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
if (IsAlive())
|
||||
{
|
||||
aiContainer.InternalDie(tick, despawnTime);
|
||||
aiContainer.pathFind.Clear();
|
||||
|
||||
this.ResetMoveSpeeds();
|
||||
this.positionX = oldPositionX;
|
||||
this.positionY = oldPositionY;
|
||||
this.positionZ = oldPositionZ;
|
||||
|
||||
|
||||
this.isAtSpawn = true;
|
||||
}
|
||||
else
|
||||
|
@ -176,25 +190,13 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
else
|
||||
{
|
||||
if (target == null && !aiContainer.pathFind.IsFollowingPath())
|
||||
aiContainer.pathFind.PathInRange(spawnX, spawnY, spawnZ, 1.0f, 15.0f);
|
||||
aiContainer.pathFind.PathInRange(spawnX, spawnY, spawnZ, 1.5f, 15.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isMovingToSpawn = false;
|
||||
}
|
||||
|
||||
// dont bother checking for any in-range players if going back to spawn
|
||||
if (!this.isMovingToSpawn && this.aiContainer.pathFind.AtPoint() && this.aggroType != AggroType.None)
|
||||
{
|
||||
foreach (var player in zone.GetActorsAroundActor<Player>(this, 50))
|
||||
{
|
||||
uint levelDifference = (uint)Math.Abs(this.charaWork.parameterSave.state_mainSkillLevel - player.charaWork.parameterSave.state_mainSkillLevel);
|
||||
|
||||
if (levelDifference < 10 && ((BattleNpcController)aiContainer.GetController()).CanAggroTarget(player))
|
||||
hateContainer.AddBaseHate(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCloseToSpawn()
|
||||
|
@ -202,17 +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)
|
||||
public override void OnAttack(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
// player melee animation
|
||||
uint battleAnimation = 0x19001000;
|
||||
// todo: get hitrate and shit, handle protect effect and whatever
|
||||
BattleUtils.TryAttack(this, state.GetTarget(), action);
|
||||
|
||||
zone.BroadcastPacketAroundActor(this,
|
||||
BattleActionX01Packet.BuildPacket(actorId, actorId, target.actorId, (uint)battleAnimation,
|
||||
(uint)action.effectId, (ushort)action.worldMasterTextId, (ushort)BattleActionX01PacketCommand.Attack, (ushort)action.amount, (byte)action.param)
|
||||
);
|
||||
base.OnAttack(state, action, ref errorPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1894,7 +1894,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
charaWork.commandCategory[trueHotbarSlot] = 1;
|
||||
|
||||
//Set recast time
|
||||
ushort maxRecastTime = (ushort)Server.GetWorldManager().GetAbility(commandId).recastTimeSeconds;
|
||||
ushort maxRecastTime = (ushort)Server.GetWorldManager().GetBattleCommand(commandId).recastTimeSeconds;
|
||||
uint recastEnd = Utils.UnixTimeStampUTC() + maxRecastTime;
|
||||
charaWork.parameterTemp.maxCommandRecastTime[trueHotbarSlot - charaWork.commandBorder] = maxRecastTime;
|
||||
charaWork.parameterSave.commandSlot_recastTime[trueHotbarSlot - charaWork.commandBorder] = recastEnd;
|
||||
|
@ -2064,23 +2064,20 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
return true;
|
||||
}
|
||||
|
||||
public override void OnAttack(State state, BattleAction action)
|
||||
public override void OnAttack(State state, BattleAction action, ref SubPacket errorPacket)
|
||||
{
|
||||
// melee attack animation
|
||||
uint battleAnimation = 0x19001000;
|
||||
|
||||
// todo: change animation based on equipped weapon
|
||||
action.effectId |= (uint)HitEffect.HitVisual1; // melee
|
||||
|
||||
// todo: get hitrate and shit, handle protect effect and whatever
|
||||
BattleUtils.TryAttack(this, state.GetTarget(), action);
|
||||
action.amount = BattleUtils.CalculateAttackDamage(this, state.GetTarget(), action);
|
||||
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
||||
|
||||
zone.BroadcastPacketAroundActor(this, BattleActionX01Packet.BuildPacket(actorId, actorId, action.targetId, (uint)battleAnimation,
|
||||
0x8000000 | action.effectId, (ushort)action.worldMasterTextId, (ushort)BattleActionX01PacketCommand.Attack, (ushort)action.amount, (byte)action.param)
|
||||
);
|
||||
base.OnAttack(state, action, ref errorPacket);
|
||||
|
||||
if (errorPacket == null)
|
||||
{
|
||||
// melee attack animation
|
||||
action.animation = 0x19001000;
|
||||
}
|
||||
var target = state.GetTarget();
|
||||
//if (target is BattleNpc)
|
||||
{
|
||||
((BattleNpc)target).hateContainer.UpdateHate(this, action.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue