using FFXIVClassic.Common; using FFXIVClassic_Map_Server.actors; using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.Actors.Chara; using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.packets.receive.events; using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.utils; using MoonSharp.Interpreter; using MySql.Data.MySqlClient; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FFXIVClassic_Map_Server.Actors { class Npc : Character { private uint actorClassId; private string uniqueIdentifier; private bool isMapObj = false; private uint layout, instance; public NpcWork npcWork = new NpcWork(); 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)) { this.positionX = posX; this.positionY = posY; this.positionZ = posZ; this.rotation = rot; this.currentMainState = actorState; this.animationId = animationId; this.displayNameId = actorClass.displayNameId; this.customDisplayName = customDisplayName; this.uniqueIdentifier = uniqueId; this.zoneId = spawnedArea.actorId; this.zone = spawnedArea; this.actorClassId = actorClass.actorClassId; LoadNpcAppearance(actorClass.actorClassId); this.classPath = actorClass.classPath; className = classPath.Substring(classPath.LastIndexOf("/")+1); charaWork.battleSave.potencial = 1.0f; charaWork.parameterSave.state_mainSkill[0] = 3; charaWork.parameterSave.state_mainSkill[2] = 3; charaWork.parameterSave.state_mainSkillLevel = 2; charaWork.parameterSave.hp[0] = 500; charaWork.parameterSave.hpMax[0] = 500; for (int i = 0; i < 32; i++ ) charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1); npcWork.pushCommand = actorClass.pushCommand; npcWork.pushCommandSub = actorClass.pushCommandSub; npcWork.pushCommandPriority = actorClass.pushCommandPriority; if (actorClassId == 1080078 || actorClassId == 1080079 || actorClassId == 1080080 || (actorClassId >= 1080123 && actorClassId <= 1080135) || (actorClassId >= 5000001 && actorClassId <= 5000090) || (actorClassId >= 5900001 && actorClassId <= 5900038)) { isMapObj = true; List lParams = LuaEngine.GetInstance().CallLuaFunctionForReturn(null, this, "init", false); if (lParams == null || lParams.Count < 6) isMapObj = false; else { layout = (uint)(Int32)lParams[4].value; instance = (uint)(Int32)lParams[5].value; isStatic = true; } } GenerateActorName((int)actorNumber); } public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, uint layout, uint instance) : base((4 << 28 | spawnedArea.actorId << 19 | (uint)actorNumber)) { this.positionX = posX; this.positionY = posY; this.positionZ = posZ; this.rotation = rot; this.currentMainState = 0; this.animationId = 0; this.displayNameId = actorClass.displayNameId; this.uniqueIdentifier = uniqueId; this.zoneId = spawnedArea.actorId; this.zone = spawnedArea; this.actorClassId = actorClass.actorClassId; LoadNpcAppearance(actorClass.actorClassId); this.classPath = actorClass.classPath; className = classPath.Substring(classPath.LastIndexOf("/") + 1); for (int i = 0; i < 32; i++) charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1); npcWork.pushCommand = actorClass.pushCommand; npcWork.pushCommandSub = actorClass.pushCommandSub; npcWork.pushCommandPriority = actorClass.pushCommandPriority; this.isMapObj = true; this.layout = layout; this.instance = instance; GenerateActorName((int)actorNumber); } public SubPacket CreateAddActorPacket() { return AddActorPacket.BuildPacket(actorId, 8); } int val = 0x0b00; // actorClassId, [], [], numBattleCommon, [battleCommon], numEventCommon, [eventCommon], args for either initForBattle/initForEvent public override SubPacket CreateScriptBindPacket(Player player) { List lParams; lParams = LuaEngine.GetInstance().CallLuaFunctionForReturn(player, this, "init", false); if (uniqueIdentifier.Equals("1")) { lParams[5].value = val; val++; player.SendMessage(0x20, "", String.Format("ID is now: 0x{0:X}", val)); } if (lParams != null && lParams.Count >= 3 && lParams[2].typeID == 0 && (int)lParams[2].value == 0) isStatic = true; else { // charaWork.property[2] = 1; // npcWork.hateType = 1; } if (lParams == null) { string classPathFake = "/Chara/Npc/Populace/PopulaceStandard"; string classNameFake = "PopulaceStandard"; lParams = LuaUtils.CreateLuaParamList(classPathFake, false, false, false, false, false, 0xF47F6, false, false, 0, 0); isStatic = true; //ActorInstantiatePacket.BuildPacket(actorId, actorName, classNameFake, lParams).DebugPrintSubPacket(); return ActorInstantiatePacket.BuildPacket(actorId, actorName, classNameFake, lParams); } else { lParams.Insert(0, new LuaParam(2, classPath)); lParams.Insert(1, new LuaParam(4, 4)); lParams.Insert(2, new LuaParam(4, 4)); lParams.Insert(3, new LuaParam(4, 4)); lParams.Insert(4, new LuaParam(4, 4)); lParams.Insert(5, new LuaParam(4, 4)); lParams.Insert(6, new LuaParam(0, (int)actorClassId)); } //ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams).DebugPrintSubPacket(); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams); } public override List GetSpawnPackets(Player player, ushort spawnType) { List subpackets = new List(); subpackets.Add(CreateAddActorPacket()); subpackets.AddRange(GetEventConditionPackets()); subpackets.Add(CreateSpeedPacket()); subpackets.Add(CreateSpawnPositonPacket(0x0)); if (isMapObj) subpackets.Add(SetActorBGPropertiesPacket.BuildPacket(actorId, instance, layout)); else subpackets.Add(CreateAppearancePacket()); subpackets.Add(CreateNamePacket()); subpackets.Add(CreateStatePacket()); subpackets.Add(CreateIdleAnimationPacket()); subpackets.Add(CreateInitStatusPacket()); subpackets.Add(CreateSetActorIconPacket()); subpackets.Add(CreateIsZoneingPacket()); subpackets.Add(CreateScriptBindPacket(player)); return subpackets; } public override List GetInitPackets() { ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("/_init", this); //Potential propPacketUtil.AddProperty("charaWork.battleSave.potencial"); //Properties for (int i = 0; i < charaWork.property.Length; i++) { if (charaWork.property[i] != 0) propPacketUtil.AddProperty(String.Format("charaWork.property[{0}]", i)); } //Parameters propPacketUtil.AddProperty("charaWork.parameterSave.hp[0]"); propPacketUtil.AddProperty("charaWork.parameterSave.hpMax[0]"); propPacketUtil.AddProperty("charaWork.parameterSave.mp"); propPacketUtil.AddProperty("charaWork.parameterSave.mpMax"); propPacketUtil.AddProperty("charaWork.parameterTemp.tp"); if (charaWork.parameterSave.state_mainSkill[0] != 0) propPacketUtil.AddProperty("charaWork.parameterSave.state_mainSkill[0]"); if (charaWork.parameterSave.state_mainSkill[1] != 0) propPacketUtil.AddProperty("charaWork.parameterSave.state_mainSkill[1]"); if (charaWork.parameterSave.state_mainSkill[2] != 0) propPacketUtil.AddProperty("charaWork.parameterSave.state_mainSkill[2]"); if (charaWork.parameterSave.state_mainSkill[3] != 0) propPacketUtil.AddProperty("charaWork.parameterSave.state_mainSkill[3]"); propPacketUtil.AddProperty("charaWork.parameterSave.state_mainSkillLevel"); //Status Times for (int i = 0; i < charaWork.statusShownTime.Length; i++) { if (charaWork.statusShownTime[i] != 0xFFFFFFFF) propPacketUtil.AddProperty(String.Format("charaWork.statusShownTime[{0}]", i)); } //General Parameters for (int i = 3; i < charaWork.battleTemp.generalParameter.Length; i++) { if (charaWork.battleTemp.generalParameter[i] != 0) propPacketUtil.AddProperty(String.Format("charaWork.battleTemp.generalParameter[{0}]", i)); } propPacketUtil.AddProperty("npcWork.hateType"); if (npcWork.pushCommand != 0) { propPacketUtil.AddProperty("npcWork.pushCommand"); if (npcWork.pushCommandSub != 0) propPacketUtil.AddProperty("npcWork.pushCommandSub"); propPacketUtil.AddProperty("npcWork.pushCommandPriority"); } return propPacketUtil.Done(); } public string GetUniqueId() { return uniqueIdentifier; } public uint GetActorClassId() { return actorClassId; } public void ChangeNpcAppearance(uint id) { LoadNpcAppearance(id); zone.BroadcastPacketAroundActor(this, CreateAppearancePacket()); } public void LoadNpcAppearance(uint id) { 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(); string query = @" SELECT base, size, hairStyle, hairHighlightColor, hairVariation, faceType, characteristics, characteristicsColor, faceEyebrows, faceIrisSize, faceEyeShape, faceNose, faceFeatures, faceMouth, ears, hairColor, skinColor, eyeColor, voice, mainHand, offHand, spMainHand, spOffHand, throwing, pack, pouch, head, body, legs, hands, feet, waist, neck, leftEar, rightEar, leftIndex, rightIndex, leftFinger, rightFinger FROM gamedata_actor_appearance WHERE id = @templateId "; MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@templateId", id); using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { //Handle Appearance modelId = reader.GetUInt32(0); appearanceIds[Character.SIZE] = reader.GetUInt32(1); appearanceIds[Character.COLORINFO] = (uint)(reader.GetUInt32(16) | (reader.GetUInt32(15) << 10) | (reader.GetUInt32(17) << 20)); //17 - Skin Color, 16 - Hair Color, 18 - Eye Color appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.GetFaceInfo(reader.GetByte(6), reader.GetByte(7), reader.GetByte(5), reader.GetByte(14), reader.GetByte(13), reader.GetByte(12), reader.GetByte(11), reader.GetByte(10), reader.GetByte(9), reader.GetByte(8))); appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt32(3) | reader.GetUInt32(2) << 10); //5- Hair Highlight, 4 - Hair Style appearanceIds[Character.VOICE] = reader.GetUInt32(17); appearanceIds[Character.MAINHAND] = reader.GetUInt32(19); appearanceIds[Character.OFFHAND] = reader.GetUInt32(20); appearanceIds[Character.SPMAINHAND] = reader.GetUInt32(21); appearanceIds[Character.SPOFFHAND] = reader.GetUInt32(22); appearanceIds[Character.THROWING] = reader.GetUInt32(23); appearanceIds[Character.PACK] = reader.GetUInt32(24); appearanceIds[Character.POUCH] = reader.GetUInt32(25); appearanceIds[Character.HEADGEAR] = reader.GetUInt32(26); appearanceIds[Character.BODYGEAR] = reader.GetUInt32(27); appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(28); appearanceIds[Character.HANDSGEAR] = reader.GetUInt32(29); appearanceIds[Character.FEETGEAR] = reader.GetUInt32(30); appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(31); appearanceIds[Character.NECKGEAR] = reader.GetUInt32(32); appearanceIds[Character.R_EAR] = reader.GetUInt32(33); appearanceIds[Character.L_EAR] = reader.GetUInt32(34); appearanceIds[Character.R_INDEXFINGER] = reader.GetUInt32(35); appearanceIds[Character.L_INDEXFINGER] = reader.GetUInt32(36); appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(37); appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(38); } } } catch (MySqlException e) { Console.WriteLine(e); } finally { conn.Dispose(); } } } public void LoadEventConditions(string eventConditions) { EventList conditions = JsonConvert.DeserializeObject(eventConditions); this.eventConditions = conditions; } public void DoOnActorSpawn(Player player) { LuaEngine.GetInstance().CallLuaFunction(player, this, "onSpawn", true); } public void PlayMapObjAnimation(Player player, string animationName) { player.QueuePacket(PlayBGAnimation.BuildPacket(actorId, animationName)); } public void Despawn() { zone.DespawnActor(this); } public void Update(double deltaTime) { LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, deltaTime); } //A party member list packet came, set the party /* public void SetParty(MonsterPartyGroup group) { if (group is MonsterPartyGroup) currentParty = group; } */ } }