mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-05-20 08:26:59 -04:00
added mob name colour update
- added mobmods (need to be loaded from db) - added Zone.GetBattleNpcById - added missing IsValidTarget check in AttackState
This commit is contained in:
@@ -159,7 +159,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/currentContentGroup", this);
|
||||
propPacketUtil.AddProperty("charaWork.currentContentGroup");
|
||||
zone.BroadcastPacketsAroundActor(this, propPacketUtil.Done());
|
||||
|
||||
}
|
||||
|
||||
public List<SubPacket> GetActorStatusPackets()
|
||||
@@ -593,6 +592,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
//var packet = BattleActionX01Packet.BuildPacket(owner.actorId, owner.actorId, target.actorId, (uint)0x19001000, (uint)0x8000604, (ushort)0x765D, (ushort)BattleActionX01PacketCommand.Attack, (ushort)damage, (byte)0x1);
|
||||
}
|
||||
|
||||
target.OnDamageTaken(this, action);
|
||||
// todo: call onAttack/onDamageTaken
|
||||
target.DelHP(action.amount);
|
||||
if (target is BattleNpc)
|
||||
@@ -605,6 +605,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
// damage is handled in script
|
||||
this.DelMP(spell.mpCost); // mpCost can be set in script e.g. if caster has something for free spells
|
||||
|
||||
foreach (var action in actions)
|
||||
zone.FindActorInArea<Character>(action.targetId).OnDamageTaken(this, action);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
}
|
||||
@@ -615,6 +618,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
// damage is handled in script
|
||||
this.DelTP(skill.tpCost);
|
||||
|
||||
foreach (var action in actions)
|
||||
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action);
|
||||
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
}
|
||||
@@ -623,6 +629,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
if (target is BattleNpc)
|
||||
((BattleNpc)target).lastAttacker = this;
|
||||
|
||||
foreach (var action in actions)
|
||||
zone.FindActorInArea<BattleNpc>(action.targetId)?.OnDamageTaken(this, action);
|
||||
}
|
||||
|
||||
public virtual void OnSpawn()
|
||||
@@ -638,6 +647,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
public virtual void OnDespawn()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnDamageTaken(Character attacker, BattleAction action)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
using MoonSharp;
|
||||
using MoonSharp.Interpreter;
|
||||
using FFXIVClassic_Map_Server.lua;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
{
|
||||
@@ -15,8 +16,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
public uint durationMs;
|
||||
public bool checkState;
|
||||
// todo: lua function
|
||||
Script script;
|
||||
LuaScript script;
|
||||
}
|
||||
|
||||
class ActionQueue
|
||||
{
|
||||
private Character owner;
|
||||
@@ -27,7 +29,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
public ActionQueue(Character owner)
|
||||
{
|
||||
|
||||
this.owner = owner;
|
||||
actionQueue = new Queue<Action>();
|
||||
timerQueue = new Queue<Action>();
|
||||
}
|
||||
|
||||
public void PushAction(Action action)
|
||||
@@ -45,5 +49,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
}
|
||||
|
||||
public void CheckAction(DateTime tick)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -363,8 +363,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
public override void ChangeTarget(Character target)
|
||||
{
|
||||
owner.target = target;
|
||||
owner.currentLockedTarget = target != null ? target.actorId : 0xC0000000;
|
||||
owner.currentTarget = target != null ? target.actorId : 0xC0000000;
|
||||
owner.currentLockedTarget = target?.actorId ?? 0xC0000000;
|
||||
owner.currentTarget = target?.actorId ?? 0xC0000000;
|
||||
|
||||
foreach (var player in owner.zone.GetActorsAroundActor<Player>(owner, 50))
|
||||
player.QueuePacket(owner.GetHateTypePacket(player));
|
||||
|
||||
base.ChangeTarget(target);
|
||||
}
|
||||
}
|
||||
|
@@ -155,7 +155,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
owner.aiContainer.ChangeTarget(null);
|
||||
return false;
|
||||
}
|
||||
else if (!owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
||||
else if (!owner.IsValidTarget(target, ValidTarget.Enemy) || !owner.aiContainer.GetTargetFind().CanTarget(target, false, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||
using FFXIVClassic_Map_Server.actors.group;
|
||||
using FFXIVClassic_Map_Server.packets.send;
|
||||
using FFXIVClassic_Map_Server.Actors.Chara;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
@@ -56,12 +57,13 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
private uint despawnTime;
|
||||
private uint respawnTime;
|
||||
private uint spawnDistance;
|
||||
|
||||
private uint bnpcId;
|
||||
public Character lastAttacker;
|
||||
|
||||
public uint spellListId, skillListId, dropListId;
|
||||
public Dictionary<uint, BattleCommand> skillList = new Dictionary<uint, BattleCommand>();
|
||||
public Dictionary<uint, BattleCommand> spellList = new Dictionary<uint, BattleCommand>();
|
||||
private Dictionary<MobModifier, Int64> mobModifiers = new Dictionary<MobModifier, Int64>();
|
||||
|
||||
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
||||
ushort actorState, uint animationId, string customDisplayName)
|
||||
@@ -110,10 +112,43 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
subpackets.Add(CreateSetActorIconPacket());
|
||||
subpackets.Add(CreateIsZoneingPacket());
|
||||
subpackets.Add(CreateScriptBindPacket(player));
|
||||
subpackets.Add(GetHateTypePacket(player));
|
||||
}
|
||||
return subpackets;
|
||||
}
|
||||
|
||||
public SubPacket GetHateTypePacket(Player player)
|
||||
{
|
||||
npcWork.hateType = 1;
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
if (aiContainer.IsEngaged())
|
||||
{
|
||||
npcWork.hateType = 2;
|
||||
}
|
||||
|
||||
if (player.actorId == this.currentLockedTarget)
|
||||
{
|
||||
npcWork.hateType = NpcWork.HATE_TYPE_ENGAGED_PARTY;
|
||||
}
|
||||
else if (player.currentParty != null)
|
||||
{
|
||||
foreach (var memberId in ((Party)player.currentParty).members)
|
||||
{
|
||||
if (this.currentLockedTarget == memberId)
|
||||
{
|
||||
npcWork.hateType = NpcWork.HATE_TYPE_ENGAGED_PARTY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var propPacketUtil = new ActorPropertyPacketUtil("npcWork", this);
|
||||
propPacketUtil.AddProperty("npcWork.hateType");
|
||||
return propPacketUtil.Done()[0];
|
||||
}
|
||||
|
||||
public uint GetDetectionType()
|
||||
{
|
||||
return (uint)detectionType;
|
||||
@@ -220,6 +255,23 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceRespawn()
|
||||
{
|
||||
base.Spawn(Program.Tick);
|
||||
|
||||
this.isMovingToSpawn = false;
|
||||
this.ResetMoveSpeeds();
|
||||
this.hateContainer.ClearHate();
|
||||
zone.BroadcastPacketsAroundActor(this, GetSpawnPackets(null, 0x01));
|
||||
zone.BroadcastPacketsAroundActor(this, GetInitPackets());
|
||||
charaWork.parameterSave.hp = charaWork.parameterSave.hpMax;
|
||||
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
|
||||
RecalculateStats();
|
||||
|
||||
OnSpawn();
|
||||
updateFlags |= ActorUpdateFlags.AllNpc;
|
||||
}
|
||||
|
||||
public override void Die(DateTime tick)
|
||||
{
|
||||
if (IsAlive())
|
||||
@@ -308,6 +360,25 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
base.OnAttack(state, action, ref error);
|
||||
// todo: move this somewhere else prolly and change based on model/appearance (so maybe in Character.cs instead)
|
||||
action.animation = 0x11001000; // (temporary) wolf anim
|
||||
|
||||
if (GetMobMod((uint)MobModifier.AttackScript) != 0)
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onAttack", this, state.GetTarget(), action.amount);
|
||||
}
|
||||
|
||||
public override void OnCast(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
{
|
||||
base.OnCast(state, actions, ref errors);
|
||||
|
||||
}
|
||||
|
||||
public override void OnAbility(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
{
|
||||
base.OnAbility(state, actions, ref errors);
|
||||
}
|
||||
|
||||
public override void OnWeaponSkill(State state, BattleAction[] actions, ref BattleAction[] errors)
|
||||
{
|
||||
base.OnWeaponSkill(state, actions, ref errors);
|
||||
}
|
||||
|
||||
public override void OnSpawn()
|
||||
@@ -325,5 +396,38 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
base.OnDespawn();
|
||||
}
|
||||
|
||||
public uint GetBattleNpcId()
|
||||
{
|
||||
return bnpcId;
|
||||
}
|
||||
|
||||
public void SetBattleNpcId(uint id)
|
||||
{
|
||||
this.bnpcId = id;
|
||||
}
|
||||
|
||||
|
||||
public Int64 GetMobMod(uint mobModId)
|
||||
{
|
||||
Int64 res;
|
||||
if (mobModifiers.TryGetValue((MobModifier)mobModId, out res))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetMobMod(uint mobModId, Int64 val)
|
||||
{
|
||||
if (mobModifiers.ContainsKey((MobModifier)mobModId))
|
||||
mobModifiers[(MobModifier)mobModId] = val;
|
||||
else
|
||||
mobModifiers.Add((MobModifier)mobModId, val);
|
||||
}
|
||||
|
||||
public override void OnDamageTaken(Character attacker, BattleAction action)
|
||||
{
|
||||
if (GetMobMod((uint)MobModifier.DefendScript) != 0)
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onDamageTaken", this, attacker, action.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs
Normal file
36
FFXIVClassic Map Server/actors/chara/npc/MobModifier.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.npc
|
||||
{
|
||||
enum MobModifier
|
||||
{
|
||||
None = 0,
|
||||
SpawnLeash = 1, // how far can i move before i deaggro target
|
||||
SightRange = 2, // how close does target need to be for me to detect by sight
|
||||
SoundRange = 3, // how close does target need to be for me to detect by sound
|
||||
BuffChance = 4,
|
||||
HealChance = 5,
|
||||
SkillUseChance = 6,
|
||||
LinkRadius = 7,
|
||||
MagicDelay = 8,
|
||||
SpecialDelay = 9,
|
||||
ExpBonus = 10, //
|
||||
IgnoreSpawnLeash = 11, // pursue target forever
|
||||
DrawIn = 12, // do i suck people in around me
|
||||
HpScale = 13, //
|
||||
Assist = 14, // gotta call the bois
|
||||
NoMove = 15, // cant move
|
||||
ShareTarget = 16, // use this actor's id as target id
|
||||
AttackScript = 17, // call my script's onAttack whenever i attack
|
||||
DefendScript = 18, // call my script's onDamageTaken whenever i take damage
|
||||
SpellScript = 19, // call my script's onSpellCast whenever i finish casting
|
||||
WeaponskillScript = 20, // call my script's onWeaponSkill whenever i finish using a weaponskill
|
||||
AbilityScript = 21, // call my script's onAbility whenever i finish using an ability
|
||||
CallForHelp = 22, // actor with this id outside of target's party with this can attack me
|
||||
FreeForAll = 23, // any actor can attack me
|
||||
}
|
||||
}
|
@@ -414,6 +414,17 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
aiContainer.Update(tick);
|
||||
}
|
||||
|
||||
public override void PostUpdate(DateTime tick, List<SubPacket> packets = null)
|
||||
{
|
||||
packets = packets ?? new List<SubPacket>();
|
||||
|
||||
if ((updateFlags & ActorUpdateFlags.Work) != 0)
|
||||
{
|
||||
|
||||
}
|
||||
base.PostUpdate(tick, packets);
|
||||
}
|
||||
|
||||
public override void OnSpawn()
|
||||
{
|
||||
base.OnSpawn();
|
||||
|
@@ -2,6 +2,10 @@
|
||||
{
|
||||
class NpcWork
|
||||
{
|
||||
public static byte HATE_TYPE_NONE = 0;
|
||||
public static byte HATE_TYPE_ENGAGED = 2;
|
||||
public static byte HATE_TYPE_ENGAGED_PARTY = 3;
|
||||
|
||||
public ushort pushCommand;
|
||||
public int pushCommandSub;
|
||||
public byte pushCommandPriority;
|
||||
|
@@ -25,6 +25,7 @@ using FFXIVClassic_Map_Server.actors.chara.ai.controllers;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor.battle;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.utils;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.state;
|
||||
using FFXIVClassic_Map_Server.actors.chara.npc;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
@@ -2037,6 +2038,47 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
SendGameMessage(Server.GetWorldManager().GetActor(), 32549, 0x20);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool partyEngaged = false;
|
||||
// todo: replace with confrontation status effect? (see how dsp does it)
|
||||
if (target.aiContainer.IsEngaged())
|
||||
{
|
||||
if (currentParty != null)
|
||||
{
|
||||
if (target is BattleNpc)
|
||||
{
|
||||
var helpingActorId = ((BattleNpc)target).GetMobMod((uint)MobModifier.CallForHelp);
|
||||
partyEngaged = this.actorId == helpingActorId || (((BattleNpc)target).GetMobMod((uint)MobModifier.FreeForAll) != 0);
|
||||
}
|
||||
|
||||
if (!partyEngaged)
|
||||
{
|
||||
foreach (var memberId in ((Party)currentParty).members)
|
||||
{
|
||||
if (memberId == target.currentLockedTarget)
|
||||
{
|
||||
partyEngaged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (target.currentLockedTarget == actorId)
|
||||
{
|
||||
partyEngaged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
partyEngaged = true;
|
||||
}
|
||||
|
||||
if (!partyEngaged)
|
||||
{
|
||||
// That target is already engaged.
|
||||
SendGameMessage(Server.GetWorldManager().GetActor(), 32520, 0x20);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((validTarget & ValidTarget.Ally) != 0 && target.allegiance != allegiance)
|
||||
|
Reference in New Issue
Block a user