mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
cleaned up magicstate and weaponskillstate
- todo: fix IsFacing - added thunder spell (todo: figure out why battleactionx10 crashes client on sending shit)
This commit is contained in:
parent
452f1cc8c0
commit
9024f3fad6
@ -41,7 +41,7 @@ namespace FFXIVClassic_Map_Server
|
|||||||
|
|
||||||
private Server mServer;
|
private Server mServer;
|
||||||
|
|
||||||
private const int MILIS_LOOPTIME = 250;
|
private const int MILIS_LOOPTIME = 333;
|
||||||
private Timer mZoneTimer;
|
private Timer mZoneTimer;
|
||||||
|
|
||||||
//Content Groups
|
//Content Groups
|
||||||
@ -1013,6 +1013,7 @@ namespace FFXIVClassic_Map_Server
|
|||||||
|
|
||||||
public void ZoneThreadLoop(Object state)
|
public void ZoneThreadLoop(Object state)
|
||||||
{
|
{
|
||||||
|
// todo: fuck coroutines, seem to be causing it to hang
|
||||||
// todo: spawn new thread for each zone on startup
|
// todo: spawn new thread for each zone on startup
|
||||||
lock (zoneList)
|
lock (zoneList)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ using FFXIVClassic_Map_Server.actors.area;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||||
|
using FFXIVClassic_Map_Server.packets.send;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.Actors
|
namespace FFXIVClassic_Map_Server.Actors
|
||||||
{
|
{
|
||||||
@ -62,7 +63,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
protected DateTime lastUpdate;
|
protected DateTime lastUpdate;
|
||||||
public Actor target;
|
public Actor target;
|
||||||
|
|
||||||
public bool hasMoved = false;
|
|
||||||
public bool isAtSpawn = true;
|
public bool isAtSpawn = true;
|
||||||
|
|
||||||
public ActorUpdateFlags updateFlags;
|
public ActorUpdateFlags updateFlags;
|
||||||
@ -416,7 +416,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
//Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates)
|
//Program.Server.GetInstance().mLuaEngine.OnPath(actor, position, positionUpdates)
|
||||||
|
|
||||||
positionUpdates.Remove(pos);
|
positionUpdates.Remove(pos);
|
||||||
lastMoveUpdate = DateTime.Now;
|
|
||||||
packets.Add(CreatePositionUpdatePacket());
|
packets.Add(CreatePositionUpdatePacket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -569,6 +568,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region positioning
|
||||||
public List<float> GetPos()
|
public List<float> GetPos()
|
||||||
{
|
{
|
||||||
List<float> pos = new List<float>();
|
List<float> pos = new List<float>();
|
||||||
@ -614,12 +614,12 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo: do this properly
|
// todo: do this properly
|
||||||
public bool IsFacing(float x, float y)
|
public bool IsFacing(float x, float z)
|
||||||
{
|
{
|
||||||
var rot1 = this.rotation;
|
var rot1 = this.rotation;
|
||||||
|
|
||||||
var dX = this.positionX - x;
|
var dX = this.positionX - x;
|
||||||
var dY = this.positionY - y;
|
var dY = this.positionZ - z;
|
||||||
|
|
||||||
var rot2 = Math.Atan2(dY, dX);
|
var rot2 = Math.Atan2(dY, dX);
|
||||||
|
|
||||||
@ -632,7 +632,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
{
|
{
|
||||||
if (actor != null)
|
if (actor != null)
|
||||||
{
|
{
|
||||||
LookAt(actor.positionX, actor.positionY);
|
LookAt(actor.positionX, actor.positionZ);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -640,12 +640,20 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LookAt(float x, float y)
|
public void LookAt(Vector3 pos)
|
||||||
|
{
|
||||||
|
if (pos != null)
|
||||||
|
{
|
||||||
|
LookAt(pos.X, pos.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LookAt(float x, float z)
|
||||||
{
|
{
|
||||||
var rot1 = this.rotation;
|
var rot1 = this.rotation;
|
||||||
|
|
||||||
var dX = this.positionX - x;
|
var dX = this.positionX - x;
|
||||||
var dY = this.positionY - y;
|
var dY = this.positionZ - z;
|
||||||
|
|
||||||
var rot2 = Math.Atan2(dY, dX);
|
var rot2 = Math.Atan2(dY, dX);
|
||||||
|
|
||||||
@ -658,7 +666,8 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
|
|
||||||
public bool IsFacing(float x, float z, float angle = 40.0f)
|
public bool IsFacing(float x, float z, float angle = 40.0f)
|
||||||
{
|
{
|
||||||
return Vector3.GetAngle(positionX, positionZ, x, z) < angle;
|
angle = (float)(Math.PI * angle / 180);
|
||||||
|
return Vector3.GetAngle(positionX, positionZ, x, z) <= angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: is this legit?
|
// todo: is this legit?
|
||||||
@ -714,6 +723,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
{
|
{
|
||||||
return FindRandomPoint(positionX, positionY, positionZ, minRadius, maxRadius);
|
return FindRandomPoint(positionX, positionY, positionZ, minRadius, maxRadius);
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public Player GetAsPlayer()
|
public Player GetAsPlayer()
|
||||||
{
|
{
|
||||||
@ -739,6 +749,14 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
{
|
{
|
||||||
return this is Character ? ((Character)this) : null;
|
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)
|
||||||
|
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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FFXIVClassic_Map_Server.actors.chara;
|
using FFXIVClassic_Map_Server.actors.chara;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||||
|
using FFXIVClassic_Map_Server.packets.send;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.Actors
|
namespace FFXIVClassic_Map_Server.Actors
|
||||||
{
|
{
|
||||||
@ -108,7 +109,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
ResetMoveSpeeds();
|
ResetMoveSpeeds();
|
||||||
// todo: base this on equip and shit
|
// todo: base this on equip and shit
|
||||||
SetMod((uint)Modifier.AttackRange, 3);
|
SetMod((uint)Modifier.AttackRange, 3);
|
||||||
SetMod((uint)Modifier.AttackDelay, 4200);
|
SetMod((uint)Modifier.AttackDelay, (Program.Random.Next(30,60) * 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubPacket CreateAppearancePacket()
|
public SubPacket CreateAppearancePacket()
|
||||||
@ -254,12 +255,27 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool IsValidTarget(Character target, ValidTarget validTarget, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual bool CanAttack()
|
public virtual bool CanAttack()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool CanCast(Character target, Ability spell, ref SubPacket errorPacket)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool CanCast()
|
public virtual bool CanWeaponSkill(Character target, Ability skill, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool CanUseAbility(Character target, Ability ability, ref SubPacket errorPacket)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -277,12 +293,16 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
public bool Engage(uint targid = 0)
|
public bool Engage(uint targid = 0)
|
||||||
{
|
{
|
||||||
// todo: attack the things
|
// todo: attack the things
|
||||||
targid = targid == 0 ? currentTarget: targid;
|
if (targid == 0)
|
||||||
|
{
|
||||||
|
if (currentTarget != 0xC0000000)
|
||||||
|
targid = currentTarget;
|
||||||
|
else if (currentLockedTarget != 0xC0000000)
|
||||||
|
targid = currentLockedTarget;
|
||||||
|
}
|
||||||
if (targid != 0)
|
if (targid != 0)
|
||||||
{
|
{
|
||||||
var targ = Server.GetWorldManager().GetActorInWorld(targid);
|
aiContainer.Engage(Server.GetWorldManager().GetActorInWorld(targid) as Character);
|
||||||
if (targ is Character)
|
|
||||||
aiContainer.Engage((Character)targ);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -297,9 +317,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cast(uint spellId)
|
public void Cast(uint spellId, uint targetId = 0)
|
||||||
{
|
{
|
||||||
aiContainer.Cast(Server.GetWorldManager().GetActorInWorld(currentTarget) as Character, spellId);
|
aiContainer.Cast(Server.GetWorldManager().GetActorInWorld(targetId == 0 ? currentTarget : targetId) as Character, spellId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WeaponSkill(uint skillId)
|
public void WeaponSkill(uint skillId)
|
||||||
|
@ -5,6 +5,8 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFXIVClassic_Map_Server.actors.chara.player;
|
using FFXIVClassic_Map_Server.actors.chara.player;
|
||||||
|
using FFXIVClassic.Common;
|
||||||
|
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
@ -94,7 +96,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
return castTimeSeconds == 0;
|
return castTimeSeconds == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValidTarget(Character user, Character target)
|
public bool IsValidTarget(Character user, Character target, ref SubPacket errorPacket)
|
||||||
{
|
{
|
||||||
// todo: set box length..
|
// todo: set box length..
|
||||||
targetFind = new TargetFind(user);
|
targetFind = new TargetFind(user);
|
||||||
@ -108,7 +110,112 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
{
|
{
|
||||||
targetFind.SetAOEType(validTarget, aoeType, range, 40);
|
targetFind.SetAOEType(validTarget, aoeType, range, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
32512 cannot be performed on a KO'd target.
|
||||||
|
32513 can only be performed on a KO'd target.
|
||||||
|
32514 cannot be performed on yourself.
|
||||||
|
32515 can only be performed on yourself.
|
||||||
|
32516 cannot be performed on a friendly target.
|
||||||
|
32517 can only be performed on a friendly target.
|
||||||
|
32518 cannot be performed on an enemy.
|
||||||
|
32519 can only be performed on an enemy,
|
||||||
|
*/
|
||||||
|
|
||||||
|
// cant target dead
|
||||||
|
if ((validTarget & (ValidTarget.Corpse | ValidTarget.CorpseOnly)) == 0 && target.IsDead())
|
||||||
|
{
|
||||||
|
// cannot be perfomed on
|
||||||
|
errorPacket = user.CreateGameMessagePacket(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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpCost > user.GetTP())
|
||||||
|
{
|
||||||
|
errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32546, 0x20, (uint)id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: calculate cost based on modifiers also (probably in BattleUtils)
|
||||||
|
|
||||||
|
if (mpCost > 0 && (mpCost = CalculateCost((ushort)user.charaWork.parameterSave.state_mainSkillLevel)) > user.GetMP())
|
||||||
|
{
|
||||||
|
// todo: error message
|
||||||
|
errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32545, 0x20, (uint)id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: check target requirements
|
||||||
|
if (requirements != AbilityRequirements.None)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: i dont care to message for each scenario, just the most common ones..
|
||||||
|
if ((validTarget & ValidTarget.CorpseOnly) != 0)
|
||||||
|
{
|
||||||
|
if (target != null && target.IsAlive())
|
||||||
|
{
|
||||||
|
errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32513, 0x20, (uint)id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((validTarget & ValidTarget.Enemy) != 0)
|
||||||
|
{
|
||||||
|
if (target == user || target != null &&
|
||||||
|
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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((validTarget & (ValidTarget.PartyMember | ValidTarget.Player | ValidTarget.Ally)) != 0)
|
||||||
|
{
|
||||||
|
if (target == null || target.currentSubState != user.currentSubState )
|
||||||
|
{
|
||||||
|
errorPacket = user.CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32516, 0x20, (uint)id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return targetFind.CanTarget(target, true, true);
|
return targetFind.CanTarget(target, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ushort CalculateCost(uint level)
|
||||||
|
{
|
||||||
|
// todo: use precalculated costs instead
|
||||||
|
ushort cost = 0;
|
||||||
|
if (level <= 10)
|
||||||
|
cost = (ushort)(100 + level * 10);
|
||||||
|
else if (level <= 20)
|
||||||
|
cost = (ushort)(200 + (level - 10) * 20);
|
||||||
|
else if (level <= 30)
|
||||||
|
cost = (ushort)(400 + (level - 20) * 40);
|
||||||
|
else if (level <= 40)
|
||||||
|
cost = (ushort)(800 + (level - 30) * 70);
|
||||||
|
else if (level <= 50)
|
||||||
|
cost = (ushort)(1500 + (level - 40) * 130);
|
||||||
|
else if (level <= 60)
|
||||||
|
cost = (ushort)(2800 + (level - 50) * 200);
|
||||||
|
else if (level <= 70)
|
||||||
|
cost = (ushort)(4800 + (level - 60) * 320);
|
||||||
|
else
|
||||||
|
cost = (ushort)(8000 + (level - 70) * 500);
|
||||||
|
|
||||||
|
return (ushort)Math.Ceiling((cost * ((mpCost == 0 ? tpCost : mpCost) * 0.001)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
|
|
||||||
public void UpdateHate(Character target, int damage)
|
public void UpdateHate(Character target, int damage)
|
||||||
{
|
{
|
||||||
if (HasHateForTarget(target))
|
if (!HasHateForTarget(target))
|
||||||
{
|
AddBaseHate(target);
|
||||||
|
|
||||||
//hateList[target].volatileEnmity += (uint)damage;
|
//hateList[target].volatileEnmity += (uint)damage;
|
||||||
hateList[target].cumulativeEnmity += (uint)damage;
|
hateList[target].cumulativeEnmity += (uint)damage;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearHate(Character target = null)
|
public void ClearHate(Character target = null)
|
||||||
{
|
{
|
||||||
|
@ -151,7 +151,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
float stepDistance = speed / 3;
|
float stepDistance = speed / 3;
|
||||||
float distanceTo = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, point.X, point.Y, point.Z);
|
float distanceTo = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, point.X, point.Y, point.Z);
|
||||||
|
|
||||||
owner.LookAt(point.X, point.Y);
|
owner.LookAt(point);
|
||||||
|
|
||||||
if (distanceTo <= distanceFromPoint + stepDistance)
|
if (distanceTo <= distanceFromPoint + stepDistance)
|
||||||
{
|
{
|
||||||
|
@ -168,6 +168,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
// todo: this is stupid
|
// todo: this is stupid
|
||||||
bool withPet = (flags & ValidTarget.Ally) != 0 || masterTarget.allegiance != owner.allegiance;
|
bool withPet = (flags & ValidTarget.Ally) != 0 || masterTarget.allegiance != owner.allegiance;
|
||||||
|
|
||||||
|
if (masterTarget != null)
|
||||||
|
targets.Add(masterTarget);
|
||||||
|
|
||||||
if (IsPlayer(owner))
|
if (IsPlayer(owner))
|
||||||
{
|
{
|
||||||
if (masterTarget is Player)
|
if (masterTarget is Player)
|
||||||
@ -284,8 +287,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
|
|
||||||
private void AddAllBattleNpcs(Character target, bool withPet)
|
private void AddAllBattleNpcs(Character target, bool withPet)
|
||||||
{
|
{
|
||||||
// 70 is client render distance so we'll go with that
|
var actors = owner.zone.GetActorsAroundActor<BattleNpc>(owner, 50);
|
||||||
var actors = owner.zone.GetActorsAroundActor<BattleNpc>(owner, (int)extents);
|
|
||||||
|
|
||||||
// todo: should we look for Characters instead in case player is charmed by BattleNpc
|
// todo: should we look for Characters instead in case player is charmed by BattleNpc
|
||||||
foreach (BattleNpc actor in actors)
|
foreach (BattleNpc actor in actors)
|
||||||
@ -361,6 +363,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
if (aoeType == TargetFindAOEType.Box && IsWithinBox(target, withPet))
|
if (aoeType == TargetFindAOEType.Box && IsWithinBox(target, withPet))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (aoeType == TargetFindAOEType.None && targets.Count != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,13 +217,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
|||||||
{
|
{
|
||||||
if (owner.target.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
if (owner.target.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||||
{
|
{
|
||||||
foreach (var battlenpc in owner.zone.GetActorsAroundActor<BattleNpc>(owner, 1))
|
foreach (var chara in owner.zone.GetActorsAroundActor<Character>(owner, 1))
|
||||||
{
|
{
|
||||||
if (battlenpc == owner)
|
if (chara == owner)
|
||||||
continue;
|
continue;
|
||||||
float mobDistance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, battlenpc.positionX, battlenpc.positionY, battlenpc.positionZ);
|
|
||||||
if (mobDistance < 0.25f && (battlenpc.updateFlags & ActorUpdateFlags.Position) == 0)
|
float mobDistance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, chara.positionX, chara.positionY, chara.positionZ);
|
||||||
battlenpc.aiContainer.pathFind.PathInRange(targetPos, 1.3f, 1.8f);
|
if (mobDistance < 0.90f && (chara.updateFlags & ActorUpdateFlags.Position) == 0)
|
||||||
|
{
|
||||||
|
owner.aiContainer.pathFind.PathInRange(targetPos, 1.3f, 1.8f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (owner.target != target || owner.target?.actorId != owner.currentLockedTarget)
|
if (owner.target != target || owner.target?.actorId != owner.currentLockedTarget)
|
||||||
owner.aiContainer.ChangeTarget(target = Server.GetWorldManager().GetActorInWorld(owner.currentLockedTarget) as Character);
|
owner.aiContainer.ChangeTarget(target = Server.GetWorldManager().GetActorInWorld(owner.currentLockedTarget == 0xC0000000 ? owner.currentTarget : owner.currentLockedTarget) as Character);
|
||||||
|
|
||||||
if (target == null || target.IsDead())
|
if (target == null || target.IsDead())
|
||||||
{
|
{
|
||||||
@ -75,6 +75,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
{
|
{
|
||||||
// todo: handle interrupt/paralyze etc
|
// todo: handle interrupt/paralyze etc
|
||||||
}
|
}
|
||||||
|
attackTime = DateTime.Now.AddMilliseconds(owner.GetAttackDelayMs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -94,14 +95,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
lua.LuaEngine.CallLuaBattleAction(owner, "onAttack", false, owner, target, damage);
|
lua.LuaEngine.CallLuaBattleAction(owner, "onAttack", false, owner, target, damage);
|
||||||
|
|
||||||
{
|
{
|
||||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
var actors = owner.zone.GetActorsAroundActor<Player>(owner, 50);
|
||||||
|
foreach (var player in actors)
|
||||||
{
|
{
|
||||||
var packet = BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
var packet = BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
||||||
player.QueuePacket(packet);
|
player.QueuePacket(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target.DelHP((short)damage);
|
target.DelHP((short)damage);
|
||||||
attackTime = attackTime.AddMilliseconds(owner.GetAttackDelayMs());
|
|
||||||
owner.LookAt(target);
|
owner.LookAt(target);
|
||||||
//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, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ using FFXIVClassic.Common;
|
|||||||
using FFXIVClassic_Map_Server.Actors;
|
using FFXIVClassic_Map_Server.Actors;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor;
|
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||||
|
using FFXIVClassic_Map_Server.packets.send;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
{
|
{
|
||||||
class MagicState : State
|
class MagicState : State
|
||||||
@ -24,39 +26,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
this.spell = Server.GetWorldManager().GetAbility(spellId);
|
this.spell = Server.GetWorldManager().GetAbility(spellId);
|
||||||
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellPrepare", owner, target, spell);
|
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellPrepare", owner, target, spell);
|
||||||
|
|
||||||
if (spell != null && returnCode == 0)
|
// todo: check recast
|
||||||
|
if (owner.CanCast(target, spell, ref errorPacket))
|
||||||
{
|
{
|
||||||
// todo: hp/mp shit should be taken care of in scripts, not here
|
|
||||||
// todo: Azia can fix, check the recast time and send error
|
// todo: Azia can fix, check the recast time and send error
|
||||||
|
|
||||||
if (!spell.IsValidTarget(owner, target))
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
interrupt = true;
|
|
||||||
}
|
|
||||||
else if ((spell.mpCost = (ushort)Math.Ceiling((8000 + (owner.charaWork.parameterSave.state_mainSkillLevel - 70) * 500) * (spell.mpCost * 0.001))) > owner.GetMP())
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
interrupt = true;
|
|
||||||
}
|
|
||||||
else if (spell.level > owner.charaWork.parameterSave.state_mainSkillLevel)
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
}
|
|
||||||
else if (false /*spell.requirements & */)
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OnStart();
|
OnStart();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
if (interrupt || errorPacket != null)
|
||||||
{
|
{
|
||||||
// todo: fuckin retarded. enum log messages somewhere (prolly isnt even right param)
|
if (owner is Player && errorPacket != null)
|
||||||
if (owner is Player)
|
((Player)owner).QueuePacket(errorPacket);
|
||||||
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), (ushort)(returnCode == -1 ? 32539 : returnCode), 0x20);
|
|
||||||
|
errorPacket = null;
|
||||||
interrupt = true;
|
interrupt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +61,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
{
|
{
|
||||||
// todo: this is retarded, prolly doesnt do what i think its gonna do
|
// todo: this is retarded, prolly doesnt do what i think its gonna do
|
||||||
player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target != null ? target.actorId : 0xC0000000, spell.battleAnimation, spell.effectAnimation, 0, spell.id, 0, (byte)spell.castTimeSeconds));
|
//player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, target != null ? target.actorId : 0xC0000000, spell.battleAnimation, spell.effectAnimation, 0, spell.id, 0, (byte)spell.castTimeSeconds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,24 +105,25 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
spell.targetFind.FindWithinArea(target, spell.validTarget);
|
spell.targetFind.FindWithinArea(target, spell.validTarget);
|
||||||
isCompleted = true;
|
isCompleted = true;
|
||||||
|
|
||||||
|
var targets = spell.targetFind.GetTargets();
|
||||||
|
BattleAction[] actions = new BattleAction[targets.Count];
|
||||||
List<SubPacket> packets = new List<SubPacket>();
|
List<SubPacket> packets = new List<SubPacket>();
|
||||||
foreach (var chara in spell.targetFind.GetTargets())
|
var i = 0;
|
||||||
|
foreach (var chara in targets)
|
||||||
{
|
{
|
||||||
// todo: calculate shit, do shit
|
var action = new BattleAction();
|
||||||
bool landed = true;
|
action.effectId = spell.effectAnimation;
|
||||||
var amount = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellFinish", owner, target, spell);
|
action.param = 1;
|
||||||
|
action.unknown = 1;
|
||||||
|
action.targetId = chara.actorId;
|
||||||
|
action.worldMasterTextId = spell.worldMasterTextId;
|
||||||
|
action.amount = (ushort)lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellFinish", owner, chara, spell, action);
|
||||||
|
actions[i++] = action;
|
||||||
|
|
||||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, spell.battleAnimation, action.effectId, action.worldMasterTextId, spell.id, action.amount, action.param));
|
||||||
{
|
|
||||||
player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, chara.actorId, spell.battleAnimation, spell.effectAnimation, spell.worldMasterTextId, spell.id, (ushort)spell.param, 1));
|
|
||||||
}
|
}
|
||||||
|
//packets.Add(BattleActionX10Packet.BuildPacket(player.actorId, owner.actorId, spell.battleAnimation, spell.id, actions));
|
||||||
if (chara is BattleNpc)
|
owner.zone.BroadcastPacketsAroundActor(owner, packets);
|
||||||
{
|
|
||||||
((BattleNpc)chara).hateContainer.UpdateHate(owner, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void TryInterrupt()
|
public override void TryInterrupt()
|
||||||
@ -166,40 +149,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.DistanceSquared(owner.GetPosAsVector3(), startPos) > 4.0f)
|
|
||||||
{
|
|
||||||
// todo: send interrupt packet
|
|
||||||
interrupt = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
interrupt = !CanCast();
|
interrupt = !CanCast();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanCast()
|
private bool CanCast()
|
||||||
{
|
{
|
||||||
if (target == null)
|
return owner.CanCast(target, spell, ref errorPacket) && !HasMoved();
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// todo: shouldnt need to check if owner is dead since all states would be cleared
|
|
||||||
if (owner.aiContainer.IsDead() || target.aiContainer.IsDead())
|
private bool HasMoved()
|
||||||
{
|
{
|
||||||
return false;
|
return (Utils.DistanceSquared(owner.GetPosAsVector3(), startPos) > 4.0f);
|
||||||
}
|
|
||||||
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > spell.range)
|
|
||||||
{
|
|
||||||
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
|
||||||
{
|
|
||||||
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ using FFXIVClassic.Common;
|
|||||||
using FFXIVClassic_Map_Server.Actors;
|
using FFXIVClassic_Map_Server.Actors;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor;
|
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||||
|
using FFXIVClassic_Map_Server.packets.send;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
{
|
{
|
||||||
class WeaponSkillState : State
|
class WeaponSkillState : State
|
||||||
@ -22,37 +24,19 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
this.skill = Server.GetWorldManager().GetAbility(skillId);
|
this.skill = Server.GetWorldManager().GetAbility(skillId);
|
||||||
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, skill, "weaponskills", "onSkillPrepare", owner, target, skill);
|
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, skill, "weaponskills", "onSkillPrepare", owner, target, skill);
|
||||||
|
|
||||||
if (skill != null && returnCode == 0)
|
// todo: check recast
|
||||||
|
if (owner.CanWeaponSkill(target, skill, ref errorPacket))
|
||||||
{
|
{
|
||||||
// todo: Azia can fix, check the recast time and send error
|
// todo: Azia can fix, check the recast time and send error
|
||||||
|
|
||||||
if (!skill.IsValidTarget(owner, target))
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
interrupt = true;
|
|
||||||
}
|
|
||||||
else if ((skill.tpCost = (ushort)Math.Ceiling((8000 + (owner.charaWork.parameterSave.state_mainSkillLevel - 70) * 500) * (skill.tpCost * 0.001))) > owner.GetTP())
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
interrupt = true;
|
|
||||||
}
|
|
||||||
else if (skill.level > owner.charaWork.parameterSave.state_mainSkillLevel)
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
}
|
|
||||||
else if (false /*skill.requirements & */)
|
|
||||||
{
|
|
||||||
// todo: error message
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OnStart();
|
OnStart();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
if (interrupt || errorPacket != null)
|
||||||
{
|
{
|
||||||
if (owner is Player)
|
if (owner is Player && errorPacket != null)
|
||||||
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), (ushort)(returnCode == -1 ? 32539 : returnCode), 0x20);
|
((Player)owner).QueuePacket(errorPacket);
|
||||||
|
|
||||||
|
errorPacket = null;
|
||||||
interrupt = true;
|
interrupt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,24 +96,26 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
skill.targetFind.FindWithinArea(target, skill.validTarget);
|
skill.targetFind.FindWithinArea(target, skill.validTarget);
|
||||||
isCompleted = true;
|
isCompleted = true;
|
||||||
|
|
||||||
|
var targets = skill.targetFind.GetTargets();
|
||||||
|
BattleAction[] actions = new BattleAction[targets.Count];
|
||||||
List<SubPacket> packets = new List<SubPacket>();
|
List<SubPacket> packets = new List<SubPacket>();
|
||||||
foreach (var chara in skill.targetFind.GetTargets())
|
|
||||||
{
|
|
||||||
// todo: calculate shit, do shit
|
|
||||||
bool landed = true;
|
|
||||||
var amount = lua.LuaEngine.CallLuaAbilityFunction(owner, skill, "weaponskills", "onSkillFinish", owner, target, skill);
|
|
||||||
|
|
||||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
var i = 0;
|
||||||
|
foreach (var chara in targets)
|
||||||
{
|
{
|
||||||
player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, chara.actorId, skill.battleAnimation, skill.effectAnimation, skill.worldMasterTextId, skill.id, (ushort)skill.param, 1));
|
var action = new BattleAction();
|
||||||
}
|
action.effectId = 0;
|
||||||
|
action.param = 1;
|
||||||
|
action.unknown = 1;
|
||||||
|
action.targetId = chara.actorId;
|
||||||
|
action.worldMasterTextId = skill.worldMasterTextId;
|
||||||
|
action.amount = (ushort)lua.LuaEngine.CallLuaAbilityFunction(owner, skill, "skills", "onSkillFinish", owner, target, skill, action);
|
||||||
|
actions[i++] = action;
|
||||||
|
|
||||||
if (chara is BattleNpc)
|
packets.Add(BattleActionX01Packet.BuildPacket(chara.actorId, owner.actorId, action.targetId, skill.battleAnimation, action.effectId, action.worldMasterTextId, skill.id, action.amount, action.param));
|
||||||
{
|
|
||||||
((BattleNpc)chara).hateContainer.UpdateHate(owner, amount);
|
|
||||||
}
|
}
|
||||||
}
|
//packets.Add(BattleActionX10Packet.BuildPacket(player.actorId, owner.actorId, spell.battleAnimation, spell.id, actions));
|
||||||
|
owner.zone.BroadcastPacketsAroundActor(owner, packets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void TryInterrupt()
|
public override void TryInterrupt()
|
||||||
@ -160,28 +146,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||||||
|
|
||||||
private bool CanUse()
|
private bool CanUse()
|
||||||
{
|
{
|
||||||
if (target == null)
|
return owner.CanWeaponSkill(target, skill, ref errorPacket);
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// todo: shouldnt need to check if owner is dead since all states would be cleared
|
|
||||||
if (owner.aiContainer.IsDead() || target.aiContainer.IsDead())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > skill.range)
|
|
||||||
{
|
|
||||||
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
|
||||||
{
|
|
||||||
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,10 +91,38 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
|
|
||||||
public override bool CanAttack()
|
public override bool CanAttack()
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanCast(Character target, Ability spell, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
// todo:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWeaponSkill(Character target, Ability skill, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
// todo:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanUseAbility(Character target, Ability ability, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
// todo:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetDespawnTime()
|
||||||
|
{
|
||||||
|
return despawnTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDespawnTime(uint seconds)
|
||||||
|
{
|
||||||
|
despawnTime = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
///<summary> // todo: create an action object? </summary>
|
///<summary> // todo: create an action object? </summary>
|
||||||
public bool OnAttack(AttackState state)
|
public bool OnAttack(AttackState state)
|
||||||
{
|
{
|
||||||
@ -167,16 +195,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetDespawnTime()
|
|
||||||
{
|
|
||||||
return despawnTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDespawnTime(uint seconds)
|
|
||||||
{
|
|
||||||
despawnTime = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCloseToSpawn()
|
public bool IsCloseToSpawn()
|
||||||
{
|
{
|
||||||
return this.isAtSpawn = Utils.DistanceSquared(positionX, positionY, positionZ, spawnX, spawnY, spawnZ) <= 2500.0f;
|
return this.isAtSpawn = Utils.DistanceSquared(positionX, positionY, positionZ, spawnX, spawnY, spawnZ) <= 2500.0f;
|
||||||
|
@ -996,6 +996,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
BroadcastPacket(packet, true);
|
BroadcastPacket(packet, true);
|
||||||
|
|
||||||
Database.SavePlayerCurrentClass(this);
|
Database.SavePlayerCurrentClass(this);
|
||||||
|
RecalculateStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GraphicChange(int slot, InventoryItem invItem)
|
public void GraphicChange(int slot, InventoryItem invItem)
|
||||||
@ -1914,5 +1915,107 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
var packet = BattleActionX01Packet.BuildPacket(actorId, actorId, currentTarget != 0xC0000000 ? currentTarget : currentLockedTarget, (uint)anim, (uint)effect, (ushort)text, (ushort)command, (ushort)param, (byte)idek);
|
var packet = BattleActionX01Packet.BuildPacket(actorId, actorId, currentTarget != 0xC0000000 ? currentTarget : currentLockedTarget, (uint)anim, (uint)effect, (ushort)text, (ushort)command, (ushort)param, (byte)idek);
|
||||||
QueuePacket(packet);
|
QueuePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool IsValidTarget(Character target, ValidTarget validTarget, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
// Target does not exist.
|
||||||
|
errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32511, 0x20);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enemy only
|
||||||
|
if ((validTarget & ValidTarget.Enemy) != 0)
|
||||||
|
{
|
||||||
|
if (target.currentSubState == SetActorStatePacket.SUB_STATE_NONE)
|
||||||
|
{
|
||||||
|
// That command cannot be performed on the current target.
|
||||||
|
errorPacket = CreateGameMessagePacket(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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// todo: pvp?
|
||||||
|
if (target.currentSubState == currentSubState)
|
||||||
|
{
|
||||||
|
// That command cannot be performed on an ally.
|
||||||
|
errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32549, 0x20);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((validTarget & ValidTarget.Ally) != 0 && target.currentSubState != currentSubState)
|
||||||
|
{
|
||||||
|
// That command cannot be performed on the current target.
|
||||||
|
errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32547, 0x20);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((validTarget & ValidTarget.NPC) != 0 && target.currentSubState == SetActorStatePacket.SUB_STATE_NONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// todo: why is player always zoning?
|
||||||
|
// cant target if zoning
|
||||||
|
if (target is Player && ((Player)target).playerSession.isUpdatesLocked)
|
||||||
|
{
|
||||||
|
// That command cannot be performed on the current target.
|
||||||
|
errorPacket = CreateGameMessagePacket(Server.GetWorldManager().GetActor(), 32547, 0x20);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanCast(Character target, Ability spell, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!IsValidTarget(target, spell.validTarget, ref errorPacket) || !spell.IsValidTarget(this, target, ref errorPacket))
|
||||||
|
{
|
||||||
|
// error packet is set in IsValidTarget
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWeaponSkill(Character target, Ability skill, ref SubPacket errorPacket)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!IsValidTarget(target, skill.validTarget, ref errorPacket) || !skill.IsValidTarget(this, target, ref errorPacket))
|
||||||
|
{
|
||||||
|
// error packet is set in IsValidTarget
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||||||
binWriter.Seek(0x20, SeekOrigin.Begin);
|
binWriter.Seek(0x20, SeekOrigin.Begin);
|
||||||
binWriter.Write((UInt32) actionList.Length); //Num actions (always 1 for this)
|
binWriter.Write((UInt32) actionList.Length); //Num actions (always 1 for this)
|
||||||
binWriter.Write((UInt16)commandId);
|
binWriter.Write((UInt16)commandId);
|
||||||
binWriter.Write((UInt16)810); //?
|
binWriter.Write((UInt16)0x810); //?
|
||||||
|
|
||||||
binWriter.Seek(0x20, SeekOrigin.Begin);
|
binWriter.Seek(0x20, SeekOrigin.Begin);
|
||||||
foreach (BattleAction action in actionList)
|
foreach (BattleAction action in actionList)
|
||||||
|
@ -27,7 +27,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.battle
|
|||||||
binWriter.Seek(0x20, SeekOrigin.Begin);
|
binWriter.Seek(0x20, SeekOrigin.Begin);
|
||||||
binWriter.Write((UInt32) actionList.Length); //Num actions (always 1 for this)
|
binWriter.Write((UInt32) actionList.Length); //Num actions (always 1 for this)
|
||||||
binWriter.Write((UInt16)commandId);
|
binWriter.Write((UInt16)commandId);
|
||||||
binWriter.Write((UInt16)810); //?
|
binWriter.Write((UInt16)0x810); //?
|
||||||
|
|
||||||
binWriter.Seek(0x58, SeekOrigin.Begin);
|
binWriter.Seek(0x58, SeekOrigin.Begin);
|
||||||
foreach (BattleAction action in actionList)
|
foreach (BattleAction action in actionList)
|
||||||
|
@ -30,7 +30,7 @@ function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, ta
|
|||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
player.Cast(command.actorId);
|
player.Cast(command.actorId, targetActor);
|
||||||
player:endEvent();
|
player:endEvent();
|
||||||
|
|
||||||
end
|
end
|
@ -26,7 +26,10 @@ function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, ta
|
|||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
player.WeaponSkill(command.actorId);
|
if not player.aiContainer.IsEngaged() then
|
||||||
|
player.Engage(targetActor);
|
||||||
|
end;
|
||||||
|
player.WeaponSkill(command.actorId, targetActor);
|
||||||
player:endEvent();
|
player:endEvent();
|
||||||
|
|
||||||
end
|
end
|
@ -19,9 +19,9 @@ function onTrigger(player, argc, effectId, magnitude, tick, duration)
|
|||||||
player.DelHP(500);
|
player.DelHP(500);
|
||||||
|
|
||||||
effectId = tonumber(effectId) or 223180;
|
effectId = tonumber(effectId) or 223180;
|
||||||
magnitude = tonumber(magnitude) or 300;
|
magnitude = tonumber(magnitude) or 700;
|
||||||
tick = tonumber(tick) or 3;
|
tick = tonumber(tick) or 3;
|
||||||
duration = tonumber(duration) or 60;
|
duration = tonumber(duration) or 360;
|
||||||
|
|
||||||
while player.statusEffects.HasStatusEffect(effectId) do
|
while player.statusEffects.HasStatusEffect(effectId) do
|
||||||
player.statusEffects.RemoveStatusEffect(effectId);
|
player.statusEffects.RemoveStatusEffect(effectId);
|
||||||
|
@ -6,25 +6,22 @@ function onGain(target, effect)
|
|||||||
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
sender = "regen";
|
sender = "regen";
|
||||||
|
|
||||||
target.SendMessage(messageId, sender, "dicks");
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function onTick(target, effect)
|
function onTick(target, effect)
|
||||||
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
sender = "regen";
|
sender = "regen";
|
||||||
|
|
||||||
|
-- todo: actual regen effect thing
|
||||||
local ability = GetWorldManager().GetAbility(27346);
|
local ability = GetWorldManager().GetAbility(27346);
|
||||||
local anim = bit32.bxor(bit32.lshift(ability.animationType, 24), bit32.lshift(tonumber(1), 12) , 101);
|
local anim = bit32.bxor(bit32.lshift(ability.animationType, 24), bit32.lshift(tonumber(1), 12) , 101);
|
||||||
local addHp = effect.GetMagnitude();
|
local addHp = effect.GetMagnitude();
|
||||||
|
|
||||||
target.AddHP(addHp);
|
target.AddHP(addHp);
|
||||||
target.SendBattleActionX01Packet(anim, 101, 0, 0, addHp);
|
-- target.SendBattleActionX01Packet(anim, 101, 0, 0, addHp);
|
||||||
target.SendMessage(messageId, sender, string.format("ate %u dicks", addHp));
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function onLose(target, effect)
|
function onLose(target, effect)
|
||||||
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
sender = "regen";
|
sender = "regen";
|
||||||
|
|
||||||
target.SendMessage(messageId, sender, "dicks gon");
|
|
||||||
end;
|
end;
|
18
data/scripts/spells/thunder.lua
Normal file
18
data/scripts/spells/thunder.lua
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
function onSpellPrepare(caster, target, spell)
|
||||||
|
return 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onSpellStart(caster, target, spell)
|
||||||
|
return 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onSpellFinish(caster, target, spell, action)
|
||||||
|
local damage = math.random(10, 100);
|
||||||
|
print("fuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuckkk")
|
||||||
|
|
||||||
|
if target.hateContainer then
|
||||||
|
target.hateContainer.AddBaseHate(caster);
|
||||||
|
target.hateContainer.UpdateHate(caster, damage);
|
||||||
|
end;
|
||||||
|
return damage;
|
||||||
|
end;
|
Loading…
Reference in New Issue
Block a user