mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-05-20 08:26:59 -04:00
stubbed item use state (needs to actually look up the item and get its reuse stuff)
- added tables to load mobs from (probably dont import besides server_battlenpc_genus.sql) - added field to server_battle_commands for commands usable by both monsters and players (probably arent any really)
This commit is contained in:
@@ -2155,7 +2155,7 @@ namespace FFXIVClassic_Map_Server
|
||||
conn.Open();
|
||||
|
||||
var query = ("SELECT `id`, name, classJob, lvl, requirements, validTarget, aoeType, aoeRange, aoeTarget, numHits, positionBonus, procRequirement, `range`, buffDuration, debuffDuration, " +
|
||||
"castType, castTime, recastTime, mpCost, tpCost, animationType, effectAnimation, modelAnimation, animationDuration, battleAnimation FROM server_battle_commands;");
|
||||
"castType, castTime, recastTime, mpCost, tpCost, animationType, effectAnimation, modelAnimation, animationDuration, battleAnimation, validUser FROM server_battle_commands;");
|
||||
|
||||
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||
|
||||
@@ -2191,6 +2191,7 @@ namespace FFXIVClassic_Map_Server
|
||||
battleCommand.aoeTarget = (TargetFindAOETarget)reader.GetByte("aoeTarget");
|
||||
|
||||
battleCommand.battleAnimation = reader.GetUInt32("battleAnimation");
|
||||
battleCommand.validUser = (BattleCommandValidUser)reader.GetByte("validUser");
|
||||
|
||||
battleCommands.Add(id, battleCommand);
|
||||
}
|
||||
@@ -2208,7 +2209,50 @@ namespace FFXIVClassic_Map_Server
|
||||
return battleCommands;
|
||||
}
|
||||
|
||||
public static Dictionary<uint, BattleNpc> LoadBattleNpcList(uint zoneId)
|
||||
{
|
||||
Dictionary<uint, BattleNpc> battleNpcList = new Dictionary<uint, BattleNpc>();
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||
{
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
var query = @"";
|
||||
/*
|
||||
var query = @"SELECT bsl.uniqueId, bsl.groupId, bsl.positionX, bls.positionY, bsl.positionZ, " +
|
||||
@"bgr.groupId, bgr.genusId, bgr.actorClassId, bgr.minLevel, bgr.maxLevel, bgr.respawnTime, " +
|
||||
@"bgr.hp, bgr.mp, bgr.skillListId, bgr.spellListId, bgr.dropListId, bgr.allegiance, " +
|
||||
@"bgr.spawnType, bgr.animationId, bgr.actorState, bgr.privateAreaName, bgr.privateAreaLevel, bgr.zoneId, " +
|
||||
@"bge.genusId, bge.modelSize, bge.kindredId, bge.detection, bge.hpp, bge.mpp, bge.tpp, bge.str, bge.vit, bge.dex, " +
|
||||
@"bge.int, bge.mnd, bge.pie, bge.att, bge.acc, bge.def, bge.eva, bge.slash, bge.pierce, bge.h2h, bge.blunt, " +
|
||||
@"bge.fire, bge.ice, bge.wind, bge.lightning, bge.earth, bge.water FROM " +
|
||||
@"server_battlenpc_spawn_locations bsl INNER JOIN server_battlenpc_groups bgr ON bsl.groupId = bgr.groupId INNER JOIN " +
|
||||
@"server_battlenpc_genus bge ON bgr.genusId = bgr.genusId INNER JOIN WHERE bgr.zoneId = @zoneId";
|
||||
*/
|
||||
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||
cmd.Parameters.AddWithValue("@zoneId", zoneId);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
using (MySqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MySqlException e)
|
||||
{
|
||||
Program.Log.Error(e.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Dispose();
|
||||
}
|
||||
}
|
||||
return battleNpcList;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -97,6 +97,7 @@
|
||||
<Compile Include="actors\chara\ai\state\AttackState.cs" />
|
||||
<Compile Include="actors\chara\ai\state\DeathState.cs" />
|
||||
<Compile Include="actors\chara\ai\state\DespawnState.cs" />
|
||||
<Compile Include="actors\chara\ai\state\ItemState.cs" />
|
||||
<Compile Include="actors\chara\ai\state\MagicState.cs" />
|
||||
<Compile Include="actors\chara\ai\state\State.cs" />
|
||||
<Compile Include="actors\chara\ai\state\WeaponSkillState.cs" />
|
||||
|
@@ -401,7 +401,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
if (positionUpdates != null && positionUpdates.Count > 0)
|
||||
{
|
||||
// push latest for player
|
||||
var pos = positionUpdates[0];
|
||||
oldPositionX = positionX;
|
||||
oldPositionY = positionY;
|
||||
|
@@ -384,7 +384,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
}
|
||||
}
|
||||
|
||||
// todo: for zones override this to seach contentareas (assuming flag is passed)
|
||||
// todo: for zones override this to search contentareas (assuming flag is passed)
|
||||
public virtual List<T> GetAllActors<T>() where T : Actor
|
||||
{
|
||||
lock (mActorList)
|
||||
|
@@ -166,25 +166,19 @@ namespace FFXIVClassic_Map_Server.actors.area
|
||||
|
||||
public override void Update(DateTime tick)
|
||||
{
|
||||
// todo: again, this is retarded but debug stuff
|
||||
base.Update(tick);
|
||||
|
||||
// todo: again, this is retarded but debug stuff
|
||||
var diffTime = tick - lastUpdate;
|
||||
// arbitrary cap
|
||||
if (diffTime.TotalMilliseconds >= 33)
|
||||
{
|
||||
}
|
||||
|
||||
if (diffTime.TotalSeconds >= 10)
|
||||
{
|
||||
if (this.pathCalls > 0)
|
||||
{
|
||||
Program.Log.Error("Number of pathfinding calls {0} average time {1}", pathCalls, pathCallTime / pathCalls);
|
||||
Program.Log.Debug("Number of pathfinding calls {0} average time {1}ms", pathCalls, (float)(pathCallTime / pathCalls));
|
||||
}
|
||||
// todo: this is stupid debug stuff that needs to fuck off
|
||||
lastUpdate = tick;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -19,10 +19,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
/// <summary> Which Character types am I friendly with </summary>
|
||||
enum CharacterTargetingAllegiance
|
||||
{
|
||||
/// <summary> Friendly to Players </summary>
|
||||
Player,
|
||||
/// <summary> Friendly to BattleNpcs </summary>
|
||||
BattleNpcs
|
||||
BattleNpcs,
|
||||
/// <summary> Friendly to Players </summary>
|
||||
Player
|
||||
}
|
||||
|
||||
class Character : Actor
|
||||
@@ -564,6 +564,16 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
updateFlags |= ActorUpdateFlags.HpTpMp;
|
||||
}
|
||||
|
||||
public void SetStat(uint statId, uint val)
|
||||
{
|
||||
charaWork.battleTemp.generalParameter[statId] = (ushort)val;
|
||||
}
|
||||
|
||||
public ushort GetStat(uint statId)
|
||||
{
|
||||
return charaWork.battleTemp.generalParameter[statId];
|
||||
}
|
||||
|
||||
public virtual float GetSpeed()
|
||||
{
|
||||
// todo: for battlenpc/player calculate speed
|
||||
|
@@ -93,6 +93,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
}
|
||||
}
|
||||
|
||||
public void InternalUseItem(Character target, uint slot, uint itemId)
|
||||
{
|
||||
// todo: can allies use items?
|
||||
if (owner is Player)
|
||||
{
|
||||
if (CanChangeState())
|
||||
{
|
||||
ChangeState(new ItemState((Player)owner, target, (ushort)slot, itemId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// You cannot use that item now.
|
||||
((Player)owner).SendGameMessage(Server.GetWorldManager().GetActor(), 32544, 0x20, itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearStates()
|
||||
{
|
||||
while (states.Count > 0)
|
||||
@@ -107,9 +124,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public Controller GetController()
|
||||
public T GetController<T>() where T : Controller
|
||||
{
|
||||
return controller;
|
||||
return controller as T;
|
||||
}
|
||||
|
||||
public TargetFind GetTargetFind()
|
||||
@@ -190,13 +207,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
public bool IsSpawned()
|
||||
{
|
||||
// todo: set a flag when finished spawning
|
||||
return !IsDead();
|
||||
}
|
||||
|
||||
public bool IsEngaged()
|
||||
{
|
||||
// todo: check this is legit
|
||||
return owner.currentMainState == SetActorStatePacket.MAIN_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
@@ -260,6 +275,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
InternalMobSkill(target, mobSkillId);
|
||||
}
|
||||
|
||||
public void UseItem(Character target, uint slot, uint itemId)
|
||||
{
|
||||
if (controller != null)
|
||||
controller.UseItem(target, slot, itemId);
|
||||
}
|
||||
public void InternalChangeTarget(Character target)
|
||||
{
|
||||
// targets are changed in the controller
|
||||
|
@@ -44,6 +44,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
Miss = 0x08
|
||||
}
|
||||
|
||||
public enum BattleCommandValidUser : byte
|
||||
{
|
||||
All,
|
||||
Player,
|
||||
Monster
|
||||
}
|
||||
|
||||
class BattleCommand
|
||||
{
|
||||
public ushort id;
|
||||
@@ -75,6 +82,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
public int aoeRange;
|
||||
|
||||
public TargetFind targetFind;
|
||||
public BattleCommandValidUser validUser;
|
||||
|
||||
public BattleCommand(ushort id, string name)
|
||||
{
|
||||
@@ -100,12 +108,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
public bool IsValidTarget(Character user, Character target)
|
||||
{
|
||||
// todo: set box length..
|
||||
targetFind = new TargetFind(user);
|
||||
|
||||
if (aoeType == TargetFindAOEType.Box)
|
||||
{
|
||||
// todo: read box width from sql
|
||||
targetFind.SetAOEBox(validTarget, aoeTarget, range, aoeRange);
|
||||
}
|
||||
else
|
||||
|
@@ -125,6 +125,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
this.param = param != -1.0f ? param : 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this to prepare Box AOE
|
||||
/// </summary>
|
||||
/// <param name="validTarget"></param>
|
||||
/// <param name="aoeTarget"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="width"></param>
|
||||
public void SetAOEBox(ValidTarget validTarget, TargetFindAOETarget aoeTarget, float length, float width)
|
||||
{
|
||||
this.validTarget = validTarget;
|
||||
@@ -272,7 +279,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
{
|
||||
foreach (var actorId in party.members)
|
||||
{
|
||||
AddTarget(owner.zone.FindActorInArea(actorId) as Character, withPet);
|
||||
AddTarget(owner.zone.FindActorInArea<Character>(actorId), withPet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,9 +380,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
|
||||
private bool IsWithinCircle(Character target, float maxDistance)
|
||||
{
|
||||
// todo: make y diff modifiable?
|
||||
if (Math.Abs(owner.positionX - target.positionY) > 6.0f)
|
||||
return false;
|
||||
|
||||
if (this.targetPosition == null)
|
||||
this.targetPosition = aoeTarget == TargetFindAOETarget.Self ? owner.GetPosAsVector3() : masterTarget.GetPosAsVector3();
|
||||
|
||||
return target.GetPosAsVector3().IsWithinCircle(targetPosition, param);
|
||||
}
|
||||
|
||||
@@ -393,9 +403,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||
// if character is a player owned pet, treat as a player
|
||||
if (target.aiContainer != null)
|
||||
{
|
||||
var controller = target.aiContainer.GetController();
|
||||
if (controller != null && controller is PetController)
|
||||
return ((PetController)controller).GetPetMaster();
|
||||
var controller = target.aiContainer.GetController<PetController>();
|
||||
if (controller != null)
|
||||
return controller.GetPetMaster();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
|
||||
public override void Update(DateTime tick)
|
||||
{
|
||||
lastUpdate = tick;
|
||||
// todo: handle aggro/deaggro and other shit here
|
||||
if (owner.aiContainer.IsEngaged())
|
||||
{
|
||||
@@ -104,8 +105,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
owner.aiContainer.pathFind.PreparePath(owner.spawnX, owner.spawnY, owner.spawnZ, 1.5f, 10);
|
||||
neutralTime = lastActionTime;
|
||||
owner.hateContainer.ClearHate();
|
||||
owner.ResetMoveSpeeds();
|
||||
owner.moveState = 1;
|
||||
lua.LuaEngine.CallLuaBattleFunction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(battleStartTime));
|
||||
lua.LuaEngine.CallLuaBattleFunction(owner, "onDisengage", owner, target, Utils.UnixTimeStampUTC(lastUpdate));
|
||||
}
|
||||
|
||||
public override void Cast(Character target, uint spellId)
|
||||
@@ -143,7 +145,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
if (tick >= waitTime)
|
||||
{
|
||||
// todo: aggro cooldown
|
||||
neutralTime = tick.AddSeconds(3);
|
||||
neutralTime = tick.AddSeconds(5);
|
||||
if (owner.aiContainer.pathFind.IsFollowingPath())
|
||||
{
|
||||
owner.aiContainer.pathFind.FollowPath();
|
||||
|
@@ -29,6 +29,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
public abstract void Cast(Character target, uint spellId);
|
||||
public virtual void WeaponSkill(Character target, uint weaponSkillId) { }
|
||||
public virtual void MonsterSkill(Character target, uint mobSkillId) { }
|
||||
public virtual void UseItem(Character target, uint slot, uint itemId) { }
|
||||
public abstract void Ability(Character target, uint abilityId);
|
||||
public abstract void RangedAttack(Character target);
|
||||
public virtual void Spawn() { }
|
||||
|
@@ -87,5 +87,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void UseItem(Character target, uint slot, uint itemId)
|
||||
{
|
||||
owner.aiContainer.InternalUseItem(target, slot, itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
: base(owner, null)
|
||||
{
|
||||
owner.Disengage();
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD);
|
||||
owner.ChangeState(SetActorStatePacket.MAIN_STATE_DEAD2);
|
||||
canInterrupt = false;
|
||||
startTime = tick;
|
||||
despawnTime = startTime.AddSeconds(timeToFadeOut);
|
||||
|
23
FFXIVClassic Map Server/actors/chara/ai/state/ItemState.cs
Normal file
23
FFXIVClassic Map Server/actors/chara/ai/state/ItemState.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server.actors.chara.player;
|
||||
using FFXIVClassic_Map_Server.dataobjects;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
||||
{
|
||||
class ItemState : State
|
||||
{
|
||||
ItemData item;
|
||||
new Player owner;
|
||||
public ItemState(Player owner, Character target, ushort slot, uint itemId) :
|
||||
base(owner, target)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,21 +26,41 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
None = 0x00,
|
||||
Sight = 0x01,
|
||||
Scent = 0x02,
|
||||
LowHp = 0x04,
|
||||
IgnoreLevelDifference = 0x08
|
||||
Sound = 0x04,
|
||||
LowHp = 0x08,
|
||||
IgnoreLevelDifference = 0x10
|
||||
}
|
||||
|
||||
enum KindredType
|
||||
{
|
||||
Unknown = 0,
|
||||
Beast = 1,
|
||||
Plantoid = 2,
|
||||
Aquan = 3,
|
||||
Spoken = 4,
|
||||
Reptilian = 5,
|
||||
Insect = 6,
|
||||
Avian = 7,
|
||||
Undead = 8,
|
||||
Cursed = 9,
|
||||
Voidsent = 10,
|
||||
}
|
||||
|
||||
class BattleNpc : Npc
|
||||
{
|
||||
public HateContainer hateContainer;
|
||||
public AggroType aggroType;
|
||||
public KindredType kindredType;
|
||||
public bool neutral;
|
||||
private uint despawnTime;
|
||||
private uint respawnTime;
|
||||
private uint spawnDistance;
|
||||
|
||||
|
||||
public Character lastAttacker;
|
||||
|
||||
public Dictionary<uint, BattleCommand> skillList = new Dictionary<uint, BattleCommand>();
|
||||
public Dictionary<uint, BattleCommand> spellList = new Dictionary<uint, BattleCommand>();
|
||||
|
||||
public BattleNpc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
||||
ushort actorState, uint animationId, string customDisplayName)
|
||||
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)
|
||||
@@ -193,6 +213,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
charaWork.parameterSave.mp = charaWork.parameterSave.mpMax;
|
||||
RecalculateStats();
|
||||
|
||||
OnSpawn();
|
||||
updateFlags |= ActorUpdateFlags.AllNpc;
|
||||
}
|
||||
}
|
||||
@@ -201,9 +222,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
if (IsAlive())
|
||||
{
|
||||
if (lastAttacker is Pet && ((Pet)lastAttacker).master is Player)
|
||||
// todo: does retail
|
||||
if (lastAttacker is Pet && lastAttacker.aiContainer.GetController<PetController>()?.GetPetMaster() is Player)
|
||||
{
|
||||
lastAttacker = ((Pet)lastAttacker).master;
|
||||
lastAttacker = lastAttacker.aiContainer.GetController<PetController>().GetPetMaster();
|
||||
}
|
||||
|
||||
if (lastAttacker is Player)
|
||||
@@ -226,8 +248,8 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
((Player)lastAttacker).QueuePacket(BattleActionX01Packet.BuildPacket(lastAttacker.actorId, 0, 0, new BattleAction(actorId, 30108, 0)));
|
||||
}
|
||||
}
|
||||
positionUpdates?.Clear();
|
||||
aiContainer.InternalDie(tick, despawnTime);
|
||||
aiContainer.pathFind.Clear();
|
||||
this.ResetMoveSpeeds();
|
||||
|
||||
// todo: reset cooldowns
|
||||
@@ -289,6 +311,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
public override void OnSpawn()
|
||||
{
|
||||
base.OnSpawn();
|
||||
lua.LuaEngine.CallLuaBattleFunction(this, "onSpawn", this);
|
||||
}
|
||||
|
||||
public override void OnDeath()
|
||||
|
@@ -21,6 +21,17 @@ using FFXIVClassic_Map_Server.actors.chara.ai;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
[Flags]
|
||||
enum NpcSpawnType : ushort
|
||||
{
|
||||
Normal = 0x00,
|
||||
Scripted = 0x01,
|
||||
Nighttime = 0x02,
|
||||
Evening = 0x04,
|
||||
Daytime = 0x08,
|
||||
Weather = 0x10,
|
||||
}
|
||||
|
||||
class Npc : Character
|
||||
{
|
||||
private uint actorClassId;
|
||||
@@ -30,6 +41,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
private uint layout, instance;
|
||||
|
||||
public NpcWork npcWork = new NpcWork();
|
||||
public NpcSpawnType npcSpawnType;
|
||||
|
||||
public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, string customDisplayName)
|
||||
: base((4 << 28 | spawnedArea.actorId << 19 | (uint)actorNumber))
|
||||
@@ -414,7 +426,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
|
||||
public override void OnDespawn()
|
||||
{
|
||||
zone.BroadcastPacketAroundActor(this, RemoveActorPacket.BuildPacket(this.actorId));
|
||||
zone.BroadcastPacketAroundActor(this, RemoveActorPacket.BuildPacket(this.actorId));
|
||||
QueuePositionUpdate(spawnX, spawnY, spawnZ);
|
||||
LuaEngine.CallLuaBattleFunction(this, "onDespawn", this);
|
||||
|
@@ -13,7 +13,6 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
{
|
||||
class Pet : BattleNpc
|
||||
{
|
||||
public Character master;
|
||||
public Pet(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot,
|
||||
ushort actorState, uint animationId, string customDisplayName)
|
||||
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)
|
||||
|
@@ -1755,6 +1755,10 @@ namespace FFXIVClassic_Map_Server.Actors
|
||||
|
||||
public override void PostUpdate(DateTime tick, List<SubPacket> packets = null)
|
||||
{
|
||||
// todo: is this correct?
|
||||
if (this.playerSession.isUpdatesLocked)
|
||||
return;
|
||||
|
||||
// todo: should probably add another flag for battleTemp since all this uses reflection
|
||||
packets = new List<SubPacket>();
|
||||
|
||||
|
@@ -17,6 +17,7 @@ using FFXIVClassic.Common;
|
||||
using FFXIVClassic_Map_Server.actors.area;
|
||||
using System.Threading;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai;
|
||||
using FFXIVClassic_Map_Server.actors.chara.ai.controllers;
|
||||
|
||||
namespace FFXIVClassic_Map_Server.lua
|
||||
{
|
||||
@@ -148,7 +149,7 @@ namespace FFXIVClassic_Map_Server.lua
|
||||
else if (actor is Npc)
|
||||
{
|
||||
// todo: this is probably unnecessary as im not sure there were pets for players
|
||||
if (!(actor is Pet && ((Pet)actor).master is Player))
|
||||
if (!(actor.aiContainer.GetController<PetController>()?.GetPetMaster() is Player))
|
||||
path = String.Format("./scripts/unique/{0}/{1}/{2}.lua", actor.zone.zoneName, actor is BattleNpc ? "Monster" : "PopulaceStandard", ((Npc)actor).GetUniqueId());
|
||||
}
|
||||
// dont wanna throw an error if file doesnt exist
|
||||
|
Reference in New Issue
Block a user