mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-24 05:37:46 +00:00
abilities now use correct animation id (<3 azia)
- did stuff with magicstate/attackstate - fixed status effect tick - added regen status (todo: actually populate the table and use that name instead of enum's) - added baseStats to char (todo: add bonuses and stuff on top of those, set charaWork values to the calculated ones + bonus)
This commit is contained in:
parent
88abd59ec3
commit
11bbb023d9
25 changed files with 426 additions and 235 deletions
|
@ -1884,6 +1884,7 @@ namespace FFXIVClassic_Map_Server
|
||||||
ability.effectAnimation = reader.GetUInt16(19);
|
ability.effectAnimation = reader.GetUInt16(19);
|
||||||
ability.modelAnimation = reader.GetUInt16(20);
|
ability.modelAnimation = reader.GetUInt16(20);
|
||||||
ability.animationDurationSeconds = reader.GetUInt16(21);
|
ability.animationDurationSeconds = reader.GetUInt16(21);
|
||||||
|
ability.battleAnimation = (uint)((ability.animationType << 24) | (ability.modelAnimation << 12) | (ability.effectAnimation));
|
||||||
|
|
||||||
abilities.Add(id, ability);
|
abilities.Add(id, ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@
|
||||||
<Compile Include="actors\chara\ai\state\DeathState.cs" />
|
<Compile Include="actors\chara\ai\state\DeathState.cs" />
|
||||||
<Compile Include="actors\chara\ai\state\MagicState.cs" />
|
<Compile Include="actors\chara\ai\state\MagicState.cs" />
|
||||||
<Compile Include="actors\chara\ai\state\State.cs" />
|
<Compile Include="actors\chara\ai\state\State.cs" />
|
||||||
|
<Compile Include="actors\chara\ai\state\WeaponSkillState.cs" />
|
||||||
<Compile Include="actors\chara\ai\StatusEffect.cs" />
|
<Compile Include="actors\chara\ai\StatusEffect.cs" />
|
||||||
<Compile Include="actors\chara\ai\StatusEffectContainer.cs" />
|
<Compile Include="actors\chara\ai\StatusEffectContainer.cs" />
|
||||||
<Compile Include="actors\chara\ai\TargetFind.cs" />
|
<Compile Include="actors\chara\ai\TargetFind.cs" />
|
||||||
|
|
|
@ -670,7 +670,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsFacing(target.positionX, target.positionY, angle);
|
return IsFacing(target.positionX, target.positionZ, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueuePositionUpdate(Vector3 pos)
|
public void QueuePositionUpdate(Vector3 pos)
|
||||||
|
|
|
@ -24,6 +24,14 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
|
|
||||||
class Character : Actor
|
class Character : Actor
|
||||||
{
|
{
|
||||||
|
public const int CLASSID_PUG = 2;
|
||||||
|
public const int CLASSID_GLA = 3;
|
||||||
|
public const int CLASSID_MRD = 4;
|
||||||
|
public const int CLASSID_ARC = 7;
|
||||||
|
public const int CLASSID_LNC = 8;
|
||||||
|
public const int CLASSID_THM = 22;
|
||||||
|
public const int CLASSID_CNJ = 23;
|
||||||
|
|
||||||
public const int SIZE = 0;
|
public const int SIZE = 0;
|
||||||
public const int COLORINFO = 1;
|
public const int COLORINFO = 1;
|
||||||
public const int FACEINFO = 2;
|
public const int FACEINFO = 2;
|
||||||
|
@ -77,8 +85,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
|
|
||||||
public AIContainer aiContainer;
|
public AIContainer aiContainer;
|
||||||
public StatusEffectContainer statusEffects;
|
public StatusEffectContainer statusEffects;
|
||||||
public float meleeRange;
|
|
||||||
protected uint attackDelayMs;
|
|
||||||
|
|
||||||
public CharacterTargetingAllegiance allegiance;
|
public CharacterTargetingAllegiance allegiance;
|
||||||
|
|
||||||
|
@ -86,6 +92,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
|
|
||||||
public Dictionary<Modifier, Int64> modifiers = new Dictionary<Modifier, long>();
|
public Dictionary<Modifier, Int64> modifiers = new Dictionary<Modifier, long>();
|
||||||
|
|
||||||
|
protected ushort hpBase, hpMaxBase, mpBase, mpMaxBase, tpBase;
|
||||||
|
protected BattleTemp baseStats = new BattleTemp();
|
||||||
|
public ushort currentJob;
|
||||||
|
|
||||||
public Character(uint actorID) : base(actorID)
|
public Character(uint actorID) : base(actorID)
|
||||||
{
|
{
|
||||||
//Init timer array to "notimer"
|
//Init timer array to "notimer"
|
||||||
|
@ -95,9 +105,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
this.statusEffects = new StatusEffectContainer(this);
|
this.statusEffects = new StatusEffectContainer(this);
|
||||||
|
|
||||||
// todo: move this somewhere more appropriate
|
// todo: move this somewhere more appropriate
|
||||||
attackDelayMs = 4200;
|
|
||||||
meleeRange = 2.5f;
|
|
||||||
ResetMoveSpeeds();
|
ResetMoveSpeeds();
|
||||||
|
// todo: base this on equip and shit
|
||||||
|
SetMod((uint)Modifier.AttackRange, 3);
|
||||||
|
SetMod((uint)Modifier.AttackDelay, 4200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubPacket CreateAppearancePacket()
|
public SubPacket CreateAppearancePacket()
|
||||||
|
@ -148,6 +159,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
foreach (var effect in statusEffects.GetStatusEffects())
|
foreach (var effect in statusEffects.GetStatusEffects())
|
||||||
{
|
{
|
||||||
propPacketUtil.AddProperty($"charaWork.statusShownTime[{i}]");
|
propPacketUtil.AddProperty($"charaWork.statusShownTime[{i}]");
|
||||||
|
propPacketUtil.AddProperty(String.Format("charaWork.statusShownTime[{0}]", i));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return propPacketUtil.Done();
|
return propPacketUtil.Done();
|
||||||
|
@ -192,8 +204,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
public Int64 GetMod(uint modifier)
|
public Int64 GetMod(uint modifier)
|
||||||
{
|
{
|
||||||
Int64 res;
|
Int64 res;
|
||||||
modifiers.TryGetValue((Modifier)modifier, out res);
|
if (modifiers.TryGetValue((Modifier)modifier, out res))
|
||||||
return res;
|
return res;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMod(uint modifier, Int64 val)
|
public void SetMod(uint modifier, Int64 val)
|
||||||
|
@ -253,7 +266,12 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
|
|
||||||
public virtual uint GetAttackDelayMs()
|
public virtual uint GetAttackDelayMs()
|
||||||
{
|
{
|
||||||
return attackDelayMs;
|
return (uint)GetMod((uint)Modifier.AttackDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual uint GetAttackRange()
|
||||||
|
{
|
||||||
|
return (uint)GetMod((uint)Modifier.AttackRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Engage(uint targid = 0)
|
public bool Engage(uint targid = 0)
|
||||||
|
@ -279,10 +297,23 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cast(uint spellId)
|
||||||
|
{
|
||||||
|
aiContainer.Cast(Server.GetWorldManager().GetActorInWorld(currentTarget) as Character, spellId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WeaponSkill(uint skillId)
|
||||||
|
{
|
||||||
|
aiContainer.WeaponSkill(Server.GetWorldManager().GetActorInWorld(currentTarget) as Character, skillId);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Spawn(DateTime tick)
|
public virtual void Spawn(DateTime tick)
|
||||||
{
|
{
|
||||||
// todo: reset hp/mp/tp etc here
|
// todo: reset hp/mp/tp etc here
|
||||||
RecalculateHpMpTp();
|
ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
|
||||||
|
charaWork.parameterSave.hp = charaWork.parameterSave.hpMax;
|
||||||
|
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
|
||||||
|
RecalculateStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Die(DateTime tick)
|
public virtual void Die(DateTime tick)
|
||||||
|
@ -306,47 +337,105 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
return !IsDead();
|
return !IsDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual short GetHP()
|
public short GetHP()
|
||||||
{
|
{
|
||||||
// todo:
|
// todo:
|
||||||
return charaWork.parameterSave.hp[0];
|
return charaWork.parameterSave.hp[currentJob];
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual short GetMaxHP()
|
public short GetMaxHP()
|
||||||
{
|
{
|
||||||
return charaWork.parameterSave.hpMax[0];
|
return charaWork.parameterSave.hpMax[currentJob];
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual byte GetHPP()
|
public short GetMP()
|
||||||
{
|
{
|
||||||
return (byte)(charaWork.parameterSave.hp[0] / charaWork.parameterSave.hpMax[0]);
|
return charaWork.parameterSave.mp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AddHP(short hp)
|
public ushort GetTP()
|
||||||
|
{
|
||||||
|
return tpBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short GetMaxMP()
|
||||||
|
{
|
||||||
|
return charaWork.parameterSave.mpMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetMPP()
|
||||||
|
{
|
||||||
|
return (byte)((charaWork.parameterSave.mp / charaWork.parameterSave.mpMax) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetTPP()
|
||||||
|
{
|
||||||
|
return (byte)((tpBase / 3000) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetHPP()
|
||||||
|
{
|
||||||
|
return (byte)((charaWork.parameterSave.hp[0] / charaWork.parameterSave.hpMax[0]) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: the following functions are virtuals since we want to check hidden item bonuses etc on player for certain conditions
|
||||||
|
public virtual void AddHP(int hp)
|
||||||
{
|
{
|
||||||
// todo: +/- hp and die
|
// todo: +/- hp and die
|
||||||
// todo: battlenpcs probably have way more hp?
|
// todo: battlenpcs probably have way more hp?
|
||||||
var addHp = charaWork.parameterSave.hp[0] + hp;
|
var addHp = charaWork.parameterSave.hp[currentJob] + hp;
|
||||||
addHp = addHp.Clamp(short.MinValue, charaWork.parameterSave.hpMax[0]);
|
addHp = addHp.Clamp(ushort.MinValue, charaWork.parameterSave.hpMax[currentJob]);
|
||||||
charaWork.parameterSave.hp[0] = (short)addHp;
|
charaWork.parameterSave.hp[currentJob] = (short)addHp;
|
||||||
|
|
||||||
if (charaWork.parameterSave.hp[0] < 1)
|
if (charaWork.parameterSave.hp[currentJob] < 1)
|
||||||
Die(Program.Tick);
|
Die(Program.Tick);
|
||||||
|
|
||||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void DelHP(short hp)
|
public void AddMP(int mp)
|
||||||
|
{
|
||||||
|
charaWork.parameterSave.mp = (short)(charaWork.parameterSave.mp + mp).Clamp(ushort.MinValue, charaWork.parameterSave.mpMax);
|
||||||
|
|
||||||
|
// todo: check hidden effects and shit
|
||||||
|
|
||||||
|
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddTP(int tp)
|
||||||
|
{
|
||||||
|
tpBase = (ushort)((tpBase + tp).Clamp(0, 3000));
|
||||||
|
|
||||||
|
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DelHP(int hp)
|
||||||
{
|
{
|
||||||
AddHP((short)-hp);
|
AddHP((short)-hp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: should this include stats too?
|
public void DelMP(int mp)
|
||||||
public virtual void RecalculateHpMpTp()
|
|
||||||
{
|
{
|
||||||
// legit fuck c#
|
AddMP(-mp);
|
||||||
// todo: other shit too..
|
}
|
||||||
meleeRange = GetMod((uint)Modifier.AttackRange);
|
|
||||||
|
public void DelTP(int tp)
|
||||||
|
{
|
||||||
|
AddTP(-tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CalculateBaseStats()
|
||||||
|
{
|
||||||
|
// todo: apply mods and shit here, get race/level/job and shit
|
||||||
|
// baseStats.generalParameter[ASIDHOASID] =
|
||||||
|
}
|
||||||
|
// todo: should this include stats too?
|
||||||
|
public void RecalculateStats()
|
||||||
|
{
|
||||||
|
if (GetMod((uint)Modifier.Hp) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
// todo: recalculate stats and crap
|
// todo: recalculate stats and crap
|
||||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||||
}
|
}
|
||||||
|
@ -354,7 +443,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
public virtual float GetSpeed()
|
public virtual float GetSpeed()
|
||||||
{
|
{
|
||||||
// todo: for battlenpc/player calculate speed
|
// todo: for battlenpc/player calculate speed
|
||||||
return moveSpeeds[2];
|
return moveSpeeds[2] + GetMod((uint)Modifier.Speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,16 +42,14 @@ namespace FFXIVClassic_Map_Server.actors.chara
|
||||||
ResistWater = 31, // <3 u jorge
|
ResistWater = 31, // <3 u jorge
|
||||||
AttackRange = 32,
|
AttackRange = 32,
|
||||||
Speed = 33,
|
Speed = 33,
|
||||||
|
AttackDelay = 34,
|
||||||
|
|
||||||
|
CraftProcessing = 35,
|
||||||
|
CraftMagicProcessing = 36,
|
||||||
|
CraftProcessControl = 37,
|
||||||
|
|
||||||
/* fuck off
|
HarvestPotency = 38,
|
||||||
CRAFT_PROCESSING = 30,
|
HarvestLimit = 39,
|
||||||
CRAFT_MAGIC_PROCESSING = 31,
|
HarvestRate = 40
|
||||||
CRAFT_PROCESS_CONTROL = 32,
|
|
||||||
|
|
||||||
HARVEST_POTENCY = 33,
|
|
||||||
HARVEST_LIMIT = 34,
|
|
||||||
HARVEST_RATE = 35,
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,12 +295,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
|
|
||||||
public void InternalCast(Character target, uint spellId)
|
public void InternalCast(Character target, uint spellId)
|
||||||
{
|
{
|
||||||
|
ChangeState(new MagicState(owner, target, (ushort)spellId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InternalWeaponSkill(Character target, uint weaponSkillId)
|
public void InternalWeaponSkill(Character target, uint weaponSkillId)
|
||||||
{
|
{
|
||||||
|
ChangeState(new WeaponSkillState(owner, target, (ushort)weaponSkillId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InternalMobSkill(Character target, uint mobSkillId)
|
public void InternalMobSkill(Character target, uint mobSkillId)
|
||||||
|
@ -310,7 +310,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
|
|
||||||
public void InternalDie(DateTime tick, uint timeToFadeout)
|
public void InternalDie(DateTime tick, uint timeToFadeout)
|
||||||
{
|
{
|
||||||
if (true) return;
|
|
||||||
ClearStates();
|
ClearStates();
|
||||||
Disengage();
|
Disengage();
|
||||||
ForceChangeState(new DeathState(owner, tick, timeToFadeout));
|
ForceChangeState(new DeathState(owner, tick, timeToFadeout));
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using FFXIVClassic_Map_Server.actors.chara.player;
|
||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
|
|
||||||
class Ability
|
class Ability
|
||||||
{
|
{
|
||||||
public ushort abilityId;
|
public ushort id;
|
||||||
public string name;
|
public string name;
|
||||||
public byte job;
|
public byte job;
|
||||||
public byte level;
|
public byte level;
|
||||||
|
@ -65,14 +66,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
public ushort modelAnimation;
|
public ushort modelAnimation;
|
||||||
public ushort animationDurationSeconds;
|
public ushort animationDurationSeconds;
|
||||||
|
|
||||||
|
public uint battleAnimation;
|
||||||
|
public ushort worldMasterTextId;
|
||||||
|
public uint param;
|
||||||
|
|
||||||
public TargetFind targetFind;
|
public TargetFind targetFind;
|
||||||
|
|
||||||
public Ability(ushort id, string name)
|
public Ability(ushort id, string name)
|
||||||
{
|
{
|
||||||
this.abilityId = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.range = -1;
|
this.range = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ability Clone()
|
public Ability Clone()
|
||||||
|
@ -90,10 +94,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
return castTimeSeconds == 0;
|
return castTimeSeconds == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanPlayerUse(Character user, Character target)
|
public bool IsValidTarget(Character user, Character target)
|
||||||
{
|
{
|
||||||
// todo: set box length..
|
// todo: set box length..
|
||||||
targetFind = new TargetFind(user);
|
targetFind = new TargetFind(user);
|
||||||
|
|
||||||
if (aoeType == TargetFindAOEType.Box)
|
if (aoeType == TargetFindAOEType.Box)
|
||||||
{
|
{
|
||||||
// todo: read box width from sql
|
// todo: read box width from sql
|
||||||
|
@ -103,7 +108,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
targetFind.SetAOEType(validTarget, aoeType, range, 40);
|
targetFind.SetAOEType(validTarget, aoeType, range, 40);
|
||||||
}
|
}
|
||||||
return false;
|
return targetFind.CanTarget(target, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
var dest = owner.FindRandomPoint(x, y, z, minRange, maxRange);
|
var dest = owner.FindRandomPoint(x, y, z, minRange, maxRange);
|
||||||
// todo: this is dumb..
|
// todo: this is dumb..
|
||||||
distanceFromPoint = owner.meleeRange;
|
distanceFromPoint = owner.GetAttackRange();
|
||||||
PreparePath(dest.X, dest.Y, dest.Z);
|
PreparePath(dest.X, dest.Y, dest.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,14 +148,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
float speed = GetSpeed();
|
float speed = GetSpeed();
|
||||||
|
|
||||||
float stepDistance = speed;
|
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.X, point.Y);
|
||||||
|
|
||||||
if (distanceTo <= distanceFromPoint + stepDistance)
|
if (distanceTo <= distanceFromPoint + stepDistance)
|
||||||
{
|
{
|
||||||
if (distanceFromPoint <= 1.5f)
|
if (distanceFromPoint <= owner.GetAttackRange())
|
||||||
{
|
{
|
||||||
owner.QueuePositionUpdate(point);
|
owner.QueuePositionUpdate(point);
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,7 +419,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
public bool Update(DateTime tick)
|
public bool Update(DateTime tick)
|
||||||
{
|
{
|
||||||
// todo: maybe not tick if already reached duration?
|
// todo: maybe not tick if already reached duration?
|
||||||
if (tickMs != 0 && (lastTick - startTime).TotalMilliseconds >= tickMs)
|
if (tickMs != 0 && (tick - lastTick).TotalMilliseconds >= tickMs)
|
||||||
{
|
{
|
||||||
// todo: call effect's onTick
|
// todo: call effect's onTick
|
||||||
// todo: maybe keep a global lua object instead of creating a new one each time we wanna call a script
|
// todo: maybe keep a global lua object instead of creating a new one each time we wanna call a script
|
||||||
|
@ -443,7 +443,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
|
|
||||||
public Character GetSource()
|
public Character GetSource()
|
||||||
{
|
{
|
||||||
return source;
|
return source ?? owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetStatusEffectId()
|
public uint GetStatusEffectId()
|
||||||
|
|
|
@ -46,18 +46,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
|
|
||||||
if (sendUpdate)
|
if (sendUpdate)
|
||||||
{
|
{
|
||||||
var propPacketUtil = new ActorPropertyPacketUtil("charaWork.status", owner);
|
owner.zone.BroadcastPacketsAroundActor(owner, owner.GetActorStatusPackets());
|
||||||
|
|
||||||
//Status Times
|
|
||||||
for (int i = 0; i < owner.charaWork.statusShownTime.Length; i++)
|
|
||||||
{
|
|
||||||
if (owner.charaWork.status[i] != 0xFFFF && owner.charaWork.status[i] != 0)
|
|
||||||
propPacketUtil.AddProperty(String.Format("charaWork.status[{0}]", i));
|
|
||||||
|
|
||||||
if (owner.charaWork.statusShownTime[i] != 0xFFFFFFFF)
|
|
||||||
propPacketUtil.AddProperty(String.Format("charaWork.statusShownTime[{0}]", i));
|
|
||||||
}
|
|
||||||
owner.zone.BroadcastPacketsAroundActor(owner, propPacketUtil.Done());
|
|
||||||
sendUpdate = false;
|
sendUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +86,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
// todo: send packet to client with effect added message
|
// todo: send packet to client with effect added message
|
||||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
player.QueuePacket(packets.send.actor.battle.BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, owner.actorId, 0, newEffect.GetStatusEffectId(), 0, newEffect.GetStatusId(), 0, 0));
|
player.QueuePacket(packets.send.actor.battle.BattleActionX01Packet.BuildPacket(player.actorId, newEffect.GetSource().actorId, newEffect.GetOwner().actorId, 0x7678, 0, 0, newEffect.GetStatusId(), 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// wont send a message about losing effect here
|
// wont send a message about losing effect here
|
||||||
|
@ -115,8 +104,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
owner.charaWork.statusShownTime[index] = Utils.UnixTimeStampUTC() + (newEffect.GetDurationMs() / 1000);
|
owner.charaWork.statusShownTime[index] = Utils.UnixTimeStampUTC() + (newEffect.GetDurationMs() / 1000);
|
||||||
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(this.owner.actorId, (ushort)index, (ushort)newEffect.GetStatusId()));
|
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(this.owner.actorId, (ushort)index, (ushort)newEffect.GetStatusId()));
|
||||||
}
|
}
|
||||||
owner.RecalculateHpMpTp();
|
{
|
||||||
sendUpdate = true;
|
owner.zone.BroadcastPacketsAroundActor(owner, owner.GetActorStatusPackets());
|
||||||
|
}
|
||||||
|
owner.RecalculateStats();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -130,9 +121,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
// send packet to client with effect remove message
|
// send packet to client with effect remove message
|
||||||
if (!silent || !effect.GetSilent() || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
if (!silent || !effect.GetSilent() || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
||||||
{
|
{
|
||||||
// todo: send packet to client with effect removed message
|
// todo: send packet to client with effect added message
|
||||||
//foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
// player.QueuePacket(packets.send.actor.battle.BattleActionX01Packet.BuildPacket(player.actorId, effect.GetSource().actorId, owner.actorId, 0, effect.GetStatusEffectId(), 0, effect.GetStatusId(), 0, 0));
|
player.QueuePacket(packets.send.actor.battle.BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, owner.actorId, 0x7679, 0, 0, effect.GetStatusId(), 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: this is retarded..
|
// todo: this is retarded..
|
||||||
|
@ -145,7 +136,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
// function onLose(actor, effect)
|
// function onLose(actor, effect)
|
||||||
LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect);
|
LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect);
|
||||||
effects.Remove(effect.GetStatusEffectId());
|
effects.Remove(effect.GetStatusEffectId());
|
||||||
owner.RecalculateHpMpTp();
|
owner.RecalculateStats();
|
||||||
sendUpdate = true;
|
sendUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||||
if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > 10)
|
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.SetPathFlags(PathFindFlags.None);
|
||||||
owner.aiContainer.pathFind.PathInRange(target.positionX, target.positionY, target.positionZ, 1.5f, owner.meleeRange);
|
owner.aiContainer.pathFind.PathInRange(target.positionX, target.positionY, target.positionZ, 1.5f, owner.GetAttackRange());
|
||||||
ChangeTarget(target);
|
ChangeTarget(target);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -114,22 +114,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||||
|
|
||||||
public override void Cast(Character target, uint spellId)
|
public override void Cast(Character target, uint spellId)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Ability(Character target, uint abilityId)
|
public override void Ability(Character target, uint abilityId)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RangedAttack(Character target)
|
public override void RangedAttack(Character target)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MonsterSkill(Character target, uint mobSkillId)
|
public override void MonsterSkill(Character target, uint mobSkillId)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoRoamTick(DateTime tick)
|
private void DoRoamTick(DateTime tick)
|
||||||
|
@ -202,7 +202,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||||
var targetPos = new Vector3(owner.target.positionX, owner.target.positionY, owner.target.positionZ);
|
var targetPos = new Vector3(owner.target.positionX, owner.target.positionY, owner.target.positionZ);
|
||||||
var distance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, targetPos.X, targetPos.Y, targetPos.Z);
|
var distance = Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, targetPos.X, targetPos.Y, targetPos.Z);
|
||||||
|
|
||||||
if (distance > owner.meleeRange - 0.2f || owner.aiContainer.CanFollowPath())
|
if (distance > owner.GetAttackRange() - 0.2f || owner.aiContainer.CanFollowPath())
|
||||||
{
|
{
|
||||||
if (CanMoveForward(distance))
|
if (CanMoveForward(distance))
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||||
|
|
||||||
public override void Cast(Character target, uint spellId)
|
public override void Cast(Character target, uint spellId)
|
||||||
{
|
{
|
||||||
|
owner.aiContainer.InternalCast(target, spellId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Ability(Character target, uint abilityId)
|
public override void Ability(Character target, uint abilityId)
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
player.QueuePacket(packet);
|
player.QueuePacket(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//target.DelHP((short)damage);
|
target.DelHP((short)damage);
|
||||||
attackTime = attackTime.AddMilliseconds(owner.GetAttackDelayMs());
|
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);
|
||||||
|
@ -150,9 +150,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// todo: use a mod for melee range
|
// todo: use a mod for melee range
|
||||||
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > owner.meleeRange)
|
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > owner.GetAttackRange())
|
||||||
{
|
{
|
||||||
//owner.aiContainer.GetpathFind?.PreparePath(target.positionX, target.positionY, target.positionZ, 2.5f, 4);
|
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||||
|
{
|
||||||
|
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||||
{
|
{
|
||||||
// todo: mark for zoning and remove after main loop
|
// todo: mark for zoning and remove after main loop
|
||||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_PASSIVE);
|
owner.Spawn(Program.Tick);
|
||||||
//Server.GetWorldManager().DoZoneChange(((Player)owner), 244, null, 0, 15, -160.048f, 0, -165.737f, 0.0f);
|
//Server.GetWorldManager().DoZoneChange(((Player)owner), 244, null, 0, 15, -160.048f, 0, -165.737f, 0.0f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,6 +13,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
{
|
{
|
||||||
|
|
||||||
private Ability spell;
|
private Ability spell;
|
||||||
|
private uint cost;
|
||||||
|
private Vector3 startPos;
|
||||||
|
|
||||||
public MagicState(Character owner, Character target, ushort spellId) :
|
public MagicState(Character owner, Character target, ushort spellId) :
|
||||||
base(owner, target)
|
base(owner, target)
|
||||||
|
@ -20,53 +22,132 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
this.startTime = DateTime.Now;
|
this.startTime = DateTime.Now;
|
||||||
// todo: lookup spell from global table
|
// todo: lookup spell from global table
|
||||||
this.spell = Server.GetWorldManager().GetAbility(spellId);
|
this.spell = Server.GetWorldManager().GetAbility(spellId);
|
||||||
|
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellPrepare", owner, target, spell);
|
||||||
|
|
||||||
if (spell != null)
|
if (spell != null && returnCode == 0)
|
||||||
{
|
{
|
||||||
if (spell.CanPlayerUse(owner, target))
|
// todo: hp/mp shit should be taken care of in scripts, not here
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// todo: fuckin retarded. enum log messages somewhere (prolly isnt even right param)
|
||||||
|
if (owner is Player)
|
||||||
|
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), (ushort)(returnCode == -1 ? 32539 : returnCode), 0x20);
|
||||||
|
interrupt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStart()
|
public override void OnStart()
|
||||||
{
|
{
|
||||||
// todo: check within attack range
|
var returnCode = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellStart", owner, target, spell);
|
||||||
|
|
||||||
owner.LookAt(target);
|
if (returnCode != 0)
|
||||||
|
{
|
||||||
|
interrupt = true;
|
||||||
|
errorPacket = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, owner.actorId, 0, 0, (ushort)(returnCode == -1 ? 32539 : returnCode), spell.id, 0, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// todo: check within attack range
|
||||||
|
startPos = owner.GetPosAsVector3();
|
||||||
|
owner.LookAt(target);
|
||||||
|
|
||||||
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
|
{
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Update(DateTime tick)
|
public override bool Update(DateTime tick)
|
||||||
{
|
{
|
||||||
TryInterrupt();
|
if (spell != null)
|
||||||
|
|
||||||
if (interrupt)
|
|
||||||
{
|
{
|
||||||
OnInterrupt();
|
TryInterrupt();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: check weapon delay/haste etc and use that
|
if (interrupt)
|
||||||
if ((tick - startTime).TotalMilliseconds >= 0)
|
{
|
||||||
{
|
OnInterrupt();
|
||||||
OnComplete();
|
return true;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
// todo: check weapon delay/haste etc and use that
|
||||||
|
var actualCastTime = spell.castTimeSeconds;
|
||||||
|
|
||||||
|
if ((tick - startTime).TotalSeconds >= spell.castTimeSeconds)
|
||||||
|
{
|
||||||
|
OnComplete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInterrupt()
|
public override void OnInterrupt()
|
||||||
{
|
{
|
||||||
// todo: send paralyzed/sleep message etc.
|
// todo: send paralyzed/sleep message etc.
|
||||||
|
if (errorPacket != null)
|
||||||
|
{
|
||||||
|
owner.zone.BroadcastPacketAroundActor(owner, errorPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnComplete()
|
public override void OnComplete()
|
||||||
{
|
{
|
||||||
//this.errorPacket = BattleActionX01Packet.BuildPacket(target.actorId, owner.actorId, target.actorId, 0, effectId, 0, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, 0);
|
spell.targetFind.FindWithinArea(target, spell.validTarget);
|
||||||
isCompleted = true;
|
isCompleted = true;
|
||||||
|
|
||||||
|
List<SubPacket> packets = new List<SubPacket>();
|
||||||
|
foreach (var chara in spell.targetFind.GetTargets())
|
||||||
|
{
|
||||||
|
// todo: calculate shit, do shit
|
||||||
|
bool landed = true;
|
||||||
|
var amount = lua.LuaEngine.CallLuaAbilityFunction(owner, spell, "spells", "onSpellFinish", owner, target, spell);
|
||||||
|
|
||||||
|
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||||
|
{
|
||||||
|
player.QueuePacket(BattleActionX01Packet.BuildPacket(player.actorId, owner.actorId, chara.actorId, spell.battleAnimation, spell.effectAnimation, spell.worldMasterTextId, spell.id, (ushort)spell.param, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chara is BattleNpc)
|
||||||
|
{
|
||||||
|
((BattleNpc)chara).hateContainer.UpdateHate(owner, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void TryInterrupt()
|
public override void TryInterrupt()
|
||||||
{
|
{
|
||||||
|
if (interrupt)
|
||||||
|
return;
|
||||||
|
|
||||||
if (owner.statusEffects.HasStatusEffectsByFlag((uint)StatusEffectFlags.PreventAction))
|
if (owner.statusEffects.HasStatusEffectsByFlag((uint)StatusEffectFlags.PreventAction))
|
||||||
{
|
{
|
||||||
// todo: sometimes paralyze can let you attack, get random percentage of actually letting you attack
|
// todo: sometimes paralyze can let you attack, get random percentage of actually letting you attack
|
||||||
|
@ -85,10 +166,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupt = !CanAttack();
|
if (Utils.DistanceSquared(owner.GetPosAsVector3(), startPos) > 4.0f)
|
||||||
|
{
|
||||||
|
// todo: send interrupt packet
|
||||||
|
interrupt = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt = !CanCast();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanAttack()
|
private bool CanCast()
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
{
|
{
|
||||||
|
@ -103,9 +191,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) >= 7.5f)
|
else if (Utils.Distance(owner.positionX, owner.positionY, owner.positionZ, target.positionX, target.positionY, target.positionZ) > spell.range)
|
||||||
{
|
{
|
||||||
owner.aiContainer.pathFind?.PreparePath(target.positionX, target.positionY, target.positionZ, 2.5f, 4);
|
if (owner.currentSubState == SetActorStatePacket.SUB_STATE_PLAYER)
|
||||||
|
{
|
||||||
|
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32539, 0x20);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -23,5 +23,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.utils
|
||||||
}
|
}
|
||||||
defender.DelHP((short)damage);
|
defender.DelHP((short)damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int CalculateSpellDamage(Character attacker, Character defender, Ability spell)
|
||||||
|
{
|
||||||
|
// todo: spell formulas and stuff (stoneskin, mods, stats, etc)
|
||||||
|
return 69;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
aggroType = AggroType.Sight;
|
aggroType = AggroType.Sight;
|
||||||
this.moveState = 2;
|
this.moveState = 2;
|
||||||
ResetMoveSpeeds();
|
ResetMoveSpeeds();
|
||||||
this.meleeRange = 1.5f;
|
|
||||||
despawnTime = 10;
|
despawnTime = 10;
|
||||||
|
|
||||||
|
CalculateBaseStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(DateTime tick)
|
public override void Update(DateTime tick)
|
||||||
|
@ -85,7 +86,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
propPacketUtil.AddProperty("charaWork.battleTemp.castGauge_speed[1]");
|
propPacketUtil.AddProperty("charaWork.battleTemp.castGauge_speed[1]");
|
||||||
packets.AddRange(propPacketUtil.Done());
|
packets.AddRange(propPacketUtil.Done());
|
||||||
}
|
}
|
||||||
base.PostUpdate(tick);
|
base.PostUpdate(tick, packets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanAttack()
|
public override bool CanAttack()
|
||||||
|
|
|
@ -26,14 +26,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
{
|
{
|
||||||
class Player : Character
|
class Player : Character
|
||||||
{
|
{
|
||||||
public const int CLASSID_PUG = 2;
|
|
||||||
public const int CLASSID_GLA = 3;
|
|
||||||
public const int CLASSID_MRD = 4;
|
|
||||||
public const int CLASSID_ARC = 7;
|
|
||||||
public const int CLASSID_LNC = 8;
|
|
||||||
public const int CLASSID_THM = 22;
|
|
||||||
public const int CLASSID_CNJ = 23;
|
|
||||||
|
|
||||||
public const int CLASSID_CRP = 29;
|
public const int CLASSID_CRP = 29;
|
||||||
public const int CLASSID_BSM = 30;
|
public const int CLASSID_BSM = 30;
|
||||||
public const int CLASSID_ARM = 31;
|
public const int CLASSID_ARM = 31;
|
||||||
|
@ -97,7 +89,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
public uint destinationZone;
|
public uint destinationZone;
|
||||||
public ushort destinationSpawnType;
|
public ushort destinationSpawnType;
|
||||||
public uint[] timers = new uint[20];
|
public uint[] timers = new uint[20];
|
||||||
public ushort currentJob;
|
|
||||||
public uint currentTitle;
|
public uint currentTitle;
|
||||||
public uint playTime;
|
public uint playTime;
|
||||||
public uint lastPlayTimeUpdate;
|
public uint lastPlayTimeUpdate;
|
||||||
|
@ -1729,30 +1720,15 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
packets.AddRange(propPacketUtil.Done());
|
packets.AddRange(propPacketUtil.Done());
|
||||||
}
|
}
|
||||||
|
|
||||||
base.PostUpdate(tick);
|
base.PostUpdate(tick, packets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override short GetHP()
|
public override void AddHP(int hp)
|
||||||
{
|
|
||||||
return charaWork.parameterSave.hp[currentJob];
|
|
||||||
}
|
|
||||||
|
|
||||||
public override short GetMaxHP()
|
|
||||||
{
|
|
||||||
return charaWork.parameterSave.hpMax[currentJob];
|
|
||||||
}
|
|
||||||
|
|
||||||
public override byte GetHPP()
|
|
||||||
{
|
|
||||||
return (byte)(charaWork.parameterSave.hp[currentJob] / charaWork.parameterSave.hpMax[currentJob]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddHP(short hp)
|
|
||||||
{
|
{
|
||||||
// todo: +/- hp and die
|
// todo: +/- hp and die
|
||||||
// todo: battlenpcs probably have way more hp?
|
// todo: check hidden effects and shit
|
||||||
var addHp = charaWork.parameterSave.hp[currentJob] + hp;
|
var addHp = charaWork.parameterSave.hp[currentJob] + hp;
|
||||||
addHp = addHp.Clamp(short.MinValue, charaWork.parameterSave.hpMax[currentJob]);
|
addHp = addHp.Clamp(ushort.MinValue, charaWork.parameterSave.hpMax[currentJob]);
|
||||||
charaWork.parameterSave.hp[currentJob] = (short)addHp;
|
charaWork.parameterSave.hp[currentJob] = (short)addHp;
|
||||||
|
|
||||||
if (charaWork.parameterSave.hp[currentJob] < 1)
|
if (charaWork.parameterSave.hp[currentJob] < 1)
|
||||||
|
@ -1761,17 +1737,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DelHP(short hp)
|
|
||||||
{
|
|
||||||
AddHP((short)-hp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: should this include stats too?
|
|
||||||
public override void RecalculateHpMpTp()
|
|
||||||
{
|
|
||||||
// todo: recalculate stats and crap
|
|
||||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Die(DateTime tick)
|
public override void Die(DateTime tick)
|
||||||
{
|
{
|
||||||
|
@ -1833,7 +1798,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
QueuePackets(recastPacketUtil.Done());
|
QueuePackets(recastPacketUtil.Done());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void EquipAbility(ushort hotbarSlot, ushort commandId)
|
public void EquipAbility(ushort hotbarSlot, ushort commandId)
|
||||||
{
|
{
|
||||||
//if (charaWork.commandAcquired[commandId])
|
//if (charaWork.commandAcquired[commandId])
|
||||||
|
@ -1947,7 +1911,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||||
|
|
||||||
public void SendBattleActionX01Packet(uint anim, uint effect, uint text = 0x756D, uint command = 27260, uint param = 0x01, uint idek = 0x01)
|
public void SendBattleActionX01Packet(uint anim, uint effect, uint text = 0x756D, uint command = 27260, uint param = 0x01, uint idek = 0x01)
|
||||||
{
|
{
|
||||||
var packet = BattleActionX01Packet.BuildPacket(actorId, actorId, actorId, (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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,8 @@ namespace FFXIVClassic_Map_Server.lua
|
||||||
|
|
||||||
public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args)
|
public static int CallLuaStatusEffectFunction(Character actor, StatusEffect effect, string functionName, params object[] args)
|
||||||
{
|
{
|
||||||
string path = $"./scripts/effects/{effect.GetName()}.lua";
|
var name = ((StatusEffectId)effect.GetStatusEffectId()).ToString().ToLower();
|
||||||
|
string path = $"./scripts/effects/{name}.lua";
|
||||||
|
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
|
@ -186,7 +187,36 @@ namespace FFXIVClassic_Map_Server.lua
|
||||||
if (!script.Globals.Get(functionName).IsNil())
|
if (!script.Globals.Get(functionName).IsNil())
|
||||||
{
|
{
|
||||||
res = script.Call(script.Globals.Get(functionName), args);
|
res = script.Call(script.Globals.Get(functionName), args);
|
||||||
return (int)res.Number;
|
if (res != null)
|
||||||
|
return (int)res.Number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int CallLuaAbilityFunction(Character actor, Ability ability, string folder, string functionName, params object[] args)
|
||||||
|
{
|
||||||
|
string path = $"./scripts/{folder}/{ability.name}.lua";
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var script = LoadGlobals();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
script.DoFile(path);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Program.Log.Error($"LuaEngine.CallLuaSpellFunction [{functionName}] {e.Message}");
|
||||||
|
}
|
||||||
|
DynValue res = new DynValue();
|
||||||
|
|
||||||
|
if (!script.Globals.Get(functionName).IsNil())
|
||||||
|
{
|
||||||
|
res = script.Call(script.Globals.Get(functionName), args);
|
||||||
|
if (res != null)
|
||||||
|
return (int)res.Number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -11,6 +11,7 @@ Switches between active and passive mode states
|
||||||
function onEventStarted(player, command, triggerName)
|
function onEventStarted(player, command, triggerName)
|
||||||
|
|
||||||
if (player:GetState() == 0) then
|
if (player:GetState() == 0) then
|
||||||
|
player.ChangeState(2);
|
||||||
player.Engage();
|
player.Engage();
|
||||||
elseif (player:GetState() == 2) then
|
elseif (player:GetState() == 2) then
|
||||||
player:ChangeState(0);
|
player:ChangeState(0);
|
||||||
|
|
36
data/scripts/commands/AttackMagic.lua
Normal file
36
data/scripts/commands/AttackMagic.lua
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
require ("global")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
AttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
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);
|
||||||
|
player:endEvent();
|
||||||
|
|
||||||
|
end
|
|
@ -9,80 +9,6 @@ Finds the correct weaponskill subscript to fire when a weaponskill actor is acti
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local function handlePummel(player, target)
|
|
||||||
player:SendMessage(0x20, "", "DOING PUMMEL!!!!");
|
|
||||||
|
|
||||||
params = {};
|
|
||||||
params.range = 10.0;
|
|
||||||
params.recast = 10;
|
|
||||||
|
|
||||||
params.hpCost = 0;
|
|
||||||
params.mpCost = 0;
|
|
||||||
params.tpCost = 1000;
|
|
||||||
|
|
||||||
params.targetType = 2;
|
|
||||||
params.canCrit = true;
|
|
||||||
params.animationId = 0x12312312;
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function handleSkullSunder(player)
|
|
||||||
player:SendMessage(0x20, "", "DOING SKULL SUNDER!!!!");
|
|
||||||
end
|
|
||||||
|
|
||||||
local weaponskillHandlers = {
|
|
||||||
[0xA0F069E6] = handlePummel,
|
|
||||||
[0xA0F069E7] = nil,
|
|
||||||
[0xA0F069E8] = nil,
|
|
||||||
[0xA0F069E9] = nil,
|
|
||||||
[0xA0F069EA] = nil,
|
|
||||||
[0xA0F069EB] = nil,
|
|
||||||
[0xA0F069EC] = nil,
|
|
||||||
[0xA0F069ED] = nil,
|
|
||||||
[0xA0F069EE] = nil,
|
|
||||||
[0xA0F069EF] = nil,
|
|
||||||
[0xA0F06A0E] = nil,
|
|
||||||
[0xA0F06A0F] = nil,
|
|
||||||
[0xA0F06A10] = nil,
|
|
||||||
[0xA0F06A11] = nil,
|
|
||||||
[0xA0F06A12] = nil,
|
|
||||||
[0xA0F06A13] = nil,
|
|
||||||
[0xA0F06A14] = nil,
|
|
||||||
[0xA0F06A15] = nil,
|
|
||||||
[0xA0F06A16] = nil,
|
|
||||||
[0xA0F06A17] = nil,
|
|
||||||
[0xA0F06A36] = nil,
|
|
||||||
[0xA0F06A37] = handleSkullSunder,
|
|
||||||
[0xA0F06A38] = nil,
|
|
||||||
[0xA0F06A39] = nil,
|
|
||||||
[0xA0F06A3A] = nil,
|
|
||||||
[0xA0F06A3B] = nil,
|
|
||||||
[0xA0F06A3C] = nil,
|
|
||||||
[0xA0F06A3D] = nil,
|
|
||||||
[0xA0F06A3E] = nil,
|
|
||||||
[0xA0F06A3F] = nil,
|
|
||||||
[0xA0F06A5C] = nil,
|
|
||||||
[0xA0F06A5D] = nil,
|
|
||||||
[0xA0F06A5E] = nil,
|
|
||||||
[0xA0F06A60] = nil,
|
|
||||||
[0xA0F06A61] = nil,
|
|
||||||
[0xA0F06A62] = nil,
|
|
||||||
[0xA0F06A63] = nil,
|
|
||||||
[0xA0F06A64] = nil,
|
|
||||||
[0xA0F06A85] = nil,
|
|
||||||
[0xA0F06A86] = nil,
|
|
||||||
[0xA0F06A87] = nil,
|
|
||||||
[0xA0F06A88] = nil,
|
|
||||||
[0xA0F06A89] = nil,
|
|
||||||
[0xA0F06A8A] = nil,
|
|
||||||
[0xA0F06A8B] = nil,
|
|
||||||
[0xA0F06A8C] = nil,
|
|
||||||
[0xA0F06A8D] = nil,
|
|
||||||
[0xA0F06A8E] = nil,
|
|
||||||
[0xA0F06A8F] = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
|
||||||
--Are they in active mode?
|
--Are they in active mode?
|
||||||
|
@ -100,19 +26,7 @@ function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, ta
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
--Are you too far away?
|
player.WeaponSkill(command.actorId);
|
||||||
if (getDistanceBetweenActors(player, target) > 7) then
|
|
||||||
player:SendGameMessage(GetWorldMaster(), 32539, 0x20);
|
|
||||||
player:endEvent();
|
|
||||||
return;
|
|
||||||
end
|
|
||||||
|
|
||||||
if (weaponskillHandlers[command.actorId] ~= nil) then
|
|
||||||
weaponskillHandlers[command.actorId](player);
|
|
||||||
else
|
|
||||||
player:SendMessage(0x20, "", "That weaponskill is not implemented yet.");
|
|
||||||
end
|
|
||||||
|
|
||||||
player:endEvent();
|
player:endEvent();
|
||||||
|
|
||||||
end
|
end
|
31
data/scripts/commands/gm/effect.lua
Normal file
31
data/scripts/commands/gm/effect.lua
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
require("global");
|
||||||
|
require("bit32");
|
||||||
|
|
||||||
|
properties = {
|
||||||
|
permissions = 0,
|
||||||
|
parameters = "iiii",
|
||||||
|
description =
|
||||||
|
[[
|
||||||
|
effect
|
||||||
|
]],
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTrigger(player, argc, effectId, magnitude, tick, duration)
|
||||||
|
local messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
local sender = "effect";
|
||||||
|
|
||||||
|
if player then
|
||||||
|
player.AddHP(100000);
|
||||||
|
player.DelHP(500);
|
||||||
|
|
||||||
|
effectId = tonumber(effectId) or 223180;
|
||||||
|
magnitude = tonumber(magnitude) or 300;
|
||||||
|
tick = tonumber(tick) or 3;
|
||||||
|
duration = tonumber(duration) or 60;
|
||||||
|
|
||||||
|
while player.statusEffects.HasStatusEffect(effectId) do
|
||||||
|
player.statusEffects.RemoveStatusEffect(effectId);
|
||||||
|
end;
|
||||||
|
player.statusEffects.AddStatusEffect(effectId, magnitude, tick, duration);
|
||||||
|
end;
|
||||||
|
end;
|
30
data/scripts/effects/regen.lua
Normal file
30
data/scripts/effects/regen.lua
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
require("global")
|
||||||
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
sender = "regen";
|
||||||
|
|
||||||
|
function onGain(target, effect)
|
||||||
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
sender = "regen";
|
||||||
|
|
||||||
|
target.SendMessage(messageId, sender, "dicks");
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onTick(target, effect)
|
||||||
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
sender = "regen";
|
||||||
|
|
||||||
|
local ability = GetWorldManager().GetAbility(27346);
|
||||||
|
local anim = bit32.bxor(bit32.lshift(ability.animationType, 24), bit32.lshift(tonumber(1), 12) , 101);
|
||||||
|
local addHp = effect.GetMagnitude();
|
||||||
|
|
||||||
|
target.AddHP(addHp);
|
||||||
|
target.SendBattleActionX01Packet(anim, 101, 0, 0, addHp);
|
||||||
|
target.SendMessage(messageId, sender, string.format("ate %u dicks", addHp));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onLose(target, effect)
|
||||||
|
messageId = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
sender = "regen";
|
||||||
|
|
||||||
|
target.SendMessage(messageId, sender, "dicks gon");
|
||||||
|
end;
|
|
@ -82,7 +82,7 @@ INSERT INTO `abilities` VALUES (27142,'rampart',3,2,3,1,0,1,0,2,5,0,60,0,0,120,0
|
||||||
INSERT INTO `abilities` VALUES (27143,'tempered_will',3,42,8,1,0,1,0,0,5,0,20,0,0,180,0,0,14,515,2,2);
|
INSERT INTO `abilities` VALUES (27143,'tempered_will',3,42,8,1,0,1,0,0,5,0,20,0,0,180,0,0,14,515,2,2);
|
||||||
INSERT INTO `abilities` VALUES (27144,'outmaneuver',3,34,8,1,0,1,0,0,5,0,30,0,0,90,0,0,14,512,21,2);
|
INSERT INTO `abilities` VALUES (27144,'outmaneuver',3,34,8,1,0,1,0,0,5,0,30,0,0,90,0,0,14,512,21,2);
|
||||||
INSERT INTO `abilities` VALUES (27145,'flash',3,14,3,32,0,1,0,0,5,0,0,0,0,30,0,0,14,696,2,2);
|
INSERT INTO `abilities` VALUES (27145,'flash',3,14,3,32,0,1,0,0,5,0,0,0,0,30,0,0,14,696,2,2);
|
||||||
INSERT INTO `abilities` VALUES (27146,'cover',16,30,0,0,0,1,0,0,5,0,15,0,0,60,0,0,14,1,2,2);
|
INSERT INTO `abilities` VALUES (27146,'cover',16,30,0,0,0,1,0,0,5,0,15,0,0,60,0,0,14,725,2,2);
|
||||||
INSERT INTO `abilities` VALUES (27147,'divine_veil',16,35,0,0,0,1,0,0,5,0,20,0,0,60,0,0,14,713,2,2);
|
INSERT INTO `abilities` VALUES (27147,'divine_veil',16,35,0,0,0,1,0,0,5,0,20,0,0,60,0,0,14,713,2,2);
|
||||||
INSERT INTO `abilities` VALUES (27148,'hallowed_ground',16,50,0,0,0,1,0,0,5,0,0,0,0,900,0,0,14,709,2,2);
|
INSERT INTO `abilities` VALUES (27148,'hallowed_ground',16,50,0,0,0,1,0,0,5,0,0,0,0,900,0,0,14,709,2,2);
|
||||||
INSERT INTO `abilities` VALUES (27149,'holy_succor',16,40,0,0,0,1,0,0,15,0,0,0,2,10,100,0,1,701,1,2);
|
INSERT INTO `abilities` VALUES (27149,'holy_succor',16,40,0,0,0,1,0,0,15,0,0,0,2,10,100,0,1,701,1,2);
|
||||||
|
|
Loading…
Add table
Reference in a new issue