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:
Tahir Akhlaq
2017-09-10 03:41:58 +01:00
parent 9077c60b96
commit ce5030acd1
18 changed files with 434 additions and 22 deletions

View File

@@ -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
}

View File

@@ -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)
{
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View 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
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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)